Blame view

fs/ubifs/ubifs.c 20.6 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
2
3
4
5
6
  /*
   * This file is part of UBIFS.
   *
   * Copyright (C) 2006-2008 Nokia Corporation.
   *
b1a14f8a1   Stefan Roese   UBIFS: Change ubi...
7
   * (C) Copyright 2008-2010
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
8
9
   * Stefan Roese, DENX Software Engineering, sr@denx.de.
   *
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
10
11
12
   * Authors: Artem Bityutskiy (Битюцкий Артём)
   *          Adrian Hunter
   */
6e295186c   Simon Glass   Move malloc_cache...
13
14
  #include <common.h>
  #include <memalign.h>
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
15
  #include "ubifs.h"
c1a0fd5f2   Ricardo Ribalda Delgado   ubifs: BUG: Block...
16
  #include <u-boot/zlib.h>
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
17

ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
18
19
  #include <linux/err.h>
  #include <linux/lzo.h>
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
20
21
22
23
24
  DECLARE_GLOBAL_DATA_PTR;
  
  /* compress.c */
  
  /*
c1a0fd5f2   Ricardo Ribalda Delgado   ubifs: BUG: Block...
25
   * We need a wrapper for zunzip() because the parameters are
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
26
27
28
29
30
   * incompatible with the lzo decompressor.
   */
  static int gzip_decompress(const unsigned char *in, size_t in_len,
  			   unsigned char *out, size_t *out_len)
  {
8044c1387   Veli-Pekka Peltola   ubifs: Fix ubifsl...
31
32
  	return zunzip(out, *out_len, (unsigned char *)in,
  		      (unsigned long *)out_len, 0, 0);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
33
34
35
36
37
  }
  
  /* Fake description object for the "none" compressor */
  static struct ubifs_compressor none_compr = {
  	.compr_type = UBIFS_COMPR_NONE,
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
38
  	.name = "none",
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
39
40
41
42
43
44
  	.capi_name = "",
  	.decompress = NULL,
  };
  
  static struct ubifs_compressor lzo_compr = {
  	.compr_type = UBIFS_COMPR_LZO,
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
45
46
47
48
  #ifndef __UBOOT__
  	.comp_mutex = &lzo_mutex,
  #endif
  	.name = "lzo",
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
49
50
51
52
53
54
  	.capi_name = "lzo",
  	.decompress = lzo1x_decompress_safe,
  };
  
  static struct ubifs_compressor zlib_compr = {
  	.compr_type = UBIFS_COMPR_ZLIB,
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
55
56
57
58
  #ifndef __UBOOT__
  	.comp_mutex = &deflate_mutex,
  	.decomp_mutex = &inflate_mutex,
  #endif
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
59
60
61
62
63
64
65
  	.name = "zlib",
  	.capi_name = "deflate",
  	.decompress = gzip_decompress,
  };
  
  /* All UBIFS compressors */
  struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  
  #ifdef __UBOOT__
  /* from mm/util.c */
  
  /**
   * kmemdup - duplicate region of memory
   *
   * @src: memory region to duplicate
   * @len: memory region length
   * @gfp: GFP mask to use
   */
  void *kmemdup(const void *src, size_t len, gfp_t gfp)
  {
  	void *p;
  
  	p = kmalloc(len, gfp);
  	if (p)
  		memcpy(p, src, len);
  	return p;
  }
  
  struct crypto_comp {
  	int compressor;
  };
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
90
91
  static inline struct crypto_comp
  *crypto_alloc_comp(const char *alg_name, u32 type, u32 mask)
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
92
93
94
95
  {
  	struct ubifs_compressor *comp;
  	struct crypto_comp *ptr;
  	int i = 0;
4519668b2   Marcel Ziswiler   mtd/nand/ubi: ass...
96
  	ptr = malloc_cache_aligned(sizeof(struct crypto_comp));
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
97
98
99
100
101
102
103
104
105
106
107
108
109
  	while (i < UBIFS_COMPR_TYPES_CNT) {
  		comp = ubifs_compressors[i];
  		if (!comp) {
  			i++;
  			continue;
  		}
  		if (strncmp(alg_name, comp->capi_name, strlen(alg_name)) == 0) {
  			ptr->compressor = i;
  			return ptr;
  		}
  		i++;
  	}
  	if (i >= UBIFS_COMPR_TYPES_CNT) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
110
  		dbg_gen("invalid compression type %s", alg_name);
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
111
112
113
114
115
  		free (ptr);
  		return NULL;
  	}
  	return ptr;
  }
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
116
117
118
119
  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)
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
120
121
122
  {
  	struct ubifs_compressor *compr = ubifs_compressors[tfm->compressor];
  	int err;
e4aa10ba5   Paul Davey   fs: ubifs: Fix UB...
123
  	size_t tmp_len = *dlen;
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
124
125
126
127
128
129
  
  	if (compr->compr_type == UBIFS_COMPR_NONE) {
  		memcpy(dst, src, slen);
  		*dlen = slen;
  		return 0;
  	}
e4aa10ba5   Paul Davey   fs: ubifs: Fix UB...
130
  	err = compr->decompress(src, slen, dst, &tmp_len);
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
131
  	if (err)
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
132
  		ubifs_err(c, "cannot decompress %d bytes, compressor %s, "
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
133
  			  "error %d", slen, compr->name, err);
e4aa10ba5   Paul Davey   fs: ubifs: Fix UB...
134
  	*dlen = tmp_len;
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
135
136
137
138
  	return err;
  
  	return 0;
  }
