dfs_jffs2.c 18.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * File      : rtthread.h
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006-2012, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE.
 *
 * Change Logs:
 * Date           Author       Notes
 * 2012-1-7       prife        the first version
*/
#include <rtthread.h>
15
#include <rtdevice.h>
16 17 18

#include "cyg/infra/cyg_type.h"
#include "cyg/fileio/fileio.h"
19 20
#include "port/codes.h"
#include "port/fcntl.h"
21 22 23 24 25
#undef mode_t

#include <dfs_fs.h>
#include <dfs_def.h>

26
#include "dfs_jffs2.h"
27
#include "jffs2_config.h"
28
#include "porting.h"
29
#include <string.h>
30 31 32 33 34

#if DEVICE_PART_MAX > 1
	#error "support only one jffs2 partition on a flash device!"
#endif
			
35
/* make sure the following struct var had been initilased to 0! */
36 37
struct device_part 
{
38
	struct cyg_mtab_entry * mte;
39
	struct rt_mtd_nor_device *dev;
40
};
41 42 43
static struct device_part device_partition[DEVICE_PART_MAX] = {0};

static struct rt_mutex jffs2_lock;
44 45 46 47

#define jffs2_mount   jffs2_fste.mount
#define jffs2_umount  jffs2_fste.umount
#define jffs2_open    jffs2_fste.open
48
#define jffs2_file_unlink  jffs2_fste.unlink
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
#define jffs2_mkdir   jffs2_fste.mkdir
#define jffs2_rmdir   jffs2_fste.rmdir
#define jffs2_rename  jffs2_fste.rename
#define jffs2_link    jffs2_fste.link
#define jffs2_opendir jffs2_fste.opendir
#define jffs2_chdir   jffs2_fste.chdir
#define jffs2_ops_stat    jffs2_fste.stat
#define jffs2_getinfo jffs2_fste.getinfo
#define jffs2_setinfo jffs2_fste.setinfo

#define jffs2_file_read    jffs2_fileops.fo_read
#define jffs2_file_write   jffs2_fileops.fo_write
#define jffs2_file_lseek   jffs2_fileops.fo_lseek
#define jffs2_file_ioctl   jffs2_fileops.fo_ioctl
#define jffs2_file_select  jffs2_fileops.fo_select
#define jffs2_file_fsync   jffs2_fileops.fo_fsync
#define jffs2_file_colse   jffs2_fileops.fo_close
#define jffs2_file_fstat   jffs2_fileops.fo_fstat
#define jffs2_file_getinfo jffs2_fileops.fo_getinfo
#define jffs2_file_setinfo jffs2_fileops.fo_setinfo

#define jffs2_dir_read    jffs2_dirops.fo_read
//#define jffs2_dir_write   jffs2_dirops.fo_write
#define jffs2_dir_lseek   jffs2_dirops.fo_lseek
//#define jffs2_dir_ioctl   jffs2_dirops.fo_ioctl
#define jffs2_dir_select  jffs2_dirops.fo_select
//#define jffs2_dir_fsync   jffs2_dirops.fo_fsync
#define jffs2_dir_colse   jffs2_dirops.fo_close
//#define jffs2_dir_fstat   jffs2_dirops.fo_fstat
//#define jffs2_dir_getinfo jffs2_dirops.fo_getinfo
//#define jffs2_dir_setinfo jffs2_dirops.fo_setinfo

/*
 * RT-Thread Device Interface for jffs2
 */

/* these code is in src/flashio.c */ 
static int jffs2_result_to_dfs(int result)
{
	int status = -1;

90 91 92
	if (result < 0)
		result = -result;

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
	switch (result)
	{
	case ENOERR:/** no error */
		break;
	case EACCES:/** Tried to open read-only file for writing, or files sharing mode
				   does not allow specified operations, or given path is directory */
		status = -DFS_STATUS_EINVAL;
		break;/* no suitable */
	case EEXIST:   /** _O_CREAT and _O_EXCL flags specified, but filename already exists */
		status = -DFS_STATUS_EEXIST;
		break;
	case EINVAL:  /** Invalid oflag or pmode argument */
		status = -DFS_STATUS_EINVAL;
		break;
	case EMFILE: /** No more file handles available(too many open files)  */
108
		rt_kprintf("dfs_jffs2.c error: no more file handles available\r\n");
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
		status = -1;
		break;//fixme
	case ENOENT: /** file or path not found */
		status = -DFS_STATUS_ENOENT;
		break;
	case EBADF: /** invalid file handle */
		status = -DFS_STATUS_EBADF;
		break;
	case ENOMEM:/** no enough memory */
		status = -DFS_STATUS_ENOMEM;
		break;
	case EIO: /** I/O error from lower level flash operation */
		status = -DFS_STATUS_EIO;
		break;
	case ENOTDIR: /** Not a directory */
		status = -DFS_STATUS_ENOTDIR;
		break;
	case EISDIR: /** Is a directory */
		status = -DFS_STATUS_EISDIR;
		break;
129 130 131 132
	case ENOSPC: /**//* No space left on device */
		status = -DFS_STATUS_ENOSPC;
		break;

133
	default:
134
		rt_kprintf("dfs_jffs2.c error: %d\r\n", result);
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
		status = -1;
		break; /* unknown error! */
	}

	return status;
}

