1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * directory.c |
4 | * |
5 | * PURPOSE |
6 | * Directory related functions |
7 | * |
8 | */ |
9 | |
10 | #include "udfdecl.h" |
11 | #include "udf_i.h" |
12 | |
13 | #include <linux/fs.h> |
14 | #include <linux/string.h> |
15 | #include <linux/bio.h> |
16 | #include <linux/crc-itu-t.h> |
17 | #include <linux/iversion.h> |
18 | |
19 | static int udf_verify_fi(struct udf_fileident_iter *iter) |
20 | { |
21 | unsigned int len; |
22 | |
23 | if (iter->fi.descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) { |
24 | udf_err(iter->dir->i_sb, |
25 | "directory (ino %lu) has entry at pos %llu with incorrect tag %x\n" , |
26 | iter->dir->i_ino, (unsigned long long)iter->pos, |
27 | le16_to_cpu(iter->fi.descTag.tagIdent)); |
28 | return -EFSCORRUPTED; |
29 | } |
30 | len = udf_dir_entry_len(cfi: &iter->fi); |
31 | if (le16_to_cpu(iter->fi.lengthOfImpUse) & 3) { |
32 | udf_err(iter->dir->i_sb, |
33 | "directory (ino %lu) has entry at pos %llu with unaligned length of impUse field\n" , |
34 | iter->dir->i_ino, (unsigned long long)iter->pos); |
35 | return -EFSCORRUPTED; |
36 | } |
37 | /* |
38 | * This is in fact allowed by the spec due to long impUse field but |
39 | * we don't support it. If there is real media with this large impUse |
40 | * field, support can be added. |
41 | */ |
42 | if (len > 1 << iter->dir->i_blkbits) { |
43 | udf_err(iter->dir->i_sb, |
44 | "directory (ino %lu) has too big (%u) entry at pos %llu\n" , |
45 | iter->dir->i_ino, len, (unsigned long long)iter->pos); |
46 | return -EFSCORRUPTED; |
47 | } |
48 | if (iter->pos + len > iter->dir->i_size) { |
49 | udf_err(iter->dir->i_sb, |
50 | "directory (ino %lu) has entry past directory size at pos %llu\n" , |
51 | iter->dir->i_ino, (unsigned long long)iter->pos); |
52 | return -EFSCORRUPTED; |
53 | } |
54 | if (udf_dir_entry_len(cfi: &iter->fi) != |
55 | sizeof(struct tag) + le16_to_cpu(iter->fi.descTag.descCRCLength)) { |
56 | udf_err(iter->dir->i_sb, |
57 | "directory (ino %lu) has entry where CRC length (%u) does not match entry length (%u)\n" , |
58 | iter->dir->i_ino, |
59 | (unsigned)le16_to_cpu(iter->fi.descTag.descCRCLength), |
60 | (unsigned)(udf_dir_entry_len(&iter->fi) - |
61 | sizeof(struct tag))); |
62 | return -EFSCORRUPTED; |
63 | } |
64 | return 0; |
65 | } |
66 | |
67 | static int udf_copy_fi(struct udf_fileident_iter *iter) |
68 | { |
69 | struct udf_inode_info *iinfo = UDF_I(inode: iter->dir); |
70 | u32 blksize = 1 << iter->dir->i_blkbits; |
71 | u32 off, len, nameoff; |
72 | int err; |
73 | |
74 | /* Skip copying when we are at EOF */ |
75 | if (iter->pos >= iter->dir->i_size) { |
76 | iter->name = NULL; |
77 | return 0; |
78 | } |
79 | if (iter->dir->i_size < iter->pos + sizeof(struct fileIdentDesc)) { |
80 | udf_err(iter->dir->i_sb, |
81 | "directory (ino %lu) has entry straddling EOF\n" , |
82 | iter->dir->i_ino); |
83 | return -EFSCORRUPTED; |
84 | } |
85 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
86 | memcpy(&iter->fi, iinfo->i_data + iinfo->i_lenEAttr + iter->pos, |
87 | sizeof(struct fileIdentDesc)); |
88 | err = udf_verify_fi(iter); |
89 | if (err < 0) |
90 | return err; |
91 | iter->name = iinfo->i_data + iinfo->i_lenEAttr + iter->pos + |
92 | sizeof(struct fileIdentDesc) + |
93 | le16_to_cpu(iter->fi.lengthOfImpUse); |
94 | return 0; |
95 | } |
96 | |
97 | off = iter->pos & (blksize - 1); |
98 | len = min_t(u32, sizeof(struct fileIdentDesc), blksize - off); |
99 | memcpy(&iter->fi, iter->bh[0]->b_data + off, len); |
100 | if (len < sizeof(struct fileIdentDesc)) |
101 | memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data, |
102 | sizeof(struct fileIdentDesc) - len); |
103 | err = udf_verify_fi(iter); |
104 | if (err < 0) |
105 | return err; |
106 | |
107 | /* Handle directory entry name */ |
108 | nameoff = off + sizeof(struct fileIdentDesc) + |
109 | le16_to_cpu(iter->fi.lengthOfImpUse); |
110 | if (off + udf_dir_entry_len(cfi: &iter->fi) <= blksize) { |
111 | iter->name = iter->bh[0]->b_data + nameoff; |
112 | } else if (nameoff >= blksize) { |
113 | iter->name = iter->bh[1]->b_data + (nameoff - blksize); |
114 | } else { |
115 | iter->name = iter->namebuf; |
116 | len = blksize - nameoff; |
117 | memcpy(iter->name, iter->bh[0]->b_data + nameoff, len); |
118 | memcpy(iter->name + len, iter->bh[1]->b_data, |
119 | iter->fi.lengthFileIdent - len); |
120 | } |
121 | return 0; |
122 | } |
123 | |
124 | /* Readahead 8k once we are at 8k boundary */ |
125 | static void udf_readahead_dir(struct udf_fileident_iter *iter) |
126 | { |
127 | unsigned int ralen = 16 >> (iter->dir->i_blkbits - 9); |
128 | struct buffer_head *tmp, *bha[16]; |
129 | int i, num; |
130 | udf_pblk_t blk; |
131 | |
132 | if (iter->loffset & (ralen - 1)) |
133 | return; |
134 | |
135 | if (iter->loffset + ralen > (iter->elen >> iter->dir->i_blkbits)) |
136 | ralen = (iter->elen >> iter->dir->i_blkbits) - iter->loffset; |
137 | num = 0; |
138 | for (i = 0; i < ralen; i++) { |
139 | blk = udf_get_lb_pblock(sb: iter->dir->i_sb, loc: &iter->eloc, |
140 | offset: iter->loffset + i); |
141 | tmp = sb_getblk(sb: iter->dir->i_sb, block: blk); |
142 | if (tmp && !buffer_uptodate(bh: tmp) && !buffer_locked(bh: tmp)) |
143 | bha[num++] = tmp; |
144 | else |
145 | brelse(bh: tmp); |
146 | } |
147 | if (num) { |
148 | bh_readahead_batch(nr: num, bhs: bha, REQ_RAHEAD); |
149 | for (i = 0; i < num; i++) |
150 | brelse(bh: bha[i]); |
151 | } |
152 | } |
153 | |
154 | static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter) |
155 | { |
156 | udf_pblk_t blk; |
157 | |
158 | udf_readahead_dir(iter); |
159 | blk = udf_get_lb_pblock(sb: iter->dir->i_sb, loc: &iter->eloc, offset: iter->loffset); |
160 | return sb_bread(sb: iter->dir->i_sb, block: blk); |
161 | } |
162 | |
163 | /* |
164 | * Updates loffset to point to next directory block; eloc, elen & epos are |
165 | * updated if we need to traverse to the next extent as well. |
166 | */ |
167 | static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) |
168 | { |
169 | iter->loffset++; |
170 | if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) |
171 | return 0; |
172 | |
173 | iter->loffset = 0; |
174 | if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) |
175 | != (EXT_RECORDED_ALLOCATED >> 30)) { |
176 | if (iter->pos == iter->dir->i_size) { |
177 | iter->elen = 0; |
178 | return 0; |
179 | } |
180 | udf_err(iter->dir->i_sb, |
181 | "extent after position %llu not allocated in directory (ino %lu)\n" , |
182 | (unsigned long long)iter->pos, iter->dir->i_ino); |
183 | return -EFSCORRUPTED; |
184 | } |
185 | return 0; |
186 | } |
187 | |
188 | static int udf_fiiter_load_bhs(struct udf_fileident_iter *iter) |
189 | { |
190 | int blksize = 1 << iter->dir->i_blkbits; |
191 | int off = iter->pos & (blksize - 1); |
192 | int err; |
193 | struct fileIdentDesc *fi; |
194 | |
195 | /* Is there any further extent we can map from? */ |
196 | if (!iter->bh[0] && iter->elen) { |
197 | iter->bh[0] = udf_fiiter_bread_blk(iter); |
198 | if (!iter->bh[0]) { |
199 | err = -ENOMEM; |
200 | goto out_brelse; |
201 | } |
202 | if (!buffer_uptodate(bh: iter->bh[0])) { |
203 | err = -EIO; |
204 | goto out_brelse; |
205 | } |
206 | } |
207 | /* There's no next block so we are done */ |
208 | if (iter->pos >= iter->dir->i_size) |
209 | return 0; |
210 | /* Need to fetch next block as well? */ |
211 | if (off + sizeof(struct fileIdentDesc) > blksize) |
212 | goto fetch_next; |
213 | fi = (struct fileIdentDesc *)(iter->bh[0]->b_data + off); |
214 | /* Need to fetch next block to get name? */ |
215 | if (off + udf_dir_entry_len(cfi: fi) > blksize) { |
216 | fetch_next: |
217 | err = udf_fiiter_advance_blk(iter); |
218 | if (err) |
219 | goto out_brelse; |
220 | iter->bh[1] = udf_fiiter_bread_blk(iter); |
221 | if (!iter->bh[1]) { |
222 | err = -ENOMEM; |
223 | goto out_brelse; |
224 | } |
225 | if (!buffer_uptodate(bh: iter->bh[1])) { |
226 | err = -EIO; |
227 | goto out_brelse; |
228 | } |
229 | } |
230 | return 0; |
231 | out_brelse: |
232 | brelse(bh: iter->bh[0]); |
233 | brelse(bh: iter->bh[1]); |
234 | iter->bh[0] = iter->bh[1] = NULL; |
235 | return err; |
236 | } |
237 | |
238 | int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, |
239 | loff_t pos) |
240 | { |
241 | struct udf_inode_info *iinfo = UDF_I(inode: dir); |
242 | int err = 0; |
243 | |
244 | iter->dir = dir; |
245 | iter->bh[0] = iter->bh[1] = NULL; |
246 | iter->pos = pos; |
247 | iter->elen = 0; |
248 | iter->epos.bh = NULL; |
249 | iter->name = NULL; |
250 | /* |
251 | * When directory is verified, we don't expect directory iteration to |
252 | * fail and it can be difficult to undo without corrupting filesystem. |
253 | * So just do not allow memory allocation failures here. |
254 | */ |
255 | iter->namebuf = kmalloc(UDF_NAME_LEN_CS0, GFP_KERNEL | __GFP_NOFAIL); |
256 | |
257 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
258 | err = udf_copy_fi(iter); |
259 | goto out; |
260 | } |
261 | |
262 | if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, |
263 | &iter->eloc, &iter->elen, &iter->loffset) != |
264 | (EXT_RECORDED_ALLOCATED >> 30)) { |
265 | if (pos == dir->i_size) |
266 | return 0; |
267 | udf_err(dir->i_sb, |
268 | "position %llu not allocated in directory (ino %lu)\n" , |
269 | (unsigned long long)pos, dir->i_ino); |
270 | err = -EFSCORRUPTED; |
271 | goto out; |
272 | } |
273 | err = udf_fiiter_load_bhs(iter); |
274 | if (err < 0) |
275 | goto out; |
276 | err = udf_copy_fi(iter); |
277 | out: |
278 | if (err < 0) |
279 | udf_fiiter_release(iter); |
280 | return err; |
281 | } |
282 | |
283 | int udf_fiiter_advance(struct udf_fileident_iter *iter) |
284 | { |
285 | unsigned int oldoff, len; |
286 | int blksize = 1 << iter->dir->i_blkbits; |
287 | int err; |
288 | |
289 | oldoff = iter->pos & (blksize - 1); |
290 | len = udf_dir_entry_len(cfi: &iter->fi); |
291 | iter->pos += len; |
292 | if (UDF_I(inode: iter->dir)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { |
293 | if (oldoff + len >= blksize) { |
294 | brelse(bh: iter->bh[0]); |
295 | iter->bh[0] = NULL; |
296 | /* Next block already loaded? */ |
297 | if (iter->bh[1]) { |
298 | iter->bh[0] = iter->bh[1]; |
299 | iter->bh[1] = NULL; |
300 | } else { |
301 | err = udf_fiiter_advance_blk(iter); |
302 | if (err < 0) |
303 | return err; |
304 | } |
305 | } |
306 | err = udf_fiiter_load_bhs(iter); |
307 | if (err < 0) |
308 | return err; |
309 | } |
310 | return udf_copy_fi(iter); |
311 | } |
312 | |
313 | void udf_fiiter_release(struct udf_fileident_iter *iter) |
314 | { |
315 | iter->dir = NULL; |
316 | brelse(bh: iter->bh[0]); |
317 | brelse(bh: iter->bh[1]); |
318 | iter->bh[0] = iter->bh[1] = NULL; |
319 | kfree(objp: iter->namebuf); |
320 | iter->namebuf = NULL; |
321 | } |
322 | |
323 | static void udf_copy_to_bufs(void *buf1, int len1, void *buf2, int len2, |
324 | int off, void *src, int len) |
325 | { |
326 | int copy; |
327 | |
328 | if (off >= len1) { |
329 | off -= len1; |
330 | } else { |
331 | copy = min(off + len, len1) - off; |
332 | memcpy(buf1 + off, src, copy); |
333 | src += copy; |
334 | len -= copy; |
335 | off = 0; |
336 | } |
337 | if (len > 0) { |
338 | if (WARN_ON_ONCE(off + len > len2 || !buf2)) |
339 | return; |
340 | memcpy(buf2 + off, src, len); |
341 | } |
342 | } |
343 | |
344 | static uint16_t udf_crc_fi_bufs(void *buf1, int len1, void *buf2, int len2, |
345 | int off, int len) |
346 | { |
347 | int copy; |
348 | uint16_t crc = 0; |
349 | |
350 | if (off >= len1) { |
351 | off -= len1; |
352 | } else { |
353 | copy = min(off + len, len1) - off; |
354 | crc = crc_itu_t(crc, buffer: buf1 + off, len: copy); |
355 | len -= copy; |
356 | off = 0; |
357 | } |
358 | if (len > 0) { |
359 | if (WARN_ON_ONCE(off + len > len2 || !buf2)) |
360 | return 0; |
361 | crc = crc_itu_t(crc, buffer: buf2 + off, len); |
362 | } |
363 | return crc; |
364 | } |
365 | |
366 | static void udf_copy_fi_to_bufs(char *buf1, int len1, char *buf2, int len2, |
367 | int off, struct fileIdentDesc *fi, |
368 | uint8_t *impuse, uint8_t *name) |
369 | { |
370 | uint16_t crc; |
371 | int fioff = off; |
372 | int crcoff = off + sizeof(struct tag); |
373 | unsigned int crclen = udf_dir_entry_len(cfi: fi) - sizeof(struct tag); |
374 | char zeros[UDF_NAME_PAD] = {}; |
375 | int endoff = off + udf_dir_entry_len(cfi: fi); |
376 | |
377 | udf_copy_to_bufs(buf1, len1, buf2, len2, off, src: fi, |
378 | len: sizeof(struct fileIdentDesc)); |
379 | off += sizeof(struct fileIdentDesc); |
380 | if (impuse) |
381 | udf_copy_to_bufs(buf1, len1, buf2, len2, off, src: impuse, |
382 | le16_to_cpu(fi->lengthOfImpUse)); |
383 | off += le16_to_cpu(fi->lengthOfImpUse); |
384 | if (name) { |
385 | udf_copy_to_bufs(buf1, len1, buf2, len2, off, src: name, |
386 | len: fi->lengthFileIdent); |
387 | off += fi->lengthFileIdent; |
388 | udf_copy_to_bufs(buf1, len1, buf2, len2, off, src: zeros, |
389 | len: endoff - off); |
390 | } |
391 | |
392 | crc = udf_crc_fi_bufs(buf1, len1, buf2, len2, off: crcoff, len: crclen); |
393 | fi->descTag.descCRC = cpu_to_le16(crc); |
394 | fi->descTag.descCRCLength = cpu_to_le16(crclen); |
395 | fi->descTag.tagChecksum = udf_tag_checksum(t: &fi->descTag); |
396 | |
397 | udf_copy_to_bufs(buf1, len1, buf2, len2, off: fioff, src: fi, len: sizeof(struct tag)); |
398 | } |
399 | |
400 | void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse) |
401 | { |
402 | struct udf_inode_info *iinfo = UDF_I(inode: iter->dir); |
403 | void *buf1, *buf2 = NULL; |
404 | int len1, len2 = 0, off; |
405 | int blksize = 1 << iter->dir->i_blkbits; |
406 | |
407 | off = iter->pos & (blksize - 1); |
408 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
409 | buf1 = iinfo->i_data + iinfo->i_lenEAttr; |
410 | len1 = iter->dir->i_size; |
411 | } else { |
412 | buf1 = iter->bh[0]->b_data; |
413 | len1 = blksize; |
414 | if (iter->bh[1]) { |
415 | buf2 = iter->bh[1]->b_data; |
416 | len2 = blksize; |
417 | } |
418 | } |
419 | |
420 | udf_copy_fi_to_bufs(buf1, len1, buf2, len2, off, fi: &iter->fi, impuse, |
421 | name: iter->name == iter->namebuf ? iter->name : NULL); |
422 | |
423 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
424 | mark_inode_dirty(inode: iter->dir); |
425 | } else { |
426 | mark_buffer_dirty_inode(bh: iter->bh[0], inode: iter->dir); |
427 | if (iter->bh[1]) |
428 | mark_buffer_dirty_inode(bh: iter->bh[1], inode: iter->dir); |
429 | } |
430 | inode_inc_iversion(inode: iter->dir); |
431 | } |
432 | |
433 | void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen) |
434 | { |
435 | struct udf_inode_info *iinfo = UDF_I(inode: iter->dir); |
436 | int diff = new_elen - iter->elen; |
437 | |
438 | /* Skip update when we already went past the last extent */ |
439 | if (!iter->elen) |
440 | return; |
441 | iter->elen = new_elen; |
442 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
443 | iter->epos.offset -= sizeof(struct short_ad); |
444 | else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) |
445 | iter->epos.offset -= sizeof(struct long_ad); |
446 | udf_write_aext(iter->dir, &iter->epos, &iter->eloc, iter->elen, 1); |
447 | iinfo->i_lenExtents += diff; |
448 | mark_inode_dirty(inode: iter->dir); |
449 | } |
450 | |
451 | /* Append new block to directory. @iter is expected to point at EOF */ |
452 | int udf_fiiter_append_blk(struct udf_fileident_iter *iter) |
453 | { |
454 | struct udf_inode_info *iinfo = UDF_I(inode: iter->dir); |
455 | int blksize = 1 << iter->dir->i_blkbits; |
456 | struct buffer_head *bh; |
457 | sector_t block; |
458 | uint32_t old_elen = iter->elen; |
459 | int err; |
460 | |
461 | if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)) |
462 | return -EINVAL; |
463 | |
464 | /* Round up last extent in the file */ |
465 | udf_fiiter_update_elen(iter, ALIGN(iter->elen, blksize)); |
466 | |
467 | /* Allocate new block and refresh mapping information */ |
468 | block = iinfo->i_lenExtents >> iter->dir->i_blkbits; |
469 | bh = udf_bread(inode: iter->dir, block, create: 1, err: &err); |
470 | if (!bh) { |
471 | udf_fiiter_update_elen(iter, new_elen: old_elen); |
472 | return err; |
473 | } |
474 | if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, |
475 | &iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) { |
476 | udf_err(iter->dir->i_sb, |
477 | "block %llu not allocated in directory (ino %lu)\n" , |
478 | (unsigned long long)block, iter->dir->i_ino); |
479 | return -EFSCORRUPTED; |
480 | } |
481 | if (!(iter->pos & (blksize - 1))) { |
482 | brelse(bh: iter->bh[0]); |
483 | iter->bh[0] = bh; |
484 | } else { |
485 | iter->bh[1] = bh; |
486 | } |
487 | return 0; |
488 | } |
489 | |
490 | struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, |
491 | int inc) |
492 | { |
493 | struct short_ad *sa; |
494 | |
495 | if ((!ptr) || (!offset)) { |
496 | pr_err("%s: invalidparms\n" , __func__); |
497 | return NULL; |
498 | } |
499 | |
500 | if ((*offset + sizeof(struct short_ad)) > maxoffset) |
501 | return NULL; |
502 | else { |
503 | sa = (struct short_ad *)ptr; |
504 | if (sa->extLength == 0) |
505 | return NULL; |
506 | } |
507 | |
508 | if (inc) |
509 | *offset += sizeof(struct short_ad); |
510 | return sa; |
511 | } |
512 | |
513 | struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc) |
514 | { |
515 | struct long_ad *la; |
516 | |
517 | if ((!ptr) || (!offset)) { |
518 | pr_err("%s: invalidparms\n" , __func__); |
519 | return NULL; |
520 | } |
521 | |
522 | if ((*offset + sizeof(struct long_ad)) > maxoffset) |
523 | return NULL; |
524 | else { |
525 | la = (struct long_ad *)ptr; |
526 | if (la->extLength == 0) |
527 | return NULL; |
528 | } |
529 | |
530 | if (inc) |
531 | *offset += sizeof(struct long_ad); |
532 | return la; |
533 | } |
534 | |