| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * directory.c | 
|  | 3 | * | 
|  | 4 | * PURPOSE | 
|  | 5 | *	Directory related functions | 
|  | 6 | * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | } |