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