dc2884315   Anton Habegger   ubifs: Import ato...
139
140
141
142
143
  
  /* from shrinker.c */
  
  /* Global clean znode counter (for all mounted UBIFS instances) */
  atomic_long_t ubifs_clean_zn_cnt;
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
144
  #endif
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
145
146
147
148
149
150
151
152
153
154
155
156
  /**
   * ubifs_decompress - decompress data.
   * @in_buf: data to decompress
   * @in_len: length of the data to decompress
   * @out_buf: output buffer where decompressed data should
   * @out_len: output length is returned here
   * @compr_type: type of compression
   *
   * This function decompresses data from buffer @in_buf into buffer @out_buf.
   * The length of the uncompressed data is returned in @out_len. This functions
   * returns %0 on success or a negative error code on failure.
   */
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
157
158
  int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
  		     int in_len, void *out_buf, int *out_len, int compr_type)
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
159
160
161
162
163
  {
  	int err;
  	struct ubifs_compressor *compr;
  
  	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
164
  		ubifs_err(c, "invalid compression type %d", compr_type);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
165
166
167
168
169
170
  		return -EINVAL;
  	}
  
  	compr = ubifs_compressors[compr_type];
  
  	if (unlikely(!compr->capi_name)) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
171
  		ubifs_err(c, "%s compression is not compiled in", compr->name);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
172
173
174
175
176
177
178
179
  		return -EINVAL;
  	}
  
  	if (compr_type == UBIFS_COMPR_NONE) {
  		memcpy(out_buf, in_buf, in_len);
  		*out_len = in_len;
  		return 0;
  	}
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
180
181
  	if (compr->decomp_mutex)
  		mutex_lock(compr->decomp_mutex);
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
182
  	err = crypto_comp_decompress(c, compr->cc, in_buf, in_len, out_buf,
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
183
184
185
  				     (unsigned int *)out_len);
  	if (compr->decomp_mutex)
  		mutex_unlock(compr->decomp_mutex);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
