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