xref: /OK3568_Linux_fs/u-boot/fs/ubifs/ubifs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * This file is part of UBIFS.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2006-2008 Nokia Corporation.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * (C) Copyright 2008-2010
7*4882a593Smuzhiyun  * Stefan Roese, DENX Software Engineering, sr@denx.de.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Authors: Artem Bityutskiy (Битюцкий Артём)
10*4882a593Smuzhiyun  *          Adrian Hunter
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <common.h>
16*4882a593Smuzhiyun #include <memalign.h>
17*4882a593Smuzhiyun #include "ubifs.h"
18*4882a593Smuzhiyun #include <u-boot/zlib.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/err.h>
21*4882a593Smuzhiyun #include <linux/lzo.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* compress.c */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * We need a wrapper for zunzip() because the parameters are
29*4882a593Smuzhiyun  * incompatible with the lzo decompressor.
30*4882a593Smuzhiyun  */
gzip_decompress(const unsigned char * in,size_t in_len,unsigned char * out,size_t * out_len)31*4882a593Smuzhiyun static int gzip_decompress(const unsigned char *in, size_t in_len,
32*4882a593Smuzhiyun 			   unsigned char *out, size_t *out_len)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	return zunzip(out, *out_len, (unsigned char *)in,
35*4882a593Smuzhiyun 		      (unsigned long *)out_len, 0, 0);
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /* Fake description object for the "none" compressor */
39*4882a593Smuzhiyun static struct ubifs_compressor none_compr = {
40*4882a593Smuzhiyun 	.compr_type = UBIFS_COMPR_NONE,
41*4882a593Smuzhiyun 	.name = "none",
42*4882a593Smuzhiyun 	.capi_name = "",
43*4882a593Smuzhiyun 	.decompress = NULL,
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static struct ubifs_compressor lzo_compr = {
47*4882a593Smuzhiyun 	.compr_type = UBIFS_COMPR_LZO,
48*4882a593Smuzhiyun #ifndef __UBOOT__
49*4882a593Smuzhiyun 	.comp_mutex = &lzo_mutex,
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun 	.name = "lzo",
52*4882a593Smuzhiyun 	.capi_name = "lzo",
53*4882a593Smuzhiyun 	.decompress = lzo1x_decompress_safe,
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun static struct ubifs_compressor zlib_compr = {
57*4882a593Smuzhiyun 	.compr_type = UBIFS_COMPR_ZLIB,
58*4882a593Smuzhiyun #ifndef __UBOOT__
59*4882a593Smuzhiyun 	.comp_mutex = &deflate_mutex,
60*4882a593Smuzhiyun 	.decomp_mutex = &inflate_mutex,
61*4882a593Smuzhiyun #endif
62*4882a593Smuzhiyun 	.name = "zlib",
63*4882a593Smuzhiyun 	.capi_name = "deflate",
64*4882a593Smuzhiyun 	.decompress = gzip_decompress,
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun /* All UBIFS compressors */
68*4882a593Smuzhiyun struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun #ifdef __UBOOT__
72*4882a593Smuzhiyun /* from mm/util.c */
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun /**
75*4882a593Smuzhiyun  * kmemdup - duplicate region of memory
76*4882a593Smuzhiyun  *
77*4882a593Smuzhiyun  * @src: memory region to duplicate
78*4882a593Smuzhiyun  * @len: memory region length
79*4882a593Smuzhiyun  * @gfp: GFP mask to use
80*4882a593Smuzhiyun  */
kmemdup(const void * src,size_t len,gfp_t gfp)81*4882a593Smuzhiyun void *kmemdup(const void *src, size_t len, gfp_t gfp)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	void *p;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	p = kmalloc(len, gfp);
86*4882a593Smuzhiyun 	if (p)
87*4882a593Smuzhiyun 		memcpy(p, src, len);
88*4882a593Smuzhiyun 	return p;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun struct crypto_comp {
92*4882a593Smuzhiyun 	int compressor;
93*4882a593Smuzhiyun };
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun static inline struct crypto_comp
crypto_alloc_comp(const char * alg_name,u32 type,u32 mask)96*4882a593Smuzhiyun *crypto_alloc_comp(const char *alg_name, u32 type, u32 mask)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	struct ubifs_compressor *comp;
99*4882a593Smuzhiyun 	struct crypto_comp *ptr;
100*4882a593Smuzhiyun 	int i = 0;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	ptr = malloc_cache_aligned(sizeof(struct crypto_comp));
103*4882a593Smuzhiyun 	while (i < UBIFS_COMPR_TYPES_CNT) {
104*4882a593Smuzhiyun 		comp = ubifs_compressors[i];
105*4882a593Smuzhiyun 		if (!comp) {
106*4882a593Smuzhiyun 			i++;
107*4882a593Smuzhiyun 			continue;
108*4882a593Smuzhiyun 		}
109*4882a593Smuzhiyun 		if (strncmp(alg_name, comp->capi_name, strlen(alg_name)) == 0) {
110*4882a593Smuzhiyun 			ptr->compressor = i;
111*4882a593Smuzhiyun 			return ptr;
112*4882a593Smuzhiyun 		}
113*4882a593Smuzhiyun 		i++;
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 	if (i >= UBIFS_COMPR_TYPES_CNT) {
116*4882a593Smuzhiyun 		dbg_gen("invalid compression type %s", alg_name);
117*4882a593Smuzhiyun 		free (ptr);
118*4882a593Smuzhiyun 		return NULL;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 	return ptr;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun static inline int
crypto_comp_decompress(const struct ubifs_info * c,struct crypto_comp * tfm,const u8 * src,unsigned int slen,u8 * dst,unsigned int * dlen)123*4882a593Smuzhiyun crypto_comp_decompress(const struct ubifs_info *c, struct crypto_comp *tfm,
124*4882a593Smuzhiyun 		       const u8 *src, unsigned int slen, u8 *dst,
125*4882a593Smuzhiyun 		       unsigned int *dlen)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct ubifs_compressor *compr = ubifs_compressors[tfm->compressor];
128*4882a593Smuzhiyun 	int err;
129*4882a593Smuzhiyun 	size_t tmp_len = *dlen;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (compr->compr_type == UBIFS_COMPR_NONE) {
132*4882a593Smuzhiyun 		memcpy(dst, src, slen);
133*4882a593Smuzhiyun 		*dlen = slen;
134*4882a593Smuzhiyun 		return 0;
135*4882a593Smuzhiyun 	}
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	err = compr->decompress(src, slen, dst, &tmp_len);
138*4882a593Smuzhiyun 	if (err)
139*4882a593Smuzhiyun 		ubifs_err(c, "cannot decompress %d bytes, compressor %s, "
140*4882a593Smuzhiyun 			  "error %d", slen, compr->name, err);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	*dlen = tmp_len;
143*4882a593Smuzhiyun 	return err;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun /* from shrinker.c */
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun /* Global clean znode counter (for all mounted UBIFS instances) */
151*4882a593Smuzhiyun atomic_long_t ubifs_clean_zn_cnt;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun #endif
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun /**
156*4882a593Smuzhiyun  * ubifs_decompress - decompress data.
157*4882a593Smuzhiyun  * @in_buf: data to decompress
158*4882a593Smuzhiyun  * @in_len: length of the data to decompress
159*4882a593Smuzhiyun  * @out_buf: output buffer where decompressed data should
160*4882a593Smuzhiyun  * @out_len: output length is returned here
161*4882a593Smuzhiyun  * @compr_type: type of compression
162*4882a593Smuzhiyun  *
163*4882a593Smuzhiyun  * This function decompresses data from buffer @in_buf into buffer @out_buf.
164*4882a593Smuzhiyun  * The length of the uncompressed data is returned in @out_len. This functions
165*4882a593Smuzhiyun  * returns %0 on success or a negative error code on failure.
166*4882a593Smuzhiyun  */
ubifs_decompress(const struct ubifs_info * c,const void * in_buf,int in_len,void * out_buf,int * out_len,int compr_type)167*4882a593Smuzhiyun int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
168*4882a593Smuzhiyun 		     int in_len, void *out_buf, int *out_len, int compr_type)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	int err;
171*4882a593Smuzhiyun 	struct ubifs_compressor *compr;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
174*4882a593Smuzhiyun 		ubifs_err(c, "invalid compression type %d", compr_type);
175*4882a593Smuzhiyun 		return -EINVAL;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	compr = ubifs_compressors[compr_type];
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (unlikely(!compr->capi_name)) {
181*4882a593Smuzhiyun 		ubifs_err(c, "%s compression is not compiled in", compr->name);
182*4882a593Smuzhiyun 		return -EINVAL;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (compr_type == UBIFS_COMPR_NONE) {
186*4882a593Smuzhiyun 		memcpy(out_buf, in_buf, in_len);
187*4882a593Smuzhiyun 		*out_len = in_len;
188*4882a593Smuzhiyun 		return 0;
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	if (compr->decomp_mutex)
192*4882a593Smuzhiyun 		mutex_lock(compr->decomp_mutex);
193*4882a593Smuzhiyun 	err = crypto_comp_decompress(c, compr->cc, in_buf, in_len, out_buf,
194*4882a593Smuzhiyun 				     (unsigned int *)out_len);
195*4882a593Smuzhiyun 	if (compr->decomp_mutex)
196*4882a593Smuzhiyun 		mutex_unlock(compr->decomp_mutex);
197*4882a593Smuzhiyun 	if (err)
198*4882a593Smuzhiyun 		ubifs_err(c, "cannot decompress %d bytes, compressor %s,"
199*4882a593Smuzhiyun 			  " error %d", in_len, compr->name, err);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	return err;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun /**
205*4882a593Smuzhiyun  * compr_init - initialize a compressor.
206*4882a593Smuzhiyun  * @compr: compressor description object
207*4882a593Smuzhiyun  *
208*4882a593Smuzhiyun  * This function initializes the requested compressor and returns zero in case
209*4882a593Smuzhiyun  * of success or a negative error code in case of failure.
210*4882a593Smuzhiyun  */
compr_init(struct ubifs_compressor * compr)211*4882a593Smuzhiyun static int __init compr_init(struct ubifs_compressor *compr)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	ubifs_compressors[compr->compr_type] = compr;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun #ifdef CONFIG_NEEDS_MANUAL_RELOC
216*4882a593Smuzhiyun 	ubifs_compressors[compr->compr_type]->name += gd->reloc_off;
217*4882a593Smuzhiyun 	ubifs_compressors[compr->compr_type]->capi_name += gd->reloc_off;
218*4882a593Smuzhiyun 	ubifs_compressors[compr->compr_type]->decompress += gd->reloc_off;
219*4882a593Smuzhiyun #endif
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	if (compr->capi_name) {
222*4882a593Smuzhiyun 		compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
223*4882a593Smuzhiyun 		if (IS_ERR(compr->cc)) {
224*4882a593Smuzhiyun 			dbg_gen("cannot initialize compressor %s,"
225*4882a593Smuzhiyun 				  " error %ld", compr->name,
226*4882a593Smuzhiyun 				  PTR_ERR(compr->cc));
227*4882a593Smuzhiyun 			return PTR_ERR(compr->cc);
228*4882a593Smuzhiyun 		}
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun /**
235*4882a593Smuzhiyun  * ubifs_compressors_init - initialize UBIFS compressors.
236*4882a593Smuzhiyun  *
237*4882a593Smuzhiyun  * This function initializes the compressor which were compiled in. Returns
238*4882a593Smuzhiyun  * zero in case of success and a negative error code in case of failure.
239*4882a593Smuzhiyun  */
ubifs_compressors_init(void)240*4882a593Smuzhiyun int __init ubifs_compressors_init(void)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	int err;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	err = compr_init(&lzo_compr);
245*4882a593Smuzhiyun 	if (err)
246*4882a593Smuzhiyun 		return err;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	err = compr_init(&zlib_compr);
249*4882a593Smuzhiyun 	if (err)
250*4882a593Smuzhiyun 		return err;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	err = compr_init(&none_compr);
253*4882a593Smuzhiyun 	if (err)
254*4882a593Smuzhiyun 		return err;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	return 0;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun /*
260*4882a593Smuzhiyun  * ubifsls...
261*4882a593Smuzhiyun  */
262*4882a593Smuzhiyun 
filldir(struct ubifs_info * c,const char * name,int namlen,u64 ino,unsigned int d_type)263*4882a593Smuzhiyun static int filldir(struct ubifs_info *c, const char *name, int namlen,
264*4882a593Smuzhiyun 		   u64 ino, unsigned int d_type)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	struct inode *inode;
267*4882a593Smuzhiyun 	char filetime[32];
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	switch (d_type) {
270*4882a593Smuzhiyun 	case UBIFS_ITYPE_REG:
271*4882a593Smuzhiyun 		printf("\t");
272*4882a593Smuzhiyun 		break;
273*4882a593Smuzhiyun 	case UBIFS_ITYPE_DIR:
274*4882a593Smuzhiyun 		printf("<DIR>\t");
275*4882a593Smuzhiyun 		break;
276*4882a593Smuzhiyun 	case UBIFS_ITYPE_LNK:
277*4882a593Smuzhiyun 		printf("<LNK>\t");
278*4882a593Smuzhiyun 		break;
279*4882a593Smuzhiyun 	default:
280*4882a593Smuzhiyun 		printf("other\t");
281*4882a593Smuzhiyun 		break;
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	inode = ubifs_iget(c->vfs_sb, ino);
285*4882a593Smuzhiyun 	if (IS_ERR(inode)) {
286*4882a593Smuzhiyun 		printf("%s: Error in ubifs_iget(), ino=%lld ret=%p!\n",
287*4882a593Smuzhiyun 		       __func__, ino, inode);
288*4882a593Smuzhiyun 		return -1;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 	ctime_r((time_t *)&inode->i_mtime, filetime);
291*4882a593Smuzhiyun 	printf("%9lld  %24.24s  ", inode->i_size, filetime);
292*4882a593Smuzhiyun #ifndef __UBOOT__
293*4882a593Smuzhiyun 	ubifs_iput(inode);
294*4882a593Smuzhiyun #endif
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	printf("%s\n", name);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
ubifs_printdir(struct file * file,void * dirent)301*4882a593Smuzhiyun static int ubifs_printdir(struct file *file, void *dirent)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	int err, over = 0;
304*4882a593Smuzhiyun 	struct qstr nm;
305*4882a593Smuzhiyun 	union ubifs_key key;
306*4882a593Smuzhiyun 	struct ubifs_dent_node *dent;
307*4882a593Smuzhiyun 	struct inode *dir = file->f_path.dentry->d_inode;
308*4882a593Smuzhiyun 	struct ubifs_info *c = dir->i_sb->s_fs_info;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
313*4882a593Smuzhiyun 		/*
314*4882a593Smuzhiyun 		 * The directory was seek'ed to a senseless position or there
315*4882a593Smuzhiyun 		 * are no more entries.
316*4882a593Smuzhiyun 		 */
317*4882a593Smuzhiyun 		return 0;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	if (file->f_pos == 1) {
320*4882a593Smuzhiyun 		/* Find the first entry in TNC and save it */
321*4882a593Smuzhiyun 		lowest_dent_key(c, &key, dir->i_ino);
322*4882a593Smuzhiyun 		nm.name = NULL;
323*4882a593Smuzhiyun 		dent = ubifs_tnc_next_ent(c, &key, &nm);
324*4882a593Smuzhiyun 		if (IS_ERR(dent)) {
325*4882a593Smuzhiyun 			err = PTR_ERR(dent);
326*4882a593Smuzhiyun 			goto out;
327*4882a593Smuzhiyun 		}
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 		file->f_pos = key_hash_flash(c, &dent->key);
330*4882a593Smuzhiyun 		file->private_data = dent;
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	dent = file->private_data;
334*4882a593Smuzhiyun 	if (!dent) {
335*4882a593Smuzhiyun 		/*
336*4882a593Smuzhiyun 		 * The directory was seek'ed to and is now readdir'ed.
337*4882a593Smuzhiyun 		 * Find the entry corresponding to @file->f_pos or the
338*4882a593Smuzhiyun 		 * closest one.
339*4882a593Smuzhiyun 		 */
340*4882a593Smuzhiyun 		dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
341*4882a593Smuzhiyun 		nm.name = NULL;
342*4882a593Smuzhiyun 		dent = ubifs_tnc_next_ent(c, &key, &nm);
343*4882a593Smuzhiyun 		if (IS_ERR(dent)) {
344*4882a593Smuzhiyun 			err = PTR_ERR(dent);
345*4882a593Smuzhiyun 			goto out;
346*4882a593Smuzhiyun 		}
347*4882a593Smuzhiyun 		file->f_pos = key_hash_flash(c, &dent->key);
348*4882a593Smuzhiyun 		file->private_data = dent;
349*4882a593Smuzhiyun 	}
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	while (1) {
352*4882a593Smuzhiyun 		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
353*4882a593Smuzhiyun 			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
354*4882a593Smuzhiyun 			key_hash_flash(c, &dent->key));
355*4882a593Smuzhiyun #ifndef __UBOOT__
356*4882a593Smuzhiyun 		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
357*4882a593Smuzhiyun #endif
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		nm.len = le16_to_cpu(dent->nlen);
360*4882a593Smuzhiyun 		over = filldir(c, (char *)dent->name, nm.len,
361*4882a593Smuzhiyun 			       le64_to_cpu(dent->inum), dent->type);
362*4882a593Smuzhiyun 		if (over)
363*4882a593Smuzhiyun 			return 0;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 		/* Switch to the next entry */
366*4882a593Smuzhiyun 		key_read(c, &dent->key, &key);
367*4882a593Smuzhiyun 		nm.name = (char *)dent->name;
368*4882a593Smuzhiyun 		dent = ubifs_tnc_next_ent(c, &key, &nm);
369*4882a593Smuzhiyun 		if (IS_ERR(dent)) {
370*4882a593Smuzhiyun 			err = PTR_ERR(dent);
371*4882a593Smuzhiyun 			goto out;
372*4882a593Smuzhiyun 		}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		kfree(file->private_data);
375*4882a593Smuzhiyun 		file->f_pos = key_hash_flash(c, &dent->key);
376*4882a593Smuzhiyun 		file->private_data = dent;
377*4882a593Smuzhiyun 		cond_resched();
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun out:
381*4882a593Smuzhiyun 	if (err != -ENOENT) {
382*4882a593Smuzhiyun 		ubifs_err(c, "cannot find next direntry, error %d", err);
383*4882a593Smuzhiyun 		return err;
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	kfree(file->private_data);
387*4882a593Smuzhiyun 	file->private_data = NULL;
388*4882a593Smuzhiyun 	file->f_pos = 2;
389*4882a593Smuzhiyun 	return 0;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
ubifs_finddir(struct super_block * sb,char * dirname,unsigned long root_inum,unsigned long * inum)392*4882a593Smuzhiyun static int ubifs_finddir(struct super_block *sb, char *dirname,
393*4882a593Smuzhiyun 			 unsigned long root_inum, unsigned long *inum)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	int err;
396*4882a593Smuzhiyun 	struct qstr nm;
397*4882a593Smuzhiyun 	union ubifs_key key;
398*4882a593Smuzhiyun 	struct ubifs_dent_node *dent;
399*4882a593Smuzhiyun 	struct ubifs_info *c;
400*4882a593Smuzhiyun 	struct file *file;
401*4882a593Smuzhiyun 	struct dentry *dentry;
402*4882a593Smuzhiyun 	struct inode *dir;
403*4882a593Smuzhiyun 	int ret = 0;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	file = kzalloc(sizeof(struct file), 0);
406*4882a593Smuzhiyun 	dentry = kzalloc(sizeof(struct dentry), 0);
407*4882a593Smuzhiyun 	dir = kzalloc(sizeof(struct inode), 0);
408*4882a593Smuzhiyun 	if (!file || !dentry || !dir) {
409*4882a593Smuzhiyun 		printf("%s: Error, no memory for malloc!\n", __func__);
410*4882a593Smuzhiyun 		err = -ENOMEM;
411*4882a593Smuzhiyun 		goto out;
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	dir->i_sb = sb;
415*4882a593Smuzhiyun 	file->f_path.dentry = dentry;
416*4882a593Smuzhiyun 	file->f_path.dentry->d_parent = dentry;
417*4882a593Smuzhiyun 	file->f_path.dentry->d_inode = dir;
418*4882a593Smuzhiyun 	file->f_path.dentry->d_inode->i_ino = root_inum;
419*4882a593Smuzhiyun 	c = sb->s_fs_info;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	/* Find the first entry in TNC and save it */
424*4882a593Smuzhiyun 	lowest_dent_key(c, &key, dir->i_ino);
425*4882a593Smuzhiyun 	nm.name = NULL;
426*4882a593Smuzhiyun 	dent = ubifs_tnc_next_ent(c, &key, &nm);
427*4882a593Smuzhiyun 	if (IS_ERR(dent)) {
428*4882a593Smuzhiyun 		err = PTR_ERR(dent);
429*4882a593Smuzhiyun 		goto out;
430*4882a593Smuzhiyun 	}
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	file->f_pos = key_hash_flash(c, &dent->key);
433*4882a593Smuzhiyun 	file->private_data = dent;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	while (1) {
436*4882a593Smuzhiyun 		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
437*4882a593Smuzhiyun 			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
438*4882a593Smuzhiyun 			key_hash_flash(c, &dent->key));
439*4882a593Smuzhiyun #ifndef __UBOOT__
440*4882a593Smuzhiyun 		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
441*4882a593Smuzhiyun #endif
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 		nm.len = le16_to_cpu(dent->nlen);
444*4882a593Smuzhiyun 		if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) &&
445*4882a593Smuzhiyun 		    (strlen(dirname) == nm.len)) {
446*4882a593Smuzhiyun 			*inum = le64_to_cpu(dent->inum);
447*4882a593Smuzhiyun 			ret = 1;
448*4882a593Smuzhiyun 			goto out_free;
449*4882a593Smuzhiyun 		}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 		/* Switch to the next entry */
452*4882a593Smuzhiyun 		key_read(c, &dent->key, &key);
453*4882a593Smuzhiyun 		nm.name = (char *)dent->name;
454*4882a593Smuzhiyun 		dent = ubifs_tnc_next_ent(c, &key, &nm);
455*4882a593Smuzhiyun 		if (IS_ERR(dent)) {
456*4882a593Smuzhiyun 			err = PTR_ERR(dent);
457*4882a593Smuzhiyun 			goto out;
458*4882a593Smuzhiyun 		}
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 		kfree(file->private_data);
461*4882a593Smuzhiyun 		file->f_pos = key_hash_flash(c, &dent->key);
462*4882a593Smuzhiyun 		file->private_data = dent;
463*4882a593Smuzhiyun 		cond_resched();
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun out:
467*4882a593Smuzhiyun 	if (err != -ENOENT)
468*4882a593Smuzhiyun 		dbg_gen("cannot find next direntry, error %d", err);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun out_free:
471*4882a593Smuzhiyun 	kfree(file->private_data);
472*4882a593Smuzhiyun 	free(file);
473*4882a593Smuzhiyun 	free(dentry);
474*4882a593Smuzhiyun 	free(dir);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	return ret;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
ubifs_findfile(struct super_block * sb,char * filename)479*4882a593Smuzhiyun static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun 	int ret;
482*4882a593Smuzhiyun 	char *next;
483*4882a593Smuzhiyun 	char fpath[128];
484*4882a593Smuzhiyun 	char symlinkpath[128];
485*4882a593Smuzhiyun 	char *name = fpath;
486*4882a593Smuzhiyun 	unsigned long root_inum = 1;
487*4882a593Smuzhiyun 	unsigned long inum;
488*4882a593Smuzhiyun 	int symlink_count = 0; /* Don't allow symlink recursion */
489*4882a593Smuzhiyun 	char link_name[64];
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	strcpy(fpath, filename);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	/* Remove all leading slashes */
494*4882a593Smuzhiyun 	while (*name == '/')
495*4882a593Smuzhiyun 		name++;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	/*
498*4882a593Smuzhiyun 	 * Handle root-direcoty ('/')
499*4882a593Smuzhiyun 	 */
500*4882a593Smuzhiyun 	inum = root_inum;
501*4882a593Smuzhiyun 	if (!name || *name == '\0')
502*4882a593Smuzhiyun 		return inum;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	for (;;) {
505*4882a593Smuzhiyun 		struct inode *inode;
506*4882a593Smuzhiyun 		struct ubifs_inode *ui;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 		/* Extract the actual part from the pathname.  */
509*4882a593Smuzhiyun 		next = strchr(name, '/');
510*4882a593Smuzhiyun 		if (next) {
511*4882a593Smuzhiyun 			/* Remove all leading slashes.  */
512*4882a593Smuzhiyun 			while (*next == '/')
513*4882a593Smuzhiyun 				*(next++) = '\0';
514*4882a593Smuzhiyun 		}
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 		ret = ubifs_finddir(sb, name, root_inum, &inum);
517*4882a593Smuzhiyun 		if (!ret)
518*4882a593Smuzhiyun 			return 0;
519*4882a593Smuzhiyun 		inode = ubifs_iget(sb, inum);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 		if (!inode)
522*4882a593Smuzhiyun 			return 0;
523*4882a593Smuzhiyun 		ui = ubifs_inode(inode);
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 		if ((inode->i_mode & S_IFMT) == S_IFLNK) {
526*4882a593Smuzhiyun 			char buf[128];
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 			/* We have some sort of symlink recursion, bail out */
529*4882a593Smuzhiyun 			if (symlink_count++ > 8) {
530*4882a593Smuzhiyun 				printf("Symlink recursion, aborting\n");
531*4882a593Smuzhiyun 				return 0;
532*4882a593Smuzhiyun 			}
533*4882a593Smuzhiyun 			memcpy(link_name, ui->data, ui->data_len);
534*4882a593Smuzhiyun 			link_name[ui->data_len] = '\0';
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 			if (link_name[0] == '/') {
537*4882a593Smuzhiyun 				/* Absolute path, redo everything without
538*4882a593Smuzhiyun 				 * the leading slash */
539*4882a593Smuzhiyun 				next = name = link_name + 1;
540*4882a593Smuzhiyun 				root_inum = 1;
541*4882a593Smuzhiyun 				continue;
542*4882a593Smuzhiyun 			}
543*4882a593Smuzhiyun 			/* Relative to cur dir */
544*4882a593Smuzhiyun 			sprintf(buf, "%s/%s",
545*4882a593Smuzhiyun 					link_name, next == NULL ? "" : next);
546*4882a593Smuzhiyun 			memcpy(symlinkpath, buf, sizeof(buf));
547*4882a593Smuzhiyun 			next = name = symlinkpath;
548*4882a593Smuzhiyun 			continue;
549*4882a593Smuzhiyun 		}
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 		/*
552*4882a593Smuzhiyun 		 * Check if directory with this name exists
553*4882a593Smuzhiyun 		 */
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 		/* Found the node!  */
556*4882a593Smuzhiyun 		if (!next || *next == '\0')
557*4882a593Smuzhiyun 			return inum;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 		root_inum = inum;
560*4882a593Smuzhiyun 		name = next;
561*4882a593Smuzhiyun 	}
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	return 0;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun 
ubifs_set_blk_dev(struct blk_desc * rbdd,disk_partition_t * info)566*4882a593Smuzhiyun int ubifs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	if (rbdd) {
569*4882a593Smuzhiyun 		debug("UBIFS cannot be used with normal block devices\n");
570*4882a593Smuzhiyun 		return -1;
571*4882a593Smuzhiyun 	}
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	/*
574*4882a593Smuzhiyun 	 * Should never happen since blk_get_device_part_str() already checks
575*4882a593Smuzhiyun 	 * this, but better safe then sorry.
576*4882a593Smuzhiyun 	 */
577*4882a593Smuzhiyun 	if (!ubifs_is_mounted()) {
578*4882a593Smuzhiyun 		debug("UBIFS not mounted, use ubifsmount to mount volume first!\n");
579*4882a593Smuzhiyun 		return -1;
580*4882a593Smuzhiyun 	}
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	return 0;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
ubifs_ls(const char * filename)585*4882a593Smuzhiyun int ubifs_ls(const char *filename)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	struct ubifs_info *c = ubifs_sb->s_fs_info;
588*4882a593Smuzhiyun 	struct file *file;
589*4882a593Smuzhiyun 	struct dentry *dentry;
590*4882a593Smuzhiyun 	struct inode *dir;
591*4882a593Smuzhiyun 	void *dirent = NULL;
592*4882a593Smuzhiyun 	unsigned long inum;
593*4882a593Smuzhiyun 	int ret = 0;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
596*4882a593Smuzhiyun 	inum = ubifs_findfile(ubifs_sb, (char *)filename);
597*4882a593Smuzhiyun 	if (!inum) {
598*4882a593Smuzhiyun 		ret = -1;
599*4882a593Smuzhiyun 		goto out;
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	file = kzalloc(sizeof(struct file), 0);
603*4882a593Smuzhiyun 	dentry = kzalloc(sizeof(struct dentry), 0);
604*4882a593Smuzhiyun 	dir = kzalloc(sizeof(struct inode), 0);
605*4882a593Smuzhiyun 	if (!file || !dentry || !dir) {
606*4882a593Smuzhiyun 		printf("%s: Error, no memory for malloc!\n", __func__);
607*4882a593Smuzhiyun 		ret = -ENOMEM;
608*4882a593Smuzhiyun 		goto out_mem;
609*4882a593Smuzhiyun 	}
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	dir->i_sb = ubifs_sb;
612*4882a593Smuzhiyun 	file->f_path.dentry = dentry;
613*4882a593Smuzhiyun 	file->f_path.dentry->d_parent = dentry;
614*4882a593Smuzhiyun 	file->f_path.dentry->d_inode = dir;
615*4882a593Smuzhiyun 	file->f_path.dentry->d_inode->i_ino = inum;
616*4882a593Smuzhiyun 	file->f_pos = 1;
617*4882a593Smuzhiyun 	file->private_data = NULL;
618*4882a593Smuzhiyun 	ubifs_printdir(file, dirent);
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun out_mem:
621*4882a593Smuzhiyun 	if (file)
622*4882a593Smuzhiyun 		free(file);
623*4882a593Smuzhiyun 	if (dentry)
624*4882a593Smuzhiyun 		free(dentry);
625*4882a593Smuzhiyun 	if (dir)
626*4882a593Smuzhiyun 		free(dir);
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun out:
629*4882a593Smuzhiyun 	ubi_close_volume(c->ubi);
630*4882a593Smuzhiyun 	return ret;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun 
ubifs_exists(const char * filename)633*4882a593Smuzhiyun int ubifs_exists(const char *filename)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	struct ubifs_info *c = ubifs_sb->s_fs_info;
636*4882a593Smuzhiyun 	unsigned long inum;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
639*4882a593Smuzhiyun 	inum = ubifs_findfile(ubifs_sb, (char *)filename);
640*4882a593Smuzhiyun 	ubi_close_volume(c->ubi);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	return inum != 0;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun 
ubifs_size(const char * filename,loff_t * size)645*4882a593Smuzhiyun int ubifs_size(const char *filename, loff_t *size)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun 	struct ubifs_info *c = ubifs_sb->s_fs_info;
648*4882a593Smuzhiyun 	unsigned long inum;
649*4882a593Smuzhiyun 	struct inode *inode;
650*4882a593Smuzhiyun 	int err = 0;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	inum = ubifs_findfile(ubifs_sb, (char *)filename);
655*4882a593Smuzhiyun 	if (!inum) {
656*4882a593Smuzhiyun 		err = -1;
657*4882a593Smuzhiyun 		goto out;
658*4882a593Smuzhiyun 	}
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	inode = ubifs_iget(ubifs_sb, inum);
661*4882a593Smuzhiyun 	if (IS_ERR(inode)) {
662*4882a593Smuzhiyun 		printf("%s: Error reading inode %ld!\n", __func__, inum);
663*4882a593Smuzhiyun 		err = PTR_ERR(inode);
664*4882a593Smuzhiyun 		goto out;
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	*size = inode->i_size;
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	ubifs_iput(inode);
670*4882a593Smuzhiyun out:
671*4882a593Smuzhiyun 	ubi_close_volume(c->ubi);
672*4882a593Smuzhiyun 	return err;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun /*
676*4882a593Smuzhiyun  * ubifsload...
677*4882a593Smuzhiyun  */
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun /* file.c */
680*4882a593Smuzhiyun 
kmap(struct page * page)681*4882a593Smuzhiyun static inline void *kmap(struct page *page)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun 	return page->addr;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
read_block(struct inode * inode,void * addr,unsigned int block,struct ubifs_data_node * dn)686*4882a593Smuzhiyun static int read_block(struct inode *inode, void *addr, unsigned int block,
687*4882a593Smuzhiyun 		      struct ubifs_data_node *dn)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun 	struct ubifs_info *c = inode->i_sb->s_fs_info;
690*4882a593Smuzhiyun 	int err, len, out_len;
691*4882a593Smuzhiyun 	union ubifs_key key;
692*4882a593Smuzhiyun 	unsigned int dlen;
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	data_key_init(c, &key, inode->i_ino, block);
695*4882a593Smuzhiyun 	err = ubifs_tnc_lookup(c, &key, dn);
696*4882a593Smuzhiyun 	if (err) {
697*4882a593Smuzhiyun 		if (err == -ENOENT)
698*4882a593Smuzhiyun 			/* Not found, so it must be a hole */
699*4882a593Smuzhiyun 			memset(addr, 0, UBIFS_BLOCK_SIZE);
700*4882a593Smuzhiyun 		return err;
701*4882a593Smuzhiyun 	}
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	len = le32_to_cpu(dn->size);
706*4882a593Smuzhiyun 	if (len <= 0 || len > UBIFS_BLOCK_SIZE)
707*4882a593Smuzhiyun 		goto dump;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
710*4882a593Smuzhiyun 	out_len = UBIFS_BLOCK_SIZE;
711*4882a593Smuzhiyun 	err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
712*4882a593Smuzhiyun 			       le16_to_cpu(dn->compr_type));
713*4882a593Smuzhiyun 	if (err || len != out_len)
714*4882a593Smuzhiyun 		goto dump;
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	/*
717*4882a593Smuzhiyun 	 * Data length can be less than a full block, even for blocks that are
718*4882a593Smuzhiyun 	 * not the last in the file (e.g., as a result of making a hole and
719*4882a593Smuzhiyun 	 * appending data). Ensure that the remainder is zeroed out.
720*4882a593Smuzhiyun 	 */
721*4882a593Smuzhiyun 	if (len < UBIFS_BLOCK_SIZE)
722*4882a593Smuzhiyun 		memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	return 0;
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun dump:
727*4882a593Smuzhiyun 	ubifs_err(c, "bad data node (block %u, inode %lu)",
728*4882a593Smuzhiyun 		  block, inode->i_ino);
729*4882a593Smuzhiyun 	ubifs_dump_node(c, dn);
730*4882a593Smuzhiyun 	return -EINVAL;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun 
do_readpage(struct ubifs_info * c,struct inode * inode,struct page * page,int last_block_size)733*4882a593Smuzhiyun static int do_readpage(struct ubifs_info *c, struct inode *inode,
734*4882a593Smuzhiyun 		       struct page *page, int last_block_size)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun 	void *addr;
737*4882a593Smuzhiyun 	int err = 0, i;
738*4882a593Smuzhiyun 	unsigned int block, beyond;
739*4882a593Smuzhiyun 	struct ubifs_data_node *dn;
740*4882a593Smuzhiyun 	loff_t i_size = inode->i_size;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	dbg_gen("ino %lu, pg %lu, i_size %lld",
743*4882a593Smuzhiyun 		inode->i_ino, page->index, i_size);
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	addr = kmap(page);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
748*4882a593Smuzhiyun 	beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
749*4882a593Smuzhiyun 	if (block >= beyond) {
750*4882a593Smuzhiyun 		/* Reading beyond inode */
751*4882a593Smuzhiyun 		memset(addr, 0, PAGE_CACHE_SIZE);
752*4882a593Smuzhiyun 		goto out;
753*4882a593Smuzhiyun 	}
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
756*4882a593Smuzhiyun 	if (!dn)
757*4882a593Smuzhiyun 		return -ENOMEM;
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	i = 0;
760*4882a593Smuzhiyun 	while (1) {
761*4882a593Smuzhiyun 		int ret;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 		if (block >= beyond) {
764*4882a593Smuzhiyun 			/* Reading beyond inode */
765*4882a593Smuzhiyun 			err = -ENOENT;
766*4882a593Smuzhiyun 			memset(addr, 0, UBIFS_BLOCK_SIZE);
767*4882a593Smuzhiyun 		} else {
768*4882a593Smuzhiyun 			/*
769*4882a593Smuzhiyun 			 * Reading last block? Make sure to not write beyond
770*4882a593Smuzhiyun 			 * the requested size in the destination buffer.
771*4882a593Smuzhiyun 			 */
772*4882a593Smuzhiyun 			if (((block + 1) == beyond) || last_block_size) {
773*4882a593Smuzhiyun 				void *buff;
774*4882a593Smuzhiyun 				int dlen;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 				/*
777*4882a593Smuzhiyun 				 * We need to buffer the data locally for the
778*4882a593Smuzhiyun 				 * last block. This is to not pad the
779*4882a593Smuzhiyun 				 * destination area to a multiple of
780*4882a593Smuzhiyun 				 * UBIFS_BLOCK_SIZE.
781*4882a593Smuzhiyun 				 */
782*4882a593Smuzhiyun 				buff = malloc_cache_aligned(UBIFS_BLOCK_SIZE);
783*4882a593Smuzhiyun 				if (!buff) {
784*4882a593Smuzhiyun 					printf("%s: Error, malloc fails!\n",
785*4882a593Smuzhiyun 					       __func__);
786*4882a593Smuzhiyun 					err = -ENOMEM;
787*4882a593Smuzhiyun 					break;
788*4882a593Smuzhiyun 				}
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 				/* Read block-size into temp buffer */
791*4882a593Smuzhiyun 				ret = read_block(inode, buff, block, dn);
792*4882a593Smuzhiyun 				if (ret) {
793*4882a593Smuzhiyun 					err = ret;
794*4882a593Smuzhiyun 					if (err != -ENOENT) {
795*4882a593Smuzhiyun 						free(buff);
796*4882a593Smuzhiyun 						break;
797*4882a593Smuzhiyun 					}
798*4882a593Smuzhiyun 				}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 				if (last_block_size)
801*4882a593Smuzhiyun 					dlen = last_block_size;
802*4882a593Smuzhiyun 				else if (ret)
803*4882a593Smuzhiyun 					dlen = UBIFS_BLOCK_SIZE;
804*4882a593Smuzhiyun 				else
805*4882a593Smuzhiyun 					dlen = le32_to_cpu(dn->size);
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 				/* Now copy required size back to dest */
808*4882a593Smuzhiyun 				memcpy(addr, buff, dlen);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 				free(buff);
811*4882a593Smuzhiyun 			} else {
812*4882a593Smuzhiyun 				ret = read_block(inode, addr, block, dn);
813*4882a593Smuzhiyun 				if (ret) {
814*4882a593Smuzhiyun 					err = ret;
815*4882a593Smuzhiyun 					if (err != -ENOENT)
816*4882a593Smuzhiyun 						break;
817*4882a593Smuzhiyun 				}
818*4882a593Smuzhiyun 			}
819*4882a593Smuzhiyun 		}
820*4882a593Smuzhiyun 		if (++i >= UBIFS_BLOCKS_PER_PAGE)
821*4882a593Smuzhiyun 			break;
822*4882a593Smuzhiyun 		block += 1;
823*4882a593Smuzhiyun 		addr += UBIFS_BLOCK_SIZE;
824*4882a593Smuzhiyun 	}
825*4882a593Smuzhiyun 	if (err) {
826*4882a593Smuzhiyun 		if (err == -ENOENT) {
827*4882a593Smuzhiyun 			/* Not found, so it must be a hole */
828*4882a593Smuzhiyun 			dbg_gen("hole");
829*4882a593Smuzhiyun 			goto out_free;
830*4882a593Smuzhiyun 		}
831*4882a593Smuzhiyun 		ubifs_err(c, "cannot read page %lu of inode %lu, error %d",
832*4882a593Smuzhiyun 			  page->index, inode->i_ino, err);
833*4882a593Smuzhiyun 		goto error;
834*4882a593Smuzhiyun 	}
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun out_free:
837*4882a593Smuzhiyun 	kfree(dn);
838*4882a593Smuzhiyun out:
839*4882a593Smuzhiyun 	return 0;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun error:
842*4882a593Smuzhiyun 	kfree(dn);
843*4882a593Smuzhiyun 	return err;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun 
ubifs_read(const char * filename,void * buf,loff_t offset,loff_t size,loff_t * actread)846*4882a593Smuzhiyun int ubifs_read(const char *filename, void *buf, loff_t offset,
847*4882a593Smuzhiyun 	       loff_t size, loff_t *actread)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun 	struct ubifs_info *c = ubifs_sb->s_fs_info;
850*4882a593Smuzhiyun 	unsigned long inum;
851*4882a593Smuzhiyun 	struct inode *inode;
852*4882a593Smuzhiyun 	struct page page;
853*4882a593Smuzhiyun 	int err = 0;
854*4882a593Smuzhiyun 	int i;
855*4882a593Smuzhiyun 	int count;
856*4882a593Smuzhiyun 	int last_block_size = 0;
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 	*actread = 0;
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	if (offset & (PAGE_SIZE - 1)) {
861*4882a593Smuzhiyun 		printf("ubifs: Error offset must be a multiple of %d\n",
862*4882a593Smuzhiyun 		       PAGE_SIZE);
863*4882a593Smuzhiyun 		return -1;
864*4882a593Smuzhiyun 	}
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
867*4882a593Smuzhiyun 	/* ubifs_findfile will resolve symlinks, so we know that we get
868*4882a593Smuzhiyun 	 * the real file here */
869*4882a593Smuzhiyun 	inum = ubifs_findfile(ubifs_sb, (char *)filename);
870*4882a593Smuzhiyun 	if (!inum) {
871*4882a593Smuzhiyun 		err = -1;
872*4882a593Smuzhiyun 		goto out;
873*4882a593Smuzhiyun 	}
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	/*
876*4882a593Smuzhiyun 	 * Read file inode
877*4882a593Smuzhiyun 	 */
878*4882a593Smuzhiyun 	inode = ubifs_iget(ubifs_sb, inum);
879*4882a593Smuzhiyun 	if (IS_ERR(inode)) {
880*4882a593Smuzhiyun 		printf("%s: Error reading inode %ld!\n", __func__, inum);
881*4882a593Smuzhiyun 		err = PTR_ERR(inode);
882*4882a593Smuzhiyun 		goto out;
883*4882a593Smuzhiyun 	}
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	if (offset > inode->i_size) {
886*4882a593Smuzhiyun 		printf("ubifs: Error offset (%lld) > file-size (%lld)\n",
887*4882a593Smuzhiyun 		       offset, size);
888*4882a593Smuzhiyun 		err = -1;
889*4882a593Smuzhiyun 		goto put_inode;
890*4882a593Smuzhiyun 	}
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	/*
893*4882a593Smuzhiyun 	 * If no size was specified or if size bigger than filesize
894*4882a593Smuzhiyun 	 * set size to filesize
895*4882a593Smuzhiyun 	 */
896*4882a593Smuzhiyun 	if ((size == 0) || (size > (inode->i_size - offset)))
897*4882a593Smuzhiyun 		size = inode->i_size - offset;
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	page.addr = buf;
902*4882a593Smuzhiyun 	page.index = offset / PAGE_SIZE;
903*4882a593Smuzhiyun 	page.inode = inode;
904*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
905*4882a593Smuzhiyun 		/*
906*4882a593Smuzhiyun 		 * Make sure to not read beyond the requested size
907*4882a593Smuzhiyun 		 */
908*4882a593Smuzhiyun 		if (((i + 1) == count) && (size < inode->i_size))
909*4882a593Smuzhiyun 			last_block_size = size - (i * PAGE_SIZE);
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 		err = do_readpage(c, inode, &page, last_block_size);
912*4882a593Smuzhiyun 		if (err)
913*4882a593Smuzhiyun 			break;
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 		page.addr += PAGE_SIZE;
916*4882a593Smuzhiyun 		page.index++;
917*4882a593Smuzhiyun 	}
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	if (err) {
920*4882a593Smuzhiyun 		printf("Error reading file '%s'\n", filename);
921*4882a593Smuzhiyun 		*actread = i * PAGE_SIZE;
922*4882a593Smuzhiyun 	} else {
923*4882a593Smuzhiyun 		*actread = size;
924*4882a593Smuzhiyun 	}
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun put_inode:
927*4882a593Smuzhiyun 	ubifs_iput(inode);
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun out:
930*4882a593Smuzhiyun 	ubi_close_volume(c->ubi);
931*4882a593Smuzhiyun 	return err;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun 
ubifs_close(void)934*4882a593Smuzhiyun void ubifs_close(void)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun /* Compat wrappers for common/cmd_ubifs.c */
ubifs_load(char * filename,u32 addr,u32 size)939*4882a593Smuzhiyun int ubifs_load(char *filename, u32 addr, u32 size)
940*4882a593Smuzhiyun {
941*4882a593Smuzhiyun 	loff_t actread;
942*4882a593Smuzhiyun 	int err;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	printf("Loading file '%s' to addr 0x%08x...\n", filename, addr);
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	err = ubifs_read(filename, (void *)(uintptr_t)addr, 0, size, &actread);
947*4882a593Smuzhiyun 	if (err == 0) {
948*4882a593Smuzhiyun 		env_set_hex("filesize", actread);
949*4882a593Smuzhiyun 		printf("Done\n");
950*4882a593Smuzhiyun 	}
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	return err;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun 
uboot_ubifs_umount(void)955*4882a593Smuzhiyun void uboot_ubifs_umount(void)
956*4882a593Smuzhiyun {
957*4882a593Smuzhiyun 	if (ubifs_sb) {
958*4882a593Smuzhiyun 		printf("Unmounting UBIFS volume %s!\n",
959*4882a593Smuzhiyun 		       ((struct ubifs_info *)(ubifs_sb->s_fs_info))->vi.name);
960*4882a593Smuzhiyun 		ubifs_umount(ubifs_sb->s_fs_info);
961*4882a593Smuzhiyun 		ubifs_sb = NULL;
962*4882a593Smuzhiyun 	}
963*4882a593Smuzhiyun }
964