186
  	if (err)
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
187
188
  		ubifs_err(c, "cannot decompress %d bytes, compressor %s,"
  			  " error %d", in_len, compr->name, err);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  
  	return err;
  }
  
  /**
   * compr_init - initialize a compressor.
   * @compr: compressor description object
   *
   * This function initializes the requested compressor and returns zero in case
   * of success or a negative error code in case of failure.
   */
  static int __init compr_init(struct ubifs_compressor *compr)
  {
  	ubifs_compressors[compr->compr_type] = compr;
521af04d8   Peter Tyser   Conditionally per...
203

2e5167cca   Wolfgang Denk   Replace CONFIG_RE...
204
  #ifdef CONFIG_NEEDS_MANUAL_RELOC
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
205
206
207
  	ubifs_compressors[compr->compr_type]->name += gd->reloc_off;
  	ubifs_compressors[compr->compr_type]->capi_name += gd->reloc_off;
  	ubifs_compressors[compr->compr_type]->decompress += gd->reloc_off;
521af04d8   Peter Tyser   Conditionally per...
208
  #endif
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
209
210
211
  	if (compr->capi_name) {
  		compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
  		if (IS_ERR(compr->cc)) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
212
213
214
  			dbg_gen("cannot initialize compressor %s,"
  				  " error %ld", compr->name,
  				  PTR_ERR(compr->cc));
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
215
216
217
  			return PTR_ERR(compr->cc);
  		}
  	}
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  	return 0;
  }
  
  /**
   * ubifs_compressors_init - initialize UBIFS compressors.
   *
   * This function initializes the compressor which were compiled in. Returns
   * zero in case of success and a negative error code in case of failure.
   */
  int __init ubifs_compressors_init(void)
  {
  	int err;
  
  	err = compr_init(&lzo_compr);
  	if (err)
  		return err;
  
  	err = compr_init(&zlib_compr);
  	if (err)
  		return err;
faac4fd85   Michael Lawnick   UBIFS: Missing of...
238
239
240
  	err = compr_init(&none_compr);
  	if (err)
  		return err;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  	return 0;
  }
  
  /*
   * ubifsls...
   */
  
  static int filldir(struct ubifs_info *c, const char *name, int namlen,
  		   u64 ino, unsigned int d_type)
  {
  	struct inode *inode;
  	char filetime[32];
  
  	switch (d_type) {
  	case UBIFS_ITYPE_REG:
  		printf("\t");
  		break;
  	case UBIFS_ITYPE_DIR:
  		printf("<DIR>\t");
  		break;
  	case UBIFS_ITYPE_LNK:
  		printf("<LNK>\t");
  		break;
  	default:
  		printf("other\t");
  		break;
  	}
  
  	inode = ubifs_iget(c->vfs_sb, ino);
  	if (IS_ERR(inode)) {
  		printf("%s: Error in ubifs_iget(), ino=%lld ret=%p!
  ",
  		       __func__, ino, inode);
  		return -1;
  	}
  	ctime_r((time_t *)&inode->i_mtime, filetime);
  	printf("%9lld  %24.24s  ", inode->i_size, filetime);
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
278
  #ifndef __UBOOT__
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
279
  	ubifs_iput(inode);
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
280
  #endif
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  
  	printf("%s
  ", name);
  
  	return 0;
  }
  
  static int ubifs_printdir(struct file *file, void *dirent)
  {
  	int err, over = 0;
  	struct qstr nm;
  	union ubifs_key key;
  	struct ubifs_dent_node *dent;
  	struct inode *dir = file->f_path.dentry->d_inode;
  	struct ubifs_info *c = dir->i_sb->s_fs_info;
  
  	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
  
  	if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
  		/*
  		 * The directory was seek'ed to a senseless position or there
  		 * are no more entries.
  		 */
  		return 0;
  
  	if (file->f_pos == 1) {
  		/* Find the first entry in TNC and save it */
  		lowest_dent_key(c, &key, dir->i_ino);
  		nm.name = NULL;
  		dent = ubifs_tnc_next_ent(c, &key, &nm);
  		if (IS_ERR(dent)) {
  			err = PTR_ERR(dent);
  			goto out;
  		}
  
  		file->f_pos = key_hash_flash(c, &dent->key);
  		file->private_data = dent;
  	}
  
  	dent = file->private_data;
  	if (!dent) {
  		/*
  		 * The directory was seek'ed to and is now readdir'ed.
  		 * Find the entry corresponding to @file->f_pos or the
  		 * closest one.
  		 */
  		dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
  		nm.name = NULL;
  		dent = ubifs_tnc_next_ent(c, &key, &nm);
  		if (IS_ERR(dent)) {
  			err = PTR_ERR(dent);
  			goto out;
  		}
  		file->f_pos = key_hash_flash(c, &dent->key);
  		file->private_data = dent;
  	}
  
  	while (1) {
  		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
  			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
  			key_hash_flash(c, &dent->key));
87deefecc   Patrice Chotard   ubifs: avoid asse...
342
  #ifndef __UBOOT__
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
343
  		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
87deefecc   Patrice Chotard   ubifs: avoid asse...
344
  #endif
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  
  		nm.len = le16_to_cpu(dent->nlen);
  		over = filldir(c, (char *)dent->name, nm.len,
  			       le64_to_cpu(dent->inum), dent->type);
  		if (over)
  			return 0;
  
  		/* Switch to the next entry */
  		key_read(c, &dent->key, &key);
  		nm.name = (char *)dent->name;
  		dent = ubifs_tnc_next_ent(c, &key, &nm);
  		if (IS_ERR(dent)) {
  			err = PTR_ERR(dent);
  			goto out;
  		}
  
  		kfree(file->private_data);
  		file->f_pos = key_hash_flash(c, &dent->key);
  		file->private_data = dent;
  		cond_resched();
  	}
  
  out:
  	if (err != -ENOENT) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
369
  		ubifs_err(c, "cannot find next direntry, error %d", err);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  		return err;
  	}
  
  	kfree(file->private_data);
  	file->private_data = NULL;
  	file->f_pos = 2;
  	return 0;
  }
  
  static int ubifs_finddir(struct super_block *sb, char *dirname,
  			 unsigned long root_inum, unsigned long *inum)
  {
  	int err;
  	struct qstr nm;
  	union ubifs_key key;
  	struct ubifs_dent_node *dent;
  	struct ubifs_info *c;
  	struct file *file;
  	struct dentry *dentry;
  	struct inode *dir;
be73913b9   Stefan Roese   ubifs: Fix memory...
390
  	int ret = 0;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  
  	file = kzalloc(sizeof(struct file), 0);
  	dentry = kzalloc(sizeof(struct dentry), 0);
  	dir = kzalloc(sizeof(struct inode), 0);
  	if (!file || !dentry || !dir) {
  		printf("%s: Error, no memory for malloc!
  ", __func__);
  		err = -ENOMEM;
  		goto out;
  	}
  
  	dir->i_sb = sb;
  	file->f_path.dentry = dentry;
  	file->f_path.dentry->d_parent = dentry;
  	file->f_path.dentry->d_inode = dir;
  	file->f_path.dentry->d_inode->i_ino = root_inum;
  	c = sb->s_fs_info;
  
  	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
  
  	/* Find the first entry in TNC and save it */
  	lowest_dent_key(c, &key, dir->i_ino);
  	nm.name = NULL;
  	dent = ubifs_tnc_next_ent(c, &key, &nm);
  	if (IS_ERR(dent)) {
  		err = PTR_ERR(dent);
  		goto out;
  	}
  
  	file->f_pos = key_hash_flash(c, &dent->key);
  	file->private_data = dent;
  
  	while (1) {
  		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
  			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
  			key_hash_flash(c, &dent->key));
87deefecc   Patrice Chotard   ubifs: avoid asse...
427
  #ifndef __UBOOT__
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
428
  		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
87deefecc   Patrice Chotard   ubifs: avoid asse...
429
  #endif
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
430
431
432
433
434
  
  		nm.len = le16_to_cpu(dent->nlen);
  		if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) &&
  		    (strlen(dirname) == nm.len)) {
  			*inum = le64_to_cpu(dent->inum);
be73913b9   Stefan Roese   ubifs: Fix memory...
435
436
  			ret = 1;
  			goto out_free;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
  		}
  
  		/* Switch to the next entry */
  		key_read(c, &dent->key, &key);
  		nm.name = (char *)dent->name;
  		dent = ubifs_tnc_next_ent(c, &key, &nm);
  		if (IS_ERR(dent)) {
  			err = PTR_ERR(dent);
  			goto out;
  		}
  
  		kfree(file->private_data);
  		file->f_pos = key_hash_flash(c, &dent->key);
  		file->private_data = dent;
  		cond_resched();
  	}
  
  out:
