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