/*
 * RT-Thread DFS Interface for jffs2
 */
static int dfs_jffs2_mount(struct dfs_filesystem* fs, 
                    unsigned long rwflag, 
				    const void* data)
{
	unsigned index;
	struct cyg_mtab_entry * mte;
	int result;

	/* find a empty entry in partition table */
	for (index = 0; index < DEVICE_PART_MAX; index ++)
	{
		if (device_partition[index].dev == RT_NULL)
			break;
	}
	if (index == DEVICE_PART_MAX) 
		return -DFS_STATUS_ENOSPC;

	mte = rt_malloc(sizeof(struct cyg_mtab_entry));
	if (mte == RT_NULL)
		return -DFS_STATUS_ENOMEM;

	mte->name = fs->path;
	mte->fsname = "jffs2";
	mte->devname = NULL;
	/* note that, i use mte->data to store rtt's device 
	 * while, in jffs2_mount, mte->data will be copy into
	 * s_dev in struct super_block, and mte->data will be
	 * filled with jffs2_sb(see the source of jffs2_mount.
	 */
174
	mte->data = (CYG_ADDRWORD)fs->dev_id;
175

176
	device_partition[index].dev = RT_MTD_NOR_DEVICE(fs->dev_id);
177 178 179 180
	/* after jffs2_mount, mte->data will not be dev_id any more */
	result = jffs2_mount(NULL, mte);
	if (result != 0)
	{	
P
prife 已提交
181
		device_partition[index].dev = NULL;
182 183 184
		return jffs2_result_to_dfs(result);
	}
	/* save this pointer */
185
	device_partition[index].mte = mte;	
186 187 188 189 190 191 192 193 194
	return 0;
}

static int _find_fs(struct cyg_mtab_entry ** mte, rt_device_t dev_id)
{
	unsigned index;	
	/* find device index */
	for (index = 0; index < DEVICE_PART_MAX; index++)
	{
195
		if (device_partition[index].dev == RT_MTD_NOR_DEVICE(dev_id))
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
		{
			*mte = device_partition[index].mte;
			return 0;
		}
	}
	rt_kprintf("error, could not found the fs!");
	return -1;
}

static int dfs_jffs2_unmount(struct dfs_filesystem* fs)
{
	int result;
	unsigned index;
	/* find device index, then umount it */
	for (index = 0; index < DEVICE_PART_MAX; index++)
	{
212
		if (device_partition[index].dev == RT_MTD_NOR_DEVICE(fs->dev_id))
213 214 215 216 217 218 219 220 221 222 223 224 225
		{
			result = jffs2_umount(device_partition[index].mte);
			if (result)
				return jffs2_result_to_dfs(result);	
			rt_free(device_partition[index].mte);
			device_partition[index].dev = NULL;	
			device_partition[index].mte = NULL;
			return DFS_STATUS_OK;
		}
	}
	return -DFS_STATUS_ENOENT;
}

226
static int dfs_jffs2_mkfs(rt_device_t dev_id)
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
{
	/* just erase all blocks on this nand partition */
	return -DFS_STATUS_ENOSYS; 
}

static int dfs_jffs2_statfs(struct dfs_filesystem* fs, 
                     struct statfs *buf)
{
	/* since the limit of unsigned long, so the max size of flash device is 4G */
	struct cyg_mtab_entry * mte;
	struct jffs2_fs_info info;
	int result;
	
	result = _find_fs(&mte, fs->dev_id);
	if (result)
		return -DFS_STATUS_ENOENT;
		
