Cleanup in elf.c with .bss section clean; adm command mounts cdrom instead of floppy...
[ZeXOS.git] / kernel / core / vfs.c
blob3f3f45980f8e28544f0c3c055b2f50780c943569
1 /*
2 * ZeX/OS
3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
6 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
23 #include <system.h>
24 #include <string.h>
25 #include <build.h>
26 #include <mount.h>
27 #include <errno.h>
28 #include <cache.h>
29 #include <vfs.h>
30 #include <smp.h>
31 #include <fd.h>
33 vfs_t vfs_list;
35 extern mount_t mount_list;
37 vfs_t *vfs_list_find (char *name, char *mountpoint)
39 unsigned l = strlen (name);
41 vfs_t *vfs;
42 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
43 if (!strncmp (vfs->name, name, l) && !strcmp (vfs->mountpoint, mountpoint))
44 return vfs;
47 return 0;
50 vfs_t *vfs_list_findbymp (char *mountpoint)
52 char mdir[128];
53 char pwd[64];
54 strcpy (pwd, (char *) env_get ("PWD"));
55 unsigned l = strlen (pwd);
57 vfs_t *vfs;
58 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
59 if (strncmp (pwd, vfs->mountpoint, l))
60 continue;
62 sprintf (mdir, "%s%s/", vfs->mountpoint, vfs->name);
64 if (!strcmp (mdir, mountpoint))
65 return vfs;
68 return 0;
71 vfs_t *vfs_find (char *file, unsigned file_len)
73 if (!file)
74 return 0;
76 char pwd[64];
77 strcpy (pwd, (char *) env_get ("PWD"));
79 char buf[65];
80 unsigned pwd_len = strlen (pwd);
82 unsigned i = file[0] == '/' ? 1 : 0;
84 if (!i) {
85 memcpy (buf, pwd, pwd_len);
86 memcpy (buf+pwd_len, file+i, file_len-i);
87 buf[pwd_len+file_len-i] = '\0';
88 } else {
89 memcpy (buf, file, file_len);
90 buf[file_len] = '\0';
93 if (buf[pwd_len+file_len-i-1] == '/')
94 buf[pwd_len+file_len-i-1] = '\0';
96 vfs_t *vfs;
97 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
98 unsigned mp_len = strlen (vfs->mountpoint);
99 unsigned nm_len = strlen (vfs->name);
101 char buf2[128];
102 memcpy (buf2, vfs->mountpoint, mp_len);
103 memcpy (buf2+mp_len, vfs->name, nm_len);
104 buf2[mp_len+nm_len] = '\0';
106 if (!cstrcmp (buf, buf2))
107 return vfs;
110 return 0;
113 vfs_t *vfs_list_add (char *name, unsigned attrib, char *mountpoint)
115 unsigned name_len = strlen (name);
116 unsigned mp_len = strlen (mountpoint);
118 vfs_t *vfs;
119 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
120 if (!strcmp (vfs->name, name) && !strcmp (vfs->mountpoint, mountpoint)) {
121 DPRINT (DBG_VFS, "ERROR -> vfs_list_add () - vfs object already exist !");
122 return 0;
126 /* alloc and init context */
127 vfs = (vfs_t *) kmalloc (sizeof (vfs_t));
129 if (!vfs)
130 return 0;
132 memset (vfs, 0, sizeof (vfs_t));
134 vfs->name = (char *) kmalloc (sizeof (char) * VFS_FILENAME_LEN + 2);
136 if (!vfs->name) {
137 kfree (vfs);
138 return 0;
141 memset (vfs->name, 0, VFS_FILENAME_LEN);
142 memcpy (vfs->name, name, name_len);
143 vfs->name[name_len] = '\0';
145 memset (vfs->mountpoint, 0, VFS_MOUNTPOINT_LEN);
146 memcpy (vfs->mountpoint, mountpoint, mp_len);
147 vfs->mountpoint[mp_len] = '\0';
149 vfs->attrib = attrib;
151 vfs->content = 0;
153 /* add into list */
154 vfs->next = &vfs_list;
155 vfs->prev = vfs_list.prev;
156 vfs->prev->next = vfs;
157 vfs->next->prev = vfs;
159 return vfs;
162 bool vfs_list_del (vfs_t *vfs)
164 if (!vfs)
165 return 0;
167 vfs->next->prev = vfs->prev;
168 vfs->prev->next = vfs->next;
170 if (vfs->content) {
171 if (vfs->content->ptr)
172 cache_closebyptr (vfs->content->ptr);
174 kfree (vfs->content);
177 return 1;
180 bool vfs_list_delbymp (char *mountpoint)
182 bool f = 0;
183 vfs_t *vfs;
184 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
185 if (!strncmp (vfs->mountpoint, mountpoint, strlen (mountpoint))) {
186 f = 1;
187 break;
191 if (f) {
192 vfs->next->prev = vfs->prev;
193 vfs->prev->next = vfs->next;
195 if (vfs->content) {
196 if (vfs->content->ptr)
197 kfree (vfs->content->ptr);
199 kfree (vfs->content);
202 //kfree (vfs);
203 return 1;
206 return 0;
209 int vfs_mmap (char *file, unsigned file_len, vfs_content_t *content)
211 vfs_t *vfs = vfs_find (file, file_len);
213 if (!vfs) {
214 errno_set (ENOENT);
216 DPRINT (DBG_VFS, "vfs_mmap () - file '%s' not found", file);
217 return 0;
220 if (vfs->attrib & VFS_FILEATTR_DIR) {
221 printf ("ERROR -> this is a directory, not an file\n");
222 return 0;
225 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
226 partition_t *p = (partition_t *) mount_find ((char *) vfs->mountpoint);
228 if (p) {
229 unsigned i = 0;
230 unsigned l = strlen (vfs->name);
232 while (strlen (dir[i].name)) {
233 if (!strncmp (vfs->name, dir[i].name, l))
234 return p->fs->handler (FS_ACT_WRITE, (char *) content, i, 0);
236 i ++;
239 DPRINT (DBG_VFS, "vfs_mmap () - file '%s' not found in mounted filesystem", file);
240 return 0;
241 } else {
242 printf ("ERROR -> device not respond\n");
243 errno_set (EIO);
244 return 0;
246 } else {
247 if (vfs->content) {
248 printf ("ERROR -> You can't overwrite content of this file\n");
249 errno_set (EINVAL);
250 return 0;
253 vfs->content = (vfs_content_t *) kmalloc (sizeof (vfs_content_t));
255 if (!vfs->content) {
256 errno_set (ENOMEM);
257 return 0;
260 /* NOTE: when file in VFS is device, we match it as READable */
261 if (!(vfs->attrib & VFS_FILEATTR_READ))
262 vfs->attrib |= VFS_FILEATTR_READ;
264 /*cache_t *cache = cache_create (data, len, 1);
266 if (!cache) {
267 errno_set (ENOMEM);
268 return 0;
271 vfs->content->ptr = content->ptr;
272 vfs->content->len = content->len;
275 return 1;
278 int vfs_read (char *file, unsigned file_len, vfs_content_t *content)
280 vfs_t *vfs = vfs_find (file, file_len);
282 if (!vfs)
283 return -2;
285 if (vfs->attrib & VFS_FILEATTR_DIR) {
286 printf ("ERROR -> This is a directory, not an file\n");
287 return -1;
290 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
291 partition_t *p = (partition_t *) mount_find ((char *) vfs->mountpoint);
293 if (p) {
294 unsigned i = 0;
295 unsigned l = strlen (vfs->name);
297 while (strlen (dir[i].name)) {
298 if (!strncmp (vfs->name, dir[i].name, l)) {
299 if (!p->fs->handler (FS_ACT_READ, (char *) content, i, 0)) {
300 printf ("ERROR -> Device read action\n");
301 return -3;
304 return i;
307 i ++;
309 } else {
310 printf ("ERROR -> device not respond\n");
311 return -1;
313 } else {
314 if (vfs->attrib & VFS_FILEATTR_DEVICE && !(vfs->attrib & VFS_FILEATTR_READ)) {
315 printf ("ERROR -> This file is non-char or non-block device\n");
316 return -1;
319 if (!vfs->content) {
320 printf ("ERROR -> This file not contain a valid data\n");
321 return -1;
324 if (!vfs->content->ptr) {
325 printf ("ERROR -> This file not contain a valid data\n");
326 return -4;
329 content->ptr = vfs->content->ptr;
330 content->len = vfs->content->len;
332 return 0;
335 return -2;
338 int vfs_cat (char *file, unsigned file_len)
340 unsigned long i;
341 vfs_content_t content;
342 content.ptr = 0;
343 content.len = 0;
345 int index = vfs_read (file, file_len, &content);
347 if (index < 0)
348 return index;
349 #ifdef ARCH_i386
350 paging_disable (); /* HACK: we can occasionally access user address space (behind kernel-space which is unmapped for us) */
351 #endif
352 if (content.ptr)
353 for (i = 0; i < content.len; i ++)
354 tty_putch (content.ptr[i]);
355 #ifdef ARCH_i386
356 paging_enable ();
357 #endif
358 return index;
361 int vfs_cp (char *what, unsigned what_len, char *where, unsigned where_len)
363 vfs_content_t content;
365 int index = vfs_read (what, what_len, &content);
367 if (index == -1)
368 return -2;
370 if (!vfs_touch (where, where_len))
371 return -1;
373 if (!vfs_mmap (where, where_len, &content))
374 return 0;
376 return 1;
379 int vfs_ls (char *file, unsigned file_len)
381 char ls[64];
383 vfs_t *vfs;
384 bool res = false;
386 if (!file_len) {
387 strcpy (ls, (char *) env_get ("PWD"));
388 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
389 if (!strcmp (vfs->mountpoint, ls)) {
390 printf ("%s\t", vfs->name);
391 res = true;
393 } else {
394 if (!strncmp(file,"/",1))
395 strcpy (ls,file);
396 else {
397 strcpy (ls,(char *) env_get ("PWD"));
398 strcpy (ls+strlen(ls),file);
401 if (strncmp(file+file_len-1,"/",1)) {
402 strcpy(ls+strlen(ls),"/");
405 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
406 if (!strcmp (vfs->mountpoint, ls) ||
407 !strcmp (vfs->mountpoint+1, ls)) {
408 printf ("%s\t", vfs->name);
409 res = true;
413 if (res)
414 printf ("\n");
416 return 1;
419 int vfs_cd (char *file, unsigned file_len)
421 /* go back */
422 if (!strcmp (file, "..")) {
423 char pwd[64];
424 strcpy (pwd, (char *) env_get ("PWD"));
426 unsigned pwd_len = strlen (pwd);
428 if (!strcmp (pwd, "/"))
429 return 0;
431 /* vymaze kus retezce - az po predposledni / */
432 pwd_len --; // preskoci / na konci retezce
433 while (pwd_len) {
434 pwd_len --;
435 if (pwd[pwd_len] == '/') {
436 pwd[pwd_len+1] = '\0';
437 break;
441 vfs_t *vfs;
442 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
443 if (!strcmp (vfs->mountpoint, pwd)) {
444 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
445 //printf ("vfs->mountpoint: %s | pwd: %s\n", vfs->mountpoint, pwd);
446 partition_t *p = mount_find (pwd);
448 if (p) {
449 mount (p, file, ""); // first return to last directory
451 umount (p, (char *) env_get ("PWD")); // then umount old directory
453 while (vfs_list_delbymp ((char *) env_get ("PWD")));
455 break;
456 } else {
457 printf ("ERROR -> device not respond\n");
458 return 0;
463 env_set ("PWD", pwd); // set new directory
465 return 1;
468 /* nothing */
469 if (!strcmp (file, "."))
470 return 1;
472 vfs_t *vfs;
473 /* go to root fs dir */
474 if (!strcmp (file, "/")) {
475 env_set ("PWD", file);
477 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
478 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
479 partition_t *p = mount_find ((char *) env_get ("PWD"));
481 if (p)
482 mount (p, file, "");
486 return 1;
489 /* go to another directory */
490 char pwd[64];
491 strcpy (pwd, (char *) env_get ("PWD"));
493 char buf[65];
494 unsigned pwd_len = strlen (pwd);
496 unsigned i = file[0] == '/' ? 1 : 0;
498 if (!i) {
499 memcpy (buf, pwd, pwd_len);
500 memcpy (buf+pwd_len, file+i, file_len-i);
501 buf[pwd_len+file_len-i] = '\0';
502 } else {
503 memcpy (buf, file, file_len);
504 buf[file_len] = '\0';
507 if (buf[pwd_len+file_len-i-1] == '/')
508 buf[pwd_len+file_len-i-1] = '\0';
510 unsigned buf_l = strlen (buf);
511 if (buf[buf_l-1] == '/')
512 buf[buf_l-1] = '\0';
514 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
515 unsigned mp_len = strlen (vfs->mountpoint);
516 unsigned nm_len = strlen (vfs->name);
518 char buf2[65];
519 memcpy (buf2, vfs->mountpoint, mp_len);
520 memcpy (buf2+mp_len, vfs->name, nm_len);
521 buf2[mp_len+nm_len] = '\0';
523 if (!cstrcmp (buf, buf2)) {
524 if (vfs->attrib & VFS_FILEATTR_FILE) {
525 printf ("ERROR -> this is a file, not an directory\n");
526 return 0;
529 // check permissions
530 if (vfs->attrib & VFS_FILEATTR_SYSTEM && strcmp ((char *) env_get ("USER"), "root")) {
531 printf ("ERROR -> only root can do that\n");
532 return 0;
535 memcpy (pwd, buf2, mp_len+nm_len);
536 pwd[mp_len+nm_len] = '/';
537 pwd[mp_len+nm_len+1] = '\0';
539 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
540 partition_t *p = mount_find ((char *) env_get ("PWD"));
542 if (p)
543 mount (p, file, pwd);
544 else {
545 printf ("ERROR -> device not respond\n");
546 return 0;
550 env_set ("PWD", pwd);
552 return 1;
556 return 0;
559 int vfs_mkdir (char *file, unsigned file_len)
561 if (!file_len)
562 return 0;
564 char pwd[64];
565 strcpy (pwd, (char *) env_get ("PWD"));
567 unsigned i;
568 for (i = file_len; i; i --) {
569 if (file[i] == '/') {
570 vfs_cd (file, i);
571 break;
575 char *path = 0;
576 char *f = 0;
578 if (i) {
579 path = (char *) kmalloc (sizeof (char) * (file_len+1));
581 if (!path)
582 return 0;
584 memcpy (path, file, i+1);
585 path[i+1] = '\0';
587 f = file + i + 1;
588 } else {
589 path = (char *) pwd;
590 f = file;
593 partition_t *p = mount_find ((char *) env_get ("PWD"));
595 if (p) {
596 vfs_list_add (f, VFS_FILEATTR_DIR | VFS_FILEATTR_READ | VFS_FILEATTR_BIN | VFS_FILEATTR_MOUNTED, (char *) path);
597 p->fs->handler (FS_ACT_MKDIR, file, 0, strlen (file));
598 } else {
599 vfs_list_add (f, VFS_FILEATTR_DIR | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, (char *) path);
600 DPRINT (DBG_VFS, "NOTE -> this directory is created only in virtual file system");
603 if (i) {
604 kfree (path);
605 vfs_cd (pwd, strlen (pwd));
608 DPRINT (DBG_VFS, "vfs_mkdir (%s)", file);
610 return 1;
613 int vfs_touch (char *file, unsigned file_len)
615 if (!file_len)
616 return 0;
618 char pwd[64];
619 strcpy (pwd, (char *) env_get ("PWD"));
621 unsigned i;
622 for (i = file_len; i; i --) {
623 if (file[i] == '/') {
624 vfs_cd (file, i);
625 break;
629 char *path = 0;
630 char *f = 0;
632 if (i) {
633 path = (char *) kmalloc (sizeof (char) * (file_len+1));
635 if (!path)
636 return 0;
638 memcpy (path, file, i+1);
639 path[i+1] = '\0';
641 f = file + i + 1;
642 } else {
643 path = (char *) pwd;
644 f = file;
647 partition_t *p = mount_find ((char *) env_get ("PWD"));
649 if (p) {
650 printf ("f: %s\n", f);
651 vfs_list_add (f, VFS_FILEATTR_FILE | VFS_FILEATTR_READ | VFS_FILEATTR_BIN | VFS_FILEATTR_MOUNTED, (char *) path);
652 p->fs->handler (FS_ACT_TOUCH, f, 0, strlen (f));
653 } else {
654 vfs_list_add (f, VFS_FILEATTR_FILE | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, (char *) path);
655 DPRINT (DBG_VFS, "NOTE -> this file is created only in virtual file system");
658 if (i) {
659 kfree (path);
660 vfs_cd (pwd, strlen (pwd));
663 DPRINT (DBG_VFS, "vfs_touch (%s)", file);
665 return 1;
668 int vfs_rm (char *file, unsigned file_len)
670 if (!file_len)
671 return 0;
673 char pwd[64];
674 strcpy (pwd, (char *) env_get ("PWD"));
676 unsigned i;
677 for (i = file_len; i; i --) {
678 if (file[i] == '/') {
679 vfs_cd (file, i);
680 break;
684 char *path = 0;
685 char *f = 0;
687 if (i) {
688 path = (char *) kmalloc (sizeof (char) * (file_len+1));
690 if (!path)
691 return 0;
693 memcpy (path, file, i+1);
694 path[i+1] = '\0';
696 f = file + i + 1;
697 } else {
698 path = (char *) pwd;
699 f = file;
702 vfs_t *vfs = vfs_list_find (f, (char *) path);
704 /* file not found */
705 if (!vfs)
706 return -1;
708 if (vfs->attrib & VFS_FILEATTR_SYSTEM || vfs->attrib & VFS_FILEATTR_DIR)
709 return -2;
711 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
712 partition_t *p = mount_find ((char *) pwd);
714 if (!p)
715 return 0;
717 p->fs->handler (FS_ACT_RM, file, 0, strlen (file));
718 } else {
719 /* delete vfs file with content */
720 vfs_list_del (vfs);
723 if (i) {
724 kfree (path);
725 vfs_cd (pwd, strlen (pwd));
728 DPRINT (DBG_VFS, "vfs_rm (%s)", file);
730 return 1;
733 vfs_dirent_t *vfs_dirent ()
735 char pwd[64];
736 strcpy (pwd, (char *) env_get ("PWD"));
738 vfs_t *vfs;
739 bool res = false;
741 unsigned dirents = 0;
743 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
744 if (!strcmp (vfs->mountpoint, pwd))
745 dirents ++;
747 if (!dirents)
748 return 0;
750 vfs_dirent_t *dirent = (vfs_dirent_t *) kmalloc (sizeof (vfs_dirent_t) * (dirents+1));
752 if (!dirent)
753 return 0;
755 unsigned i = 0;
756 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
757 if (!strcmp (vfs->mountpoint, pwd)) {
758 dirent[i].name = vfs->name;
760 dirent[i].attrib = vfs->attrib;
762 if ((i+1) == dirents)
763 dirent[i].next = 0;
764 else
765 dirent[i].next = 1;
767 i ++;
770 dirent[dirents].next = 0;
772 return dirent;
775 unsigned int init_vfs ()
777 mount_list.next = &mount_list;
778 mount_list.prev = &mount_list;
780 vfs_list.next = &vfs_list;
781 vfs_list.prev = &vfs_list;
783 if (!(kernel_attr & KERNEL_NOLIVE)) {
784 vfs_list_add ("bin", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
785 vfs_list_add ("cd", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
786 vfs_list_add ("ls", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
787 vfs_list_add ("exec", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
788 vfs_list_add ("dev", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
789 vfs_list_add ("etc", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
790 vfs_list_add ("mnt", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
791 vfs_list_add ("floppy", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
792 vfs_list_add ("cdrom", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
793 vfs_list_add ("hdd", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
794 vfs_list_add ("usr", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
795 vfs_list_add ("root", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/usr/");
796 vfs_list_add ("proc", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
799 /* let's build /proc/cpuinfo */
800 smp_cpu_check ();
802 return 1;