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