	RT_ASSERT(mte->data != NULL);

246
	jffs2_get_info_from_sb((void *)mte->data, &info);
247 248
	buf->f_bsize = info.sector_size; 
	buf->f_blocks = info.nr_blocks;
249
	buf->f_bfree = info.free_size / info.sector_size;
250 251 252 253 254 255 256 257 258 259 260 261
	
	return 0;
}

static const char jffs2_root_path[] = ".";

static int dfs_jffs2_open(struct dfs_fd* file)
{
	int oflag, mode;
	int result;
	cyg_file * jffs2_file;		
	struct cyg_mtab_entry * mte;
262
	const char * name;
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285

	oflag = file->flags;

	jffs2_file = rt_malloc(sizeof(cyg_file));
	if (jffs2_file == RT_NULL)
		return -DFS_STATUS_ENOMEM;

	/* just escape '/' provided by dfs code */
	name = file->path;
	if ((name[0] == '/') && (name[1] == 0))
		name = jffs2_root_path;
	else /* name[0] still will be '/' */
		name ++;
		
	result = _find_fs(&mte, file->fs->dev_id);		
	if (result) 
	{
		rt_free(jffs2_file);
		return -DFS_STATUS_ENOENT;
	}
 	
	if (oflag & DFS_O_DIRECTORY) /* operations about dir */
	{	
286
		rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
287 288 289 290 291
		if (oflag & DFS_O_CREAT) /* create a dir*/
		{	
			/* fixme, should test file->path can end with '/' */
			result = jffs2_mkdir(mte, mte->root, name);
			if (result)
292
			{
293
				rt_mutex_release(&jffs2_lock);
294
				rt_free(jffs2_file);
295
				return jffs2_result_to_dfs(result);
296
			}
297 298 299
		}	
		/* open dir */
		result = jffs2_opendir(mte, mte->root, name, jffs2_file);
300
		rt_mutex_release(&jffs2_lock);
301
		if (result)
302
		{
303
			rt_free(jffs2_file);
304
			return jffs2_result_to_dfs(result);			
305 306 307 308
		}
#ifdef  CONFIG_JFFS2_NO_RELATIVEDIR
		jffs2_file->f_offset = 2;
#endif
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
		/* save this pointer, it will be used by dfs_jffs2_getdents*/
		file->data = jffs2_file;
		return 0;
	} 
	/* regular file operations */
	mode = 0;
	if (oflag & DFS_O_RDONLY) mode |= JFFS2_O_RDONLY;
	if (oflag & DFS_O_WRONLY) mode |= JFFS2_O_WRONLY;
	if (oflag & DFS_O_RDWR)   mode |= JFFS2_O_RDWR;
	/* Opens the file, if it is existing. If not, a new file is created. */
	if (oflag & DFS_O_CREAT) mode |= JFFS2_O_CREAT;
	/* Creates a new file. If the file is existing, it is truncated and overwritten. */
	if (oflag & DFS_O_TRUNC) mode |= JFFS2_O_TRUNC;
	/* Creates a new file. The function fails if the file is already existing. */
	if (oflag & DFS_O_EXCL) mode |= JFFS2_O_EXCL;
324
//	if (oflag & DFS_O_APPEND) mode |= JFFS2_O_APPEND;
325
	rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
326 327 328
    result = jffs2_open(mte, 0, name, mode, jffs2_file);
    if (result != 0)
    {
329
    	rt_mutex_release(&jffs2_lock);
330 331 332 333 334 335 336 337 338
		rt_free(jffs2_file);
		return jffs2_result_to_dfs(result);
    }
	
	/* save this pointer, it will be used when calling read()write(), 
	flush(), lessk(), and will be rt_free when calling close()*/
	file->data = jffs2_file;
	file->pos = jffs2_file->f_offset; 
	file->size = 0;
339
	jffs2_file_lseek(jffs2_file, (off_t *)(&(file->size)), DFS_SEEK_END);
340
	jffs2_file->f_offset = (off_t)file->pos;
341
	rt_mutex_release(&jffs2_lock);
342
	
343
	if (oflag & DFS_O_APPEND)
344
	{
345
		file->pos = file->size;	
346 347 348
 		jffs2_file->f_offset = file->size;
	}	
	return 0; 
349
}				   
350 351 352 353 354 355 356 357 358 359 360

