xref: /rk3399_rockchip-uboot/fs/ubifs/ubifs.c (revision 3267bc1b2b52a8ffd0dfda663c02c86eaab6f70d)
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  * This program is free software; you can redistribute it and/or modify it
109eefe2a2SStefan Roese  * under the terms of the GNU General Public License version 2 as published by
119eefe2a2SStefan Roese  * the Free Software Foundation.
129eefe2a2SStefan Roese  *
139eefe2a2SStefan Roese  * This program is distributed in the hope that it will be useful, but WITHOUT
149eefe2a2SStefan Roese  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
159eefe2a2SStefan Roese  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
169eefe2a2SStefan Roese  * more details.
179eefe2a2SStefan Roese  *
189eefe2a2SStefan Roese  * You should have received a copy of the GNU General Public License along with
199eefe2a2SStefan Roese  * this program; if not, write to the Free Software Foundation, Inc., 51
209eefe2a2SStefan Roese  * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
219eefe2a2SStefan Roese  *
229eefe2a2SStefan Roese  * Authors: Artem Bityutskiy (Битюцкий Артём)
239eefe2a2SStefan Roese  *          Adrian Hunter
249eefe2a2SStefan Roese  */
259eefe2a2SStefan Roese 
269eefe2a2SStefan Roese #include "ubifs.h"
27c1a0fd5fSRicardo Ribalda Delgado #include <u-boot/zlib.h>
289eefe2a2SStefan Roese 
299eefe2a2SStefan Roese DECLARE_GLOBAL_DATA_PTR;
309eefe2a2SStefan Roese 
319eefe2a2SStefan Roese /* compress.c */
329eefe2a2SStefan Roese 
339eefe2a2SStefan Roese /*
34c1a0fd5fSRicardo Ribalda Delgado  * We need a wrapper for zunzip() because the parameters are
359eefe2a2SStefan Roese  * incompatible with the lzo decompressor.
369eefe2a2SStefan Roese  */
379eefe2a2SStefan Roese static int gzip_decompress(const unsigned char *in, size_t in_len,
389eefe2a2SStefan Roese 			   unsigned char *out, size_t *out_len)
399eefe2a2SStefan Roese {
409eefe2a2SStefan Roese 	unsigned long len = in_len;
41c1a0fd5fSRicardo Ribalda Delgado 	return zunzip(out, *out_len, (unsigned char *)in, &len, 0, 0);
429eefe2a2SStefan Roese }
439eefe2a2SStefan Roese 
449eefe2a2SStefan Roese /* Fake description object for the "none" compressor */
459eefe2a2SStefan Roese static struct ubifs_compressor none_compr = {
469eefe2a2SStefan Roese 	.compr_type = UBIFS_COMPR_NONE,
479eefe2a2SStefan Roese 	.name = "no compression",
489eefe2a2SStefan Roese 	.capi_name = "",
499eefe2a2SStefan Roese 	.decompress = NULL,
509eefe2a2SStefan Roese };
519eefe2a2SStefan Roese 
529eefe2a2SStefan Roese static struct ubifs_compressor lzo_compr = {
539eefe2a2SStefan Roese 	.compr_type = UBIFS_COMPR_LZO,
549eefe2a2SStefan Roese 	.name = "LZO",
559eefe2a2SStefan Roese 	.capi_name = "lzo",
569eefe2a2SStefan Roese 	.decompress = lzo1x_decompress_safe,
579eefe2a2SStefan Roese };
589eefe2a2SStefan Roese 
599eefe2a2SStefan Roese static struct ubifs_compressor zlib_compr = {
609eefe2a2SStefan Roese 	.compr_type = UBIFS_COMPR_ZLIB,
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 
699eefe2a2SStefan Roese /**
709eefe2a2SStefan Roese  * ubifs_decompress - decompress data.
719eefe2a2SStefan Roese  * @in_buf: data to decompress
729eefe2a2SStefan Roese  * @in_len: length of the data to decompress
739eefe2a2SStefan Roese  * @out_buf: output buffer where decompressed data should
749eefe2a2SStefan Roese  * @out_len: output length is returned here
759eefe2a2SStefan Roese  * @compr_type: type of compression
769eefe2a2SStefan Roese  *
779eefe2a2SStefan Roese  * This function decompresses data from buffer @in_buf into buffer @out_buf.
789eefe2a2SStefan Roese  * The length of the uncompressed data is returned in @out_len. This functions
799eefe2a2SStefan Roese  * returns %0 on success or a negative error code on failure.
809eefe2a2SStefan Roese  */
819eefe2a2SStefan Roese int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
829eefe2a2SStefan Roese 		     int *out_len, int compr_type)
839eefe2a2SStefan Roese {
849eefe2a2SStefan Roese 	int err;
859eefe2a2SStefan Roese 	struct ubifs_compressor *compr;
869eefe2a2SStefan Roese 
879eefe2a2SStefan Roese 	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
889eefe2a2SStefan Roese 		ubifs_err("invalid compression type %d", compr_type);
899eefe2a2SStefan Roese 		return -EINVAL;
909eefe2a2SStefan Roese 	}
919eefe2a2SStefan Roese 
929eefe2a2SStefan Roese 	compr = ubifs_compressors[compr_type];
939eefe2a2SStefan Roese 
949eefe2a2SStefan Roese 	if (unlikely(!compr->capi_name)) {
959eefe2a2SStefan Roese 		ubifs_err("%s compression is not compiled in", compr->name);
969eefe2a2SStefan Roese 		return -EINVAL;
979eefe2a2SStefan Roese 	}
989eefe2a2SStefan Roese 
999eefe2a2SStefan Roese 	if (compr_type == UBIFS_COMPR_NONE) {
1009eefe2a2SStefan Roese 		memcpy(out_buf, in_buf, in_len);
1019eefe2a2SStefan Roese 		*out_len = in_len;
1029eefe2a2SStefan Roese 		return 0;
1039eefe2a2SStefan Roese 	}
1049eefe2a2SStefan Roese 
1059eefe2a2SStefan Roese 	err = compr->decompress(in_buf, in_len, out_buf, (size_t *)out_len);
1069eefe2a2SStefan Roese 	if (err)
1079eefe2a2SStefan Roese 		ubifs_err("cannot decompress %d bytes, compressor %s, "
1089eefe2a2SStefan Roese 			  "error %d", in_len, compr->name, err);
1099eefe2a2SStefan Roese 
1109eefe2a2SStefan Roese 	return err;
1119eefe2a2SStefan Roese }
1129eefe2a2SStefan Roese 
1139eefe2a2SStefan Roese /**
1149eefe2a2SStefan Roese  * compr_init - initialize a compressor.
1159eefe2a2SStefan Roese  * @compr: compressor description object
1169eefe2a2SStefan Roese  *
1179eefe2a2SStefan Roese  * This function initializes the requested compressor and returns zero in case
1189eefe2a2SStefan Roese  * of success or a negative error code in case of failure.
1199eefe2a2SStefan Roese  */
1209eefe2a2SStefan Roese static int __init compr_init(struct ubifs_compressor *compr)
1219eefe2a2SStefan Roese {
1229eefe2a2SStefan Roese 	ubifs_compressors[compr->compr_type] = compr;
123521af04dSPeter Tyser 
1242e5167ccSWolfgang Denk #ifdef CONFIG_NEEDS_MANUAL_RELOC
1259eefe2a2SStefan Roese 	ubifs_compressors[compr->compr_type]->name += gd->reloc_off;
1269eefe2a2SStefan Roese 	ubifs_compressors[compr->compr_type]->capi_name += gd->reloc_off;
1279eefe2a2SStefan Roese 	ubifs_compressors[compr->compr_type]->decompress += gd->reloc_off;
128521af04dSPeter Tyser #endif
129521af04dSPeter Tyser 
1309eefe2a2SStefan Roese 	return 0;
1319eefe2a2SStefan Roese }
1329eefe2a2SStefan Roese 
1339eefe2a2SStefan Roese /**
1349eefe2a2SStefan Roese  * ubifs_compressors_init - initialize UBIFS compressors.
1359eefe2a2SStefan Roese  *
1369eefe2a2SStefan Roese  * This function initializes the compressor which were compiled in. Returns
1379eefe2a2SStefan Roese  * zero in case of success and a negative error code in case of failure.
1389eefe2a2SStefan Roese  */
1399eefe2a2SStefan Roese int __init ubifs_compressors_init(void)
1409eefe2a2SStefan Roese {
1419eefe2a2SStefan Roese 	int err;
1429eefe2a2SStefan Roese 
1439eefe2a2SStefan Roese 	err = compr_init(&lzo_compr);
1449eefe2a2SStefan Roese 	if (err)
1459eefe2a2SStefan Roese 		return err;
1469eefe2a2SStefan Roese 
1479eefe2a2SStefan Roese 	err = compr_init(&zlib_compr);
1489eefe2a2SStefan Roese 	if (err)
1499eefe2a2SStefan Roese 		return err;
1509eefe2a2SStefan Roese 
151faac4fd8SMichael Lawnick 	err = compr_init(&none_compr);
152faac4fd8SMichael Lawnick 	if (err)
153faac4fd8SMichael Lawnick 		return err;
154faac4fd8SMichael Lawnick 
1559eefe2a2SStefan Roese 	return 0;
1569eefe2a2SStefan Roese }
1579eefe2a2SStefan Roese 
1589eefe2a2SStefan Roese /*
1599eefe2a2SStefan Roese  * ubifsls...
1609eefe2a2SStefan Roese  */
1619eefe2a2SStefan Roese 
1629eefe2a2SStefan Roese static int filldir(struct ubifs_info *c, const char *name, int namlen,
1639eefe2a2SStefan Roese 		   u64 ino, unsigned int d_type)
1649eefe2a2SStefan Roese {
1659eefe2a2SStefan Roese 	struct inode *inode;
1669eefe2a2SStefan Roese 	char filetime[32];
1679eefe2a2SStefan Roese 
1689eefe2a2SStefan Roese 	switch (d_type) {
1699eefe2a2SStefan Roese 	case UBIFS_ITYPE_REG:
1709eefe2a2SStefan Roese 		printf("\t");
1719eefe2a2SStefan Roese 		break;
1729eefe2a2SStefan Roese 	case UBIFS_ITYPE_DIR:
1739eefe2a2SStefan Roese 		printf("<DIR>\t");
1749eefe2a2SStefan Roese 		break;
1759eefe2a2SStefan Roese 	case UBIFS_ITYPE_LNK:
1769eefe2a2SStefan Roese 		printf("<LNK>\t");
1779eefe2a2SStefan Roese 		break;
1789eefe2a2SStefan Roese 	default:
1799eefe2a2SStefan Roese 		printf("other\t");
1809eefe2a2SStefan Roese 		break;
1819eefe2a2SStefan Roese 	}
1829eefe2a2SStefan Roese 
1839eefe2a2SStefan Roese 	inode = ubifs_iget(c->vfs_sb, ino);
1849eefe2a2SStefan Roese 	if (IS_ERR(inode)) {
1859eefe2a2SStefan Roese 		printf("%s: Error in ubifs_iget(), ino=%lld ret=%p!\n",
1869eefe2a2SStefan Roese 		       __func__, ino, inode);
1879eefe2a2SStefan Roese 		return -1;
1889eefe2a2SStefan Roese 	}
1899eefe2a2SStefan Roese 	ctime_r((time_t *)&inode->i_mtime, filetime);
1909eefe2a2SStefan Roese 	printf("%9lld  %24.24s  ", inode->i_size, filetime);
1919eefe2a2SStefan Roese 	ubifs_iput(inode);
1929eefe2a2SStefan Roese 
1939eefe2a2SStefan Roese 	printf("%s\n", name);
1949eefe2a2SStefan Roese 
1959eefe2a2SStefan Roese 	return 0;
1969eefe2a2SStefan Roese }
1979eefe2a2SStefan Roese 
1989eefe2a2SStefan Roese static int ubifs_printdir(struct file *file, void *dirent)
1999eefe2a2SStefan Roese {
2009eefe2a2SStefan Roese 	int err, over = 0;
2019eefe2a2SStefan Roese 	struct qstr nm;
2029eefe2a2SStefan Roese 	union ubifs_key key;
2039eefe2a2SStefan Roese 	struct ubifs_dent_node *dent;
2049eefe2a2SStefan Roese 	struct inode *dir = file->f_path.dentry->d_inode;
2059eefe2a2SStefan Roese 	struct ubifs_info *c = dir->i_sb->s_fs_info;
2069eefe2a2SStefan Roese 
2079eefe2a2SStefan Roese 	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
2089eefe2a2SStefan Roese 
2099eefe2a2SStefan Roese 	if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
2109eefe2a2SStefan Roese 		/*
2119eefe2a2SStefan Roese 		 * The directory was seek'ed to a senseless position or there
2129eefe2a2SStefan Roese 		 * are no more entries.
2139eefe2a2SStefan Roese 		 */
2149eefe2a2SStefan Roese 		return 0;
2159eefe2a2SStefan Roese 
2169eefe2a2SStefan Roese 	if (file->f_pos == 1) {
2179eefe2a2SStefan Roese 		/* Find the first entry in TNC and save it */
2189eefe2a2SStefan Roese 		lowest_dent_key(c, &key, dir->i_ino);
2199eefe2a2SStefan Roese 		nm.name = NULL;
2209eefe2a2SStefan Roese 		dent = ubifs_tnc_next_ent(c, &key, &nm);
2219eefe2a2SStefan Roese 		if (IS_ERR(dent)) {
2229eefe2a2SStefan Roese 			err = PTR_ERR(dent);
2239eefe2a2SStefan Roese 			goto out;
2249eefe2a2SStefan Roese 		}
2259eefe2a2SStefan Roese 
2269eefe2a2SStefan Roese 		file->f_pos = key_hash_flash(c, &dent->key);
2279eefe2a2SStefan Roese 		file->private_data = dent;
2289eefe2a2SStefan Roese 	}
2299eefe2a2SStefan Roese 
2309eefe2a2SStefan Roese 	dent = file->private_data;
2319eefe2a2SStefan Roese 	if (!dent) {
2329eefe2a2SStefan Roese 		/*
2339eefe2a2SStefan Roese 		 * The directory was seek'ed to and is now readdir'ed.
2349eefe2a2SStefan Roese 		 * Find the entry corresponding to @file->f_pos or the
2359eefe2a2SStefan Roese 		 * closest one.
2369eefe2a2SStefan Roese 		 */
2379eefe2a2SStefan Roese 		dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
2389eefe2a2SStefan Roese 		nm.name = NULL;
2399eefe2a2SStefan Roese 		dent = ubifs_tnc_next_ent(c, &key, &nm);
2409eefe2a2SStefan Roese 		if (IS_ERR(dent)) {
2419eefe2a2SStefan Roese 			err = PTR_ERR(dent);
2429eefe2a2SStefan Roese 			goto out;
2439eefe2a2SStefan Roese 		}
2449eefe2a2SStefan Roese 		file->f_pos = key_hash_flash(c, &dent->key);
2459eefe2a2SStefan Roese 		file->private_data = dent;
2469eefe2a2SStefan Roese 	}
2479eefe2a2SStefan Roese 
2489eefe2a2SStefan Roese 	while (1) {
2499eefe2a2SStefan Roese 		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
2509eefe2a2SStefan Roese 			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
2519eefe2a2SStefan Roese 			key_hash_flash(c, &dent->key));
2529eefe2a2SStefan Roese 		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
2539eefe2a2SStefan Roese 
2549eefe2a2SStefan Roese 		nm.len = le16_to_cpu(dent->nlen);
2559eefe2a2SStefan Roese 		over = filldir(c, (char *)dent->name, nm.len,
2569eefe2a2SStefan Roese 			       le64_to_cpu(dent->inum), dent->type);
2579eefe2a2SStefan Roese 		if (over)
2589eefe2a2SStefan Roese 			return 0;
2599eefe2a2SStefan Roese 
2609eefe2a2SStefan Roese 		/* Switch to the next entry */
2619eefe2a2SStefan Roese 		key_read(c, &dent->key, &key);
2629eefe2a2SStefan Roese 		nm.name = (char *)dent->name;
2639eefe2a2SStefan Roese 		dent = ubifs_tnc_next_ent(c, &key, &nm);
2649eefe2a2SStefan Roese 		if (IS_ERR(dent)) {
2659eefe2a2SStefan Roese 			err = PTR_ERR(dent);
2669eefe2a2SStefan Roese 			goto out;
2679eefe2a2SStefan Roese 		}
2689eefe2a2SStefan Roese 
2699eefe2a2SStefan Roese 		kfree(file->private_data);
2709eefe2a2SStefan Roese 		file->f_pos = key_hash_flash(c, &dent->key);
2719eefe2a2SStefan Roese 		file->private_data = dent;
2729eefe2a2SStefan Roese 		cond_resched();
2739eefe2a2SStefan Roese 	}
2749eefe2a2SStefan Roese 
2759eefe2a2SStefan Roese out:
2769eefe2a2SStefan Roese 	if (err != -ENOENT) {
2779eefe2a2SStefan Roese 		ubifs_err("cannot find next direntry, error %d", err);
2789eefe2a2SStefan Roese 		return err;
2799eefe2a2SStefan Roese 	}
2809eefe2a2SStefan Roese 
2819eefe2a2SStefan Roese 	kfree(file->private_data);
2829eefe2a2SStefan Roese 	file->private_data = NULL;
2839eefe2a2SStefan Roese 	file->f_pos = 2;
2849eefe2a2SStefan Roese 	return 0;
2859eefe2a2SStefan Roese }
2869eefe2a2SStefan Roese 
2879eefe2a2SStefan Roese static int ubifs_finddir(struct super_block *sb, char *dirname,
2889eefe2a2SStefan Roese 			 unsigned long root_inum, unsigned long *inum)
2899eefe2a2SStefan Roese {
2909eefe2a2SStefan Roese 	int err;
2919eefe2a2SStefan Roese 	struct qstr nm;
2929eefe2a2SStefan Roese 	union ubifs_key key;
2939eefe2a2SStefan Roese 	struct ubifs_dent_node *dent;
2949eefe2a2SStefan Roese 	struct ubifs_info *c;
2959eefe2a2SStefan Roese 	struct file *file;
2969eefe2a2SStefan Roese 	struct dentry *dentry;
2979eefe2a2SStefan Roese 	struct inode *dir;
2989eefe2a2SStefan Roese 
2999eefe2a2SStefan Roese 	file = kzalloc(sizeof(struct file), 0);
3009eefe2a2SStefan Roese 	dentry = kzalloc(sizeof(struct dentry), 0);
3019eefe2a2SStefan Roese 	dir = kzalloc(sizeof(struct inode), 0);
3029eefe2a2SStefan Roese 	if (!file || !dentry || !dir) {
3039eefe2a2SStefan Roese 		printf("%s: Error, no memory for malloc!\n", __func__);
3049eefe2a2SStefan Roese 		err = -ENOMEM;
3059eefe2a2SStefan Roese 		goto out;
3069eefe2a2SStefan Roese 	}
3079eefe2a2SStefan Roese 
3089eefe2a2SStefan Roese 	dir->i_sb = sb;
3099eefe2a2SStefan Roese 	file->f_path.dentry = dentry;
3109eefe2a2SStefan Roese 	file->f_path.dentry->d_parent = dentry;
3119eefe2a2SStefan Roese 	file->f_path.dentry->d_inode = dir;
3129eefe2a2SStefan Roese 	file->f_path.dentry->d_inode->i_ino = root_inum;
3139eefe2a2SStefan Roese 	c = sb->s_fs_info;
3149eefe2a2SStefan Roese 
3159eefe2a2SStefan Roese 	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
3169eefe2a2SStefan Roese 
3179eefe2a2SStefan Roese 	/* Find the first entry in TNC and save it */
3189eefe2a2SStefan Roese 	lowest_dent_key(c, &key, dir->i_ino);
3199eefe2a2SStefan Roese 	nm.name = NULL;
3209eefe2a2SStefan Roese 	dent = ubifs_tnc_next_ent(c, &key, &nm);
3219eefe2a2SStefan Roese 	if (IS_ERR(dent)) {
3229eefe2a2SStefan Roese 		err = PTR_ERR(dent);
3239eefe2a2SStefan Roese 		goto out;
3249eefe2a2SStefan Roese 	}
3259eefe2a2SStefan Roese 
3269eefe2a2SStefan Roese 	file->f_pos = key_hash_flash(c, &dent->key);
3279eefe2a2SStefan Roese 	file->private_data = dent;
3289eefe2a2SStefan Roese 
3299eefe2a2SStefan Roese 	while (1) {
3309eefe2a2SStefan Roese 		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
3319eefe2a2SStefan Roese 			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
3329eefe2a2SStefan Roese 			key_hash_flash(c, &dent->key));
3339eefe2a2SStefan Roese 		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
3349eefe2a2SStefan Roese 
3359eefe2a2SStefan Roese 		nm.len = le16_to_cpu(dent->nlen);
3369eefe2a2SStefan Roese 		if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) &&
3379eefe2a2SStefan Roese 		    (strlen(dirname) == nm.len)) {
3389eefe2a2SStefan Roese 			*inum = le64_to_cpu(dent->inum);
3399eefe2a2SStefan Roese 			return 1;
3409eefe2a2SStefan Roese 		}
3419eefe2a2SStefan Roese 
3429eefe2a2SStefan Roese 		/* Switch to the next entry */
3439eefe2a2SStefan Roese 		key_read(c, &dent->key, &key);
3449eefe2a2SStefan Roese 		nm.name = (char *)dent->name;
3459eefe2a2SStefan Roese 		dent = ubifs_tnc_next_ent(c, &key, &nm);
3469eefe2a2SStefan Roese 		if (IS_ERR(dent)) {
3479eefe2a2SStefan Roese 			err = PTR_ERR(dent);
3489eefe2a2SStefan Roese 			goto out;
3499eefe2a2SStefan Roese 		}
3509eefe2a2SStefan Roese 
3519eefe2a2SStefan Roese 		kfree(file->private_data);
3529eefe2a2SStefan Roese 		file->f_pos = key_hash_flash(c, &dent->key);
3539eefe2a2SStefan Roese 		file->private_data = dent;
3549eefe2a2SStefan Roese 		cond_resched();
3559eefe2a2SStefan Roese 	}
3569eefe2a2SStefan Roese 
3579eefe2a2SStefan Roese out:
3589eefe2a2SStefan Roese 	if (err != -ENOENT) {
3599eefe2a2SStefan Roese 		ubifs_err("cannot find next direntry, error %d", err);
3609eefe2a2SStefan Roese 		return err;
3619eefe2a2SStefan Roese 	}
3629eefe2a2SStefan Roese 
363*3267bc1bSWolfgang Denk 	if (file->private_data)
364*3267bc1bSWolfgang Denk 		kfree(file->private_data);
3659eefe2a2SStefan Roese 	if (file)
3669eefe2a2SStefan Roese 		free(file);
3679eefe2a2SStefan Roese 	if (dentry)
3689eefe2a2SStefan Roese 		free(dentry);
3699eefe2a2SStefan Roese 	if (dir)
3709eefe2a2SStefan Roese 		free(dir);
3719eefe2a2SStefan Roese 
3729eefe2a2SStefan Roese 	return 0;
3739eefe2a2SStefan Roese }
3749eefe2a2SStefan Roese 
3759eefe2a2SStefan Roese static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
3769eefe2a2SStefan Roese {
3779eefe2a2SStefan Roese 	int ret;
3789eefe2a2SStefan Roese 	char *next;
3799eefe2a2SStefan Roese 	char fpath[128];
3809d7952e4SSimon Kagstrom 	char symlinkpath[128];
3819eefe2a2SStefan Roese 	char *name = fpath;
3829eefe2a2SStefan Roese 	unsigned long root_inum = 1;
3839eefe2a2SStefan Roese 	unsigned long inum;
3849d7952e4SSimon Kagstrom 	int symlink_count = 0; /* Don't allow symlink recursion */
38564b68178SRicardo Ribalda Delgado 	char link_name[64];
3869eefe2a2SStefan Roese 
3879eefe2a2SStefan Roese 	strcpy(fpath, filename);
3889eefe2a2SStefan Roese 
3899eefe2a2SStefan Roese 	/* Remove all leading slashes */
3909eefe2a2SStefan Roese 	while (*name == '/')
3919eefe2a2SStefan Roese 		name++;
3929eefe2a2SStefan Roese 
3939eefe2a2SStefan Roese 	/*
3949eefe2a2SStefan Roese 	 * Handle root-direcoty ('/')
3959eefe2a2SStefan Roese 	 */
3969eefe2a2SStefan Roese 	inum = root_inum;
3979eefe2a2SStefan Roese 	if (!name || *name == '\0')
3989eefe2a2SStefan Roese 		return inum;
3999eefe2a2SStefan Roese 
4009eefe2a2SStefan Roese 	for (;;) {
4019d7952e4SSimon Kagstrom 		struct inode *inode;
4029d7952e4SSimon Kagstrom 		struct ubifs_inode *ui;
4039d7952e4SSimon Kagstrom 
4049eefe2a2SStefan Roese 		/* Extract the actual part from the pathname.  */
4059eefe2a2SStefan Roese 		next = strchr(name, '/');
4069eefe2a2SStefan Roese 		if (next) {
4079eefe2a2SStefan Roese 			/* Remove all leading slashes.  */
4089eefe2a2SStefan Roese 			while (*next == '/')
4099eefe2a2SStefan Roese 				*(next++) = '\0';
4109eefe2a2SStefan Roese 		}
4119eefe2a2SStefan Roese 
4129eefe2a2SStefan Roese 		ret = ubifs_finddir(sb, name, root_inum, &inum);
4139d7952e4SSimon Kagstrom 		if (!ret)
4149d7952e4SSimon Kagstrom 			return 0;
4159d7952e4SSimon Kagstrom 		inode = ubifs_iget(sb, inum);
4169d7952e4SSimon Kagstrom 
4179d7952e4SSimon Kagstrom 		if (!inode)
4189d7952e4SSimon Kagstrom 			return 0;
4199d7952e4SSimon Kagstrom 		ui = ubifs_inode(inode);
4209d7952e4SSimon Kagstrom 
4219d7952e4SSimon Kagstrom 		if ((inode->i_mode & S_IFMT) == S_IFLNK) {
4229d7952e4SSimon Kagstrom 			char buf[128];
4239d7952e4SSimon Kagstrom 
4249d7952e4SSimon Kagstrom 			/* We have some sort of symlink recursion, bail out */
4259d7952e4SSimon Kagstrom 			if (symlink_count++ > 8) {
4269d7952e4SSimon Kagstrom 				printf("Symlink recursion, aborting\n");
4279d7952e4SSimon Kagstrom 				return 0;
4289d7952e4SSimon Kagstrom 			}
4299d7952e4SSimon Kagstrom 			memcpy(link_name, ui->data, ui->data_len);
4309d7952e4SSimon Kagstrom 			link_name[ui->data_len] = '\0';
4319d7952e4SSimon Kagstrom 
4329d7952e4SSimon Kagstrom 			if (link_name[0] == '/') {
4339d7952e4SSimon Kagstrom 				/* Absolute path, redo everything without
4349d7952e4SSimon Kagstrom 				 * the leading slash */
4359d7952e4SSimon Kagstrom 				next = name = link_name + 1;
4369d7952e4SSimon Kagstrom 				root_inum = 1;
4379d7952e4SSimon Kagstrom 				continue;
4389d7952e4SSimon Kagstrom 			}
4399d7952e4SSimon Kagstrom 			/* Relative to cur dir */
440ef37c683SSimon Kagstrom 			sprintf(buf, "%s/%s",
4419d7952e4SSimon Kagstrom 					link_name, next == NULL ? "" : next);
4429d7952e4SSimon Kagstrom 			memcpy(symlinkpath, buf, sizeof(buf));
4439d7952e4SSimon Kagstrom 			next = name = symlinkpath;
4449d7952e4SSimon Kagstrom 			continue;
4459d7952e4SSimon Kagstrom 		}
4469eefe2a2SStefan Roese 
4479eefe2a2SStefan Roese 		/*
4489eefe2a2SStefan Roese 		 * Check if directory with this name exists
4499eefe2a2SStefan Roese 		 */
4509eefe2a2SStefan Roese 
4519eefe2a2SStefan Roese 		/* Found the node!  */
4529d7952e4SSimon Kagstrom 		if (!next || *next == '\0')
4539eefe2a2SStefan Roese 			return inum;
4549eefe2a2SStefan Roese 
4559eefe2a2SStefan Roese 		root_inum = inum;
4569eefe2a2SStefan Roese 		name = next;
4579eefe2a2SStefan Roese 	}
4589eefe2a2SStefan Roese 
4599eefe2a2SStefan Roese 	return 0;
4609eefe2a2SStefan Roese }
4619eefe2a2SStefan Roese 
4629eefe2a2SStefan Roese int ubifs_ls(char *filename)
4639eefe2a2SStefan Roese {
4649eefe2a2SStefan Roese 	struct ubifs_info *c = ubifs_sb->s_fs_info;
4659eefe2a2SStefan Roese 	struct file *file;
4669eefe2a2SStefan Roese 	struct dentry *dentry;
4679eefe2a2SStefan Roese 	struct inode *dir;
4689eefe2a2SStefan Roese 	void *dirent = NULL;
4699eefe2a2SStefan Roese 	unsigned long inum;
4709eefe2a2SStefan Roese 	int ret = 0;
4719eefe2a2SStefan Roese 
4729eefe2a2SStefan Roese 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
4739eefe2a2SStefan Roese 	inum = ubifs_findfile(ubifs_sb, filename);
4749eefe2a2SStefan Roese 	if (!inum) {
4759eefe2a2SStefan Roese 		ret = -1;
4769eefe2a2SStefan Roese 		goto out;
4779eefe2a2SStefan Roese 	}
4789eefe2a2SStefan Roese 
4799eefe2a2SStefan Roese 	file = kzalloc(sizeof(struct file), 0);
4809eefe2a2SStefan Roese 	dentry = kzalloc(sizeof(struct dentry), 0);
4819eefe2a2SStefan Roese 	dir = kzalloc(sizeof(struct inode), 0);
4829eefe2a2SStefan Roese 	if (!file || !dentry || !dir) {
4839eefe2a2SStefan Roese 		printf("%s: Error, no memory for malloc!\n", __func__);
4849eefe2a2SStefan Roese 		ret = -ENOMEM;
4859eefe2a2SStefan Roese 		goto out_mem;
4869eefe2a2SStefan Roese 	}
4879eefe2a2SStefan Roese 
4889eefe2a2SStefan Roese 	dir->i_sb = ubifs_sb;
4899eefe2a2SStefan Roese 	file->f_path.dentry = dentry;
4909eefe2a2SStefan Roese 	file->f_path.dentry->d_parent = dentry;
4919eefe2a2SStefan Roese 	file->f_path.dentry->d_inode = dir;
4929eefe2a2SStefan Roese 	file->f_path.dentry->d_inode->i_ino = inum;
4939eefe2a2SStefan Roese 	file->f_pos = 1;
4949eefe2a2SStefan Roese 	file->private_data = NULL;
4959eefe2a2SStefan Roese 	ubifs_printdir(file, dirent);
4969eefe2a2SStefan Roese 
4979eefe2a2SStefan Roese out_mem:
4989eefe2a2SStefan Roese 	if (file)
4999eefe2a2SStefan Roese 		free(file);
5009eefe2a2SStefan Roese 	if (dentry)
5019eefe2a2SStefan Roese 		free(dentry);
5029eefe2a2SStefan Roese 	if (dir)
5039eefe2a2SStefan Roese 		free(dir);
5049eefe2a2SStefan Roese 
5059eefe2a2SStefan Roese out:
5069eefe2a2SStefan Roese 	ubi_close_volume(c->ubi);
5079eefe2a2SStefan Roese 	return ret;
5089eefe2a2SStefan Roese }
5099eefe2a2SStefan Roese 
5109eefe2a2SStefan Roese /*
5119eefe2a2SStefan Roese  * ubifsload...
5129eefe2a2SStefan Roese  */
5139eefe2a2SStefan Roese 
5149eefe2a2SStefan Roese /* file.c */
5159eefe2a2SStefan Roese 
5169eefe2a2SStefan Roese static inline void *kmap(struct page *page)
5179eefe2a2SStefan Roese {
5189eefe2a2SStefan Roese 	return page->addr;
5199eefe2a2SStefan Roese }
5209eefe2a2SStefan Roese 
5219eefe2a2SStefan Roese static int read_block(struct inode *inode, void *addr, unsigned int block,
5229eefe2a2SStefan Roese 		      struct ubifs_data_node *dn)
5239eefe2a2SStefan Roese {
5249eefe2a2SStefan Roese 	struct ubifs_info *c = inode->i_sb->s_fs_info;
5259eefe2a2SStefan Roese 	int err, len, out_len;
5269eefe2a2SStefan Roese 	union ubifs_key key;
5279eefe2a2SStefan Roese 	unsigned int dlen;
5289eefe2a2SStefan Roese 
5299eefe2a2SStefan Roese 	data_key_init(c, &key, inode->i_ino, block);
5309eefe2a2SStefan Roese 	err = ubifs_tnc_lookup(c, &key, dn);
5319eefe2a2SStefan Roese 	if (err) {
5329eefe2a2SStefan Roese 		if (err == -ENOENT)
5339eefe2a2SStefan Roese 			/* Not found, so it must be a hole */
5349eefe2a2SStefan Roese 			memset(addr, 0, UBIFS_BLOCK_SIZE);
5359eefe2a2SStefan Roese 		return err;
5369eefe2a2SStefan Roese 	}
5379eefe2a2SStefan Roese 
5389eefe2a2SStefan Roese 	ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
5399eefe2a2SStefan Roese 
5409eefe2a2SStefan Roese 	len = le32_to_cpu(dn->size);
5419eefe2a2SStefan Roese 	if (len <= 0 || len > UBIFS_BLOCK_SIZE)
5429eefe2a2SStefan Roese 		goto dump;
5439eefe2a2SStefan Roese 
5449eefe2a2SStefan Roese 	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
5459eefe2a2SStefan Roese 	out_len = UBIFS_BLOCK_SIZE;
5469eefe2a2SStefan Roese 	err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
5479eefe2a2SStefan Roese 			       le16_to_cpu(dn->compr_type));
5489eefe2a2SStefan Roese 	if (err || len != out_len)
5499eefe2a2SStefan Roese 		goto dump;
5509eefe2a2SStefan Roese 
5519eefe2a2SStefan Roese 	/*
5529eefe2a2SStefan Roese 	 * Data length can be less than a full block, even for blocks that are
5539eefe2a2SStefan Roese 	 * not the last in the file (e.g., as a result of making a hole and
5549eefe2a2SStefan Roese 	 * appending data). Ensure that the remainder is zeroed out.
5559eefe2a2SStefan Roese 	 */
5569eefe2a2SStefan Roese 	if (len < UBIFS_BLOCK_SIZE)
5579eefe2a2SStefan Roese 		memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
5589eefe2a2SStefan Roese 
5599eefe2a2SStefan Roese 	return 0;
5609eefe2a2SStefan Roese 
5619eefe2a2SStefan Roese dump:
5629eefe2a2SStefan Roese 	ubifs_err("bad data node (block %u, inode %lu)",
5639eefe2a2SStefan Roese 		  block, inode->i_ino);
5649eefe2a2SStefan Roese 	dbg_dump_node(c, dn);
5659eefe2a2SStefan Roese 	return -EINVAL;
5669eefe2a2SStefan Roese }
5679eefe2a2SStefan Roese 
568b1a14f8aSStefan Roese static int do_readpage(struct ubifs_info *c, struct inode *inode,
569b1a14f8aSStefan Roese 		       struct page *page, int last_block_size)
5709eefe2a2SStefan Roese {
5719eefe2a2SStefan Roese 	void *addr;
5729eefe2a2SStefan Roese 	int err = 0, i;
5739eefe2a2SStefan Roese 	unsigned int block, beyond;
5749eefe2a2SStefan Roese 	struct ubifs_data_node *dn;
5759eefe2a2SStefan Roese 	loff_t i_size = inode->i_size;
5769eefe2a2SStefan Roese 
5779eefe2a2SStefan Roese 	dbg_gen("ino %lu, pg %lu, i_size %lld",
5789eefe2a2SStefan Roese 		inode->i_ino, page->index, i_size);
5799eefe2a2SStefan Roese 
5809eefe2a2SStefan Roese 	addr = kmap(page);
5819eefe2a2SStefan Roese 
5829eefe2a2SStefan Roese 	block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
5839eefe2a2SStefan Roese 	beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
5849eefe2a2SStefan Roese 	if (block >= beyond) {
5859eefe2a2SStefan Roese 		/* Reading beyond inode */
5869eefe2a2SStefan Roese 		memset(addr, 0, PAGE_CACHE_SIZE);
5879eefe2a2SStefan Roese 		goto out;
5889eefe2a2SStefan Roese 	}
5899eefe2a2SStefan Roese 
5909eefe2a2SStefan Roese 	dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
591165f9859SDaniel Mack 	if (!dn)
592165f9859SDaniel Mack 		return -ENOMEM;
5939eefe2a2SStefan Roese 
5949eefe2a2SStefan Roese 	i = 0;
5959eefe2a2SStefan Roese 	while (1) {
5969eefe2a2SStefan Roese 		int ret;
5979eefe2a2SStefan Roese 
5989eefe2a2SStefan Roese 		if (block >= beyond) {
5999eefe2a2SStefan Roese 			/* Reading beyond inode */
6009eefe2a2SStefan Roese 			err = -ENOENT;
6019eefe2a2SStefan Roese 			memset(addr, 0, UBIFS_BLOCK_SIZE);
6029eefe2a2SStefan Roese 		} else {
603b1a14f8aSStefan Roese 			/*
604b1a14f8aSStefan Roese 			 * Reading last block? Make sure to not write beyond
605b1a14f8aSStefan Roese 			 * the requested size in the destination buffer.
606b1a14f8aSStefan Roese 			 */
607b1a14f8aSStefan Roese 			if (((block + 1) == beyond) || last_block_size) {
608b1a14f8aSStefan Roese 				void *buff;
609b1a14f8aSStefan Roese 				int dlen;
610b1a14f8aSStefan Roese 
611b1a14f8aSStefan Roese 				/*
612b1a14f8aSStefan Roese 				 * We need to buffer the data locally for the
613b1a14f8aSStefan Roese 				 * last block. This is to not pad the
614b1a14f8aSStefan Roese 				 * destination area to a multiple of
615b1a14f8aSStefan Roese 				 * UBIFS_BLOCK_SIZE.
616b1a14f8aSStefan Roese 				 */
617b1a14f8aSStefan Roese 				buff = malloc(UBIFS_BLOCK_SIZE);
618b1a14f8aSStefan Roese 				if (!buff) {
619b1a14f8aSStefan Roese 					printf("%s: Error, malloc fails!\n",
620b1a14f8aSStefan Roese 					       __func__);
621b1a14f8aSStefan Roese 					err = -ENOMEM;
622b1a14f8aSStefan Roese 					break;
623b1a14f8aSStefan Roese 				}
624b1a14f8aSStefan Roese 
625b1a14f8aSStefan Roese 				/* Read block-size into temp buffer */
626b1a14f8aSStefan Roese 				ret = read_block(inode, buff, block, dn);
627b1a14f8aSStefan Roese 				if (ret) {
628b1a14f8aSStefan Roese 					err = ret;
629b1a14f8aSStefan Roese 					if (err != -ENOENT) {
630b1a14f8aSStefan Roese 						free(buff);
631b1a14f8aSStefan Roese 						break;
632b1a14f8aSStefan Roese 					}
633b1a14f8aSStefan Roese 				}
634b1a14f8aSStefan Roese 
635b1a14f8aSStefan Roese 				if (last_block_size)
636b1a14f8aSStefan Roese 					dlen = last_block_size;
637b1a14f8aSStefan Roese 				else
638b1a14f8aSStefan Roese 					dlen = le32_to_cpu(dn->size);
639b1a14f8aSStefan Roese 
640b1a14f8aSStefan Roese 				/* Now copy required size back to dest */
641b1a14f8aSStefan Roese 				memcpy(addr, buff, dlen);
642b1a14f8aSStefan Roese 
643b1a14f8aSStefan Roese 				free(buff);
644b1a14f8aSStefan Roese 			} else {
6459eefe2a2SStefan Roese 				ret = read_block(inode, addr, block, dn);
6469eefe2a2SStefan Roese 				if (ret) {
6479eefe2a2SStefan Roese 					err = ret;
6489eefe2a2SStefan Roese 					if (err != -ENOENT)
6499eefe2a2SStefan Roese 						break;
650b1a14f8aSStefan Roese 				}
6519eefe2a2SStefan Roese 			}
6529eefe2a2SStefan Roese 		}
6539eefe2a2SStefan Roese 		if (++i >= UBIFS_BLOCKS_PER_PAGE)
6549eefe2a2SStefan Roese 			break;
6559eefe2a2SStefan Roese 		block += 1;
6569eefe2a2SStefan Roese 		addr += UBIFS_BLOCK_SIZE;
6579eefe2a2SStefan Roese 	}
6589eefe2a2SStefan Roese 	if (err) {
6599eefe2a2SStefan Roese 		if (err == -ENOENT) {
6609eefe2a2SStefan Roese 			/* Not found, so it must be a hole */
6619eefe2a2SStefan Roese 			dbg_gen("hole");
6629eefe2a2SStefan Roese 			goto out_free;
6639eefe2a2SStefan Roese 		}
6649eefe2a2SStefan Roese 		ubifs_err("cannot read page %lu of inode %lu, error %d",
6659eefe2a2SStefan Roese 			  page->index, inode->i_ino, err);
6669eefe2a2SStefan Roese 		goto error;
6679eefe2a2SStefan Roese 	}
6689eefe2a2SStefan Roese 
6699eefe2a2SStefan Roese out_free:
6709eefe2a2SStefan Roese 	kfree(dn);
6719eefe2a2SStefan Roese out:
6729eefe2a2SStefan Roese 	return 0;
6739eefe2a2SStefan Roese 
6749eefe2a2SStefan Roese error:
6759eefe2a2SStefan Roese 	kfree(dn);
6769eefe2a2SStefan Roese 	return err;
6779eefe2a2SStefan Roese }
6789eefe2a2SStefan Roese 
6799eefe2a2SStefan Roese int ubifs_load(char *filename, u32 addr, u32 size)
6809eefe2a2SStefan Roese {
6819eefe2a2SStefan Roese 	struct ubifs_info *c = ubifs_sb->s_fs_info;
6829eefe2a2SStefan Roese 	unsigned long inum;
6839eefe2a2SStefan Roese 	struct inode *inode;
6849eefe2a2SStefan Roese 	struct page page;
6859eefe2a2SStefan Roese 	int err = 0;
6869eefe2a2SStefan Roese 	int i;
6879eefe2a2SStefan Roese 	int count;
688b1a14f8aSStefan Roese 	int last_block_size = 0;
6899eefe2a2SStefan Roese 
6909eefe2a2SStefan Roese 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
6919d7952e4SSimon Kagstrom 	/* ubifs_findfile will resolve symlinks, so we know that we get
6929d7952e4SSimon Kagstrom 	 * the real file here */
6939eefe2a2SStefan Roese 	inum = ubifs_findfile(ubifs_sb, filename);
6949eefe2a2SStefan Roese 	if (!inum) {
6959eefe2a2SStefan Roese 		err = -1;
6969eefe2a2SStefan Roese 		goto out;
6979eefe2a2SStefan Roese 	}
6989eefe2a2SStefan Roese 
6999eefe2a2SStefan Roese 	/*
7009eefe2a2SStefan Roese 	 * Read file inode
7019eefe2a2SStefan Roese 	 */
7029eefe2a2SStefan Roese 	inode = ubifs_iget(ubifs_sb, inum);
7039eefe2a2SStefan Roese 	if (IS_ERR(inode)) {
7049eefe2a2SStefan Roese 		printf("%s: Error reading inode %ld!\n", __func__, inum);
7059eefe2a2SStefan Roese 		err = PTR_ERR(inode);
7069eefe2a2SStefan Roese 		goto out;
7079eefe2a2SStefan Roese 	}
7089eefe2a2SStefan Roese 
7099eefe2a2SStefan Roese 	/*
7109eefe2a2SStefan Roese 	 * If no size was specified or if size bigger than filesize
7119eefe2a2SStefan Roese 	 * set size to filesize
7129eefe2a2SStefan Roese 	 */
7139eefe2a2SStefan Roese 	if ((size == 0) || (size > inode->i_size))
7149eefe2a2SStefan Roese 		size = inode->i_size;
7159eefe2a2SStefan Roese 
7169eefe2a2SStefan Roese 	count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
7179eefe2a2SStefan Roese 	printf("Loading file '%s' to addr 0x%08x with size %d (0x%08x)...\n",
7189eefe2a2SStefan Roese 	       filename, addr, size, size);
7199eefe2a2SStefan Roese 
7209eefe2a2SStefan Roese 	page.addr = (void *)addr;
7219eefe2a2SStefan Roese 	page.index = 0;
7229eefe2a2SStefan Roese 	page.inode = inode;
7239eefe2a2SStefan Roese 	for (i = 0; i < count; i++) {
724b1a14f8aSStefan Roese 		/*
725b1a14f8aSStefan Roese 		 * Make sure to not read beyond the requested size
726b1a14f8aSStefan Roese 		 */
727b1a14f8aSStefan Roese 		if (((i + 1) == count) && (size < inode->i_size))
728b1a14f8aSStefan Roese 			last_block_size = size - (i * PAGE_SIZE);
729b1a14f8aSStefan Roese 
730b1a14f8aSStefan Roese 		err = do_readpage(c, inode, &page, last_block_size);
7319eefe2a2SStefan Roese 		if (err)
7329eefe2a2SStefan Roese 			break;
7339eefe2a2SStefan Roese 
7349eefe2a2SStefan Roese 		page.addr += PAGE_SIZE;
7359eefe2a2SStefan Roese 		page.index++;
7369eefe2a2SStefan Roese 	}
7379eefe2a2SStefan Roese 
7389eefe2a2SStefan Roese 	if (err)
7399eefe2a2SStefan Roese 		printf("Error reading file '%s'\n", filename);
7409eefe2a2SStefan Roese 	else
7419eefe2a2SStefan Roese 		printf("Done\n");
7429eefe2a2SStefan Roese 
7439eefe2a2SStefan Roese 	ubifs_iput(inode);
7449eefe2a2SStefan Roese 
7459eefe2a2SStefan Roese out:
7469eefe2a2SStefan Roese 	ubi_close_volume(c->ubi);
7479eefe2a2SStefan Roese 	return err;
7489eefe2a2SStefan Roese }
749