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> 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; 29b490bdd6SSteve Magnani int i, num; 30b490bdd6SSteve Magnani udf_pblk_t block; 311da177e4SLinus Torvalds struct buffer_head *tmp, *bha[16]; 3248d6d8ffSMarcin Slusarz struct udf_inode_info *iinfo = UDF_I(dir); 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds fibh->soffset = fibh->eoffset; 351da177e4SLinus Torvalds 3648d6d8ffSMarcin Slusarz if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 3748d6d8ffSMarcin Slusarz fi = udf_get_fileident(iinfo->i_ext.i_data - 3848d6d8ffSMarcin Slusarz (iinfo->i_efe ? 391da177e4SLinus Torvalds sizeof(struct extendedFileEntry) : 401da177e4SLinus Torvalds sizeof(struct fileEntry)), 414b11111aSMarcin Slusarz dir->i_sb->s_blocksize, 424b11111aSMarcin Slusarz &(fibh->eoffset)); 431da177e4SLinus Torvalds if (!fi) 441da177e4SLinus Torvalds return NULL; 451da177e4SLinus Torvalds 46af793295SJan Kara *nf_pos += fibh->eoffset - fibh->soffset; 471da177e4SLinus Torvalds 48cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 49cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds return fi; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 54cb00ea35SCyrill Gorcunov if (fibh->eoffset == dir->i_sb->s_blocksize) { 55ff116fc8SJan Kara int lextoffset = epos->offset; 564b11111aSMarcin Slusarz unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits; 571da177e4SLinus Torvalds 58ff116fc8SJan Kara if (udf_next_aext(dir, epos, eloc, elen, 1) != 591da177e4SLinus Torvalds (EXT_RECORDED_ALLOCATED >> 30)) 601da177e4SLinus Torvalds return NULL; 611da177e4SLinus Torvalds 6297e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds (*offset)++; 651da177e4SLinus Torvalds 664b11111aSMarcin Slusarz if ((*offset << blocksize_bits) >= *elen) 671da177e4SLinus Torvalds *offset = 0; 681da177e4SLinus Torvalds else 69ff116fc8SJan Kara epos->offset = lextoffset; 701da177e4SLinus Torvalds 713bf25cb4SJan Kara brelse(fibh->sbh); 724b11111aSMarcin Slusarz fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); 734b11111aSMarcin Slusarz if (!fibh->sbh) 741da177e4SLinus Torvalds return NULL; 751da177e4SLinus Torvalds fibh->soffset = fibh->eoffset = 0; 761da177e4SLinus Torvalds 774b11111aSMarcin Slusarz if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) { 784b11111aSMarcin Slusarz i = 16 >> (blocksize_bits - 9); 794b11111aSMarcin Slusarz if (i + *offset > (*elen >> blocksize_bits)) 804b11111aSMarcin Slusarz i = (*elen >> blocksize_bits)-*offset; 81cb00ea35SCyrill Gorcunov for (num = 0; i > 0; i--) { 8297e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, 834b11111aSMarcin Slusarz *offset + i); 841da177e4SLinus Torvalds tmp = udf_tgetblk(dir->i_sb, block); 854b11111aSMarcin Slusarz if (tmp && !buffer_uptodate(tmp) && 864b11111aSMarcin Slusarz !buffer_locked(tmp)) 871da177e4SLinus Torvalds bha[num++] = tmp; 881da177e4SLinus Torvalds else 891da177e4SLinus Torvalds brelse(tmp); 901da177e4SLinus Torvalds } 91cb00ea35SCyrill Gorcunov if (num) { 9270246286SChristoph Hellwig ll_rw_block(REQ_OP_READ, REQ_RAHEAD, num, bha); 931da177e4SLinus Torvalds for (i = 0; i < num; i++) 941da177e4SLinus Torvalds brelse(bha[i]); 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds } 97cb00ea35SCyrill Gorcunov } else if (fibh->sbh != fibh->ebh) { 983bf25cb4SJan Kara brelse(fibh->sbh); 991da177e4SLinus Torvalds fibh->sbh = fibh->ebh; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, 1031da177e4SLinus Torvalds &(fibh->eoffset)); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds if (!fi) 1061da177e4SLinus Torvalds return NULL; 1071da177e4SLinus Torvalds 108af793295SJan Kara *nf_pos += fibh->eoffset - fibh->soffset; 1091da177e4SLinus Torvalds 110cb00ea35SCyrill Gorcunov if (fibh->eoffset <= dir->i_sb->s_blocksize) { 111cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 112cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 113cb00ea35SCyrill Gorcunov } else if (fibh->eoffset > dir->i_sb->s_blocksize) { 114ff116fc8SJan Kara int lextoffset = epos->offset; 1151da177e4SLinus Torvalds 116ff116fc8SJan Kara if (udf_next_aext(dir, epos, eloc, elen, 1) != 1171da177e4SLinus Torvalds (EXT_RECORDED_ALLOCATED >> 30)) 1181da177e4SLinus Torvalds return NULL; 1191da177e4SLinus Torvalds 12097e961fdSPekka Enberg block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds (*offset)++; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) 1251da177e4SLinus Torvalds *offset = 0; 1261da177e4SLinus Torvalds else 127ff116fc8SJan Kara epos->offset = lextoffset; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds fibh->soffset -= dir->i_sb->s_blocksize; 1301da177e4SLinus Torvalds fibh->eoffset -= dir->i_sb->s_blocksize; 1311da177e4SLinus Torvalds 1324b11111aSMarcin Slusarz fibh->ebh = udf_tread(dir->i_sb, block); 1334b11111aSMarcin Slusarz if (!fibh->ebh) 1341da177e4SLinus Torvalds return NULL; 1351da177e4SLinus Torvalds 136cb00ea35SCyrill Gorcunov if (sizeof(struct fileIdentDesc) > -fibh->soffset) { 1371da177e4SLinus Torvalds int fi_len; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset); 1404b11111aSMarcin Slusarz memcpy((uint8_t *)cfi - fibh->soffset, 1414b11111aSMarcin Slusarz fibh->ebh->b_data, 1421da177e4SLinus Torvalds sizeof(struct fileIdentDesc) + fibh->soffset); 1431da177e4SLinus Torvalds 1444b11111aSMarcin Slusarz fi_len = (sizeof(struct fileIdentDesc) + 1454b11111aSMarcin Slusarz cfi->lengthFileIdent + 1461da177e4SLinus Torvalds le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3; 1471da177e4SLinus Torvalds 148af793295SJan Kara *nf_pos += fi_len - (fibh->eoffset - fibh->soffset); 1491da177e4SLinus Torvalds fibh->eoffset = fibh->soffset + fi_len; 150cb00ea35SCyrill Gorcunov } else { 151cb00ea35SCyrill Gorcunov memcpy((uint8_t *)cfi, (uint8_t *)fi, 152cb00ea35SCyrill Gorcunov sizeof(struct fileIdentDesc)); 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds return fi; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 158cb00ea35SCyrill Gorcunov struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset) 1591da177e4SLinus Torvalds { 1601da177e4SLinus Torvalds struct fileIdentDesc *fi; 1611da177e4SLinus Torvalds int lengthThisIdent; 1621da177e4SLinus Torvalds uint8_t *ptr; 1631da177e4SLinus Torvalds int padlen; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds if ((!buffer) || (!offset)) { 166a983f368SJoe Perches udf_debug("invalidparms, buffer=%p, offset=%p\n", 167a983f368SJoe Perches buffer, offset); 1681da177e4SLinus Torvalds return NULL; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds ptr = buffer; 1721da177e4SLinus Torvalds 1734b11111aSMarcin Slusarz if ((*offset > 0) && (*offset < bufsize)) 1741da177e4SLinus Torvalds ptr += *offset; 1751da177e4SLinus Torvalds fi = (struct fileIdentDesc *)ptr; 1765e0f0017SMarcin Slusarz if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) { 1771da177e4SLinus Torvalds udf_debug("0x%x != TAG_IDENT_FID\n", 1781da177e4SLinus Torvalds le16_to_cpu(fi->descTag.tagIdent)); 179*fcbf7637SSteve Magnani udf_debug("offset: %d sizeof: %lu bufsize: %d\n", 180cb00ea35SCyrill Gorcunov *offset, (unsigned long)sizeof(struct fileIdentDesc), 181cb00ea35SCyrill Gorcunov bufsize); 1821da177e4SLinus Torvalds return NULL; 1831da177e4SLinus Torvalds } 1844b11111aSMarcin Slusarz if ((*offset + sizeof(struct fileIdentDesc)) > bufsize) 1851da177e4SLinus Torvalds lengthThisIdent = sizeof(struct fileIdentDesc); 1864b11111aSMarcin Slusarz else 1871da177e4SLinus Torvalds lengthThisIdent = sizeof(struct fileIdentDesc) + 1881da177e4SLinus Torvalds fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse); 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds /* we need to figure padding, too! */ 1911da177e4SLinus Torvalds padlen = lengthThisIdent % UDF_NAME_PAD; 1921da177e4SLinus Torvalds if (padlen) 1931da177e4SLinus Torvalds lengthThisIdent += (UDF_NAME_PAD - padlen); 1941da177e4SLinus Torvalds *offset = *offset + lengthThisIdent; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds return fi; 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds 1995ca4e4beSPekka Enberg struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, 200cb00ea35SCyrill Gorcunov int inc) 2011da177e4SLinus Torvalds { 2025ca4e4beSPekka Enberg struct short_ad *sa; 2031da177e4SLinus Torvalds 204cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 20578ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 2061da177e4SLinus Torvalds return NULL; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds 2095ca4e4beSPekka Enberg if ((*offset + sizeof(struct short_ad)) > maxoffset) 2101da177e4SLinus Torvalds return NULL; 2114b11111aSMarcin Slusarz else { 2125ca4e4beSPekka Enberg sa = (struct short_ad *)ptr; 2134b11111aSMarcin Slusarz if (sa->extLength == 0) 2141da177e4SLinus Torvalds return NULL; 2154b11111aSMarcin Slusarz } 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds if (inc) 2185ca4e4beSPekka Enberg *offset += sizeof(struct short_ad); 2191da177e4SLinus Torvalds return sa; 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds 2225ca4e4beSPekka Enberg struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc) 2231da177e4SLinus Torvalds { 2245ca4e4beSPekka Enberg struct long_ad *la; 2251da177e4SLinus Torvalds 226cb00ea35SCyrill Gorcunov if ((!ptr) || (!offset)) { 22778ace70cSJoe Perches pr_err("%s: invalidparms\n", __func__); 2281da177e4SLinus Torvalds return NULL; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2315ca4e4beSPekka Enberg if ((*offset + sizeof(struct long_ad)) > maxoffset) 2321da177e4SLinus Torvalds return NULL; 2334b11111aSMarcin Slusarz else { 2345ca4e4beSPekka Enberg la = (struct long_ad *)ptr; 2354b11111aSMarcin Slusarz if (la->extLength == 0) 2361da177e4SLinus Torvalds return NULL; 2374b11111aSMarcin Slusarz } 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds if (inc) 2405ca4e4beSPekka Enberg *offset += sizeof(struct long_ad); 2411da177e4SLinus Torvalds return la; 2421da177e4SLinus Torvalds } 243