SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

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

source navigation ] diff markup ] identifier search ] general search ]