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> 191da177e4SLinus Torvalds #include <linux/buffer_head.h> 201da177e4SLinus Torvalds 21cb00ea35SCyrill Gorcunov struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, 221da177e4SLinus Torvalds struct udf_fileident_bh *fibh, 231da177e4SLinus Torvalds struct fileIdentDesc *cfi, 24ff116fc8SJan Kara struct extent_position *epos, 255ca4e4beSPekka Enberg struct kernel_lb_addr *eloc, uint32_t *elen, 26ff116fc8SJan Kara sector_t *offset) 271da177e4SLinus Torvalds { 281da177e4SLinus Torvalds struct fileIdentDesc *fi; 291da177e4SLinus Torvalds int i, num, block; 301da177e4SLinus Torvalds struct buffer_head *tmp, *bha[16]; 3148d6d8ffSMarcin Slusarz struct udf_inode_info *iinfo = UDF_I(dir); 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds fibh->soffset = fibh->eoffset; 341da177e4SLinus Torvalds 3548d6d8ffSMarcin Slusarz if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 3648d6d8ffSMarcin Slusarz fi = udf_get_fileident(iinfo->i_ext.i_data - 3748d6d8ffSMarcin Slusarz (iinfo->i_efe ? 381da177e4SLinus Torvalds sizeof(struct extendedFileEntry) : 391da177e4SLinus Torvalds sizeof(struct fileEntry)), 404b11111aSMarcin Slusarz dir->i_sb->s_blocksize, 414b11111aSMarcin Slusarz &(fibh->eoffset)); 421da177e4SLinus Torvalds if (!fi) 431da177e4SLinus Torvalds return NULL; 441da177e4SLinus Torvalds 45af793295SJan Kara *nf_pos += fibh->eoffset - fibh->soffset; 461da177e4SLinus Torvalds 47cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 48cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds return fi; 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds 53cb00ea35SCyrill Gorcunov if (fibh->eoffset == dir->i_sb->s_blocksize) { 54ff116fc8SJan Kara int lextoffset = epos->offset; 554b11111aSMarcin Slusarz unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits; 561da177e4SLinus Torvalds 57ff116fc8SJan Kara if (udf_next_aext(dir, epos, eloc, elen, 1) != 581da177e4SLinus Torvalds (EXT_RECORDED_ALLOCATED >> 30)) 591da177e4SLinus Torvalds return NULL; 601da177e4SLinus Torvalds 6197e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds (*offset)++; 641da177e4SLinus Torvalds 654b11111aSMarcin Slusarz if ((*offset << blocksize_bits) >= *elen) 661da177e4SLinus Torvalds *offset = 0; 671da177e4SLinus Torvalds else 68ff116fc8SJan Kara epos->offset = lextoffset; 691da177e4SLinus Torvalds 703bf25cb4SJan Kara brelse(fibh->sbh); 714b11111aSMarcin Slusarz fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); 724b11111aSMarcin Slusarz if (!fibh->sbh) 731da177e4SLinus Torvalds return NULL; 741da177e4SLinus Torvalds fibh->soffset = fibh->eoffset = 0; 751da177e4SLinus Torvalds 764b11111aSMarcin Slusarz if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) { 774b11111aSMarcin Slusarz i = 16 >> (blocksize_bits - 9); 784b11111aSMarcin Slusarz if (i + *offset > (*elen >> blocksize_bits)) 794b11111aSMarcin Slusarz i = (*elen >> blocksize_bits)-*offset; 80cb00ea35SCyrill Gorcunov for (num = 0; i > 0; i--) { 8197e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, 824b11111aSMarcin Slusarz *offset + i); 831da177e4SLinus Torvalds tmp = udf_tgetblk(dir->i_sb, block); 844b11111aSMarcin Slusarz if (tmp && !buffer_uptodate(tmp) && 854b11111aSMarcin Slusarz !buffer_locked(tmp)) 861da177e4SLinus Torvalds bha[num++] = tmp; 871da177e4SLinus Torvalds else 881da177e4SLinus Torvalds brelse(tmp); 891da177e4SLinus Torvalds } 90cb00ea35SCyrill Gorcunov if (num) { 911da177e4SLinus Torvalds ll_rw_block(READA, num, bha); 921da177e4SLinus Torvalds for (i = 0; i < num; i++) 931da177e4SLinus Torvalds brelse(bha[i]); 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds } 96cb00ea35SCyrill Gorcunov } else if (fibh->sbh != fibh->ebh) { 973bf25cb4SJan Kara brelse(fibh->sbh); 981da177e4SLinus Torvalds fibh->sbh = fibh->ebh; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, 1021da177e4SLinus Torvalds &(fibh->eoffset)); 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds if (!fi) 1051da177e4SLinus Torvalds return NULL; 1061da177e4SLinus Torvalds 107af793295SJan Kara *nf_pos += fibh->eoffset - fibh->soffset; 1081da177e4SLinus Torvalds 109cb00ea35SCyrill Gorcunov if (fibh->eoffset <= dir->i_sb->s_blocksize) { 110cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 111cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 112cb00ea35SCyrill Gorcunov } else if (fibh->eoffset > dir->i_sb->s_blocksize) { 113ff116fc8SJan Kara int lextoffset = epos->offset; 1141da177e4SLinus Torvalds 115ff116fc8SJan Kara if (udf_next_aext(dir, epos, eloc, elen, 1) != 1161da177e4SLinus Torvalds (EXT_RECORDED_ALLOCATED >> 30)) 1171da177e4SLinus Torvalds return NULL; 1181da177e4SLinus Torvalds 11997e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds (*offset)++; 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) 1241da177e4SLinus Torvalds *offset = 0; 1251da177e4SLinus Torvalds else 126ff116fc8SJan Kara epos->offset = lextoffset; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds fibh->soffset -= dir->i_sb->s_blocksize; 1291da177e4SLinus Torvalds fibh->eoffset -= dir->i_sb->s_blocksize; 1301da177e4SLinus Torvalds 1314b11111aSMarcin Slusarz fibh->ebh = udf_tread(dir->i_sb, block); 1324b11111aSMarcin Slusarz if (!fibh->ebh) 1331da177e4SLinus Torvalds return NULL; 1341da177e4SLinus Torvalds 135cb00ea35SCyrill Gorcunov if (sizeof(struct fileIdentDesc) > -fibh->soffset) { 1361da177e4SLinus Torvalds int fi_len; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset); 1394b11111aSMarcin Slusarz memcpy((uint8_t *)cfi - fibh->soffset, 1404b11111aSMarcin Slusarz fibh->ebh->b_data, 1411da177e4SLinus Torvalds sizeof(struct fileIdentDesc) + fibh->soffset); 1421da177e4SLinus Torvalds 1434b11111aSMarcin Slusarz fi_len = (sizeof(struct fileIdentDesc) + 1444b11111aSMarcin Slusarz cfi->lengthFileIdent + 1451da177e4SLinus Torvalds le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3; 1461da177e4SLinus Torvalds 147af793295SJan Kara *nf_pos += fi_len - (fibh->eoffset - fibh->soffset); 1481da177e4SLinus Torvalds fibh->eoffset = fibh->soffset + fi_len; 149cb00ea35SCyrill Gorcunov } else { 150cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 151cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds return fi; 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 157cb00ea35SCyrill Gorcunov struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset) 1581da177e4SLinus Torvalds { 1591da177e4SLinus Torvalds struct fileIdentDesc *fi; 1601da177e4SLinus Torvalds int lengthThisIdent; 1611da177e4SLinus Torvalds uint8_t *ptr; 1621da177e4SLinus Torvalds int padlen; 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds if ((!buffer) || (!offset)) { 165*a983f368SJoe Perches udf_debug("invalidparms, buffer=%p, offset=%p\n", 166*a983f368SJoe Perches buffer, offset); 1671da177e4SLinus Torvalds return NULL; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds ptr = buffer; 1711da177e4SLinus Torvalds 1724b11111aSMarcin Slusarz if ((*offset > 0) && (*offset < bufsize)) 1731da177e4SLinus Torvalds ptr += *offset; 1741da177e4SLinus Torvalds fi = (struct fileIdentDesc *)ptr; 1755e0f0017SMarcin Slusarz if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) { 1761da177e4SLinus Torvalds udf_debug("0x%x != TAG_IDENT_FID\n", 1771da177e4SLinus Torvalds le16_to_cpu(fi->descTag.tagIdent)); 1781da177e4SLinus Torvalds udf_debug("offset: %u sizeof: %lu bufsize: %u\n", 179cb00ea35SCyrill Gorcunov *offset, (unsigned long)sizeof(struct fileIdentDesc), 180cb00ea35SCyrill Gorcunov bufsize); 1811da177e4SLinus Torvalds return NULL; 1821da177e4SLinus Torvalds } 1834b11111aSMarcin Slusarz if ((*offset + sizeof(struct fileIdentDesc)) > bufsize) 1841da177e4SLinus Torvalds lengthThisIdent = sizeof(struct fileIdentDesc); 1854b11111aSMarcin Slusarz else 1861da177e4SLinus Torvalds lengthThisIdent = sizeof(struct fileIdentDesc) + 1871da177e4SLinus Torvalds fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds /* we need to figure padding, too! */ 1901da177e4SLinus Torvalds padlen = lengthThisIdent % UDF_NAME_PAD; 1911da177e4SLinus Torvalds if (padlen) 1921da177e4SLinus Torvalds lengthThisIdent += (UDF_NAME_PAD - padlen); 1931da177e4SLinus Torvalds *offset = *offset + lengthThisIdent; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds return fi; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 1985ca4e4beSPekka Enberg struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, 199cb00ea35SCyrill Gorcunov int inc) 2001da177e4SLinus Torvalds { 2015ca4e4beSPekka Enberg struct short_ad *sa; 2021da177e4SLinus Torvalds 203cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 20478ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 2051da177e4SLinus Torvalds return NULL; 2061da177e4SLinus Torvalds } 2071da177e4SLinus Torvalds 2085ca4e4beSPekka Enberg if ((*offset + sizeof(struct short_ad)) > maxoffset) 2091da177e4SLinus Torvalds return NULL; 2104b11111aSMarcin Slusarz else { 2115ca4e4beSPekka Enberg sa = (struct short_ad *)ptr; 2124b11111aSMarcin Slusarz if (sa->extLength == 0) 2131da177e4SLinus Torvalds return NULL; 2144b11111aSMarcin Slusarz } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds if (inc) 2175ca4e4beSPekka Enberg *offset += sizeof(struct short_ad); 2181da177e4SLinus Torvalds return sa; 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds 2215ca4e4beSPekka Enberg struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc) 2221da177e4SLinus Torvalds { 2235ca4e4beSPekka Enberg struct long_ad *la; 2241da177e4SLinus Torvalds 225cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 22678ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 2271da177e4SLinus Torvalds return NULL; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2305ca4e4beSPekka Enberg if ((*offset + sizeof(struct long_ad)) > maxoffset) 2311da177e4SLinus Torvalds return NULL; 2324b11111aSMarcin Slusarz else { 2335ca4e4beSPekka Enberg la = (struct long_ad *)ptr; 2344b11111aSMarcin Slusarz if (la->extLength == 0) 2351da177e4SLinus Torvalds return NULL; 2364b11111aSMarcin Slusarz } 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds if (inc) 2395ca4e4beSPekka Enberg *offset += sizeof(struct long_ad); 2401da177e4SLinus Torvalds return la; 2411da177e4SLinus Torvalds } 242