• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * JFFS2 -- Journalling Flash File System, Version 2.
3  *
4  * Copyright (C) 2001-2003 Free Software Foundation, Inc.
5  *
6  * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com>
7  * Contributors: David Woodhouse, Nick Garnett, Richard Panton.
8  *
9  * For licensing information, see the file 'LICENCE' in this directory.
10  *
11  * $Id: fs-ecos.c,v 1.44 2005/07/24 15:29:57 dedekind Exp $
12  *
13  */
14 
15 #include <stdio.h>    //prife for SEEK_SET SEEK_CUR SEEK_END
16 #include <linux/kernel.h>
17 #include <string.h>
18 #include <linux/pagemap.h>
19 #include <linux/semaphore.h>
20 #include <linux/delay.h>
21 #include "mtd_list.h"
22 #include "jffs2/nodelist.h"
23 #include "los_crc32.h"
24 #include "jffs2/compr.h"
25 #include "port/fcntl.h"
26 #include "porting.h"
27 #include "limits.h"
28 #include "los_process_pri.h"
29 #include "capability_type.h"
30 #include "capability_api.h"
31 #include "mtd_partition.h"
32 #include "vfs_jffs2.h"
33 
34 // Filesystem operations
35 static int jffs2_mount(cyg_mtab_entry *mte, int partition_num);
36 static int jffs2_umount(cyg_mtab_entry *mte);
37 static int jffs2_open (cyg_mtab_entry *mte, const char *name, int flags,
38                     int mode,  cyg_file *fte);
39 static int jffs2_ops_unlink(cyg_mtab_entry *mte, const char *name);
40 static int jffs2_ops_mkdir(cyg_mtab_entry *mte, const char *name, int mode);
41 static int jffs2_ops_rmdir(cyg_mtab_entry *mte, const char *name);
42 static int jffs2_ops_rename(cyg_mtab_entry *mte, const char *name1, const char *name2);
43 static int jffs2_opendir(cyg_mtab_entry *mte, const char *name, cyg_file *fte);
44 static int jffs2_stat(cyg_mtab_entry *mte, const char *name, struct jffs2_stat *buf);
45 static int jffs2_fo_chattr(cyg_mtab_entry *mte, const char *name, iattr *attr);
46 
47 // File operations
48 static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
49 static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
50 static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence);
51 static int jffs2_fo_close(struct CYG_FILE_TAG *fp);
52 
53 // Directory operations
54 static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
55 static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence);
56 
57 static int jffs2_read_inode (struct _inode *inode);
58 static void jffs2_clear_inode (struct _inode *inode);
59 static int jffs2_truncate_file (struct _inode *inode);
60 static int jffsfs_IsPathDivider(char ch);
61 static int jffs_check_path(const char *path);
62 static unsigned int CheckPermission(struct _inode *node, int accMode);
63 int jffs2_chattr (struct _inode *dir_i, const unsigned char *d_name, iattr *attr, struct _inode *node_old);
64 
65 
66 struct MtdNorDev jffs_part[CONFIG_MTD_PATTITION_NUM];
67 //==========================================================================
68 // STATIC VARIABLES !!!
69 
70 static unsigned char gc_buffer[PAGE_CACHE_SIZE];	//avoids malloc when user may be under memory pressure
71 static unsigned char n_fs_mounted = 0;  // a counter to track the number of jffs2 instances mounted
72 
73 #define JFFS_PATH_DIVIDERS  "/"
74 //==========================================================================
75 // Directory operations
76 
77 struct jffs2_dirsearch {
78 	struct _inode *dir;    // directory to search
79 	const unsigned char *path;  // path to follow
80 	struct _inode *node;        // Node found
81 	const unsigned char *name;  // last name fragment used
82 	int namelen;            // name fragment length
83 	int last;            // last name in path?
84 	int accMode;            // access mode
85 };
86 
87 typedef struct jffs2_dirsearch jffs2_dirsearch;
88 
89 //==========================================================================
90 // Ref count and nlink management
91 
92 // FIXME: This seems like real cruft. Wouldn't it be better just to do the
93 // right thing?
icache_evict(struct _inode * root_i,struct _inode * i)94 static void icache_evict(struct _inode *root_i, struct _inode *i)
95 {
96 	struct _inode *this = root_i;
97 	struct _inode *next = NULL;
98 	struct _inode *temp = NULL;
99 	struct jffs2_inode_info *f = NULL;
100 	jffs_lock();
101  restart:
102 	D2(PRINTK("icache_evict\n"));
103 	// If this is an absolute search path from the root,
104 	// remove all cached inodes with i_count of zero (these are only
105 	// held where needed for dotdot filepaths)
106 
107 	while (this) {
108 		next = this->i_cache_next;
109 		if (this != i && this->i_count == 0) {
110 			struct _inode *parent = this->i_parent;
111 
112 			if (this->i_cache_next)
113 				this->i_cache_next->i_cache_prev = this->i_cache_prev;
114 			if (this->i_cache_prev)
115 				this->i_cache_prev->i_cache_next = this->i_cache_next;
116 			jffs2_clear_inode(this);
117 			f = JFFS2_INODE_INFO(this);
118 			(void)mutex_destroy(&(f->sem));
119 			(void)memset_s(this, sizeof(*this), 0x5a, sizeof(*this));
120 			temp = this;
121 			free(this);
122 			if (parent && parent != temp) {
123 				parent->i_count--;
124 				this = root_i;
125 				goto restart;
126 			}
127 		}
128 		this = next;
129 	}
130 	jffs_unlock();
131 }
132 
133 //==========================================================================
134 // Directory search
135 
136 // -------------------------------------------------------------------------
137 // init_dirsearch()
138 // Initialize a dirsearch object to start a search
139 
init_dirsearch(jffs2_dirsearch * ds,struct _inode * dir,const unsigned char * name,int flags)140 void init_dirsearch(jffs2_dirsearch * ds,
141 	struct _inode *dir, const unsigned char *name,  int flags)
142 {
143 	D2(PRINTK("init_dirsearch name = %s\n", name));
144 	D2(PRINTK("init_dirsearch dir = %x\n", dir));
145 
146 	dir->i_count++;
147 	ds->dir = dir;
148 	ds->path = name;
149 	ds->node = dir;
150 	ds->name = name;
151 	ds->namelen = 0;
152 	ds->last = false;
153 	ds->accMode = flags;
154 }
155 
156 // -------------------------------------------------------------------------
157 // find_entry()
158 // Search a single directory for the next name in a path and update the
159 // dirsearch object appropriately.
160 
find_entry(jffs2_dirsearch * ds)161 static int find_entry(jffs2_dirsearch * ds)
162 {
163 	struct _inode *dir = ds->dir;
164 	const unsigned char *name = ds->path;
165 	const unsigned char *n = name;
166 	int namelen = 0;
167 	struct _inode *d;
168 	int accMode = 0;
169 
170 	// Isolate the next element of the path name.
171 	while (*n != '\0' && *n != '/') {
172 		n++;
173 		namelen++;
174 	}
175 
176 	// Check if this is the last path element.
177 	while( *n == '/') n++;
178 	if (*n == '\0')
179 		ds->last = true;
180 
181 	// update name in dirsearch object
182 	ds->name = name;
183 	ds->namelen = namelen;
184 	if (name[0] == '.')
185 		switch (namelen) {
186 		default:
187 			break;
188 		case 2:
189 			// Dot followed by not Dot, treat as any other name
190 			if (name[1] != '.')
191 				break;
192 			// Dot Dot
193 			// Move back up the search path
194 			ds->dir = ds->node;
195 			ds->node = ds->dir->i_parent;
196 			ds->node->i_count++;
197 			return ENOERR;
198 		case 1:
199 			// Dot is consumed
200 			ds->node = ds->dir;
201 			ds->dir->i_count++;
202 			return ENOERR;
203 		}
204 
205 	// Here we have the name and its length set up.
206 	// Search the directory for a matching entry
207 	d = jffs2_lookup(dir, name, namelen);
208 
209 	if (d == NULL) {
210 		return ENOENT;
211 	}
212 	if (IS_ERR(d)) {
213 		return -(int)(PTR_ERR(d));}
214 
215 	// If it's a new directory inode, increase refcount on its parent
216 	if (S_ISDIR(d->i_mode) && !d->i_parent) {
217 		d->i_parent = dir;
218 		dir->i_count++;
219 	}
220 
221 	accMode = (ds->last) ? ds->accMode : EXEC_OP;
222 
223 	if (CheckPermission(d, accMode)) {
224 		jffs2_iput(d);
225 		return EACCES;
226 	}
227 
228 	// pass back the node we have found
229 	ds->node = d;
230 	return ENOERR;
231 }
232 
233 // -------------------------------------------------------------------------
234 // jffs2_find()
235 // Main interface to directory search code. This is used in all file
236 // level operations to locate the object named by the pathname.
237 
238 // Returns with use count incremented on both the sought object and
239 // the directory it was found in
jffs2_find(jffs2_dirsearch * d)240 static int jffs2_find(jffs2_dirsearch * d)
241 {
242 	int err;
243 
244 	D2(PRINTK("jffs2_find for path =%s\n", d->path));
245 	// Short circuit empty paths
246 	if (*(d->path) == '\0') {
247 		d->node->i_count++;
248 		return ENOERR;
249 	}
250 
251 	// iterate down directory tree until we find the object
252 	// we want.
253 	for (;;) {
254 		// check that we really have a directory
255 		if (!S_ISDIR(d->dir->i_mode)) {
256 			return ENOTDIR;
257 		}
258 
259 		err = find_entry(d);
260 		if (err != ENOERR) {
261 			return err;
262 		}
263 		if (d->last)
264 			return ENOERR;
265 
266 		/* We're done with it, although it we found a subdir that
267 		   will have caused the refcount to have been increased */
268 		jffs2_iput(d->dir);
269 
270 		// Update dirsearch object to search next directory.
271 		d->dir = d->node;
272 		d->path += d->namelen;
273 		while (*(d->path) == '/')
274 			d->path++;    // skip dirname separators
275 	}
276 }
277 
278 
279 //==========================================================================
280 // Filesystem operations
281 // -------------------------------------------------------------------------
282 // jffs2_mount()
283 // Process a mount request. This mainly creates a root for the
284 // filesystem.
jffs2_read_super(struct super_block * sb)285 static int jffs2_read_super(struct super_block *sb)
286 {
287 	int err;
288 	struct jffs2_sb_info *c;
289 	struct MtdNorDev *device;
290 
291 	c = JFFS2_SB_INFO(sb);
292 	device = (struct MtdNorDev*)(sb->s_dev);
293 
294 	/* initialize mutex lock */
295 	(void)mutex_init(&c->alloc_sem);
296 	(void)mutex_init(&c->erase_free_sem);
297 	spin_lock_init(&c->erase_completion_lock);
298 	spin_lock_init(&c->inocache_lock);
299 
300 	/* sector size is the erase block size */
301 	c->sector_size = device->blockSize;
302 	c->flash_size  = (device->blockEnd - device->blockStart + 1) * device->blockSize;
303 	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
304 	err = jffs2_do_mount_fs(c);
305 
306 	if (err) {
307 		(void)mutex_destroy(&c->alloc_sem);
308 		(void)mutex_destroy(&c->erase_free_sem);
309 		return -err;
310 	}
311 	D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
312 
313 	sb->s_root = jffs2_iget(sb, 1);
314 
315 	if (IS_ERR(sb->s_root)) {
316 		D1(printk(KERN_WARNING "get root inode failed\n"));
317 		err = PTR_ERR(sb->s_root);
318 		sb->s_root = NULL;
319 		goto out_nodes;
320 	}
321 	return 0;
322 
323 out_nodes:
324 	jffs2_free_ino_caches(c);
325 	jffs2_free_raw_node_refs(c);
326 	free(c->blocks);
327 	(void)mutex_destroy(&c->alloc_sem);
328 	(void)mutex_destroy(&c->erase_free_sem);
329 
330 	return err;
331 }
332 
jffs2_mount(cyg_mtab_entry * mte,int partition_num)333 static int jffs2_mount(cyg_mtab_entry *mte, int partition_num)
334 {
335 	struct super_block *jffs2_sb = NULL;
336 	struct jffs2_sb_info *c = NULL;
337 	mtd_partition *current_node = GetSpinorPartitionHead();
338 	LOS_DL_LIST *patition_head = NULL;
339 	int err;
340 	struct MtdDev *spinor_mtd = NULL;
341 
342 	jffs2_dbg(1, "begin los_jffs2_mount:%d\n", partition_num);
343 
344 	jffs2_sb = malloc(sizeof (struct super_block));
345 
346 	if (jffs2_sb == NULL) {
347 		return ENOMEM;
348 	}
349 	c = JFFS2_SB_INFO(jffs2_sb);
350 	(void)memset_s(jffs2_sb, sizeof (struct super_block), 0, sizeof (struct super_block));
351 	patition_head = &(GetSpinorPartitionHead()->node_info);
352 	LOS_DL_LIST_FOR_EACH_ENTRY(current_node,patition_head, mtd_partition, node_info) {
353 		if (current_node->patitionnum == partition_num)
354 			break;
355 	}
356 #ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
357 	spinor_mtd = GetMtd("spinor");
358 #else
359 	spinor_mtd = (struct MtdDev *)LOS_DL_LIST_ENTRY(patition_head->pstNext, mtd_partition, node_info)->mtd_info;
360 #endif
361 	if (spinor_mtd == NULL) {
362 		free(jffs2_sb);
363 		return EPERM;
364 	}
365 	jffs_part[partition_num].blockEnd = current_node->end_block;
366 	jffs_part[partition_num].blockSize = spinor_mtd->eraseSize;
367 	jffs_part[partition_num].blockStart = current_node->start_block;
368 #ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
369 	(void)FreeMtd(spinor_mtd);
370 #endif
371 	jffs2_sb->jffs2_sb.mtd = current_node->mtd_info;
372 	jffs2_sb->s_dev = (cyg_io_handle_t)(&jffs_part[partition_num]);
373 
374 	c->flash_size  = (current_node->end_block - current_node->start_block + 1) * spinor_mtd->eraseSize;
375 	c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size);
376 	c->sector_size = spinor_mtd->eraseSize;
377 
378 	jffs2_dbg(1, "C mtd_size:%d,mtd-erase:%d,blocks:%d,hashsize:%d\n",
379 		c->flash_size, c->sector_size, c->flash_size / c->sector_size, c->inocache_hashsize);
380 
381 	c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * c->inocache_hashsize);
382 	if (c->inocache_list == NULL) {
383 		free(jffs2_sb);
384 		return ENOMEM;
385 	}
386 	(void)memset_s(c->inocache_list, sizeof(struct jffs2_inode_cache *) * c->inocache_hashsize, 0,
387 		sizeof(struct jffs2_inode_cache *) * c->inocache_hashsize);
388 	if (n_fs_mounted++ == 0) {
389 		(void)jffs2_create_slab_caches(); // No error check, cannot fail
390 		(void)jffs2_compressors_init();
391 	}
392 
393 	err = jffs2_read_super(jffs2_sb);
394 
395 	if (err) {
396 		if (--n_fs_mounted == 0) {
397 			jffs2_destroy_slab_caches();
398 			(void)jffs2_compressors_exit();
399 		}
400 
401 		free(jffs2_sb);
402 		free(c->inocache_list);
403 		c->inocache_list = NULL;
404 		return err;
405 	}
406 	jffs2_sb->s_root->i_parent = jffs2_sb->s_root;    // points to itself, no dotdot paths above mountpoint
407 	jffs2_sb->s_root->i_cache_prev = NULL;    // root inode, so always null
408 	jffs2_sb->s_root->i_cache_next = NULL;
409 	jffs2_sb->s_root->i_count = 1;    // Ensures the root inode is always in ram until umount
410 
411 #ifdef CYGOPT_FS_JFFS2_GCTHREAD
412 	jffs2_start_garbage_collect_thread(c);
413 #endif
414 
415 	mte->data = (CYG_ADDRWORD)jffs2_sb;
416 	jffs2_sb->s_mount_count++;
417 	mte->root = (cyg_dir)jffs2_sb->s_root;
418 	D2(PRINTK("jffs2_mounted superblock at %x\n", mte->root));
419 	return ENOERR;
420 }
421 
422 
423 // -------------------------------------------------------------------------
424 // jffs2_umount()
425 // Unmount the filesystem.
426 
jffs2_umount(cyg_mtab_entry * mte)427 static int jffs2_umount(cyg_mtab_entry *mte)
428 {
429 	struct _inode *root = (struct _inode *) mte->root;
430 	struct super_block *jffs2_sb = root->i_sb;
431 	struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb);
432 	struct jffs2_full_dirent *fd, *next;
433 
434 	D2(PRINTK("jffs2_umount\n"));
435 
436 	// Only really umount if this is the only mount
437 	if (jffs2_sb->s_mount_count == 1) {
438 		icache_evict(root, NULL);
439 		if (root->i_cache_next != NULL) {
440 			struct _inode *inode = root;
441 			while (inode) {
442 				PRINTK("Ino #%u has use count %d\n",
443 					   inode->i_ino, inode->i_count);
444 				inode = inode->i_cache_next;
445 			}
446 			// root icount was set to 1 on mount
447 			return EBUSY;
448 		}
449 		if (root->i_count != 1) {
450 			PRINTK("Ino #1 has use count %d\n",
451 				   root->i_count);
452 			return EBUSY;
453 		}
454 #ifdef CYGOPT_FS_JFFS2_GCTHREAD
455 		jffs2_stop_garbage_collect_thread(c);
456 #endif
457 		jffs2_iput(root); // Time to free the root inode
458 
459 		// free directory entries
460 		for (fd = root->jffs2_i.dents; fd; fd = next) {
461 			next = fd->next;
462 			jffs2_free_full_dirent(fd);
463 		}
464 
465 		free(root);
466 
467 		// Clean up the super block and root inode
468 		jffs2_free_ino_caches(c);
469 		jffs2_free_raw_node_refs(c);
470 		free(c->blocks);
471 		c->blocks = NULL;
472 		free(c->inocache_list);
473 		c->inocache_list = NULL;
474 
475 		(void)mutex_destroy(&c->alloc_sem);
476 		(void)mutex_destroy(&c->erase_free_sem);
477 		free(jffs2_sb);
478 		// Clear superblock & root pointer
479 		mte->root = 0;
480 		mte->data = 0;
481 		// That's all folks.
482 		D2(PRINTK("jffs2_umount No current mounts\n"));
483 	} else {
484 		jffs2_sb->s_mount_count--;
485 	}
486 	if (--n_fs_mounted == 0) {
487 		jffs2_destroy_slab_caches();
488 		(void)jffs2_compressors_exit();
489 	}
490 	return ENOERR;
491 }
492 
493 // -------------------------------------------------------------------------
494 // jffs2_open()
495 // Open a file for reading or writing.
496 
jffs2_open(cyg_mtab_entry * mte,const char * name,int flags,int mode,cyg_file * fte)497 static int jffs2_open (cyg_mtab_entry *mte, const char *name, int flags,
498                     int mode,  cyg_file *fte)
499 {
500 	jffs2_dirsearch ds;
501 	struct _inode *node = NULL;
502 	int err;
503 	jffs2_dbg(1, "open %s at mode: %d\n",name,mode);
504 
505 #ifndef CYGOPT_FS_JFFS2_WRITE
506 	if (flags & (O_CREAT | O_TRUNC | O_WRONLY))
507 		return EROFS;
508 #endif
509 
510 	if (jffs_check_path(name))
511 		return ENAMETOOLONG;
512 
513 	init_dirsearch(&ds, (struct _inode *)mte->root,
514 		(const unsigned char *) name,  jffs2_oflag_to_accmode(flags));
515 
516 	err = jffs2_find(&ds);
517 
518 	if (err == ENOENT) {
519 #ifdef CYGOPT_FS_JFFS2_WRITE
520 		if (ds.last && (flags & O_CREAT)) {
521 
522 			// No node there, if the O_CREAT bit is set then we must
523 			// create a new one. The dir and name fields of the dirsearch
524 			// object will have been updated so we know where to put it.
525 			err = jffs2_create(ds.dir, ds.name, mode, &node);
526 		if (err != 0) {
527 			//Possible orphaned inode on the flash - but will be gc'd
528 			jffs2_iput(ds.dir);
529 			return -err;
530 		}
531 
532 		err = ENOERR;
533 		}
534 #endif
535 	} else if (err == ENOERR) {
536 		// The node exists. If the O_CREAT and O_EXCL bits are set, we
537 		// must fail the open.
538 
539 		if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
540 			jffs2_iput(ds.node);
541 			err = EEXIST;
542 		}  else
543 			node = ds.node;
544 	} else if (err == EACCES) {
545 		jffs2_iput(ds.dir);
546 		return -err;
547 	}
548 
549 	D1(PRINTK("%s, %d, uid %d gid %d mode %d%d%d\n", __FUNCTION__, __LINE__, node->i_uid, node->i_gid,
550 		(node->i_mode >> JFFS2_USER_SHFIT) & JFFS2_MODE_ALL, (node->i_mode >> JFFS2_GROUP_SHFIT) & JFFS2_MODE_ALL,
551 		(node->i_mode) & JFFS2_MODE_ALL));
552 
553 	// Finished with the directory now
554 	jffs2_iput(ds.dir);
555 
556 	if (err != ENOERR) {
557 		return err;
558 	}
559 	// Check that we actually have a file here
560 	if (S_ISDIR(node->i_mode)) {
561 		jffs2_iput(node);
562 		return EISDIR;
563 	}
564 
565 	// If the O_TRUNC bit is set we must clean out the file data.
566 	if (flags & O_TRUNC) {
567 #ifdef CYGOPT_FS_JFFS2_WRITE
568 		err = jffs2_truncate_file(node);
569 		if (err) {
570 			jffs2_iput(node);
571 			return err;
572 		}
573 #else
574 		jffs2_iput(node);
575 		return EROFS;
576 #endif
577 	}
578 
579 	// Initialise the file object
580 	fte->f_flag = flags & JFFS2_O_ACCMODE;
581 	fte->f_offset = (flags & O_APPEND) ? node->i_size : 0;
582 	fte->f_data = (UINTPTR) node;
583 
584 	return ENOERR;
585 }
586 
587 // -------------------------------------------------------------------------
588 // jffs2_ops_unlink()
589 // Remove a file link from its directory.
590 
jffs2_ops_unlink(cyg_mtab_entry * mte,const char * name)591 static int jffs2_ops_unlink(cyg_mtab_entry *mte, const char *name)
592 {
593 	jffs2_dirsearch ds;
594 	int err;
595 
596 	jffs2_dbg(1, "unlink: %s\n", name);
597 
598 	if (jffs_check_path(name))
599 		return ENAMETOOLONG;
600 
601 	init_dirsearch(&ds, (struct _inode *) mte->root,
602 		(const unsigned char *)name, 0);
603 
604 	err = jffs2_find(&ds);
605 
606 	if (err != ENOERR) {
607 		jffs2_iput(ds.dir);
608 		return err;
609 	}
610 
611 	if (CheckPermission(ds.dir, WRITE_OP | EXEC_OP)) {
612 		jffs2_iput(ds.dir);
613 		jffs2_iput(ds.node);
614 		return EACCES;
615 	}
616 
617 	// Cannot unlink directories, use rmdir() instead
618 	if (S_ISDIR(ds.node->i_mode)) {
619 		jffs2_iput(ds.dir);
620 		jffs2_iput(ds.node);
621 		return EISDIR;
622 	}
623 
624 	// Delete it from its directory
625 
626 	err = jffs2_unlink(ds.dir, ds.node, ds.name);
627 	jffs2_iput(ds.dir);
628 	jffs2_iput(ds.node);
629 
630 	return -err;
631 }
632 
633 // -------------------------------------------------------------------------
634 // jffs2_ops_mkdir()
635 // Create a new directory.
636 
jffs2_ops_mkdir(cyg_mtab_entry * mte,const char * name,int mode)637 static int jffs2_ops_mkdir(cyg_mtab_entry *mte, const char *name,int mode)
638 {
639 	jffs2_dirsearch ds;
640 	int err;
641 
642 	jffs2_dbg(1, "mkdir: %s\n",name);
643 
644 	if (jffs_check_path(name))
645 		return ENAMETOOLONG;
646 
647 	init_dirsearch(&ds, (struct _inode *)mte->root, (const unsigned char *)name, 0);
648 
649 	err = jffs2_find(&ds);
650 	if (err == ENOENT) {
651 		if (ds.last) {
652 			// The entry does not exist, and it is the last element in
653 			// the pathname, so we can create it here.
654 			err = jffs2_mkdir(ds.dir, ds.name, mode);
655 		}
656 		// If this was not the last element, then an intermediate
657 		// directory does not exist.
658 	} else {
659 		// If there we no error, something already exists with that
660 		// name, so we cannot create another one.
661 		if (err == ENOERR) {
662 			jffs2_iput(ds.node);
663 			err = -EEXIST;
664 		}
665 	}
666 	jffs2_iput(ds.dir);
667 	if (err == EACCES) {
668 		err = -EACCES;
669 	}
670 	return err;
671 }
672 
673 // -------------------------------------------------------------------------
674 // jffs2_ops_rmdir()
675 // Remove a directory.
676 
jffs2_ops_rmdir(cyg_mtab_entry * mte,const char * name)677 static int jffs2_ops_rmdir(cyg_mtab_entry *mte, const char *name)
678 {
679 	jffs2_dirsearch ds;
680 	int err;
681 
682 	jffs2_dbg(1, "rmdir: %s\n",name);
683 
684 	if (jffs_check_path(name))
685 		return ENAMETOOLONG;
686 
687 	init_dirsearch(&ds, (struct _inode *)mte->root, (const unsigned char *)name, 0);
688 
689 	err = jffs2_find(&ds);
690 	if (err != ENOERR) {
691 		jffs2_iput(ds.dir);
692 		return -err;
693 	}
694 
695 	if (CheckPermission(ds.dir, WRITE_OP | EXEC_OP)) {
696 		jffs2_iput(ds.dir);
697 		jffs2_iput(ds.node);
698 		return -EACCES;
699 	}
700 
701 	// Check that this is actually a directory.
702 	if (!S_ISDIR(ds.node->i_mode)) {
703 		jffs2_iput(ds.dir);
704 		jffs2_iput(ds.node);
705 		return -ENOTDIR;
706 	}
707 
708 	err = jffs2_rmdir(ds.dir, ds.node, ds.name);
709 
710 	jffs2_iput(ds.dir);
711 	jffs2_iput(ds.node);
712 	return err;
713 }
714 
715 // -------------------------------------------------------------------------
716 // jffs2_ops_rename()
717 // Rename a file/dir.
718 
jffs2_ops_rename(cyg_mtab_entry * mte,const char * name1,const char * name2)719 static int jffs2_ops_rename(cyg_mtab_entry *mte, const char *name1, const char *name2)
720 {
721 	jffs2_dirsearch ds1, ds2;
722 	int err;
723 	struct jffs2_inode_info *f = NULL;
724 	struct jffs2_full_dirent *fd = NULL;
725 	unsigned int oldrelpath_len, newrelpath_len, cmp_namelen;
726 
727 	jffs2_dbg(1, "from: %s to: %s\n", name1, name2);
728 
729 	if (jffs_check_path(name1))
730 		return ENAMETOOLONG;
731 
732 	if (jffs_check_path(name2))
733 		return ENAMETOOLONG;
734 
735 	oldrelpath_len = strlen(name1);
736 	newrelpath_len = strlen(name2);
737 	if (!oldrelpath_len || !newrelpath_len)
738 		return EPERM;
739 
740 	cmp_namelen = (oldrelpath_len <= newrelpath_len) ? oldrelpath_len : newrelpath_len;
741 	if ((!strncmp(name1, name2, cmp_namelen)) && ((name1[cmp_namelen] == '/') || (name2[cmp_namelen] == '/'))) {
742 		err = -EPERM;
743 		return err;
744 	}
745 
746 	init_dirsearch(&ds1, (struct _inode *)mte->root,
747 		(const unsigned char *)name1, 0);
748 
749 	err = jffs2_find(&ds1);
750 
751 	if (err != ENOERR) {
752 		jffs2_iput(ds1.dir);
753 		return err;
754 	}
755 
756 	if (CheckPermission(ds1.dir, WRITE_OP | EXEC_OP)) {
757 		jffs2_iput(ds1.dir);
758 		jffs2_iput(ds1.node);
759 		return -EACCES;
760 	}
761 
762 
763 	init_dirsearch(&ds2, (struct _inode *)mte->root,
764 		(const unsigned char *)name2, 0);
765 
766 	err = jffs2_find(&ds2);
767 
768 	// Allow through renames to non-existent objects.
769 	if (ds2.last && err == ENOENT) {
770 		ds2.node = NULL;
771 		err = ENOERR;
772 	} else if ((err == ENOERR) && S_ISDIR(ds2.node->i_mode)) {
773 		f = JFFS2_INODE_INFO(ds2.node);
774 		for (fd = f->dents; fd; fd = fd->next) {
775 			if (fd->ino) {
776 				jffs2_iput(ds2.node);
777 				err = ENOTEMPTY;
778 				break;
779 			}
780 		}
781 	}
782 	if (err != ENOERR) {
783 		jffs2_iput(ds1.dir);
784 		jffs2_iput(ds1.node);
785 		jffs2_iput(ds2.dir);
786 		return err;
787 	}
788 
789 	if (CheckPermission(ds2.dir, WRITE_OP | EXEC_OP)) {
790 		jffs2_iput(ds1.dir);
791 		jffs2_iput(ds1.node);
792 		jffs2_iput(ds2.dir);
793 		jffs2_iput(ds2.node);
794 		return -EACCES;
795 	}
796 
797 	// Null rename, just return
798 	if (ds1.node == ds2.node) {
799 		err = ENOERR;
800 		goto out;
801 	}
802 
803 	// First deal with any entry that is at the destination
804 	if (ds2.node != NULL) {
805 		// Check that we are renaming like-for-like
806 
807 		if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) {
808 			err = EISDIR;
809 			goto out;
810 		}
811 
812 		if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) {
813 			err = ENOTDIR;
814 			goto out;
815 		}
816 
817 		// Now delete the destination directory entry
818 		/* Er, what happened to atomicity of rename()? */
819 		err = -jffs2_unlink(ds2.dir, ds2.node, ds2.name);
820 
821 		if (err != 0)
822 			goto out;
823 	}
824 	// Now we know that there is no clashing node at the destination,
825 	// make a new direntry at the destination and delete the old entry
826 	// at the source.
827 
828 	err = -jffs2_rename(ds1.dir, ds1.node, ds1.name, ds2.dir, ds2.name);
829 
830 	// Update directory times
831 	if (!err)
832 		ds1.dir->i_ctime =
833 			ds1.dir->i_mtime =
834 			ds2.dir->i_ctime = ds2.dir->i_mtime = jffs2_get_timestamp();
835  out:
836 	jffs2_iput(ds1.dir);
837 	if (S_ISDIR(ds1.node->i_mode)) {
838 		/* Renamed a directory to elsewhere... so fix up its
839 		   i_parent pointer and the i_counts of its old and
840 		   new parents. */
841 		jffs2_iput(ds1.node->i_parent);
842 		ds1.node->i_parent = ds2.dir;
843 		/* We effectively increase its use count by not... */
844 	} else {
845 		jffs2_iput(ds2.dir); /* ... doing this */
846 	}
847 	jffs2_iput(ds1.node);
848 	if (ds2.node != NULL)
849 		jffs2_iput(ds2.node);
850 
851 	return err;
852 }
853 
jffsfs_IsPathDivider(char ch)854 static int jffsfs_IsPathDivider(char ch)
855 {
856 	const char *str = JFFS_PATH_DIVIDERS;
857 	while (*str) {
858 		if (*str == ch)
859 			return 1;
860 		str++;
861 	}
862 	return 0;
863 }
864 
865 // -------------------------------------------------------------------------
866 // jffs2_opendir()
867 // Open a directory for reading.
868 
jffs2_opendir(cyg_mtab_entry * mte,const char * name,cyg_file * fte)869 static int jffs2_opendir(cyg_mtab_entry *mte, const char *name, cyg_file *fte)
870 {
871 	jffs2_dirsearch ds;
872 	int err;
873 
874 	jffs2_dbg(1, "opendir: %s\n",name);
875 
876 	if (jffs_check_path(name))
877 		return ENAMETOOLONG;
878 
879 	init_dirsearch(&ds, (struct _inode *) mte->root,
880 		(const unsigned char *) name, jffs2_oflag_to_accmode(O_RDONLY | O_EXECVE));
881 
882 	err = jffs2_find(&ds);
883 
884 	jffs2_iput(ds.dir);
885 
886 	if (err != ENOERR) {
887 		return err;
888 	}
889 
890 	// check it is really a directory.
891 	if (!S_ISDIR(ds.node->i_mode)) {
892 		jffs2_iput(ds.node);
893 		return ENOTDIR;
894 	}
895 
896 	// Initialize the file object, setting the f_ops field to a
897 	// special set of file ops.
898 
899 	fte->f_flag = 0;
900 	fte->f_offset = 0;
901 	fte->f_data = (UINTPTR) ds.node;
902 
903 	return ENOERR;
904 }
905 
jffs2_fo_chattr(cyg_mtab_entry * mte,const char * name,iattr * attr)906 static int jffs2_fo_chattr(cyg_mtab_entry *mte, const char *name, iattr *attr)
907 {
908 	jffs2_dirsearch ds;
909 	int ret;
910 	int flags = 0;
911 	D2(PRINTK("jffs2_chattr: %s\n", name));
912 
913 	if (jffs_check_path(name))
914 		return ENAMETOOLONG;
915 
916 	init_dirsearch(&ds, (struct _inode *)mte->root, (const unsigned char *)name, flags);
917 
918 	ret = jffs2_find(&ds);
919 	if (ret == ENOERR) {
920 		ret = jffs2_chattr(ds.dir, ds.name, attr, ds.node);
921 		jffs2_iput(ds.node);
922 	} else {
923 		ret = -ret;
924 	}
925 	jffs2_iput(ds.dir);
926 	return ret;
927 }
928 
929 // -------------------------------------------------------------------------
930 // jffs2_stat()
931 // Get struct stat info for named object.
932 
jffs2_stat(cyg_mtab_entry * mte,const char * name,struct jffs2_stat * buf)933 static int jffs2_stat(cyg_mtab_entry *mte, const char *name, struct jffs2_stat *buf)
934 {
935 	jffs2_dirsearch ds;
936 	int err;
937 
938 	jffs2_dbg(1, "get %s stat\n", name);
939 
940 	if (jffs_check_path(name))
941 		return ENAMETOOLONG;
942 
943 	init_dirsearch(&ds, (struct _inode *)mte->root,
944 		(const unsigned char *) name, 0);
945 
946 	err = jffs2_find(&ds);
947 	jffs2_iput(ds.dir);
948 
949 	if (err != ENOERR)
950 		return err;
951 
952 	// Fill in the status
953 	buf->st_mode = ds.node->i_mode;
954 	buf->st_ino = ds.node->i_ino;
955 	buf->st_dev = 0;
956 	buf->st_nlink = ds.node->i_nlink;
957 	buf->st_uid = ds.node->i_uid;
958 	buf->st_gid = ds.node->i_gid;
959 	buf->st_size = ds.node->i_size;
960 	buf->sddst_atime = ds.node->i_atime;
961 	buf->sddst_mtime = ds.node->i_mtime;
962 	buf->sddst_ctime = ds.node->i_ctime;
963 
964 	jffs2_iput(ds.node);
965 
966 	return ENOERR;
967 }
968 
969 //==========================================================================
970 // File operations
971 
972 // -------------------------------------------------------------------------
973 // jffs2_fo_read()
974 // Read data from the file.
975 
jffs2_fo_read(struct CYG_FILE_TAG * fp,struct CYG_UIO_TAG * uio)976 static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
977 {
978 	struct _inode *inode = (struct _inode *) fp->f_data;
979 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
980 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
981 	int i;
982 	ssize_t resid = uio->uio_resid;
983 	off_t pos = fp->f_offset;
984 
985 	mutex_lock(&f->sem);
986 
987 	// Loop over the io vectors until there are none left
988 	for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) {
989 		int ret;
990 		jffs2_iovec *iov = &uio->uio_iov[i];
991 		off_t len = min((iov->iov_len), (inode->i_size - pos));
992 
993 		D2(PRINTK("jffs2_fo_read inode size %d\n", inode->i_size));
994 
995 		ret = jffs2_read_inode_range(c, f,(unsigned char *) iov->iov_base, pos,len);
996 		if (ret) {
997 			D1(PRINTK
998 			   ("jffs2_fo_read(): read_inode_range failed %d\n",
999 				ret));
1000 			uio->uio_resid = resid;
1001 			mutex_unlock(&f->sem);
1002 			return -ret;
1003 		}
1004 		resid -= len;
1005 		pos += len;
1006 	}
1007 
1008 	// We successfully read some data, update the node's access time
1009 	// and update the file offset and transfer residue.
1010 
1011 	inode->i_atime = jffs2_get_timestamp();
1012 
1013 	uio->uio_resid = resid;
1014 	fp->f_offset = pos;
1015 
1016 	mutex_unlock(&f->sem);
1017 
1018 	return ENOERR;
1019 }
1020 
1021 #ifdef CYGOPT_FS_JFFS2_WRITE
1022 // -------------------------------------------------------------------------
1023 // jffs2_fo_write()
1024 // Write data to file.
jffs2_extend_file(struct _inode * inode,struct jffs2_raw_inode * ri,unsigned long offset)1025 static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri,
1026 			   unsigned long offset)
1027 {
1028 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1029 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1030 	struct jffs2_full_dnode *fn;
1031 	uint32_t alloc_len;
1032 	int ret = 0;
1033 
1034 	/* Make new hole frag from old EOF to new page */
1035 	D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
1036 		  (unsigned int)inode->i_size, offset));
1037 
1038 	ret = jffs2_reserve_space(c, sizeof(*ri), &alloc_len, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1039 	if (ret)
1040 		return ret;
1041 
1042 	mutex_lock(&f->sem);
1043 
1044 	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
1045 	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
1046 	ri->totlen = cpu_to_je32(sizeof(*ri));
1047 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, (sizeof(struct jffs2_unknown_node)-4)));
1048 
1049 	ri->version = cpu_to_je32(++f->highest_version);
1050 	ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset));
1051 
1052 	ri->offset = cpu_to_je32(inode->i_size);
1053 	ri->dsize = cpu_to_je32((offset - inode->i_size));
1054 	ri->csize = cpu_to_je32(0);
1055 	ri->compr = JFFS2_COMPR_ZERO;
1056 	ri->node_crc = cpu_to_je32(crc32(0, ri, (sizeof(*ri)-8)));
1057 	ri->data_crc = cpu_to_je32(0);
1058 
1059 	fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
1060 	jffs2_complete_reservation(c);
1061 	if (IS_ERR(fn)) {
1062 		ret = PTR_ERR(fn);
1063 		(void)mutex_unlock(&f->sem);
1064 		return ret;
1065 	}
1066 	ret = jffs2_add_full_dnode_to_inode(c, f, fn);
1067 	if (f->metadata) {
1068 		jffs2_mark_node_obsolete(c, f->metadata->raw);
1069 		jffs2_free_full_dnode(f->metadata);
1070 		f->metadata = NULL;
1071 	}
1072 	if (ret) {
1073 		D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret));
1074 		jffs2_mark_node_obsolete(c, fn->raw);
1075 		jffs2_free_full_dnode(fn);
1076 		mutex_unlock(&f->sem);
1077 		return ret;
1078 	}
1079 	inode->i_size = offset;
1080 	mutex_unlock(&f->sem);
1081 	return 0;
1082 }
1083 
1084 // jffs2_fo_open()
1085 // Truncate a file
jffs2_truncate_file(struct _inode * inode)1086 static int jffs2_truncate_file (struct _inode *inode)
1087 {
1088 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1089 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1090 	struct jffs2_full_dnode *new_metadata, * old_metadata;
1091 	struct jffs2_raw_inode *ri;
1092 	uint32_t alloclen;
1093 	int err;
1094 
1095 	ri = jffs2_alloc_raw_inode();
1096 	if (!ri) {
1097 		return ENOMEM;
1098 	}
1099 	err = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1100 
1101 	if (err) {
1102 		jffs2_free_raw_inode(ri);
1103 		return err;
1104 	}
1105 	mutex_lock(&f->sem);
1106 	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
1107 	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
1108 	ri->totlen = cpu_to_je32(sizeof(*ri));
1109 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, (sizeof(struct jffs2_unknown_node)-4)));
1110 
1111 	ri->ino = cpu_to_je32(inode->i_ino);
1112 	ri->version = cpu_to_je32(++f->highest_version);
1113 
1114 	ri->uid = cpu_to_je16(inode->i_uid);
1115 	ri->gid = cpu_to_je16(inode->i_gid);
1116 	ri->mode = cpu_to_jemode(inode->i_mode);
1117 	ri->isize = cpu_to_je32(0);
1118 	ri->atime = cpu_to_je32(inode->i_atime);
1119 	ri->mtime = cpu_to_je32(jffs2_get_timestamp());
1120 	ri->offset = cpu_to_je32(0);
1121 	ri->csize = ri->dsize = cpu_to_je32(0);
1122 	ri->compr = JFFS2_COMPR_NONE;
1123 	ri->node_crc = cpu_to_je32(crc32(0, ri, (sizeof(*ri)-8)));
1124 	ri->data_crc = cpu_to_je32(0);
1125 	new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
1126 	if (IS_ERR(new_metadata)) {
1127 	jffs2_complete_reservation(c);
1128 	jffs2_free_raw_inode(ri);
1129 	mutex_unlock(&f->sem);
1130 	return PTR_ERR(new_metadata);
1131 	}
1132 
1133 	/* It worked. Update the inode */
1134 	inode->i_mtime = jffs2_get_timestamp();
1135 	inode->i_size = 0;
1136 	old_metadata = f->metadata;
1137 	jffs2_truncate_fragtree (c, &f->fragtree, 0);
1138 	f->metadata = new_metadata;
1139 	if (old_metadata) {
1140 		jffs2_mark_node_obsolete(c, old_metadata->raw);
1141 		jffs2_free_full_dnode(old_metadata);
1142 	}
1143 	jffs2_free_raw_inode(ri);
1144 
1145 mutex_unlock(&f->sem);
1146 	jffs2_complete_reservation(c);
1147 
1148 	return 0;
1149 }
1150 
1151 // jffs2_fo_open()
1152 // Truncate a file
1153 
jffs2_fo_write(struct CYG_FILE_TAG * fp,struct CYG_UIO_TAG * uio)1154 static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1155 {
1156 	struct _inode *inode = (struct _inode *) fp->f_data;
1157 	off_t pos = fp->f_offset;
1158 	ssize_t resid = uio->uio_resid;
1159 	struct jffs2_raw_inode ri;
1160 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1161 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1162 	int i;
1163 
1164 #ifdef LOSCFG_KERNEL_SMP
1165 	struct super_block *sb = inode->i_sb;
1166 	UINT16 gc_cpu_mask = LOS_TaskCpuAffiGet(sb->s_gc_thread);
1167 	UINT32 cur_task_id = LOS_CurTaskIDGet();
1168 	UINT16 cur_cpu_mask = LOS_TaskCpuAffiGet(cur_task_id);
1169 
1170 	if (cur_cpu_mask != gc_cpu_mask) {
1171 		if (cur_cpu_mask != LOSCFG_KERNEL_CPU_MASK)
1172 			(void)LOS_TaskCpuAffiSet(sb->s_gc_thread, cur_cpu_mask);
1173 		else
1174 			(void)LOS_TaskCpuAffiSet(cur_task_id, gc_cpu_mask);
1175 	}
1176 #endif
1177 	// If the APPEND mode bit was supplied, force all writes to
1178 	// the end of the file.
1179 	if (fp->f_flag & O_APPEND)
1180 		pos = fp->f_offset = inode->i_size;
1181 
1182 	if (pos < 0)
1183 		return EINVAL;
1184 
1185 	(void)memset_s(&ri, sizeof(ri), 0, sizeof(ri));
1186 
1187 	ri.ino = cpu_to_je32(f->inocache->ino);
1188 	ri.mode = cpu_to_jemode(inode->i_mode);
1189 	ri.uid = cpu_to_je16(inode->i_uid);
1190 	ri.gid = cpu_to_je16(inode->i_gid);
1191 	ri.atime = ri.ctime = ri.mtime = cpu_to_je32(jffs2_get_timestamp());
1192 
1193 	if (pos > inode->i_size) {
1194 		int err;
1195 		ri.version = cpu_to_je32(++f->highest_version);
1196 		err = jffs2_extend_file(inode, &ri, pos);
1197 		if (err)
1198 			return -err;
1199 	}
1200 	ri.isize = cpu_to_je32(inode->i_size);
1201 
1202 	// Now loop over the iovecs until they are all done, or
1203 	// we get an error.
1204 	for (i = 0; i < uio->uio_iovcnt; i++) {
1205 		jffs2_iovec *iov = &uio->uio_iov[i];
1206 		unsigned char *buf = iov->iov_base;
1207 		off_t len = iov->iov_len;
1208 
1209 		uint32_t writtenlen;
1210 		int err;
1211 
1212 		D2(PRINTK("jffs2_fo_write page_start_pos %d\n", pos));
1213 		D2(PRINTK("jffs2_fo_write transfer size %d\n", len));
1214 
1215 		err = jffs2_write_inode_range(c, f, &ri, buf,
1216 				  pos, len, &writtenlen);
1217 		if (err) {
1218 			pos += writtenlen;
1219 			resid -= writtenlen;
1220 
1221 			inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime);
1222 			if (pos > inode->i_size)
1223 				inode->i_size = pos;
1224 
1225 			uio->uio_resid = resid;
1226 			fp->f_offset = pos;
1227 
1228 			return -err;
1229 		}
1230 
1231 		if (writtenlen != len) {
1232 			pos += writtenlen;
1233 			resid -= writtenlen;
1234 
1235 			inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime);
1236 			if (pos > inode->i_size)
1237 				inode->i_size = pos;
1238 
1239 			uio->uio_resid = resid;
1240 			fp->f_offset = pos;
1241 
1242 			return ENOSPC;
1243 		}
1244 
1245 		pos += len;
1246 		resid -= len;
1247 	}
1248 
1249 	// We wrote some data successfully, update the modified and access
1250 	// times of the inode, increase its size appropriately, and update
1251 	// the file offset and transfer residue.
1252 	inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime);
1253 	if (pos > inode->i_size)
1254 		inode->i_size = pos;
1255 
1256 	uio->uio_resid = resid;
1257 	fp->f_offset = pos;
1258 
1259 	return ENOERR;
1260 }
1261 #endif /* CYGOPT_FS_JFFS2_WRITE */
1262 
1263 // -------------------------------------------------------------------------
1264 // jffs2_fo_lseek()
1265 // Seek to a new file position.
1266 
jffs2_fo_lseek(struct CYG_FILE_TAG * fp,off_t * apos,int whence)1267 static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)
1268 {
1269 	struct _inode *node = (struct _inode *) fp->f_data;
1270 	off_t pos = *apos;
1271 
1272 	D2(PRINTK("jffs2_fo_lseek\n"));
1273 
1274 	switch (whence) {
1275 	case SEEK_SET:
1276 		// Pos is already where we want to be.
1277 		break;
1278 
1279 	case SEEK_CUR:
1280 		// Add pos to current offset.
1281 		pos += fp->f_offset;
1282 		break;
1283 
1284 	case SEEK_END:
1285 		// Add pos to file size.
1286 		pos += node->i_size;
1287 		break;
1288 
1289 	default:
1290 		return EINVAL;
1291 	}
1292 
1293 	if (pos < 0)
1294 		return EINVAL;
1295 
1296 	// All OK, set fp offset and return new position.
1297 	*apos = fp->f_offset = pos;
1298 
1299 	return ENOERR;
1300 }
1301 
1302 // -------------------------------------------------------------------------
1303 // jffs2_fo_close()
1304 // Close a file. We just decrement the refcnt and let it go away if
1305 // that is all that is keeping it here.
1306 
jffs2_fo_close(struct CYG_FILE_TAG * fp)1307 static int jffs2_fo_close(struct CYG_FILE_TAG *fp)
1308 {
1309 	struct _inode *node = (struct _inode *) fp->f_data;
1310 
1311 	jffs2_dbg(1, "jffs close data: 0x%x\n",fp->f_data);
1312 	if (node == NULL) {
1313 		return ENOENT;
1314 	}
1315 	jffs2_iput(node);
1316 
1317 	fp->f_data = 0;
1318 	free(fp);
1319 
1320 	return ENOERR;
1321 }
1322 
1323 //==========================================================================
1324 // Directory operations
1325 
1326 // -------------------------------------------------------------------------
1327 // jffs2_fo_dirread()
1328 // Read a single directory entry from a file.
1329 
filldir(char * nbuf,int nlen,const unsigned char * name,int namlen)1330 static __inline void filldir(char *nbuf, int nlen, const unsigned char *name, int namlen)
1331 {
1332 	int len = nlen < namlen ? nlen : namlen;
1333 	(void)memcpy_s(nbuf, nlen, name, len);
1334 	nbuf[len] = '\0';
1335 }
1336 
jffs2_fo_dirread(struct CYG_FILE_TAG * fp,struct CYG_UIO_TAG * uio)1337 static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1338 {
1339 	struct _inode *d_inode = (struct _inode *) fp->f_data;
1340 	struct jffs2_dirent *ent = (struct jffs2_dirent *) uio->uio_iov[0].iov_base;
1341 	char *nbuf = ent->d_name;
1342 	int nlen = sizeof(ent->d_name) - 1;
1343 	off_t len = uio->uio_iov[0].iov_len;
1344 	struct jffs2_inode_info *f;
1345 	struct _inode *inode = d_inode;
1346 	struct jffs2_full_dirent *fd;
1347 	unsigned long offset, curofs;
1348 	int found = 1;
1349 
1350 	jffs2_dbg(1, "read at: 0x%x \n", fp->f_data);
1351 
1352 	if (len < (off_t)sizeof (struct jffs2_dirent))
1353 		return EINVAL;
1354 
1355 	if (CheckPermission(inode, READ_OP)) {
1356 		return EACCES;
1357 	}
1358 
1359 	D1(printk
1360 	   (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino));
1361 
1362 	f = JFFS2_INODE_INFO(inode);
1363 
1364 	offset = fp->f_offset;
1365 	if (offset == 0) {
1366 		D1(printk
1367 		   (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino));
1368 		filldir(nbuf, nlen, (const unsigned char *) ".", 1);
1369 #ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
1370 		// Flags here are the same as jffs2_mkdir. Make sure
1371 		// d_type is the same as st_mode of calling stat.
1372 		ent->d_type =
1373 		  jemode_to_cpu(cpu_to_jemode(S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR));
1374 #endif
1375 		goto out;
1376 	}
1377 	if (offset == 1) {
1378 		filldir(nbuf, nlen, (const unsigned char *) "..", 2);
1379 #ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
1380 		// Flags here are the same as jffs2_mkdir. Make sure
1381 		// d_type is the same as st_mode of calling stat.
1382 		ent->d_type =
1383 		  jemode_to_cpu(cpu_to_jemode(S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR));
1384 #endif
1385 		goto out;
1386 	}
1387 	curofs = 1;
1388 	mutex_lock(&f->sem);
1389 	for (fd = f->dents; fd; fd = fd->next) {
1390 		curofs++;
1391 		/* First loop: curofs = 2; offset = 2 */
1392 		if (curofs < offset) {
1393 			D2(printk
1394 			   (KERN_DEBUG
1395 				"Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
1396 				fd->name, fd->ino, fd->type, curofs, offset));
1397 			continue;
1398 		}
1399 		if (!fd->ino) {
1400 			D2(printk
1401 			   (KERN_DEBUG "Skipping deletion dirent \"%s\"\n",
1402 				fd->name));
1403 			offset++;
1404 			continue;
1405 		}
1406 		D2(printk
1407 		   (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset,
1408 			fd->name, fd->ino, fd->type));
1409 		filldir(nbuf, nlen, fd->name, strlen((char *)fd->name));
1410 		ent->d_type = fd->type;
1411 		goto out_sem;
1412 	}
1413 	/* Reached the end of the directory */
1414 	found = 0;
1415       out_sem:
1416 	mutex_unlock(&f->sem);
1417 	if (fd == NULL) {
1418 		D2(printk
1419 			(KERN_DEBUG "reached the end of the directory\n"));
1420 		return ENOENT;
1421 	}
1422 	  out:
1423 	fp->f_offset = ++offset;
1424 
1425 
1426 	if (found) {
1427 		uio->uio_resid -= sizeof (struct jffs2_dirent);
1428 	}
1429 	return ENOERR;
1430 }
1431 
jffs2_fo_dirlseek(struct CYG_FILE_TAG * fp,off_t * pos,int whence)1432 static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence)
1433 {
1434 	// Only allow SEEK_SET to zero
1435 	jffs2_dbg(1, "lseekdir at: %d \n", whence);
1436 
1437 	if (whence != SEEK_SET || *pos != 0)
1438 		return EINVAL;
1439 
1440 	*pos = fp->f_offset = 2;
1441 
1442 	return ENOERR;
1443 }
1444 
1445 //==========================================================================
1446 //
1447 // Called by JFFS2
1448 // ===============
1449 //
1450 //
1451 //==========================================================================
1452 
jffs2_gc_fetch_page(struct jffs2_sb_info * c,struct jffs2_inode_info * f,unsigned long offset,unsigned long * priv)1453 unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
1454 			   struct jffs2_inode_info *f,
1455 			   unsigned long offset,
1456 			   unsigned long *priv)
1457 {
1458 	/* FIXME: This works only with one file system mounted at a time */
1459 	int ret;
1460 
1461 	ret = jffs2_read_inode_range(c, f, gc_buffer,
1462 			 offset & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE);
1463 	if (ret)
1464 		return ERR_PTR(ret);
1465 
1466 	return gc_buffer;
1467 }
1468 
jffs2_gc_release_page(struct jffs2_sb_info * c,unsigned char * ptr,unsigned long * priv)1469 void jffs2_gc_release_page(struct jffs2_sb_info *c,
1470 		   unsigned char *ptr,
1471 		   unsigned long *priv)
1472 {
1473 	/* Do nothing */
1474 }
1475 
new_inode(struct super_block * sb)1476 struct _inode *new_inode(struct super_block *sb)
1477 {
1478 	struct _inode *inode;
1479 	struct _inode *cached_inode;
1480 
1481 	inode = malloc(sizeof (struct _inode));
1482 	if (inode == NULL)
1483 		return 0;
1484 
1485 	D2(PRINTK("malloc new_inode %x ####################################\n",
1486 		inode));
1487 
1488 	(void)memset_s(inode, sizeof (struct _inode), 0, sizeof (struct _inode));
1489 	inode->i_sb = sb;
1490 	inode->i_ino = 1;
1491 	inode->i_count = 1;
1492 	inode->i_nlink = 1;    // Let JFFS2 manage the link count
1493 	inode->i_size = 0;
1494 
1495 	inode->i_cache_next = NULL;    // Newest inode, about to be cached
1496 	// Add to the icache
1497 	for (cached_inode = sb->s_root; cached_inode != NULL;
1498 		 cached_inode = cached_inode->i_cache_next) {
1499 		if (cached_inode->i_cache_next == NULL) {
1500 			cached_inode->i_cache_next = inode;    // Current last in cache points to newcomer
1501 			inode->i_cache_prev = cached_inode;    // Newcomer points back to last
1502 			break;
1503 		}
1504 	}
1505 	return inode;
1506 }
1507 
ilookup(struct super_block * sb,uint32_t ino)1508 static struct _inode *ilookup(struct super_block *sb, uint32_t ino)
1509 {
1510 	struct _inode *inode = NULL;
1511 
1512 	D2(PRINTK("ilookup\n"));
1513 	// Check for this inode in the cache
1514 	jffs_lock();
1515 	for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) {
1516 		if (inode->i_ino == ino) {
1517 			inode->i_count++;
1518 			break;
1519 		}
1520 	}
1521 	jffs_unlock();
1522 	return inode;
1523 }
1524 
jffs2_iget(struct super_block * sb,uint32_t ino)1525 struct _inode *jffs2_iget(struct super_block *sb, uint32_t ino)
1526 {
1527 	// Called in super.c jffs2_read_super, dir.c jffs2_lookup,
1528 	// and gc.c jffs2_garbage_collect_pass
1529 
1530 	// Must first check for cached inode
1531 	// If this fails let new_inode create one
1532 
1533 	struct _inode *inode;
1534 	int err;
1535 
1536 	D2(PRINTK("jffs2_iget\n"));
1537 
1538 	jffs_lock();
1539 	inode = ilookup(sb, ino);
1540 	if (inode) {
1541 		jffs_unlock();
1542 		return inode;
1543 	}
1544 
1545 	// Not cached, so malloc it
1546 
1547 	inode = new_inode(sb);
1548 	if (inode == NULL) {
1549 		jffs_unlock();
1550 		return ERR_PTR(-ENOMEM);
1551 	}
1552 	inode->i_ino = ino;
1553 	err = jffs2_read_inode(inode);
1554 
1555 	if (err) {
1556 		PRINTK("jffs2_read_inode() failed\n");
1557 				inode->i_nlink = 0; // free _this_ bad inode right now
1558 
1559 		jffs2_iput(inode);
1560 		jffs_unlock();
1561 		return ERR_PTR(err);
1562 	}
1563 
1564 	jffs_unlock();
1565 	return inode;
1566 }
1567 
1568 // -------------------------------------------------------------------------
1569 // Decrement the reference count on an inode. If this makes the ref count
1570 // zero, then this inode can be freed.
1571 
jffs2_iput(struct _inode * i)1572 void jffs2_iput(struct _inode *i)
1573 {
1574 	// Called in jffs2_find
1575 	// (and jffs2_open and jffs2_ops_mkdir?)
1576 	// super.c jffs2_read_super,
1577 	// and gc.c jffs2_garbage_collect_pass
1578 	struct jffs2_inode_info *f = NULL;
1579 	struct _inode *temp = NULL;
1580 	jffs_lock();
1581  recurse:
1582 	if (!i) {
1583 		PRINT_ERR("jffs2_iput() called with NULL inode\n");
1584 		// and let it fault...
1585 		jffs_unlock();
1586 		return;
1587 	}
1588 	i->i_count--;
1589 	if (i->i_count < 0)
1590 		BUG();
1591 
1592 	if (i->i_count) {
1593 		jffs_unlock();
1594 		return;
1595 	}
1596 
1597 	if (!i->i_nlink) {
1598 		struct _inode *parent;
1599 		// Remove from the icache linked list and free immediately
1600 		if (i->i_cache_prev)
1601 			i->i_cache_prev->i_cache_next = i->i_cache_next;
1602 		if (i->i_cache_next)
1603 			i->i_cache_next->i_cache_prev = i->i_cache_prev;
1604 		parent = i->i_parent;
1605 		jffs2_clear_inode(i);
1606 		f = JFFS2_INODE_INFO(i);
1607 		(void)mutex_destroy(&(f->sem));
1608 		(void)memset_s(i, sizeof(*i), 0x5a, sizeof(*i));
1609 		temp = i;
1610 		free(i);
1611 
1612 		if (parent && parent != temp) {
1613 			i = parent;
1614 			goto recurse;
1615 		}
1616 
1617 	} else {
1618 		// Evict some _other_ inode with i_count zero, leaving
1619 		// this latest one in the cache for a while
1620 		icache_evict(i->i_sb->s_root, i);
1621 	}
1622 	jffs_unlock();
1623 }
1624 
1625 
1626 // -------------------------------------------------------------------------
1627 // EOF jffs2.c
1628 
1629 
jffs2_init_inode_info(struct jffs2_inode_info * f)1630 static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
1631 {
1632 	(void)memset_s(f, sizeof(struct jffs2_inode_info), 0, sizeof(struct jffs2_inode_info));
1633 	(void)mutex_init(&f->sem);
1634 	(void)mutex_lock(&f->sem);
1635 }
1636 
jffs2_clear_inode(struct _inode * inode)1637 static void jffs2_clear_inode (struct _inode *inode)
1638 {
1639 	/* We can forget about this inode for now - drop all
1640 	 *  the nodelists associated with it, etc.
1641 	 */
1642 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1643 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1644 
1645 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
1646 
1647 	jffs2_do_clear_inode(c, f);
1648 }
1649 
1650 
1651 /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
1652    fill in the raw_inode while you're at it. */
jffs2_new_inode(struct _inode * dir_i,int mode,struct jffs2_raw_inode * ri)1653 struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri)
1654 {
1655 	struct _inode *inode;
1656 	struct super_block *sb = dir_i->i_sb;
1657 	struct jffs2_sb_info *c;
1658 	struct jffs2_inode_info *f;
1659 	int ret;
1660 
1661 	D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
1662 
1663 	c = JFFS2_SB_INFO(sb);
1664 
1665 	if (CheckPermission(dir_i, WRITE_OP | EXEC_OP)) {
1666 		D1(PRINTK("%s, %d, check permission fail\n", __FUNCTION__, __LINE__));
1667 		return ERR_PTR(-EACCES);
1668 	}
1669 
1670 	jffs_lock();
1671 	inode = new_inode(sb);
1672 	if (!inode) {
1673 		jffs_unlock();
1674 		return ERR_PTR(-ENOMEM);
1675 	}
1676 
1677 	f = JFFS2_INODE_INFO(inode);
1678 	jffs2_init_inode_info(f);
1679 	(void)memset_s(ri, sizeof(*ri), 0, sizeof(*ri));
1680 	/* Set OS-specific defaults for new inodes */
1681 	ri->uid = cpu_to_je16(OsCurrUserGet()->effUserID);
1682 	ri->gid = cpu_to_je16(OsCurrUserGet()->effGid);
1683 	ri->mode =  cpu_to_jemode(mode);
1684 	ret = jffs2_do_new_inode (c, f, mode, ri);
1685 	if (ret) {
1686 		// forceful evict: f->sem is locked already, and the
1687 		// inode is bad.
1688 		if (inode->i_cache_prev)
1689 			   inode->i_cache_prev->i_cache_next = inode->i_cache_next;
1690 		if (inode->i_cache_next)
1691 			   inode->i_cache_next->i_cache_prev = inode->i_cache_prev;
1692 		mutex_unlock(&(f->sem));
1693 		jffs2_clear_inode(inode);
1694 		(void)mutex_destroy(&(f->sem));
1695 		(void)memset_s(inode, sizeof(*inode), 0x6a, sizeof(*inode));
1696 		free(inode);
1697 		jffs_unlock();
1698 		return ERR_PTR(ret);
1699 	}
1700 	inode->i_nlink = 1;
1701 	inode->i_ino = je32_to_cpu(ri->ino);
1702 	inode->i_mode = jemode_to_cpu(ri->mode);
1703 	inode->i_gid = je16_to_cpu(ri->gid);
1704 	inode->i_uid = je16_to_cpu(ri->uid);
1705 	inode->i_atime = inode->i_ctime = inode->i_mtime = jffs2_get_timestamp();
1706 	ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime);
1707 
1708 	inode->i_size = 0;
1709 	jffs_unlock();
1710 
1711 	return inode;
1712 }
1713 
1714 
jffs2_read_inode(struct _inode * inode)1715 static int jffs2_read_inode (struct _inode *inode)
1716 {
1717 	struct jffs2_inode_info *f;
1718 	struct jffs2_sb_info *c;
1719 	struct jffs2_raw_inode latest_node;
1720 	int ret;
1721 
1722 	D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
1723 
1724 	f = JFFS2_INODE_INFO(inode);
1725 	c = JFFS2_SB_INFO(inode->i_sb);
1726 
1727 	jffs2_init_inode_info(f);
1728 
1729 	ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
1730 
1731 	if (ret) {
1732 		(void)mutex_unlock(&f->sem);
1733 
1734 		return ret;
1735 	}
1736 	inode->i_mode = jemode_to_cpu(latest_node.mode);
1737 	inode->i_uid = je16_to_cpu(latest_node.uid);
1738 	inode->i_gid = je16_to_cpu(latest_node.gid);
1739 	inode->i_size = je32_to_cpu(latest_node.isize);
1740 	inode->i_atime = je32_to_cpu(latest_node.atime);
1741 	inode->i_mtime = je32_to_cpu(latest_node.mtime);
1742 	inode->i_ctime = je32_to_cpu(latest_node.ctime);
1743 
1744 	inode->i_nlink = f->inocache->pino_nlink;
1745 	mutex_unlock(&f->sem);
1746 
1747 	D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
1748 	return 0;
1749 }
1750 
1751 
jffs2_gc_release_inode(struct jffs2_sb_info * c,struct jffs2_inode_info * f)1752 void jffs2_gc_release_inode(struct jffs2_sb_info *c,
1753 		   struct jffs2_inode_info *f)
1754 {
1755 	jffs2_iput(OFNI_EDONI_2SFFJ(f));
1756 }
1757 
jffs2_gc_fetch_inode(struct jffs2_sb_info * c,int inum,int unlinked)1758 struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
1759 					 int inum, int unlinked)
1760 {
1761 	struct _inode *inode;
1762 	struct jffs2_inode_cache *ic;
1763 
1764 	if (unlinked) {
1765 		/* The inode has zero nlink but its nodes weren't yet marked
1766 		   obsolete. This has to be because we're still waiting for
1767 		   the final (close() and) jffs2_iput() to happen.
1768 
1769 		   There's a possibility that the final jffs2_iput() could have
1770 		   happened while we were contemplating. In order to ensure
1771 		   that we don't cause a new read_inode() (which would fail)
1772 		   for the inode in question, we use ilookup() in this case
1773 		   instead of jffs2_iget().
1774 
1775 		   The nlink can't _become_ zero at this point because we're
1776 		   holding the alloc_sem, and jffs2_do_unlink() would also
1777 		   need that while decrementing nlink on any inode.
1778 		*/
1779 		inode = ilookup(OFNI_BS_2SFFJ(c), inum);
1780 		if (!inode) {
1781 			D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
1782 				  inum));
1783 
1784 			spin_lock(&c->inocache_lock);
1785 			ic = jffs2_get_ino_cache(c, inum);
1786 			if (!ic) {
1787 				D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
1788 				spin_unlock(&c->inocache_lock);
1789 				return NULL;
1790 			}
1791 			if (ic->state != INO_STATE_CHECKEDABSENT) {
1792 				/* Wait for progress. Don't just loop */
1793 				D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
1794 					  ic->ino, ic->state));
1795 				sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
1796 			} else {
1797 				spin_unlock(&c->inocache_lock);
1798 			}
1799 
1800 			return NULL;
1801 		}
1802 	} else {
1803 		/* Inode has links to it still; they're not going away because
1804 		   jffs2_do_unlink() would need the alloc_sem and we have it.
1805 		   Just jffs2_iget() it, and if read_inode() is necessary that's OK.
1806 		*/
1807 		inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum);
1808 		if (IS_ERR(inode))
1809 			return (void *)inode;
1810 	}
1811 
1812 	return JFFS2_INODE_INFO(inode);
1813 }
jffs_check_path(const char * path)1814 static int jffs_check_path(const char *path)
1815 {
1816 	int n = 0;
1817 	int divs = 0;
1818 	while (*path && n < NAME_MAX && divs < 100) {  // File depth cannot exceed 100
1819 		if (jffsfs_IsPathDivider(*path)) {
1820 			n = 0;
1821 			divs++;
1822 		} else
1823 			n++;
1824 		path++;
1825 	}
1826 	return (*path) ? -1 : 0;
1827 }
1828 
jffs2_oflag_to_accmode(int oflags)1829 int jffs2_oflag_to_accmode(int oflags)
1830 {
1831 	/* regular file operations */
1832 	int acc_mode = 0;
1833 	if ((oflags & O_ACCMODE) == O_RDONLY) {
1834 		acc_mode |= READ_OP;
1835 	}
1836 
1837 	if (oflags & O_WRONLY) {
1838 		acc_mode |= WRITE_OP;
1839 	}
1840 
1841 	if (oflags & O_RDWR) {
1842 		acc_mode |= READ_OP | WRITE_OP;
1843 	}
1844 
1845 	/* Opens the file, if it is existing. If not, a new file is created. */
1846 	if (oflags & O_CREAT) {
1847 		acc_mode |= WRITE_OP;
1848 	}
1849 
1850 	/* Creates a new file. If the file is existing, it is truncated and overwritten. */
1851 	if (oflags & O_TRUNC) {
1852 		acc_mode |= WRITE_OP;
1853 	}
1854 
1855 	/* Creates a new file. The function fails if the file is already existing. */
1856 	if (oflags & O_EXCL) {
1857 		acc_mode |= WRITE_OP;
1858 	}
1859 
1860 	if (oflags & O_APPEND) {
1861 		acc_mode |= WRITE_OP;
1862 	}
1863 
1864 	/* mark for executing operation */
1865 	if (oflags & O_EXECVE) {
1866 		acc_mode |= EXEC_OP;
1867 	}
1868 
1869 	return acc_mode;
1870 }
1871 
CheckPermission(struct _inode * node,int accMode)1872 static unsigned int CheckPermission(struct _inode *node, int accMode)
1873 {
1874 	uint uid = OsCurrUserGet()->effUserID;
1875 	mode_t file_mode = node->i_mode;
1876 
1877 	if (uid == node->i_uid) {
1878 		file_mode >>= JFFS2_USER_SHFIT;
1879 	} else if (LOS_CheckInGroups(node->i_gid)) {
1880 		file_mode >>= JFFS2_GROUP_SHFIT;
1881 	}
1882 
1883 	file_mode &= JFFS2_MODE_ALL;
1884 
1885 	if ((accMode & file_mode) == accMode) {
1886 		return 0;
1887 	}
1888 
1889 	file_mode = 0;
1890 	if (S_ISDIR(node->i_mode)) {
1891 		if ((accMode & EXEC_OP) && (IsCapPermit(CAP_DAC_READ_SEARCH))) {
1892 			file_mode |= EXEC_OP;
1893 		}
1894 	} else {
1895 		if ((accMode & EXEC_OP) && (IsCapPermit(CAP_DAC_EXECUTE)) && (node->i_mode & S_IXUGO)) {
1896 			file_mode |= EXEC_OP;
1897 		}
1898 	}
1899 
1900 	if ((accMode & WRITE_OP) && IsCapPermit(CAP_DAC_WRITE)) {
1901 		file_mode |= WRITE_OP;
1902 	}
1903 
1904 	if ((accMode & READ_OP) && IsCapPermit(CAP_DAC_READ_SEARCH)) {
1905 		file_mode |= READ_OP;
1906 	}
1907 
1908 	if ((accMode & file_mode) == accMode) {
1909 		return 0;
1910 	}
1911 
1912 	D1(PRINTK("%s, %d, permission check fail,uid %d, gid %d, mode %d, accMode %d, cuid %d\n",
1913 		__FUNCTION__, __LINE__, node->i_uid, node->i_gid, (node->i_mode) & UMASK_FULL, accMode, uid));
1914 
1915 	return 1;
1916 }
1917 
check_to_setattr(struct jffs2_raw_inode * ri,struct jffs2_inode_info * f,const struct _inode * node,iattr * attr)1918 static int check_to_setattr(struct jffs2_raw_inode *ri, struct jffs2_inode_info *f,
1919 							const struct _inode *node, iattr *attr)
1920 {
1921 	unsigned int valid;
1922 	mode_t tmp_mode;
1923 	uint c_uid = OsCurrUserGet()->effUserID;
1924 	uint c_gid = OsCurrUserGet()->effGid;
1925 
1926 	valid = attr->attr_chg_valid;
1927 	ri->uid = cpu_to_je16(node->i_uid);
1928 	ri->gid = cpu_to_je16(node->i_gid);
1929 	tmp_mode = node->i_mode;
1930 	if (valid & CHG_UID) {
1931 		if (((c_uid != node->i_uid) || (attr->attr_chg_uid != node->i_uid)) && (!IsCapPermit(CAP_CHOWN))) {
1932 			return -EPERM;
1933 		} else {
1934 			ri->uid = cpu_to_je16(attr->attr_chg_uid);
1935 		}
1936 	}
1937 
1938 	if (valid & CHG_GID) {
1939 		if (((c_gid != node->i_gid) || (attr->attr_chg_gid != node->i_gid)) && (!IsCapPermit(CAP_CHOWN))) {
1940 			return -EPERM;
1941 		} else {
1942 			ri->gid = cpu_to_je16(attr->attr_chg_gid);
1943 		}
1944 	}
1945 
1946 	if (valid & CHG_MODE) {
1947 		if (!IsCapPermit(CAP_FOWNER) && (c_uid != node->i_uid)) {
1948 			return -EPERM;
1949 		} else {
1950 			attr->attr_chg_mode  &= ~S_IFMT; // delete file type
1951 			tmp_mode &= S_IFMT;
1952 			tmp_mode = attr->attr_chg_mode | tmp_mode; // add old file type
1953 		}
1954 	}
1955 	ri->mode = cpu_to_jemode(tmp_mode);
1956 	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
1957 	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
1958 	ri->totlen = cpu_to_je32(sizeof(*ri));
1959 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, (sizeof(struct jffs2_unknown_node)-4)));
1960 	ri->ino = cpu_to_je32(node->i_ino);
1961 	ri->version = cpu_to_je32(++f->highest_version);
1962 	ri->isize = cpu_to_je32((uint32_t)node->i_size);
1963 	ri->atime = cpu_to_je32(node->i_atime);
1964 	ri->mtime = cpu_to_je32(jffs2_get_timestamp());
1965 	ri->offset = cpu_to_je32(0);
1966 	ri->csize = ri->dsize = cpu_to_je32(0);
1967 	ri->compr = JFFS2_COMPR_NONE;
1968 	ri->node_crc = cpu_to_je32(crc32(0, ri, (sizeof(*ri)-8)));
1969 	ri->data_crc = cpu_to_je32(0);
1970 	return 0;
1971 }
1972 
jffs2_chattr(struct _inode * dir_i,const unsigned char * d_name,iattr * attr,struct _inode * node_old)1973 int jffs2_chattr (struct _inode *dir_i, const unsigned char *d_name, iattr *attr, struct _inode *node_old)
1974 {
1975 	struct jffs2_inode_info *f = NULL;
1976 	struct jffs2_sb_info *c = NULL;
1977 	struct jffs2_raw_inode *ri = NULL;
1978 	struct jffs2_full_dnode *new_metadata = NULL;
1979 	struct jffs2_full_dnode *old_metadata = NULL;
1980 	uint32_t alloclen;
1981 	int ret;
1982 	ri = jffs2_alloc_raw_inode();
1983 	if (!ri) {
1984 		set_errno(ENOMEM);
1985 		return -ENOMEM;
1986 	}
1987 	c = JFFS2_SB_INFO(dir_i->i_sb);
1988 	/* Try to reserve enough space for both node and dirent.
1989 	 * Just the node will do for now, though
1990 	 */
1991 	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
1992 	if (ret) {
1993 		jffs2_free_raw_inode(ri);
1994 		return ret;
1995 	}
1996 
1997 	f = JFFS2_INODE_INFO(node_old);
1998 	mutex_lock(&f->sem);
1999 	ret = check_to_setattr(ri, f, node_old, attr);
2000 
2001 	if (ret < 0) {
2002 		set_errno(-ret);
2003 		goto errout;
2004 	}
2005 	new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
2006 	if (IS_ERR(new_metadata)) {
2007 		ret = PTR_ERR(new_metadata);
2008 		set_errno(-ret);
2009 		goto errout;
2010 	}
2011 	node_old->i_atime = je32_to_cpu(ri->atime);
2012 	node_old->i_ctime = je32_to_cpu(ri->ctime);
2013 	node_old->i_mtime = je32_to_cpu(ri->mtime);
2014 	node_old->i_mode = jemode_to_cpu(ri->mode);
2015 	node_old->i_uid = je16_to_cpu(ri->uid);
2016 	node_old->i_gid = je16_to_cpu(ri->gid);
2017 
2018 	old_metadata = f->metadata;
2019 	f->metadata = new_metadata;
2020 	if (old_metadata) {
2021 		jffs2_mark_node_obsolete(c, old_metadata->raw);
2022 		jffs2_free_full_dnode(old_metadata);
2023 	}
2024 	jffs2_complete_reservation(c);
2025 	jffs2_free_raw_inode(ri);
2026 	mutex_unlock(&f->sem);
2027 	return 0;
2028 errout:
2029 	jffs2_complete_reservation(c);
2030 	jffs2_free_raw_inode(ri);
2031 	mutex_unlock(&f->sem);
2032 	return ret;
2033 }
2034 
2035 struct los_jffs2_operations jffs2_dir_operations = {
2036 	.opendir  =	jffs2_opendir,
2037 	.lseekdir = jffs2_fo_dirlseek,
2038 	.readdir  =	jffs2_fo_dirread,
2039 
2040 };
2041 
2042 struct los_jffs2_operations jffs2_fs_type = {
2043 	.mount  = jffs2_mount,
2044 	.stat   = jffs2_stat,
2045 	.umount = jffs2_umount
2046 };
2047 
2048 
2049 struct los_jffs2_operations jffs2_file_operations = {
2050 	.open   = jffs2_open,
2051 	.close  = jffs2_fo_close,
2052 	.read   = jffs2_fo_read,
2053 	.write  = jffs2_fo_write,
2054 	.lseek  = jffs2_fo_lseek,
2055 	.chattr = jffs2_fo_chattr
2056 };
2057 
2058 struct los_jffs2_operations jffs2_dir_inode_operations = {
2059 	.mkdir  = jffs2_ops_mkdir,
2060 	.rmdir  = jffs2_ops_rmdir,
2061 	.unlink = jffs2_ops_unlink,
2062 	.rename = jffs2_ops_rename,
2063 };
2064