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