net: implement random_ether_addr
[barebox-mini2440.git] / fs / fs.c
blob841706704219bf727467ddd89181b1cc88205540
1 /*
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
7 * project.
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
23 #include <common.h>
24 #include <fs.h>
25 #include <driver.h>
26 #include <errno.h>
27 #include <malloc.h>
28 #include <linux/stat.h>
29 #include <fcntl.h>
30 #include <xfuncs.h>
31 #include <init.h>
32 #include <module.h>
34 void *read_file(const char *filename, size_t *size)
36 int fd;
37 struct stat s;
38 void *buf = NULL;
40 if (stat(filename, &s))
41 return NULL;
43 buf = xzalloc(s.st_size + 1);
45 fd = open(filename, O_RDONLY);
46 if (fd < 0)
47 goto err_out;
49 if (read(fd, buf, s.st_size) < s.st_size)
50 goto err_out1;
52 close(fd);
54 if (size)
55 *size = s.st_size;
57 return buf;
59 err_out1:
60 close(fd);
61 err_out:
62 free(buf);
63 return NULL;
66 EXPORT_SYMBOL(read_file);
68 char *mkmodestr(unsigned long mode, char *str)
70 static const char *l = "xwr";
71 int mask = 1, i;
72 char c;
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++) {
86 c = l[i%3];
87 str[9-i] = (mode & mask)?c:'-';
88 mask = mask<<1;
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';
94 str[10] = '\0';
95 return str;
97 EXPORT_SYMBOL(mkmodestr);
99 static char *cwd;
101 static int init_cwd(void)
103 cwd = xzalloc(PATH_MAX);
104 *cwd = '/';
105 return 0;
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];
114 int sl = 0;
116 debug("in: %s\n", pathname);
118 if (*pathname != '/')
119 strcpy(path, cwd);
120 strcat(path, "/");
121 strcat(path, pathname);
123 slashes[0] = in = out = path;
125 while (*in) {
126 if(*in == '/') {
127 slashes[sl++] = out;
128 *out++ = *in++;
129 while(*in == '/')
130 in++;
131 } else {
132 if (*in == '.' && (*(in + 1) == '/' || !*(in + 1))) {
133 sl--;
134 if (sl < 0)
135 sl = 0;
136 out = slashes[sl];
137 in++;
138 continue;
140 if (*in == '.' && *(in + 1) == '.') {
141 sl -= 2;
142 if (sl < 0)
143 sl = 0;
144 out = slashes[sl];
145 in += 2;
146 continue;
148 *out++ = *in++;
152 *out-- = 0;
155 * Remove trailing slash
157 if (*out == '/')
158 *out = 0;
160 if (!*path) {
161 *path = '/';
162 *(path + 1) = 0;
165 return path;
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;
174 char *path, *tok;
176 if (*_path != '/')
177 return NULL;
179 path = strdup(_path);
181 tok = strchr(path + 1, '/');
182 if (tok)
183 *tok = 0;
185 while (e) {
186 if (!strcmp(path, e->path)) {
187 match = e;
188 break;
190 e = e->next;
193 free(path);
195 return match ? match : mtab;
198 struct mtab_entry *mtab_next_entry(struct mtab_entry *e)
200 if (!e)
201 return mtab;
202 return e->next;
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)
214 int i;
216 for (i = 3; i < MAX_FILES; i++) {
217 if (!files[i].in_use) {
218 memset(&files[i], 0, sizeof(FILE));
219 files[i].in_use = 1;
220 files[i].no = i;
221 return &files[i];
224 return NULL;
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);
238 if (!e)
239 return NULL;
240 if (e != mtab)
241 *path += strlen(e->path);
243 dev = e->dev;
245 return dev;
248 static int dir_is_empty(const char *pathname)
250 DIR *dir;
251 struct dirent *d;
252 int ret = 1;
254 dir = opendir(pathname);
255 if (!dir) {
256 errno = -ENOENT;
257 return -ENOENT;
260 while ((d = readdir(dir))) {
261 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
262 continue;
263 ret = 0;
264 break;
267 closedir(dir);
268 return ret;
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
278 * can be passed in.
280 static int path_check_prereq(const char *path, unsigned int flags)
282 struct stat s;
283 unsigned int m;
285 errno = 0;
287 if (stat(path, &s)) {
288 if (flags & S_UB_DOES_NOT_EXIST)
289 return 0;
290 errno = -ENOENT;
291 goto out;
294 if (flags & S_UB_DOES_NOT_EXIST) {
295 errno = -EEXIST;
296 goto out;
299 if (flags == S_UB_EXISTS)
300 return 0;
302 m = s.st_mode;
304 if (S_ISDIR(m)) {
305 if (flags & S_IFREG) {
306 errno = -EISDIR;
307 goto out;
309 if ((flags & S_UB_IS_EMPTY) && !dir_is_empty(path)) {
310 errno = -ENOTEMPTY;
311 goto out;
314 if ((flags & S_IFDIR) && S_ISREG(m)) {
315 errno = -ENOTDIR;
316 goto out;
318 out:
319 return errno;
322 const char *getcwd(void)
324 return cwd;
326 EXPORT_SYMBOL(getcwd);
328 int chdir(const char *pathname)
330 char *p = normalise_path(pathname);
331 errno = 0;
333 if (path_check_prereq(p, S_IFDIR))
334 goto out;
336 strcpy(cwd, p);
338 free(p);
339 out:
340 return errno;
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);
349 char *freep = p;
351 if (path_check_prereq(pathname, S_IFREG))
352 goto out;
354 dev = get_fs_device_by_path(&p);
355 if (!dev)
356 goto out;
357 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
359 if (!fsdrv->unlink) {
360 errno = -ENOSYS;
361 goto out;
364 errno = fsdrv->unlink(dev, p);
365 out:
366 free(freep);
367 return errno;
369 EXPORT_SYMBOL(unlink);
371 int open(const char *pathname, int flags, ...)
373 struct device_d *dev;
374 struct fs_driver_d *fsdrv;
375 FILE *f;
376 int exist;
377 struct stat s;
378 char *path = normalise_path(pathname);
379 char *freep = path;
381 exist = (stat(path, &s) == 0) ? 1 : 0;
383 if (exist && S_ISDIR(s.st_mode)) {
384 errno = -EISDIR;
385 goto out1;
388 if (!exist && !(flags & O_CREAT)) {
389 errno = -ENOENT;
390 goto out1;
393 f = get_file();
394 if (!f) {
395 errno = -EMFILE;
396 goto out1;
399 dev = get_fs_device_by_path(&path);
400 if (!dev)
401 goto out;
403 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
405 f->dev = dev;
406 f->flags = flags;
408 if ((flags & O_ACCMODE) && !fsdrv->write) {
409 errno = -EROFS;
410 goto out;
413 if (!exist) {
414 if (NULL != fsdrv->create)
415 errno = fsdrv->create(dev, path,
416 S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
417 else
418 errno = -EROFS;
419 if (errno)
420 goto out;
422 errno = fsdrv->open(dev, f, path);
423 if (errno)
424 goto out;
427 if (flags & O_TRUNC) {
428 errno = fsdrv->truncate(dev, f, 0);
429 f->size = 0;
430 if (errno)
431 goto out;
434 if (flags & O_APPEND)
435 f->pos = f->size;
437 free(freep);
438 return f->no;
440 out:
441 put_file(f);
442 out1:
443 free(freep);
444 return errno;
446 EXPORT_SYMBOL(open);
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];
460 dev = f->dev;
462 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
464 if (fsdrv->ioctl)
465 errno = fsdrv->ioctl(dev, f, request, buf);
466 else
467 errno = -ENOSYS;
468 return errno;
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];
477 dev = f->dev;
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);
485 if (errno > 0)
486 f->pos += errno;
487 return errno;
489 EXPORT_SYMBOL(read);
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];
497 dev = f->dev;
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);
502 if (errno) {
503 if (errno != -ENOSPC)
504 return errno;
505 count = f->size - f->pos;
506 if (!count)
507 return errno;
508 } else {
509 f->size = f->pos + count;
512 errno = fsdrv->write(dev, f, buf, count);
514 if (errno > 0)
515 f->pos += errno;
516 return errno;
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];
525 off_t pos;
527 errno = 0;
529 dev = f->dev;
530 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
531 if (!fsdrv->lseek) {
532 errno = -ENOSYS;
533 return -1;
536 switch(whence) {
537 case SEEK_SET:
538 if (offset > f->size)
539 goto out;
540 pos = offset;
541 break;
542 case SEEK_CUR:
543 if (offset + f->pos > f->size)
544 goto out;
545 pos = f->pos + offset;
546 break;
547 case SEEK_END:
548 if (offset)
549 goto out;
550 pos = f->size;
551 break;
552 default:
553 goto out;
556 return fsdrv->lseek(dev, f, pos);
558 out:
559 errno = -EINVAL;
560 return -1;
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];
570 dev = f->dev;
572 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
574 if (f->pos + count > f->size)
575 count = f->size - f->pos;
577 if (fsdrv->erase)
578 errno = fsdrv->erase(dev, f, count, offset);
579 else
580 errno = -ENOSYS;
582 return errno;
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];
592 dev = f->dev;
594 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
596 if (f->pos + count > f->size)
597 count = f->size - f->pos;
599 if (fsdrv->protect)
600 errno = fsdrv->protect(dev, f, count, offset, prot);
601 else
602 errno = -ENOSYS;
604 return errno;
606 EXPORT_SYMBOL(protect);
608 int protect_file(const char *file, int prot)
610 int fd, ret;
612 fd = open(file, O_WRONLY);
613 if (fd < 0)
614 return fd;
616 ret = protect(fd, ~0, 0, prot);
618 close(fd);
620 return ret;
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;
630 dev = f->dev;
632 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
634 if (fsdrv->memmap)
635 errno = fsdrv->memmap(dev, f, &ret, flags);
636 else
637 errno = -EINVAL;
639 return ret;
641 EXPORT_SYMBOL(memmap);
643 int close(int fd)
645 struct device_d *dev;
646 struct fs_driver_d *fsdrv;
647 FILE *f = &files[fd];
649 dev = f->dev;
651 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
652 errno = fsdrv->close(dev, f);
654 put_file(f);
655 return errno;
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);
665 return 0;
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;
681 int ret;
682 char *path = normalise_path(_path);
684 errno = 0;
686 debug("mount: %s on %s type %s\n", device, path, fsname);
688 if (get_mtab_entry_by_path(path) != mtab) {
689 errno = -EBUSY;
690 goto out;
693 if (strchr(path + 1, '/')) {
694 printf("mounting allowed on first directory level only\n");
695 errno = -EBUSY;
696 goto out;
699 list_for_each_entry(f, &fs_driver_list, list) {
700 if (!strcmp(f->drv.name, fsname)) {
701 fs_drv = f;
702 break;
706 if (!fs_drv) {
707 errno = -EINVAL;
708 goto out;
711 if (mtab) {
712 if (path_check_prereq(path, S_IFDIR))
713 goto out;
714 } else {
715 /* no mtab, so we only allow to mount on '/' */
716 if (*path != '/' || *(path + 1)) {
717 errno = -ENOTDIR;
718 goto out;
722 fsdev = xzalloc(sizeof(struct fs_device_d));
723 if (!fs_drv->flags & FS_DRIVER_NO_DEV) {
724 fsdev->backingstore = strdup(device);
725 if (!device) {
726 printf("need a device for driver %s\n", fsname);
727 errno = -ENODEV;
728 free(fsdev);
729 goto out;
732 sprintf(fsdev->dev.name, "%s", fsname);
733 fsdev->dev.type_data = fsdev;
735 if ((ret = register_device(&fsdev->dev))) {
736 free(fsdev);
737 errno = ret;
738 goto out;
741 if (!fsdev->dev.driver) {
742 /* driver didn't accept the device. Bail out */
743 free(fsdev);
744 errno = -EINVAL;
745 goto out;
748 if (parent_device)
749 dev_add_child(parent_device, &fsdev->dev);
751 dev = &fsdev->dev;
753 /* add mtab entry */
754 entry = &fsdev->mtab;
755 sprintf(entry->path, "%s", path);
756 entry->dev = dev;
757 entry->parent_device = parent_device;
758 entry->next = NULL;
760 if (!mtab)
761 mtab = entry;
762 else {
763 struct mtab_entry *e = mtab;
764 while (e->next)
765 e = e->next;
766 e->next = entry;
768 out:
769 free(path);
770 return errno;
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)) {
782 last = entry;
783 entry = entry->next;
786 free(p);
788 if (!entry) {
789 errno = -EFAULT;
790 return errno;
793 if (entry == mtab)
794 mtab = mtab->next;
795 else
796 last->next = entry->next;
798 unregister_device(entry->dev);
799 fsdev = entry->dev->type_data;
800 free(fsdev->backingstore);
801 free(fsdev);
803 return 0;
805 EXPORT_SYMBOL(umount);
807 DIR *opendir(const char *pathname)
809 DIR *dir = NULL;
810 struct device_d *dev;
811 struct fs_driver_d *fsdrv;
812 char *p = normalise_path(pathname);
813 char *freep = p;
815 if (path_check_prereq(pathname, S_IFDIR))
816 goto out;
818 dev = get_fs_device_by_path(&p);
819 if (!dev)
820 goto out;
821 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
823 debug("opendir: fsdrv: %p\n",fsdrv);
825 dir = fsdrv->opendir(dev, p);
826 if (dir) {
827 dir->dev = dev;
828 dir->fsdrv = fsdrv;
831 out:
832 free(freep);
833 return dir;
835 EXPORT_SYMBOL(opendir);
837 struct dirent *readdir(DIR *dir)
839 if (!dir)
840 return NULL;
842 return dir->fsdrv->readdir(dir->dev, dir);
844 EXPORT_SYMBOL(readdir);
846 int closedir(DIR *dir)
848 if (!dir) {
849 errno = -EBADF;
850 return -1;
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);
863 char *freep = f;
865 memset(s, 0, sizeof(struct stat));
867 e = get_mtab_entry_by_path(f);
868 if (!e) {
869 errno = -ENOENT;
870 goto out;
873 if (e != mtab && strcmp(f, e->path)) {
874 f += strlen(e->path);
875 dev = e->dev;
876 } else
877 dev = mtab->dev;
879 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
881 if (*f == 0)
882 f = "/";
884 errno = fsdrv->stat(dev, f, s);
885 out:
886 free(freep);
887 return errno;
889 EXPORT_SYMBOL(stat);
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);
896 char *freep = p;
898 if (path_check_prereq(pathname, S_UB_DOES_NOT_EXIST))
899 goto out;
901 dev = get_fs_device_by_path(&p);
902 if (!dev)
903 goto out;
904 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
906 if (fsdrv->mkdir) {
907 errno = fsdrv->mkdir(dev, p);
908 goto out;
911 errno = -EROFS;
912 out:
913 free(freep);
914 return errno;
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);
923 char *freep = p;
925 if (path_check_prereq(pathname, S_IFDIR | S_UB_IS_EMPTY))
926 goto out;
928 dev = get_fs_device_by_path(&p);
929 if (!dev)
930 goto out;
931 fsdrv = (struct fs_driver_d *)dev->driver->type_data;
933 if (fsdrv->rmdir) {
934 errno = fsdrv->rmdir(dev, p);
935 goto out;
938 errno = -EROFS;
939 out:
940 free(freep);
941 return errno;
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 */
951 if (!rwsize) {
952 memcpy(_dst, _src, count);
953 return;
956 rwsize = rwsize >> O_RWSIZE_SHIFT;
958 count /= rwsize;
960 while (count-- > 0) {
961 switch (rwsize) {
962 case 1:
963 *((u_char *)dst) = *((u_char *)src);
964 break;
965 case 2:
966 *((ushort *)dst) = *((ushort *)src);
967 break;
968 case 4:
969 *((ulong *)dst) = *((ulong *)src);
970 break;
972 dst += rwsize;
973 src += rwsize;
977 ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags)
979 ulong size;
980 struct device_d *dev;
982 if (!cdev->dev)
983 return -1;
984 dev = cdev->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);
989 return size;
991 EXPORT_SYMBOL(mem_read);
993 ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags)
995 ulong size;
996 struct device_d *dev;
998 if (!cdev->dev)
999 return -1;
1000 dev = cdev->dev;
1002 size = min((ulong)count, dev->size - offset);
1003 memcpy_sz((void *)(dev->map_base + offset), buf, size, flags & O_RWSIZE_MASK);
1004 return size;
1006 EXPORT_SYMBOL(mem_write);