static int dfs_jffs2_close(struct dfs_fd* file)
{
	int result;
	cyg_file * jffs2_file;
	
	RT_ASSERT(file->data != NULL);
	jffs2_file = (cyg_file *)(file->data);
	
	if (file->flags & DFS_O_DIRECTORY) /* operations about dir */
	{
361
		rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
362
		result = jffs2_dir_colse(jffs2_file);
363
		rt_mutex_release(&jffs2_lock);
364 365
		if (result)
			return jffs2_result_to_dfs(result);	
366 367

		rt_free(jffs2_file);
368 369 370
		return 0;
	}
	/* regular file operations */
371
	rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
372
	result = jffs2_file_colse(jffs2_file);
373
	rt_mutex_release(&jffs2_lock);
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
	if (result)
		return jffs2_result_to_dfs(result);	
	
	/* release memory */
	rt_free(jffs2_file);
	return 0;
}

static int dfs_jffs2_ioctl(struct dfs_fd* file, int cmd, void* args)
{
	return -DFS_STATUS_ENOSYS;
}

static int dfs_jffs2_read(struct dfs_fd* file, void* buf, rt_size_t len)
{
	cyg_file * jffs2_file;
	struct CYG_UIO_TAG uio_s;
	struct CYG_IOVEC_TAG iovec;
	int char_read;
	int result;
	
	RT_ASSERT(file->data != NULL);
	jffs2_file = (cyg_file *)(file->data);	
    uio_s.uio_iov = &iovec;
    uio_s.uio_iov->iov_base = buf;
    uio_s.uio_iov->iov_len = len;
    uio_s.uio_iovcnt = 1; //must be 1
    //uio_s.uio_offset //not used...
    uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;
	
	char_read = jffs2_file->f_offset; /* the current offset */	
405
	rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
406
	result = jffs2_file_read(jffs2_file, &uio_s);	
407
	rt_mutex_release(&jffs2_lock);
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
	if (result)
		return jffs2_result_to_dfs(result);	
	
	/* update position */
	file->pos = jffs2_file->f_offset;
	char_read = jffs2_file->f_offset - char_read;
	return char_read;
}

static int dfs_jffs2_write(struct dfs_fd* file, 
                    const void* buf, 
					rt_size_t len)
{
	cyg_file * jffs2_file;
	struct CYG_UIO_TAG uio_s;
	struct CYG_IOVEC_TAG iovec;
	int char_write;
	int result;
	
	RT_ASSERT(file->data != NULL);
	jffs2_file = (cyg_file *)(file->data);	
    uio_s.uio_iov = &iovec;
430
    uio_s.uio_iov->iov_base = (void *)buf;
431 432 433 434 435 436
    uio_s.uio_iov->iov_len = len;
    uio_s.uio_iovcnt = 1; //must be 1
    //uio_s.uio_offset //not used...
    uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;
	
	char_write = jffs2_file->f_offset;
437
	rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
438
	result = jffs2_file_write(jffs2_file, &uio_s);
439
	rt_mutex_release(&jffs2_lock);
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
	if (result)
		return jffs2_result_to_dfs(result);
	
	/* update position */
	file->pos = jffs2_file->f_offset;	
	char_write = jffs2_file->f_offset - char_write;
	return char_write;
}

static int dfs_jffs2_flush(struct dfs_fd* file)
{
	/* infact, jffs2 not support, jffs2_fo_sync just return ok */
	return -DFS_STATUS_ENOSYS;
}

/* fixme warning: the offset is rt_off_t, so maybe the size of a file is must <= 2G*/
static int dfs_jffs2_lseek(struct dfs_fd* file, 
                    rt_off_t offset)
{
	cyg_file * jffs2_file;
	int result;
	
	RT_ASSERT(file->data != NULL);
	jffs2_file = (cyg_file *)(file->data);		
	
	/* set offset as current offset */
466
	rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
467
	result = jffs2_file_lseek(jffs2_file, &offset, DFS_SEEK_SET);
468
	rt_mutex_release(&jffs2_lock);
469 470
	if (result)
		return jffs2_result_to_dfs(result);
471 472 473
	/* update file position */
	file->pos = offset;
	return offset;
474 475 476 477 478 479 480 481 482 483 484 485
}

