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/bio.h> 20 21 struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, 22 struct udf_fileident_bh *fibh, 23 struct fileIdentDesc *cfi, 24 struct extent_position *epos, 25 struct kernel_lb_addr *eloc, uint32_t *elen, 26 sector_t *offset) 27 { 28 struct fileIdentDesc *fi; 29 int i, num; 30 udf_pblk_t block; 31 struct buffer_head *tmp, *bha[16]; 32 struct udf_inode_info *iinfo = UDF_I(dir); 33 34 fibh->soffset = fibh->eoffset; 35 36 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 37 fi = udf_get_fileident(iinfo->i_data - 38 (iinfo->i_efe ? 39 sizeof(struct extendedFileEntry) : 40 sizeof(struct fileEntry)), 41 dir->i_sb->s_blocksize, 42 &(fibh->eoffset)); 43 if (!fi) 44 return NULL; 45 46 *nf_pos += fibh->eoffset - fibh->soffset; 47 48 memcpy((uint8_t *)cfi, (uint8_t *)fi, 49 sizeof(struct fileIdentDesc)); 50 51 return fi; 52 } 53 54 if (fibh->eoffset == dir->i_sb->s_blocksize) { 55 uint32_t lextoffset = epos->offset; 56 unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits; 57 58 if (udf_next_aext(dir, epos, eloc, elen, 1) != 59 (EXT_RECORDED_ALLOCATED >> 30)) 60 return NULL; 61 62 block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); 63 64 (*offset)++; 65 66 if ((*offset << blocksize_bits) >= *elen) 67 *offset = 0; 68 else 69 epos->offset = lextoffset; 70 71 brelse(fibh->sbh); 72 fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); 73 if (!fibh->sbh) 74 return NULL; 75 fibh->soffset = fibh->eoffset = 0; 76 77 if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) { 78 i = 16 >> (blocksize_bits - 9); 79 if (i + *offset > (*elen >> blocksize_bits)) 80 i = (*elen >> blocksize_bits)-*offset; 81 for (num = 0; i > 0; i--) { 82 block = udf_get_lb_pblock(dir->i_sb, eloc, 83 *offset + i); 84 tmp = udf_tgetblk(dir->i_sb, block); 85 if (tmp && !buffer_uptodate(tmp) && 86 !buffer_locked(tmp)) 87 bha[num++] = tmp; 88 else 89 brelse(tmp); 90 } 91 if (num) { 92 ll_rw_block(REQ_OP_READ | REQ_RAHEAD, num, bha); 93 for (i = 0; i < num; i++) 94 brelse(bha[i]); 95 } 96 } 97 } else if (fibh->sbh != fibh->ebh) { 98 brelse(fibh->sbh); 99 fibh->sbh = fibh->ebh; 100 } 101 102 fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, 103 &(fibh->eoffset)); 104 105 if (!fi) 106 return NULL; 107 108 *nf_pos += fibh->eoffset - fibh->soffset; 109 110 if (fibh->eoffset <= dir->i_sb->s_blocksize) { 111 memcpy((uint8_t *)cfi, (uint8_t *)fi, 112 sizeof(struct fileIdentDesc)); 113 } else if (fibh->eoffset > dir->i_sb->s_blocksize) { 114 uint32_t lextoffset = epos->offset; 115 116 if (udf_next_aext(dir, epos, eloc, elen, 1) != 117 (EXT_RECORDED_ALLOCATED >> 30)) 118 return NULL; 119 120 block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); 121 122 (*offset)++; 123 124 if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) 125 *offset = 0; 126 else 127 epos->offset = lextoffset; 128 129 fibh->soffset -= dir->i_sb->s_blocksize; 130 fibh->eoffset -= dir->i_sb->s_blocksize; 131 132 fibh->ebh = udf_tread(dir->i_sb, block); 133 if (!fibh->ebh) 134 return NULL; 135 136 if (sizeof(struct fileIdentDesc) > -fibh->soffset) { 137 int fi_len; 138 139 memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset); 140 memcpy((uint8_t *)cfi - fibh->soffset, 141 fibh->ebh->b_data, 142 sizeof(struct fileIdentDesc) + fibh->soffset); 143 144 fi_len = udf_dir_entry_len(cfi); 145 *nf_pos += fi_len - (fibh->eoffset - fibh->soffset); 146 fibh->eoffset = fibh->soffset + fi_len; 147 } else { 148 memcpy((uint8_t *)cfi, (uint8_t *)fi, 149 sizeof(struct fileIdentDesc)); 150 } 151 } 152 /* Got last entry outside of dir size - fs is corrupted! */ 153 if (*nf_pos > dir->i_size) 154 return NULL; 155 return fi; 156 } 157 158 struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset) 159 { 160 struct fileIdentDesc *fi; 161 int lengthThisIdent; 162 uint8_t *ptr; 163 int padlen; 164 165 if ((!buffer) || (!offset)) { 166 udf_debug("invalidparms, buffer=%p, offset=%p\n", 167 buffer, offset); 168 return NULL; 169 } 170 171 ptr = buffer; 172 173 if ((*offset > 0) && (*offset < bufsize)) 174 ptr += *offset; 175 fi = (struct fileIdentDesc *)ptr; 176 if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) { 177 udf_debug("0x%x != TAG_IDENT_FID\n", 178 le16_to_cpu(fi->descTag.tagIdent)); 179 udf_debug("offset: %d sizeof: %lu bufsize: %d\n", 180 *offset, (unsigned long)sizeof(struct fileIdentDesc), 181 bufsize); 182 return NULL; 183 } 184 if ((*offset + sizeof(struct fileIdentDesc)) > bufsize) 185 lengthThisIdent = sizeof(struct fileIdentDesc); 186 else 187 lengthThisIdent = sizeof(struct fileIdentDesc) + 188 fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse); 189 190 /* we need to figure padding, too! */ 191 padlen = lengthThisIdent % UDF_NAME_PAD; 192 if (padlen) 193 lengthThisIdent += (UDF_NAME_PAD - padlen); 194 *offset = *offset + lengthThisIdent; 195 196 return fi; 197 } 198 199 struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, 200 int inc) 201 { 202 struct short_ad *sa; 203 204 if ((!ptr) || (!offset)) { 205 pr_err("%s: invalidparms\n", __func__); 206 return NULL; 207 } 208 209 if ((*offset + sizeof(struct short_ad)) > maxoffset) 210 return NULL; 211 else { 212 sa = (struct short_ad *)ptr; 213 if (sa->extLength == 0) 214 return NULL; 215 } 216 217 if (inc) 218 *offset += sizeof(struct short_ad); 219 return sa; 220 } 221 222 struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc) 223 { 224 struct long_ad *la; 225 226 if ((!ptr) || (!offset)) { 227 pr_err("%s: invalidparms\n", __func__); 228 return NULL; 229 } 230 231 if ((*offset + sizeof(struct long_ad)) > maxoffset) 232 return NULL; 233 else { 234 la = (struct long_ad *)ptr; 235 if (la->extLength == 0) 236 return NULL; 237 } 238 239 if (inc) 240 *offset += sizeof(struct long_ad); 241 return la; 242 } 243