xref: /openbmc/linux/fs/udf/directory.c (revision e868d61272caa648214046a096e5a6bfc068dc8c)
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