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> 20*d16076d9SJan Kara #include <linux/crc-itu-t.h> 21*d16076d9SJan Kara #include <linux/iversion.h> 22*d16076d9SJan Kara 23*d16076d9SJan Kara static int udf_verify_fi(struct udf_fileident_iter *iter) 24*d16076d9SJan Kara { 25*d16076d9SJan Kara unsigned int len; 26*d16076d9SJan Kara 27*d16076d9SJan Kara if (iter->fi.descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) { 28*d16076d9SJan Kara udf_err(iter->dir->i_sb, 29*d16076d9SJan Kara "directory (ino %lu) has entry at pos %llu with incorrect tag %x\n", 30*d16076d9SJan Kara iter->dir->i_ino, (unsigned long long)iter->pos, 31*d16076d9SJan Kara le16_to_cpu(iter->fi.descTag.tagIdent)); 32*d16076d9SJan Kara return -EFSCORRUPTED; 33*d16076d9SJan Kara } 34*d16076d9SJan Kara len = udf_dir_entry_len(&iter->fi); 35*d16076d9SJan Kara if (le16_to_cpu(iter->fi.lengthOfImpUse) & 3) { 36*d16076d9SJan Kara udf_err(iter->dir->i_sb, 37*d16076d9SJan Kara "directory (ino %lu) has entry at pos %llu with unaligned lenght of impUse field\n", 38*d16076d9SJan Kara iter->dir->i_ino, (unsigned long long)iter->pos); 39*d16076d9SJan Kara return -EFSCORRUPTED; 40*d16076d9SJan Kara } 41*d16076d9SJan Kara /* 42*d16076d9SJan Kara * This is in fact allowed by the spec due to long impUse field but 43*d16076d9SJan Kara * we don't support it. If there is real media with this large impUse 44*d16076d9SJan Kara * field, support can be added. 45*d16076d9SJan Kara */ 46*d16076d9SJan Kara if (len > 1 << iter->dir->i_blkbits) { 47*d16076d9SJan Kara udf_err(iter->dir->i_sb, 48*d16076d9SJan Kara "directory (ino %lu) has too big (%u) entry at pos %llu\n", 49*d16076d9SJan Kara iter->dir->i_ino, len, (unsigned long long)iter->pos); 50*d16076d9SJan Kara return -EFSCORRUPTED; 51*d16076d9SJan Kara } 52*d16076d9SJan Kara if (iter->pos + len > iter->dir->i_size) { 53*d16076d9SJan Kara udf_err(iter->dir->i_sb, 54*d16076d9SJan Kara "directory (ino %lu) has entry past directory size at pos %llu\n", 55*d16076d9SJan Kara iter->dir->i_ino, (unsigned long long)iter->pos); 56*d16076d9SJan Kara return -EFSCORRUPTED; 57*d16076d9SJan Kara } 58*d16076d9SJan Kara if (udf_dir_entry_len(&iter->fi) != 59*d16076d9SJan Kara sizeof(struct tag) + le16_to_cpu(iter->fi.descTag.descCRCLength)) { 60*d16076d9SJan Kara udf_err(iter->dir->i_sb, 61*d16076d9SJan Kara "directory (ino %lu) has entry where CRC length (%u) does not match entry length (%u)\n", 62*d16076d9SJan Kara iter->dir->i_ino, 63*d16076d9SJan Kara (unsigned)le16_to_cpu(iter->fi.descTag.descCRCLength), 64*d16076d9SJan Kara (unsigned)(udf_dir_entry_len(&iter->fi) - 65*d16076d9SJan Kara sizeof(struct tag))); 66*d16076d9SJan Kara return -EFSCORRUPTED; 67*d16076d9SJan Kara } 68*d16076d9SJan Kara return 0; 69*d16076d9SJan Kara } 70*d16076d9SJan Kara 71*d16076d9SJan Kara static int udf_copy_fi(struct udf_fileident_iter *iter) 72*d16076d9SJan Kara { 73*d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 74*d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 75*d16076d9SJan Kara int err, off, len, nameoff; 76*d16076d9SJan Kara 77*d16076d9SJan Kara /* Skip copying when we are at EOF */ 78*d16076d9SJan Kara if (iter->pos >= iter->dir->i_size) { 79*d16076d9SJan Kara iter->name = NULL; 80*d16076d9SJan Kara return 0; 81*d16076d9SJan Kara } 82*d16076d9SJan Kara if (iter->dir->i_size < iter->pos + sizeof(struct fileIdentDesc)) { 83*d16076d9SJan Kara udf_err(iter->dir->i_sb, 84*d16076d9SJan Kara "directory (ino %lu) has entry straddling EOF\n", 85*d16076d9SJan Kara iter->dir->i_ino); 86*d16076d9SJan Kara return -EFSCORRUPTED; 87*d16076d9SJan Kara } 88*d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 89*d16076d9SJan Kara memcpy(&iter->fi, iinfo->i_data + iinfo->i_lenEAttr + iter->pos, 90*d16076d9SJan Kara sizeof(struct fileIdentDesc)); 91*d16076d9SJan Kara err = udf_verify_fi(iter); 92*d16076d9SJan Kara if (err < 0) 93*d16076d9SJan Kara return err; 94*d16076d9SJan Kara iter->name = iinfo->i_data + iinfo->i_lenEAttr + iter->pos + 95*d16076d9SJan Kara sizeof(struct fileIdentDesc) + 96*d16076d9SJan Kara le16_to_cpu(iter->fi.lengthOfImpUse); 97*d16076d9SJan Kara return 0; 98*d16076d9SJan Kara } 99*d16076d9SJan Kara 100*d16076d9SJan Kara off = iter->pos & (blksize - 1); 101*d16076d9SJan Kara len = min_t(int, sizeof(struct fileIdentDesc), blksize - off); 102*d16076d9SJan Kara memcpy(&iter->fi, iter->bh[0]->b_data + off, len); 103*d16076d9SJan Kara if (len < sizeof(struct fileIdentDesc)) 104*d16076d9SJan Kara memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data, 105*d16076d9SJan Kara sizeof(struct fileIdentDesc) - len); 106*d16076d9SJan Kara err = udf_verify_fi(iter); 107*d16076d9SJan Kara if (err < 0) 108*d16076d9SJan Kara return err; 109*d16076d9SJan Kara 110*d16076d9SJan Kara /* Handle directory entry name */ 111*d16076d9SJan Kara nameoff = off + sizeof(struct fileIdentDesc) + 112*d16076d9SJan Kara le16_to_cpu(iter->fi.lengthOfImpUse); 113*d16076d9SJan Kara if (off + udf_dir_entry_len(&iter->fi) <= blksize) { 114*d16076d9SJan Kara iter->name = iter->bh[0]->b_data + nameoff; 115*d16076d9SJan Kara } else if (nameoff >= blksize) { 116*d16076d9SJan Kara iter->name = iter->bh[1]->b_data + (nameoff - blksize); 117*d16076d9SJan Kara } else { 118*d16076d9SJan Kara iter->name = iter->namebuf; 119*d16076d9SJan Kara len = blksize - nameoff; 120*d16076d9SJan Kara memcpy(iter->name, iter->bh[0]->b_data + nameoff, len); 121*d16076d9SJan Kara memcpy(iter->name + len, iter->bh[1]->b_data, 122*d16076d9SJan Kara iter->fi.lengthFileIdent - len); 123*d16076d9SJan Kara } 124*d16076d9SJan Kara return 0; 125*d16076d9SJan Kara } 126*d16076d9SJan Kara 127*d16076d9SJan Kara /* Readahead 8k once we are at 8k boundary */ 128*d16076d9SJan Kara static void udf_readahead_dir(struct udf_fileident_iter *iter) 129*d16076d9SJan Kara { 130*d16076d9SJan Kara unsigned int ralen = 16 >> (iter->dir->i_blkbits - 9); 131*d16076d9SJan Kara struct buffer_head *tmp, *bha[16]; 132*d16076d9SJan Kara int i, num; 133*d16076d9SJan Kara udf_pblk_t blk; 134*d16076d9SJan Kara 135*d16076d9SJan Kara if (iter->loffset & (ralen - 1)) 136*d16076d9SJan Kara return; 137*d16076d9SJan Kara 138*d16076d9SJan Kara if (iter->loffset + ralen > (iter->elen >> iter->dir->i_blkbits)) 139*d16076d9SJan Kara ralen = (iter->elen >> iter->dir->i_blkbits) - iter->loffset; 140*d16076d9SJan Kara num = 0; 141*d16076d9SJan Kara for (i = 0; i < ralen; i++) { 142*d16076d9SJan Kara blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc, 143*d16076d9SJan Kara iter->loffset + i); 144*d16076d9SJan Kara tmp = udf_tgetblk(iter->dir->i_sb, blk); 145*d16076d9SJan Kara if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) 146*d16076d9SJan Kara bha[num++] = tmp; 147*d16076d9SJan Kara else 148*d16076d9SJan Kara brelse(tmp); 149*d16076d9SJan Kara } 150*d16076d9SJan Kara if (num) { 151*d16076d9SJan Kara bh_readahead_batch(num, bha, REQ_RAHEAD); 152*d16076d9SJan Kara for (i = 0; i < num; i++) 153*d16076d9SJan Kara brelse(bha[i]); 154*d16076d9SJan Kara } 155*d16076d9SJan Kara } 156*d16076d9SJan Kara 157*d16076d9SJan Kara static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter) 158*d16076d9SJan Kara { 159*d16076d9SJan Kara udf_pblk_t blk; 160*d16076d9SJan Kara 161*d16076d9SJan Kara udf_readahead_dir(iter); 162*d16076d9SJan Kara blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc, iter->loffset); 163*d16076d9SJan Kara return udf_tread(iter->dir->i_sb, blk); 164*d16076d9SJan Kara } 165*d16076d9SJan Kara 166*d16076d9SJan Kara /* 167*d16076d9SJan Kara * Updates loffset to point to next directory block; eloc, elen & epos are 168*d16076d9SJan Kara * updated if we need to traverse to the next extent as well. 169*d16076d9SJan Kara */ 170*d16076d9SJan Kara static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) 171*d16076d9SJan Kara { 172*d16076d9SJan Kara iter->loffset++; 173*d16076d9SJan Kara if (iter->loffset < iter->elen >> iter->dir->i_blkbits) 174*d16076d9SJan Kara return 0; 175*d16076d9SJan Kara 176*d16076d9SJan Kara iter->loffset = 0; 177*d16076d9SJan Kara if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) 178*d16076d9SJan Kara != (EXT_RECORDED_ALLOCATED >> 30)) { 179*d16076d9SJan Kara if (iter->pos == iter->dir->i_size) { 180*d16076d9SJan Kara iter->elen = 0; 181*d16076d9SJan Kara return 0; 182*d16076d9SJan Kara } 183*d16076d9SJan Kara udf_err(iter->dir->i_sb, 184*d16076d9SJan Kara "extent after position %llu not allocated in directory (ino %lu)\n", 185*d16076d9SJan Kara (unsigned long long)iter->pos, iter->dir->i_ino); 186*d16076d9SJan Kara return -EFSCORRUPTED; 187*d16076d9SJan Kara } 188*d16076d9SJan Kara return 0; 189*d16076d9SJan Kara } 190*d16076d9SJan Kara 191*d16076d9SJan Kara static int udf_fiiter_load_bhs(struct udf_fileident_iter *iter) 192*d16076d9SJan Kara { 193*d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 194*d16076d9SJan Kara int off = iter->pos & (blksize - 1); 195*d16076d9SJan Kara int err; 196*d16076d9SJan Kara struct fileIdentDesc *fi; 197*d16076d9SJan Kara 198*d16076d9SJan Kara /* Is there any further extent we can map from? */ 199*d16076d9SJan Kara if (!iter->bh[0] && iter->elen) { 200*d16076d9SJan Kara iter->bh[0] = udf_fiiter_bread_blk(iter); 201*d16076d9SJan Kara if (!iter->bh[0]) { 202*d16076d9SJan Kara err = -ENOMEM; 203*d16076d9SJan Kara goto out_brelse; 204*d16076d9SJan Kara } 205*d16076d9SJan Kara if (!buffer_uptodate(iter->bh[0])) { 206*d16076d9SJan Kara err = -EIO; 207*d16076d9SJan Kara goto out_brelse; 208*d16076d9SJan Kara } 209*d16076d9SJan Kara } 210*d16076d9SJan Kara /* There's no next block so we are done */ 211*d16076d9SJan Kara if (iter->pos >= iter->dir->i_size) 212*d16076d9SJan Kara return 0; 213*d16076d9SJan Kara /* Need to fetch next block as well? */ 214*d16076d9SJan Kara if (off + sizeof(struct fileIdentDesc) > blksize) 215*d16076d9SJan Kara goto fetch_next; 216*d16076d9SJan Kara fi = (struct fileIdentDesc *)(iter->bh[0]->b_data + off); 217*d16076d9SJan Kara /* Need to fetch next block to get name? */ 218*d16076d9SJan Kara if (off + udf_dir_entry_len(fi) > blksize) { 219*d16076d9SJan Kara fetch_next: 220*d16076d9SJan Kara udf_fiiter_advance_blk(iter); 221*d16076d9SJan Kara iter->bh[1] = udf_fiiter_bread_blk(iter); 222*d16076d9SJan Kara if (!iter->bh[1]) { 223*d16076d9SJan Kara err = -ENOMEM; 224*d16076d9SJan Kara goto out_brelse; 225*d16076d9SJan Kara } 226*d16076d9SJan Kara if (!buffer_uptodate(iter->bh[1])) { 227*d16076d9SJan Kara err = -EIO; 228*d16076d9SJan Kara goto out_brelse; 229*d16076d9SJan Kara } 230*d16076d9SJan Kara } 231*d16076d9SJan Kara return 0; 232*d16076d9SJan Kara out_brelse: 233*d16076d9SJan Kara brelse(iter->bh[0]); 234*d16076d9SJan Kara brelse(iter->bh[1]); 235*d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 236*d16076d9SJan Kara return err; 237*d16076d9SJan Kara } 238*d16076d9SJan Kara 239*d16076d9SJan Kara int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, 240*d16076d9SJan Kara loff_t pos) 241*d16076d9SJan Kara { 242*d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(dir); 243*d16076d9SJan Kara int err = 0; 244*d16076d9SJan Kara 245*d16076d9SJan Kara iter->dir = dir; 246*d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 247*d16076d9SJan Kara iter->pos = pos; 248*d16076d9SJan Kara iter->elen = 0; 249*d16076d9SJan Kara iter->epos.bh = NULL; 250*d16076d9SJan Kara iter->name = NULL; 251*d16076d9SJan Kara 252*d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 253*d16076d9SJan Kara return udf_copy_fi(iter); 254*d16076d9SJan Kara 255*d16076d9SJan Kara if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, 256*d16076d9SJan Kara &iter->eloc, &iter->elen, &iter->loffset) != 257*d16076d9SJan Kara (EXT_RECORDED_ALLOCATED >> 30)) { 258*d16076d9SJan Kara if (pos == dir->i_size) 259*d16076d9SJan Kara return 0; 260*d16076d9SJan Kara udf_err(dir->i_sb, 261*d16076d9SJan Kara "position %llu not allocated in directory (ino %lu)\n", 262*d16076d9SJan Kara (unsigned long long)pos, dir->i_ino); 263*d16076d9SJan Kara return -EFSCORRUPTED; 264*d16076d9SJan Kara } 265*d16076d9SJan Kara err = udf_fiiter_load_bhs(iter); 266*d16076d9SJan Kara if (err < 0) 267*d16076d9SJan Kara return err; 268*d16076d9SJan Kara err = udf_copy_fi(iter); 269*d16076d9SJan Kara if (err < 0) { 270*d16076d9SJan Kara udf_fiiter_release(iter); 271*d16076d9SJan Kara return err; 272*d16076d9SJan Kara } 273*d16076d9SJan Kara return 0; 274*d16076d9SJan Kara } 275*d16076d9SJan Kara 276*d16076d9SJan Kara int udf_fiiter_advance(struct udf_fileident_iter *iter) 277*d16076d9SJan Kara { 278*d16076d9SJan Kara unsigned int oldoff, len; 279*d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 280*d16076d9SJan Kara int err; 281*d16076d9SJan Kara 282*d16076d9SJan Kara oldoff = iter->pos & (blksize - 1); 283*d16076d9SJan Kara len = udf_dir_entry_len(&iter->fi); 284*d16076d9SJan Kara iter->pos += len; 285*d16076d9SJan Kara if (UDF_I(iter->dir)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 286*d16076d9SJan Kara if (oldoff + len >= blksize) { 287*d16076d9SJan Kara brelse(iter->bh[0]); 288*d16076d9SJan Kara iter->bh[0] = NULL; 289*d16076d9SJan Kara /* Next block already loaded? */ 290*d16076d9SJan Kara if (iter->bh[1]) { 291*d16076d9SJan Kara iter->bh[0] = iter->bh[1]; 292*d16076d9SJan Kara iter->bh[1] = NULL; 293*d16076d9SJan Kara } else { 294*d16076d9SJan Kara udf_fiiter_advance_blk(iter); 295*d16076d9SJan Kara } 296*d16076d9SJan Kara } 297*d16076d9SJan Kara err = udf_fiiter_load_bhs(iter); 298*d16076d9SJan Kara if (err < 0) 299*d16076d9SJan Kara return err; 300*d16076d9SJan Kara } 301*d16076d9SJan Kara return udf_copy_fi(iter); 302*d16076d9SJan Kara } 303*d16076d9SJan Kara 304*d16076d9SJan Kara void udf_fiiter_release(struct udf_fileident_iter *iter) 305*d16076d9SJan Kara { 306*d16076d9SJan Kara iter->dir = NULL; 307*d16076d9SJan Kara brelse(iter->bh[0]); 308*d16076d9SJan Kara brelse(iter->bh[1]); 309*d16076d9SJan Kara iter->bh[0] = iter->bh[1] = NULL; 310*d16076d9SJan Kara } 311*d16076d9SJan Kara 312*d16076d9SJan Kara static void udf_copy_to_bufs(void *buf1, int len1, void *buf2, int len2, 313*d16076d9SJan Kara int off, void *src, int len) 314*d16076d9SJan Kara { 315*d16076d9SJan Kara int copy; 316*d16076d9SJan Kara 317*d16076d9SJan Kara if (off >= len1) { 318*d16076d9SJan Kara off -= len1; 319*d16076d9SJan Kara } else { 320*d16076d9SJan Kara copy = min(off + len, len1) - off; 321*d16076d9SJan Kara memcpy(buf1 + off, src, copy); 322*d16076d9SJan Kara src += copy; 323*d16076d9SJan Kara len -= copy; 324*d16076d9SJan Kara off = 0; 325*d16076d9SJan Kara } 326*d16076d9SJan Kara if (len > 0) { 327*d16076d9SJan Kara if (WARN_ON_ONCE(off + len > len2 || !buf2)) 328*d16076d9SJan Kara return; 329*d16076d9SJan Kara memcpy(buf2 + off, src, len); 330*d16076d9SJan Kara } 331*d16076d9SJan Kara } 332*d16076d9SJan Kara 333*d16076d9SJan Kara static uint16_t udf_crc_fi_bufs(void *buf1, int len1, void *buf2, int len2, 334*d16076d9SJan Kara int off, int len) 335*d16076d9SJan Kara { 336*d16076d9SJan Kara int copy; 337*d16076d9SJan Kara uint16_t crc = 0; 338*d16076d9SJan Kara 339*d16076d9SJan Kara if (off >= len1) { 340*d16076d9SJan Kara off -= len1; 341*d16076d9SJan Kara } else { 342*d16076d9SJan Kara copy = min(off + len, len1) - off; 343*d16076d9SJan Kara crc = crc_itu_t(crc, buf1 + off, copy); 344*d16076d9SJan Kara len -= copy; 345*d16076d9SJan Kara off = 0; 346*d16076d9SJan Kara } 347*d16076d9SJan Kara if (len > 0) { 348*d16076d9SJan Kara if (WARN_ON_ONCE(off + len > len2 || !buf2)) 349*d16076d9SJan Kara return 0; 350*d16076d9SJan Kara crc = crc_itu_t(crc, buf2 + off, len); 351*d16076d9SJan Kara } 352*d16076d9SJan Kara return crc; 353*d16076d9SJan Kara } 354*d16076d9SJan Kara 355*d16076d9SJan Kara static void udf_copy_fi_to_bufs(char *buf1, int len1, char *buf2, int len2, 356*d16076d9SJan Kara int off, struct fileIdentDesc *fi, 357*d16076d9SJan Kara uint8_t *impuse, uint8_t *name) 358*d16076d9SJan Kara { 359*d16076d9SJan Kara uint16_t crc; 360*d16076d9SJan Kara int fioff = off; 361*d16076d9SJan Kara int crcoff = off + sizeof(struct tag); 362*d16076d9SJan Kara unsigned int crclen = udf_dir_entry_len(fi) - sizeof(struct tag); 363*d16076d9SJan Kara 364*d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, fi, 365*d16076d9SJan Kara sizeof(struct fileIdentDesc)); 366*d16076d9SJan Kara off += sizeof(struct fileIdentDesc); 367*d16076d9SJan Kara if (impuse) 368*d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, impuse, 369*d16076d9SJan Kara le16_to_cpu(fi->lengthOfImpUse)); 370*d16076d9SJan Kara off += le16_to_cpu(fi->lengthOfImpUse); 371*d16076d9SJan Kara if (name) 372*d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, off, name, 373*d16076d9SJan Kara fi->lengthFileIdent); 374*d16076d9SJan Kara 375*d16076d9SJan Kara crc = udf_crc_fi_bufs(buf1, len1, buf2, len2, crcoff, crclen); 376*d16076d9SJan Kara fi->descTag.descCRC = cpu_to_le16(crc); 377*d16076d9SJan Kara fi->descTag.descCRCLength = cpu_to_le16(crclen); 378*d16076d9SJan Kara fi->descTag.tagChecksum = udf_tag_checksum(&fi->descTag); 379*d16076d9SJan Kara 380*d16076d9SJan Kara udf_copy_to_bufs(buf1, len1, buf2, len2, fioff, fi, sizeof(struct tag)); 381*d16076d9SJan Kara } 382*d16076d9SJan Kara 383*d16076d9SJan Kara void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse) 384*d16076d9SJan Kara { 385*d16076d9SJan Kara struct udf_inode_info *iinfo = UDF_I(iter->dir); 386*d16076d9SJan Kara void *buf1, *buf2 = NULL; 387*d16076d9SJan Kara int len1, len2 = 0, off; 388*d16076d9SJan Kara int blksize = 1 << iter->dir->i_blkbits; 389*d16076d9SJan Kara 390*d16076d9SJan Kara off = iter->pos & (blksize - 1); 391*d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 392*d16076d9SJan Kara buf1 = iinfo->i_data + iinfo->i_lenEAttr; 393*d16076d9SJan Kara len1 = iter->dir->i_size; 394*d16076d9SJan Kara } else { 395*d16076d9SJan Kara buf1 = iter->bh[0]->b_data; 396*d16076d9SJan Kara len1 = blksize; 397*d16076d9SJan Kara if (iter->bh[1]) { 398*d16076d9SJan Kara buf2 = iter->bh[1]->b_data; 399*d16076d9SJan Kara len2 = blksize; 400*d16076d9SJan Kara } 401*d16076d9SJan Kara } 402*d16076d9SJan Kara 403*d16076d9SJan Kara udf_copy_fi_to_bufs(buf1, len1, buf2, len2, off, &iter->fi, impuse, 404*d16076d9SJan Kara iter->name == iter->namebuf ? iter->name : NULL); 405*d16076d9SJan Kara 406*d16076d9SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 407*d16076d9SJan Kara mark_inode_dirty(iter->dir); 408*d16076d9SJan Kara } else { 409*d16076d9SJan Kara mark_buffer_dirty_inode(iter->bh[0], iter->dir); 410*d16076d9SJan Kara if (iter->bh[1]) 411*d16076d9SJan Kara mark_buffer_dirty_inode(iter->bh[1], iter->dir); 412*d16076d9SJan Kara } 413*d16076d9SJan Kara inode_inc_iversion(iter->dir); 414*d16076d9SJan Kara } 4151da177e4SLinus Torvalds 416cb00ea35SCyrill Gorcunov struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, 4171da177e4SLinus Torvalds struct udf_fileident_bh *fibh, 4181da177e4SLinus Torvalds struct fileIdentDesc *cfi, 419ff116fc8SJan Kara struct extent_position *epos, 4205ca4e4beSPekka Enberg struct kernel_lb_addr *eloc, uint32_t *elen, 421ff116fc8SJan Kara sector_t *offset) 4221da177e4SLinus Torvalds { 4231da177e4SLinus Torvalds struct fileIdentDesc *fi; 424b490bdd6SSteve Magnani int i, num; 425b490bdd6SSteve Magnani udf_pblk_t block; 4261da177e4SLinus Torvalds struct buffer_head *tmp, *bha[16]; 42748d6d8ffSMarcin Slusarz struct udf_inode_info *iinfo = UDF_I(dir); 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds fibh->soffset = fibh->eoffset; 4301da177e4SLinus Torvalds 43148d6d8ffSMarcin Slusarz if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 432382a2287SJan Kara fi = udf_get_fileident(iinfo->i_data - 43348d6d8ffSMarcin Slusarz (iinfo->i_efe ? 4341da177e4SLinus Torvalds sizeof(struct extendedFileEntry) : 4351da177e4SLinus Torvalds sizeof(struct fileEntry)), 4364b11111aSMarcin Slusarz dir->i_sb->s_blocksize, 4374b11111aSMarcin Slusarz &(fibh->eoffset)); 4381da177e4SLinus Torvalds if (!fi) 4391da177e4SLinus Torvalds return NULL; 4401da177e4SLinus Torvalds 441af793295SJan Kara *nf_pos += fibh->eoffset - fibh->soffset; 4421da177e4SLinus Torvalds 443cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 444cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds return fi; 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds 449cb00ea35SCyrill Gorcunov if (fibh->eoffset == dir->i_sb->s_blocksize) { 45089a4d970SSteve Magnani uint32_t lextoffset = epos->offset; 4514b11111aSMarcin Slusarz unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits; 4521da177e4SLinus Torvalds 453ff116fc8SJan Kara if (udf_next_aext(dir, epos, eloc, elen, 1) != 4541da177e4SLinus Torvalds (EXT_RECORDED_ALLOCATED >> 30)) 4551da177e4SLinus Torvalds return NULL; 4561da177e4SLinus Torvalds 45797e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds (*offset)++; 4601da177e4SLinus Torvalds 4614b11111aSMarcin Slusarz if ((*offset << blocksize_bits) >= *elen) 4621da177e4SLinus Torvalds *offset = 0; 4631da177e4SLinus Torvalds else 464ff116fc8SJan Kara epos->offset = lextoffset; 4651da177e4SLinus Torvalds 4663bf25cb4SJan Kara brelse(fibh->sbh); 4674b11111aSMarcin Slusarz fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); 4684b11111aSMarcin Slusarz if (!fibh->sbh) 4691da177e4SLinus Torvalds return NULL; 4701da177e4SLinus Torvalds fibh->soffset = fibh->eoffset = 0; 4711da177e4SLinus Torvalds 4724b11111aSMarcin Slusarz if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) { 4734b11111aSMarcin Slusarz i = 16 >> (blocksize_bits - 9); 4744b11111aSMarcin Slusarz if (i + *offset > (*elen >> blocksize_bits)) 4754b11111aSMarcin Slusarz i = (*elen >> blocksize_bits)-*offset; 476cb00ea35SCyrill Gorcunov for (num = 0; i > 0; i--) { 47797e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, 4784b11111aSMarcin Slusarz *offset + i); 4791da177e4SLinus Torvalds tmp = udf_tgetblk(dir->i_sb, block); 4804b11111aSMarcin Slusarz if (tmp && !buffer_uptodate(tmp) && 4814b11111aSMarcin Slusarz !buffer_locked(tmp)) 4821da177e4SLinus Torvalds bha[num++] = tmp; 4831da177e4SLinus Torvalds else 4841da177e4SLinus Torvalds brelse(tmp); 4851da177e4SLinus Torvalds } 486cb00ea35SCyrill Gorcunov if (num) { 48759a16786SZhang Yi bh_readahead_batch(num, bha, REQ_RAHEAD); 4881da177e4SLinus Torvalds for (i = 0; i < num; i++) 4891da177e4SLinus Torvalds brelse(bha[i]); 4901da177e4SLinus Torvalds } 4911da177e4SLinus Torvalds } 492cb00ea35SCyrill Gorcunov } else if (fibh->sbh != fibh->ebh) { 4933bf25cb4SJan Kara brelse(fibh->sbh); 4941da177e4SLinus Torvalds fibh->sbh = fibh->ebh; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, 4981da177e4SLinus Torvalds &(fibh->eoffset)); 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds if (!fi) 5011da177e4SLinus Torvalds return NULL; 5021da177e4SLinus Torvalds 503af793295SJan Kara *nf_pos += fibh->eoffset - fibh->soffset; 5041da177e4SLinus Torvalds 505cb00ea35SCyrill Gorcunov if (fibh->eoffset <= dir->i_sb->s_blocksize) { 506cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 507cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 508cb00ea35SCyrill Gorcunov } else if (fibh->eoffset > dir->i_sb->s_blocksize) { 50989a4d970SSteve Magnani uint32_t lextoffset = epos->offset; 5101da177e4SLinus Torvalds 511ff116fc8SJan Kara if (udf_next_aext(dir, epos, eloc, elen, 1) != 5121da177e4SLinus Torvalds (EXT_RECORDED_ALLOCATED >> 30)) 5131da177e4SLinus Torvalds return NULL; 5141da177e4SLinus Torvalds 51597e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds (*offset)++; 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) 5201da177e4SLinus Torvalds *offset = 0; 5211da177e4SLinus Torvalds else 522ff116fc8SJan Kara epos->offset = lextoffset; 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds fibh->soffset -= dir->i_sb->s_blocksize; 5251da177e4SLinus Torvalds fibh->eoffset -= dir->i_sb->s_blocksize; 5261da177e4SLinus Torvalds 5274b11111aSMarcin Slusarz fibh->ebh = udf_tread(dir->i_sb, block); 5284b11111aSMarcin Slusarz if (!fibh->ebh) 5291da177e4SLinus Torvalds return NULL; 5301da177e4SLinus Torvalds 531cb00ea35SCyrill Gorcunov if (sizeof(struct fileIdentDesc) > -fibh->soffset) { 5321da177e4SLinus Torvalds int fi_len; 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset); 5354b11111aSMarcin Slusarz memcpy((uint8_t *)cfi - fibh->soffset, 5364b11111aSMarcin Slusarz fibh->ebh->b_data, 5371da177e4SLinus Torvalds sizeof(struct fileIdentDesc) + fibh->soffset); 5381da177e4SLinus Torvalds 539f2e83347SJan Kara fi_len = udf_dir_entry_len(cfi); 540af793295SJan Kara *nf_pos += fi_len - (fibh->eoffset - fibh->soffset); 5411da177e4SLinus Torvalds fibh->eoffset = fibh->soffset + fi_len; 542cb00ea35SCyrill Gorcunov } else { 543cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 544cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds } 547fa65653eSJan Kara /* Got last entry outside of dir size - fs is corrupted! */ 548fa65653eSJan Kara if (*nf_pos > dir->i_size) 549fa65653eSJan Kara return NULL; 5501da177e4SLinus Torvalds return fi; 5511da177e4SLinus Torvalds } 5521da177e4SLinus Torvalds 553cb00ea35SCyrill Gorcunov struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset) 5541da177e4SLinus Torvalds { 5551da177e4SLinus Torvalds struct fileIdentDesc *fi; 5561da177e4SLinus Torvalds int lengthThisIdent; 5571da177e4SLinus Torvalds uint8_t *ptr; 5581da177e4SLinus Torvalds int padlen; 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds if ((!buffer) || (!offset)) { 561a983f368SJoe Perches udf_debug("invalidparms, buffer=%p, offset=%p\n", 562a983f368SJoe Perches buffer, offset); 5631da177e4SLinus Torvalds return NULL; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds ptr = buffer; 5671da177e4SLinus Torvalds 5684b11111aSMarcin Slusarz if ((*offset > 0) && (*offset < bufsize)) 5691da177e4SLinus Torvalds ptr += *offset; 5701da177e4SLinus Torvalds fi = (struct fileIdentDesc *)ptr; 5715e0f0017SMarcin Slusarz if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) { 5721da177e4SLinus Torvalds udf_debug("0x%x != TAG_IDENT_FID\n", 5731da177e4SLinus Torvalds le16_to_cpu(fi->descTag.tagIdent)); 574fcbf7637SSteve Magnani udf_debug("offset: %d sizeof: %lu bufsize: %d\n", 575cb00ea35SCyrill Gorcunov *offset, (unsigned long)sizeof(struct fileIdentDesc), 576cb00ea35SCyrill Gorcunov bufsize); 5771da177e4SLinus Torvalds return NULL; 5781da177e4SLinus Torvalds } 5794b11111aSMarcin Slusarz if ((*offset + sizeof(struct fileIdentDesc)) > bufsize) 5801da177e4SLinus Torvalds lengthThisIdent = sizeof(struct fileIdentDesc); 5814b11111aSMarcin Slusarz else 5821da177e4SLinus Torvalds lengthThisIdent = sizeof(struct fileIdentDesc) + 5831da177e4SLinus Torvalds fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse); 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds /* we need to figure padding, too! */ 5861da177e4SLinus Torvalds padlen = lengthThisIdent % UDF_NAME_PAD; 5871da177e4SLinus Torvalds if (padlen) 5881da177e4SLinus Torvalds lengthThisIdent += (UDF_NAME_PAD - padlen); 5891da177e4SLinus Torvalds *offset = *offset + lengthThisIdent; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds return fi; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5945ca4e4beSPekka Enberg struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, 595cb00ea35SCyrill Gorcunov int inc) 5961da177e4SLinus Torvalds { 5975ca4e4beSPekka Enberg struct short_ad *sa; 5981da177e4SLinus Torvalds 599cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 60078ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 6011da177e4SLinus Torvalds return NULL; 6021da177e4SLinus Torvalds } 6031da177e4SLinus Torvalds 6045ca4e4beSPekka Enberg if ((*offset + sizeof(struct short_ad)) > maxoffset) 6051da177e4SLinus Torvalds return NULL; 6064b11111aSMarcin Slusarz else { 6075ca4e4beSPekka Enberg sa = (struct short_ad *)ptr; 6084b11111aSMarcin Slusarz if (sa->extLength == 0) 6091da177e4SLinus Torvalds return NULL; 6104b11111aSMarcin Slusarz } 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds if (inc) 6135ca4e4beSPekka Enberg *offset += sizeof(struct short_ad); 6141da177e4SLinus Torvalds return sa; 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 6175ca4e4beSPekka Enberg struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc) 6181da177e4SLinus Torvalds { 6195ca4e4beSPekka Enberg struct long_ad *la; 6201da177e4SLinus Torvalds 621cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 62278ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 6231da177e4SLinus Torvalds return NULL; 6241da177e4SLinus Torvalds } 6251da177e4SLinus Torvalds 6265ca4e4beSPekka Enberg if ((*offset + sizeof(struct long_ad)) > maxoffset) 6271da177e4SLinus Torvalds return NULL; 6284b11111aSMarcin Slusarz else { 6295ca4e4beSPekka Enberg la = (struct long_ad *)ptr; 6304b11111aSMarcin Slusarz if (la->extLength == 0) 6311da177e4SLinus Torvalds return NULL; 6324b11111aSMarcin Slusarz } 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds if (inc) 6355ca4e4beSPekka Enberg *offset += sizeof(struct long_ad); 6361da177e4SLinus Torvalds return la; 6371da177e4SLinus Torvalds } 638