/* return the size of  struct dirent*/
static int dfs_jffs2_getdents(struct dfs_fd* file, 
                       struct dirent* dirp, 
					   rt_uint32_t count)
{
	cyg_file * jffs2_file;
	struct CYG_UIO_TAG uio_s;
	struct CYG_IOVEC_TAG iovec;
	struct jffs2_dirent jffs2_d;
	struct dirent * d;
486
	rt_uint32_t index;
487 488 489 490 491
#if !defined (CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE)
	struct jffs2_stat s;
	cyg_mtab_entry * mte;
	char * fullname;
#endif
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
	int result;
	
	RT_ASSERT(file->data != RT_NULL);	
	jffs2_file = (cyg_file*)(file->data);
	
	//set jffs2_d
	memset(&jffs2_d, 0, sizeof(struct jffs2_dirent));
	//set CYG_UIO_TAG uio_s
	uio_s.uio_iov = &iovec;
	uio_s.uio_iov->iov_base = &jffs2_d;
	uio_s.uio_iov->iov_len = sizeof(struct jffs2_dirent);;
	uio_s.uio_iovcnt = 1; //must be 1
	uio_s.uio_offset = 0;//not used...
	uio_s.uio_resid = uio_s.uio_iov->iov_len; //seem no use in jffs2;	

507 508 509 510 511 512 513
#if !defined (CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE)

	result = _find_fs(&mte, file->fs->dev_id);
	if (result)
		return -DFS_STATUS_ENOENT;
#endif

514 515 516 517 518 519 520 521 522 523
	/* make integer count, usually count is 1 */
	count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
	if (count == 0) 
		return -DFS_STATUS_EINVAL;

	index = 0;
	/* usually, the while loop should only be looped only once! */
	while (1)
	{
		d = dirp + index;
524
		rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
525
		result = jffs2_dir_read(jffs2_file, &uio_s); 
526
		rt_mutex_release(&jffs2_lock);
527 528 529 530
		/* if met a error or all entry are read over, break while*/
		if (result || jffs2_d.d_name[0] == 0)
			break;

531
#if defined (CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE)
532 533 534 535 536 537
		switch(jffs2_d.d_type & JFFS2_S_IFMT) 
		{ 
		case JFFS2_S_IFREG: d->d_type = DFS_DT_REG; break; 		
		case JFFS2_S_IFDIR: d->d_type = DFS_DT_DIR; break; 
		default: d->d_type = DFS_DT_UNKNOWN; break; 
		} 	
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
#else
		fullname = rt_malloc(FILE_PATH_MAX);
		if(fullname == RT_NULL)
				return -DFS_STATUS_ENOMEM;

		/* make a right entry */
		if ((file->path[0] == '/') )
		{
			if (file->path[1] == 0)
				strcpy(fullname, jffs2_d.d_name);
			else
				rt_sprintf(fullname, "%s/%s", file->path+1, jffs2_d.d_name);
		}
		else
			rt_sprintf(fullname, "%s/%s", file->path, jffs2_d.d_name);
553
		rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
554
		result = jffs2_porting_stat(mte, mte->root, fullname, (void *)&s);
555
		rt_mutex_release(&jffs2_lock);
556 557 558 559 560 561 562 563 564 565 566 567 568
		if (result)
			return jffs2_result_to_dfs(result);

		rt_free(fullname);
		/* convert to dfs stat structure */
		switch(s.st_mode & JFFS2_S_IFMT)
		{
		case JFFS2_S_IFREG: d->d_type = DFS_DT_REG; break;
		case JFFS2_S_IFDIR: d->d_type = DFS_DT_DIR; break;
		default: d->d_type = DFS_DT_UNKNOWN; break;
		}
#endif
		/* write the rest fields of struct dirent* dirp  */
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
		d->d_namlen = rt_strlen(jffs2_d.d_name);
		d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
		rt_strncpy(d->d_name, jffs2_d.d_name, d->d_namlen + 1);
		
		index ++;
		if (index * sizeof(struct dirent) >= count)
			break;
	}
	if (result)
		return jffs2_result_to_dfs(result);
	return index * sizeof(struct dirent);
}

static int dfs_jffs2_unlink(struct dfs_filesystem* fs, const char* path)
{
	int result;
	struct jffs2_stat s;
	cyg_mtab_entry * mte;
			
	result = _find_fs(&mte, fs->dev_id);		
	if (result) 
		return -DFS_STATUS_ENOENT;
		
	/* deal path */
	if (path[0] == '/')
		path++;
	
	/* judge file type, dir is to be delete by rmdir, others by unlink */
597
	rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
598
	result = jffs2_porting_stat(mte, mte->root, path, (void *)&s);
599
	if (result)
600 601
	{
		rt_mutex_release(&jffs2_lock);
602
		return jffs2_result_to_dfs(result);
603 604
	}

605 606 607
	switch(s.st_mode & JFFS2_S_IFMT)
	{
	case JFFS2_S_IFREG:
608
		result = jffs2_file_unlink(mte, mte->root, path);
609 610 611 612 613 614
		break;
	case JFFS2_S_IFDIR:
		result = jffs2_rmdir(mte, mte->root, path);
		break;
	default:
		/* unknown file type */
615
		rt_mutex_release(&jffs2_lock);
616 617
		return -1;
	}
618
	rt_mutex_release(&jffs2_lock);
619 620 621 622 623 624 625 626 627 628 629 630 631 632
	if (result) 
		return jffs2_result_to_dfs(result);
	return 0;			
}

