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