be73913b9   Stefan Roese   ubifs: Fix memory...
455
  	if (err != -ENOENT)
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
456
  		dbg_gen("cannot find next direntry, error %d", err);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
457

be73913b9   Stefan Roese   ubifs: Fix memory...
458
  out_free:
4b29975fd   Heinrich Schuchardt   ubifs: no NULL ch...
459
460
461
462
  	kfree(file->private_data);
  	free(file);
  	free(dentry);
  	free(dir);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
463

be73913b9   Stefan Roese   ubifs: Fix memory...
464
  	return ret;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
465
466
467
468
469
470
471
  }
  
  static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
  {
  	int ret;
  	char *next;
  	char fpath[128];
9d7952e4c   Simon Kagstrom   ubifs: Add suppor...
472
  	char symlinkpath[128];
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
473
474
475
  	char *name = fpath;
  	unsigned long root_inum = 1;
  	unsigned long inum;
9d7952e4c   Simon Kagstrom   ubifs: Add suppor...
476
  	int symlink_count = 0; /* Don't allow symlink recursion */
64b681784   Ricardo Ribalda Delgado   ubifs.c: BUG: Err...
477
  	char link_name[64];
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  
  	strcpy(fpath, filename);
  
  	/* Remove all leading slashes */
  	while (*name == '/')
  		name++;
  
  	/*
  	 * Handle root-direcoty ('/')
  	 */
  	inum = root_inum;
  	if (!name || *name == '\0')
  		return inum;
  
  	for (;;) {
9d7952e4c   Simon Kagstrom   ubifs: Add suppor...
493
494
  		struct inode *inode;
  		struct ubifs_inode *ui;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
495
496
497
498
499
500
501
502
503
  		/* Extract the actual part from the pathname.  */
  		next = strchr(name, '/');
  		if (next) {
  			/* Remove all leading slashes.  */
  			while (*next == '/')
  				*(next++) = '\0';
  		}
  
  		ret = ubifs_finddir(sb, name, root_inum, &inum);
9d7952e4c   Simon Kagstrom   ubifs: Add suppor...
504
505
506
507
508
509
510
511
512
  		if (!ret)
  			return 0;
  		inode = ubifs_iget(sb, inum);
  
  		if (!inode)
  			return 0;
  		ui = ubifs_inode(inode);
  
  		if ((inode->i_mode & S_IFMT) == S_IFLNK) {
9d7952e4c   Simon Kagstrom   ubifs: Add suppor...
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  			char buf[128];
  
  			/* We have some sort of symlink recursion, bail out */
  			if (symlink_count++ > 8) {
  				printf("Symlink recursion, aborting
  ");
  				return 0;
  			}
  			memcpy(link_name, ui->data, ui->data_len);
  			link_name[ui->data_len] = '\0';
  
  			if (link_name[0] == '/') {
  				/* Absolute path, redo everything without
  				 * the leading slash */
  				next = name = link_name + 1;
  				root_inum = 1;
  				continue;
  			}
  			/* Relative to cur dir */
ef37c6835   Simon Kagstrom   ubifs: Correct de...
532
  			sprintf(buf, "%s/%s",
9d7952e4c   Simon Kagstrom   ubifs: Add suppor...
533
534
535
536
537
  					link_name, next == NULL ? "" : next);
  			memcpy(symlinkpath, buf, sizeof(buf));
  			next = name = symlinkpath;
  			continue;
  		}
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
538
539
540
541
542
543
  
  		/*
  		 * Check if directory with this name exists
  		 */
  
  		/* Found the node!  */
9d7952e4c   Simon Kagstrom   ubifs: Add suppor...
544
545
  		if (!next || *next == '\0')
  			return inum;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
546
547
548
549
550
551
552
  
  		root_inum = inum;
  		name = next;
  	}
  
  	return 0;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
553
  int ubifs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info)
29cc5bcad   Hans de Goede   ubifs: Add functi...
554
555
556
557
558
559
560
561
  {
  	if (rbdd) {
  		debug("UBIFS cannot be used with normal block devices
  ");
  		return -1;
  	}
  
  	/*
e35929e4a   Simon Glass   dm: blk: Rename g...
562
  	 * Should never happen since blk_get_device_part_str() already checks
29cc5bcad   Hans de Goede   ubifs: Add functi...
563
564
565
566
567
568
569
570
571
572
  	 * this, but better safe then sorry.
  	 */
  	if (!ubifs_is_mounted()) {
  		debug("UBIFS not mounted, use ubifsmount to mount volume first!
  ");
  		return -1;
  	}
  
  	return 0;
  }
ad15749b6   Hans de Goede   ubifs: Modify ubi...
573
  int ubifs_ls(const char *filename)
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
574
575
576
577
578
579
580
581
582
583
  {
  	struct ubifs_info *c = ubifs_sb->s_fs_info;
  	struct file *file;
  	struct dentry *dentry;
  	struct inode *dir;
  	void *dirent = NULL;
  	unsigned long inum;
  	int ret = 0;
  
  	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
ad15749b6   Hans de Goede   ubifs: Modify ubi...
584
  	inum = ubifs_findfile(ubifs_sb, (char *)filename);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  	if (!inum) {
  		ret = -1;
  		goto out;
  	}
  
  	file = kzalloc(sizeof(struct file), 0);
  	dentry = kzalloc(sizeof(struct dentry), 0);
  	dir = kzalloc(sizeof(struct inode), 0);
  	if (!file || !dentry || !dir) {
  		printf("%s: Error, no memory for malloc!
  ", __func__);
  		ret = -ENOMEM;
  		goto out_mem;
  	}
  
  	dir->i_sb = ubifs_sb;
  	file->f_path.dentry = dentry;
  	file->f_path.dentry->d_parent = dentry;
  	file->f_path.dentry->d_inode = dir;
  	file->f_path.dentry->d_inode->i_ino = inum;
  	file->f_pos = 1;
  	file->private_data = NULL;
  	ubifs_printdir(file, dirent);
  
  out_mem:
  	if (file)
  		free(file);
  	if (dentry)
  		free(dentry);
  	if (dir)
  		free(dir);
  
  out:
  	ubi_close_volume(c->ubi);
  	return ret;
  }
29cc5bcad   Hans de Goede   ubifs: Add functi...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  int ubifs_exists(const char *filename)
  {
  	struct ubifs_info *c = ubifs_sb->s_fs_info;
  	unsigned long inum;
  
  	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
  	inum = ubifs_findfile(ubifs_sb, (char *)filename);
  	ubi_close_volume(c->ubi);
  
  	return inum != 0;
  }
  
  int ubifs_size(const char *filename, loff_t *size)
  {
  	struct ubifs_info *c = ubifs_sb->s_fs_info;
  	unsigned long inum;
  	struct inode *inode;
  	int err = 0;
  
  	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
  
  	inum = ubifs_findfile(ubifs_sb, (char *)filename);
  	if (!inum) {
  		err = -1;
  		goto out;
  	}
  
  	inode = ubifs_iget(ubifs_sb, inum);
  	if (IS_ERR(inode)) {
  		printf("%s: Error reading inode %ld!
  ", __func__, inum);
  		err = PTR_ERR(inode);
  		goto out;
  	}
  
  	*size = inode->i_size;
  
  	ubifs_iput(inode);
  out:
  	ubi_close_volume(c->ubi);
  	return err;
  }
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  /*
   * ubifsload...
   */
  
  /* file.c */
  
  static inline void *kmap(struct page *page)
  {
  	return page->addr;
  }
  
  static int read_block(struct inode *inode, void *addr, unsigned int block,
  		      struct ubifs_data_node *dn)
  {
  	struct ubifs_info *c = inode->i_sb->s_fs_info;
  	int err, len, out_len;
  	union ubifs_key key;
  	unsigned int dlen;
  
  	data_key_init(c, &key, inode->i_ino, block);
  	err = ubifs_tnc_lookup(c, &key, dn);
  	if (err) {
  		if (err == -ENOENT)
  			/* Not found, so it must be a hole */
  			memset(addr, 0, UBIFS_BLOCK_SIZE);
  		return err;
  	}
  
  	ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
  
  	len = le32_to_cpu(dn->size);
  	if (len <= 0 || len > UBIFS_BLOCK_SIZE)
  		goto dump;
  
  	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
  	out_len = UBIFS_BLOCK_SIZE;
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
699
  	err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
  			       le16_to_cpu(dn->compr_type));
  	if (err || len != out_len)
  		goto dump;
  
  	/*
  	 * Data length can be less than a full block, even for blocks that are
  	 * not the last in the file (e.g., as a result of making a hole and
  	 * appending data). Ensure that the remainder is zeroed out.
  	 */
  	if (len < UBIFS_BLOCK_SIZE)
  		memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
  
  	return 0;
  
  dump:
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
715
  	ubifs_err(c, "bad data node (block %u, inode %lu)",
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
716
  		  block, inode->i_ino);
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
717
  	ubifs_dump_node(c, dn);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
718
719
  	return -EINVAL;
  }
b1a14f8a1   Stefan Roese   UBIFS: Change ubi...
720
721
  static int do_readpage(struct ubifs_info *c, struct inode *inode,
  		       struct page *page, int last_block_size)
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
  {
  	void *addr;
  	int err = 0, i;
  	unsigned int block, beyond;
  	struct ubifs_data_node *dn;
  	loff_t i_size = inode->i_size;
  
  	dbg_gen("ino %lu, pg %lu, i_size %lld",
  		inode->i_ino, page->index, i_size);
  
  	addr = kmap(page);
  
  	block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
  	beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
  	if (block >= beyond) {
  		/* Reading beyond inode */
  		memset(addr, 0, PAGE_CACHE_SIZE);
  		goto out;
  	}
  
  	dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
165f9859b   Daniel Mack   ubifs: fix small ...
743
744
  	if (!dn)
  		return -ENOMEM;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
745
746
747
748
749
750
751
752
753
754
  
  	i = 0;
  	while (1) {
  		int ret;
  
  		if (block >= beyond) {
  			/* Reading beyond inode */
  			err = -ENOENT;
  			memset(addr, 0, UBIFS_BLOCK_SIZE);
  		} else {
b1a14f8a1   Stefan Roese   UBIFS: Change ubi...
755
756
757
758
759
760
761
762
763
764
765
766
767
768
  			/*
  			 * Reading last block? Make sure to not write beyond
  			 * the requested size in the destination buffer.
  			 */
  			if (((block + 1) == beyond) || last_block_size) {
  				void *buff;
  				int dlen;
  
  				/*
  				 * We need to buffer the data locally for the
  				 * last block. This is to not pad the
  				 * destination area to a multiple of
  				 * UBIFS_BLOCK_SIZE.
  				 */
4519668b2   Marcel Ziswiler   mtd/nand/ubi: ass...
769
  				buff = malloc_cache_aligned(UBIFS_BLOCK_SIZE);
b1a14f8a1   Stefan Roese   UBIFS: Change ubi...
770
771
772
773
774
  				if (!buff) {
  					printf("%s: Error, malloc fails!
  ",
  					       __func__);
  					err = -ENOMEM;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
775
  					break;
b1a14f8a1   Stefan Roese   UBIFS: Change ubi...
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  				}
  
  				/* Read block-size into temp buffer */
  				ret = read_block(inode, buff, block, dn);
  				if (ret) {
  					err = ret;
  					if (err != -ENOENT) {
  						free(buff);
  						break;
  					}
  				}
  
  				if (last_block_size)
  					dlen = last_block_size;
  				else
  					dlen = le32_to_cpu(dn->size);
  
  				/* Now copy required size back to dest */
  				memcpy(addr, buff, dlen);
  
  				free(buff);
  			} else {
  				ret = read_block(inode, addr, block, dn);
  				if (ret) {
  					err = ret;
  					if (err != -ENOENT)
  						break;
  				}
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
804
805
806
807
808
809
810
811
812
813
814
815
816
  			}
  		}
  		if (++i >= UBIFS_BLOCKS_PER_PAGE)
  			break;
  		block += 1;
  		addr += UBIFS_BLOCK_SIZE;
  	}
  	if (err) {
  		if (err == -ENOENT) {
  			/* Not found, so it must be a hole */
  			dbg_gen("hole");
  			goto out_free;
  		}
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
817
  		ubifs_err(c, "cannot read page %lu of inode %lu, error %d",
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
818
819
820
821
822
823
824
825
826
827
828
829
830
  			  page->index, inode->i_ino, err);
  		goto error;
  	}
  
  out_free:
  	kfree(dn);
  out:
  	return 0;
  
  error:
  	kfree(dn);
  	return err;
  }
ad15749b6   Hans de Goede   ubifs: Modify ubi...
831
832
  int ubifs_read(const char *filename, void *buf, loff_t offset,
  	       loff_t size, loff_t *actread)
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
833
834
835
836
837
838
839
840
  {
  	struct ubifs_info *c = ubifs_sb->s_fs_info;
  	unsigned long inum;
  	struct inode *inode;
  	struct page page;
  	int err = 0;
  	int i;
  	int count;
b1a14f8a1   Stefan Roese   UBIFS: Change ubi...
841
  	int last_block_size = 0;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
842

ad15749b6   Hans de Goede   ubifs: Modify ubi...
843
844
845
  	*actread = 0;
  
  	if (offset & (PAGE_SIZE - 1)) {
1381901e9   Vagrant Cascadian   Fix spelling of "...
846
847
  		printf("ubifs: Error offset must be a multiple of %d
  ",
ad15749b6   Hans de Goede   ubifs: Modify ubi...
848
849
850
  		       PAGE_SIZE);
  		return -1;
  	}
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
851
  	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
9d7952e4c   Simon Kagstrom   ubifs: Add suppor...
852
853
  	/* ubifs_findfile will resolve symlinks, so we know that we get
  	 * the real file here */
ad15749b6   Hans de Goede   ubifs: Modify ubi...
854
  	inum = ubifs_findfile(ubifs_sb, (char *)filename);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
  	if (!inum) {
  		err = -1;
  		goto out;
  	}
  
  	/*
  	 * Read file inode
  	 */
  	inode = ubifs_iget(ubifs_sb, inum);
  	if (IS_ERR(inode)) {
  		printf("%s: Error reading inode %ld!
  ", __func__, inum);
  		err = PTR_ERR(inode);
  		goto out;
  	}
ad15749b6   Hans de Goede   ubifs: Modify ubi...
870
871
872
873
874
875
876
  	if (offset > inode->i_size) {
  		printf("ubifs: Error offset (%lld) > file-size (%lld)
  ",
  		       offset, size);
  		err = -1;
  		goto put_inode;
  	}
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
877
  	/*
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
878
879
880
  	 * If no size was specified or if size bigger than filesize
  	 * set size to filesize
  	 */
ad15749b6   Hans de Goede   ubifs: Modify ubi...
881
882
  	if ((size == 0) || (size > (inode->i_size - offset)))
  		size = inode->i_size - offset;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
883
884
  
  	count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
885

ad15749b6   Hans de Goede   ubifs: Modify ubi...
886
887
  	page.addr = buf;
  	page.index = offset / PAGE_SIZE;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
888
889
  	page.inode = inode;
  	for (i = 0; i < count; i++) {
b1a14f8a1   Stefan Roese   UBIFS: Change ubi...
890
891
892
893
894
895
896
  		/*
  		 * Make sure to not read beyond the requested size
  		 */
  		if (((i + 1) == count) && (size < inode->i_size))
  			last_block_size = size - (i * PAGE_SIZE);
  
  		err = do_readpage(c, inode, &page, last_block_size);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
897
898
899
900
901
902
  		if (err)
  			break;
  
  		page.addr += PAGE_SIZE;
  		page.index++;
  	}
ad15749b6   Hans de Goede   ubifs: Modify ubi...
903
  	if (err) {
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
904
905
  		printf("Error reading file '%s'
  ", filename);
ad15749b6   Hans de Goede   ubifs: Modify ubi...
906
907
908
  		*actread = i * PAGE_SIZE;
  	} else {
  		*actread = size;
46d7274cd   Bastian Ruppert   UBIFS: Change ubi...
909
  	}
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
910

ad15749b6   Hans de Goede   ubifs: Modify ubi...
911
  put_inode:
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
912
913
914
915
916
917
  	ubifs_iput(inode);
  
  out:
  	ubi_close_volume(c->ubi);
  	return err;
  }
ad15749b6   Hans de Goede   ubifs: Modify ubi...
918

29cc5bcad   Hans de Goede   ubifs: Add functi...
919
920
921
  void ubifs_close(void)
  {
  }
ad15749b6   Hans de Goede   ubifs: Modify ubi...
922
923
924
925
926
927
928
929
  /* Compat wrappers for common/cmd_ubifs.c */
  int ubifs_load(char *filename, u32 addr, u32 size)
  {
  	loff_t actread;
  	int err;
  
  	printf("Loading file '%s' to addr 0x%08x...
  ", filename, addr);
34cc30af2   Siva Durga Prasad Paladugu   fs: usbifs: Fix w...
930
  	err = ubifs_read(filename, (void *)(uintptr_t)addr, 0, size, &actread);
ad15749b6   Hans de Goede   ubifs: Modify ubi...
931
  	if (err == 0) {
018f53032   Simon Glass   env: Rename commo...
932
  		env_set_hex("filesize", actread);
ad15749b6   Hans de Goede   ubifs: Modify ubi...
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
  		printf("Done
  ");
  	}
  
  	return err;
  }
  
  void uboot_ubifs_umount(void)
  {
  	if (ubifs_sb) {
  		printf("Unmounting UBIFS volume %s!
  ",
  		       ((struct ubifs_info *)(ubifs_sb->s_fs_info))->vi.name);
  		ubifs_umount(ubifs_sb->s_fs_info);
  		ubifs_sb = NULL;
  	}
  }