1 /* 2 * dir.c 3 * 4 * PURPOSE 5 * Directory handling routines for the OSTA-UDF(tm) filesystem. 6 * 7 * CONTACTS 8 * E-mail regarding any portion of the Linux UDF file system should be 9 * directed to the development team mailing list (run by majordomo): 10 * linux_udf@hpesjro.fc.hp.com 11 * 12 * COPYRIGHT 13 * This file is distributed under the terms of the GNU General Public 14 * License (GPL). Copies of the GPL can be obtained from: 15 * ftp://prep.ai.mit.edu/pub/gnu/GPL 16 * Each contributing author retains all rights to their own work. 17 * 18 * (C) 1998-2004 Ben Fennema 19 * 20 * HISTORY 21 * 22 * 10/05/98 dgb Split directory operations into its own file 23 * Implemented directory reads via do_udf_readdir 24 * 10/06/98 Made directory operations work! 25 * 11/17/98 Rewrote directory to support ICBTAG_FLAG_AD_LONG 26 * 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading 27 * across blocks. 28 * 12/12/98 Split out the lookup code to namei.c. bulk of directory 29 * code now in directory.c:udf_fileident_read. 30 */ 31 32 #include "udfdecl.h" 33 34 #include <linux/string.h> 35 #include <linux/errno.h> 36 #include <linux/mm.h> 37 #include <linux/slab.h> 38 #include <linux/smp_lock.h> 39 #include <linux/buffer_head.h> 40 41 #include "udf_i.h" 42 #include "udf_sb.h" 43 44 /* Prototypes for file operations */ 45 static int udf_readdir(struct file *, void *, filldir_t); 46 static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *); 47 48 /* readdir and lookup functions */ 49 50 struct file_operations udf_dir_operations = { 51 .read = generic_read_dir, 52 .readdir = udf_readdir, 53 .ioctl = udf_ioctl, 54 .fsync = udf_fsync_file, 55 }; 56 57 /* 58 * udf_readdir 59 * 60 * PURPOSE 61 * Read a directory entry. 62 * 63 * DESCRIPTION 64 * Optional - sys_getdents() will return -ENOTDIR if this routine is not 65 * available. 66 * 67 * Refer to sys_getdents() in fs/readdir.c 68 * sys_getdents() -> . 69 * 70 * PRE-CONDITIONS 71 * filp Pointer to directory file. 72 * buf Pointer to directory entry buffer. 73 * filldir Pointer to filldir function. 74 * 75 * POST-CONDITIONS 76 * <return> >=0 on success. 77 * 78 * HISTORY 79 * July 1, 1997 - Andrew E. Mileski 80 * Written, tested, and released. 81 */ 82 83 int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) 84 { 85 struct inode *dir = filp->f_dentry->d_inode; 86 int result; 87 88 lock_kernel(); 89 90 if ( filp->f_pos == 0 ) 91 { 92 if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) 93 { 94 unlock_kernel(); 95 return 0; 96 } 97 filp->f_pos ++; 98 } 99 100 result = do_udf_readdir(dir, filp, filldir, dirent); 101 unlock_kernel(); 102 return result; 103 } 104 105 static int 106 do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent) 107 { 108 struct udf_fileident_bh fibh; 109 struct fileIdentDesc *fi=NULL; 110 struct fileIdentDesc cfi; 111 int block, iblock; 112 loff_t nf_pos = filp->f_pos - 1; 113 int flen; 114 char fname[UDF_NAME_LEN]; 115 char *nameptr; 116 uint16_t liu; 117 uint8_t lfi; 118 loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; 119 struct buffer_head * bh = NULL, * tmp, * bha[16]; 120 kernel_lb_addr bloc, eloc; 121 uint32_t extoffset, elen, offset; 122 int i, num; 123 unsigned int dt_type; 124 125 if (nf_pos >= size) 126 return 0; 127 128 if (nf_pos == 0) 129 nf_pos = (udf_ext0_offset(dir) >> 2); 130 131 fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; 132 if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) 133 fibh.sbh = fibh.ebh = NULL; 134 else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2), 135 &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) 136 { 137 offset >>= dir->i_sb->s_blocksize_bits; 138 block = udf_get_lb_pblock(dir->i_sb, eloc, offset); 139 if ((++offset << dir->i_sb->s_blocksize_bits) < elen) 140 { 141 if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT) 142 extoffset -= sizeof(short_ad); 143 else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG) 144 extoffset -= sizeof(long_ad); 145 } 146 else 147 offset = 0; 148 149 if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) 150 { 151 udf_release_data(bh); 152 return -EIO; 153 } 154 155 if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1))) 156 { 157 i = 16 >> (dir->i_sb->s_blocksize_bits - 9); 158 if (i+offset > (elen >> dir->i_sb->s_blocksize_bits)) 159 i = (elen >> dir->i_sb->s_blocksize_bits)-offset; 160 for (num=0; i>0; i--) 161 { 162 block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i); 163 tmp = udf_tgetblk(dir->i_sb, block); 164 if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) 165 bha[num++] = tmp; 166 else 167 brelse(tmp); 168 } 169 if (num) 170 { 171 ll_rw_block(READA, num, bha); 172 for (i=0; i<num; i++) 173 brelse(bha[i]); 174 } 175 } 176 } 177 else 178 { 179 udf_release_data(bh); 180 return -ENOENT; 181 } 182 183 while ( nf_pos < size ) 184 { 185 filp->f_pos = nf_pos + 1; 186 187 fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); 188 189 if (!fi) 190 { 191 if (fibh.sbh != fibh.ebh) 192 udf_release_data(fibh.ebh); 193 udf_release_data(fibh.sbh); 194 udf_release_data(bh); 195 return 0; 196 } 197 198 liu = le16_to_cpu(cfi.lengthOfImpUse); 199 lfi = cfi.lengthFileIdent; 200 201 if (fibh.sbh == fibh.ebh) 202 nameptr = fi->fileIdent + liu; 203 else 204 { 205 int poffset; /* Unpaded ending offset */ 206 207 poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi; 208 209 if (poffset >= lfi) 210 nameptr = (char *)(fibh.ebh->b_data + poffset - lfi); 211 else 212 { 213 nameptr = fname; 214 memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); 215 memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset); 216 } 217 } 218 219 if ( (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 ) 220 { 221 if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) ) 222 continue; 223 } 224 225 if ( (cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 ) 226 { 227 if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) ) 228 continue; 229 } 230 231 if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT ) 232 { 233 iblock = parent_ino(filp->f_dentry); 234 flen = 2; 235 memcpy(fname, "..", flen); 236 dt_type = DT_DIR; 237 } 238 else 239 { 240 kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation); 241 242 iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0); 243 flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); 244 dt_type = DT_UNKNOWN; 245 } 246 247 if (flen) 248 { 249 if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) 250 { 251 if (fibh.sbh != fibh.ebh) 252 udf_release_data(fibh.ebh); 253 udf_release_data(fibh.sbh); 254 udf_release_data(bh); 255 return 0; 256 } 257 } 258 } /* end while */ 259 260 filp->f_pos = nf_pos + 1; 261 262 if (fibh.sbh != fibh.ebh) 263 udf_release_data(fibh.ebh); 264 udf_release_data(fibh.sbh); 265 udf_release_data(bh); 266 267 return 0; 268 } 269