1 /*
2 This file is part of UFFS, the Ultra-low-cost Flash File System.
3
4 Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5
6 UFFS is free software; you can redistribute it and/or modify it under
7 the GNU Library General Public License as published by the Free Software
8 Foundation; either version 2 of the License, or (at your option) any
9 later version.
10
11 UFFS is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 or GNU Library General Public License, as applicable, for more details.
15
16 You should have received a copy of the GNU General Public License
17 and GNU Library General Public License along with UFFS; if not, write
18 to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 As a special exception, if other files instantiate templates or use
22 macros or inline functions from this file, or you compile this file
23 and link it with other works to produce a work based on this file,
24 this file does not by itself cause the resulting work to be covered
25 by the GNU General Public License. However the source code for this
26 file must still be made available in accordance with section (3) of
27 the GNU General Public License v2.
28
29 This exception does not invalidate any other reasons why a work based
30 on this file might be covered by the GNU General Public License.
31 */
32
33 /**
34 * \file uffs_fd.c
35 * \brief POSIX like, hight level file operations
36 * \author Ricky Zheng, created 8th Jun, 2005
37 */
38
39 #include <string.h>
40 #include "uffs_config.h"
41 #include "uffs/uffs_fs.h"
42 #include "uffs/uffs_fd.h"
43 #include "uffs/uffs_utils.h"
44 #include "uffs/uffs_version.h"
45 #include "uffs/uffs_mtb.h"
46 #include "uffs/uffs_public.h"
47 #include "uffs/uffs_find.h"
48
49 #define PFX "fd : "
50
51 /**
52 * \brief POSIX DIR
53 */
54 struct uffs_dirSt {
55 struct uffs_ObjectSt *obj; /* dir object */
56 struct uffs_FindInfoSt f; /* find info */
57 struct uffs_ObjectInfoSt info; /* object info */
58 struct uffs_dirent dirent; /* dir entry */
59 };
60
61
62 #define FD_OFFSET 3 //!< just make file handler more like POSIX (0, 1, 2 for stdin/stdout/stderr)
63
64 #define OBJ2FD(obj) \
65 ( \
66 ( \
67 uffs_PoolGetIndex(uffs_GetObjectPool(), obj) | \
68 (_fd_signature << FD_SIGNATURE_SHIFT) \
69 ) \
70 + FD_OFFSET \
71 )
72
73 /**
74 * check #fd signature, convert #fd to #obj
75 * if success, hold global file system lock, otherwise return with #ret
76 */
77 #define CHK_OBJ_LOCK(fd, obj, ret) \
78 do { \
79 uffs_GlobalFsLockLock(); \
80 fd -= FD_OFFSET; \
81 if ( (fd >> FD_SIGNATURE_SHIFT) != _fd_signature ) { \
82 uffs_set_error(-UEBADF); \
83 uffs_Perror(UFFS_MSG_NOISY, "invalid fd: %d (sig: %d, expect: %d)", \
84 fd + FD_OFFSET, fd >> FD_SIGNATURE_SHIFT, _fd_signature); \
85 uffs_GlobalFsLockUnlock(); \
86 return (ret); \
87 } \
88 fd = fd & ((1 << FD_SIGNATURE_SHIFT) - 1); \
89 obj = (uffs_Object *)uffs_PoolGetBufByIndex(uffs_GetObjectPool(), fd); \
90 if ((obj) == NULL || \
91 uffs_PoolVerify(uffs_GetObjectPool(), (obj)) == U_FALSE || \
92 uffs_PoolCheckFreeList(uffs_GetObjectPool(), (obj)) == U_TRUE) { \
93 uffs_set_error(-UEBADF); \
94 uffs_Perror(UFFS_MSG_NOISY, "invalid obj"); \
95 uffs_GlobalFsLockUnlock(); \
96 return (ret); \
97 } \
98 } while(0)
99
100 /**
101 * check #dirp signature,
102 * if success, hold global file system lock,
103 * otherwise return with #ret
104 */
105 #define CHK_DIR_LOCK(dirp, ret) \
106 do { \
107 uffs_GlobalFsLockLock(); \
108 if ((dirp) == NULL || \
109 uffs_PoolVerify(&_dir_pool, (dirp)) == U_FALSE || \
110 uffs_PoolCheckFreeList(&_dir_pool, (dirp)) == U_TRUE) { \
111 uffs_set_error(-UEBADF); \
112 uffs_Perror(UFFS_MSG_NOISY, "invalid dirp"); \
113 uffs_GlobalFsLockUnlock(); \
114 return (ret); \
115 } \
116 } while(0)
117
118 /**
119 * check #dirp signature,
120 * if success, hold global file system lock,
121 * otherwise return void
122 */
123 #define CHK_DIR_VOID_LOCK(dirp) \
124 do { \
125 uffs_GlobalFsLockLock(); \
126 if ((dirp) == NULL || \
127 uffs_PoolVerify(&_dir_pool, (dirp)) == U_FALSE || \
128 uffs_PoolCheckFreeList(&_dir_pool, (dirp)) == U_TRUE) { \
129 uffs_set_error(-UEBADF); \
130 uffs_Perror(UFFS_MSG_NOISY, "invalid dirp"); \
131 uffs_GlobalFsLockUnlock(); \
132 return; \
133 } \
134 } while(0)
135
136
137 static int _dir_pool_data[sizeof(uffs_DIR) * MAX_DIR_HANDLE / sizeof(int)];
138 static uffs_Pool _dir_pool;
139 static int _uffs_errno = 0;
140
141
142 //
143 // What is fd signature ? fd signature is for detecting file system get formated by other party.
144 // A thread open a file, read()...sleep()...write()...sleep()...
145 // B thread format UFFS partition, increase fd signature.
146 // A thread ...sleep()...read() --> Opps, fd signature changed ! read() return error(expected).
147 //
148 #define MAX_FD_SIGNATURE_ROUND (100)
149 static int _fd_signature = 0;
150
151 //
152 // only get called when formating UFFS partition
153 //
uffs_FdSignatureIncrease(void)154 void uffs_FdSignatureIncrease(void)
155 {
156 if (_fd_signature++ > MAX_FD_SIGNATURE_ROUND)
157 _fd_signature = 0;
158 }
159
160 /**
161 * initialise uffs_DIR buffers, called by UFFS internal
162 */
uffs_DirEntryBufInit(void)163 URET uffs_DirEntryBufInit(void)
164 {
165 return uffs_PoolInit(&_dir_pool, _dir_pool_data,
166 sizeof(_dir_pool_data),
167 sizeof(uffs_DIR), MAX_DIR_HANDLE);
168 }
169
170 /**
171 * Release uffs_DIR buffers, called by UFFS internal
172 */
uffs_DirEntryBufRelease(void)173 URET uffs_DirEntryBufRelease(void)
174 {
175 return uffs_PoolRelease(&_dir_pool);
176 }
177
178 /**
179 * Put all dir entry buf match dev
180 */
uffs_DirEntryBufPutAll(uffs_Device * dev)181 int uffs_DirEntryBufPutAll(uffs_Device *dev)
182 {
183 int count = 0;
184 uffs_DIR *dirp = NULL;
185
186 do {
187 dirp = (uffs_DIR *) uffs_PoolFindNextAllocated(&_dir_pool, dirp);
188 if (dirp && dirp->obj && dirp->obj->dev &&
189 dirp->obj->dev->dev_num == dev->dev_num) {
190 uffs_PoolPut(&_dir_pool, dirp);
191 count++;
192 }
193 } while (dirp);
194
195 return count;
196 }
197
198
uffs_DirEntryBufGetPool(void)199 uffs_Pool * uffs_DirEntryBufGetPool(void)
200 {
201 return &_dir_pool;
202 }
203
GetDirEntry(void)204 static uffs_DIR * GetDirEntry(void)
205 {
206 uffs_DIR *dirp = (uffs_DIR *) uffs_PoolGet(&_dir_pool);
207
208 if (dirp)
209 memset(dirp, 0, sizeof(uffs_DIR));
210
211 return dirp;
212 }
213
PutDirEntry(uffs_DIR * p)214 static void PutDirEntry(uffs_DIR *p)
215 {
216 uffs_PoolPut(&_dir_pool, p);
217 }
218
219
220 /** get global errno
221 */
uffs_get_error(void)222 int uffs_get_error(void)
223 {
224 return _uffs_errno;
225 }
226
227 /** set global errno
228 */
uffs_set_error(int err)229 int uffs_set_error(int err)
230 {
231 return (_uffs_errno = err);
232 }
233
234 /* POSIX compliant file system APIs */
235
uffs_open(const char * name,int oflag,...)236 int uffs_open(const char *name, int oflag, ...)
237 {
238 uffs_Object *obj;
239 int ret = 0;
240
241 uffs_GlobalFsLockLock();
242
243 obj = uffs_GetObject();
244 if (obj == NULL) {
245 uffs_set_error(-UEMFILE);
246 ret = -1;
247 }
248 else {
249 if (uffs_OpenObject(obj, name, oflag) == U_FAIL) {
250 uffs_set_error(-uffs_GetObjectErr(obj));
251 uffs_PutObject(obj);
252 ret = -1;
253 }
254 else {
255 ret = OBJ2FD(obj);
256 }
257 }
258
259 uffs_GlobalFsLockUnlock();
260
261 return ret;
262 }
263
uffs_close(int fd)264 int uffs_close(int fd)
265 {
266 int ret = 0;
267 uffs_Object *obj;
268
269 CHK_OBJ_LOCK(fd, obj, -1);
270
271 uffs_ClearObjectErr(obj);
272 if (uffs_CloseObject(obj) == U_FAIL) {
273 uffs_set_error(-uffs_GetObjectErr(obj));
274 ret = -1;
275 }
276 else {
277 uffs_PutObject(obj);
278 ret = 0;
279 }
280
281 uffs_GlobalFsLockUnlock();
282
283 return ret;
284 }
285
uffs_read(int fd,void * data,int len)286 int uffs_read(int fd, void *data, int len)
287 {
288 int ret;
289 uffs_Object *obj;
290
291 CHK_OBJ_LOCK(fd, obj, -1);
292 uffs_ClearObjectErr(obj);
293 ret = uffs_ReadObject(obj, data, len);
294 uffs_set_error(-uffs_GetObjectErr(obj));
295
296 uffs_GlobalFsLockUnlock();
297
298 return ret;
299 }
300
uffs_write(int fd,const void * data,int len)301 int uffs_write(int fd, const void *data, int len)
302 {
303 int ret;
304 uffs_Object *obj;
305
306 CHK_OBJ_LOCK(fd, obj, -1);
307 uffs_ClearObjectErr(obj);
308 ret = uffs_WriteObject(obj, data, len);
309 uffs_set_error(-uffs_GetObjectErr(obj));
310
311 uffs_GlobalFsLockUnlock();
312
313 return ret;
314 }
315
uffs_seek(int fd,long offset,int origin)316 long uffs_seek(int fd, long offset, int origin)
317 {
318 int ret;
319 uffs_Object *obj;
320
321 CHK_OBJ_LOCK(fd, obj, -1);
322 uffs_ClearObjectErr(obj);
323 ret = uffs_SeekObject(obj, offset, origin);
324 uffs_set_error(-uffs_GetObjectErr(obj));
325
326 uffs_GlobalFsLockUnlock();
327
328 return ret;
329 }
330
uffs_tell(int fd)331 long uffs_tell(int fd)
332 {
333 long ret;
334 uffs_Object *obj;
335
336 CHK_OBJ_LOCK(fd, obj, -1);
337 uffs_ClearObjectErr(obj);
338 ret = (long) uffs_GetCurOffset(obj);
339 uffs_set_error(-uffs_GetObjectErr(obj));
340
341 uffs_GlobalFsLockUnlock();
342
343 return ret;
344 }
345
uffs_eof(int fd)346 int uffs_eof(int fd)
347 {
348 int ret;
349 uffs_Object *obj;
350
351 CHK_OBJ_LOCK(fd, obj, -1);
352 uffs_ClearObjectErr(obj);
353 ret = uffs_EndOfFile(obj);
354 uffs_set_error(-uffs_GetObjectErr(obj));
355
356 uffs_GlobalFsLockUnlock();
357
358 return ret;
359 }
360
uffs_flush(int fd)361 int uffs_flush(int fd)
362 {
363 int ret;
364 uffs_Object *obj;
365
366 CHK_OBJ_LOCK(fd, obj, -1);
367 uffs_ClearObjectErr(obj);
368 ret = (uffs_FlushObject(obj) == U_SUCC) ? 0 : -1;
369 uffs_set_error(-uffs_GetObjectErr(obj));
370
371 uffs_GlobalFsLockUnlock();
372
373 return ret;
374 }
375
uffs_rename(const char * old_name,const char * new_name)376 int uffs_rename(const char *old_name, const char *new_name)
377 {
378 int err = 0;
379 int ret = 0;
380
381 uffs_GlobalFsLockLock();
382 ret = (uffs_RenameObject(old_name, new_name, &err) == U_SUCC) ? 0 : -1;
383 uffs_set_error(-err);
384 uffs_GlobalFsLockUnlock();
385
386 return ret;
387 }
388
uffs_remove(const char * name)389 int uffs_remove(const char *name)
390 {
391 int err = 0;
392 int ret = 0;
393 struct uffs_stat st;
394
395 if (uffs_stat(name, &st) < 0) {
396 err = UENOENT;
397 ret = -1;
398 }
399 else if (st.st_mode & US_IFDIR) {
400 err = UEISDIR;
401 ret = -1;
402 }
403 else {
404 uffs_GlobalFsLockLock();
405 if (uffs_DeleteObject(name, &err) == U_SUCC) {
406 ret = 0;
407 }
408 else {
409 ret = -1;
410 }
411 uffs_GlobalFsLockUnlock();
412 }
413
414 uffs_set_error(-err);
415 return ret;
416 }
417
uffs_ftruncate(int fd,long remain)418 int uffs_ftruncate(int fd, long remain)
419 {
420 int ret;
421 uffs_Object *obj;
422
423 CHK_OBJ_LOCK(fd, obj, -1);
424 uffs_ClearObjectErr(obj);
425 ret = (uffs_TruncateObject(obj, remain) == U_SUCC) ? 0 : -1;
426 uffs_set_error(-uffs_GetObjectErr(obj));
427 uffs_GlobalFsLockUnlock();
428
429 return ret;
430 }
431
do_stat(uffs_Object * obj,struct uffs_stat * buf)432 static int do_stat(uffs_Object *obj, struct uffs_stat *buf)
433 {
434 uffs_ObjectInfo info;
435 int ret = 0;
436 int err = 0;
437
438 if (uffs_GetObjectInfo(obj, &info, &err) == U_FAIL) {
439 ret = -1;
440 }
441 else {
442 buf->st_dev = obj->dev->dev_num;
443 buf->st_ino = info.serial;
444 buf->st_nlink = 0;
445 buf->st_uid = 0;
446 buf->st_gid = 0;
447 buf->st_rdev = 0;
448 buf->st_size = info.len;
449 buf->st_blksize = obj->dev->com.pg_data_size;
450 buf->st_blocks = 0;
451 buf->st_atime = info.info.last_modify;
452 buf->st_mtime = info.info.last_modify;
453 buf->st_ctime = info.info.create_time;
454 buf->st_mode = (info.info.attr & FILE_ATTR_DIR ? US_IFDIR : US_IFREG);
455 if (info.info.attr & FILE_ATTR_WRITE)
456 buf->st_mode |= US_IRWXU;
457 }
458
459 uffs_set_error(-err);
460 return ret;
461 }
462
uffs_stat(const char * name,struct uffs_stat * buf)463 int uffs_stat(const char *name, struct uffs_stat *buf)
464 {
465 uffs_Object *obj;
466 int ret = 0;
467 int err = 0;
468 URET result;
469
470 uffs_GlobalFsLockLock();
471
472 obj = uffs_GetObject();
473 if (obj) {
474 if (*name && name[strlen(name) - 1] == '/') {
475 result = uffs_OpenObject(obj, name, UO_RDONLY | UO_DIR);
476 }
477 else {
478 if ((result = uffs_OpenObject(obj, name, UO_RDONLY)) != U_SUCC) // try file
479 result = uffs_OpenObject(obj, name, UO_RDONLY | UO_DIR); // then try dir
480 }
481 if (result == U_SUCC) {
482 ret = do_stat(obj, buf);
483 uffs_CloseObject(obj);
484 }
485 else {
486 err = uffs_GetObjectErr(obj);
487 ret = -1;
488 }
489 uffs_PutObject(obj);
490 }
491 else {
492 err = UENOMEM;
493 ret = -1;
494 }
495
496 uffs_set_error(-err);
497 uffs_GlobalFsLockUnlock();
498
499 return ret;
500 }
501
uffs_lstat(const char * name,struct uffs_stat * buf)502 int uffs_lstat(const char *name, struct uffs_stat *buf)
503 {
504 return uffs_stat(name, buf);
505 }
506
uffs_fstat(int fd,struct uffs_stat * buf)507 int uffs_fstat(int fd, struct uffs_stat *buf)
508 {
509 int ret;
510 uffs_Object *obj;
511
512 CHK_OBJ_LOCK(fd, obj, -1);
513
514 ret = do_stat(obj, buf);
515 uffs_GlobalFsLockUnlock();
516
517 return ret;
518 }
519
uffs_closedir(uffs_DIR * dirp)520 int uffs_closedir(uffs_DIR *dirp)
521 {
522 CHK_DIR_LOCK(dirp, -1);
523
524 uffs_FindObjectClose(&dirp->f);
525 if (dirp->obj) {
526 uffs_CloseObject(dirp->obj);
527 uffs_PutObject(dirp->obj);
528 }
529 PutDirEntry(dirp);
530 uffs_GlobalFsLockUnlock();
531
532 return 0;
533 }
534
uffs_opendir(const char * path)535 uffs_DIR * uffs_opendir(const char *path)
536 {
537 int err = 0;
538 uffs_DIR *ret = NULL;
539 uffs_DIR *dirp;
540
541 uffs_GlobalFsLockLock();
542
543 dirp = GetDirEntry();
544
545 if (dirp) {
546 dirp->obj = uffs_GetObject();
547 if (dirp->obj) {
548 if (uffs_OpenObject(dirp->obj, path, UO_RDONLY | UO_DIR) == U_SUCC) {
549 if (uffs_FindObjectOpen(&dirp->f, dirp->obj) == U_SUCC) {
550 ret = dirp;
551 goto ext;
552 }
553 else {
554 uffs_CloseObject(dirp->obj);
555 }
556 }
557 else {
558 err = uffs_GetObjectErr(dirp->obj);
559 }
560 uffs_PutObject(dirp->obj);
561 dirp->obj = NULL;
562 }
563 else {
564 err = UEMFILE;
565 }
566 PutDirEntry(dirp);
567 }
568 else {
569 err = UEMFILE;
570 }
571 ext:
572 uffs_set_error(-err);
573 uffs_GlobalFsLockUnlock();
574
575 return ret;
576 }
577
uffs_readdir(uffs_DIR * dirp)578 struct uffs_dirent * uffs_readdir(uffs_DIR *dirp)
579 {
580 struct uffs_dirent *ent = NULL;
581
582 CHK_DIR_LOCK(dirp, NULL);
583
584 if (uffs_FindObjectNext(&dirp->info, &dirp->f) == U_SUCC) {
585 ent = &dirp->dirent;
586 ent->d_ino = dirp->info.serial;
587 ent->d_namelen = dirp->info.info.name_len < (sizeof(ent->d_name) - 1) ? dirp->info.info.name_len : (sizeof(ent->d_name) - 1);
588 memcpy(ent->d_name, dirp->info.info.name, ent->d_namelen);
589 ent->d_name[ent->d_namelen] = '\0';
590 ent->d_off = dirp->f.pos;
591 ent->d_reclen = sizeof(struct uffs_dirent);
592 ent->d_type = dirp->info.info.attr;
593 }
594 uffs_GlobalFsLockUnlock();
595
596 return ent;
597 }
598
uffs_rewinddir(uffs_DIR * dirp)599 void uffs_rewinddir(uffs_DIR *dirp)
600 {
601 CHK_DIR_VOID_LOCK(dirp);
602
603 uffs_FindObjectRewind(&dirp->f);
604
605 uffs_GlobalFsLockUnlock();
606 }
607
608
uffs_mkdir(const char * name,...)609 int uffs_mkdir(const char *name, ...)
610 {
611 uffs_Object *obj;
612 int ret = 0;
613 int err = 0;
614
615 uffs_GlobalFsLockLock();
616
617 obj = uffs_GetObject();
618 if (obj) {
619 if (uffs_CreateObject(obj, name, UO_CREATE|UO_DIR) != U_SUCC) {
620 err = obj->err;
621 ret = -1;
622 }
623 else {
624 uffs_CloseObject(obj);
625 ret = 0;
626 }
627 uffs_PutObject(obj);
628 }
629 else {
630 err = UEMFILE;
631 ret = -1;
632 }
633
634 uffs_set_error(-err);
635 uffs_GlobalFsLockUnlock();
636
637 return ret;
638 }
639
uffs_rmdir(const char * name)640 int uffs_rmdir(const char *name)
641 {
642 int err = 0;
643 int ret = 0;
644 struct uffs_stat st;
645
646 if (uffs_stat(name, &st) < 0) {
647 err = UENOENT;
648 ret = -1;
649 }
650 else if ((st.st_mode & US_IFDIR) == 0) {
651 err = UENOTDIR;
652 ret = -1;
653 }
654 else {
655 uffs_GlobalFsLockLock();
656 if (uffs_DeleteObject(name, &err) == U_SUCC) {
657 ret = 0;
658 }
659 else {
660 ret = -1;
661 }
662 uffs_GlobalFsLockUnlock();
663 }
664 uffs_set_error(-err);
665 return ret;
666 }
667
uffs_version(void)668 int uffs_version(void)
669 {
670 return uffs_GetVersion();
671 }
672
uffs_format(const char * mount_point)673 int uffs_format(const char *mount_point)
674 {
675 uffs_Device *dev = NULL;
676 URET ret = U_FAIL;
677
678 dev = uffs_GetDeviceFromMountPoint(mount_point);
679 if (dev) {
680 uffs_GlobalFsLockLock();
681 ret = uffs_FormatDevice(dev, U_TRUE);
682 uffs_GlobalFsLockUnlock();
683 }
684
685 return ret == U_SUCC ? 0 : -1;
686 }
687
uffs_space_total(const char * mount_point)688 long uffs_space_total(const char *mount_point)
689 {
690 uffs_Device *dev = NULL;
691 long ret = -1L;
692
693 dev = uffs_GetDeviceFromMountPoint(mount_point);
694 if (dev) {
695 uffs_GlobalFsLockLock();
696 ret = (long) uffs_GetDeviceTotal(dev);
697 uffs_GlobalFsLockUnlock();
698 }
699
700 return ret;
701 }
702
uffs_space_used(const char * mount_point)703 long uffs_space_used(const char *mount_point)
704 {
705 uffs_Device *dev = NULL;
706 long ret = -1L;
707
708 dev = uffs_GetDeviceFromMountPoint(mount_point);
709 if (dev) {
710 uffs_GlobalFsLockLock();
711 ret = (long) uffs_GetDeviceUsed(dev);
712 uffs_GlobalFsLockUnlock();
713 }
714
715 return ret;
716 }
717
uffs_space_free(const char * mount_point)718 long uffs_space_free(const char *mount_point)
719 {
720 uffs_Device *dev = NULL;
721 long ret = -1L;
722
723 dev = uffs_GetDeviceFromMountPoint(mount_point);
724 if (dev) {
725 uffs_GlobalFsLockLock();
726 ret = (long) uffs_GetDeviceFree(dev);
727 uffs_GlobalFsLockUnlock();
728 }
729
730 return ret;
731 }
732
733
uffs_flush_all(const char * mount_point)734 void uffs_flush_all(const char *mount_point)
735 {
736 uffs_Device *dev = NULL;
737
738 dev = uffs_GetDeviceFromMountPoint(mount_point);
739 if (dev) {
740 uffs_GlobalFsLockLock();
741 uffs_BufFlushAll(dev);
742 uffs_PutDevice(dev);
743 uffs_GlobalFsLockUnlock();
744 }
745 }
746
747