diff options
Diffstat (limited to 'fs/hpfs/ea.c')
-rw-r--r-- | fs/hpfs/ea.c | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c new file mode 100644 index 000000000000..66339dc030e4 --- /dev/null +++ b/fs/hpfs/ea.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/ea.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 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) { | ||
246 | hpfs_error(s, "fnode %08x: ea_offs == %03x, ea_size_s == %03x", | ||
247 | inode->i_ino, fnode->ea_offs, fnode->ea_size_s); | ||
248 | return; | ||
249 | } | ||
250 | if ((fnode->ea_size_s || !fnode->ea_size_l) && | ||
251 | fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s + strlen(key) + size + 5 <= 0x200) { | ||
252 | ea = fnode_end_ea(fnode); | ||
253 | *(char *)ea = 0; | ||
254 | ea->namelen = strlen(key); | ||
255 | ea->valuelen = size; | ||
256 | strcpy(ea->name, key); | ||
257 | memcpy(ea_data(ea), data, size); | ||
258 | fnode->ea_size_s += strlen(key) + size + 5; | ||
259 | goto ret; | ||
260 | } | ||
261 | /* Most the code here is 99.9993422% unused. I hope there are no bugs. | ||
262 | But what .. HPFS.IFS has also bugs in ea management. */ | ||
263 | if (fnode->ea_size_s && !fnode->ea_size_l) { | ||
264 | secno n; | ||
265 | struct buffer_head *bh; | ||
266 | char *data; | ||
267 | if (!(n = hpfs_alloc_sector(s, fno, 1, 0, 1))) return; | ||
268 | if (!(data = hpfs_get_sector(s, n, &bh))) { | ||
269 | hpfs_free_sectors(s, n, 1); | ||
270 | return; | ||
271 | } | ||
272 | memcpy(data, fnode_ea(fnode), fnode->ea_size_s); | ||
273 | fnode->ea_size_l = fnode->ea_size_s; | ||
274 | fnode->ea_size_s = 0; | ||
275 | fnode->ea_secno = n; | ||
276 | fnode->ea_anode = 0; | ||
277 | mark_buffer_dirty(bh); | ||
278 | brelse(bh); | ||
279 | } | ||
280 | pos = fnode->ea_size_l + 5 + strlen(key) + size; | ||
281 | len = (fnode->ea_size_l + 511) >> 9; | ||
282 | if (pos >= 30000) goto bail; | ||
283 | while (((pos + 511) >> 9) > len) { | ||
284 | if (!len) { | ||
285 | if (!(fnode->ea_secno = hpfs_alloc_sector(s, fno, 1, 0, 1))) | ||
286 | goto bail; | ||
287 | fnode->ea_anode = 0; | ||
288 | len++; | ||
289 | } else if (!fnode->ea_anode) { | ||
290 | if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) { | ||
291 | len++; | ||
292 | } else { | ||
293 | /* Aargh... don't know how to create ea anodes :-( */ | ||
294 | /*struct buffer_head *bh; | ||
295 | struct anode *anode; | ||
296 | anode_secno a_s; | ||
297 | if (!(anode = hpfs_alloc_anode(s, fno, &a_s, &bh))) | ||
298 | goto bail; | ||
299 | anode->up = fno; | ||
300 | anode->btree.fnode_parent = 1; | ||
301 | anode->btree.n_free_nodes--; | ||
302 | anode->btree.n_used_nodes++; | ||
303 | anode->btree.first_free += 12; | ||
304 | anode->u.external[0].disk_secno = fnode->ea_secno; | ||
305 | anode->u.external[0].file_secno = 0; | ||
306 | anode->u.external[0].length = len; | ||
307 | mark_buffer_dirty(bh); | ||
308 | brelse(bh); | ||
309 | fnode->ea_anode = 1; | ||
310 | fnode->ea_secno = a_s;*/ | ||
311 | secno new_sec; | ||
312 | int i; | ||
313 | if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9), 1))) | ||
314 | goto bail; | ||
315 | for (i = 0; i < len; i++) { | ||
316 | struct buffer_head *bh1, *bh2; | ||
317 | void *b1, *b2; | ||
318 | if (!(b1 = hpfs_map_sector(s, fnode->ea_secno + i, &bh1, len - i - 1))) { | ||
319 | hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); | ||
320 | goto bail; | ||
321 | } | ||
322 | if (!(b2 = hpfs_get_sector(s, new_sec + i, &bh2))) { | ||
323 | brelse(bh1); | ||
324 | hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); | ||
325 | goto bail; | ||
326 | } | ||
327 | memcpy(b2, b1, 512); | ||
328 | brelse(bh1); | ||
329 | mark_buffer_dirty(bh2); | ||
330 | brelse(bh2); | ||
331 | } | ||
332 | hpfs_free_sectors(s, fnode->ea_secno, len); | ||
333 | fnode->ea_secno = new_sec; | ||
334 | len = (pos + 511) >> 9; | ||
335 | } | ||
336 | } | ||
337 | if (fnode->ea_anode) { | ||
338 | if (hpfs_add_sector_to_btree(s, fnode->ea_secno, | ||
339 | 0, len) != -1) { | ||
340 | len++; | ||
341 | } else { | ||
342 | goto bail; | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | h[0] = 0; | ||
347 | h[1] = strlen(key); | ||
348 | h[2] = size & 0xff; | ||
349 | h[3] = size >> 8; | ||
350 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l, 4, h)) goto bail; | ||
351 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 4, h[1] + 1, key)) goto bail; | ||
352 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 5 + h[1], size, data)) goto bail; | ||
353 | fnode->ea_size_l = pos; | ||
354 | ret: | ||
355 | hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size; | ||
356 | return; | ||
357 | bail: | ||
358 | if (fnode->ea_secno) | ||
359 | if (fnode->ea_anode) hpfs_truncate_btree(s, fnode->ea_secno, 1, (fnode->ea_size_l + 511) >> 9); | ||
360 | else hpfs_free_sectors(s, fnode->ea_secno + ((fnode->ea_size_l + 511) >> 9), len - ((fnode->ea_size_l + 511) >> 9)); | ||
361 | else fnode->ea_secno = fnode->ea_size_l = 0; | ||
362 | } | ||
363 | |||