2 * fs.c - posix like file functions
4 * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
6 * See file CREDITS for list of people who contributed to this
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <linux/stat.h>
34 void *read_file(const char *filename
, size_t *size
)
40 if (stat(filename
, &s
))
43 buf
= xzalloc(s
.st_size
+ 1);
45 fd
= open(filename
, O_RDONLY
);
49 if (read(fd
, buf
, s
.st_size
) < s
.st_size
)
66 EXPORT_SYMBOL(read_file
);
68 char *mkmodestr(unsigned long mode
, char *str
)
70 static const char *l
= "xwr";
74 switch (mode
& S_IFMT
) {
75 case S_IFDIR
: str
[0] = 'd'; break;
76 case S_IFBLK
: str
[0] = 'b'; break;
77 case S_IFCHR
: str
[0] = 'c'; break;
78 case S_IFIFO
: str
[0] = 'f'; break;
79 case S_IFLNK
: str
[0] = 'l'; break;
80 case S_IFSOCK
: str
[0] = 's'; break;
81 case S_IFREG
: str
[0] = '-'; break;
82 default: str
[0] = '?';
85 for(i
= 0; i
< 9; i
++) {
87 str
[9-i
] = (mode
& mask
)?c
:'-';
91 if(mode
& S_ISUID
) str
[3] = (mode
& S_IXUSR
)?'s':'S';
92 if(mode
& S_ISGID
) str
[6] = (mode
& S_IXGRP
)?'s':'S';
93 if(mode
& S_ISVTX
) str
[9] = (mode
& S_IXOTH
)?'t':'T';
97 EXPORT_SYMBOL(mkmodestr
);
101 static int init_cwd(void)
103 cwd
= xzalloc(PATH_MAX
);
108 postcore_initcall(init_cwd
);
110 char *normalise_path(const char *pathname
)
112 char *path
= xzalloc(strlen(pathname
) + strlen(cwd
) + 2);
113 char *in
, *out
, *slashes
[32];
116 debug("in: %s\n", pathname
);
118 if (*pathname
!= '/')
121 strcat(path
, pathname
);
123 slashes
[0] = in
= out
= path
;
132 if (*in
== '.' && (*(in
+ 1) == '/' || !*(in
+ 1))) {
140 if (*in
== '.' && *(in
+ 1) == '.') {
155 * Remove trailing slash
167 EXPORT_SYMBOL(normalise_path
);
169 static struct mtab_entry
*mtab
;
171 struct mtab_entry
*get_mtab_entry_by_path(const char *_path
)
173 struct mtab_entry
*match
= NULL
, *e
= mtab
;
179 path
= strdup(_path
);
181 tok
= strchr(path
+ 1, '/');
186 if (!strcmp(path
, e
->path
)) {
195 return match
? match
: mtab
;
198 struct mtab_entry
*mtab_next_entry(struct mtab_entry
*e
)
205 const char *fsdev_get_mountpoint(struct fs_device_d
*fsdev
)
207 return fsdev
->mtab
.path
;
210 static FILE files
[MAX_FILES
];
212 static FILE *get_file(void)
216 for (i
= 3; i
< MAX_FILES
; i
++) {
217 if (!files
[i
].in_use
) {
218 memset(&files
[i
], 0, sizeof(FILE));
227 static void put_file(FILE *f
)
229 files
[f
->no
].in_use
= 0;
232 static struct device_d
*get_fs_device_by_path(char **path
)
234 struct device_d
*dev
;
235 struct mtab_entry
*e
;
237 e
= get_mtab_entry_by_path(*path
);
241 *path
+= strlen(e
->path
);
248 static int dir_is_empty(const char *pathname
)
254 dir
= opendir(pathname
);
260 while ((d
= readdir(dir
))) {
261 if (!strcmp(d
->d_name
, ".") || !strcmp(d
->d_name
, ".."))
271 #define S_UB_IS_EMPTY (1 << 31)
272 #define S_UB_EXISTS (1 << 30)
273 #define S_UB_DOES_NOT_EXIST (1 << 29)
276 * Helper function to check the prerequisites of a path given
277 * to fs functions. Besides the flags above S_IFREG and S_IFDIR
280 static int path_check_prereq(const char *path
, unsigned int flags
)
287 if (stat(path
, &s
)) {
288 if (flags
& S_UB_DOES_NOT_EXIST
)
294 if (flags
& S_UB_DOES_NOT_EXIST
) {
299 if (flags
== S_UB_EXISTS
)
305 if (flags
& S_IFREG
) {
309 if ((flags
& S_UB_IS_EMPTY
) && !dir_is_empty(path
)) {
314 if ((flags
& S_IFDIR
) && S_ISREG(m
)) {
322 const char *getcwd(void)
326 EXPORT_SYMBOL(getcwd
);
328 int chdir(const char *pathname
)
330 char *p
= normalise_path(pathname
);
333 if (path_check_prereq(p
, S_IFDIR
))
342 EXPORT_SYMBOL(chdir
);
344 int unlink(const char *pathname
)
346 struct device_d
*dev
;
347 struct fs_driver_d
*fsdrv
;
348 char *p
= normalise_path(pathname
);
351 if (path_check_prereq(pathname
, S_IFREG
))
354 dev
= get_fs_device_by_path(&p
);
357 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
359 if (!fsdrv
->unlink
) {
364 errno
= fsdrv
->unlink(dev
, p
);
369 EXPORT_SYMBOL(unlink
);
371 int open(const char *pathname
, int flags
, ...)
373 struct device_d
*dev
;
374 struct fs_driver_d
*fsdrv
;
378 char *path
= normalise_path(pathname
);
381 exist
= (stat(path
, &s
) == 0) ? 1 : 0;
383 if (exist
&& S_ISDIR(s
.st_mode
)) {
388 if (!exist
&& !(flags
& O_CREAT
)) {
399 dev
= get_fs_device_by_path(&path
);
403 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
408 if ((flags
& O_ACCMODE
) && !fsdrv
->write
) {
414 if (NULL
!= fsdrv
->create
)
415 errno
= fsdrv
->create(dev
, path
,
416 S_IFREG
| S_IRWXU
| S_IRWXG
| S_IRWXO
);
422 errno
= fsdrv
->open(dev
, f
, path
);
427 if (flags
& O_TRUNC
) {
428 errno
= fsdrv
->truncate(dev
, f
, 0);
434 if (flags
& O_APPEND
)
448 int creat(const char *pathname
, mode_t mode
)
450 return open(pathname
, O_CREAT
| O_WRONLY
| O_TRUNC
);
452 EXPORT_SYMBOL(creat
);
454 int ioctl(int fd
, int request
, void *buf
)
456 struct device_d
*dev
;
457 struct fs_driver_d
*fsdrv
;
458 FILE *f
= &files
[fd
];
462 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
465 errno
= fsdrv
->ioctl(dev
, f
, request
, buf
);
471 int read(int fd
, void *buf
, size_t count
)
473 struct device_d
*dev
;
474 struct fs_driver_d
*fsdrv
;
475 FILE *f
= &files
[fd
];
479 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
481 if (f
->pos
+ count
> f
->size
)
482 count
= f
->size
- f
->pos
;
483 errno
= fsdrv
->read(dev
, f
, buf
, count
);
491 ssize_t
write(int fd
, const void *buf
, size_t count
)
493 struct device_d
*dev
;
494 struct fs_driver_d
*fsdrv
;
495 FILE *f
= &files
[fd
];
499 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
500 if (f
->pos
+ count
> f
->size
) {
501 errno
= fsdrv
->truncate(dev
, f
, f
->pos
+ count
);
503 if (errno
!= -ENOSPC
)
505 count
= f
->size
- f
->pos
;
509 f
->size
= f
->pos
+ count
;
512 errno
= fsdrv
->write(dev
, f
, buf
, count
);
518 EXPORT_SYMBOL(write
);
520 off_t
lseek(int fildes
, off_t offset
, int whence
)
522 struct device_d
*dev
;
523 struct fs_driver_d
*fsdrv
;
524 FILE *f
= &files
[fildes
];
530 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
538 if (offset
> f
->size
)
543 if (offset
+ f
->pos
> f
->size
)
545 pos
= f
->pos
+ offset
;
556 return fsdrv
->lseek(dev
, f
, pos
);
562 EXPORT_SYMBOL(lseek
);
564 int erase(int fd
, size_t count
, unsigned long offset
)
566 struct device_d
*dev
;
567 struct fs_driver_d
*fsdrv
;
568 FILE *f
= &files
[fd
];
572 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
574 if (f
->pos
+ count
> f
->size
)
575 count
= f
->size
- f
->pos
;
578 errno
= fsdrv
->erase(dev
, f
, count
, offset
);
584 EXPORT_SYMBOL(erase
);
586 int protect(int fd
, size_t count
, unsigned long offset
, int prot
)
588 struct device_d
*dev
;
589 struct fs_driver_d
*fsdrv
;
590 FILE *f
= &files
[fd
];
594 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
596 if (f
->pos
+ count
> f
->size
)
597 count
= f
->size
- f
->pos
;
600 errno
= fsdrv
->protect(dev
, f
, count
, offset
, prot
);
606 EXPORT_SYMBOL(protect
);
608 int protect_file(const char *file
, int prot
)
612 fd
= open(file
, O_WRONLY
);
616 ret
= protect(fd
, ~0, 0, prot
);
623 void *memmap(int fd
, int flags
)
625 struct device_d
*dev
;
626 struct fs_driver_d
*fsdrv
;
627 FILE *f
= &files
[fd
];
628 void *ret
= (void *)-1;
632 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
635 errno
= fsdrv
->memmap(dev
, f
, &ret
, flags
);
641 EXPORT_SYMBOL(memmap
);
645 struct device_d
*dev
;
646 struct fs_driver_d
*fsdrv
;
647 FILE *f
= &files
[fd
];
651 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
652 errno
= fsdrv
->close(dev
, f
);
657 EXPORT_SYMBOL(close
);
659 static LIST_HEAD(fs_driver_list
);
661 int register_fs_driver(struct fs_driver_d
*fsdrv
)
663 list_add_tail(&fsdrv
->list
, &fs_driver_list
);
664 register_driver(&fsdrv
->drv
);
667 EXPORT_SYMBOL(register_fs_driver
);
670 * Mount a device to a directory.
671 * We do this by registering a new device on which the filesystem
672 * driver will match. The filesystem driver then grabs the infomation
673 * it needs from the new devices type_data.
675 int mount(const char *device
, const char *fsname
, const char *_path
)
677 struct fs_driver_d
*fs_drv
= NULL
, *f
;
678 struct mtab_entry
*entry
;
679 struct fs_device_d
*fsdev
;
680 struct device_d
*dev
, *parent_device
= NULL
;
682 char *path
= normalise_path(_path
);
686 debug("mount: %s on %s type %s\n", device
, path
, fsname
);
688 if (get_mtab_entry_by_path(path
) != mtab
) {
693 if (strchr(path
+ 1, '/')) {
694 printf("mounting allowed on first directory level only\n");
699 list_for_each_entry(f
, &fs_driver_list
, list
) {
700 if (!strcmp(f
->drv
.name
, fsname
)) {
712 if (path_check_prereq(path
, S_IFDIR
))
715 /* no mtab, so we only allow to mount on '/' */
716 if (*path
!= '/' || *(path
+ 1)) {
722 fsdev
= xzalloc(sizeof(struct fs_device_d
));
723 if (!fs_drv
->flags
& FS_DRIVER_NO_DEV
) {
724 fsdev
->backingstore
= strdup(device
);
726 printf("need a device for driver %s\n", fsname
);
732 sprintf(fsdev
->dev
.name
, "%s", fsname
);
733 fsdev
->dev
.type_data
= fsdev
;
735 if ((ret
= register_device(&fsdev
->dev
))) {
741 if (!fsdev
->dev
.driver
) {
742 /* driver didn't accept the device. Bail out */
749 dev_add_child(parent_device
, &fsdev
->dev
);
754 entry
= &fsdev
->mtab
;
755 sprintf(entry
->path
, "%s", path
);
757 entry
->parent_device
= parent_device
;
763 struct mtab_entry
*e
= mtab
;
772 EXPORT_SYMBOL(mount
);
774 int umount(const char *pathname
)
776 struct mtab_entry
*entry
= mtab
;
777 struct mtab_entry
*last
= mtab
;
778 char *p
= normalise_path(pathname
);
779 struct fs_device_d
*fsdev
;
781 while(entry
&& strcmp(p
, entry
->path
)) {
796 last
->next
= entry
->next
;
798 unregister_device(entry
->dev
);
799 fsdev
= entry
->dev
->type_data
;
800 free(fsdev
->backingstore
);
805 EXPORT_SYMBOL(umount
);
807 DIR *opendir(const char *pathname
)
810 struct device_d
*dev
;
811 struct fs_driver_d
*fsdrv
;
812 char *p
= normalise_path(pathname
);
815 if (path_check_prereq(pathname
, S_IFDIR
))
818 dev
= get_fs_device_by_path(&p
);
821 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
823 debug("opendir: fsdrv: %p\n",fsdrv
);
825 dir
= fsdrv
->opendir(dev
, p
);
835 EXPORT_SYMBOL(opendir
);
837 struct dirent
*readdir(DIR *dir
)
842 return dir
->fsdrv
->readdir(dir
->dev
, dir
);
844 EXPORT_SYMBOL(readdir
);
846 int closedir(DIR *dir
)
853 return dir
->fsdrv
->closedir(dir
->dev
, dir
);
855 EXPORT_SYMBOL(closedir
);
857 int stat(const char *filename
, struct stat
*s
)
859 struct device_d
*dev
;
860 struct fs_driver_d
*fsdrv
;
861 struct mtab_entry
*e
;
862 char *f
= normalise_path(filename
);
865 memset(s
, 0, sizeof(struct stat
));
867 e
= get_mtab_entry_by_path(f
);
873 if (e
!= mtab
&& strcmp(f
, e
->path
)) {
874 f
+= strlen(e
->path
);
879 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
884 errno
= fsdrv
->stat(dev
, f
, s
);
891 int mkdir (const char *pathname
, mode_t mode
)
893 struct fs_driver_d
*fsdrv
;
894 struct device_d
*dev
;
895 char *p
= normalise_path(pathname
);
898 if (path_check_prereq(pathname
, S_UB_DOES_NOT_EXIST
))
901 dev
= get_fs_device_by_path(&p
);
904 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
907 errno
= fsdrv
->mkdir(dev
, p
);
916 EXPORT_SYMBOL(mkdir
);
918 int rmdir (const char *pathname
)
920 struct fs_driver_d
*fsdrv
;
921 struct device_d
*dev
;
922 char *p
= normalise_path(pathname
);
925 if (path_check_prereq(pathname
, S_IFDIR
| S_UB_IS_EMPTY
))
928 dev
= get_fs_device_by_path(&p
);
931 fsdrv
= (struct fs_driver_d
*)dev
->driver
->type_data
;
934 errno
= fsdrv
->rmdir(dev
, p
);
943 EXPORT_SYMBOL(rmdir
);
945 static void memcpy_sz(void *_dst
, const void *_src
, ulong count
, ulong rwsize
)
947 ulong dst
= (ulong
)_dst
;
948 ulong src
= (ulong
)_src
;
950 /* no rwsize specification given. Do whatever memcpy likes best */
952 memcpy(_dst
, _src
, count
);
956 rwsize
= rwsize
>> O_RWSIZE_SHIFT
;
960 while (count
-- > 0) {
963 *((u_char
*)dst
) = *((u_char
*)src
);
966 *((ushort
*)dst
) = *((ushort
*)src
);
969 *((ulong
*)dst
) = *((ulong
*)src
);
977 ssize_t
mem_read(struct cdev
*cdev
, void *buf
, size_t count
, ulong offset
, ulong flags
)
980 struct device_d
*dev
;
986 size
= min((ulong
)count
, dev
->size
- offset
);
987 debug("mem_read: dev->map_base: %p size: %d offset: %d\n",dev
->map_base
, size
, offset
);
988 memcpy_sz(buf
, (void *)(dev
->map_base
+ offset
), size
, flags
& O_RWSIZE_MASK
);
991 EXPORT_SYMBOL(mem_read
);
993 ssize_t
mem_write(struct cdev
*cdev
, const void *buf
, size_t count
, ulong offset
, ulong flags
)
996 struct device_d
*dev
;
1002 size
= min((ulong
)count
, dev
->size
- offset
);
1003 memcpy_sz((void *)(dev
->map_base
+ offset
), buf
, size
, flags
& O_RWSIZE_MASK
);
1006 EXPORT_SYMBOL(mem_write
);