1 /* 2 * directory.c 3 * 4 * PURPOSE 5 * Directory related functions 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 19 #include "udfdecl.h" 20 #include "udf_i.h" 21 22 #include <linux/fs.h> 23 #include <linux/string.h> 24 #include <linux/buffer_head.h> 25 26 #if 0 27 static uint8_t * 28 udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size, 29 kernel_lb_addr fe_loc, int *pos, int *offset, 30 struct buffer_head **bh, int *error) 31 { 32 int loffset = *offset; 33 int block; 34 uint8_t *ad; 35 int remainder; 36 37 *error = 0; 38 39 ad = (uint8_t *)(*bh)->b_data + *offset; 40 *offset += ad_size; 41 42 if (!ad) 43 { 44 udf_release_data(*bh); 45 *error = 1; 46 return NULL; 47 } 48 49 if (*offset == dir->i_sb->s_blocksize) 50 { 51 udf_release_data(*bh); 52 block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); 53 if (!block) 54 return NULL; 55 if (!(*bh = udf_tread(dir->i_sb, block))) 56 return NULL; 57 } 58 else if (*offset > dir->i_sb->s_blocksize) 59 { 60 ad = tmpad; 61 62 remainder = dir->i_sb->s_blocksize - loffset; 63 memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder); 64 65 udf_release_data(*bh); 66 block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); 67 if (!block) 68 return NULL; 69 if (!((*bh) = udf_tread(dir->i_sb, block))) 70 return NULL; 71 72 memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder); 73 *offset = ad_size - remainder; 74 } 75 return ad; 76 } 77 #endif 78 79 struct fileIdentDesc * 80 udf_fileident_read(struct inode *dir, loff_t *nf_pos, 81 struct udf_fileident_bh *fibh, 82 struct fileIdentDesc *cfi, 83 kernel_lb_addr *bloc, uint32_t *extoffset, 84 kernel_lb_addr *eloc, uint32_t *elen, 85 uint32_t *offset, struct buffer_head **bh) 86 { 87 struct fileIdentDesc *fi; 88 int i, num, block; 89 struct buffer_head * tmp, * bha[16]; 90 91 fibh->soffset = fibh->eoffset; 92 93 if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) 94 { 95 fi = udf_get_fileident(UDF_I_DATA(dir) - 96 (UDF_I_EFE(dir) ? 97 sizeof(struct extendedFileEntry) : 98 sizeof(struct fileEntry)), 99 dir->i_sb->s_blocksize, &(fibh->eoffset)); 100 101 if (!fi) 102 return NULL; 103 104 *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2); 105 106 memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); 107 108 return fi; 109 } 110 111 if (fibh->eoffset == dir->i_sb->s_blocksize) 112 { 113 int lextoffset = *extoffset; 114 115 if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) != 116 (EXT_RECORDED_ALLOCATED >> 30)) 117 { 118 return NULL; 119 } 120 121 block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset); 122 123 (*offset) ++; 124 125 if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) 126 *offset = 0; 127 else 128 *extoffset = lextoffset; 129 130 udf_release_data(fibh->sbh); 131 if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) 132 return NULL; 133 fibh->soffset = fibh->eoffset = 0; 134 135 if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1))) 136 { 137 i = 16 >> (dir->i_sb->s_blocksize_bits - 9); 138 if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits)) 139 i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset; 140 for (num=0; i>0; i--) 141 { 142 block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i); 143 tmp = udf_tgetblk(dir->i_sb, block); 144 if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) 145 bha[num++] = tmp; 146 else 147 brelse(tmp); 148 } 149 if (num) 150 { 151 ll_rw_block(READA, num, bha); 152 for (i=0; i<num; i++) 153 brelse(bha[i]); 154 } 155 } 156 } 157 else if (fibh->sbh != fibh->ebh) 158 { 159 udf_release_data(fibh->sbh); 160 fibh->sbh = fibh->ebh; 161 } 162 163 fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, 164 &(fibh->eoffset)); 165 166 if (!fi) 167 return NULL; 168 169 *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2); 170 171 if (fibh->eoffset <= dir->i_sb->s_blocksize) 172 { 173 memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); 174 } 175 else if (fibh->eoffset > dir->i_sb->s_blocksize) 176 { 177 int lextoffset = *extoffset; 178 179 if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) != 180 (EXT_RECORDED_ALLOCATED >> 30)) 181 { 182 return NULL; 183 } 184 185 block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset); 186 187 (*offset) ++; 188 189 if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) 190 *offset = 0; 191 else 192 *extoffset = lextoffset; 193 194 fibh->soffset -= dir->i_sb->s_blocksize; 195 fibh->eoffset -= dir->i_sb->s_blocksize; 196 197 if (!(fibh->ebh = udf_tread(dir->i_sb, block))) 198 return NULL; 199 200 if (sizeof(struct fileIdentDesc) > - fibh->soffset) 201 { 202 int fi_len; 203 204 memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset); 205 memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data, 206 sizeof(struct fileIdentDesc) + fibh->soffset); 207 208 fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent + 209 le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3; 210 211 *nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2); 212 fibh->eoffset = fibh->soffset + fi_len; 213 } 214 else 215 { 216 memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); 217 } 218 } 219 return fi; 220 } 221 222 struct fileIdentDesc * 223 udf_get_fileident(void * buffer, int bufsize, int * offset) 224 { 225 struct fileIdentDesc *fi; 226 int lengthThisIdent; 227 uint8_t * ptr; 228 int padlen; 229 230 if ( (!buffer) || (!offset) ) { 231 udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset); 232 return NULL; 233 } 234 235 ptr = buffer; 236 237 if ( (*offset > 0) && (*offset < bufsize) ) { 238 ptr += *offset; 239 } 240 fi=(struct fileIdentDesc *)ptr; 241 if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID) 242 { 243 udf_debug("0x%x != TAG_IDENT_FID\n", 244 le16_to_cpu(fi->descTag.tagIdent)); 245 udf_debug("offset: %u sizeof: %lu bufsize: %u\n", 246 *offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize); 247 return NULL; 248 } 249 if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize ) 250 { 251 lengthThisIdent = sizeof(struct fileIdentDesc); 252 } 253 else 254 lengthThisIdent = sizeof(struct fileIdentDesc) + 255 fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse); 256 257 /* we need to figure padding, too! */ 258 padlen = lengthThisIdent % UDF_NAME_PAD; 259 if (padlen) 260 lengthThisIdent += (UDF_NAME_PAD - padlen); 261 *offset = *offset + lengthThisIdent; 262 263 return fi; 264 } 265 266 #if 0 267 static extent_ad * 268 udf_get_fileextent(void * buffer, int bufsize, int * offset) 269 { 270 extent_ad * ext; 271 struct fileEntry *fe; 272 uint8_t * ptr; 273 274 if ( (!buffer) || (!offset) ) 275 { 276 printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n"); 277 return NULL; 278 } 279 280 fe = (struct fileEntry *)buffer; 281 282 if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE ) 283 { 284 udf_debug("0x%x != TAG_IDENT_FE\n", 285 le16_to_cpu(fe->descTag.tagIdent)); 286 return NULL; 287 } 288 289 ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr); 290 291 if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) ) 292 { 293 ptr += *offset; 294 } 295 296 ext = (extent_ad *)ptr; 297 298 *offset = *offset + sizeof(extent_ad); 299 return ext; 300 } 301 #endif 302 303 short_ad * 304 udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc) 305 { 306 short_ad *sa; 307 308 if ( (!ptr) || (!offset) ) 309 { 310 printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n"); 311 return NULL; 312 } 313 314 if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) ) 315 return NULL; 316 else if ((sa = (short_ad *)ptr)->extLength == 0) 317 return NULL; 318 319 if (inc) 320 *offset += sizeof(short_ad); 321 return sa; 322 } 323 324 long_ad * 325 udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc) 326 { 327 long_ad *la; 328 329 if ( (!ptr) || (!offset) ) 330 { 331 printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n"); 332 return NULL; 333 } 334 335 if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) ) 336 return NULL; 337 else if ((la = (long_ad *)ptr)->extLength == 0) 338 return NULL; 339 340 if (inc) 341 *offset += sizeof(long_ad); 342 return la; 343 } 344