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