All user-space apps ware moved to 8MB virtual address address (link.ld changes);...
[ZeXOS.git] / kernel / core / vfs.c
blobc4fc1452676f26b8a86690de2600417d3fb45702
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 <errno.h>
26 #include <vfs.h>
27 #include <smp.h>
28 #include <fd.h>
30 vfs_t vfs_list;
32 extern mount_t mount_list;
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 !");
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 int 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 DPRINT ("vfs_mmap () - file '%s' not found in mounted filesystem", file);
217 return 0;
218 } else {
219 printf ("ERROR -> device not respond\n");
220 errno_set (EIO);
221 return 0;
223 } else {
224 if (vfs->content) {
225 printf ("ERROR -> You can't overwrite content of this file\n");
226 errno_set (EINVAL);
227 return 0;
230 vfs->content = (vfs_content_t *) kmalloc (sizeof (vfs_content_t));
232 if (!vfs->content) {
233 errno_set (ENOMEM);
234 return 0;
237 /* NOTE: when file in VFS is device, we match it as READable */
238 if (!(vfs->attrib & VFS_FILEATTR_READ))
239 vfs->attrib |= VFS_FILEATTR_READ;
241 vfs->content->ptr = data;
243 vfs->content->len = len;
246 return 1;
250 errno_set (ENOENT);
252 DPRINT ("vfs_mmap () - file '%s' not found", file);
254 return 0;
257 extern unsigned long file_cache_id;
258 int vfs_read (char *file, unsigned file_len)
260 vfs_t *vfs;
262 char pwd[64];
263 strcpy (pwd, (char *) env_get ("PWD"));
265 char buf[65];
266 unsigned pwd_len = strlen (pwd);
268 char block[4096];
269 unsigned long len;
271 unsigned i = file[0] == '/' ? 1 : 0;
273 if (!i) {
274 memcpy (buf, pwd, pwd_len);
275 memcpy (buf+pwd_len, file+i, file_len-i);
276 buf[pwd_len+file_len-i] = '\0';
277 } else {
278 memcpy (buf, file, file_len);
279 buf[file_len] = '\0';
282 if (buf[pwd_len+file_len-i-1] == '/')
283 buf[pwd_len+file_len-i-1] = '\0';
285 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
286 unsigned mp_len = strlen (vfs->mountpoint);
287 unsigned nm_len = strlen (vfs->name);
289 char buf2[128];
290 memcpy (buf2, vfs->mountpoint, mp_len);
291 memcpy (buf2+mp_len, vfs->name, nm_len);
292 buf2[mp_len+nm_len] = '\0';
294 if (!cstrcmp (buf, buf2)) {
295 if (vfs->attrib & VFS_FILEATTR_DIR) {
296 printf ("ERROR -> This is a directory, not an file\n");
297 return -1;
300 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
301 partition_t *p = (partition_t *) partition_findbyfile (file);
303 if (p) {
304 i = 0;
306 while (strlen (dir[i].name)) {
307 if (!strncmp (file, dir[i].name, file_len)) {
308 file_cache = (unsigned char *) FILE_CACHE; // file_cache store address
310 if (!p->fs->handler (FS_ACT_READ, block, i, len)) {
311 file_cache_id = 0;
312 printf ("ERROR -> Device read action\n");
313 return -3;
316 return i;
319 i ++;
321 } else {
322 printf ("ERROR -> device not respond\n");
323 return -1;
325 } else {
326 if (vfs->attrib & VFS_FILEATTR_DEVICE && !(vfs->attrib & VFS_FILEATTR_READ)) {
327 file_cache_id = 0;
328 printf ("ERROR -> This file is non-char or non-block device\n");
329 return -1;
332 if (!vfs->content) {
333 printf ("ERROR -> This file not contain a valid data\n");
334 file_cache_id = 0;
335 return -1;
338 if (!vfs->content->ptr) {
339 printf ("ERROR -> This file not contain a valid data\n");
340 return -4;
343 file_cache = vfs->content->ptr;
344 file_cache_id = vfs->content->len;
346 return 0;
349 file_cache_id = 0;
351 return -2;
355 file_cache_id = 0;
357 return -2;
360 int vfs_cat (char *file, unsigned file_len)
362 unsigned long i;
363 int index;
365 index = vfs_read (file, file_len);
367 if (index == -1)
368 return index;
370 for (i = 0; i < file_cache_id; i ++)
371 tty_putch (file_cache[i]);
373 return index;
376 int vfs_cp (char *what, unsigned what_len, char *where, unsigned where_len)
378 unsigned long i;
379 int index;
381 index = vfs_read (what, what_len);
383 if (index == -1)
384 return -2;
386 if (!vfs_touch (where, where_len))
387 return -1;
389 if (!vfs_mmap (where, where_len, file_cache, file_cache_id))
390 return 0;
392 return 1;
395 int vfs_ls (char *file, unsigned file_len)
397 char ls[64];
399 vfs_t *vfs;
400 bool res = false;
402 if (!file_len) {
403 strcpy (ls, (char *) env_get ("PWD"));
404 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
405 if (!strcmp (vfs->mountpoint, ls)) {
406 printf ("%s\t", vfs->name);
407 res = true;
409 } else {
410 if (!strncmp(file,"/",1)) {
411 strcpy (ls,file);
412 } else {
413 strcpy (ls,(char *) env_get ("PWD"));
414 strcpy (ls+strlen(ls),file);
417 if (strncmp(file+file_len-1,"/",1)) {
418 strcpy(ls+strlen(ls),"/");
421 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
422 if (!strcmp (vfs->mountpoint, ls) ||
423 !strcmp (vfs->mountpoint+1, ls)) {
424 printf ("%s\t", vfs->name);
425 res = true;
429 /*printf ("%s\t%u%u%u%u%u%u%u\n", vfs->name,
430 vfs->attrib & VFS_FILEATTR_READ,
431 vfs->attrib & VFS_FILEATTR_WRITE,
432 vfs->attrib & VFS_FILEATTR_HIDDEN,
433 vfs->attrib & VFS_FILEATTR_SYSTEM,
434 vfs->attrib & VFS_FILEATTR_DIR,
435 vfs->attrib & VFS_FILEATTR_BIN);*/
437 if (res)
438 printf ("\n");
440 return 1;
443 int vfs_cd (char *file, unsigned file_len)
445 /* go back */
446 if (!strcmp (file, "..")) {
447 char pwd[64];
448 strcpy (pwd, (char *) env_get ("PWD"));
450 unsigned pwd_len = strlen (pwd);
452 if (!strcmp (pwd, "/"))
453 return 0;
455 /* vymaze kus retezce - az po predposledni / */
456 pwd_len --; // preskoci / na konci retezce
457 while (pwd_len) {
458 pwd_len --;
459 if (pwd[pwd_len] == '/') {
460 pwd[pwd_len+1] = '\0';
461 break;
465 vfs_t *vfs;
466 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
467 if (!strcmp (vfs->mountpoint, pwd)) {
468 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
469 //printf ("vfs->mountpoint: %s | pwd: %s\n", vfs->mountpoint, pwd);
470 partition_t *p = mount_find (pwd);
472 if (p) {
473 mount (p, file, ""); // first return to last directory
475 umount (p, (char *) env_get ("PWD")); // then umount old directory
477 while (vfs_list_delbymp ((char *) env_get ("PWD")));
479 break;
480 } else {
481 printf ("ERROR -> device not respond\n");
482 return 0;
487 env_set ("PWD", pwd); // set new directory
489 return 1;
492 /* nothing */
493 if (!strcmp (file, "."))
494 return 1;
496 vfs_t *vfs;
497 /* go to root fs dir */
498 if (!strcmp (file, "/")) {
499 env_set ("PWD", file);
501 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
502 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
503 partition_t *p = mount_find ((char *) env_get ("PWD"));
505 if (p)
506 mount (p, file, "");
510 return 1;
513 /* go to another directory */
514 char pwd[64];
515 strcpy (pwd, (char *) env_get ("PWD"));
517 char buf[65];
518 unsigned pwd_len = strlen (pwd);
520 unsigned i = file[0] == '/' ? 1 : 0;
522 if (!i) {
523 memcpy (buf, pwd, pwd_len);
524 memcpy (buf+pwd_len, file+i, file_len-i);
525 buf[pwd_len+file_len-i] = '\0';
526 } else {
527 memcpy (buf, file, file_len);
528 buf[file_len] = '\0';
531 if (buf[pwd_len+file_len-i-1] == '/')
532 buf[pwd_len+file_len-i-1] = '\0';
534 unsigned buf_l = strlen (buf);
535 if (buf[buf_l-1] == '/')
536 buf[buf_l-1] = '\0';
538 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next) {
539 unsigned mp_len = strlen (vfs->mountpoint);
540 unsigned nm_len = strlen (vfs->name);
542 char buf2[65];
543 memcpy (buf2, vfs->mountpoint, mp_len);
544 memcpy (buf2+mp_len, vfs->name, nm_len);
545 buf2[mp_len+nm_len] = '\0';
547 if (!cstrcmp (buf, buf2)) {
548 if (vfs->attrib & VFS_FILEATTR_FILE) {
549 printf ("ERROR -> this is a file, not an directory\n");
550 return 0;
553 // check permissions
554 if (vfs->attrib & VFS_FILEATTR_SYSTEM && strcmp ((char *) env_get ("USER"), "root")) {
555 printf ("ERROR -> only root can do that\n");
556 return 0;
559 memcpy (pwd, buf2, mp_len+nm_len);
560 pwd[mp_len+nm_len] = '/';
561 pwd[mp_len+nm_len+1] = '\0';
563 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
564 partition_t *p = mount_find ((char *) env_get ("PWD"));
566 if (p)
567 mount (p, file, pwd);
568 else {
569 printf ("ERROR -> device not respond\n");
570 return 0;
574 env_set ("PWD", pwd);
576 return 1;
580 return 0;
583 int vfs_mkdir (char *file, unsigned file_len)
585 if (file_len) {
586 char pwd[64];
587 strcpy (pwd, (char *) env_get ("PWD"));
589 unsigned i;
590 for (i = file_len; i; i --) {
591 if (file[i] == '/') {
592 vfs_cd (file, i);
593 break;
597 char *path = 0;
598 char *f = 0;
600 if (i) {
601 path = (char *) kmalloc (sizeof (char) * (file_len+1));
603 if (!path)
604 return 0;
606 memcpy (path, file, i+1);
607 path[i+1] = '\0';
609 f = file + i + 1;
610 } else {
611 path = (char *) pwd;
612 f = file;
615 partition_t *p = mount_find ((char *) env_get ("PWD"));
617 if (p) {
618 vfs_list_add (f, VFS_FILEATTR_DIR | VFS_FILEATTR_READ | VFS_FILEATTR_BIN | VFS_FILEATTR_MOUNTED, (char *) path);
619 p->fs->handler (FS_ACT_MKDIR, file, 0, strlen (file));
620 } else {
621 vfs_list_add (f, VFS_FILEATTR_DIR | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, (char *) path);
622 DPRINT ("NOTE -> this directory is created only in virtual file system");
625 if (i) {
626 kfree (path);
627 vfs_cd (pwd, strlen (pwd));
630 DPRINT ("vfs_mkdir ()");
631 return 1;
634 return 0;
637 int vfs_touch (char *file, unsigned file_len)
639 if (file_len) {
640 char pwd[64];
641 strcpy (pwd, (char *) env_get ("PWD"));
643 unsigned i;
644 for (i = file_len; i; i --) {
645 if (file[i] == '/') {
646 vfs_cd (file, i);
647 break;
651 char *path = 0;
652 char *f = 0;
654 if (i) {
655 path = (char *) kmalloc (sizeof (char) * (file_len+1));
657 if (!path)
658 return 0;
660 memcpy (path, file, i+1);
661 path[i+1] = '\0';
663 f = file + i + 1;
664 } else {
665 path = (char *) pwd;
666 f = file;
669 partition_t *p = mount_find ((char *) env_get ("PWD"));
671 if (p) {
672 vfs_list_add (f, VFS_FILEATTR_FILE | VFS_FILEATTR_READ | VFS_FILEATTR_BIN | VFS_FILEATTR_MOUNTED, (char *) path);
673 p->fs->handler (FS_ACT_TOUCH, file, 0, strlen (file));
674 } else {
675 vfs_list_add (f, VFS_FILEATTR_FILE | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, (char *) path);
676 DPRINT ("NOTE -> this file is created only in virtual file system");
679 if (i) {
680 kfree (path);
681 vfs_cd (pwd, strlen (pwd));
684 DPRINT ("vfs_touch ()");
685 return 1;
688 return 0;
691 int vfs_rm (char *file, unsigned file_len)
693 if (file_len) {
694 char pwd[64];
695 strcpy (pwd, (char *) env_get ("PWD"));
697 unsigned i;
698 for (i = file_len; i; i --) {
699 if (file[i] == '/') {
700 vfs_cd (file, i);
701 break;
705 char *path = 0;
706 char *f = 0;
708 if (i) {
709 path = (char *) kmalloc (sizeof (char) * (file_len+1));
711 if (!path)
712 return 0;
714 memcpy (path, file, i+1);
715 path[i+1] = '\0';
717 f = file + i + 1;
718 } else {
719 path = (char *) pwd;
720 f = file;
723 vfs_t *vfs = vfs_list_find (f, (char *) path);
725 /* file not found */
726 if (!vfs)
727 return -1;
729 if (vfs->attrib & VFS_FILEATTR_SYSTEM || vfs->attrib & VFS_FILEATTR_DIR)
730 return -2;
732 if (vfs->attrib & VFS_FILEATTR_MOUNTED) {
733 partition_t *p = mount_find ((char *) pwd);
735 if (!p)
736 return 0;
738 p->fs->handler (FS_ACT_RM, file, 0, strlen (file));
739 } else {
740 /* delete vfs file with content */
741 vfs_list_del (vfs);
744 if (i) {
745 kfree (path);
746 vfs_cd (pwd, strlen (pwd));
749 DPRINT ("vfs_rm ()");
750 return 1;
753 return 0;
756 vfs_dirent_t *vfs_dirent ()
758 char pwd[64];
759 strcpy (pwd, (char *) env_get ("PWD"));
761 vfs_t *vfs;
762 bool res = false;
764 unsigned dirents = 0;
766 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
767 if (!strcmp (vfs->mountpoint, pwd))
768 dirents ++;
770 if (!dirents)
771 return 0;
773 vfs_dirent_t *dirent = (vfs_dirent_t *) kmalloc (sizeof (vfs_dirent_t) * (dirents+1));
775 if (!dirent)
776 return 0;
778 unsigned i = 0;
779 for (vfs = vfs_list.next; vfs != &vfs_list; vfs = vfs->next)
780 if (!strcmp (vfs->mountpoint, pwd)) {
781 /*unsigned len = strlen (vfs->name);
782 dirent[i].name = (char *) kmalloc (sizeof (char) * (len + 1));
784 if (!dirent[i].name)
785 return 0;
787 memcpy (dirent[i].name, vfs->name, len);
788 dirent[i].name[len] = '\0';*/
789 dirent[i].name = vfs->name;
791 dirent[i].attrib = vfs->attrib;
793 if ((i+1) == dirents)
794 dirent[i].next = 0;
795 else
796 dirent[i].next = 1;
798 i ++;
801 dirent[dirents].next = 0;
803 return dirent;
806 unsigned int init_vfs ()
808 mount_list.next = &mount_list;
809 mount_list.prev = &mount_list;
811 vfs_list.next = &vfs_list;
812 vfs_list.prev = &vfs_list;
814 if (!(kernel_attr & KERNEL_NOLIVE)) {
815 vfs_list_add ("bin", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
816 vfs_list_add ("cd", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
817 vfs_list_add ("ls", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
818 vfs_list_add ("exec", VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ | VFS_FILEATTR_BIN, "/bin/");
819 vfs_list_add ("dev", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
820 vfs_list_add ("etc", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
821 vfs_list_add ("mnt", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
822 vfs_list_add ("floppy", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
823 vfs_list_add ("cdrom", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
824 vfs_list_add ("hdd", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/mnt/");
825 vfs_list_add ("usr", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
826 vfs_list_add ("root", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/usr/");
827 vfs_list_add ("proc", VFS_FILEATTR_DIR | VFS_FILEATTR_SYSTEM | VFS_FILEATTR_READ, "/");
830 /* let's build /proc/cpuinfo */
831 smp_cpu_check ();
833 return 1;