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 brelse(*bh); 40 *error = 1; 41 return NULL; 42 } 43 44 if (*offset == dir->i_sb->s_blocksize) 45 { 46 brelse(*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 brelse(*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 struct extent_position *epos, 79 kernel_lb_addr *eloc, uint32_t *elen, 80 sector_t *offset) 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 = epos->offset; 109 110 if (udf_next_aext(dir, epos, eloc, elen, 1) != 111 (EXT_RECORDED_ALLOCATED >> 30)) 112 return NULL; 113 114 block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset); 115 116 (*offset) ++; 117 118 if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) 119 *offset = 0; 120 else 121 epos->offset = lextoffset; 122 123 brelse(fibh->sbh); 124 if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) 125 return NULL; 126 fibh->soffset = fibh->eoffset = 0; 127 128 if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1))) 129 { 130 i = 16 >> (dir->i_sb->s_blocksize_bits - 9); 131 if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits)) 132 i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset; 133 for (num=0; i>0; i--) 134 { 135 block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i); 136 tmp = udf_tgetblk(dir->i_sb, block); 137 if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) 138 bha[num++] = tmp; 139 else 140 brelse(tmp); 141 } 142 if (num) 143 { 144 ll_rw_block(READA, num, bha); 145 for (i=0; i<num; i++) 146 brelse(bha[i]); 147 } 148 } 149 } 150 else if (fibh->sbh != fibh->ebh) 151 { 152 brelse(fibh->sbh); 153 fibh->sbh = fibh->ebh; 154 } 155 156 fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, 157 &(fibh->eoffset)); 158 159 if (!fi) 160 return NULL; 161 162 *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2); 163 164 if (fibh->eoffset <= dir->i_sb->s_blocksize) 165 { 166 memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); 167 } 168 else if (fibh->eoffset > dir->i_sb->s_blocksize) 169 { 170 int lextoffset = epos->offset; 171 172 if (udf_next_aext(dir, epos, eloc, elen, 1) != 173 (EXT_RECORDED_ALLOCATED >> 30)) 174 return NULL; 175 176 block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset); 177 178 (*offset) ++; 179 180 if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) 181 *offset = 0; 182 else 183 epos->offset = lextoffset; 184 185 fibh->soffset -= dir->i_sb->s_blocksize; 186 fibh->eoffset -= dir->i_sb->s_blocksize; 187 188 if (!(fibh->ebh = udf_tread(dir->i_sb, block))) 189 return NULL; 190 191 if (sizeof(struct fileIdentDesc) > - fibh->soffset) 192 { 193 int fi_len; 194 195 memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset); 196 memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data, 197 sizeof(struct fileIdentDesc) + fibh->soffset); 198 199 fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent + 200 le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3; 201 202 *nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2); 203 fibh->eoffset = fibh->soffset + fi_len; 204 } 205 else 206 { 207 memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); 208 } 209 } 210 return fi; 211 } 212 213 struct fileIdentDesc * 214 udf_get_fileident(void * buffer, int bufsize, int * offset) 215 { 216 struct fileIdentDesc *fi; 217 int lengthThisIdent; 218 uint8_t * ptr; 219 int padlen; 220 221 if ( (!buffer) || (!offset) ) { 222 udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset); 223 return NULL; 224 } 225 226 ptr = buffer; 227 228 if ( (*offset > 0) && (*offset < bufsize) ) { 229 ptr += *offset; 230 } 231 fi=(struct fileIdentDesc *)ptr; 232 if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID) 233 { 234 udf_debug("0x%x != TAG_IDENT_FID\n", 235 le16_to_cpu(fi->descTag.tagIdent)); 236 udf_debug("offset: %u sizeof: %lu bufsize: %u\n", 237 *offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize); 238 return NULL; 239 } 240 if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize ) 241 { 242 lengthThisIdent = sizeof(struct fileIdentDesc); 243 } 244 else 245 lengthThisIdent = sizeof(struct fileIdentDesc) + 246 fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse); 247 248 /* we need to figure padding, too! */ 249 padlen = lengthThisIdent % UDF_NAME_PAD; 250 if (padlen) 251 lengthThisIdent += (UDF_NAME_PAD - padlen); 252 *offset = *offset + lengthThisIdent; 253 254 return fi; 255 } 256 257 #if 0 258 static extent_ad * 259 udf_get_fileextent(void * buffer, int bufsize, int * offset) 260 { 261 extent_ad * ext; 262 struct fileEntry *fe; 263 uint8_t * ptr; 264 265 if ( (!buffer) || (!offset) ) 266 { 267 printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n"); 268 return NULL; 269 } 270 271 fe = (struct fileEntry *)buffer; 272 273 if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE ) 274 { 275 udf_debug("0x%x != TAG_IDENT_FE\n", 276 le16_to_cpu(fe->descTag.tagIdent)); 277 return NULL; 278 } 279 280 ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr); 281 282 if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) ) 283 { 284 ptr += *offset; 285 } 286 287 ext = (extent_ad *)ptr; 288 289 *offset = *offset + sizeof(extent_ad); 290 return ext; 291 } 292 #endif 293 294 short_ad * 295 udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc) 296 { 297 short_ad *sa; 298 299 if ( (!ptr) || (!offset) ) 300 { 301 printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n"); 302 return NULL; 303 } 304 305 if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) ) 306 return NULL; 307 else if ((sa = (short_ad *)ptr)->extLength == 0) 308 return NULL; 309 310 if (inc) 311 *offset += sizeof(short_ad); 312 return sa; 313 } 314 315 long_ad * 316 udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc) 317 { 318 long_ad *la; 319 320 if ( (!ptr) || (!offset) ) 321 { 322 printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n"); 323 return NULL; 324 } 325 326 if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) ) 327 return NULL; 328 else if ((la = (long_ad *)ptr)->extLength == 0) 329 return NULL; 330 331 if (inc) 332 *offset += sizeof(long_ad); 333 return la; 334 } 335