]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/fs/hpfs/ea.c | |
3 | * | |
4 | * Mikulas Patocka ([email protected]), 1998-1999 | |
5 | * | |
6 | * handling extended attributes | |
7 | */ | |
8 | ||
9 | #include "hpfs_fn.h" | |
10 | ||
11 | /* Remove external extended attributes. ano specifies whether a is a | |
12 | direct sector where eas starts or an anode */ | |
13 | ||
14 | void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len) | |
15 | { | |
16 | unsigned pos = 0; | |
17 | while (pos < len) { | |
18 | char ex[4 + 255 + 1 + 8]; | |
19 | struct extended_attribute *ea = (struct extended_attribute *)ex; | |
20 | if (pos + 4 > len) { | |
21 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | |
22 | ano ? "anode" : "sectors", a, len); | |
23 | return; | |
24 | } | |
25 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; | |
26 | if (ea->indirect) { | |
27 | if (ea->valuelen != 8) { | |
28 | hpfs_error(s, "ea->indirect set while ea->valuelen!=8, %s %08x, pos %08x", | |
29 | ano ? "anode" : "sectors", a, pos); | |
30 | return; | |
31 | } | |
32 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 9, ex+4)) | |
33 | return; | |
34 | hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea)); | |
35 | } | |
36 | pos += ea->namelen + ea->valuelen + 5; | |
37 | } | |
38 | if (!ano) hpfs_free_sectors(s, a, (len+511) >> 9); | |
39 | else { | |
40 | struct buffer_head *bh; | |
41 | struct anode *anode; | |
42 | if ((anode = hpfs_map_anode(s, a, &bh))) { | |
43 | hpfs_remove_btree(s, &anode->btree); | |
44 | brelse(bh); | |
45 | hpfs_free_sectors(s, a, 1); | |
46 | } | |
47 | } | |
48 | } | |
49 | ||
50 | static char *get_indirect_ea(struct super_block *s, int ano, secno a, int size) | |
51 | { | |
52 | char *ret; | |
53 | if (!(ret = kmalloc(size + 1, GFP_NOFS))) { | |
54 | printk("HPFS: out of memory for EA\n"); | |
55 | return NULL; | |
56 | } | |
57 | if (hpfs_ea_read(s, a, ano, 0, size, ret)) { | |
58 | kfree(ret); | |
59 | return NULL; | |
60 | } | |
61 | ret[size] = 0; | |
62 | return ret; | |
63 | } | |
64 | ||
65 | static void set_indirect_ea(struct super_block *s, int ano, secno a, char *data, | |
66 | int size) | |
67 | { | |
68 | hpfs_ea_write(s, a, ano, 0, size, data); | |
69 | } | |
70 | ||
71 | /* Read an extended attribute named 'key' into the provided buffer */ | |
72 | ||
73 | int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key, | |
74 | char *buf, int size) | |
75 | { | |
76 | unsigned pos; | |
77 | int ano, len; | |
78 | secno a; | |
79 | struct extended_attribute *ea; | |
80 | struct extended_attribute *ea_end = fnode_end_ea(fnode); | |
81 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | |
82 | if (!strcmp(ea->name, key)) { | |
83 | if (ea->indirect) | |
84 | goto indirect; | |
85 | if (ea->valuelen >= size) | |
86 | return -EINVAL; | |
87 | memcpy(buf, ea_data(ea), ea->valuelen); | |
88 | buf[ea->valuelen] = 0; | |
89 | return 0; | |
90 | } | |
91 | a = fnode->ea_secno; | |
92 | len = fnode->ea_size_l; | |
93 | ano = fnode->ea_anode; | |
94 | pos = 0; | |
95 | while (pos < len) { | |
96 | char ex[4 + 255 + 1 + 8]; | |
97 | ea = (struct extended_attribute *)ex; | |
98 | if (pos + 4 > len) { | |
99 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | |
100 | ano ? "anode" : "sectors", a, len); | |
101 | return -EIO; | |
102 | } | |
103 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return -EIO; | |
104 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) | |
105 | return -EIO; | |
106 | if (!strcmp(ea->name, key)) { | |
107 | if (ea->indirect) | |
108 | goto indirect; | |
109 | if (ea->valuelen >= size) | |
110 | return -EINVAL; | |
111 | if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, buf)) | |
112 | return -EIO; | |
113 | buf[ea->valuelen] = 0; | |
114 | return 0; | |
115 | } | |
116 | pos += ea->namelen + ea->valuelen + 5; | |
117 | } | |
118 | return -ENOENT; | |
119 | indirect: | |
120 | if (ea_len(ea) >= size) | |
121 | return -EINVAL; | |
122 | if (hpfs_ea_read(s, ea_sec(ea), ea->anode, 0, ea_len(ea), buf)) | |
123 | return -EIO; | |
124 | buf[ea_len(ea)] = 0; | |
125 | return 0; | |
126 | } | |
127 | ||
128 | /* Read an extended attribute named 'key' */ | |
129 | char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *size) | |
130 | { | |
131 | char *ret; | |
132 | unsigned pos; | |
133 | int ano, len; | |
134 | secno a; | |
135 | struct extended_attribute *ea; | |
136 | struct extended_attribute *ea_end = fnode_end_ea(fnode); | |
137 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | |
138 | if (!strcmp(ea->name, key)) { | |
139 | if (ea->indirect) | |
140 | return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); | |
141 | if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) { | |
142 | printk("HPFS: out of memory for EA\n"); | |
143 | return NULL; | |
144 | } | |
145 | memcpy(ret, ea_data(ea), ea->valuelen); | |
146 | ret[ea->valuelen] = 0; | |
147 | return ret; | |
148 | } | |
149 | a = fnode->ea_secno; | |
150 | len = fnode->ea_size_l; | |
151 | ano = fnode->ea_anode; | |
152 | pos = 0; | |
153 | while (pos < len) { | |
154 | char ex[4 + 255 + 1 + 8]; | |
155 | ea = (struct extended_attribute *)ex; | |
156 | if (pos + 4 > len) { | |
157 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | |
158 | ano ? "anode" : "sectors", a, len); | |
159 | return NULL; | |
160 | } | |
161 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return NULL; | |
162 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) | |
163 | return NULL; | |
164 | if (!strcmp(ea->name, key)) { | |
165 | if (ea->indirect) | |
166 | return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); | |
167 | if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) { | |
168 | printk("HPFS: out of memory for EA\n"); | |
169 | return NULL; | |
170 | } | |
171 | if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, ret)) { | |
172 | kfree(ret); | |
173 | return NULL; | |
174 | } | |
175 | ret[ea->valuelen] = 0; | |
176 | return ret; | |
177 | } | |
178 | pos += ea->namelen + ea->valuelen + 5; | |
179 | } | |
180 | return NULL; | |
181 | } | |
182 | ||
183 | /* | |
184 | * Update or create extended attribute 'key' with value 'data'. Note that | |
185 | * when this ea exists, it MUST have the same size as size of data. | |
186 | * This driver can't change sizes of eas ('cause I just don't need it). | |
187 | */ | |
188 | ||
189 | void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data, int size) | |
190 | { | |
191 | fnode_secno fno = inode->i_ino; | |
192 | struct super_block *s = inode->i_sb; | |
193 | unsigned pos; | |
194 | int ano, len; | |
195 | secno a; | |
196 | unsigned char h[4]; | |
197 | struct extended_attribute *ea; | |
198 | struct extended_attribute *ea_end = fnode_end_ea(fnode); | |
199 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | |
200 | if (!strcmp(ea->name, key)) { | |
201 | if (ea->indirect) { | |
202 | if (ea_len(ea) == size) | |
203 | set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); | |
204 | } else if (ea->valuelen == size) { | |
205 | memcpy(ea_data(ea), data, size); | |
206 | } | |
207 | return; | |
208 | } | |
209 | a = fnode->ea_secno; | |
210 | len = fnode->ea_size_l; | |
211 | ano = fnode->ea_anode; | |
212 | pos = 0; | |
213 | while (pos < len) { | |
214 | char ex[4 + 255 + 1 + 8]; | |
215 | ea = (struct extended_attribute *)ex; | |
216 | if (pos + 4 > len) { | |
217 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | |
218 | ano ? "anode" : "sectors", a, len); | |
219 | return; | |
220 | } | |
221 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; | |
222 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) | |
223 | return; | |
224 | if (!strcmp(ea->name, key)) { | |
225 | if (ea->indirect) { | |
226 | if (ea_len(ea) == size) | |
227 | set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); | |
228 | } | |
229 | else { | |
230 | if (ea->valuelen == size) | |
231 | hpfs_ea_write(s, a, ano, pos + 4 + ea->namelen + 1, size, data); | |
232 | } | |
233 | return; | |
234 | } | |
235 | pos += ea->namelen + ea->valuelen + 5; | |
236 | } | |
237 | if (!fnode->ea_offs) { | |
238 | /*if (fnode->ea_size_s) { | |
239 | hpfs_error(s, "fnode %08x: ea_size_s == %03x, ea_offs == 0", | |
240 | inode->i_ino, fnode->ea_size_s); | |
241 | return; | |
242 | }*/ | |
243 | fnode->ea_offs = 0xc4; | |
244 | } | |
245 | if (fnode->ea_offs < 0xc4 || fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200) { | |
18debbbc RD |
246 | hpfs_error(s, "fnode %08lx: ea_offs == %03x, ea_size_s == %03x", |
247 | (unsigned long)inode->i_ino, | |
248 | fnode->ea_offs, fnode->ea_size_s); | |
1da177e4 LT |
249 | return; |
250 | } | |
251 | if ((fnode->ea_size_s || !fnode->ea_size_l) && | |
252 | fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s + strlen(key) + size + 5 <= 0x200) { | |
253 | ea = fnode_end_ea(fnode); | |
254 | *(char *)ea = 0; | |
255 | ea->namelen = strlen(key); | |
256 | ea->valuelen = size; | |
257 | strcpy(ea->name, key); | |
258 | memcpy(ea_data(ea), data, size); | |
259 | fnode->ea_size_s += strlen(key) + size + 5; | |
260 | goto ret; | |
261 | } | |
262 | /* Most the code here is 99.9993422% unused. I hope there are no bugs. | |
263 | But what .. HPFS.IFS has also bugs in ea management. */ | |
264 | if (fnode->ea_size_s && !fnode->ea_size_l) { | |
265 | secno n; | |
266 | struct buffer_head *bh; | |
267 | char *data; | |
268 | if (!(n = hpfs_alloc_sector(s, fno, 1, 0, 1))) return; | |
269 | if (!(data = hpfs_get_sector(s, n, &bh))) { | |
270 | hpfs_free_sectors(s, n, 1); | |
271 | return; | |
272 | } | |
273 | memcpy(data, fnode_ea(fnode), fnode->ea_size_s); | |
274 | fnode->ea_size_l = fnode->ea_size_s; | |
275 | fnode->ea_size_s = 0; | |
276 | fnode->ea_secno = n; | |
277 | fnode->ea_anode = 0; | |
278 | mark_buffer_dirty(bh); | |
279 | brelse(bh); | |
280 | } | |
281 | pos = fnode->ea_size_l + 5 + strlen(key) + size; | |
282 | len = (fnode->ea_size_l + 511) >> 9; | |
283 | if (pos >= 30000) goto bail; | |
284 | while (((pos + 511) >> 9) > len) { | |
285 | if (!len) { | |
286 | if (!(fnode->ea_secno = hpfs_alloc_sector(s, fno, 1, 0, 1))) | |
287 | goto bail; | |
288 | fnode->ea_anode = 0; | |
289 | len++; | |
290 | } else if (!fnode->ea_anode) { | |
291 | if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) { | |
292 | len++; | |
293 | } else { | |
294 | /* Aargh... don't know how to create ea anodes :-( */ | |
295 | /*struct buffer_head *bh; | |
296 | struct anode *anode; | |
297 | anode_secno a_s; | |
298 | if (!(anode = hpfs_alloc_anode(s, fno, &a_s, &bh))) | |
299 | goto bail; | |
300 | anode->up = fno; | |
301 | anode->btree.fnode_parent = 1; | |
302 | anode->btree.n_free_nodes--; | |
303 | anode->btree.n_used_nodes++; | |
304 | anode->btree.first_free += 12; | |
305 | anode->u.external[0].disk_secno = fnode->ea_secno; | |
306 | anode->u.external[0].file_secno = 0; | |
307 | anode->u.external[0].length = len; | |
308 | mark_buffer_dirty(bh); | |
309 | brelse(bh); | |
310 | fnode->ea_anode = 1; | |
311 | fnode->ea_secno = a_s;*/ | |
312 | secno new_sec; | |
313 | int i; | |
314 | if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9), 1))) | |
315 | goto bail; | |
316 | for (i = 0; i < len; i++) { | |
317 | struct buffer_head *bh1, *bh2; | |
318 | void *b1, *b2; | |
319 | if (!(b1 = hpfs_map_sector(s, fnode->ea_secno + i, &bh1, len - i - 1))) { | |
320 | hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); | |
321 | goto bail; | |
322 | } | |
323 | if (!(b2 = hpfs_get_sector(s, new_sec + i, &bh2))) { | |
324 | brelse(bh1); | |
325 | hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); | |
326 | goto bail; | |
327 | } | |
328 | memcpy(b2, b1, 512); | |
329 | brelse(bh1); | |
330 | mark_buffer_dirty(bh2); | |
331 | brelse(bh2); | |
332 | } | |
333 | hpfs_free_sectors(s, fnode->ea_secno, len); | |
334 | fnode->ea_secno = new_sec; | |
335 | len = (pos + 511) >> 9; | |
336 | } | |
337 | } | |
338 | if (fnode->ea_anode) { | |
339 | if (hpfs_add_sector_to_btree(s, fnode->ea_secno, | |
340 | 0, len) != -1) { | |
341 | len++; | |
342 | } else { | |
343 | goto bail; | |
344 | } | |
345 | } | |
346 | } | |
347 | h[0] = 0; | |
348 | h[1] = strlen(key); | |
349 | h[2] = size & 0xff; | |
350 | h[3] = size >> 8; | |
351 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l, 4, h)) goto bail; | |
352 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 4, h[1] + 1, key)) goto bail; | |
353 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 5 + h[1], size, data)) goto bail; | |
354 | fnode->ea_size_l = pos; | |
355 | ret: | |
356 | hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size; | |
357 | return; | |
358 | bail: | |
359 | if (fnode->ea_secno) | |
360 | if (fnode->ea_anode) hpfs_truncate_btree(s, fnode->ea_secno, 1, (fnode->ea_size_l + 511) >> 9); | |
361 | else hpfs_free_sectors(s, fnode->ea_secno + ((fnode->ea_size_l + 511) >> 9), len - ((fnode->ea_size_l + 511) >> 9)); | |
362 | else fnode->ea_secno = fnode->ea_size_l = 0; | |
363 | } | |
364 |