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); 74d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 75d16076d9SJan Kara int err, off, len, nameoff; 76d16076d9SJan Kara 77d16076d9SJan Kara /* Skip copying when we are at EOF */ 78d16076d9SJan Kara if (iter->pos >= iter->dir->i_size) { 79d16076d9SJan Kara iter->name = NULL; 80d16076d9SJan Kara return 0; 81d16076d9SJan Kara } 82d16076d9SJan Kara if (iter->dir->i_size < iter->pos + sizeof(struct fileIdentDesc)) { 83d16076d9SJan Kara udf_err(iter->dir->i_sb, 84d16076d9SJan Kara "directory (ino %lu) has entry straddling EOF\n", 85d16076d9SJan Kara iter->dir->i_ino); 86d16076d9SJan Kara return -EFSCORRUPTED; 87d16076d9SJan Kara } 88d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 89d16076d9SJan Kara memcpy(&iter->fi, iinfo->i_data + iinfo->i_lenEAttr + iter->pos, 90d16076d9SJan Kara sizeof(struct fileIdentDesc)); 91d16076d9SJan Kara err = udf_verify_fi(iter); 92d16076d9SJan Kara if (err < 0) 93d16076d9SJan Kara return err; 94d16076d9SJan Kara iter->name = iinfo->i_data + iinfo->i_lenEAttr + iter->pos + 95d16076d9SJan Kara sizeof(struct fileIdentDesc) + 96d16076d9SJan Kara le16_to_cpu(iter->fi.lengthOfImpUse); 97d16076d9SJan Kara return 0; 98d16076d9SJan Kara } 99d16076d9SJan Kara 100d16076d9SJan Kara off = iter->pos & (blksize - 1); 101d16076d9SJan Kara len = min_t(int, sizeof(struct fileIdentDesc), blksize - off); 102d16076d9SJan Kara memcpy(&iter->fi, iter->bh[0]->b_data + off, len); 103d16076d9SJan Kara if (len < sizeof(struct fileIdentDesc)) 104d16076d9SJan Kara memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data, 105d16076d9SJan Kara sizeof(struct fileIdentDesc) - len); 106d16076d9SJan Kara err = udf_verify_fi(iter); 107d16076d9SJan Kara if (err < 0) 108d16076d9SJan Kara return err; 109d16076d9SJan Kara 110d16076d9SJan Kara /* Handle directory entry name */ 111d16076d9SJan Kara nameoff = off + sizeof(struct fileIdentDesc) + 112d16076d9SJan Kara le16_to_cpu(iter->fi.lengthOfImpUse); 113d16076d9SJan Kara if (off + udf_dir_entry_len(&iter->fi) <= blksize) { 114d16076d9SJan Kara iter->name = iter->bh[0]->b_data + nameoff; 115d16076d9SJan Kara } else if (nameoff >= blksize) { 116d16076d9SJan Kara iter->name = iter->bh[1]->b_data + (nameoff - blksize); 117d16076d9SJan Kara } else { 118d16076d9SJan Kara iter->name = iter->namebuf; 119d16076d9SJan Kara len = blksize - nameoff; 120d16076d9SJan Kara memcpy(iter->name, iter->bh[0]->b_data + nameoff, len); 121d16076d9SJan Kara memcpy(iter->name + len, iter->bh[1]->b_data, 122d16076d9SJan Kara iter->fi.lengthFileIdent - len); 123d16076d9SJan Kara } 124d16076d9SJan Kara return 0; 125d16076d9SJan Kara } 126d16076d9SJan Kara 127d16076d9SJan Kara /* Readahead 8k once we are at 8k boundary */ 128d16076d9SJan Kara static void udf_readahead_dir(struct udf_fileident_iter *iter) 129d16076d9SJan Kara { 130d16076d9SJan Kara unsigned int ralen = 16 >> (iter->dir->i_blkbits - 9); 131d16076d9SJan Kara struct buffer_head *tmp, *bha[16]; 132d16076d9SJan Kara int i, num; 133d16076d9SJan Kara udf_pblk_t blk; 134d16076d9SJan Kara 135d16076d9SJan Kara if (iter->loffset & (ralen - 1)) 136d16076d9SJan Kara return; 137d16076d9SJan Kara 138d16076d9SJan Kara if (iter->loffset + ralen > (iter->elen >> iter->dir->i_blkbits)) 139d16076d9SJan Kara ralen = (iter->elen >> iter->dir->i_blkbits) - iter->loffset; 140d16076d9SJan Kara num = 0; 141d16076d9SJan Kara for (i = 0; i < ralen; i++) { 142d16076d9SJan Kara blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc, 143d16076d9SJan Kara iter->loffset + i); 144d16076d9SJan Kara tmp = udf_tgetblk(iter->dir->i_sb, blk); 145d16076d9SJan Kara if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) 146d16076d9SJan Kara bha[num++] = tmp; 147d16076d9SJan Kara else 148d16076d9SJan Kara brelse(tmp); 149d16076d9SJan Kara } 150d16076d9SJan Kara if (num) { 151d16076d9SJan Kara bh_readahead_batch(num, bha, REQ_RAHEAD); 152d16076d9SJan Kara for (i = 0; i < num; i++) 153d16076d9SJan Kara brelse(bha[i]); 154d16076d9SJan Kara } 155d16076d9SJan Kara } 156d16076d9SJan Kara 157d16076d9SJan Kara static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter) 158d16076d9SJan Kara { 159d16076d9SJan Kara udf_pblk_t blk; 160d16076d9SJan Kara 161d16076d9SJan Kara udf_readahead_dir(iter); 162d16076d9SJan Kara blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc, iter->loffset); 163d16076d9SJan Kara return udf_tread(iter->dir->i_sb, blk); 164d16076d9SJan Kara } 165d16076d9SJan Kara 166d16076d9SJan Kara /* 167d16076d9SJan Kara * Updates loffset to point to next directory block; eloc, elen & epos are 168d16076d9SJan Kara * updated if we need to traverse to the next extent as well. 169d16076d9SJan Kara */ 170d16076d9SJan Kara static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) 171d16076d9SJan Kara { 172d16076d9SJan Kara iter->loffset++; 173d16076d9SJan Kara if (iter->loffset < iter->elen >> iter->dir->i_blkbits) 174d16076d9SJan Kara return 0; 175d16076d9SJan Kara 176d16076d9SJan Kara iter->loffset = 0; 177d16076d9SJan Kara if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) 178d16076d9SJan Kara != (EXT_RECORDED_ALLOCATED >> 30)) { 179d16076d9SJan Kara if (iter->pos == iter->dir->i_size) { 180d16076d9SJan Kara iter->elen = 0; 181d16076d9SJan Kara return 0; 182d16076d9SJan Kara } 183d16076d9SJan Kara udf_err(iter->dir->i_sb, 184d16076d9SJan Kara "extent after position %llu not allocated in directory (ino %lu)\n", 185d16076d9SJan Kara (unsigned long long)iter->pos, iter->dir->i_ino); 186d16076d9SJan Kara return -EFSCORRUPTED; 187d16076d9SJan Kara } 188d16076d9SJan Kara return 0; 189d16076d9SJan Kara } 190d16076d9SJan Kara 191d16076d9SJan Kara static int udf_fiiter_load_bhs(struct udf_fileident_iter *iter) 192d16076d9SJan Kara { 193d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 194d16076d9SJan Kara int off = iter->pos & (blksize - 1); 195d16076d9SJan Kara int err; 196d16076d9SJan Kara struct fileIdentDesc *fi; 197d16076d9SJan Kara 198d16076d9SJan Kara /* Is there any further extent we can map from? */ 199d16076d9SJan Kara if (!iter->bh[0] && iter->elen) { 200d16076d9SJan Kara iter->bh[0] = udf_fiiter_bread_blk(iter); 201d16076d9SJan Kara if (!iter->bh[0]) { 202d16076d9SJan Kara err = -ENOMEM; 203d16076d9SJan Kara goto out_brelse; 204d16076d9SJan Kara } 205d16076d9SJan Kara if (!buffer_uptodate(iter->bh[0])) { 206d16076d9SJan Kara err = -EIO; 207d16076d9SJan Kara goto out_brelse; 208d16076d9SJan Kara } 209d16076d9SJan Kara } 210d16076d9SJan Kara /* There's no next block so we are done */ 211d16076d9SJan Kara if (iter->pos >= iter->dir->i_size) 212d16076d9SJan Kara return 0; 213d16076d9SJan Kara /* Need to fetch next block as well? */ 214d16076d9SJan Kara if (off + sizeof(struct fileIdentDesc) > blksize) 215d16076d9SJan Kara goto fetch_next; 216d16076d9SJan Kara fi = (struct fileIdentDesc *)(iter->bh[0]->b_data + off); 217d16076d9SJan Kara /* Need to fetch next block to get name? */ 218d16076d9SJan Kara if (off + udf_dir_entry_len(fi) > blksize) { 219d16076d9SJan Kara fetch_next: 220*ee454ad2SJan Kara err = udf_fiiter_advance_blk(iter); 221*ee454ad2SJan Kara if (err) 222*ee454ad2SJan Kara goto out_brelse; 223d16076d9SJan Kara iter->bh[1] = udf_fiiter_bread_blk(iter); 224d16076d9SJan Kara if (!iter->bh[1]) { 225d16076d9SJan Kara err = -ENOMEM; 226d16076d9SJan Kara goto out_brelse; 227d16076d9SJan Kara } 228d16076d9SJan Kara if (!buffer_uptodate(iter->bh[1])) { 229d16076d9SJan Kara err = -EIO; 230d16076d9SJan Kara goto out_brelse; 231d16076d9SJan Kara } 232d16076d9SJan Kara } 233d16076d9SJan Kara return 0; 234d16076d9SJan Kara out_brelse: 235d16076d9SJan Kara brelse(iter->bh[0]); 236d16076d9SJan Kara brelse(iter->bh[1]); 237d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 238d16076d9SJan Kara return err; 239d16076d9SJan Kara } 240d16076d9SJan Kara 241d16076d9SJan Kara int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, 242d16076d9SJan Kara loff_t pos) 243d16076d9SJan Kara { 244d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(dir); 245d16076d9SJan Kara int err = 0; 246d16076d9SJan Kara 247d16076d9SJan Kara iter->dir = dir; 248d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 249d16076d9SJan Kara iter->pos = pos; 250d16076d9SJan Kara iter->elen = 0; 251d16076d9SJan Kara iter->epos.bh = NULL; 252d16076d9SJan Kara iter->name = NULL; 2530aba4860SJan Kara iter->namebuf = kmalloc(UDF_NAME_LEN_CS0, GFP_KERNEL); 2540aba4860SJan Kara if (!iter->namebuf) 2550aba4860SJan Kara return -ENOMEM; 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 { 301*ee454ad2SJan Kara err = udf_fiiter_advance_blk(iter); 302*ee454ad2SJan Kara if (err < 0) 303*ee454ad2SJan 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