1*5ce34554SBagas 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); 98d16076d9SJan Kara len = min_t(int, 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 { 169d16076d9SJan Kara iter->loffset++; 1701ea1cd11SJan Kara if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) 171d16076d9SJan Kara return 0; 172d16076d9SJan Kara 173d16076d9SJan Kara iter->loffset = 0; 174d16076d9SJan Kara if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) 175d16076d9SJan Kara != (EXT_RECORDED_ALLOCATED >> 30)) { 176d16076d9SJan Kara if (iter->pos == iter->dir->i_size) { 177d16076d9SJan Kara iter->elen = 0; 178d16076d9SJan Kara return 0; 179d16076d9SJan Kara } 180d16076d9SJan Kara udf_err(iter->dir->i_sb, 181d16076d9SJan Kara "extent after position %llu not allocated in directory (ino %lu)\n", 182d16076d9SJan Kara (unsigned long long)iter->pos, iter->dir->i_ino); 183d16076d9SJan Kara return -EFSCORRUPTED; 184d16076d9SJan Kara } 185d16076d9SJan Kara return 0; 186d16076d9SJan Kara } 187d16076d9SJan Kara 188d16076d9SJan Kara static int udf_fiiter_load_bhs(struct udf_fileident_iter *iter) 189d16076d9SJan Kara { 190d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 191d16076d9SJan Kara int off = iter->pos & (blksize - 1); 192d16076d9SJan Kara int err; 193d16076d9SJan Kara struct fileIdentDesc *fi; 194d16076d9SJan Kara 195d16076d9SJan Kara /* Is there any further extent we can map from? */ 196d16076d9SJan Kara if (!iter->bh[0] && iter->elen) { 197d16076d9SJan Kara iter->bh[0] = udf_fiiter_bread_blk(iter); 198d16076d9SJan Kara if (!iter->bh[0]) { 199d16076d9SJan Kara err = -ENOMEM; 200d16076d9SJan Kara goto out_brelse; 201d16076d9SJan Kara } 202d16076d9SJan Kara if (!buffer_uptodate(iter->bh[0])) { 203d16076d9SJan Kara err = -EIO; 204d16076d9SJan Kara goto out_brelse; 205d16076d9SJan Kara } 206d16076d9SJan Kara } 207d16076d9SJan Kara /* There's no next block so we are done */ 208d16076d9SJan Kara if (iter->pos >= iter->dir->i_size) 209d16076d9SJan Kara return 0; 210d16076d9SJan Kara /* Need to fetch next block as well? */ 211d16076d9SJan Kara if (off + sizeof(struct fileIdentDesc) > blksize) 212d16076d9SJan Kara goto fetch_next; 213d16076d9SJan Kara fi = (struct fileIdentDesc *)(iter->bh[0]->b_data + off); 214d16076d9SJan Kara /* Need to fetch next block to get name? */ 215d16076d9SJan Kara if (off + udf_dir_entry_len(fi) > blksize) { 216d16076d9SJan Kara fetch_next: 217ee454ad2SJan Kara err = udf_fiiter_advance_blk(iter); 218ee454ad2SJan Kara if (err) 219ee454ad2SJan Kara goto out_brelse; 220d16076d9SJan Kara iter->bh[1] = udf_fiiter_bread_blk(iter); 221d16076d9SJan Kara if (!iter->bh[1]) { 222d16076d9SJan Kara err = -ENOMEM; 223d16076d9SJan Kara goto out_brelse; 224d16076d9SJan Kara } 225d16076d9SJan Kara if (!buffer_uptodate(iter->bh[1])) { 226d16076d9SJan Kara err = -EIO; 227d16076d9SJan Kara goto out_brelse; 228d16076d9SJan Kara } 229d16076d9SJan Kara } 230d16076d9SJan Kara return 0; 231d16076d9SJan Kara out_brelse: 232d16076d9SJan Kara brelse(iter->bh[0]); 233d16076d9SJan Kara brelse(iter->bh[1]); 234d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 235d16076d9SJan Kara return err; 236d16076d9SJan Kara } 237d16076d9SJan Kara 238d16076d9SJan Kara int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, 239d16076d9SJan Kara loff_t pos) 240d16076d9SJan Kara { 241d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(dir); 242d16076d9SJan Kara int err = 0; 243d16076d9SJan Kara 244d16076d9SJan Kara iter->dir = dir; 245d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 246d16076d9SJan Kara iter->pos = pos; 247d16076d9SJan Kara iter->elen = 0; 248d16076d9SJan Kara iter->epos.bh = NULL; 249d16076d9SJan Kara iter->name = NULL; 250df97f64dSJan Kara /* 251df97f64dSJan Kara * When directory is verified, we don't expect directory iteration to 252df97f64dSJan Kara * fail and it can be difficult to undo without corrupting filesystem. 253df97f64dSJan Kara * So just do not allow memory allocation failures here. 254df97f64dSJan Kara */ 255df97f64dSJan Kara iter->namebuf = kmalloc(UDF_NAME_LEN_CS0, GFP_KERNEL | __GFP_NOFAIL); 256d16076d9SJan Kara 2570aba4860SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 2580aba4860SJan Kara err = udf_copy_fi(iter); 2590aba4860SJan Kara goto out; 2600aba4860SJan Kara } 261d16076d9SJan Kara 262d16076d9SJan Kara if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, 263d16076d9SJan Kara &iter->eloc, &iter->elen, &iter->loffset) != 264d16076d9SJan Kara (EXT_RECORDED_ALLOCATED >> 30)) { 265d16076d9SJan Kara if (pos == dir->i_size) 266d16076d9SJan Kara return 0; 267d16076d9SJan Kara udf_err(dir->i_sb, 268d16076d9SJan Kara "position %llu not allocated in directory (ino %lu)\n", 269d16076d9SJan Kara (unsigned long long)pos, dir->i_ino); 2700aba4860SJan Kara err = -EFSCORRUPTED; 2710aba4860SJan Kara goto out; 272d16076d9SJan Kara } 273d16076d9SJan Kara err = udf_fiiter_load_bhs(iter); 274d16076d9SJan Kara if (err < 0) 2750aba4860SJan Kara goto out; 276d16076d9SJan Kara err = udf_copy_fi(iter); 2770aba4860SJan Kara out: 2780aba4860SJan Kara if (err < 0) 279d16076d9SJan Kara udf_fiiter_release(iter); 280d16076d9SJan Kara return err; 281d16076d9SJan Kara } 282d16076d9SJan Kara 283d16076d9SJan Kara int udf_fiiter_advance(struct udf_fileident_iter *iter) 284d16076d9SJan Kara { 285d16076d9SJan Kara unsigned int oldoff, len; 286d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 287d16076d9SJan Kara int err; 288d16076d9SJan Kara 289d16076d9SJan Kara oldoff = iter->pos & (blksize - 1); 290d16076d9SJan Kara len = udf_dir_entry_len(&iter->fi); 291d16076d9SJan Kara iter->pos += len; 292d16076d9SJan Kara if (UDF_I(iter->dir)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 293d16076d9SJan Kara if (oldoff + len >= blksize) { 294d16076d9SJan Kara brelse(iter->bh[0]); 295d16076d9SJan Kara iter->bh[0] = NULL; 296d16076d9SJan Kara /* Next block already loaded? */ 297d16076d9SJan Kara if (iter->bh[1]) { 298d16076d9SJan Kara iter->bh[0] = iter->bh[1]; 299d16076d9SJan Kara iter->bh[1] = NULL; 300d16076d9SJan Kara } else { 301ee454ad2SJan Kara err = udf_fiiter_advance_blk(iter); 302ee454ad2SJan Kara if (err < 0) 303ee454ad2SJan Kara return err; 304d16076d9SJan Kara } 305d16076d9SJan Kara } 306d16076d9SJan Kara err = udf_fiiter_load_bhs(iter); 307d16076d9SJan Kara if (err < 0) 308d16076d9SJan Kara return err; 309d16076d9SJan Kara } 310d16076d9SJan Kara return udf_copy_fi(iter); 311d16076d9SJan Kara } 312d16076d9SJan Kara 313d16076d9SJan Kara void udf_fiiter_release(struct udf_fileident_iter *iter) 314d16076d9SJan Kara { 315d16076d9SJan Kara iter->dir = NULL; 316d16076d9SJan Kara brelse(iter->bh[0]); 317d16076d9SJan Kara brelse(iter->bh[1]); 318d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 3190aba4860SJan Kara kfree(iter->namebuf); 3200aba4860SJan Kara iter->namebuf = NULL; 321d16076d9SJan Kara } 322d16076d9SJan Kara 323d16076d9SJan Kara static void udf_copy_to_bufs(void *buf1, int len1, void *buf2, int len2, 324d16076d9SJan Kara int off, void *src, int len) 325d16076d9SJan Kara { 326d16076d9SJan Kara int copy; 327d16076d9SJan Kara 328d16076d9SJan Kara if (off >= len1) { 329d16076d9SJan Kara off -= len1; 330d16076d9SJan Kara } else { 331d16076d9SJan Kara copy = min(off + len, len1) - off; 332d16076d9SJan Kara memcpy(buf1 + off, src, copy); 333d16076d9SJan Kara src += copy; 334d16076d9SJan Kara len -= copy; 335d16076d9SJan Kara off = 0; 336d16076d9SJan Kara } 337d16076d9SJan Kara if (len > 0) { 338d16076d9SJan Kara if (WARN_ON_ONCE(off + len > len2 || !buf2)) 339d16076d9SJan Kara return; 340d16076d9SJan Kara memcpy(buf2 + off, src, len); 341d16076d9SJan Kara } 342d16076d9SJan Kara } 343d16076d9SJan Kara 344d16076d9SJan Kara static uint16_t udf_crc_fi_bufs(void *buf1, int len1, void *buf2, int len2, 345d16076d9SJan Kara int off, int len) 346d16076d9SJan Kara { 347d16076d9SJan Kara int copy; 348d16076d9SJan Kara uint16_t crc = 0; 349d16076d9SJan Kara 350d16076d9SJan Kara if (off >= len1) { 351d16076d9SJan Kara off -= len1; 352d16076d9SJan Kara } else { 353d16076d9SJan Kara copy = min(off + len, len1) - off; 354d16076d9SJan Kara crc = crc_itu_t(crc, buf1 + off, copy); 355d16076d9SJan Kara len -= copy; 356d16076d9SJan Kara off = 0; 357d16076d9SJan Kara } 358d16076d9SJan Kara if (len > 0) { 359d16076d9SJan Kara if (WARN_ON_ONCE(off + len > len2 || !buf2)) 360d16076d9SJan Kara return 0; 361d16076d9SJan Kara crc = crc_itu_t(crc, buf2 + off, len); 362d16076d9SJan Kara } 363d16076d9SJan Kara return crc; 364d16076d9SJan Kara } 365d16076d9SJan Kara 366d16076d9SJan Kara static void udf_copy_fi_to_bufs(char *buf1, int len1, char *buf2, int len2, 367d16076d9SJan Kara int off, struct fileIdentDesc *fi, 368d16076d9SJan Kara uint8_t *impuse, uint8_t *name) 369d16076d9SJan Kara { 370d16076d9SJan Kara uint16_t crc; 371d16076d9SJan Kara int fioff = off; 372d16076d9SJan Kara int crcoff = off + sizeof(struct tag); 373d16076d9SJan Kara unsigned int crclen = udf_dir_entry_len(fi) - sizeof(struct tag); 3743bea4ae1SJan Kara char zeros[UDF_NAME_PAD] = {}; 3753bea4ae1SJan Kara int endoff = off + udf_dir_entry_len(fi); 376d16076d9SJan Kara 377d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, fi, 378d16076d9SJan Kara sizeof(struct fileIdentDesc)); 379d16076d9SJan Kara off += sizeof(struct fileIdentDesc); 380d16076d9SJan Kara if (impuse) 381d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, impuse, 382d16076d9SJan Kara le16_to_cpu(fi->lengthOfImpUse)); 383d16076d9SJan Kara off += le16_to_cpu(fi->lengthOfImpUse); 3843bea4ae1SJan Kara if (name) { 385d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, name, 386d16076d9SJan Kara fi->lengthFileIdent); 3873bea4ae1SJan Kara off += fi->lengthFileIdent; 3883bea4ae1SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, zeros, 3893bea4ae1SJan Kara endoff - off); 3903bea4ae1SJan Kara } 391d16076d9SJan Kara 392d16076d9SJan Kara crc = udf_crc_fi_bufs(buf1, len1, buf2, len2, crcoff, crclen); 393d16076d9SJan Kara fi->descTag.descCRC = cpu_to_le16(crc); 394d16076d9SJan Kara fi->descTag.descCRCLength = cpu_to_le16(crclen); 395d16076d9SJan Kara fi->descTag.tagChecksum = udf_tag_checksum(&fi->descTag); 396d16076d9SJan Kara 397d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, fioff, fi, sizeof(struct tag)); 398d16076d9SJan Kara } 399d16076d9SJan Kara 400d16076d9SJan Kara void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse) 401d16076d9SJan Kara { 402d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 403d16076d9SJan Kara void *buf1, *buf2 = NULL; 404d16076d9SJan Kara int len1, len2 = 0, off; 405d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 406d16076d9SJan Kara 407d16076d9SJan Kara off = iter->pos & (blksize - 1); 408d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 409d16076d9SJan Kara buf1 = iinfo->i_data + iinfo->i_lenEAttr; 410d16076d9SJan Kara len1 = iter->dir->i_size; 411d16076d9SJan Kara } else { 412d16076d9SJan Kara buf1 = iter->bh[0]->b_data; 413d16076d9SJan Kara len1 = blksize; 414d16076d9SJan Kara if (iter->bh[1]) { 415d16076d9SJan Kara buf2 = iter->bh[1]->b_data; 416d16076d9SJan Kara len2 = blksize; 417d16076d9SJan Kara } 418d16076d9SJan Kara } 419d16076d9SJan Kara 420d16076d9SJan Kara udf_copy_fi_to_bufs(buf1, len1, buf2, len2, off, &iter->fi, impuse, 421d16076d9SJan Kara iter->name == iter->namebuf ? iter->name : NULL); 422d16076d9SJan Kara 423d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 424d16076d9SJan Kara mark_inode_dirty(iter->dir); 425d16076d9SJan Kara } else { 426d16076d9SJan Kara mark_buffer_dirty_inode(iter->bh[0], iter->dir); 427d16076d9SJan Kara if (iter->bh[1]) 428d16076d9SJan Kara mark_buffer_dirty_inode(iter->bh[1], iter->dir); 429d16076d9SJan Kara } 430d16076d9SJan Kara inode_inc_iversion(iter->dir); 431d16076d9SJan Kara } 4321da177e4SLinus Torvalds 433f2844803SJan Kara void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen) 434f2844803SJan Kara { 435f2844803SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 436f2844803SJan Kara int diff = new_elen - iter->elen; 437f2844803SJan Kara 438f2844803SJan Kara /* Skip update when we already went past the last extent */ 439f2844803SJan Kara if (!iter->elen) 440f2844803SJan Kara return; 441f2844803SJan Kara iter->elen = new_elen; 442f2844803SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 443f2844803SJan Kara iter->epos.offset -= sizeof(struct short_ad); 444f2844803SJan Kara else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 445f2844803SJan Kara iter->epos.offset -= sizeof(struct long_ad); 446f2844803SJan Kara udf_write_aext(iter->dir, &iter->epos, &iter->eloc, iter->elen, 1); 447f2844803SJan Kara iinfo->i_lenExtents += diff; 448f2844803SJan Kara mark_inode_dirty(iter->dir); 449f2844803SJan Kara } 450f2844803SJan Kara 451f2844803SJan Kara /* Append new block to directory. @iter is expected to point at EOF */ 452f2844803SJan Kara int udf_fiiter_append_blk(struct udf_fileident_iter *iter) 453f2844803SJan Kara { 454f2844803SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 455f2844803SJan Kara int blksize = 1 << iter->dir->i_blkbits; 456f2844803SJan Kara struct buffer_head *bh; 457f2844803SJan Kara sector_t block; 458f2844803SJan Kara uint32_t old_elen = iter->elen; 459f2844803SJan Kara int err; 460f2844803SJan Kara 461f2844803SJan Kara if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)) 462f2844803SJan Kara return -EINVAL; 463f2844803SJan Kara 464f2844803SJan Kara /* Round up last extent in the file */ 465f2844803SJan Kara udf_fiiter_update_elen(iter, ALIGN(iter->elen, blksize)); 466f2844803SJan Kara 467f2844803SJan Kara /* Allocate new block and refresh mapping information */ 468f2844803SJan Kara block = iinfo->i_lenExtents >> iter->dir->i_blkbits; 469f2844803SJan Kara bh = udf_bread(iter->dir, block, 1, &err); 470f2844803SJan Kara if (!bh) { 471f2844803SJan Kara udf_fiiter_update_elen(iter, old_elen); 472f2844803SJan Kara return err; 473f2844803SJan Kara } 474f2844803SJan Kara if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, 475f2844803SJan Kara &iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) { 476f2844803SJan Kara udf_err(iter->dir->i_sb, 477f2844803SJan Kara "block %llu not allocated in directory (ino %lu)\n", 478f2844803SJan Kara (unsigned long long)block, iter->dir->i_ino); 479f2844803SJan Kara return -EFSCORRUPTED; 480f2844803SJan Kara } 481f2844803SJan Kara if (!(iter->pos & (blksize - 1))) { 482f2844803SJan Kara brelse(iter->bh[0]); 483f2844803SJan Kara iter->bh[0] = bh; 484f2844803SJan Kara } else { 485f2844803SJan Kara iter->bh[1] = bh; 486f2844803SJan Kara } 487f2844803SJan Kara return 0; 488f2844803SJan Kara } 489f2844803SJan Kara 4905ca4e4beSPekka Enberg struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, 491cb00ea35SCyrill Gorcunov int inc) 4921da177e4SLinus Torvalds { 4935ca4e4beSPekka Enberg struct short_ad *sa; 4941da177e4SLinus Torvalds 495cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 49678ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 4971da177e4SLinus Torvalds return NULL; 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds 5005ca4e4beSPekka Enberg if ((*offset + sizeof(struct short_ad)) > maxoffset) 5011da177e4SLinus Torvalds return NULL; 5024b11111aSMarcin Slusarz else { 5035ca4e4beSPekka Enberg sa = (struct short_ad *)ptr; 5044b11111aSMarcin Slusarz if (sa->extLength == 0) 5051da177e4SLinus Torvalds return NULL; 5064b11111aSMarcin Slusarz } 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds if (inc) 5095ca4e4beSPekka Enberg *offset += sizeof(struct short_ad); 5101da177e4SLinus Torvalds return sa; 5111da177e4SLinus Torvalds } 5121da177e4SLinus Torvalds 5135ca4e4beSPekka Enberg struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc) 5141da177e4SLinus Torvalds { 5155ca4e4beSPekka Enberg struct long_ad *la; 5161da177e4SLinus Torvalds 517cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 51878ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 5191da177e4SLinus Torvalds return NULL; 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds 5225ca4e4beSPekka Enberg if ((*offset + sizeof(struct long_ad)) > maxoffset) 5231da177e4SLinus Torvalds return NULL; 5244b11111aSMarcin Slusarz else { 5255ca4e4beSPekka Enberg la = (struct long_ad *)ptr; 5264b11111aSMarcin Slusarz if (la->extLength == 0) 5271da177e4SLinus Torvalds return NULL; 5284b11111aSMarcin Slusarz } 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds if (inc) 5315ca4e4beSPekka Enberg *offset += sizeof(struct long_ad); 5321da177e4SLinus Torvalds return la; 5331da177e4SLinus Torvalds } 534