xref: /rk3399_rockchip-uboot/fs/ubifs/ubifs.c (revision 255bb28338c545348cae4d9681888d7654f307a2)
19eefe2a2SStefan Roese /*
29eefe2a2SStefan Roese  * This file is part of UBIFS.
39eefe2a2SStefan Roese  *
49eefe2a2SStefan Roese  * Copyright (C) 2006-2008 Nokia Corporation.
59eefe2a2SStefan Roese  *
6b1a14f8aSStefan Roese  * (C) Copyright 2008-2010
79eefe2a2SStefan Roese  * Stefan Roese, DENX Software Engineering, sr@denx.de.
89eefe2a2SStefan Roese  *
99eefe2a2SStefan Roese  * Authors: Artem Bityutskiy (Битюцкий Артём)
109eefe2a2SStefan Roese  *          Adrian Hunter
115b8031ccSTom Rini  *
125b8031ccSTom Rini  * SPDX-License-Identifier:	GPL-2.0
139eefe2a2SStefan Roese  */
149eefe2a2SStefan Roese 
156e295186SSimon Glass #include <common.h>
166e295186SSimon Glass #include <memalign.h>
179eefe2a2SStefan Roese #include "ubifs.h"
18c1a0fd5fSRicardo Ribalda Delgado #include <u-boot/zlib.h>
199eefe2a2SStefan Roese 
20ff94bc40SHeiko Schocher #include <linux/err.h>
21ff94bc40SHeiko Schocher #include <linux/lzo.h>
22ff94bc40SHeiko Schocher 
239eefe2a2SStefan Roese DECLARE_GLOBAL_DATA_PTR;
249eefe2a2SStefan Roese 
259eefe2a2SStefan Roese /* compress.c */
269eefe2a2SStefan Roese 
279eefe2a2SStefan Roese /*
28c1a0fd5fSRicardo Ribalda Delgado  * We need a wrapper for zunzip() because the parameters are
299eefe2a2SStefan Roese  * incompatible with the lzo decompressor.
309eefe2a2SStefan Roese  */
gzip_decompress(const unsigned char * in,size_t in_len,unsigned char * out,size_t * out_len)319eefe2a2SStefan Roese static int gzip_decompress(const unsigned char *in, size_t in_len,
329eefe2a2SStefan Roese 			   unsigned char *out, size_t *out_len)
339eefe2a2SStefan Roese {
348044c138SVeli-Pekka Peltola 	return zunzip(out, *out_len, (unsigned char *)in,
358044c138SVeli-Pekka Peltola 		      (unsigned long *)out_len, 0, 0);
369eefe2a2SStefan Roese }
379eefe2a2SStefan Roese 
389eefe2a2SStefan Roese /* Fake description object for the "none" compressor */
399eefe2a2SStefan Roese static struct ubifs_compressor none_compr = {
409eefe2a2SStefan Roese 	.compr_type = UBIFS_COMPR_NONE,
41ff94bc40SHeiko Schocher 	.name = "none",
429eefe2a2SStefan Roese 	.capi_name = "",
439eefe2a2SStefan Roese 	.decompress = NULL,
449eefe2a2SStefan Roese };
459eefe2a2SStefan Roese 
469eefe2a2SStefan Roese static struct ubifs_compressor lzo_compr = {
479eefe2a2SStefan Roese 	.compr_type = UBIFS_COMPR_LZO,
48ff94bc40SHeiko Schocher #ifndef __UBOOT__
49ff94bc40SHeiko Schocher 	.comp_mutex = &lzo_mutex,
50ff94bc40SHeiko Schocher #endif
51ff94bc40SHeiko Schocher 	.name = "lzo",
529eefe2a2SStefan Roese 	.capi_name = "lzo",
539eefe2a2SStefan Roese 	.decompress = lzo1x_decompress_safe,
549eefe2a2SStefan Roese };
559eefe2a2SStefan Roese 
569eefe2a2SStefan Roese static struct ubifs_compressor zlib_compr = {
579eefe2a2SStefan Roese 	.compr_type = UBIFS_COMPR_ZLIB,
58ff94bc40SHeiko Schocher #ifndef __UBOOT__
59ff94bc40SHeiko Schocher 	.comp_mutex = &deflate_mutex,
60ff94bc40SHeiko Schocher 	.decomp_mutex = &inflate_mutex,
61ff94bc40SHeiko Schocher #endif
629eefe2a2SStefan Roese 	.name = "zlib",
639eefe2a2SStefan Roese 	.capi_name = "deflate",
649eefe2a2SStefan Roese 	.decompress = gzip_decompress,
659eefe2a2SStefan Roese };
669eefe2a2SStefan Roese 
679eefe2a2SStefan Roese /* All UBIFS compressors */
689eefe2a2SStefan Roese struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
699eefe2a2SStefan Roese 
70ff94bc40SHeiko Schocher 
71ff94bc40SHeiko Schocher #ifdef __UBOOT__
72ff94bc40SHeiko Schocher /* from mm/util.c */
73ff94bc40SHeiko Schocher 
74ff94bc40SHeiko Schocher /**
75ff94bc40SHeiko Schocher  * kmemdup - duplicate region of memory
76ff94bc40SHeiko Schocher  *
77ff94bc40SHeiko Schocher  * @src: memory region to duplicate
78ff94bc40SHeiko Schocher  * @len: memory region length
79ff94bc40SHeiko Schocher  * @gfp: GFP mask to use
80ff94bc40SHeiko Schocher  */
kmemdup(const void * src,size_t len,gfp_t gfp)81ff94bc40SHeiko Schocher void *kmemdup(const void *src, size_t len, gfp_t gfp)
82ff94bc40SHeiko Schocher {
83ff94bc40SHeiko Schocher 	void *p;
84ff94bc40SHeiko Schocher 
85ff94bc40SHeiko Schocher 	p = kmalloc(len, gfp);
86ff94bc40SHeiko Schocher 	if (p)
87ff94bc40SHeiko Schocher 		memcpy(p, src, len);
88ff94bc40SHeiko Schocher 	return p;
89ff94bc40SHeiko Schocher }
90ff94bc40SHeiko Schocher 
91ff94bc40SHeiko Schocher struct crypto_comp {
92ff94bc40SHeiko Schocher 	int compressor;
93ff94bc40SHeiko Schocher };
94ff94bc40SHeiko Schocher 
950195a7bbSHeiko Schocher static inline struct crypto_comp
crypto_alloc_comp(const char * alg_name,u32 type,u32 mask)960195a7bbSHeiko Schocher *crypto_alloc_comp(const char *alg_name, u32 type, u32 mask)
97ff94bc40SHeiko Schocher {
98ff94bc40SHeiko Schocher 	struct ubifs_compressor *comp;
99ff94bc40SHeiko Schocher 	struct crypto_comp *ptr;
100ff94bc40SHeiko Schocher 	int i = 0;
101ff94bc40SHeiko Schocher 
1024519668bSMarcel Ziswiler 	ptr = malloc_cache_aligned(sizeof(struct crypto_comp));
103ff94bc40SHeiko Schocher 	while (i < UBIFS_COMPR_TYPES_CNT) {
104ff94bc40SHeiko Schocher 		comp = ubifs_compressors[i];
105ff94bc40SHeiko Schocher 		if (!comp) {
106ff94bc40SHeiko Schocher 			i++;
107ff94bc40SHeiko Schocher 			continue;
108ff94bc40SHeiko Schocher 		}
109ff94bc40SHeiko Schocher 		if (strncmp(alg_name, comp->capi_name, strlen(alg_name)) == 0) {
110ff94bc40SHeiko Schocher 			ptr->compressor = i;
111ff94bc40SHeiko Schocher 			return ptr;
112ff94bc40SHeiko Schocher 		}
113ff94bc40SHeiko Schocher 		i++;
114ff94bc40SHeiko Schocher 	}
115ff94bc40SHeiko Schocher 	if (i >= UBIFS_COMPR_TYPES_CNT) {
1160195a7bbSHeiko Schocher 		dbg_gen("invalid compression type %s", alg_name);
117ff94bc40SHeiko Schocher 		free (ptr);
118ff94bc40SHeiko Schocher 		return NULL;
119ff94bc40SHeiko Schocher 	}
120ff94bc40SHeiko Schocher 	return ptr;
121ff94bc40SHeiko Schocher }
1220195a7bbSHeiko Schocher 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)1230195a7bbSHeiko Schocher crypto_comp_decompress(const struct ubifs_info *c, struct crypto_comp *tfm,
1240195a7bbSHeiko Schocher 		       const u8 *src, unsigned int slen, u8 *dst,
1250195a7bbSHeiko Schocher 		       unsigned int *dlen)
126ff94bc40SHeiko Schocher {
127ff94bc40SHeiko Schocher 	struct ubifs_compressor *compr = ubifs_compressors[tfm->compressor];
128ff94bc40SHeiko Schocher 	int err;
1296dd3ad81SPaul Davey 	size_t tmp_len = *dlen;
130ff94bc40SHeiko Schocher 
131ff94bc40SHeiko Schocher 	if (compr->compr_type == UBIFS_COMPR_NONE) {
132ff94bc40SHeiko Schocher 		memcpy(dst, src, slen);
133ff94bc40SHeiko Schocher 		*dlen = slen;
134ff94bc40SHeiko Schocher 		return 0;
135ff94bc40SHeiko Schocher 	}
136ff94bc40SHeiko Schocher 
1376dd3ad81SPaul Davey 	err = compr->decompress(src, slen, dst, &tmp_len);
138ff94bc40SHeiko Schocher 	if (err)
1390195a7bbSHeiko Schocher 		ubifs_err(c, "cannot decompress %d bytes, compressor %s, "
140ff94bc40SHeiko Schocher 			  "error %d", slen, compr->name, err);
141ff94bc40SHeiko Schocher 
1426dd3ad81SPaul Davey 	*dlen = tmp_len;
143ff94bc40SHeiko Schocher 	return err;
144ff94bc40SHeiko Schocher 
145ff94bc40SHeiko Schocher 	return 0;
146ff94bc40SHeiko Schocher }
147dc288431SAnton Habegger 
148dc288431SAnton Habegger /* from shrinker.c */
149dc288431SAnton Habegger 
150dc288431SAnton Habegger /* Global clean znode counter (for all mounted UBIFS instances) */
151dc288431SAnton Habegger atomic_long_t ubifs_clean_zn_cnt;
152dc288431SAnton Habegger 
153ff94bc40SHeiko Schocher #endif
154ff94bc40SHeiko Schocher 
1559eefe2a2SStefan Roese /**
1569eefe2a2SStefan Roese  * ubifs_decompress - decompress data.
1579eefe2a2SStefan Roese  * @in_buf: data to decompress
1589eefe2a2SStefan Roese  * @in_len: length of the data to decompress
1599eefe2a2SStefan Roese  * @out_buf: output buffer where decompressed data should
1609eefe2a2SStefan Roese  * @out_len: output length is returned here
1619eefe2a2SStefan Roese  * @compr_type: type of compression
1629eefe2a2SStefan Roese  *
1639eefe2a2SStefan Roese  * This function decompresses data from buffer @in_buf into buffer @out_buf.
1649eefe2a2SStefan Roese  * The length of the uncompressed data is returned in @out_len. This functions
1659eefe2a2SStefan Roese  * returns %0 on success or a negative error code on failure.
1669eefe2a2SStefan Roese  */
ubifs_decompress(const struct ubifs_info * c,const void * in_buf,int in_len,void * out_buf,int * out_len,int compr_type)1670195a7bbSHeiko Schocher int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
1680195a7bbSHeiko Schocher 		     int in_len, void *out_buf, int *out_len, int compr_type)
1699eefe2a2SStefan Roese {
1709eefe2a2SStefan Roese 	int err;
1719eefe2a2SStefan Roese 	struct ubifs_compressor *compr;
1729eefe2a2SStefan Roese 
1739eefe2a2SStefan Roese 	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
1740195a7bbSHeiko Schocher 		ubifs_err(c, "invalid compression type %d", compr_type);
1759eefe2a2SStefan Roese 		return -EINVAL;
1769eefe2a2SStefan Roese 	}
1779eefe2a2SStefan Roese 
1789eefe2a2SStefan Roese 	compr = ubifs_compressors[compr_type];
1799eefe2a2SStefan Roese 
1809eefe2a2SStefan Roese 	if (unlikely(!compr->capi_name)) {
1810195a7bbSHeiko Schocher 		ubifs_err(c, "%s compression is not compiled in", compr->name);
1829eefe2a2SStefan Roese 		return -EINVAL;
1839eefe2a2SStefan Roese 	}
1849eefe2a2SStefan Roese 
1859eefe2a2SStefan Roese 	if (compr_type == UBIFS_COMPR_NONE) {
1869eefe2a2SStefan Roese 		memcpy(out_buf, in_buf, in_len);
1879eefe2a2SStefan Roese 		*out_len = in_len;
1889eefe2a2SStefan Roese 		return 0;
1899eefe2a2SStefan Roese 	}
1909eefe2a2SStefan Roese 
191ff94bc40SHeiko Schocher 	if (compr->decomp_mutex)
192ff94bc40SHeiko Schocher 		mutex_lock(compr->decomp_mutex);
1930195a7bbSHeiko Schocher 	err = crypto_comp_decompress(c, compr->cc, in_buf, in_len, out_buf,
194ff94bc40SHeiko Schocher 				     (unsigned int *)out_len);
195ff94bc40SHeiko Schocher 	if (compr->decomp_mutex)
196ff94bc40SHeiko Schocher 		mutex_unlock(compr->decomp_mutex);
1979eefe2a2SStefan Roese 	if (err)
1980195a7bbSHeiko Schocher 		ubifs_err(c, "cannot decompress %d bytes, compressor %s,"
1990195a7bbSHeiko Schocher 			  " error %d", in_len, compr->name, err);
2009eefe2a2SStefan Roese 
2019eefe2a2SStefan Roese 	return err;
2029eefe2a2SStefan Roese }
2039eefe2a2SStefan Roese 
2049eefe2a2SStefan Roese /**
2059eefe2a2SStefan Roese  * compr_init - initialize a compressor.
2069eefe2a2SStefan Roese  * @compr: compressor description object
2079eefe2a2SStefan Roese  *
2089eefe2a2SStefan Roese  * This function initializes the requested compressor and returns zero in case
2099eefe2a2SStefan Roese  * of success or a negative error code in case of failure.
2109eefe2a2SStefan Roese  */
compr_init(struct ubifs_compressor * compr)2119eefe2a2SStefan Roese static int __init compr_init(struct ubifs_compressor *compr)
2129eefe2a2SStefan Roese {
2139eefe2a2SStefan Roese 	ubifs_compressors[compr->compr_type] = compr;
214521af04dSPeter Tyser 
2152e5167ccSWolfgang Denk #ifdef CONFIG_NEEDS_MANUAL_RELOC
2169eefe2a2SStefan Roese 	ubifs_compressors[compr->compr_type]->name += gd->reloc_off;
2179eefe2a2SStefan Roese 	ubifs_compressors[compr->compr_type]->capi_name += gd->reloc_off;
2189eefe2a2SStefan Roese 	ubifs_compressors[compr->compr_type]->decompress += gd->reloc_off;
219521af04dSPeter Tyser #endif
220521af04dSPeter Tyser 
221ff94bc40SHeiko Schocher 	if (compr->capi_name) {
222ff94bc40SHeiko Schocher 		compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
223ff94bc40SHeiko Schocher 		if (IS_ERR(compr->cc)) {
2240195a7bbSHeiko Schocher 			dbg_gen("cannot initialize compressor %s,"
2250195a7bbSHeiko Schocher 				  " error %ld", compr->name,
2260195a7bbSHeiko Schocher 				  PTR_ERR(compr->cc));
227ff94bc40SHeiko Schocher 			return PTR_ERR(compr->cc);
228ff94bc40SHeiko Schocher 		}
229ff94bc40SHeiko Schocher 	}
230ff94bc40SHeiko Schocher 
2319eefe2a2SStefan Roese 	return 0;
2329eefe2a2SStefan Roese }
2339eefe2a2SStefan Roese 
2349eefe2a2SStefan Roese /**
2359eefe2a2SStefan Roese  * ubifs_compressors_init - initialize UBIFS compressors.
2369eefe2a2SStefan Roese  *
2379eefe2a2SStefan Roese  * This function initializes the compressor which were compiled in. Returns
2389eefe2a2SStefan Roese  * zero in case of success and a negative error code in case of failure.
2399eefe2a2SStefan Roese  */
ubifs_compressors_init(void)2409eefe2a2SStefan Roese int __init ubifs_compressors_init(void)
2419eefe2a2SStefan Roese {
2429eefe2a2SStefan Roese 	int err;
2439eefe2a2SStefan Roese 
2449eefe2a2SStefan Roese 	err = compr_init(&lzo_compr);
2459eefe2a2SStefan Roese 	if (err)
2469eefe2a2SStefan Roese 		return err;
2479eefe2a2SStefan Roese 
2489eefe2a2SStefan Roese 	err = compr_init(&zlib_compr);
2499eefe2a2SStefan Roese 	if (err)
2509eefe2a2SStefan Roese 		return err;
2519eefe2a2SStefan Roese 
252faac4fd8SMichael Lawnick 	err = compr_init(&none_compr);
253faac4fd8SMichael Lawnick 	if (err)
254faac4fd8SMichael Lawnick 		return err;
255faac4fd8SMichael Lawnick 
2569eefe2a2SStefan Roese 	return 0;
2579eefe2a2SStefan Roese }
2589eefe2a2SStefan Roese 
2599eefe2a2SStefan Roese /*
2609eefe2a2SStefan Roese  * ubifsls...
2619eefe2a2SStefan Roese  */
2629eefe2a2SStefan Roese 
filldir(struct ubifs_info * c,const char * name,int namlen,u64 ino,unsigned int d_type)2639eefe2a2SStefan Roese static int filldir(struct ubifs_info *c, const char *name, int namlen,
2649eefe2a2SStefan Roese 		   u64 ino, unsigned int d_type)
2659eefe2a2SStefan Roese {
2669eefe2a2SStefan Roese 	struct inode *inode;
2679eefe2a2SStefan Roese 	char filetime[32];
2689eefe2a2SStefan Roese 
2699eefe2a2SStefan Roese 	switch (d_type) {
2709eefe2a2SStefan Roese 	case UBIFS_ITYPE_REG:
2719eefe2a2SStefan Roese 		printf("\t");
2729eefe2a2SStefan Roese 		break;
2739eefe2a2SStefan Roese 	case UBIFS_ITYPE_DIR:
2749eefe2a2SStefan Roese 		printf("<DIR>\t");
2759eefe2a2SStefan Roese 		break;
2769eefe2a2SStefan Roese 	case UBIFS_ITYPE_LNK:
2779eefe2a2SStefan Roese 		printf("<LNK>\t");
2789eefe2a2SStefan Roese 		break;
2799eefe2a2SStefan Roese 	default:
2809eefe2a2SStefan Roese 		printf("other\t");
2819eefe2a2SStefan Roese 		break;
2829eefe2a2SStefan Roese 	}
2839eefe2a2SStefan Roese 
2849eefe2a2SStefan Roese 	inode = ubifs_iget(c->vfs_sb, ino);
2859eefe2a2SStefan Roese 	if (IS_ERR(inode)) {
2869eefe2a2SStefan Roese 		printf("%s: Error in ubifs_iget(), ino=%lld ret=%p!\n",
2879eefe2a2SStefan Roese 		       __func__, ino, inode);
2889eefe2a2SStefan Roese 		return -1;
2899eefe2a2SStefan Roese 	}
2909eefe2a2SStefan Roese 	ctime_r((time_t *)&inode->i_mtime, filetime);
2919eefe2a2SStefan Roese 	printf("%9lld  %24.24s  ", inode->i_size, filetime);
292ff94bc40SHeiko Schocher #ifndef __UBOOT__
2939eefe2a2SStefan Roese 	ubifs_iput(inode);
294ff94bc40SHeiko Schocher #endif
2959eefe2a2SStefan Roese 
2969eefe2a2SStefan Roese 	printf("%s\n", name);
2979eefe2a2SStefan Roese 
2989eefe2a2SStefan Roese 	return 0;
2999eefe2a2SStefan Roese }
3009eefe2a2SStefan Roese 
ubifs_printdir(struct file * file,void * dirent)3019eefe2a2SStefan Roese static int ubifs_printdir(struct file *file, void *dirent)
3029eefe2a2SStefan Roese {
3039eefe2a2SStefan Roese 	int err, over = 0;
3049eefe2a2SStefan Roese 	struct qstr nm;
3059eefe2a2SStefan Roese 	union ubifs_key key;
3069eefe2a2SStefan Roese 	struct ubifs_dent_node *dent;
3079eefe2a2SStefan Roese 	struct inode *dir = file->f_path.dentry->d_inode;
3089eefe2a2SStefan Roese 	struct ubifs_info *c = dir->i_sb->s_fs_info;
3099eefe2a2SStefan Roese 
3109eefe2a2SStefan Roese 	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
3119eefe2a2SStefan Roese 
3129eefe2a2SStefan Roese 	if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
3139eefe2a2SStefan Roese 		/*
3149eefe2a2SStefan Roese 		 * The directory was seek'ed to a senseless position or there
3159eefe2a2SStefan Roese 		 * are no more entries.
3169eefe2a2SStefan Roese 		 */
3179eefe2a2SStefan Roese 		return 0;
3189eefe2a2SStefan Roese 
3199eefe2a2SStefan Roese 	if (file->f_pos == 1) {
3209eefe2a2SStefan Roese 		/* Find the first entry in TNC and save it */
3219eefe2a2SStefan Roese 		lowest_dent_key(c, &key, dir->i_ino);
3229eefe2a2SStefan Roese 		nm.name = NULL;
3239eefe2a2SStefan Roese 		dent = ubifs_tnc_next_ent(c, &key, &nm);
3249eefe2a2SStefan Roese 		if (IS_ERR(dent)) {
3259eefe2a2SStefan Roese 			err = PTR_ERR(dent);
3269eefe2a2SStefan Roese 			goto out;
3279eefe2a2SStefan Roese 		}
3289eefe2a2SStefan Roese 
3299eefe2a2SStefan Roese 		file->f_pos = key_hash_flash(c, &dent->key);
3309eefe2a2SStefan Roese 		file->private_data = dent;
3319eefe2a2SStefan Roese 	}
3329eefe2a2SStefan Roese 
3339eefe2a2SStefan Roese 	dent = file->private_data;
3349eefe2a2SStefan Roese 	if (!dent) {
3359eefe2a2SStefan Roese 		/*
3369eefe2a2SStefan Roese 		 * The directory was seek'ed to and is now readdir'ed.
3379eefe2a2SStefan Roese 		 * Find the entry corresponding to @file->f_pos or the
3389eefe2a2SStefan Roese 		 * closest one.
3399eefe2a2SStefan Roese 		 */
3409eefe2a2SStefan Roese 		dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
3419eefe2a2SStefan Roese 		nm.name = NULL;
3429eefe2a2SStefan Roese 		dent = ubifs_tnc_next_ent(c, &key, &nm);
3439eefe2a2SStefan Roese 		if (IS_ERR(dent)) {
3449eefe2a2SStefan Roese 			err = PTR_ERR(dent);
3459eefe2a2SStefan Roese 			goto out;
3469eefe2a2SStefan Roese 		}
3479eefe2a2SStefan Roese 		file->f_pos = key_hash_flash(c, &dent->key);
3489eefe2a2SStefan Roese 		file->private_data = dent;
3499eefe2a2SStefan Roese 	}
3509eefe2a2SStefan Roese 
3519eefe2a2SStefan Roese 	while (1) {
3529eefe2a2SStefan Roese 		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
3539eefe2a2SStefan Roese 			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
3549eefe2a2SStefan Roese 			key_hash_flash(c, &dent->key));
35589468843SPatrice Chotard #ifndef __UBOOT__
3569eefe2a2SStefan Roese 		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
35789468843SPatrice Chotard #endif
3589eefe2a2SStefan Roese 
3599eefe2a2SStefan Roese 		nm.len = le16_to_cpu(dent->nlen);
3609eefe2a2SStefan Roese 		over = filldir(c, (char *)dent->name, nm.len,
3619eefe2a2SStefan Roese 			       le64_to_cpu(dent->inum), dent->type);
3629eefe2a2SStefan Roese 		if (over)
3639eefe2a2SStefan Roese 			return 0;
3649eefe2a2SStefan Roese 
3659eefe2a2SStefan Roese 		/* Switch to the next entry */
3669eefe2a2SStefan Roese 		key_read(c, &dent->key, &key);
3679eefe2a2SStefan Roese 		nm.name = (char *)dent->name;
3689eefe2a2SStefan Roese 		dent = ubifs_tnc_next_ent(c, &key, &nm);
3699eefe2a2SStefan Roese 		if (IS_ERR(dent)) {
3709eefe2a2SStefan Roese 			err = PTR_ERR(dent);
3719eefe2a2SStefan Roese 			goto out;
3729eefe2a2SStefan Roese 		}
3739eefe2a2SStefan Roese 
3749eefe2a2SStefan Roese 		kfree(file->private_data);
3759eefe2a2SStefan Roese 		file->f_pos = key_hash_flash(c, &dent->key);
3769eefe2a2SStefan Roese 		file->private_data = dent;
3779eefe2a2SStefan Roese 		cond_resched();
3789eefe2a2SStefan Roese 	}
3799eefe2a2SStefan Roese 
3809eefe2a2SStefan Roese out:
3819eefe2a2SStefan Roese 	if (err != -ENOENT) {
3820195a7bbSHeiko Schocher 		ubifs_err(c, "cannot find next direntry, error %d", err);
3839eefe2a2SStefan Roese 		return err;
3849eefe2a2SStefan Roese 	}
3859eefe2a2SStefan Roese 
3869eefe2a2SStefan Roese 	kfree(file->private_data);
3879eefe2a2SStefan Roese 	file->private_data = NULL;
3889eefe2a2SStefan Roese 	file->f_pos = 2;
3899eefe2a2SStefan Roese 	return 0;
3909eefe2a2SStefan Roese }
3919eefe2a2SStefan Roese 
ubifs_finddir(struct super_block * sb,char * dirname,unsigned long root_inum,unsigned long * inum)3929eefe2a2SStefan Roese static int ubifs_finddir(struct super_block *sb, char *dirname,
3939eefe2a2SStefan Roese 			 unsigned long root_inum, unsigned long *inum)
3949eefe2a2SStefan Roese {
3959eefe2a2SStefan Roese 	int err;
3969eefe2a2SStefan Roese 	struct qstr nm;
3979eefe2a2SStefan Roese 	union ubifs_key key;
3989eefe2a2SStefan Roese 	struct ubifs_dent_node *dent;
3999eefe2a2SStefan Roese 	struct ubifs_info *c;
4009eefe2a2SStefan Roese 	struct file *file;
4019eefe2a2SStefan Roese 	struct dentry *dentry;
4029eefe2a2SStefan Roese 	struct inode *dir;
403be73913bSStefan Roese 	int ret = 0;
4049eefe2a2SStefan Roese 
4059eefe2a2SStefan Roese 	file = kzalloc(sizeof(struct file), 0);
4069eefe2a2SStefan Roese 	dentry = kzalloc(sizeof(struct dentry), 0);
4079eefe2a2SStefan Roese 	dir = kzalloc(sizeof(struct inode), 0);
4089eefe2a2SStefan Roese 	if (!file || !dentry || !dir) {
4099eefe2a2SStefan Roese 		printf("%s: Error, no memory for malloc!\n", __func__);
4109eefe2a2SStefan Roese 		err = -ENOMEM;
4119eefe2a2SStefan Roese 		goto out;
4129eefe2a2SStefan Roese 	}
4139eefe2a2SStefan Roese 
4149eefe2a2SStefan Roese 	dir->i_sb = sb;
4159eefe2a2SStefan Roese 	file->f_path.dentry = dentry;
4169eefe2a2SStefan Roese 	file->f_path.dentry->d_parent = dentry;
4179eefe2a2SStefan Roese 	file->f_path.dentry->d_inode = dir;
4189eefe2a2SStefan Roese 	file->f_path.dentry->d_inode->i_ino = root_inum;
4199eefe2a2SStefan Roese 	c = sb->s_fs_info;
4209eefe2a2SStefan Roese 
4219eefe2a2SStefan Roese 	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
4229eefe2a2SStefan Roese 
4239eefe2a2SStefan Roese 	/* Find the first entry in TNC and save it */
4249eefe2a2SStefan Roese 	lowest_dent_key(c, &key, dir->i_ino);
4259eefe2a2SStefan Roese 	nm.name = NULL;
4269eefe2a2SStefan Roese 	dent = ubifs_tnc_next_ent(c, &key, &nm);
4279eefe2a2SStefan Roese 	if (IS_ERR(dent)) {
4289eefe2a2SStefan Roese 		err = PTR_ERR(dent);
4299eefe2a2SStefan Roese 		goto out;
4309eefe2a2SStefan Roese 	}
4319eefe2a2SStefan Roese 
4329eefe2a2SStefan Roese 	file->f_pos = key_hash_flash(c, &dent->key);
4339eefe2a2SStefan Roese 	file->private_data = dent;
4349eefe2a2SStefan Roese 
4359eefe2a2SStefan Roese 	while (1) {
4369eefe2a2SStefan Roese 		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
4379eefe2a2SStefan Roese 			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
4389eefe2a2SStefan Roese 			key_hash_flash(c, &dent->key));
43989468843SPatrice Chotard #ifndef __UBOOT__
4409eefe2a2SStefan Roese 		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
44189468843SPatrice Chotard #endif
4429eefe2a2SStefan Roese 
4439eefe2a2SStefan Roese 		nm.len = le16_to_cpu(dent->nlen);
4449eefe2a2SStefan Roese 		if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) &&
4459eefe2a2SStefan Roese 		    (strlen(dirname) == nm.len)) {
4469eefe2a2SStefan Roese 			*inum = le64_to_cpu(dent->inum);
447be73913bSStefan Roese 			ret = 1;
448be73913bSStefan Roese 			goto out_free;
4499eefe2a2SStefan Roese 		}
4509eefe2a2SStefan Roese 
4519eefe2a2SStefan Roese 		/* Switch to the next entry */
4529eefe2a2SStefan Roese 		key_read(c, &dent->key, &key);
4539eefe2a2SStefan Roese 		nm.name = (char *)dent->name;
4549eefe2a2SStefan Roese 		dent = ubifs_tnc_next_ent(c, &key, &nm);
4559eefe2a2SStefan Roese 		if (IS_ERR(dent)) {
4569eefe2a2SStefan Roese 			err = PTR_ERR(dent);
4579eefe2a2SStefan Roese 			goto out;
4589eefe2a2SStefan Roese 		}
4599eefe2a2SStefan Roese 
4609eefe2a2SStefan Roese 		kfree(file->private_data);
4619eefe2a2SStefan Roese 		file->f_pos = key_hash_flash(c, &dent->key);
4629eefe2a2SStefan Roese 		file->private_data = dent;
4639eefe2a2SStefan Roese 		cond_resched();
4649eefe2a2SStefan Roese 	}
4659eefe2a2SStefan Roese 
4669eefe2a2SStefan Roese out:
467be73913bSStefan Roese 	if (err != -ENOENT)
4680195a7bbSHeiko Schocher 		dbg_gen("cannot find next direntry, error %d", err);
4699eefe2a2SStefan Roese 
470be73913bSStefan Roese out_free:
4713267bc1bSWolfgang Denk 	kfree(file->private_data);
4729eefe2a2SStefan Roese 	free(file);
4739eefe2a2SStefan Roese 	free(dentry);
4749eefe2a2SStefan Roese 	free(dir);
4759eefe2a2SStefan Roese 
476be73913bSStefan Roese 	return ret;
4779eefe2a2SStefan Roese }
4789eefe2a2SStefan Roese 
ubifs_findfile(struct super_block * sb,char * filename)4799eefe2a2SStefan Roese static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
4809eefe2a2SStefan Roese {
4819eefe2a2SStefan Roese 	int ret;
4829eefe2a2SStefan Roese 	char *next;
4839eefe2a2SStefan Roese 	char fpath[128];
4849d7952e4SSimon Kagstrom 	char symlinkpath[128];
4859eefe2a2SStefan Roese 	char *name = fpath;
4869eefe2a2SStefan Roese 	unsigned long root_inum = 1;
4879eefe2a2SStefan Roese 	unsigned long inum;
4889d7952e4SSimon Kagstrom 	int symlink_count = 0; /* Don't allow symlink recursion */
48964b68178SRicardo Ribalda Delgado 	char link_name[64];
4909eefe2a2SStefan Roese 
4919eefe2a2SStefan Roese 	strcpy(fpath, filename);
4929eefe2a2SStefan Roese 
4939eefe2a2SStefan Roese 	/* Remove all leading slashes */
4949eefe2a2SStefan Roese 	while (*name == '/')
4959eefe2a2SStefan Roese 		name++;
4969eefe2a2SStefan Roese 
4979eefe2a2SStefan Roese 	/*
4989eefe2a2SStefan Roese 	 * Handle root-direcoty ('/')
4999eefe2a2SStefan Roese 	 */
5009eefe2a2SStefan Roese 	inum = root_inum;
5019eefe2a2SStefan Roese 	if (!name || *name == '\0')
5029eefe2a2SStefan Roese 		return inum;
5039eefe2a2SStefan Roese 
5049eefe2a2SStefan Roese 	for (;;) {
5059d7952e4SSimon Kagstrom 		struct inode *inode;
5069d7952e4SSimon Kagstrom 		struct ubifs_inode *ui;
5079d7952e4SSimon Kagstrom 
5089eefe2a2SStefan Roese 		/* Extract the actual part from the pathname.  */
5099eefe2a2SStefan Roese 		next = strchr(name, '/');
5109eefe2a2SStefan Roese 		if (next) {
5119eefe2a2SStefan Roese 			/* Remove all leading slashes.  */
5129eefe2a2SStefan Roese 			while (*next == '/')
5139eefe2a2SStefan Roese 				*(next++) = '\0';
5149eefe2a2SStefan Roese 		}
5159eefe2a2SStefan Roese 
5169eefe2a2SStefan Roese 		ret = ubifs_finddir(sb, name, root_inum, &inum);
5179d7952e4SSimon Kagstrom 		if (!ret)
5189d7952e4SSimon Kagstrom 			return 0;
5199d7952e4SSimon Kagstrom 		inode = ubifs_iget(sb, inum);
5209d7952e4SSimon Kagstrom 
5219d7952e4SSimon Kagstrom 		if (!inode)
5229d7952e4SSimon Kagstrom 			return 0;
5239d7952e4SSimon Kagstrom 		ui = ubifs_inode(inode);
5249d7952e4SSimon Kagstrom 
5259d7952e4SSimon Kagstrom 		if ((inode->i_mode & S_IFMT) == S_IFLNK) {
5269d7952e4SSimon Kagstrom 			char buf[128];
5279d7952e4SSimon Kagstrom 
5289d7952e4SSimon Kagstrom 			/* We have some sort of symlink recursion, bail out */
5299d7952e4SSimon Kagstrom 			if (symlink_count++ > 8) {
5309d7952e4SSimon Kagstrom 				printf("Symlink recursion, aborting\n");
5319d7952e4SSimon Kagstrom 				return 0;
5329d7952e4SSimon Kagstrom 			}
5339d7952e4SSimon Kagstrom 			memcpy(link_name, ui->data, ui->data_len);
5349d7952e4SSimon Kagstrom 			link_name[ui->data_len] = '\0';
5359d7952e4SSimon Kagstrom 
5369d7952e4SSimon Kagstrom 			if (link_name[0] == '/') {
5379d7952e4SSimon Kagstrom 				/* Absolute path, redo everything without
5389d7952e4SSimon Kagstrom 				 * the leading slash */
5399d7952e4SSimon Kagstrom 				next = name = link_name + 1;
5409d7952e4SSimon Kagstrom 				root_inum = 1;
5419d7952e4SSimon Kagstrom 				continue;
5429d7952e4SSimon Kagstrom 			}
5439d7952e4SSimon Kagstrom 			/* Relative to cur dir */
544ef37c683SSimon Kagstrom 			sprintf(buf, "%s/%s",
5459d7952e4SSimon Kagstrom 					link_name, next == NULL ? "" : next);
5469d7952e4SSimon Kagstrom 			memcpy(symlinkpath, buf, sizeof(buf));
5479d7952e4SSimon Kagstrom 			next = name = symlinkpath;
5489d7952e4SSimon Kagstrom 			continue;
5499d7952e4SSimon Kagstrom 		}
5509eefe2a2SStefan Roese 
5519eefe2a2SStefan Roese 		/*
5529eefe2a2SStefan Roese 		 * Check if directory with this name exists
5539eefe2a2SStefan Roese 		 */
5549eefe2a2SStefan Roese 
5559eefe2a2SStefan Roese 		/* Found the node!  */
5569d7952e4SSimon Kagstrom 		if (!next || *next == '\0')
5579eefe2a2SStefan Roese 			return inum;
5589eefe2a2SStefan Roese 
5599eefe2a2SStefan Roese 		root_inum = inum;
5609eefe2a2SStefan Roese 		name = next;
5619eefe2a2SStefan Roese 	}
5629eefe2a2SStefan Roese 
5639eefe2a2SStefan Roese 	return 0;
5649eefe2a2SStefan Roese }
5659eefe2a2SStefan Roese 
ubifs_set_blk_dev(struct blk_desc * rbdd,disk_partition_t * info)5664101f687SSimon Glass int ubifs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info)
56729cc5bcaSHans de Goede {
56829cc5bcaSHans de Goede 	if (rbdd) {
56929cc5bcaSHans de Goede 		debug("UBIFS cannot be used with normal block devices\n");
57029cc5bcaSHans de Goede 		return -1;
57129cc5bcaSHans de Goede 	}
57229cc5bcaSHans de Goede 
57329cc5bcaSHans de Goede 	/*
574e35929e4SSimon Glass 	 * Should never happen since blk_get_device_part_str() already checks
57529cc5bcaSHans de Goede 	 * this, but better safe then sorry.
57629cc5bcaSHans de Goede 	 */
57729cc5bcaSHans de Goede 	if (!ubifs_is_mounted()) {
57829cc5bcaSHans de Goede 		debug("UBIFS not mounted, use ubifsmount to mount volume first!\n");
57929cc5bcaSHans de Goede 		return -1;
58029cc5bcaSHans de Goede 	}
58129cc5bcaSHans de Goede 
58229cc5bcaSHans de Goede 	return 0;
58329cc5bcaSHans de Goede }
58429cc5bcaSHans de Goede 
ubifs_ls(const char * filename)585ad15749bSHans de Goede int ubifs_ls(const char *filename)
5869eefe2a2SStefan Roese {
5879eefe2a2SStefan Roese 	struct ubifs_info *c = ubifs_sb->s_fs_info;
5889eefe2a2SStefan Roese 	struct file *file;
5899eefe2a2SStefan Roese 	struct dentry *dentry;
5909eefe2a2SStefan Roese 	struct inode *dir;
5919eefe2a2SStefan Roese 	void *dirent = NULL;
5929eefe2a2SStefan Roese 	unsigned long inum;
5939eefe2a2SStefan Roese 	int ret = 0;
5949eefe2a2SStefan Roese 
5959eefe2a2SStefan Roese 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
596ad15749bSHans de Goede 	inum = ubifs_findfile(ubifs_sb, (char *)filename);
5979eefe2a2SStefan Roese 	if (!inum) {
5989eefe2a2SStefan Roese 		ret = -1;
5999eefe2a2SStefan Roese 		goto out;
6009eefe2a2SStefan Roese 	}
6019eefe2a2SStefan Roese 
6029eefe2a2SStefan Roese 	file = kzalloc(sizeof(struct file), 0);
6039eefe2a2SStefan Roese 	dentry = kzalloc(sizeof(struct dentry), 0);
6049eefe2a2SStefan Roese 	dir = kzalloc(sizeof(struct inode), 0);
6059eefe2a2SStefan Roese 	if (!file || !dentry || !dir) {
6069eefe2a2SStefan Roese 		printf("%s: Error, no memory for malloc!\n", __func__);
6079eefe2a2SStefan Roese 		ret = -ENOMEM;
6089eefe2a2SStefan Roese 		goto out_mem;
6099eefe2a2SStefan Roese 	}
6109eefe2a2SStefan Roese 
6119eefe2a2SStefan Roese 	dir->i_sb = ubifs_sb;
6129eefe2a2SStefan Roese 	file->f_path.dentry = dentry;
6139eefe2a2SStefan Roese 	file->f_path.dentry->d_parent = dentry;
6149eefe2a2SStefan Roese 	file->f_path.dentry->d_inode = dir;
6159eefe2a2SStefan Roese 	file->f_path.dentry->d_inode->i_ino = inum;
6169eefe2a2SStefan Roese 	file->f_pos = 1;
6179eefe2a2SStefan Roese 	file->private_data = NULL;
6189eefe2a2SStefan Roese 	ubifs_printdir(file, dirent);
6199eefe2a2SStefan Roese 
6209eefe2a2SStefan Roese out_mem:
6219eefe2a2SStefan Roese 	if (file)
6229eefe2a2SStefan Roese 		free(file);
6239eefe2a2SStefan Roese 	if (dentry)
6249eefe2a2SStefan Roese 		free(dentry);
6259eefe2a2SStefan Roese 	if (dir)
6269eefe2a2SStefan Roese 		free(dir);
6279eefe2a2SStefan Roese 
6289eefe2a2SStefan Roese out:
6299eefe2a2SStefan Roese 	ubi_close_volume(c->ubi);
6309eefe2a2SStefan Roese 	return ret;
6319eefe2a2SStefan Roese }
6329eefe2a2SStefan Roese 
ubifs_exists(const char * filename)63329cc5bcaSHans de Goede int ubifs_exists(const char *filename)
63429cc5bcaSHans de Goede {
63529cc5bcaSHans de Goede 	struct ubifs_info *c = ubifs_sb->s_fs_info;
63629cc5bcaSHans de Goede 	unsigned long inum;
63729cc5bcaSHans de Goede 
63829cc5bcaSHans de Goede 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
63929cc5bcaSHans de Goede 	inum = ubifs_findfile(ubifs_sb, (char *)filename);
64029cc5bcaSHans de Goede 	ubi_close_volume(c->ubi);
64129cc5bcaSHans de Goede 
64229cc5bcaSHans de Goede 	return inum != 0;
64329cc5bcaSHans de Goede }
64429cc5bcaSHans de Goede 
ubifs_size(const char * filename,loff_t * size)64529cc5bcaSHans de Goede int ubifs_size(const char *filename, loff_t *size)
64629cc5bcaSHans de Goede {
64729cc5bcaSHans de Goede 	struct ubifs_info *c = ubifs_sb->s_fs_info;
64829cc5bcaSHans de Goede 	unsigned long inum;
64929cc5bcaSHans de Goede 	struct inode *inode;
65029cc5bcaSHans de Goede 	int err = 0;
65129cc5bcaSHans de Goede 
65229cc5bcaSHans de Goede 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
65329cc5bcaSHans de Goede 
65429cc5bcaSHans de Goede 	inum = ubifs_findfile(ubifs_sb, (char *)filename);
65529cc5bcaSHans de Goede 	if (!inum) {
65629cc5bcaSHans de Goede 		err = -1;
65729cc5bcaSHans de Goede 		goto out;
65829cc5bcaSHans de Goede 	}
65929cc5bcaSHans de Goede 
66029cc5bcaSHans de Goede 	inode = ubifs_iget(ubifs_sb, inum);
66129cc5bcaSHans de Goede 	if (IS_ERR(inode)) {
66229cc5bcaSHans de Goede 		printf("%s: Error reading inode %ld!\n", __func__, inum);
66329cc5bcaSHans de Goede 		err = PTR_ERR(inode);
66429cc5bcaSHans de Goede 		goto out;
66529cc5bcaSHans de Goede 	}
66629cc5bcaSHans de Goede 
66729cc5bcaSHans de Goede 	*size = inode->i_size;
66829cc5bcaSHans de Goede 
66929cc5bcaSHans de Goede 	ubifs_iput(inode);
67029cc5bcaSHans de Goede out:
67129cc5bcaSHans de Goede 	ubi_close_volume(c->ubi);
67229cc5bcaSHans de Goede 	return err;
67329cc5bcaSHans de Goede }
67429cc5bcaSHans de Goede 
6759eefe2a2SStefan Roese /*
6769eefe2a2SStefan Roese  * ubifsload...
6779eefe2a2SStefan Roese  */
6789eefe2a2SStefan Roese 
6799eefe2a2SStefan Roese /* file.c */
6809eefe2a2SStefan Roese 
kmap(struct page * page)6819eefe2a2SStefan Roese static inline void *kmap(struct page *page)
6829eefe2a2SStefan Roese {
6839eefe2a2SStefan Roese 	return page->addr;
6849eefe2a2SStefan Roese }
6859eefe2a2SStefan Roese 
read_block(struct inode * inode,void * addr,unsigned int block,struct ubifs_data_node * dn)6869eefe2a2SStefan Roese static int read_block(struct inode *inode, void *addr, unsigned int block,
6879eefe2a2SStefan Roese 		      struct ubifs_data_node *dn)
6889eefe2a2SStefan Roese {
6899eefe2a2SStefan Roese 	struct ubifs_info *c = inode->i_sb->s_fs_info;
6909eefe2a2SStefan Roese 	int err, len, out_len;
6919eefe2a2SStefan Roese 	union ubifs_key key;
6929eefe2a2SStefan Roese 	unsigned int dlen;
6939eefe2a2SStefan Roese 
6949eefe2a2SStefan Roese 	data_key_init(c, &key, inode->i_ino, block);
6959eefe2a2SStefan Roese 	err = ubifs_tnc_lookup(c, &key, dn);
6969eefe2a2SStefan Roese 	if (err) {
6979eefe2a2SStefan Roese 		if (err == -ENOENT)
6989eefe2a2SStefan Roese 			/* Not found, so it must be a hole */
6999eefe2a2SStefan Roese 			memset(addr, 0, UBIFS_BLOCK_SIZE);
7009eefe2a2SStefan Roese 		return err;
7019eefe2a2SStefan Roese 	}
7029eefe2a2SStefan Roese 
7039eefe2a2SStefan Roese 	ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
7049eefe2a2SStefan Roese 
7059eefe2a2SStefan Roese 	len = le32_to_cpu(dn->size);
7069eefe2a2SStefan Roese 	if (len <= 0 || len > UBIFS_BLOCK_SIZE)
7079eefe2a2SStefan Roese 		goto dump;
7089eefe2a2SStefan Roese 
7099eefe2a2SStefan Roese 	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
7109eefe2a2SStefan Roese 	out_len = UBIFS_BLOCK_SIZE;
7110195a7bbSHeiko Schocher 	err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
7129eefe2a2SStefan Roese 			       le16_to_cpu(dn->compr_type));
7139eefe2a2SStefan Roese 	if (err || len != out_len)
7149eefe2a2SStefan Roese 		goto dump;
7159eefe2a2SStefan Roese 
7169eefe2a2SStefan Roese 	/*
7179eefe2a2SStefan Roese 	 * Data length can be less than a full block, even for blocks that are
7189eefe2a2SStefan Roese 	 * not the last in the file (e.g., as a result of making a hole and
7199eefe2a2SStefan Roese 	 * appending data). Ensure that the remainder is zeroed out.
7209eefe2a2SStefan Roese 	 */
7219eefe2a2SStefan Roese 	if (len < UBIFS_BLOCK_SIZE)
7229eefe2a2SStefan Roese 		memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
7239eefe2a2SStefan Roese 
7249eefe2a2SStefan Roese 	return 0;
7259eefe2a2SStefan Roese 
7269eefe2a2SStefan Roese dump:
7270195a7bbSHeiko Schocher 	ubifs_err(c, "bad data node (block %u, inode %lu)",
7289eefe2a2SStefan Roese 		  block, inode->i_ino);
729ff94bc40SHeiko Schocher 	ubifs_dump_node(c, dn);
7309eefe2a2SStefan Roese 	return -EINVAL;
7319eefe2a2SStefan Roese }
7329eefe2a2SStefan Roese 
do_readpage(struct ubifs_info * c,struct inode * inode,struct page * page,int last_block_size)733b1a14f8aSStefan Roese static int do_readpage(struct ubifs_info *c, struct inode *inode,
734b1a14f8aSStefan Roese 		       struct page *page, int last_block_size)
7359eefe2a2SStefan Roese {
7369eefe2a2SStefan Roese 	void *addr;
7379eefe2a2SStefan Roese 	int err = 0, i;
7389eefe2a2SStefan Roese 	unsigned int block, beyond;
7399eefe2a2SStefan Roese 	struct ubifs_data_node *dn;
7409eefe2a2SStefan Roese 	loff_t i_size = inode->i_size;
7419eefe2a2SStefan Roese 
7429eefe2a2SStefan Roese 	dbg_gen("ino %lu, pg %lu, i_size %lld",
7439eefe2a2SStefan Roese 		inode->i_ino, page->index, i_size);
7449eefe2a2SStefan Roese 
7459eefe2a2SStefan Roese 	addr = kmap(page);
7469eefe2a2SStefan Roese 
7479eefe2a2SStefan Roese 	block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
7489eefe2a2SStefan Roese 	beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
7499eefe2a2SStefan Roese 	if (block >= beyond) {
7509eefe2a2SStefan Roese 		/* Reading beyond inode */
7519eefe2a2SStefan Roese 		memset(addr, 0, PAGE_CACHE_SIZE);
7529eefe2a2SStefan Roese 		goto out;
7539eefe2a2SStefan Roese 	}
7549eefe2a2SStefan Roese 
7559eefe2a2SStefan Roese 	dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
756165f9859SDaniel Mack 	if (!dn)
757165f9859SDaniel Mack 		return -ENOMEM;
7589eefe2a2SStefan Roese 
7599eefe2a2SStefan Roese 	i = 0;
7609eefe2a2SStefan Roese 	while (1) {
7619eefe2a2SStefan Roese 		int ret;
7629eefe2a2SStefan Roese 
7639eefe2a2SStefan Roese 		if (block >= beyond) {
7649eefe2a2SStefan Roese 			/* Reading beyond inode */
7659eefe2a2SStefan Roese 			err = -ENOENT;
7669eefe2a2SStefan Roese 			memset(addr, 0, UBIFS_BLOCK_SIZE);
7679eefe2a2SStefan Roese 		} else {
768b1a14f8aSStefan Roese 			/*
769b1a14f8aSStefan Roese 			 * Reading last block? Make sure to not write beyond
770b1a14f8aSStefan Roese 			 * the requested size in the destination buffer.
771b1a14f8aSStefan Roese 			 */
772b1a14f8aSStefan Roese 			if (((block + 1) == beyond) || last_block_size) {
773b1a14f8aSStefan Roese 				void *buff;
774b1a14f8aSStefan Roese 				int dlen;
775b1a14f8aSStefan Roese 
776b1a14f8aSStefan Roese 				/*
777b1a14f8aSStefan Roese 				 * We need to buffer the data locally for the
778b1a14f8aSStefan Roese 				 * last block. This is to not pad the
779b1a14f8aSStefan Roese 				 * destination area to a multiple of
780b1a14f8aSStefan Roese 				 * UBIFS_BLOCK_SIZE.
781b1a14f8aSStefan Roese 				 */
7824519668bSMarcel Ziswiler 				buff = malloc_cache_aligned(UBIFS_BLOCK_SIZE);
783b1a14f8aSStefan Roese 				if (!buff) {
784b1a14f8aSStefan Roese 					printf("%s: Error, malloc fails!\n",
785b1a14f8aSStefan Roese 					       __func__);
786b1a14f8aSStefan Roese 					err = -ENOMEM;
787b1a14f8aSStefan Roese 					break;
788b1a14f8aSStefan Roese 				}
789b1a14f8aSStefan Roese 
790b1a14f8aSStefan Roese 				/* Read block-size into temp buffer */
791b1a14f8aSStefan Roese 				ret = read_block(inode, buff, block, dn);
792b1a14f8aSStefan Roese 				if (ret) {
793b1a14f8aSStefan Roese 					err = ret;
794b1a14f8aSStefan Roese 					if (err != -ENOENT) {
795b1a14f8aSStefan Roese 						free(buff);
796b1a14f8aSStefan Roese 						break;
797b1a14f8aSStefan Roese 					}
798b1a14f8aSStefan Roese 				}
799b1a14f8aSStefan Roese 
800b1a14f8aSStefan Roese 				if (last_block_size)
801b1a14f8aSStefan Roese 					dlen = last_block_size;
802*255bb283SPali Rohár 				else if (ret)
803*255bb283SPali Rohár 					dlen = UBIFS_BLOCK_SIZE;
804b1a14f8aSStefan Roese 				else
805b1a14f8aSStefan Roese 					dlen = le32_to_cpu(dn->size);
806b1a14f8aSStefan Roese 
807b1a14f8aSStefan Roese 				/* Now copy required size back to dest */
808b1a14f8aSStefan Roese 				memcpy(addr, buff, dlen);
809b1a14f8aSStefan Roese 
810b1a14f8aSStefan Roese 				free(buff);
811b1a14f8aSStefan Roese 			} else {
8129eefe2a2SStefan Roese 				ret = read_block(inode, addr, block, dn);
8139eefe2a2SStefan Roese 				if (ret) {
8149eefe2a2SStefan Roese 					err = ret;
8159eefe2a2SStefan Roese 					if (err != -ENOENT)
8169eefe2a2SStefan Roese 						break;
817b1a14f8aSStefan Roese 				}
8189eefe2a2SStefan Roese 			}
8199eefe2a2SStefan Roese 		}
8209eefe2a2SStefan Roese 		if (++i >= UBIFS_BLOCKS_PER_PAGE)
8219eefe2a2SStefan Roese 			break;
8229eefe2a2SStefan Roese 		block += 1;
8239eefe2a2SStefan Roese 		addr += UBIFS_BLOCK_SIZE;
8249eefe2a2SStefan Roese 	}
8259eefe2a2SStefan Roese 	if (err) {
8269eefe2a2SStefan Roese 		if (err == -ENOENT) {
8279eefe2a2SStefan Roese 			/* Not found, so it must be a hole */
8289eefe2a2SStefan Roese 			dbg_gen("hole");
8299eefe2a2SStefan Roese 			goto out_free;
8309eefe2a2SStefan Roese 		}
8310195a7bbSHeiko Schocher 		ubifs_err(c, "cannot read page %lu of inode %lu, error %d",
8329eefe2a2SStefan Roese 			  page->index, inode->i_ino, err);
8339eefe2a2SStefan Roese 		goto error;
8349eefe2a2SStefan Roese 	}
8359eefe2a2SStefan Roese 
8369eefe2a2SStefan Roese out_free:
8379eefe2a2SStefan Roese 	kfree(dn);
8389eefe2a2SStefan Roese out:
8399eefe2a2SStefan Roese 	return 0;
8409eefe2a2SStefan Roese 
8419eefe2a2SStefan Roese error:
8429eefe2a2SStefan Roese 	kfree(dn);
8439eefe2a2SStefan Roese 	return err;
8449eefe2a2SStefan Roese }
8459eefe2a2SStefan Roese 
ubifs_read(const char * filename,void * buf,loff_t offset,loff_t size,loff_t * actread)846ad15749bSHans de Goede int ubifs_read(const char *filename, void *buf, loff_t offset,
847ad15749bSHans de Goede 	       loff_t size, loff_t *actread)
8489eefe2a2SStefan Roese {
8499eefe2a2SStefan Roese 	struct ubifs_info *c = ubifs_sb->s_fs_info;
8509eefe2a2SStefan Roese 	unsigned long inum;
8519eefe2a2SStefan Roese 	struct inode *inode;
8529eefe2a2SStefan Roese 	struct page page;
8539eefe2a2SStefan Roese 	int err = 0;
8549eefe2a2SStefan Roese 	int i;
8559eefe2a2SStefan Roese 	int count;
856b1a14f8aSStefan Roese 	int last_block_size = 0;
8579eefe2a2SStefan Roese 
858ad15749bSHans de Goede 	*actread = 0;
859ad15749bSHans de Goede 
860ad15749bSHans de Goede 	if (offset & (PAGE_SIZE - 1)) {
8611381901eSVagrant Cascadian 		printf("ubifs: Error offset must be a multiple of %d\n",
862ad15749bSHans de Goede 		       PAGE_SIZE);
863ad15749bSHans de Goede 		return -1;
864ad15749bSHans de Goede 	}
865ad15749bSHans de Goede 
8669eefe2a2SStefan Roese 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
8679d7952e4SSimon Kagstrom 	/* ubifs_findfile will resolve symlinks, so we know that we get
8689d7952e4SSimon Kagstrom 	 * the real file here */
869ad15749bSHans de Goede 	inum = ubifs_findfile(ubifs_sb, (char *)filename);
8709eefe2a2SStefan Roese 	if (!inum) {
8719eefe2a2SStefan Roese 		err = -1;
8729eefe2a2SStefan Roese 		goto out;
8739eefe2a2SStefan Roese 	}
8749eefe2a2SStefan Roese 
8759eefe2a2SStefan Roese 	/*
8769eefe2a2SStefan Roese 	 * Read file inode
8779eefe2a2SStefan Roese 	 */
8789eefe2a2SStefan Roese 	inode = ubifs_iget(ubifs_sb, inum);
8799eefe2a2SStefan Roese 	if (IS_ERR(inode)) {
8809eefe2a2SStefan Roese 		printf("%s: Error reading inode %ld!\n", __func__, inum);
8819eefe2a2SStefan Roese 		err = PTR_ERR(inode);
8829eefe2a2SStefan Roese 		goto out;
8839eefe2a2SStefan Roese 	}
8849eefe2a2SStefan Roese 
885ad15749bSHans de Goede 	if (offset > inode->i_size) {
886ad15749bSHans de Goede 		printf("ubifs: Error offset (%lld) > file-size (%lld)\n",
887ad15749bSHans de Goede 		       offset, size);
888ad15749bSHans de Goede 		err = -1;
889ad15749bSHans de Goede 		goto put_inode;
890ad15749bSHans de Goede 	}
891ad15749bSHans de Goede 
8929eefe2a2SStefan Roese 	/*
8939eefe2a2SStefan Roese 	 * If no size was specified or if size bigger than filesize
8949eefe2a2SStefan Roese 	 * set size to filesize
8959eefe2a2SStefan Roese 	 */
896ad15749bSHans de Goede 	if ((size == 0) || (size > (inode->i_size - offset)))
897ad15749bSHans de Goede 		size = inode->i_size - offset;
8989eefe2a2SStefan Roese 
8999eefe2a2SStefan Roese 	count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
9009eefe2a2SStefan Roese 
901ad15749bSHans de Goede 	page.addr = buf;
902ad15749bSHans de Goede 	page.index = offset / PAGE_SIZE;
9039eefe2a2SStefan Roese 	page.inode = inode;
9049eefe2a2SStefan Roese 	for (i = 0; i < count; i++) {
905b1a14f8aSStefan Roese 		/*
906b1a14f8aSStefan Roese 		 * Make sure to not read beyond the requested size
907b1a14f8aSStefan Roese 		 */
908b1a14f8aSStefan Roese 		if (((i + 1) == count) && (size < inode->i_size))
909b1a14f8aSStefan Roese 			last_block_size = size - (i * PAGE_SIZE);
910b1a14f8aSStefan Roese 
911b1a14f8aSStefan Roese 		err = do_readpage(c, inode, &page, last_block_size);
9129eefe2a2SStefan Roese 		if (err)
9139eefe2a2SStefan Roese 			break;
9149eefe2a2SStefan Roese 
9159eefe2a2SStefan Roese 		page.addr += PAGE_SIZE;
9169eefe2a2SStefan Roese 		page.index++;
9179eefe2a2SStefan Roese 	}
9189eefe2a2SStefan Roese 
919ad15749bSHans de Goede 	if (err) {
9209eefe2a2SStefan Roese 		printf("Error reading file '%s'\n", filename);
921ad15749bSHans de Goede 		*actread = i * PAGE_SIZE;
922ad15749bSHans de Goede 	} else {
923ad15749bSHans de Goede 		*actread = size;
92446d7274cSBastian Ruppert 	}
9259eefe2a2SStefan Roese 
926ad15749bSHans de Goede put_inode:
9279eefe2a2SStefan Roese 	ubifs_iput(inode);
9289eefe2a2SStefan Roese 
9299eefe2a2SStefan Roese out:
9309eefe2a2SStefan Roese 	ubi_close_volume(c->ubi);
9319eefe2a2SStefan Roese 	return err;
9329eefe2a2SStefan Roese }
933ad15749bSHans de Goede 
ubifs_close(void)93429cc5bcaSHans de Goede void ubifs_close(void)
93529cc5bcaSHans de Goede {
93629cc5bcaSHans de Goede }
93729cc5bcaSHans de Goede 
938ad15749bSHans de Goede /* Compat wrappers for common/cmd_ubifs.c */
ubifs_load(char * filename,u32 addr,u32 size)939ad15749bSHans de Goede int ubifs_load(char *filename, u32 addr, u32 size)
940ad15749bSHans de Goede {
941ad15749bSHans de Goede 	loff_t actread;
942ad15749bSHans de Goede 	int err;
943ad15749bSHans de Goede 
944ad15749bSHans de Goede 	printf("Loading file '%s' to addr 0x%08x...\n", filename, addr);
945ad15749bSHans de Goede 
94634cc30afSSiva Durga Prasad Paladugu 	err = ubifs_read(filename, (void *)(uintptr_t)addr, 0, size, &actread);
947ad15749bSHans de Goede 	if (err == 0) {
948018f5303SSimon Glass 		env_set_hex("filesize", actread);
949ad15749bSHans de Goede 		printf("Done\n");
950ad15749bSHans de Goede 	}
951ad15749bSHans de Goede 
952ad15749bSHans de Goede 	return err;
953ad15749bSHans de Goede }
954ad15749bSHans de Goede 
uboot_ubifs_umount(void)955ad15749bSHans de Goede void uboot_ubifs_umount(void)
956ad15749bSHans de Goede {
957ad15749bSHans de Goede 	if (ubifs_sb) {
958ad15749bSHans de Goede 		printf("Unmounting UBIFS volume %s!\n",
959ad15749bSHans de Goede 		       ((struct ubifs_info *)(ubifs_sb->s_fs_info))->vi.name);
960ad15749bSHans de Goede 		ubifs_umount(ubifs_sb->s_fs_info);
961ad15749bSHans de Goede 		ubifs_sb = NULL;
962ad15749bSHans de Goede 	}
963ad15749bSHans de Goede }
964