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