static int dfs_jffs2_rename(struct dfs_filesystem* fs, 
                     const char* oldpath,
					 const char* newpath)
{
	int result;
	cyg_mtab_entry * mte;
			
	result = _find_fs(&mte, fs->dev_id);		
	if (result) 
633
		return -DFS_STATUS_ENOENT;
634 635 636 637
			
	if (*oldpath == '/')
		oldpath += 1;
	if (*newpath == '/')
638
		newpath += 1;
639
	rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
640
	result = jffs2_rename(mte, mte->root, oldpath, mte->root, newpath);
641
	rt_mutex_release(&jffs2_lock);
642 643 644 645 646 647 648 649 650
	if (result)
		return jffs2_result_to_dfs(result);
	return 0;
}

static int dfs_jffs2_stat(struct dfs_filesystem* fs, const char *path, struct stat *st)
{
	int result;
	struct jffs2_stat s;
651
	cyg_mtab_entry * mte;
652 653 654 655 656
		
	/* deal the path for jffs2 */
	RT_ASSERT(!((path[0] == '/') && (path[1] == 0)));
	
	if (path[0] == '/')
657 658
		path++;

659 660
	result = _find_fs(&mte, fs->dev_id);		
	if (result) 
661 662
		return -DFS_STATUS_ENOENT;

663
	rt_mutex_take(&jffs2_lock, RT_WAITING_FOREVER);
664
	result = jffs2_porting_stat(mte, mte->root, path, (void *)&s);
665
	rt_mutex_release(&jffs2_lock);
666 667 668 669 670 671 672 673 674

	if (result)
		return jffs2_result_to_dfs(result);
	/* convert to dfs stat structure */
	switch(s.st_mode & JFFS2_S_IFMT) 
	{ 
	case JFFS2_S_IFREG: 
		st->st_mode = DFS_S_IFREG | DFS_S_IRUSR | DFS_S_IRGRP | DFS_S_IROTH |
		DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH;
675
		break;
676 677

	case JFFS2_S_IFDIR:
678 679
		st->st_mode = DFS_S_IFDIR | DFS_S_IXUSR | DFS_S_IXGRP | DFS_S_IXOTH;
		break;		
680

681 682
	default: 
		st->st_mode = DFS_DT_UNKNOWN; //fixme
683
		break; 
684
	} 	
685 686 687 688

	st->st_dev  = 0;
	st->st_size = s.st_size;
	st->st_mtime = s.st_mtime;
689
	st->st_blksize = 1;//fixme: what's this field?
690 691 692 693 694 695 696

	return 0;
}

static const struct dfs_filesystem_operation dfs_jffs2_ops = 
{
	"jffs2", /* file system type: jffs2 */
697
#if RTTHREAD_VERSION >= 10100
698
	DFS_FS_FLAG_DEFAULT, /* use Relative Path */
699
#endif
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
	dfs_jffs2_mount,
	dfs_jffs2_unmount,
	dfs_jffs2_mkfs,
	dfs_jffs2_statfs,

	dfs_jffs2_open,
	dfs_jffs2_close,
	dfs_jffs2_ioctl,
	dfs_jffs2_read,
	dfs_jffs2_write,
	dfs_jffs2_flush,
	dfs_jffs2_lseek,
	dfs_jffs2_getdents,
	dfs_jffs2_unlink,
	dfs_jffs2_stat,
	dfs_jffs2_rename,
};

int dfs_jffs2_init(void)
{
    /* register fatfs file system */
    dfs_register(&dfs_jffs2_ops);
722 723 724 725 726 727
    /* initialize mutex */
	if (rt_mutex_init(&jffs2_lock, "jffs2lock", RT_IPC_FLAG_FIFO) != RT_EOK)
	{
		rt_kprintf("init jffs2 lock mutex failed\n");
	}
	rt_kprintf("init jffs2 lock mutex okay\n");
728 729
	return 0;
}
B
Bernard Xiong 已提交
730 731
INIT_FS_EXPORT(dfs_jffs2_init);