11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * directory.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * PURPOSE 51da177e4SLinus Torvalds * Directory related functions 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * COPYRIGHT 81da177e4SLinus Torvalds * This file is distributed under the terms of the GNU General Public 91da177e4SLinus Torvalds * License (GPL). Copies of the GPL can be obtained from: 101da177e4SLinus Torvalds * ftp://prep.ai.mit.edu/pub/gnu/GPL 111da177e4SLinus Torvalds * Each contributing author retains all rights to their own work. 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include "udfdecl.h" 151da177e4SLinus Torvalds #include "udf_i.h" 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <linux/fs.h> 181da177e4SLinus Torvalds #include <linux/string.h> 192f8b5444SChristoph Hellwig #include <linux/bio.h> 20d16076d9SJan Kara #include <linux/crc-itu-t.h> 21d16076d9SJan Kara #include <linux/iversion.h> 22d16076d9SJan Kara 23d16076d9SJan Kara static int udf_verify_fi(struct udf_fileident_iter *iter) 24d16076d9SJan Kara { 25d16076d9SJan Kara unsigned int len; 26d16076d9SJan Kara 27d16076d9SJan Kara if (iter->fi.descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) { 28d16076d9SJan Kara udf_err(iter->dir->i_sb, 29d16076d9SJan Kara "directory (ino %lu) has entry at pos %llu with incorrect tag %x\n", 30d16076d9SJan Kara iter->dir->i_ino, (unsigned long long)iter->pos, 31d16076d9SJan Kara le16_to_cpu(iter->fi.descTag.tagIdent)); 32d16076d9SJan Kara return -EFSCORRUPTED; 33d16076d9SJan Kara } 34d16076d9SJan Kara len = udf_dir_entry_len(&iter->fi); 35d16076d9SJan Kara if (le16_to_cpu(iter->fi.lengthOfImpUse) & 3) { 36d16076d9SJan Kara udf_err(iter->dir->i_sb, 3702113feaSColin Ian King "directory (ino %lu) has entry at pos %llu with unaligned length of impUse field\n", 38d16076d9SJan Kara iter->dir->i_ino, (unsigned long long)iter->pos); 39d16076d9SJan Kara return -EFSCORRUPTED; 40d16076d9SJan Kara } 41d16076d9SJan Kara /* 42d16076d9SJan Kara * This is in fact allowed by the spec due to long impUse field but 43d16076d9SJan Kara * we don't support it. If there is real media with this large impUse 44d16076d9SJan Kara * field, support can be added. 45d16076d9SJan Kara */ 46d16076d9SJan Kara if (len > 1 << iter->dir->i_blkbits) { 47d16076d9SJan Kara udf_err(iter->dir->i_sb, 48d16076d9SJan Kara "directory (ino %lu) has too big (%u) entry at pos %llu\n", 49d16076d9SJan Kara iter->dir->i_ino, len, (unsigned long long)iter->pos); 50d16076d9SJan Kara return -EFSCORRUPTED; 51d16076d9SJan Kara } 52d16076d9SJan Kara if (iter->pos + len > iter->dir->i_size) { 53d16076d9SJan Kara udf_err(iter->dir->i_sb, 54d16076d9SJan Kara "directory (ino %lu) has entry past directory size at pos %llu\n", 55d16076d9SJan Kara iter->dir->i_ino, (unsigned long long)iter->pos); 56d16076d9SJan Kara return -EFSCORRUPTED; 57d16076d9SJan Kara } 58d16076d9SJan Kara if (udf_dir_entry_len(&iter->fi) != 59d16076d9SJan Kara sizeof(struct tag) + le16_to_cpu(iter->fi.descTag.descCRCLength)) { 60d16076d9SJan Kara udf_err(iter->dir->i_sb, 61d16076d9SJan Kara "directory (ino %lu) has entry where CRC length (%u) does not match entry length (%u)\n", 62d16076d9SJan Kara iter->dir->i_ino, 63d16076d9SJan Kara (unsigned)le16_to_cpu(iter->fi.descTag.descCRCLength), 64d16076d9SJan Kara (unsigned)(udf_dir_entry_len(&iter->fi) - 65d16076d9SJan Kara sizeof(struct tag))); 66d16076d9SJan Kara return -EFSCORRUPTED; 67d16076d9SJan Kara } 68d16076d9SJan Kara return 0; 69d16076d9SJan Kara } 70d16076d9SJan Kara 71d16076d9SJan Kara static int udf_copy_fi(struct udf_fileident_iter *iter) 72d16076d9SJan Kara { 73d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 7451e38c92SKees Cook u32 blksize = 1 << iter->dir->i_blkbits; 7551e38c92SKees Cook u32 off, len, nameoff; 7651e38c92SKees Cook int err; 77d16076d9SJan Kara 78d16076d9SJan Kara /* Skip copying when we are at EOF */ 79d16076d9SJan Kara if (iter->pos >= iter->dir->i_size) { 80d16076d9SJan Kara iter->name = NULL; 81d16076d9SJan Kara return 0; 82d16076d9SJan Kara } 83d16076d9SJan Kara if (iter->dir->i_size < iter->pos + sizeof(struct fileIdentDesc)) { 84d16076d9SJan Kara udf_err(iter->dir->i_sb, 85d16076d9SJan Kara "directory (ino %lu) has entry straddling EOF\n", 86d16076d9SJan Kara iter->dir->i_ino); 87d16076d9SJan Kara return -EFSCORRUPTED; 88d16076d9SJan Kara } 89d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 90d16076d9SJan Kara memcpy(&iter->fi, iinfo->i_data + iinfo->i_lenEAttr + iter->pos, 91d16076d9SJan Kara sizeof(struct fileIdentDesc)); 92d16076d9SJan Kara err = udf_verify_fi(iter); 93d16076d9SJan Kara if (err < 0) 94d16076d9SJan Kara return err; 95d16076d9SJan Kara iter->name = iinfo->i_data + iinfo->i_lenEAttr + iter->pos + 96d16076d9SJan Kara sizeof(struct fileIdentDesc) + 97d16076d9SJan Kara le16_to_cpu(iter->fi.lengthOfImpUse); 98d16076d9SJan Kara return 0; 99d16076d9SJan Kara } 100d16076d9SJan Kara 101d16076d9SJan Kara off = iter->pos & (blksize - 1); 102d16076d9SJan Kara len = min_t(int, sizeof(struct fileIdentDesc), blksize - off); 103d16076d9SJan Kara memcpy(&iter->fi, iter->bh[0]->b_data + off, len); 104d16076d9SJan Kara if (len < sizeof(struct fileIdentDesc)) 105d16076d9SJan Kara memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data, 106d16076d9SJan Kara sizeof(struct fileIdentDesc) - len); 107d16076d9SJan Kara err = udf_verify_fi(iter); 108d16076d9SJan Kara if (err < 0) 109d16076d9SJan Kara return err; 110d16076d9SJan Kara 111d16076d9SJan Kara /* Handle directory entry name */ 112d16076d9SJan Kara nameoff = off + sizeof(struct fileIdentDesc) + 113d16076d9SJan Kara le16_to_cpu(iter->fi.lengthOfImpUse); 114d16076d9SJan Kara if (off + udf_dir_entry_len(&iter->fi) <= blksize) { 115d16076d9SJan Kara iter->name = iter->bh[0]->b_data + nameoff; 116d16076d9SJan Kara } else if (nameoff >= blksize) { 117d16076d9SJan Kara iter->name = iter->bh[1]->b_data + (nameoff - blksize); 118d16076d9SJan Kara } else { 119d16076d9SJan Kara iter->name = iter->namebuf; 120d16076d9SJan Kara len = blksize - nameoff; 121d16076d9SJan Kara memcpy(iter->name, iter->bh[0]->b_data + nameoff, len); 122d16076d9SJan Kara memcpy(iter->name + len, iter->bh[1]->b_data, 123d16076d9SJan Kara iter->fi.lengthFileIdent - len); 124d16076d9SJan Kara } 125d16076d9SJan Kara return 0; 126d16076d9SJan Kara } 127d16076d9SJan Kara 128d16076d9SJan Kara /* Readahead 8k once we are at 8k boundary */ 129d16076d9SJan Kara static void udf_readahead_dir(struct udf_fileident_iter *iter) 130d16076d9SJan Kara { 131d16076d9SJan Kara unsigned int ralen = 16 >> (iter->dir->i_blkbits - 9); 132d16076d9SJan Kara struct buffer_head *tmp, *bha[16]; 133d16076d9SJan Kara int i, num; 134d16076d9SJan Kara udf_pblk_t blk; 135d16076d9SJan Kara 136d16076d9SJan Kara if (iter->loffset & (ralen - 1)) 137d16076d9SJan Kara return; 138d16076d9SJan Kara 139d16076d9SJan Kara if (iter->loffset + ralen > (iter->elen >> iter->dir->i_blkbits)) 140d16076d9SJan Kara ralen = (iter->elen >> iter->dir->i_blkbits) - iter->loffset; 141d16076d9SJan Kara num = 0; 142d16076d9SJan Kara for (i = 0; i < ralen; i++) { 143d16076d9SJan Kara blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc, 144d16076d9SJan Kara iter->loffset + i); 145101ee137SJan Kara tmp = sb_getblk(iter->dir->i_sb, blk); 146d16076d9SJan Kara if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) 147d16076d9SJan Kara bha[num++] = tmp; 148d16076d9SJan Kara else 149d16076d9SJan Kara brelse(tmp); 150d16076d9SJan Kara } 151d16076d9SJan Kara if (num) { 152d16076d9SJan Kara bh_readahead_batch(num, bha, REQ_RAHEAD); 153d16076d9SJan Kara for (i = 0; i < num; i++) 154d16076d9SJan Kara brelse(bha[i]); 155d16076d9SJan Kara } 156d16076d9SJan Kara } 157d16076d9SJan Kara 158d16076d9SJan Kara static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter) 159d16076d9SJan Kara { 160d16076d9SJan Kara udf_pblk_t blk; 161d16076d9SJan Kara 162d16076d9SJan Kara udf_readahead_dir(iter); 163d16076d9SJan Kara blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc, iter->loffset); 164101ee137SJan Kara return sb_bread(iter->dir->i_sb, blk); 165d16076d9SJan Kara } 166d16076d9SJan Kara 167d16076d9SJan Kara /* 168d16076d9SJan Kara * Updates loffset to point to next directory block; eloc, elen & epos are 169d16076d9SJan Kara * updated if we need to traverse to the next extent as well. 170d16076d9SJan Kara */ 171d16076d9SJan Kara static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) 172d16076d9SJan Kara { 173d16076d9SJan Kara iter->loffset++; 1741ea1cd11SJan Kara if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) 175d16076d9SJan Kara return 0; 176d16076d9SJan Kara 177d16076d9SJan Kara iter->loffset = 0; 178d16076d9SJan Kara if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) 179d16076d9SJan Kara != (EXT_RECORDED_ALLOCATED >> 30)) { 180d16076d9SJan Kara if (iter->pos == iter->dir->i_size) { 181d16076d9SJan Kara iter->elen = 0; 182d16076d9SJan Kara return 0; 183d16076d9SJan Kara } 184d16076d9SJan Kara udf_err(iter->dir->i_sb, 185d16076d9SJan Kara "extent after position %llu not allocated in directory (ino %lu)\n", 186d16076d9SJan Kara (unsigned long long)iter->pos, iter->dir->i_ino); 187d16076d9SJan Kara return -EFSCORRUPTED; 188d16076d9SJan Kara } 189d16076d9SJan Kara return 0; 190d16076d9SJan Kara } 191d16076d9SJan Kara 192d16076d9SJan Kara static int udf_fiiter_load_bhs(struct udf_fileident_iter *iter) 193d16076d9SJan Kara { 194d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 195d16076d9SJan Kara int off = iter->pos & (blksize - 1); 196d16076d9SJan Kara int err; 197d16076d9SJan Kara struct fileIdentDesc *fi; 198d16076d9SJan Kara 199d16076d9SJan Kara /* Is there any further extent we can map from? */ 200d16076d9SJan Kara if (!iter->bh[0] && iter->elen) { 201d16076d9SJan Kara iter->bh[0] = udf_fiiter_bread_blk(iter); 202d16076d9SJan Kara if (!iter->bh[0]) { 203d16076d9SJan Kara err = -ENOMEM; 204d16076d9SJan Kara goto out_brelse; 205d16076d9SJan Kara } 206d16076d9SJan Kara if (!buffer_uptodate(iter->bh[0])) { 207d16076d9SJan Kara err = -EIO; 208d16076d9SJan Kara goto out_brelse; 209d16076d9SJan Kara } 210d16076d9SJan Kara } 211d16076d9SJan Kara /* There's no next block so we are done */ 212d16076d9SJan Kara if (iter->pos >= iter->dir->i_size) 213d16076d9SJan Kara return 0; 214d16076d9SJan Kara /* Need to fetch next block as well? */ 215d16076d9SJan Kara if (off + sizeof(struct fileIdentDesc) > blksize) 216d16076d9SJan Kara goto fetch_next; 217d16076d9SJan Kara fi = (struct fileIdentDesc *)(iter->bh[0]->b_data + off); 218d16076d9SJan Kara /* Need to fetch next block to get name? */ 219d16076d9SJan Kara if (off + udf_dir_entry_len(fi) > blksize) { 220d16076d9SJan Kara fetch_next: 221ee454ad2SJan Kara err = udf_fiiter_advance_blk(iter); 222ee454ad2SJan Kara if (err) 223ee454ad2SJan Kara goto out_brelse; 224d16076d9SJan Kara iter->bh[1] = udf_fiiter_bread_blk(iter); 225d16076d9SJan Kara if (!iter->bh[1]) { 226d16076d9SJan Kara err = -ENOMEM; 227d16076d9SJan Kara goto out_brelse; 228d16076d9SJan Kara } 229d16076d9SJan Kara if (!buffer_uptodate(iter->bh[1])) { 230d16076d9SJan Kara err = -EIO; 231d16076d9SJan Kara goto out_brelse; 232d16076d9SJan Kara } 233d16076d9SJan Kara } 234d16076d9SJan Kara return 0; 235d16076d9SJan Kara out_brelse: 236d16076d9SJan Kara brelse(iter->bh[0]); 237d16076d9SJan Kara brelse(iter->bh[1]); 238d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 239d16076d9SJan Kara return err; 240d16076d9SJan Kara } 241d16076d9SJan Kara 242d16076d9SJan Kara int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, 243d16076d9SJan Kara loff_t pos) 244d16076d9SJan Kara { 245d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(dir); 246d16076d9SJan Kara int err = 0; 247d16076d9SJan Kara 248d16076d9SJan Kara iter->dir = dir; 249d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 250d16076d9SJan Kara iter->pos = pos; 251d16076d9SJan Kara iter->elen = 0; 252d16076d9SJan Kara iter->epos.bh = NULL; 253d16076d9SJan Kara iter->name = NULL; 254*df97f64dSJan Kara /* 255*df97f64dSJan Kara * When directory is verified, we don't expect directory iteration to 256*df97f64dSJan Kara * fail and it can be difficult to undo without corrupting filesystem. 257*df97f64dSJan Kara * So just do not allow memory allocation failures here. 258*df97f64dSJan Kara */ 259*df97f64dSJan Kara iter->namebuf = kmalloc(UDF_NAME_LEN_CS0, GFP_KERNEL | __GFP_NOFAIL); 260d16076d9SJan Kara 2610aba4860SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 2620aba4860SJan Kara err = udf_copy_fi(iter); 2630aba4860SJan Kara goto out; 2640aba4860SJan Kara } 265d16076d9SJan Kara 266d16076d9SJan Kara if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, 267d16076d9SJan Kara &iter->eloc, &iter->elen, &iter->loffset) != 268d16076d9SJan Kara (EXT_RECORDED_ALLOCATED >> 30)) { 269d16076d9SJan Kara if (pos == dir->i_size) 270d16076d9SJan Kara return 0; 271d16076d9SJan Kara udf_err(dir->i_sb, 272d16076d9SJan Kara "position %llu not allocated in directory (ino %lu)\n", 273d16076d9SJan Kara (unsigned long long)pos, dir->i_ino); 2740aba4860SJan Kara err = -EFSCORRUPTED; 2750aba4860SJan Kara goto out; 276d16076d9SJan Kara } 277d16076d9SJan Kara err = udf_fiiter_load_bhs(iter); 278d16076d9SJan Kara if (err < 0) 2790aba4860SJan Kara goto out; 280d16076d9SJan Kara err = udf_copy_fi(iter); 2810aba4860SJan Kara out: 2820aba4860SJan Kara if (err < 0) 283d16076d9SJan Kara udf_fiiter_release(iter); 284d16076d9SJan Kara return err; 285d16076d9SJan Kara } 286d16076d9SJan Kara 287d16076d9SJan Kara int udf_fiiter_advance(struct udf_fileident_iter *iter) 288d16076d9SJan Kara { 289d16076d9SJan Kara unsigned int oldoff, len; 290d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 291d16076d9SJan Kara int err; 292d16076d9SJan Kara 293d16076d9SJan Kara oldoff = iter->pos & (blksize - 1); 294d16076d9SJan Kara len = udf_dir_entry_len(&iter->fi); 295d16076d9SJan Kara iter->pos += len; 296d16076d9SJan Kara if (UDF_I(iter->dir)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 297d16076d9SJan Kara if (oldoff + len >= blksize) { 298d16076d9SJan Kara brelse(iter->bh[0]); 299d16076d9SJan Kara iter->bh[0] = NULL; 300d16076d9SJan Kara /* Next block already loaded? */ 301d16076d9SJan Kara if (iter->bh[1]) { 302d16076d9SJan Kara iter->bh[0] = iter->bh[1]; 303d16076d9SJan Kara iter->bh[1] = NULL; 304d16076d9SJan Kara } else { 305ee454ad2SJan Kara err = udf_fiiter_advance_blk(iter); 306ee454ad2SJan Kara if (err < 0) 307ee454ad2SJan Kara return err; 308d16076d9SJan Kara } 309d16076d9SJan Kara } 310d16076d9SJan Kara err = udf_fiiter_load_bhs(iter); 311d16076d9SJan Kara if (err < 0) 312d16076d9SJan Kara return err; 313d16076d9SJan Kara } 314d16076d9SJan Kara return udf_copy_fi(iter); 315d16076d9SJan Kara } 316d16076d9SJan Kara 317d16076d9SJan Kara void udf_fiiter_release(struct udf_fileident_iter *iter) 318d16076d9SJan Kara { 319d16076d9SJan Kara iter->dir = NULL; 320d16076d9SJan Kara brelse(iter->bh[0]); 321d16076d9SJan Kara brelse(iter->bh[1]); 322d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 3230aba4860SJan Kara kfree(iter->namebuf); 3240aba4860SJan Kara iter->namebuf = NULL; 325d16076d9SJan Kara } 326d16076d9SJan Kara 327d16076d9SJan Kara static void udf_copy_to_bufs(void *buf1, int len1, void *buf2, int len2, 328d16076d9SJan Kara int off, void *src, int len) 329d16076d9SJan Kara { 330d16076d9SJan Kara int copy; 331d16076d9SJan Kara 332d16076d9SJan Kara if (off >= len1) { 333d16076d9SJan Kara off -= len1; 334d16076d9SJan Kara } else { 335d16076d9SJan Kara copy = min(off + len, len1) - off; 336d16076d9SJan Kara memcpy(buf1 + off, src, copy); 337d16076d9SJan Kara src += copy; 338d16076d9SJan Kara len -= copy; 339d16076d9SJan Kara off = 0; 340d16076d9SJan Kara } 341d16076d9SJan Kara if (len > 0) { 342d16076d9SJan Kara if (WARN_ON_ONCE(off + len > len2 || !buf2)) 343d16076d9SJan Kara return; 344d16076d9SJan Kara memcpy(buf2 + off, src, len); 345d16076d9SJan Kara } 346d16076d9SJan Kara } 347d16076d9SJan Kara 348d16076d9SJan Kara static uint16_t udf_crc_fi_bufs(void *buf1, int len1, void *buf2, int len2, 349d16076d9SJan Kara int off, int len) 350d16076d9SJan Kara { 351d16076d9SJan Kara int copy; 352d16076d9SJan Kara uint16_t crc = 0; 353d16076d9SJan Kara 354d16076d9SJan Kara if (off >= len1) { 355d16076d9SJan Kara off -= len1; 356d16076d9SJan Kara } else { 357d16076d9SJan Kara copy = min(off + len, len1) - off; 358d16076d9SJan Kara crc = crc_itu_t(crc, buf1 + off, copy); 359d16076d9SJan Kara len -= copy; 360d16076d9SJan Kara off = 0; 361d16076d9SJan Kara } 362d16076d9SJan Kara if (len > 0) { 363d16076d9SJan Kara if (WARN_ON_ONCE(off + len > len2 || !buf2)) 364d16076d9SJan Kara return 0; 365d16076d9SJan Kara crc = crc_itu_t(crc, buf2 + off, len); 366d16076d9SJan Kara } 367d16076d9SJan Kara return crc; 368d16076d9SJan Kara } 369d16076d9SJan Kara 370d16076d9SJan Kara static void udf_copy_fi_to_bufs(char *buf1, int len1, char *buf2, int len2, 371d16076d9SJan Kara int off, struct fileIdentDesc *fi, 372d16076d9SJan Kara uint8_t *impuse, uint8_t *name) 373d16076d9SJan Kara { 374d16076d9SJan Kara uint16_t crc; 375d16076d9SJan Kara int fioff = off; 376d16076d9SJan Kara int crcoff = off + sizeof(struct tag); 377d16076d9SJan Kara unsigned int crclen = udf_dir_entry_len(fi) - sizeof(struct tag); 3783bea4ae1SJan Kara char zeros[UDF_NAME_PAD] = {}; 3793bea4ae1SJan Kara int endoff = off + udf_dir_entry_len(fi); 380d16076d9SJan Kara 381d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, fi, 382d16076d9SJan Kara sizeof(struct fileIdentDesc)); 383d16076d9SJan Kara off += sizeof(struct fileIdentDesc); 384d16076d9SJan Kara if (impuse) 385d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, impuse, 386d16076d9SJan Kara le16_to_cpu(fi->lengthOfImpUse)); 387d16076d9SJan Kara off += le16_to_cpu(fi->lengthOfImpUse); 3883bea4ae1SJan Kara if (name) { 389d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, name, 390d16076d9SJan Kara fi->lengthFileIdent); 3913bea4ae1SJan Kara off += fi->lengthFileIdent; 3923bea4ae1SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, zeros, 3933bea4ae1SJan Kara endoff - off); 3943bea4ae1SJan Kara } 395d16076d9SJan Kara 396d16076d9SJan Kara crc = udf_crc_fi_bufs(buf1, len1, buf2, len2, crcoff, crclen); 397d16076d9SJan Kara fi->descTag.descCRC = cpu_to_le16(crc); 398d16076d9SJan Kara fi->descTag.descCRCLength = cpu_to_le16(crclen); 399d16076d9SJan Kara fi->descTag.tagChecksum = udf_tag_checksum(&fi->descTag); 400d16076d9SJan Kara 401d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, fioff, fi, sizeof(struct tag)); 402d16076d9SJan Kara } 403d16076d9SJan Kara 404d16076d9SJan Kara void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse) 405d16076d9SJan Kara { 406d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 407d16076d9SJan Kara void *buf1, *buf2 = NULL; 408d16076d9SJan Kara int len1, len2 = 0, off; 409d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 410d16076d9SJan Kara 411d16076d9SJan Kara off = iter->pos & (blksize - 1); 412d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 413d16076d9SJan Kara buf1 = iinfo->i_data + iinfo->i_lenEAttr; 414d16076d9SJan Kara len1 = iter->dir->i_size; 415d16076d9SJan Kara } else { 416d16076d9SJan Kara buf1 = iter->bh[0]->b_data; 417d16076d9SJan Kara len1 = blksize; 418d16076d9SJan Kara if (iter->bh[1]) { 419d16076d9SJan Kara buf2 = iter->bh[1]->b_data; 420d16076d9SJan Kara len2 = blksize; 421d16076d9SJan Kara } 422d16076d9SJan Kara } 423d16076d9SJan Kara 424d16076d9SJan Kara udf_copy_fi_to_bufs(buf1, len1, buf2, len2, off, &iter->fi, impuse, 425d16076d9SJan Kara iter->name == iter->namebuf ? iter->name : NULL); 426d16076d9SJan Kara 427d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 428d16076d9SJan Kara mark_inode_dirty(iter->dir); 429d16076d9SJan Kara } else { 430d16076d9SJan Kara mark_buffer_dirty_inode(iter->bh[0], iter->dir); 431d16076d9SJan Kara if (iter->bh[1]) 432d16076d9SJan Kara mark_buffer_dirty_inode(iter->bh[1], iter->dir); 433d16076d9SJan Kara } 434d16076d9SJan Kara inode_inc_iversion(iter->dir); 435d16076d9SJan Kara } 4361da177e4SLinus Torvalds 437f2844803SJan Kara void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen) 438f2844803SJan Kara { 439f2844803SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 440f2844803SJan Kara int diff = new_elen - iter->elen; 441f2844803SJan Kara 442f2844803SJan Kara /* Skip update when we already went past the last extent */ 443f2844803SJan Kara if (!iter->elen) 444f2844803SJan Kara return; 445f2844803SJan Kara iter->elen = new_elen; 446f2844803SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 447f2844803SJan Kara iter->epos.offset -= sizeof(struct short_ad); 448f2844803SJan Kara else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 449f2844803SJan Kara iter->epos.offset -= sizeof(struct long_ad); 450f2844803SJan Kara udf_write_aext(iter->dir, &iter->epos, &iter->eloc, iter->elen, 1); 451f2844803SJan Kara iinfo->i_lenExtents += diff; 452f2844803SJan Kara mark_inode_dirty(iter->dir); 453f2844803SJan Kara } 454f2844803SJan Kara 455f2844803SJan Kara /* Append new block to directory. @iter is expected to point at EOF */ 456f2844803SJan Kara int udf_fiiter_append_blk(struct udf_fileident_iter *iter) 457f2844803SJan Kara { 458f2844803SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 459f2844803SJan Kara int blksize = 1 << iter->dir->i_blkbits; 460f2844803SJan Kara struct buffer_head *bh; 461f2844803SJan Kara sector_t block; 462f2844803SJan Kara uint32_t old_elen = iter->elen; 463f2844803SJan Kara int err; 464f2844803SJan Kara 465f2844803SJan Kara if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)) 466f2844803SJan Kara return -EINVAL; 467f2844803SJan Kara 468f2844803SJan Kara /* Round up last extent in the file */ 469f2844803SJan Kara udf_fiiter_update_elen(iter, ALIGN(iter->elen, blksize)); 470f2844803SJan Kara 471f2844803SJan Kara /* Allocate new block and refresh mapping information */ 472f2844803SJan Kara block = iinfo->i_lenExtents >> iter->dir->i_blkbits; 473f2844803SJan Kara bh = udf_bread(iter->dir, block, 1, &err); 474f2844803SJan Kara if (!bh) { 475f2844803SJan Kara udf_fiiter_update_elen(iter, old_elen); 476f2844803SJan Kara return err; 477f2844803SJan Kara } 478f2844803SJan Kara if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, 479f2844803SJan Kara &iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) { 480f2844803SJan Kara udf_err(iter->dir->i_sb, 481f2844803SJan Kara "block %llu not allocated in directory (ino %lu)\n", 482f2844803SJan Kara (unsigned long long)block, iter->dir->i_ino); 483f2844803SJan Kara return -EFSCORRUPTED; 484f2844803SJan Kara } 485f2844803SJan Kara if (!(iter->pos & (blksize - 1))) { 486f2844803SJan Kara brelse(iter->bh[0]); 487f2844803SJan Kara iter->bh[0] = bh; 488f2844803SJan Kara } else { 489f2844803SJan Kara iter->bh[1] = bh; 490f2844803SJan Kara } 491f2844803SJan Kara return 0; 492f2844803SJan Kara } 493f2844803SJan Kara 4945ca4e4beSPekka Enberg struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, 495cb00ea35SCyrill Gorcunov int inc) 4961da177e4SLinus Torvalds { 4975ca4e4beSPekka Enberg struct short_ad *sa; 4981da177e4SLinus Torvalds 499cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 50078ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 5011da177e4SLinus Torvalds return NULL; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5045ca4e4beSPekka Enberg if ((*offset + sizeof(struct short_ad)) > maxoffset) 5051da177e4SLinus Torvalds return NULL; 5064b11111aSMarcin Slusarz else { 5075ca4e4beSPekka Enberg sa = (struct short_ad *)ptr; 5084b11111aSMarcin Slusarz if (sa->extLength == 0) 5091da177e4SLinus Torvalds return NULL; 5104b11111aSMarcin Slusarz } 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds if (inc) 5135ca4e4beSPekka Enberg *offset += sizeof(struct short_ad); 5141da177e4SLinus Torvalds return sa; 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds 5175ca4e4beSPekka Enberg struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc) 5181da177e4SLinus Torvalds { 5195ca4e4beSPekka Enberg struct long_ad *la; 5201da177e4SLinus Torvalds 521cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 52278ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 5231da177e4SLinus Torvalds return NULL; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds 5265ca4e4beSPekka Enberg if ((*offset + sizeof(struct long_ad)) > maxoffset) 5271da177e4SLinus Torvalds return NULL; 5284b11111aSMarcin Slusarz else { 5295ca4e4beSPekka Enberg la = (struct long_ad *)ptr; 5304b11111aSMarcin Slusarz if (la->extLength == 0) 5311da177e4SLinus Torvalds return NULL; 5324b11111aSMarcin Slusarz } 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds if (inc) 5355ca4e4beSPekka Enberg *offset += sizeof(struct long_ad); 5361da177e4SLinus Torvalds return la; 5371da177e4SLinus Torvalds } 538