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