Kernel 0.6.3; ZNFS filesystem is able to create file, directories, change directory...
[ZeXOS.git] / kernel / core / vfs.c
blob41c2b070d9fa634a125422e3dbbaa90ca69ef345
1 /*
2 * ZeX/OS
3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <system.h>
23 #include <string.h>
24 #include <mount.h>
25 #include <vfs.h>
26 #include <smp.h>
27 #include <fd.h>
29 vfs_t vfs_list;
31 extern mount_t mount_list;
32 extern unsigned int fd_count;
34 vfs_t *vfs_list_find (char *name, char *mountpoint)
36 unsigned l = strlen (name);
38 vfs_t *vfs;
39 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
40 if (!strncmp (vfs->name, name, l) && !strcmp (vfs->mountpoint, mountpoint))
41 return vfs;
44 return 0;
47 vfs_t *vfs_list_findbymp (char *mountpoint)
49 char mdir[128];
50 char pwd[64];
51 strcpy (pwd, (char *) env_get ("PWD"));
52 unsigned l = strlen (pwd);
54 vfs_t *vfs;
55 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
56 if (strncmp (pwd, vfs->mountpoint, l))
57 continue;
59 sprintf (mdir, "%s%s/", vfs->mountpoint, vfs->name);
61 if (!strcmp (mdir, mountpoint))
62 return vfs;
65 return 0;
68 vfs_t *vfs_list_add (char *name, unsigned attrib, char *mountpoint)
70 unsigned name_len = strlen (name);
71 unsigned mp_len = strlen (mountpoint);
73 vfs_t *vfs;
74 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
75 if (!strcmp (vfs->name, name) && !strcmp (vfs->mountpoint, mountpoint)) {
76 DPRINT ("ERROR -> vfs_list_add () - vfs object already exist !\n");
77 return 0;
81 /* alloc and init context */
82 vfs = (vfs_t *) kmalloc (sizeof (vfs_t));
84 if (!vfs)
85 return 0;
87 memset (vfs, 0, sizeof (vfs_t));
89 vfs->name = (char *) kmalloc (sizeof (char) * VFS_FILENAME_LEN + 2);
91 if (!vfs->name) {
92 kfree (vfs);
93 return 0;
96 memset (vfs->name, 0, VFS_FILENAME_LEN);
97 memcpy (vfs->name, name, name_len);
98 vfs->name[name_len] = '\0';
100 memset (vfs->mountpoint, 0, VFS_MOUNTPOINT_LEN);
101 memcpy (vfs->mountpoint, mountpoint, mp_len);
102 vfs->mountpoint[mp_len] = '\0';
104 vfs->attrib = attrib;
106 vfs->content = 0;
108 /* add into list */
109 vfs->next = &vfs_list;
110 vfs->prev = vfs_list.prev;
111 vfs->prev->next = vfs;
112 vfs->next->prev = vfs;
114 return vfs;
117 bool vfs_list_del (vfs_t *vfs)
119 if (!vfs)
120 return 0;
122 vfs->next->prev = vfs->prev;
123 vfs->prev->next = vfs->next;
125 if (vfs->content) {
126 if (vfs->content->ptr)
127 kfree (vfs->content->ptr);
129 kfree (vfs->content);
132 return 1;
135 bool vfs_list_delbymp (char *mountpoint)
137 bool f = 0;
138 vfs_t *vfs;
139 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
140 if (!strncmp (vfs->mountpoint, mountpoint, strlen (mountpoint))) {
141 f = 1;
142 break;
146 if (f) {
147 vfs->next->prev = vfs->prev;
148 vfs->prev->next = vfs->next;
150 if (vfs->content) {
151 if (vfs->content->ptr)
152 kfree (vfs->content->ptr);
154 kfree (vfs->content);
157 //kfree (vfs);
158 return 1;
161 return 0;
164 bool vfs_mmap (char *file, unsigned file_len, char *data, unsigned long len)
166 vfs_t *vfs;
168 char pwd[64];
169 strcpy (pwd, (char *) env_get ("PWD"));
171 char buf[65];
172 unsigned pwd_len = strlen (pwd);
174 unsigned i = file[0] == '/' ? 1 : 0;
176 if (!i) {
177 memcpy (buf, pwd, pwd_len);
178 memcpy (buf+pwd_len, file+i, file_len-i);
179 buf[pwd_len+file_len-i] = '\0';
180 } else {
181 memcpy (buf, file, file_len);
182 buf[file_len] = '\0';
185 if (buf[pwd_len+file_len-i-1] == '/')
186 buf[pwd_len+file_len-i-1] = '\0';
188 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
189 unsigned mp_len = strlen (vfs->mountpoint);
190 unsigned nm_len = strlen (vfs->name);
192 char buf2[65];
193 memcpy (buf2, vfs->mountpoint, mp_len);
194 memcpy (buf2+mp_len, vfs->name, nm_len);
195 buf2[mp_len+nm_len] = '\0';
197 if (!cstrcmp (buf, buf2)) {
198 if (vfs->attrib & VFS_FILEATTR_DIR) {
199 printf ("ERROR -> this is a directory, not an file\n");
200 return 0;
203 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
204 partition_t *p = (partition_t *) partition_findbyfile (file);
206 if (p) {
207 i = 0;
209 while (strlen (dir[i].name)) {
210 if (!strncmp (file, dir[i].name, file_len))
211 return p->fs->handler (FS_ACT_WRITE, data, i, len);
213 i ++;
216 return 0;
217 } else {
218 printf ("ERROR -> device not respond\n");
219 return 0;
221 } else {
222 if (vfs->content) {
223 printf ("ERROR -> You can't overwrite content of this file\n");
224 return 1;
227 vfs->content = (vfs_content_t *) kmalloc (sizeof (vfs_content_t));
229 if (!vfs->content)
230 return 1;
232 /*vfs->content->ptr = (char *) kmalloc (sizeof (char) * (len+1));
234 if (!vfs->content->ptr) {
235 kfree (vfs->content);
236 vfs->content = 0;
237 return 0;
240 memcpy (vfs->content->ptr, data, len);
241 vfs->content->ptr[len] = '\0';*/
243 vfs->content->ptr = data;
245 vfs->content->len = len;
248 return 1;
251 return 0;
254 extern unsigned long file_cache_id;
255 int vfs_read (char *file, unsigned file_len)
257 vfs_t *vfs;
259 char pwd[64];
260 strcpy (pwd, (char *) env_get ("PWD"));
262 char buf[65];
263 unsigned pwd_len = strlen (pwd);
265 char *block;
266 unsigned long len;
268 unsigned i = file[0] == '/' ? 1 : 0;
270 if (!i) {
271 memcpy (buf, pwd, pwd_len);
272 memcpy (buf+pwd_len, file+i, file_len-i);
273 buf[pwd_len+file_len-i] = '\0';
274 } else {
275 memcpy (buf, file, file_len);
276 buf[file_len] = '\0';
279 if (buf[pwd_len+file_len-i-1] == '/')
280 buf[pwd_len+file_len-i-1] = '\0';
282 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
283 unsigned mp_len = strlen (vfs->mountpoint);
284 unsigned nm_len = strlen (vfs->name);
286 char buf2[65];
287 memcpy (buf2, vfs->mountpoint, mp_len);
288 memcpy (buf2+mp_len, vfs->name, nm_len);
289 buf2[mp_len+nm_len] = '\0';
291 if (!cstrcmp (buf, buf2)) {
292 if (vfs->attrib & VFS_FILEATTR_DIR) {
293 printf ("ERROR -> this is a directory, not an file\n");
294 return -1;
297 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
298 partition_t *p = (partition_t *) partition_findbyfile (file);
300 if (p) {
301 i = 0;
303 while (strlen (dir[i].name)) {
304 if (!strncmp (file, dir[i].name, file_len)) {
305 p->fs->handler (FS_ACT_READ, block, i, len);
307 return i;
310 i ++;
312 } else {
313 printf ("ERROR -> device not respond\n");
314 return -1;
316 } else {
317 if (vfs->attrib & VFS_FILEATTR_DEVICE) {
318 return 0;
321 if (!vfs->content) {
322 printf ("ERROR -> This file not contain a valid data\n");
323 return -1;
326 file_cache = vfs->content->ptr;
327 file_cache_id = vfs->content->len;
329 return 0;
332 return -1;
336 return -2;
339 bool vfs_cat (char *file, unsigned file_len)
341 unsigned long i;
342 int index;
344 index = vfs_read (file, file_len);
346 if (index == -1)
347 return 0;
349 for (i = 0; i < file_cache_id; i ++)
350 tty_putch (file_cache[i]);
352 return 1;
355 bool vfs_ls (char *file, unsigned file_len)
357 char ls[64];
359 vfs_t *vfs;
360 bool res = false;
362 if (!file_len) {
363 strcpy (ls, (char *) env_get ("PWD"));
364 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
365 if (!strcmp (vfs->mountpoint, ls)) {
366 printf ("%s\t", vfs->name);
367 res = true;
369 } else {
370 if (!strncmp(file,"/",1)) {
371 strcpy (ls,file);
372 } else {
373 strcpy (ls,(char *) env_get ("PWD"));
374 strcpy (ls+strlen(ls),file);
377 if (strncmp(file+file_len-1,"/",1)) {
378 strcpy(ls+strlen(ls),"/");
381 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
382 if (!strcmp (vfs->mountpoint, ls) ||
383 !strcmp (vfs->mountpoint+1, ls)) {
384 printf ("%s\t", vfs->name);
385 res = true;
389 /*printf ("%s\t%u%u%u%u%u%u%u\n", vfs->name,
390 vfs->attrib & VFS_FILEATTR_READ,
391 vfs->attrib & VFS_FILEATTR_WRITE,
392 vfs->attrib & VFS_FILEATTR_HIDDEN,
393 vfs->attrib & VFS_FILEATTR_SYSTEM,
394 vfs->attrib & VFS_FILEATTR_DIR,
395 vfs->attrib & VFS_FILEATTR_BIN);*/
397 if (res)
398 printf ("\n");
400 return 1;
403 bool vfs_cd (char *file, unsigned file_len)
405 /* go back */
406 if (!strcmp (file, "..")) {
407 char pwd[64];
408 strcpy (pwd, (char *) env_get ("PWD"));
410 unsigned pwd_len = strlen (pwd);
412 if (!strcmp (pwd, "/"))
413 return 0;
415 /* vymaze kus retezce - az po predposledni / */
416 pwd_len --; // preskoci / na konci retezce
417 while (pwd_len) {
418 pwd_len --;
419 if (pwd[pwd_len] == '/') {
420 pwd[pwd_len+1] = '\0';
421 break;
425 vfs_t *vfs;
426 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
427 if (!strcmp (vfs->mountpoint, pwd)) {
428 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
429 //printf ("vfs->mountpoint: %s | pwd: %s\n", vfs->mountpoint, pwd);
430 partition_t *p = mount_find (pwd);
432 if (p) {
433 mount (p, file, ""); // first return to last directory
435 umount (p, (char *) env_get ("PWD")); // then umount old directory
437 while (vfs_list_delbymp ((char *) env_get ("PWD")));
439 break;
440 } else {
441 printf ("ERROR -> device not respond\n");
442 return 0;
447 env_set ("PWD", pwd); // set new directory
449 return 1;
452 /* nothing */
453 if (!strcmp (file, "."))
454 return 1;
456 vfs_t *vfs;
457 /* go to root fs dir */
458 if (!strcmp (file, "/")) {
459 env_set ("PWD", file);
461 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
462 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
463 partition_t *p = mount_find ((char *) env_get ("PWD"));
465 if (p)
466 mount (p, file, "");
470 return 1;
473 /* go to another directory */
474 char pwd[64];
475 strcpy (pwd, (char *) env_get ("PWD"));
477 char buf[65];
478 unsigned pwd_len = strlen (pwd);
480 unsigned i = file[0] == '/' ? 1 : 0;
482 if (!i) {
483 memcpy (buf, pwd, pwd_len);
484 memcpy (buf+pwd_len, file+i, file_len-i);
485 buf[pwd_len+file_len-i] = '\0';
486 } else {
487 memcpy (buf, file, file_len);
488 buf[file_len] = '\0';
491 if (buf[pwd_len+file_len-i-1] == '/')
492 buf[pwd_len+file_len-i-1] = '\0';
494 unsigned buf_l = strlen (buf);
495 if (buf[buf_l-1] == '/')
496 buf[buf_l-1] = '\0';
498 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
499 unsigned mp_len = strlen (vfs->mountpoint);
500 unsigned nm_len = strlen (vfs->name);
502 char buf2[65];
503 memcpy (buf2, vfs->mountpoint, mp_len);
504 memcpy (buf2+mp_len, vfs->name, nm_len);
505 buf2[mp_len+nm_len] = '\0';
507 if (!cstrcmp (buf, buf2)) {
508 if (vfs->attrib & VFS_FILEATTR_FILE) {
509 printf ("ERROR -> this is a file, not an directory\n");
510 return 0;
513 // check permissions
514 if (vfs->attrib & VFS_FILEATTR_SYSTEM && strcmp ((char *) env_get ("USER"), "root")) {
515 printf ("ERROR -> only root can do that\n");
516 return 0;
519 memcpy (pwd, buf2, mp_len+nm_len);
520 pwd[mp_len+nm_len] = '/';
521 pwd[mp_len+nm_len+1] = '\0';
523 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
524 partition_t *p = mount_find ((char *) env_get ("PWD"));
526 if (p)
527 mount (p, file, pwd);
528 else {
529 printf ("ERROR -> device not respond\n");
530 return 0;
534 env_set ("PWD", pwd);
536 return 1;
540 return 0;
543 bool vfs_mkdir (char *file, unsigned file_len)
545 if (file_len) {
546 char pwd[64];
547 strcpy (pwd, (char *) env_get ("PWD"));
549 partition_t *p = mount_find ((char *) pwd);
551 if (p) {
552 vfs_list_add (file, VFS_FILEATTR_DIR | VFS_FILEATTR_READ | VFS_FILEATTR_MOUNTED, (char *) pwd);
553 p->fs->handler (FS_ACT_MKDIR, file, 0, file_len);
554 } else {
555 vfs_list_add (file, VFS_FILEATTR_DIR | VFS_FILEATTR_READ, (char *) pwd);
556 DPRINT ("NOTE -> this directory is created only in virtual file system\n");
559 DPRINT ("vfs_mkdir ()\n");
560 return 1;
563 return 0;
566 bool vfs_touch (char *file, unsigned file_len)
568 if (file_len) {
569 char pwd[64];
570 strcpy (pwd, (char *) env_get ("PWD"));
572 unsigned i;
573 for (i = file_len; i; i --) {
574 if (file[i] == '/') {
575 vfs_cd (file, i);
576 break;
580 char *path = 0;
581 char *f = 0;
583 if (i) {
584 path = (char *) kmalloc (sizeof (char) * (file_len+1));
586 if (!path)
587 return 0;
589 memcpy (path, file, i+1);
590 path[i+1] = '\0';
592 f = file + i + 1;
593 } else {
594 path = (char *) pwd;
595 f = file;
598 partition_t *p = mount_find ((char *) pwd);
600 if (p) {
601 vfs_list_add (f, VFS_FILEATTR_FILE | VFS_FILEATTR_READ | VFS_FILEATTR_BIN | VFS_FILEATTR_MOUNTED, (char *) path);
602 p->fs->handler (FS_ACT_TOUCH, file, 0, strlen (file));
603 } else {
604 vfs_list_add (f, VFS_FILEATTR_FILE | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, (char *) path);
605 DPRINT ("NOTE -> this file is created only in virtual file system\n");
608 if (i) {
609 kfree (path);
610 vfs_cd (pwd, strlen (pwd));
613 DPRINT ("vfs_touch ()\n");
614 return 1;
617 return 0;
620 int vfs_rm (char *file, unsigned file_len)
622 if (file_len) {
623 char pwd[64];
624 strcpy (pwd, (char *) env_get ("PWD"));
626 unsigned i;
627 for (i = file_len; i; i --) {
628 if (file[i] == '/') {
629 vfs_cd (file, i);
630 break;
634 char *path = 0;
635 char *f = 0;
637 if (i) {
638 path = (char *) kmalloc (sizeof (char) * (file_len+1));
640 if (!path)
641 return 0;
643 memcpy (path, file, i+1);
644 path[i+1] = '\0';
646 f = file + i + 1;
647 } else {
648 path = (char *) pwd;
649 f = file;
652 vfs_t *vfs = vfs_list_find (f, (char *) path);
654 /* file not found */
655 if (!vfs)
656 return -1;
658 if (vfs->attrib & VFS_FILEATTR_SYSTEM || vfs->attrib & VFS_FILEATTR_DIR)
659 return -2;
661 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
662 partition_t *p = mount_find ((char *) pwd);
664 if (!p)
665 return 0;
667 p->fs->handler (FS_ACT_RM, file, 0, strlen (file));
668 } else {
669 /* delete vfs file with content */
670 vfs_list_del (vfs);
673 if (i) {
674 kfree (path);
675 vfs_cd (pwd, strlen (pwd));
678 DPRINT ("vfs_rm ()\n");
679 return 1;
682 return 0;
685 vfs_dirent_t *vfs_dirent ()
687 char pwd[64];
688 strcpy (pwd, (char *) env_get ("PWD"));
690 vfs_t *vfs;
691 bool res = false;
693 unsigned dirents = 0;
695 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
696 if (!strcmp (vfs->mountpoint, pwd))
697 dirents ++;
699 if (!dirents)
700 return 0;
702 vfs_dirent_t *dirent = (vfs_dirent_t *) kmalloc (sizeof (vfs_dirent_t) * (dirents+1));
704 if (!dirent)
705 return 0;
707 unsigned i = 0;
708 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
709 if (!strcmp (vfs->mountpoint, pwd)) {
710 /*unsigned len = strlen (vfs->name);
711 dirent[i].name = (char *) kmalloc (sizeof (char) * (len + 1));
713 if (!dirent[i].name)
714 return 0;
716 memcpy (dirent[i].name, vfs->name, len);
717 dirent[i].name[len] = '\0';*/
718 dirent[i].name = vfs->name;
720 dirent[i].attrib = vfs->attrib;
722 if ((i+1) == dirents)
723 dirent[i].next = 0;
724 else
725 dirent[i].next = 1;
727 i ++;
730 dirent[dirents].next = 0;
732 return dirent;
735 unsigned int init_vfs ()
737 mount_list.next = &mount_list;
738 mount_list.prev = &mount_list;
740 vfs_list.next = &vfs_list;
741 vfs_list.prev = &vfs_list;
743 vfs_list_add ("bin", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
744 vfs_list_add ("cd", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
745 vfs_list_add ("ls", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
746 vfs_list_add ("exec", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
747 vfs_list_add ("dev", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
748 vfs_list_add ("etc", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
749 vfs_list_add ("mnt", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
750 vfs_list_add ("floppy", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
751 vfs_list_add ("cdrom", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
752 vfs_list_add ("hdd", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
753 vfs_list_add ("usr", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
754 vfs_list_add ("root", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/usr/");
755 vfs_list_add ("proc", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
757 /* let's build /proc/cpuinfo */
758 smp_cpu_check ();
760 return 1;