]>
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; | |
4085e155 | 26 | if (ea_indirect(ea)) { |
d0969d19 | 27 | if (ea_valuelen(ea) != 8) { |
4085e155 | 28 | hpfs_error(s, "ea_indirect(ea) set while ea->valuelen!=8, %s %08x, pos %08x", |
1da177e4 LT |
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; | |
4085e155 | 34 | hpfs_ea_remove(s, ea_sec(ea), ea_in_anode(ea), ea_len(ea)); |
1da177e4 | 35 | } |
d0969d19 | 36 | pos += ea->namelen + ea_valuelen(ea) + 5; |
1da177e4 LT |
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 | ||
7e7742ee AV |
65 | static void set_indirect_ea(struct super_block *s, int ano, secno a, |
66 | const char *data, int size) | |
1da177e4 LT |
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; | |
c3514817 | 79 | char ex[4 + 255 + 1 + 8]; |
1da177e4 LT |
80 | struct extended_attribute *ea; |
81 | struct extended_attribute *ea_end = fnode_end_ea(fnode); | |
82 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | |
83 | if (!strcmp(ea->name, key)) { | |
4085e155 | 84 | if (ea_indirect(ea)) |
1da177e4 | 85 | goto indirect; |
d0969d19 | 86 | if (ea_valuelen(ea) >= size) |
1da177e4 | 87 | return -EINVAL; |
d0969d19 MP |
88 | memcpy(buf, ea_data(ea), ea_valuelen(ea)); |
89 | buf[ea_valuelen(ea)] = 0; | |
1da177e4 LT |
90 | return 0; |
91 | } | |
0b69760b MP |
92 | a = le32_to_cpu(fnode->ea_secno); |
93 | len = le32_to_cpu(fnode->ea_size_l); | |
c4c99543 | 94 | ano = fnode_in_anode(fnode); |
1da177e4 LT |
95 | pos = 0; |
96 | while (pos < len) { | |
1da177e4 LT |
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; | |
4085e155 | 104 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea_indirect(ea) ? 8 : 0), ex + 4)) |
1da177e4 LT |
105 | return -EIO; |
106 | if (!strcmp(ea->name, key)) { | |
4085e155 | 107 | if (ea_indirect(ea)) |
1da177e4 | 108 | goto indirect; |
d0969d19 | 109 | if (ea_valuelen(ea) >= size) |
1da177e4 | 110 | return -EINVAL; |
d0969d19 | 111 | if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea_valuelen(ea), buf)) |
1da177e4 | 112 | return -EIO; |
d0969d19 | 113 | buf[ea_valuelen(ea)] = 0; |
1da177e4 LT |
114 | return 0; |
115 | } | |
d0969d19 | 116 | pos += ea->namelen + ea_valuelen(ea) + 5; |
1da177e4 LT |
117 | } |
118 | return -ENOENT; | |
119 | indirect: | |
120 | if (ea_len(ea) >= size) | |
121 | return -EINVAL; | |
4085e155 | 122 | if (hpfs_ea_read(s, ea_sec(ea), ea_in_anode(ea), 0, ea_len(ea), buf)) |
1da177e4 LT |
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)) { | |
4085e155 AV |
139 | if (ea_indirect(ea)) |
140 | return get_indirect_ea(s, ea_in_anode(ea), ea_sec(ea), *size = ea_len(ea)); | |
d0969d19 | 141 | if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) { |
1da177e4 LT |
142 | printk("HPFS: out of memory for EA\n"); |
143 | return NULL; | |
144 | } | |
d0969d19 MP |
145 | memcpy(ret, ea_data(ea), ea_valuelen(ea)); |
146 | ret[ea_valuelen(ea)] = 0; | |
1da177e4 LT |
147 | return ret; |
148 | } | |
0b69760b MP |
149 | a = le32_to_cpu(fnode->ea_secno); |
150 | len = le32_to_cpu(fnode->ea_size_l); | |
c4c99543 | 151 | ano = fnode_in_anode(fnode); |
1da177e4 LT |
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; | |
4085e155 | 162 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea_indirect(ea) ? 8 : 0), ex + 4)) |
1da177e4 LT |
163 | return NULL; |
164 | if (!strcmp(ea->name, key)) { | |
4085e155 AV |
165 | if (ea_indirect(ea)) |
166 | return get_indirect_ea(s, ea_in_anode(ea), ea_sec(ea), *size = ea_len(ea)); | |
d0969d19 | 167 | if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) { |
1da177e4 LT |
168 | printk("HPFS: out of memory for EA\n"); |
169 | return NULL; | |
170 | } | |
d0969d19 | 171 | if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea_valuelen(ea), ret)) { |
1da177e4 LT |
172 | kfree(ret); |
173 | return NULL; | |
174 | } | |
d0969d19 | 175 | ret[ea_valuelen(ea)] = 0; |
1da177e4 LT |
176 | return ret; |
177 | } | |
d0969d19 | 178 | pos += ea->namelen + ea_valuelen(ea) + 5; |
1da177e4 LT |
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 | ||
7e7742ee AV |
189 | void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, |
190 | const char *data, int size) | |
1da177e4 LT |
191 | { |
192 | fnode_secno fno = inode->i_ino; | |
193 | struct super_block *s = inode->i_sb; | |
194 | unsigned pos; | |
195 | int ano, len; | |
196 | secno a; | |
197 | unsigned char h[4]; | |
198 | struct extended_attribute *ea; | |
199 | struct extended_attribute *ea_end = fnode_end_ea(fnode); | |
200 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | |
201 | if (!strcmp(ea->name, key)) { | |
4085e155 | 202 | if (ea_indirect(ea)) { |
1da177e4 | 203 | if (ea_len(ea) == size) |
4085e155 | 204 | set_indirect_ea(s, ea_in_anode(ea), ea_sec(ea), data, size); |
d0969d19 | 205 | } else if (ea_valuelen(ea) == size) { |
1da177e4 LT |
206 | memcpy(ea_data(ea), data, size); |
207 | } | |
208 | return; | |
209 | } | |
0b69760b MP |
210 | a = le32_to_cpu(fnode->ea_secno); |
211 | len = le32_to_cpu(fnode->ea_size_l); | |
c4c99543 | 212 | ano = fnode_in_anode(fnode); |
1da177e4 LT |
213 | pos = 0; |
214 | while (pos < len) { | |
215 | char ex[4 + 255 + 1 + 8]; | |
216 | ea = (struct extended_attribute *)ex; | |
217 | if (pos + 4 > len) { | |
218 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | |
219 | ano ? "anode" : "sectors", a, len); | |
220 | return; | |
221 | } | |
222 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; | |
4085e155 | 223 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea_indirect(ea) ? 8 : 0), ex + 4)) |
1da177e4 LT |
224 | return; |
225 | if (!strcmp(ea->name, key)) { | |
4085e155 | 226 | if (ea_indirect(ea)) { |
1da177e4 | 227 | if (ea_len(ea) == size) |
4085e155 | 228 | set_indirect_ea(s, ea_in_anode(ea), ea_sec(ea), data, size); |
1da177e4 LT |
229 | } |
230 | else { | |
d0969d19 | 231 | if (ea_valuelen(ea) == size) |
1da177e4 LT |
232 | hpfs_ea_write(s, a, ano, pos + 4 + ea->namelen + 1, size, data); |
233 | } | |
234 | return; | |
235 | } | |
d0969d19 | 236 | pos += ea->namelen + ea_valuelen(ea) + 5; |
1da177e4 | 237 | } |
0b69760b MP |
238 | if (!le16_to_cpu(fnode->ea_offs)) { |
239 | /*if (le16_to_cpu(fnode->ea_size_s)) { | |
1da177e4 | 240 | hpfs_error(s, "fnode %08x: ea_size_s == %03x, ea_offs == 0", |
0b69760b | 241 | inode->i_ino, le16_to_cpu(fnode->ea_size_s)); |
1da177e4 LT |
242 | return; |
243 | }*/ | |
0b69760b | 244 | fnode->ea_offs = cpu_to_le16(0xc4); |
1da177e4 | 245 | } |
0b69760b | 246 | if (le16_to_cpu(fnode->ea_offs) < 0xc4 || le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) > 0x200) { |
18debbbc RD |
247 | hpfs_error(s, "fnode %08lx: ea_offs == %03x, ea_size_s == %03x", |
248 | (unsigned long)inode->i_ino, | |
de5e2b36 | 249 | le16_to_cpu(fnode->ea_offs), le16_to_cpu(fnode->ea_size_s)); |
1da177e4 LT |
250 | return; |
251 | } | |
0b69760b MP |
252 | if ((le16_to_cpu(fnode->ea_size_s) || !le32_to_cpu(fnode->ea_size_l)) && |
253 | le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) + strlen(key) + size + 5 <= 0x200) { | |
1da177e4 LT |
254 | ea = fnode_end_ea(fnode); |
255 | *(char *)ea = 0; | |
256 | ea->namelen = strlen(key); | |
d0969d19 MP |
257 | ea->valuelen_lo = size; |
258 | ea->valuelen_hi = size >> 8; | |
1da177e4 LT |
259 | strcpy(ea->name, key); |
260 | memcpy(ea_data(ea), data, size); | |
0b69760b | 261 | fnode->ea_size_s = cpu_to_le16(le16_to_cpu(fnode->ea_size_s) + strlen(key) + size + 5); |
1da177e4 LT |
262 | goto ret; |
263 | } | |
264 | /* Most the code here is 99.9993422% unused. I hope there are no bugs. | |
265 | But what .. HPFS.IFS has also bugs in ea management. */ | |
0b69760b | 266 | if (le16_to_cpu(fnode->ea_size_s) && !le32_to_cpu(fnode->ea_size_l)) { |
1da177e4 LT |
267 | secno n; |
268 | struct buffer_head *bh; | |
269 | char *data; | |
7d23ce36 | 270 | if (!(n = hpfs_alloc_sector(s, fno, 1, 0))) return; |
1da177e4 LT |
271 | if (!(data = hpfs_get_sector(s, n, &bh))) { |
272 | hpfs_free_sectors(s, n, 1); | |
273 | return; | |
274 | } | |
0b69760b MP |
275 | memcpy(data, fnode_ea(fnode), le16_to_cpu(fnode->ea_size_s)); |
276 | fnode->ea_size_l = cpu_to_le32(le16_to_cpu(fnode->ea_size_s)); | |
277 | fnode->ea_size_s = cpu_to_le16(0); | |
278 | fnode->ea_secno = cpu_to_le32(n); | |
c4c99543 | 279 | fnode->flags &= ~FNODE_anode; |
1da177e4 LT |
280 | mark_buffer_dirty(bh); |
281 | brelse(bh); | |
282 | } | |
0b69760b MP |
283 | pos = le32_to_cpu(fnode->ea_size_l) + 5 + strlen(key) + size; |
284 | len = (le32_to_cpu(fnode->ea_size_l) + 511) >> 9; | |
1da177e4 LT |
285 | if (pos >= 30000) goto bail; |
286 | while (((pos + 511) >> 9) > len) { | |
287 | if (!len) { | |
0b69760b MP |
288 | secno q = hpfs_alloc_sector(s, fno, 1, 0); |
289 | if (!q) goto bail; | |
290 | fnode->ea_secno = cpu_to_le32(q); | |
c4c99543 | 291 | fnode->flags &= ~FNODE_anode; |
1da177e4 | 292 | len++; |
c4c99543 | 293 | } else if (!fnode_in_anode(fnode)) { |
0b69760b | 294 | if (hpfs_alloc_if_possible(s, le32_to_cpu(fnode->ea_secno) + len)) { |
1da177e4 LT |
295 | len++; |
296 | } else { | |
297 | /* Aargh... don't know how to create ea anodes :-( */ | |
298 | /*struct buffer_head *bh; | |
299 | struct anode *anode; | |
300 | anode_secno a_s; | |
301 | if (!(anode = hpfs_alloc_anode(s, fno, &a_s, &bh))) | |
302 | goto bail; | |
0b69760b | 303 | anode->up = cpu_to_le32(fno); |
1da177e4 LT |
304 | anode->btree.fnode_parent = 1; |
305 | anode->btree.n_free_nodes--; | |
306 | anode->btree.n_used_nodes++; | |
0b69760b MP |
307 | anode->btree.first_free = cpu_to_le16(le16_to_cpu(anode->btree.first_free) + 12); |
308 | anode->u.external[0].disk_secno = cpu_to_le32(le32_to_cpu(fnode->ea_secno)); | |
309 | anode->u.external[0].file_secno = cpu_to_le32(0); | |
310 | anode->u.external[0].length = cpu_to_le32(len); | |
1da177e4 LT |
311 | mark_buffer_dirty(bh); |
312 | brelse(bh); | |
c4c99543 | 313 | fnode->flags |= FNODE_anode; |
0b69760b | 314 | fnode->ea_secno = cpu_to_le32(a_s);*/ |
1da177e4 LT |
315 | secno new_sec; |
316 | int i; | |
7d23ce36 | 317 | if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9)))) |
1da177e4 LT |
318 | goto bail; |
319 | for (i = 0; i < len; i++) { | |
320 | struct buffer_head *bh1, *bh2; | |
321 | void *b1, *b2; | |
0b69760b | 322 | if (!(b1 = hpfs_map_sector(s, le32_to_cpu(fnode->ea_secno) + i, &bh1, len - i - 1))) { |
1da177e4 LT |
323 | hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); |
324 | goto bail; | |
325 | } | |
326 | if (!(b2 = hpfs_get_sector(s, new_sec + i, &bh2))) { | |
327 | brelse(bh1); | |
328 | hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); | |
329 | goto bail; | |
330 | } | |
331 | memcpy(b2, b1, 512); | |
332 | brelse(bh1); | |
333 | mark_buffer_dirty(bh2); | |
334 | brelse(bh2); | |
335 | } | |
0b69760b MP |
336 | hpfs_free_sectors(s, le32_to_cpu(fnode->ea_secno), len); |
337 | fnode->ea_secno = cpu_to_le32(new_sec); | |
1da177e4 LT |
338 | len = (pos + 511) >> 9; |
339 | } | |
340 | } | |
c4c99543 | 341 | if (fnode_in_anode(fnode)) { |
0b69760b | 342 | if (hpfs_add_sector_to_btree(s, le32_to_cpu(fnode->ea_secno), |
1da177e4 LT |
343 | 0, len) != -1) { |
344 | len++; | |
345 | } else { | |
346 | goto bail; | |
347 | } | |
348 | } | |
349 | } | |
350 | h[0] = 0; | |
351 | h[1] = strlen(key); | |
352 | h[2] = size & 0xff; | |
353 | h[3] = size >> 8; | |
c4c99543 AV |
354 | if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode_in_anode(fnode), le32_to_cpu(fnode->ea_size_l), 4, h)) goto bail; |
355 | if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode_in_anode(fnode), le32_to_cpu(fnode->ea_size_l) + 4, h[1] + 1, key)) goto bail; | |
356 | if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode_in_anode(fnode), le32_to_cpu(fnode->ea_size_l) + 5 + h[1], size, data)) goto bail; | |
0b69760b | 357 | fnode->ea_size_l = cpu_to_le32(pos); |
1da177e4 LT |
358 | ret: |
359 | hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size; | |
360 | return; | |
361 | bail: | |
0b69760b | 362 | if (le32_to_cpu(fnode->ea_secno)) |
c4c99543 | 363 | if (fnode_in_anode(fnode)) hpfs_truncate_btree(s, le32_to_cpu(fnode->ea_secno), 1, (le32_to_cpu(fnode->ea_size_l) + 511) >> 9); |
0b69760b MP |
364 | else hpfs_free_sectors(s, le32_to_cpu(fnode->ea_secno) + ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9), len - ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9)); |
365 | else fnode->ea_secno = fnode->ea_size_l = cpu_to_le32(0); | |
1da177e4 LT |
366 | } |
367 |