001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021 #include <sos/assert.h>
022 #include <sos/list.h>
023 #include <sos/kmem_slab.h>
024 #include <sos/kmalloc.h>
025 #include "chardev.h"
026
027 #include "fs.h"
028
029
030
031 static struct sos_fs_manager_type * fs_list = NULL;
032
033
034 static sos_ui64_t last_fs_instance_uid;
035
036
037
038
039
040 static sos_ret_t fs_fetch_node(struct sos_fs_manager_instance *fs,
041 sos_ui64_t storage_location,
042 struct sos_fs_node ** result_fsnode);
043
044 static sos_ret_t
045 fs_allocate_node(struct sos_fs_manager_instance * fs,
046 sos_fs_node_type_t type,
047 sos_ui32_t flags,
048 const struct sos_process * creator,
049 sos_ui32_t access_rights,
050 struct sos_fs_node ** result_fsnode);
051
052 static sos_ret_t mark_dirty_fsnode(struct sos_fs_node * fsnode,
053 sos_bool_t force_sync);
054
055 static sos_ret_t sos_fs_sync_node(struct sos_fs_node * fsnode);
056
057 static sos_ret_t sos_fs_sync_fs(struct sos_fs_manager_instance * fs);
058
059 static sos_ret_t
060 fs_lookup_node(const struct sos_fs_pathname * path,
061 sos_bool_t follow_symlinks,
062 const struct sos_fs_nscache_node * root_nsnode,
063 const struct sos_fs_nscache_node * start_nsnode,
064 struct sos_fs_nscache_node ** result_nsnode,
065 struct sos_fs_pathname * result_remaining_path,
066 int lookup_recursion_level);
067
068 static sos_ret_t
069 fs_resolve_symlink(const struct sos_fs_nscache_node * root_nsnode,
070 const struct sos_fs_nscache_node * symlink_nsnode,
071 struct sos_fs_nscache_node ** target_nsnode,
072 int lookup_recursion_level);
073
074 static sos_ret_t
075 fs_register_child_node(const struct sos_process * creator,
076 struct sos_fs_nscache_node * parent_nsnode,
077 const struct sos_fs_pathname * name,
078 struct sos_fs_node * fsnode,
079 sos_ui32_t flags,
080 struct sos_fs_nscache_node ** result_nsnode);
081
082 static sos_ret_t
083 fs_create_child_node(struct sos_fs_nscache_node * parent_nsnode,
084 const struct sos_fs_pathname * name,
085 sos_fs_node_type_t type,
086 sos_ui32_t flags,
087 const struct sos_process * creator,
088 sos_ui32_t access_rights,
089 struct sos_fs_nscache_node ** result_nsnode);
090
091 static sos_ret_t
092 fs_connect_existing_child_node(const struct sos_process * creator,
093 struct sos_fs_nscache_node * parent_nsnode,
094 const struct sos_fs_pathname * name,
095 struct sos_fs_nscache_node * nsnode);
096
097 static sos_ret_t
098 fs_create_node(const struct sos_fs_pathname * _path,
099 const struct sos_process * creator,
100 sos_ui32_t access_rights,
101 sos_fs_node_type_t type,
102 struct sos_fs_nscache_node ** result_nsnode);
103
104 static sos_ret_t
105 fs_remove_node(const struct sos_process * actor,
106 struct sos_fs_nscache_node * nsnode);
107
108
109
110
111
112
113 sos_ret_t
114 sos_fs_subsystem_setup(const char * root_device,
115 const char * fsname,
116 const char * mount_args,
117 struct sos_fs_manager_instance ** result_rootfs)
118 {
119 sos_ret_t retval;
120 struct sos_fs_manager_type * fs_type;
121 struct sos_fs_manager_instance * new_fs;
122 struct sos_fs_node * rdev_fsnode;
123 int nb_fstypes;
124
125
126 rdev_fsnode = NULL;
127
128 last_fs_instance_uid = 0;
129 *result_rootfs = NULL;
130
131 retval = sos_fs_nscache_subsystem_setup();
132 if (SOS_OK != retval)
133 return retval;
134
135
136 list_foreach(fs_list, fs_type, nb_fstypes)
137 {
138 if (! strcmp(fsname, fs_type->name))
139 break;
140 }
141 if (! list_foreach_early_break(fs_list, fs_type, nb_fstypes))
142 return -SOS_ENODEV;
143
144 retval = fs_type->mount(fs_type,
145 rdev_fsnode,
146 mount_args, & new_fs);
147 if (SOS_OK != retval)
148 {
149 if (rdev_fsnode)
150 sos_fs_unref_fsnode(rdev_fsnode);
151 return retval;
152 }
153
154
155 sos_fs_nscache_get_fs_node(new_fs->root)->fs = new_fs;
156
157 *result_rootfs = new_fs;
158 return SOS_OK;
159 }
160
161
162 sos_ret_t sos_fs_ref_fsnode(struct sos_fs_node * fsnode)
163 {
164 fsnode->inmem_ref_cnt ++;
165 return SOS_OK;
166 }
167
168
169 sos_ret_t _sos_fs_unref_fsnode(struct sos_fs_node * node)
170 {
171 SOS_ASSERT_FATAL(node->inmem_ref_cnt > 0);
172
173
174
175 if ((node->inmem_ref_cnt == 1) && (node->dirty))
176 {
177 SOS_ASSERT_FATAL(SOS_OK == sos_fs_sync_node(node));
178 }
179
180 node->inmem_ref_cnt --;
181
182 if (node->inmem_ref_cnt == 0)
183 {
184 if (SOS_FS_NODE_DEVICE_CHAR == node->type)
185 sos_chardev_helper_release_fsnode(node);
186 else if (SOS_FS_NODE_DEVICE_BLOCK == node->type)
187 sos_blockdev_helper_release_fsnode(node);
188 sos_hash_remove(node->fs->nodecache, node);
189 node->destructor(node);
190 }
191
192 return SOS_OK;
193 }
194
195
196 sos_ret_t sos_fs_ref_opened_file(struct sos_fs_opened_file * of)
197 {
198 of->ref_cnt ++;
199 return SOS_OK;
200 }
201
202
203 sos_ret_t _sos_fs_unref_opened_file(struct sos_fs_opened_file ** _of)
204 {
205 struct sos_fs_opened_file * of = *_of;
206 *_of = NULL;
207
208 SOS_ASSERT_FATAL(of->ref_cnt > 0);
209 of->ref_cnt --;
210
211 if (0 == of->ref_cnt)
212 {
213 sos_ret_t retval;
214 struct sos_fs_nscache_node * nsnode = of->direntry;
215 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(nsnode);
216
217 retval = fsnode->close_opened_file(fsnode, of);
218 if (SOS_OK != retval)
219 return retval;
220
221 return sos_fs_nscache_unref_node(nsnode);
222 }
223
224 return SOS_OK;
225 }
226
227
228
229
230
231
232
233
234 static sos_ret_t fs_fetch_node(struct sos_fs_manager_instance *fs,
235 sos_ui64_t storage_location,
236 struct sos_fs_node ** result_fsnode)
237 {
238 sos_ret_t retval;
239
240
241 *result_fsnode = (struct sos_fs_node*)
242 sos_hash_lookup(fs->nodecache,
243 & storage_location);
244 if (*result_fsnode)
245 return SOS_OK;
246
247
248 retval = fs->fetch_node_from_disk(fs, storage_location, result_fsnode);
249 if (SOS_OK != retval)
250 return retval;
251
252 (*result_fsnode)->generation = 0;
253
254
255 if (SOS_FS_NODE_DEVICE_CHAR == (*result_fsnode)->type)
256 SOS_ASSERT_FATAL(SOS_OK
257 == sos_chardev_helper_ref_new_fsnode(*result_fsnode));
258 else if (SOS_FS_NODE_DEVICE_BLOCK == (*result_fsnode)->type)
259 SOS_ASSERT_FATAL(SOS_OK
260 == sos_blockdev_helper_ref_new_fsnode(*result_fsnode));
261
262 sos_hash_insert(fs->nodecache, *result_fsnode);
263 return SOS_OK;
264 }
265
266
267
268
269
270 static sos_ret_t
271 fs_allocate_node(struct sos_fs_manager_instance * fs,
272 sos_fs_node_type_t type,
273 sos_ui32_t flags,
274 const struct sos_process * creator,
275 sos_ui32_t access_rights,
276 struct sos_fs_node ** result_fsnode)
277 {
278 sos_ret_t retval;
279
280
281 if (fs->flags & SOS_FS_MOUNT_READONLY)
282 return -SOS_EPERM;
283
284
285 retval = fs->allocate_new_node(fs, type,
286 creator, access_rights,
287 flags,
288 result_fsnode);
289 if (SOS_OK != retval)
290 return retval;
291
292
293 (*result_fsnode)->fs = fs;
294
295
296 if (SOS_FS_NODE_DEVICE_CHAR == (*result_fsnode)->type)
297 {
298 SOS_ASSERT_FATAL(SOS_OK
299 == sos_chardev_helper_ref_new_fsnode(*result_fsnode));
300 }
301 else if (SOS_FS_NODE_DEVICE_BLOCK == (*result_fsnode)->type)
302 {
303 SOS_ASSERT_FATAL(SOS_OK
304 == sos_blockdev_helper_ref_new_fsnode(*result_fsnode));
305 }
306
307
308
309 retval = sos_hash_insert(fs->nodecache, *result_fsnode);
310 if (SOS_OK != retval)
311 {
312 sos_fs_unref_fsnode(*result_fsnode);
313 return retval;
314 }
315
316
317 mark_dirty_fsnode(*result_fsnode, FALSE);
318 return retval;
319 }
320
321
322
323
324
325 static sos_ret_t mark_dirty_fsnode(struct sos_fs_node * fsnode,
326 sos_bool_t force_sync)
327 {
328 sos_ret_t retval;
329 sos_bool_t was_dirty = fsnode->dirty;
330
331 fsnode->dirty = TRUE;
332 fsnode->generation ++;
333 retval = SOS_OK;
334
335
336
337 if (!was_dirty && fsnode->dirty)
338 list_add_tail_named(fsnode->fs->dirty_nodes, fsnode,
339 prev_dirty, next_dirty);
340
341 if (force_sync || (fsnode->fs->flags & SOS_FS_MOUNT_SYNC))
342 return sos_fs_sync_node(fsnode);
343
344 return retval;
345 }
346
347
348
349 static sos_ret_t sos_fs_sync_node(struct sos_fs_node * fsnode)
350 {
351 sos_ret_t retval;
352
353 if (! fsnode->dirty)
354 return SOS_OK;
355
356 retval = fsnode->ops_file->sync(fsnode);
357 if (SOS_OK != retval)
358 return retval;
359
360
361 list_delete_named(fsnode->fs->dirty_nodes, fsnode,
362 prev_dirty, next_dirty);
363 fsnode->dirty = FALSE;
364
365
366 if (fsnode->fs->device)
367 {
368 retval = sos_blockdev_helper_sync_fsnode(fsnode->fs->device);
369 if (SOS_OK != retval)
370 {
371
372 list_add_tail_named(fsnode->fs->dirty_nodes, fsnode,
373 prev_dirty, next_dirty);
374 fsnode->dirty = TRUE;
375 return retval;
376 }
377 }
378
379 return SOS_OK;
380 }
381
382
383
384
385 static sos_ret_t sos_fs_sync_fs(struct sos_fs_manager_instance * fs)
386 {
387 struct sos_fs_node * fsnode;
388 while (NULL != (fsnode = list_get_head_named(fs->dirty_nodes,
389 prev_dirty, next_dirty)))
390 {
391 sos_ret_t retval = sos_fs_sync_node(fsnode);
392 if (SOS_OK != retval)
393 return retval;
394 }
395
396 return SOS_OK;
397 }
398
399
400
401
402
403
404
405
406
407 static sos_ret_t
408 fs_resolve_symlink(const struct sos_fs_nscache_node * root_nsnode,
409 const struct sos_fs_nscache_node * symlink_nsnode,
410 struct sos_fs_nscache_node ** target_nsnode,
411 int lookup_recursion_level)
412 {
413 sos_ret_t retval;
414 const struct sos_fs_nscache_node * start_nsnode;
415 struct sos_fs_node * symlink_fsnode;
416 struct sos_fs_pathname path;
417 struct sos_fs_pathname remaining;
418
419 symlink_fsnode = sos_fs_nscache_get_fs_node(symlink_nsnode);
420 retval = symlink_fsnode->ops_symlink->expand(symlink_fsnode,
421 & path.contents,
422 & path.length);
423 if (SOS_OK != retval)
424 return retval;
425 if (path.length <= 0)
426 return -SOS_ENOENT;
427
428
429 if (path.contents[0] == '/')
430 start_nsnode = root_nsnode;
431 else
432 {
433 retval = sos_fs_nscache_get_parent(symlink_nsnode,
434 (struct sos_fs_nscache_node**)& start_nsnode);
435 if (SOS_OK != retval)
436 return retval;
437 }
438
439 retval = fs_lookup_node(& path, TRUE, root_nsnode, start_nsnode,
440 target_nsnode,
441 & remaining, lookup_recursion_level);
442 if (SOS_OK != retval)
443 return retval;
444
445
446 if (remaining.length != 0)
447 {
448 sos_fs_nscache_unref_node(*target_nsnode);
449 return -SOS_ENOENT;
450 }
451
452 return SOS_OK;
453 }
454
455
456 #define MAX_LOOKUP_RECURSION_LEVEL 5
457
458
459
460
461
462
463
464
465
466
467
468
469 static sos_ret_t
470 fs_lookup_node(const struct sos_fs_pathname * path,
471 sos_bool_t follow_symlinks,
472 const struct sos_fs_nscache_node * root_nsnode,
473 const struct sos_fs_nscache_node * start_nsnode,
474 struct sos_fs_nscache_node ** result_nsnode,
475 struct sos_fs_pathname * result_remaining_path,
476 int lookup_recursion_level)
477 {
478 sos_ret_t retval;
479 struct sos_fs_nscache_node * current_nsnode;
480
481
482 lookup_recursion_level ++;
483 if (lookup_recursion_level > MAX_LOOKUP_RECURSION_LEVEL)
484 {
485 return -SOS_ELOOP;
486 }
487
488 if (path->length <= 0)
489 return -SOS_ENOENT;
490
491 *result_nsnode = NULL;
492 memcpy(result_remaining_path, path, sizeof(*path));
493
494 current_nsnode = (struct sos_fs_nscache_node *)start_nsnode;
495 sos_fs_nscache_ref_node(current_nsnode);
496 while (1)
497 {
498 struct sos_fs_pathname current_component, remaining;
499 struct sos_fs_nscache_node * next_nsnode = NULL;
500 sos_bool_t slashes_after_first_component;
501
502
503
504
505 slashes_after_first_component
506 = sos_fs_pathname_split_path(result_remaining_path,
507 & current_component, & remaining);
508
509
510
511
512
513
514 if (current_component.length == 0)
515 {
516
517 memcpy(result_remaining_path, & remaining, sizeof(remaining));
518 *result_nsnode = current_nsnode;
519 return SOS_OK;
520 }
521
522
523 if (sos_fs_nscache_get_fs_node(current_nsnode)->type
524 != SOS_FS_NODE_DIRECTORY)
525 {
526 sos_fs_nscache_unref_node(current_nsnode);
527 return -SOS_ENOENT;
528 }
529
530
531 if (! (sos_fs_nscache_get_fs_node(current_nsnode)->access_rights
532 & SOS_FS_EXECUTABLE) )
533 {
534 sos_fs_nscache_unref_node(current_nsnode);
535 return -SOS_EACCES;
536 }
537
538
539
540 retval = sos_fs_nscache_lookup(current_nsnode,
541 & current_component,
542 root_nsnode,
543 & next_nsnode);
544 if (SOS_OK != retval)
545 {
546 struct sos_fs_node * current_fsnode, * next_fsnode;
547 sos_ui64_t storage_location;
548
549
550
551
552
553 current_fsnode = sos_fs_nscache_get_fs_node(current_nsnode);
554
555 retval = current_fsnode->ops_dir
556 ->lookup(current_fsnode,
557 current_component.contents,
558 current_component.length,
559 & storage_location);
560 if (SOS_OK != retval)
561 {
562
563 *result_nsnode = current_nsnode;
564 return SOS_OK;
565 }
566
567
568
569 retval = fs_fetch_node(current_fsnode->fs,
570 storage_location, & next_fsnode);
571 if (SOS_OK != retval)
572 {
573 sos_fs_nscache_unref_node(current_nsnode);
574 return retval;
575 }
576
577
578 retval = sos_fs_nscache_add_new_child_node(current_nsnode,
579 & current_component,
580 next_fsnode,
581 & next_nsnode);
582 sos_fs_nscache_unref_node(current_nsnode);
583 if (SOS_OK != retval)
584 return retval;
585 }
586 else
587 sos_fs_nscache_unref_node(current_nsnode);
588
589
590 if (sos_fs_nscache_get_fs_node(next_nsnode)->type
591 == SOS_FS_NODE_SYMLINK)
592 {
593
594
595 if ( (remaining.length != 0)
596 || follow_symlinks )
597 {
598 struct sos_fs_nscache_node * symlink_target;
599
600 retval = fs_resolve_symlink(root_nsnode, next_nsnode,
601 & symlink_target,
602 lookup_recursion_level);
603 sos_fs_nscache_unref_node(next_nsnode);
604 if (SOS_OK != retval)
605 return retval;
606
607 next_nsnode = symlink_target;
608 }
609 }
610
611
612
613 if (slashes_after_first_component
614 &&
615 ( sos_fs_nscache_get_fs_node(next_nsnode)->type
616 != SOS_FS_NODE_DIRECTORY) )
617 {
618 sos_fs_nscache_unref_node(next_nsnode);
619 return -SOS_ENOTDIR;
620 }
621
622
623 memcpy(result_remaining_path, & remaining, sizeof(remaining));
624 current_nsnode = next_nsnode;
625 }
626
627 sos_display_fatal_error("Should not get there");
628 return -SOS_EFATAL;
629 }
630
631
632
633
634
635
636
637
638 static sos_ret_t
639 fs_register_child_node(const struct sos_process * creator,
640 struct sos_fs_nscache_node * parent_nsnode,
641 const struct sos_fs_pathname * name,
642 struct sos_fs_node * fsnode,
643 sos_ui32_t flags,
644 struct sos_fs_nscache_node ** result_nsnode)
645 {
646 sos_ret_t retval;
647 struct sos_fs_node * parent_fsnode;
648 struct sos_fs_pathname first_component, remaining;
649 sos_bool_t slashes_after_first_component = FALSE;
650
651 parent_fsnode = sos_fs_nscache_get_fs_node(parent_nsnode);
652 if (parent_fsnode->type != SOS_FS_NODE_DIRECTORY)
653 return -SOS_ENOTDIR;
654
655 if (name->length <= 0)
656 return -SOS_EINVAL;
657
658 slashes_after_first_component
659 = sos_fs_pathname_split_path(name, & first_component, & remaining);
660
661 if (fsnode->type != SOS_FS_NODE_DIRECTORY)
662 {
663
664
665 if (slashes_after_first_component)
666 return -SOS_EINVAL;
667 }
668 else
669 {
670
671
672 if (remaining.length > 0)
673 return -SOS_EINVAL;
674 }
675
676
677 if (! (parent_fsnode->access_rights & SOS_FS_WRITABLE) )
678 return -SOS_EACCES;
679
680
681 if (fsnode->fs != parent_fsnode->fs)
682 return -SOS_EXDEV;
683
684
685 sos_fs_nscache_ref_node(parent_nsnode);
686
687
688 retval = parent_fsnode->ops_dir->link(parent_fsnode,
689 creator,
690 first_component.contents,
691 first_component.length,
692 fsnode);
693 if (SOS_OK != retval)
694 {
695 sos_fs_nscache_unref_node(parent_nsnode);
696 return retval;
697 }
698
699
700 mark_dirty_fsnode(parent_fsnode, FALSE);
701
702
703 retval = sos_fs_nscache_add_new_child_node(parent_nsnode, & first_component,
704 fsnode, result_nsnode);
705
706 sos_fs_nscache_unref_node(parent_nsnode);
707 return retval;
708 }
709
710
711
712
713
714 static sos_ret_t
715 fs_create_child_node(struct sos_fs_nscache_node * parent_nsnode,
716 const struct sos_fs_pathname * name,
717 sos_fs_node_type_t type,
718 sos_ui32_t flags,
719 const struct sos_process * creator,
720 sos_ui32_t access_rights,
721 struct sos_fs_nscache_node ** result_nsnode)
722 {
723 sos_ret_t retval;
724 struct sos_fs_node * fsnode, * parent_fsnode;
725
726 parent_fsnode = sos_fs_nscache_get_fs_node(parent_nsnode);
727 if (parent_fsnode->type != SOS_FS_NODE_DIRECTORY)
728 return -SOS_ENOTDIR;
729
730
731 sos_fs_nscache_ref_node(parent_nsnode);
732
733 retval = fs_allocate_node(parent_fsnode->fs, type, flags, creator,
734 access_rights, & fsnode);
735 if (SOS_OK != retval)
736 {
737 sos_fs_nscache_unref_node(parent_nsnode);
738 return retval;
739 }
740
741 retval = fs_register_child_node(creator,
742 parent_nsnode, name, fsnode, flags,
743 result_nsnode);
744 sos_fs_nscache_unref_node(parent_nsnode);
745
746
747 sos_fs_unref_fsnode(fsnode);
748
749 return retval;
750 }
751
752
753
754
755
756
757
758
759 static sos_ret_t
760 fs_connect_existing_child_node(const struct sos_process * creator,
761 struct sos_fs_nscache_node * parent_nsnode,
762 const struct sos_fs_pathname * name,
763 struct sos_fs_nscache_node * nsnode)
764 {
765 sos_ret_t retval;
766 struct sos_fs_node * parent_fsnode, * fsnode;
767 struct sos_fs_pathname first_component, remaining;
768 sos_bool_t slashes_after_first_component = FALSE;
769
770 fsnode = sos_fs_nscache_get_fs_node(nsnode);
771 parent_fsnode = sos_fs_nscache_get_fs_node(parent_nsnode);
772 if (parent_fsnode->type != SOS_FS_NODE_DIRECTORY)
773 return -SOS_ENOTDIR;
774
775 if (name->length <= 0)
776 return -SOS_EINVAL;
777
778 slashes_after_first_component
779 = sos_fs_pathname_split_path(name, & first_component, & remaining);
780
781 if (fsnode->type != SOS_FS_NODE_DIRECTORY)
782 {
783
784
785 if (slashes_after_first_component)
786 return -SOS_EINVAL;
787 }
788 else
789 {
790
791
792 if (remaining.length > 0)
793 return -SOS_EINVAL;
794 }
795
796
797 if (! (parent_fsnode->access_rights & SOS_FS_WRITABLE) )
798 return -SOS_EACCES;
799
800
801 if (fsnode->fs != parent_fsnode->fs)
802 return -SOS_EXDEV;
803
804
805 sos_fs_nscache_ref_node(parent_nsnode);
806
807
808 retval = parent_fsnode->ops_dir->link(parent_fsnode,
809 creator,
810 first_component.contents,
811 first_component.length,
812 fsnode);
813 if (SOS_OK != retval)
814 {
815 sos_fs_nscache_unref_node(parent_nsnode);
816 return retval;
817 }
818
819
820 mark_dirty_fsnode(parent_fsnode, FALSE);
821
822
823 retval = sos_fs_nscache_add_existing_child_node(parent_nsnode,
824 & first_component,
825 nsnode);
826 sos_fs_nscache_unref_node(parent_nsnode);
827 return retval;
828 }
829
830
831
832
833 static sos_ret_t
834 fs_create_node(const struct sos_fs_pathname * _path,
835 const struct sos_process * creator,
836 sos_ui32_t access_rights,
837 sos_fs_node_type_t type,
838 struct sos_fs_nscache_node ** result_nsnode)
839 {
840 sos_ret_t retval;
841 struct sos_fs_pathname path;
842 struct sos_fs_nscache_node *nsnode, *new_nsnode;
843
844 path.contents = _path->contents;
845 path.length = _path->length;
846
847 if (path.length <= 0)
848 return -SOS_ENOENT;
849
850 if (path.contents[0] == '/')
851 nsnode = sos_process_get_root(creator)->direntry;
852 else
853 nsnode = sos_process_get_cwd(creator)->direntry;
854
855 retval = fs_lookup_node(& path,
856 TRUE,
857 sos_process_get_root(creator)->direntry,
858 nsnode,
859 & nsnode,
860 & path,
861 0);
862 if (SOS_OK != retval)
863 return retval;
864
865 if (path.length <= 0)
866 {
867
868 sos_fs_nscache_unref_node(nsnode);
869 return -SOS_EEXIST;
870 }
871
872
873 retval = fs_create_child_node(nsnode,
874 & path,
875 type,
876 0,
877 creator, access_rights,
878 & new_nsnode);
879 sos_fs_nscache_unref_node(nsnode);
880
881
882 if (NULL == result_nsnode)
883 sos_fs_nscache_unref_node(new_nsnode);
884 else
885 *result_nsnode = new_nsnode;
886
887 return retval;
888 }
889
890
891 static sos_ret_t
892 fs_remove_node(const struct sos_process * actor,
893 struct sos_fs_nscache_node * nsnode)
894 {
895 sos_ret_t retval;
896 struct sos_fs_nscache_node * parent_nsnode;
897 struct sos_fs_node * parent_fsnode;
898 struct sos_fs_pathname childname;
899
900
901 if (nsnode == sos_fs_nscache_get_fs_node(nsnode)->fs->root)
902 return -SOS_EBUSY;
903
904 retval = sos_fs_nscache_get_parent(nsnode, & parent_nsnode);
905 if (SOS_OK != retval)
906 return retval;
907 parent_fsnode = sos_fs_nscache_get_fs_node(parent_nsnode);
908
909
910 if (parent_fsnode->fs->flags & SOS_FS_MOUNT_READONLY)
911 return -SOS_EPERM;
912
913
914 if (! (parent_fsnode->access_rights & SOS_FS_WRITABLE) )
915 return -SOS_EACCES;
916
917 sos_fs_nscache_ref_node(parent_nsnode);
918
919 sos_fs_nscache_get_name(nsnode, & childname);
920 retval = parent_fsnode->ops_dir->unlink(parent_fsnode, actor,
921 childname.contents,
922 childname.length);
923 if (SOS_OK == retval)
924 sos_fs_nscache_disconnect_node(nsnode);
925
926
927 if (SOS_OK == retval)
928 mark_dirty_fsnode(parent_fsnode, FALSE);
929
930 sos_fs_nscache_unref_node(parent_nsnode);
931 return retval;
932 }
933
934
935
936
937
938
939 sos_ret_t sos_fs_new_opened_file(const struct sos_process * owner,
940 struct sos_fs_nscache_node * nsnode,
941 sos_ui32_t open_flags,
942 struct sos_fs_opened_file ** result_of)
943 {
944 sos_ret_t retval;
945 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(nsnode);
946
947 retval = fsnode->new_opened_file(fsnode, owner, open_flags, result_of);
948 if (SOS_OK != retval)
949 return retval;
950
951 (*result_of)->ref_cnt = 1;
952 (*result_of)->generation = 1;
953
954 retval = sos_fs_nscache_register_opened_file(nsnode, *result_of);
955 if (SOS_OK != retval)
956 {
957 fsnode->close_opened_file(fsnode, *result_of);
958 return retval;
959 }
960
961 (*result_of)->open_flags = open_flags;
962 return SOS_OK;
963 }
964
965
966 sos_ret_t
967 sos_fs_duplicate_opened_file(struct sos_fs_opened_file * src_of,
968 const struct sos_process * dst_proc,
969 struct sos_fs_opened_file ** result_of)
970 {
971 sos_ret_t retval = src_of->duplicate(src_of, dst_proc, result_of);
972 if (SOS_OK != retval)
973 return retval;
974
975 SOS_ASSERT_FATAL((*result_of)->owner == dst_proc);
976 (*result_of)->ref_cnt = 1;
977 (*result_of)->generation = 1;
978 retval = sos_fs_nscache_register_opened_file(src_of->direntry, *result_of);
979 if (SOS_OK != retval)
980 {
981 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(src_of->direntry);
982 fsnode->close_opened_file(fsnode, *result_of);
983 return retval;
984 }
985
986 return retval;
987 }
988
989
990 sos_ret_t sos_fs_open(const struct sos_process *owner,
991 const char *_path,
992 sos_size_t _pathlen,
993 sos_ui32_t open_flags,
994 sos_ui32_t creat_access_rights,
995 struct sos_fs_opened_file ** of)
996 {
997 sos_ret_t retval;
998 struct sos_fs_nscache_node *nsnode;
999 struct sos_fs_node * fsnode;
1000 struct sos_fs_pathname path;
1001
1002
1003 if ( (open_flags & SOS_FS_OPEN_DIRECTORY)
1004 && ( (open_flags & (SOS_FS_OPEN_CREAT
1005 | SOS_FS_OPEN_TRUNC)) ) )
1006 return -SOS_EINVAL;
1007
1008 if (_pathlen <= 0)
1009 return -SOS_ENOENT;
1010
1011 path.contents = _path;
1012 path.length = _pathlen;
1013
1014 if (path.contents[0] == '/')
1015 nsnode = sos_process_get_root(owner)->direntry;
1016 else
1017 nsnode = sos_process_get_cwd(owner)->direntry;
1018
1019 retval = fs_lookup_node(& path,
1020 ! (open_flags & SOS_FS_OPEN_NOFOLLOW),
1021 sos_process_get_root(owner)->direntry,
1022 nsnode,
1023 & nsnode,
1024 & path,
1025 0);
1026 if (SOS_OK != retval)
1027 return retval;
1028
1029 if (path.length <= 0)
1030 {
1031
1032
1033
1034 if (open_flags & SOS_FS_OPEN_EXCL)
1035 {
1036 sos_fs_nscache_unref_node(nsnode);
1037 return -SOS_EEXIST;
1038 }
1039
1040 fsnode = sos_fs_nscache_get_fs_node(nsnode);
1041 if ((open_flags & SOS_FS_OPEN_DIRECTORY)
1042 && (fsnode->type != SOS_FS_NODE_DIRECTORY))
1043 {
1044 sos_fs_nscache_unref_node(nsnode);
1045 return -SOS_ENOTDIR;
1046 }
1047
1048
1049 if ((open_flags & SOS_FS_OPEN_TRUNC)
1050 && fsnode->ops_file->truncate)
1051 {
1052 retval = fsnode->ops_file->truncate(fsnode, 0);
1053 if (SOS_OK != retval)
1054 {
1055 sos_fs_nscache_unref_node(nsnode);
1056 return retval;
1057 }
1058 }
1059 }
1060 else
1061 {
1062 struct sos_fs_nscache_node * parent_nsnode = nsnode;
1063
1064
1065 if (! (open_flags & SOS_FS_OPEN_CREAT))
1066 {
1067 sos_fs_nscache_unref_node(parent_nsnode);
1068 return -SOS_ENOENT;
1069 }
1070
1071
1072 retval = fs_create_child_node(parent_nsnode,
1073 & path,
1074 SOS_FS_NODE_REGULAR_FILE,
1075 open_flags,
1076 owner,
1077 creat_access_rights,
1078 & nsnode);
1079 sos_fs_nscache_unref_node(parent_nsnode);
1080 if (SOS_OK != retval)
1081 {
1082 return retval;
1083 }
1084
1085 fsnode = sos_fs_nscache_get_fs_node(nsnode);
1086 }
1087
1088
1089 open_flags &= ~(SOS_FS_OPEN_CREAT
1090 | SOS_FS_OPEN_EXCL
1091 | SOS_FS_OPEN_NOFOLLOW
1092 | SOS_FS_OPEN_DIRECTORY);
1093 if (! (fsnode->access_rights & SOS_FS_WRITABLE))
1094 open_flags &= ~(SOS_FS_OPEN_WRITE);
1095 if (! (fsnode->access_rights & SOS_FS_READABLE))
1096 open_flags &= ~(SOS_FS_OPEN_READ);
1097 if (fsnode->fs->flags & SOS_FS_MOUNT_READONLY)
1098 open_flags &= ~(SOS_FS_OPEN_READ);
1099
1100
1101
1102
1103 retval = sos_fs_new_opened_file(owner, nsnode, open_flags, of);
1104
1105 sos_fs_nscache_unref_node(nsnode);
1106 return retval;
1107 }
1108
1109
1110 sos_ret_t sos_fs_close(struct sos_fs_opened_file * of)
1111 {
1112 return sos_fs_unref_opened_file(of);
1113 }
1114
1115
1116 sos_ret_t sos_fs_mark_dirty(struct sos_fs_opened_file * of)
1117 {
1118 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
1119
1120
1121 SOS_ASSERT_FATAL(! (fsnode->fs->flags & SOS_FS_MOUNT_READONLY));
1122
1123 return mark_dirty_fsnode(fsnode, of->open_flags & SOS_FS_OPEN_SYNC);
1124 }
1125
1126
1127 sos_ret_t sos_fs_read(struct sos_fs_opened_file * of,
1128 sos_uaddr_t dest_buf,
1129 sos_size_t * len)
1130 {
1131 if (! (of->open_flags & SOS_FS_OPEN_READ))
1132 return -SOS_EPERM;
1133
1134 if (! of->ops_file->read)
1135 return -SOS_ENOSYS;
1136
1137 return of->ops_file->read(of, dest_buf, len);
1138 }
1139
1140
1141 sos_ret_t sos_fs_write(struct sos_fs_opened_file * of,
1142 sos_uaddr_t src_buf,
1143 sos_size_t * len)
1144 {
1145 if (! (of->open_flags & SOS_FS_OPEN_WRITE))
1146 return -SOS_EPERM;
1147
1148 if (! of->ops_file->write)
1149 return -SOS_ENOSYS;
1150
1151 return of->ops_file->write(of, src_buf, len);
1152 }
1153
1154
1155 sos_ret_t sos_fs_seek(struct sos_fs_opened_file *of,
1156 sos_lsoffset_t offset,
1157 sos_seek_whence_t whence,
1158 sos_lsoffset_t * result_position)
1159 {
1160 if (! of->ops_file->seek)
1161 return -SOS_ENOSYS;
1162
1163 return of->ops_file->seek(of, offset, whence, result_position);
1164 }
1165
1166
1167 sos_ret_t sos_fs_ftruncate(struct sos_fs_opened_file *of,
1168 sos_lsoffset_t length)
1169 {
1170 sos_ret_t retval;
1171 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
1172
1173 if (! (of->open_flags & SOS_FS_OPEN_WRITE))
1174 return -SOS_EPERM;
1175
1176 if (! fsnode->ops_file->truncate)
1177 return -SOS_ENOSYS;
1178
1179 retval = fsnode->ops_file->truncate(fsnode, length);
1180 if (SOS_OK == retval)
1181 mark_dirty_fsnode(fsnode, FALSE);
1182
1183 return retval;
1184 }
1185
1186
1187 sos_ret_t sos_fs_mmap(struct sos_fs_opened_file *of,
1188 sos_uaddr_t *uaddr, sos_size_t size,
1189 sos_ui32_t access_rights,
1190 sos_ui32_t flags,
1191 sos_luoffset_t offset)
1192 {
1193 sos_ui32_t required_access = 0;
1194 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
1195
1196 if (! of->ops_file->mmap)
1197 return -SOS_ENOSYS;
1198
1199
1200 if (access_rights & SOS_VM_MAP_PROT_READ)
1201 required_access |= SOS_FS_OPEN_READ;
1202 if ( (access_rights & SOS_VM_MAP_PROT_WRITE) && (flags & SOS_VR_MAP_SHARED) )
1203 required_access |= SOS_FS_OPEN_WRITE;
1204 if (access_rights & SOS_VM_MAP_PROT_EXEC)
1205 required_access |= SOS_FS_OPEN_READ;
1206
1207
1208 if ((of->open_flags & required_access) != required_access)
1209 return -SOS_EPERM;
1210
1211 if ( (access_rights & SOS_VM_MAP_PROT_EXEC)
1212 && (fsnode->fs->flags & SOS_FS_MOUNT_NOEXEC) )
1213 return -SOS_EPERM;
1214
1215 return of->ops_file->mmap(of, uaddr, size, access_rights, flags, offset);
1216 }
1217
1218
1219 sos_ret_t sos_fs_fcntl(struct sos_fs_opened_file *of,
1220 int req_id,
1221 sos_ui32_t req_arg )
1222 {
1223 if (! of->ops_file->fcntl)
1224 return -SOS_ENOSYS;
1225
1226 return of->ops_file->fcntl(of, req_id, req_arg);
1227 }
1228
1229
1230 sos_ret_t sos_fs_ioctl(struct sos_fs_opened_file *of,
1231 int req_id,
1232 sos_ui32_t req_arg )
1233 {
1234 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
1235
1236 if (fsnode->type == SOS_FS_NODE_DEVICE_CHAR)
1237 {
1238 if (! of->ops_chardev->ioctl)
1239 return -SOS_ENOSYS;
1240
1241 return of->ops_chardev->ioctl(of, req_id, req_arg);
1242 }
1243 else if (fsnode->type == SOS_FS_NODE_DEVICE_BLOCK)
1244 {
1245 if (! of->ops_blockdev->ioctl)
1246 return -SOS_ENOSYS;
1247
1248 return of->ops_blockdev->ioctl(of, req_id, req_arg);
1249 }
1250
1251 return -SOS_ENOSYS;
1252 }
1253
1254
1255 sos_ret_t sos_fs_readdir(struct sos_fs_opened_file * of,
1256 struct sos_fs_dirent * result)
1257 {
1258 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
1259
1260 if (fsnode->type != SOS_FS_NODE_DIRECTORY)
1261 return -SOS_ENOTDIR;
1262
1263 return of->ops_dir->readdir(of, result);
1264 }
1265
1266
1267 sos_ret_t sos_fs_creat(const struct sos_process * creator,
1268 const char * _path,
1269 sos_size_t _pathlen,
1270 sos_ui32_t access_rights)
1271 {
1272 struct sos_fs_pathname path;
1273
1274 path.contents = _path;
1275 path.length = _pathlen;
1276
1277 return fs_create_node(& path, creator, access_rights,
1278 SOS_FS_NODE_REGULAR_FILE, NULL);
1279 }
1280
1281
1282 sos_ret_t sos_fs_link(const struct sos_process * creator,
1283 const char * _old_path,
1284 sos_size_t _old_pathlen,
1285 const char * _new_path,
1286 sos_size_t _new_pathlen)
1287 {
1288 sos_ret_t retval;
1289 struct sos_fs_nscache_node *old_nsnode, *dest_parent_nsnode, *new_nsnode;
1290 struct sos_fs_node * fsnode;
1291 struct sos_fs_pathname old_path, new_path;
1292
1293 if (_old_pathlen <= 0)
1294 return -SOS_ENOENT;
1295 if (_new_pathlen <= 0)
1296 return -SOS_ENOENT;
1297
1298
1299 old_path.contents = _old_path;
1300 old_path.length = _old_pathlen;
1301
1302 if (old_path.contents[0] == '/')
1303 old_nsnode = sos_process_get_root(creator)->direntry;
1304 else
1305 old_nsnode = sos_process_get_cwd(creator)->direntry;
1306
1307 retval = fs_lookup_node(& old_path,
1308 FALSE ,
1309 sos_process_get_root(creator)->direntry,
1310 old_nsnode,
1311 & old_nsnode,
1312 & old_path,
1313 0);
1314 if (SOS_OK != retval)
1315 return retval;
1316
1317 if (old_path.length > 0)
1318 {
1319
1320 sos_fs_nscache_unref_node(old_nsnode);
1321 return -SOS_ENOENT;
1322 }
1323
1324 fsnode = sos_fs_nscache_get_fs_node(old_nsnode);
1325
1326
1327 if (fsnode->type == SOS_FS_NODE_DIRECTORY)
1328 {
1329 sos_fs_nscache_unref_node(old_nsnode);
1330 return -SOS_ENOENT;
1331 }
1332
1333
1334 new_path.contents = _new_path;
1335 new_path.length = _new_pathlen;
1336
1337 if (new_path.contents[0] == '/')
1338 dest_parent_nsnode = sos_process_get_root(creator)->direntry;
1339 else
1340 dest_parent_nsnode = sos_process_get_cwd(creator)->direntry;
1341
1342 retval = fs_lookup_node(& new_path,
1343 TRUE ,
1344 sos_process_get_root(creator)->direntry,
1345 dest_parent_nsnode,
1346 & dest_parent_nsnode,
1347 & new_path,
1348 0);
1349 if (SOS_OK != retval)
1350 {
1351 sos_fs_nscache_unref_node(old_nsnode);
1352 return retval;
1353 }
1354
1355 if (new_path.length == 0)
1356 {
1357
1358 sos_fs_nscache_unref_node(dest_parent_nsnode);
1359 sos_fs_nscache_unref_node(old_nsnode);
1360 return -SOS_EEXIST;
1361 }
1362
1363
1364 retval = fs_register_child_node(creator, dest_parent_nsnode, & new_path,
1365 fsnode, 0,
1366 & new_nsnode);
1367
1368 sos_fs_nscache_unref_node(dest_parent_nsnode);
1369 sos_fs_nscache_unref_node(old_nsnode);
1370 sos_fs_nscache_unref_node(new_nsnode);
1371 return retval;
1372 }
1373
1374
1375 sos_ret_t sos_fs_rename(const struct sos_process * actor,
1376 const char * _old_path,
1377 sos_size_t _old_pathlen,
1378 const char * _new_path,
1379 sos_size_t _new_pathlen)
1380 {
1381 sos_ret_t retval;
1382 struct sos_fs_nscache_node *old_nsnode, *old_parent_nsnode,
1383 *dest_parent_nsnode, *replaced_nsnode;
1384 struct sos_fs_pathname old_name, replaced_name;
1385 struct sos_fs_pathname old_path, new_path;
1386
1387 old_nsnode = old_parent_nsnode = dest_parent_nsnode = replaced_nsnode = NULL;
1388
1389 if (_old_pathlen <= 0)
1390 return -SOS_ENOENT;
1391 if (_new_pathlen <= 0)
1392 return -SOS_ENOENT;
1393
1394
1395 old_path.contents = _old_path;
1396 old_path.length = _old_pathlen;
1397
1398 if (old_path.contents[0] == '/')
1399 old_nsnode = sos_process_get_root(actor)->direntry;
1400 else
1401 old_nsnode = sos_process_get_cwd(actor)->direntry;
1402
1403 retval = fs_lookup_node(& old_path,
1404 FALSE ,
1405 sos_process_get_root(actor)->direntry,
1406 old_nsnode,
1407 & old_nsnode,
1408 & old_path,
1409 0);
1410 if (SOS_OK != retval)
1411 return retval;
1412
1413 if (old_path.length > 0)
1414 {
1415
1416 sos_fs_nscache_unref_node(old_nsnode);
1417 return -SOS_ENOENT;
1418 }
1419
1420
1421 if (sos_fs_nscache_is_mountnode(old_nsnode))
1422 {
1423 sos_fs_nscache_unref_node(old_nsnode);
1424 return -SOS_ENOENT;
1425 }
1426
1427
1428
1429 retval = sos_fs_nscache_get_parent(old_nsnode, & old_parent_nsnode);
1430 if (SOS_OK != retval)
1431 {
1432 sos_fs_nscache_unref_node(old_nsnode);
1433 return retval;
1434 }
1435 sos_fs_nscache_ref_node(old_parent_nsnode);
1436
1437
1438 replaced_nsnode = NULL;
1439 new_path.contents = _new_path;
1440 new_path.length = _new_pathlen;
1441
1442 if (new_path.contents[0] == '/')
1443 dest_parent_nsnode = sos_process_get_root(actor)->direntry;
1444 else
1445 dest_parent_nsnode = sos_process_get_cwd(actor)->direntry;
1446
1447 retval = fs_lookup_node(& new_path,
1448 TRUE ,
1449 sos_process_get_root(actor)->direntry,
1450 dest_parent_nsnode,
1451 & dest_parent_nsnode,
1452 & new_path,
1453 0);
1454 if (SOS_OK != retval)
1455 {
1456 goto undo_rename;
1457 }
1458
1459
1460 if (old_nsnode == dest_parent_nsnode)
1461 {
1462 sos_fs_nscache_unref_node(old_nsnode);
1463 sos_fs_nscache_unref_node(old_parent_nsnode);
1464 sos_fs_nscache_unref_node(dest_parent_nsnode);
1465 return SOS_OK;
1466 }
1467
1468
1469 sos_fs_nscache_get_name(old_nsnode, & old_name);
1470 retval = fs_remove_node(actor, old_nsnode);
1471 if (SOS_OK != retval)
1472 {
1473 sos_fs_nscache_unref_node(old_nsnode);
1474 sos_fs_nscache_unref_node(old_parent_nsnode);
1475 sos_fs_nscache_unref_node(dest_parent_nsnode);
1476 return -SOS_ENOENT;
1477 }
1478
1479 if (new_path.length == 0)
1480 {
1481
1482
1483
1484
1485 if (sos_fs_nscache_get_fs_node(dest_parent_nsnode)->type
1486 == SOS_FS_NODE_DIRECTORY)
1487 {
1488 retval = -SOS_EBUSY;
1489 goto undo_rename;
1490 }
1491
1492 replaced_nsnode = dest_parent_nsnode;
1493 dest_parent_nsnode = NULL;
1494
1495
1496 retval = sos_fs_nscache_get_parent(replaced_nsnode,
1497 & dest_parent_nsnode);
1498 if (SOS_OK != retval)
1499 {
1500 dest_parent_nsnode = replaced_nsnode;
1501 goto undo_rename;
1502 }
1503
1504 sos_fs_nscache_ref_node(dest_parent_nsnode);
1505
1506
1507 sos_fs_nscache_get_name(replaced_nsnode, & replaced_name);
1508 retval = fs_remove_node(actor, replaced_nsnode);
1509 if (SOS_OK != retval)
1510 goto undo_rename;
1511 }
1512
1513
1514 retval = fs_connect_existing_child_node(actor, dest_parent_nsnode,
1515 & new_path,
1516 old_nsnode);
1517 if (SOS_OK != retval)
1518 goto undo_rename;
1519
1520 sos_fs_nscache_unref_node(old_nsnode);
1521 sos_fs_nscache_unref_node(old_parent_nsnode);
1522 sos_fs_nscache_unref_node(dest_parent_nsnode);
1523 if (NULL != replaced_nsnode)
1524 sos_fs_nscache_unref_node(replaced_nsnode);
1525
1526 return retval;
1527
1528 undo_rename:
1529
1530
1531
1532
1533 if (NULL != replaced_nsnode)
1534 {
1535 fs_connect_existing_child_node(actor, dest_parent_nsnode,
1536 & replaced_name,
1537 replaced_nsnode);
1538 sos_fs_nscache_unref_node(replaced_nsnode);
1539 }
1540
1541 fs_connect_existing_child_node(actor, old_parent_nsnode,
1542 & old_name,
1543 old_nsnode);
1544 sos_fs_nscache_unref_node(old_nsnode);
1545 sos_fs_nscache_unref_node(old_parent_nsnode);
1546
1547 if (NULL != dest_parent_nsnode)
1548 sos_fs_nscache_unref_node(dest_parent_nsnode);
1549
1550 return retval;
1551 }
1552
1553
1554 sos_ret_t sos_fs_unlink(const struct sos_process * actor,
1555 const char * _path,
1556 sos_size_t _pathlen)
1557 {
1558 sos_ret_t retval;
1559 struct sos_fs_pathname path;
1560 struct sos_fs_nscache_node * nsnode;
1561
1562 path.contents = _path;
1563 path.length = _pathlen;
1564
1565 if (path.length <= 0)
1566 return -SOS_ENOENT;
1567
1568 if (path.contents[0] == '/')
1569 nsnode = sos_process_get_root(actor)->direntry;
1570 else
1571 nsnode = sos_process_get_cwd(actor)->direntry;
1572
1573 retval = fs_lookup_node(& path, FALSE,
1574 sos_process_get_root(actor)->direntry,
1575 nsnode,
1576 & nsnode, & path, 0);
1577 if (SOS_OK != retval)
1578 return retval;
1579
1580
1581 if (path.length > 0)
1582 {
1583 sos_fs_nscache_unref_node(nsnode);
1584 return -SOS_ENOENT;
1585 }
1586
1587 if (sos_fs_nscache_get_fs_node(nsnode)->type == SOS_FS_NODE_DIRECTORY)
1588 retval = -SOS_EISDIR;
1589 else
1590 retval = fs_remove_node(actor, nsnode);
1591
1592 sos_fs_nscache_unref_node(nsnode);
1593 return retval;
1594 }
1595
1596
1597 sos_ret_t sos_fs_symlink(const struct sos_process * creator,
1598 const char * _path,
1599 sos_size_t _pathlen,
1600 sos_uaddr_t symlink_target,
1601 sos_size_t symlink_target_len)
1602 {
1603 sos_ret_t retval;
1604 struct sos_fs_pathname path;
1605 struct sos_fs_node * fsnode;
1606 struct sos_fs_nscache_node * symlink;
1607 struct sos_fs_opened_file * tmp_of;
1608 sos_size_t len;
1609
1610 path.contents = _path;
1611 path.length = _pathlen;
1612
1613 retval = fs_create_node(& path, creator, SOS_FS_S_IRWXALL,
1614 SOS_FS_NODE_SYMLINK, & symlink);
1615 if (SOS_OK != retval)
1616 return retval;
1617
1618
1619 fsnode = sos_fs_nscache_get_fs_node(symlink);
1620 retval = fsnode->new_opened_file(fsnode, creator,
1621 SOS_FS_OPEN_WRITE, & tmp_of);
1622 if (SOS_OK != retval)
1623 {
1624 fs_remove_node(creator, symlink);
1625 sos_fs_nscache_unref_node(symlink);
1626 return retval;
1627 }
1628
1629 tmp_of->ref_cnt = 1;
1630 retval = sos_fs_nscache_register_opened_file(symlink, tmp_of);
1631 if (SOS_OK != retval)
1632 {
1633 fsnode->close_opened_file(fsnode, tmp_of);
1634 fs_remove_node(creator, symlink);
1635 sos_fs_nscache_unref_node(symlink);
1636 return retval;
1637 }
1638
1639 len = symlink_target_len;
1640 retval = sos_fs_write(tmp_of, symlink_target, & len);
1641 mark_dirty_fsnode(fsnode, FALSE);
1642 fsnode->close_opened_file(fsnode, tmp_of);
1643
1644 if ((SOS_OK != retval) || (len != symlink_target_len))
1645 {
1646 fs_remove_node(creator, symlink);
1647 if (SOS_OK == retval)
1648 retval = -SOS_ENAMETOOLONG;
1649 }
1650
1651 sos_fs_nscache_unref_node(symlink);
1652 return retval;
1653 }
1654
1655
1656 sos_ret_t sos_fs_mkdir(const struct sos_process * creator,
1657 const char * _path,
1658 sos_size_t _pathlen,
1659 sos_ui32_t access_rights)
1660 {
1661 struct sos_fs_pathname path;
1662
1663 path.contents = _path;
1664 path.length = _pathlen;
1665
1666 return fs_create_node(& path, creator, access_rights,
1667 SOS_FS_NODE_DIRECTORY, NULL);
1668 }
1669
1670
1671 sos_ret_t sos_fs_rmdir(const struct sos_process * actor,
1672 const char * _path,
1673 sos_size_t _pathlen)
1674 {
1675 sos_ret_t retval;
1676 struct sos_fs_pathname path;
1677 struct sos_fs_nscache_node * nsnode;
1678
1679 path.contents = _path;
1680 path.length = _pathlen;
1681
1682 if (path.length <= 0)
1683 return -SOS_ENOENT;
1684
1685 if (path.contents[0] == '/')
1686 nsnode = sos_process_get_root(actor)->direntry;
1687 else
1688 nsnode = sos_process_get_cwd(actor)->direntry;
1689
1690 retval = fs_lookup_node(& path, FALSE,
1691 sos_process_get_root(actor)->direntry,
1692 nsnode,
1693 & nsnode, & path, 0);
1694 if (SOS_OK != retval)
1695 return retval;
1696
1697
1698 if (path.length > 0)
1699 {
1700 sos_fs_nscache_unref_node(nsnode);
1701 return -SOS_ENOENT;
1702 }
1703
1704
1705 if (sos_fs_nscache_get_fs_node(nsnode)->type != SOS_FS_NODE_DIRECTORY)
1706 retval = -SOS_ENOTDIR;
1707
1708
1709 else if (sos_fs_nscache_get_ref_cnt(nsnode) > 1)
1710 retval = -SOS_EBUSY;
1711
1712
1713
1714 else if (sos_fs_nscache_get_fs_node(nsnode)->ondisk_lnk_cnt > 1)
1715 retval = -SOS_ENOTEMPTY;
1716
1717
1718 else
1719 retval = fs_remove_node(actor, nsnode);
1720
1721 sos_fs_nscache_unref_node(nsnode);
1722 return retval;
1723 }
1724
1725
1726 sos_ret_t sos_fs_mknod(const struct sos_process * creator,
1727 const char * _path,
1728 sos_size_t _pathlen,
1729 sos_fs_node_type_t type ,
1730 sos_ui32_t access_rights,
1731 const struct sos_fs_dev_id_t * devid)
1732 {
1733 sos_ret_t retval;
1734 struct sos_fs_pathname path;
1735 struct sos_fs_nscache_node * nsnode;
1736 struct sos_fs_node * fsnode;
1737
1738 if ((type != SOS_FS_NODE_DEVICE_BLOCK)
1739 && (type != SOS_FS_NODE_DEVICE_CHAR))
1740 return -SOS_EINVAL;
1741
1742 path.contents = _path;
1743 path.length = _pathlen;
1744
1745 retval = fs_create_node(& path, creator, access_rights,
1746 type, & nsnode);
1747 if (SOS_OK != retval)
1748 return retval;
1749
1750 fsnode = sos_fs_nscache_get_fs_node(nsnode);
1751 fsnode->dev_id.device_class = devid->device_class;
1752 fsnode->dev_id.device_instance = devid->device_instance;
1753
1754 sos_fs_nscache_unref_node(nsnode);
1755 return SOS_OK;
1756 }
1757
1758
1759 sos_ret_t sos_fs_stat(const struct sos_process * actor,
1760 const char * _path,
1761 sos_size_t _pathlen,
1762 int nofollow,
1763 struct sos_fs_stat * result)
1764 {
1765 sos_ret_t retval;
1766 struct sos_fs_pathname path;
1767 struct sos_fs_nscache_node * nsnode;
1768 struct sos_fs_node * fsnode;
1769
1770 path.contents = _path;
1771 path.length = _pathlen;
1772
1773 if (path.length <= 0)
1774 return -SOS_ENOENT;
1775
1776 if (path.contents[0] == '/')
1777 nsnode = sos_process_get_root(actor)->direntry;
1778 else
1779 nsnode = sos_process_get_cwd(actor)->direntry;
1780
1781 retval = fs_lookup_node(& path, (nofollow != 0),
1782 sos_process_get_root(actor)->direntry,
1783 nsnode,
1784 & nsnode, & path, 0);
1785 if (SOS_OK != retval)
1786 return retval;
1787
1788
1789 if (path.length > 0)
1790 {
1791 sos_fs_nscache_unref_node(nsnode);
1792 return -SOS_ENOENT;
1793 }
1794
1795 fsnode = sos_fs_nscache_get_fs_node(nsnode);
1796 retval = fsnode->ops_file->stat(fsnode, result);
1797
1798 sos_fs_nscache_unref_node(nsnode);
1799 return retval;
1800 }
1801
1802
1803 sos_ret_t sos_fs_fsync(struct sos_fs_opened_file * of)
1804 {
1805 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
1806 return sos_fs_sync_node(fsnode);
1807 }
1808
1809
1810 sos_ret_t sos_fs_chmod(const struct sos_process * actor,
1811 const char * _path,
1812 sos_size_t _pathlen,
1813 sos_ui32_t access_rights)
1814 {
1815 sos_ret_t retval;
1816 struct sos_fs_pathname path;
1817 struct sos_fs_nscache_node * nsnode;
1818 struct sos_fs_node * fsnode;
1819
1820 path.contents = _path;
1821 path.length = _pathlen;
1822
1823 if (path.length <= 0)
1824 return -SOS_ENOENT;
1825
1826 if (path.contents[0] == '/')
1827 nsnode = sos_process_get_root(actor)->direntry;
1828 else
1829 nsnode = sos_process_get_cwd(actor)->direntry;
1830
1831 retval = fs_lookup_node(& path, TRUE,
1832 sos_process_get_root(actor)->direntry,
1833 nsnode,
1834 & nsnode, & path, 0);
1835 if (SOS_OK != retval)
1836 return retval;
1837
1838
1839 if (path.length > 0)
1840 {
1841 sos_fs_nscache_unref_node(nsnode);
1842 return -SOS_ENOENT;
1843 }
1844
1845 fsnode = sos_fs_nscache_get_fs_node(nsnode);
1846 retval = fsnode->ops_file->chmod(fsnode, access_rights);
1847 if (SOS_OK == retval)
1848 mark_dirty_fsnode(fsnode, FALSE);
1849
1850 sos_fs_nscache_unref_node(nsnode);
1851 return retval;
1852 }
1853
1854
1855 sos_ret_t sos_fs_vfstat(const struct sos_process * actor,
1856 const char * _path,
1857 sos_size_t _pathlen,
1858 struct sos_fs_statfs * result)
1859 {
1860 sos_ret_t retval;
1861 struct sos_fs_pathname path;
1862 struct sos_fs_nscache_node * nsnode;
1863 struct sos_fs_node * fsnode;
1864
1865 path.contents = _path;
1866 path.length = _pathlen;
1867
1868 if (path.length <= 0)
1869 return -SOS_ENOENT;
1870
1871 if (path.contents[0] == '/')
1872 nsnode = sos_process_get_root(actor)->direntry;
1873 else
1874 nsnode = sos_process_get_cwd(actor)->direntry;
1875
1876 retval = fs_lookup_node(& path, FALSE,
1877 sos_process_get_root(actor)->direntry,
1878 nsnode,
1879 & nsnode, & path, 0);
1880 if (SOS_OK != retval)
1881 return retval;
1882
1883
1884 if (path.length > 0)
1885 {
1886 sos_fs_nscache_unref_node(nsnode);
1887 return -SOS_ENOENT;
1888 }
1889
1890 fsnode = sos_fs_nscache_get_fs_node(nsnode);
1891 if (fsnode->fs->statfs)
1892 retval = fsnode->fs->statfs(fsnode->fs, result);
1893 else
1894 retval = -SOS_ENOSYS;
1895
1896 sos_fs_nscache_unref_node(nsnode);
1897 return retval;
1898 }
1899
1900
1901
1902 sos_ret_t sos_fs_sync_all_fs()
1903 {
1904 int dummy = 0;
1905 sos_ui64_t uid = 0;
1906
1907 while (1)
1908 {
1909
1910 struct sos_fs_manager_type * fstype;
1911 int ntype;
1912 list_foreach(fs_list, fstype, ntype)
1913 {
1914
1915 struct sos_fs_manager_instance * fs;
1916 int ninst;
1917
1918
1919
1920
1921
1922
1923
1924
1925 list_foreach_forward(fstype->instances, fs, ninst)
1926 {
1927 if (fs->uid <= uid)
1928 continue;
1929
1930 uid = fs->uid;
1931 sos_fs_sync_fs(fs);
1932
1933
1934
1935
1936 goto lookup_next_fs;
1937 }
1938 }
1939
1940
1941 break;
1942
1943 lookup_next_fs:
1944
1945 dummy ++;
1946 }
1947
1948
1949 return sos_blockdev_sync_all_devices();
1950 }
1951
1952
1953
1954
1955
1956
1957
1958
1959 sos_ret_t sos_fs_register_fs_instance(struct sos_fs_manager_instance * fs,
1960 struct sos_fs_node * root_fsnode)
1961 {
1962 sos_ret_t retval;
1963 struct sos_fs_nscache_node * nsnode_root;
1964
1965 retval = sos_fs_nscache_create_mounted_root(root_fsnode, & nsnode_root);
1966 if (SOS_OK != retval)
1967 return retval;
1968
1969 fs->uid = ++last_fs_instance_uid;
1970 fs->root = nsnode_root;
1971 sos_hash_insert(fs->nodecache, root_fsnode);
1972
1973 list_add_tail(fs->fs_type->instances, fs);
1974 return SOS_OK;
1975 }
1976
1977
1978 sos_ret_t sos_fs_unregister_fs_instance(struct sos_fs_manager_instance * fs)
1979 {
1980 fs->uid = 0;
1981 list_delete(fs->fs_type->instances, fs);
1982 return SOS_OK;
1983 }
1984
1985
1986 sos_ret_t sos_fs_register_fs_type(struct sos_fs_manager_type * fstype)
1987 {
1988 struct sos_fs_manager_type * iterator;
1989 int nbtypes;
1990
1991 list_foreach_forward(fs_list, iterator, nbtypes)
1992 {
1993 if (! strncmp(fstype->name, iterator->name, SOS_FS_MANAGER_NAME_MAXLEN))
1994 return -SOS_EEXIST;
1995 }
1996
1997 list_add_tail(fs_list, fstype);
1998 return SOS_OK;
1999 }
2000
2001
2002 sos_ret_t sos_fs_unregister_fs_type(struct sos_fs_manager_type * fstype)
2003 {
2004 struct sos_fs_manager_type * iterator;
2005 int nbtypes;
2006
2007 if (! list_is_empty(fstype->instances))
2008 return -SOS_EBUSY;
2009
2010 list_foreach_forward(fs_list, iterator, nbtypes)
2011 {
2012 if (! strncmp(fstype->name, iterator->name, SOS_FS_MANAGER_NAME_MAXLEN))
2013 {
2014 list_delete(fs_list, fstype);
2015 return SOS_OK;
2016 }
2017 }
2018
2019 return -SOS_EINVAL;
2020 }
2021
2022
2023
2024
2025
2026 sos_ret_t sos_fs_mount(struct sos_process * actor,
2027 const char * _src_path,
2028 sos_size_t _src_pathlen,
2029 const char * _dst_path,
2030 sos_size_t _dst_pathlen,
2031 const char * fsname,
2032 sos_ui32_t mountflags,
2033 const char * args,
2034 struct sos_fs_manager_instance ** result_fs)
2035 {
2036 sos_ret_t retval;
2037 struct sos_fs_pathname src_path, dst_path;
2038 struct sos_fs_nscache_node * src_nsnode, * dst_nsnode;
2039 struct sos_fs_manager_type * fs_type;
2040 struct sos_fs_manager_instance * new_fs;
2041 int nb_fstypes;
2042
2043 if (_dst_pathlen <= 0)
2044 return -SOS_ENOENT;
2045
2046
2047 list_foreach(fs_list, fs_type, nb_fstypes)
2048 {
2049 if (! strcmp(fsname, fs_type->name))
2050 break;
2051 }
2052 if (! list_foreach_early_break(fs_list, fs_type, nb_fstypes))
2053 return -SOS_ENODEV;
2054
2055 src_path.contents = _src_path;
2056 src_path.length = _src_pathlen;
2057
2058
2059 if (src_path.length <= 0)
2060 src_nsnode = NULL;
2061 else if (src_path.contents[0] == '/')
2062 src_nsnode = sos_process_get_root(actor)->direntry;
2063 else
2064 src_nsnode = sos_process_get_cwd(actor)->direntry;
2065
2066
2067 if (src_nsnode)
2068 {
2069 retval = fs_lookup_node(& src_path, TRUE,
2070 sos_process_get_root(actor)->direntry,
2071 src_nsnode,
2072 & src_nsnode, & src_path, 0);
2073 if (SOS_OK != retval)
2074 return retval;
2075
2076
2077 if (src_path.length > 0)
2078 {
2079 sos_fs_nscache_unref_node(src_nsnode);
2080 return -SOS_ENOENT;
2081 }
2082 }
2083
2084 dst_path.contents = _dst_path;
2085 dst_path.length = _dst_pathlen;
2086
2087
2088 if (dst_path.contents[0] == '/')
2089 dst_nsnode = sos_process_get_root(actor)->direntry;
2090 else
2091 dst_nsnode = sos_process_get_cwd(actor)->direntry;
2092
2093
2094 retval = fs_lookup_node(& dst_path, TRUE,
2095 sos_process_get_root(actor)->direntry,
2096 dst_nsnode,
2097 & dst_nsnode, & dst_path, 0);
2098 if ((SOS_OK != retval) || (dst_path.length > 0))
2099 {
2100 if (src_nsnode)
2101 sos_fs_nscache_unref_node(src_nsnode);
2102 if (dst_path.length > 0)
2103 retval = -SOS_ENOENT;
2104 return retval;
2105 }
2106
2107
2108 retval
2109 = fs_type->mount(fs_type,
2110 (src_nsnode)?sos_fs_nscache_get_fs_node(src_nsnode):NULL,
2111 args, & new_fs);
2112 if (SOS_OK != retval)
2113 {
2114 if (src_nsnode)
2115 sos_fs_nscache_unref_node(src_nsnode);
2116 sos_fs_nscache_unref_node(dst_nsnode);
2117 return retval;
2118 }
2119
2120
2121 SOS_ASSERT_FATAL(NULL != new_fs->nodecache);
2122 SOS_ASSERT_FATAL(NULL != new_fs->root);
2123
2124
2125 sos_fs_nscache_get_fs_node(new_fs->root)->fs = new_fs;
2126
2127
2128 retval = sos_fs_nscache_mount(dst_nsnode, new_fs->root);
2129 SOS_ASSERT_FATAL(SOS_OK == retval);
2130
2131
2132 if (src_nsnode)
2133 sos_fs_nscache_unref_node(src_nsnode);
2134 sos_fs_nscache_unref_node(dst_nsnode);
2135
2136 if (result_fs)
2137 *result_fs = new_fs;
2138
2139 return SOS_OK;
2140 }
2141
2142
2143 sos_ret_t sos_fs_umount(struct sos_process * actor,
2144 const char * _mounted_root_path,
2145 sos_size_t _mounted_root_pathlen)
2146 {
2147 sos_ret_t retval;
2148 struct sos_fs_pathname mounted_root_path;
2149 struct sos_fs_nscache_node * mounted_root_nsnode;
2150 struct sos_fs_manager_instance * fs;
2151
2152 if (_mounted_root_pathlen <= 0)
2153 return -SOS_ENOENT;
2154
2155 mounted_root_path.contents = _mounted_root_path;
2156 mounted_root_path.length = _mounted_root_pathlen;
2157
2158
2159 if (mounted_root_path.contents[0] == '/')
2160 mounted_root_nsnode = sos_process_get_root(actor)->direntry;
2161 else
2162 mounted_root_nsnode = sos_process_get_cwd(actor)->direntry;
2163
2164
2165 retval = fs_lookup_node(& mounted_root_path, TRUE,
2166 sos_process_get_root(actor)->direntry,
2167 mounted_root_nsnode,
2168 & mounted_root_nsnode, & mounted_root_path, 0);
2169 if (SOS_OK != retval)
2170 return retval;
2171
2172
2173 if (mounted_root_path.length > 0)
2174 {
2175 sos_fs_nscache_unref_node(mounted_root_nsnode);
2176 return -SOS_ENOENT;
2177 }
2178
2179
2180 fs = sos_fs_nscache_get_fs_node(mounted_root_nsnode)->fs;
2181 if (fs->root != mounted_root_nsnode)
2182 {
2183 sos_fs_nscache_unref_node(mounted_root_nsnode);
2184 return -SOS_ENOENT;
2185 }
2186
2187
2188 retval = sos_fs_nscache_umount(mounted_root_nsnode);
2189
2190
2191 sos_fs_nscache_unref_node(mounted_root_nsnode);
2192 if (SOS_OK != retval)
2193 return retval;
2194
2195 fs->root = NULL;
2196
2197
2198 retval = sos_fs_sync_fs(fs);
2199 if (SOS_OK != retval)
2200 {
2201 return retval;
2202 }
2203
2204 retval = fs->fs_type->umount(fs->fs_type, fs);
2205 return retval;
2206 }