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      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 
026 #include "fs.h"
027 
028 
029 /** List of available filesystems registered in the system */
030 static struct sos_fs_manager_type * fs_list = NULL;
031 
032 /** Last UID delivered for the FS instances */
033 static sos_ui64_t last_fs_instance_uid;
034 
035 
036 /* **********************************************************
037  * Forward declarations
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  * Basic low-level memory & co related functions
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   /* root_device is ignored for now */
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   /* Look for the FS manager type */
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   /* Update some reserved fields */
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   /* Commit the changes the the FS when the last reference is being
172      removed */
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  * Some helper functions
224  */
225 
226 /** Fetch the given fsnode from hash first, or from disk when not in
227     hash */
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   /* If it is already loaded in memory, no need to look further */
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   /* Otherwise, call the appropriate method of the FS */
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  * Helper function to allocate a new on-disk node
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   /* Make sure FS is writable ! */
266   if (fs->flags & SOS_FS_MOUNT_READONLY)
267     return -SOS_EPERM;
268 
269   /* Allocate the node on disk */
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   /* Update some resrved fields */
278   (*result_fsnode)->fs = fs;
279 
280   /* insert it in the node cache */
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   /* Success: Consider the node as dirty */
289   mark_dirty_fsnode(*result_fsnode, FALSE);
290   return retval;
291 }
292 
293 
294 /** Helper function to add the given node in the dirty list, or to
295     write it directly to the disk if the system is mounted in SYNC
296     mode */
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   /* If the fsnode is newly dirty, add it to the dirty list of the
308      FS */
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       /* Commit the node changes to the FS */
316       if (SOS_OK == sos_fs_sync_node(fsnode))
317         {
318           /* Commit the FS changes to the device */
319           if (SOS_OK
320               == fsnode->fs->device->ops_file->sync(fsnode->fs->device))
321             return SOS_OK;
322 
323           /* We got a problem: FORCE re-add the node to the dirty list */
324           was_dirty = FALSE;
325           fsnode->dirty = TRUE;
326           retval = -SOS_EBUSY;
327         }
328     }
329 
330   return retval;
331 }
332 
333 
334 /** Remove the given node from the dirty list of the FS */
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   /* Remove it from the dirty list */
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 /** Collapse the whole dirty list of the FS and commit the changes to
356     the underlying device */
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  * Resolve the given symlink: return the nsnode for the destination
377  * of the symlink, or error status for dangling symlinks
378  *
379  * @note result_nsnode is a NEW reference to the node. It should be
380  * unreferenced when unused
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   /* Absolute path for target ? */
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   /* The target of the symlink could not be completely opened ! */
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  * @return OK in any case, except if 1/ a symlink could not be
436  * resolved, or 2/ a path "a/b" is given where "a" is not a directory,
437  * or 3/ a fsnode that should exist could not be retrieved from disk.
438  *
439  * @param result_remaining_path contains the path that could not be resolved
440  *
441  * @param result_nsnode a NEW reference to the farthest node that
442  * could be resolved. It should be unreferenced when unused
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   /* Make sure we did not go too deep while resolving symlinks */
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 /*       dbg_dump_pathname("Before", result_remaining_path); */
478 
479       /* Extract the next component of the path */
480       slashes_after_first_component
481         = sos_fs_pathname_split_path(result_remaining_path,
482                                      & current_component, & remaining);
483 /*       dbg_dump_pathname("After", result_remaining_path); */
484 /*       dbg_dump_pathname("Cur", & current_component); */
485 /*       dbg_dump_pathname("Rem", & remaining); */
486 /*       sos_bochs_printf("Slash after=%d\n", slashes_after_first_component); */
487 
488       /* Could resolve the whole path ? */
489       if (current_component.length == 0)
490         {
491           /* Ok, fine, we got it ! */
492           memcpy(result_remaining_path, & remaining, sizeof(remaining));
493           *result_nsnode = current_nsnode;        
494           return SOS_OK;
495         }
496 
497       /* Otherwise: make sure we reached a DIR node */
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       /* Make sure this directory is "executable" */
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       /* If we can find the entry in the namespace cache, it is really
514          fine ! */
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            * Not found in the namespace cache. Must read from the
526            * disk...
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               /* Well, we cannot go further, stop here */
538               *result_nsnode = current_nsnode;
539               return SOS_OK;
540             }
541 
542           /* Now retrieve this node from disk or from the cache into
543              memory */
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           /* Integrate it in the nscache */
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       /* Reaching a symlink ? */
565       if (sos_fs_nscache_get_fs_node(next_nsnode)->type
566           == SOS_FS_NODE_SYMLINK)
567         {
568           /* Expand the link only for non-terminal nodes, or for the
569              terminal node only if follow_symlinks is TRUE */
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; /* Dangling symlink */
581 
582               next_nsnode = symlink_target;
583             }
584         }
585       
586       /* Make sure there was no slash after this component, unless
587          this component is a directory */
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       /* Ok, fine, we got it, update the path we still have to explore */
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  * It is assumed that parent does not already have a child with the
609  * given name. We make sure that the "path" is a single entity (ie
610  * not "a/b")
611  * @return Error if fsnode is not on the same FS as parent_nsnode
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       /* Make sure the given name is exactly a single path component
639          (ie no '/') */
640       if (slashes_after_first_component)
641         return -SOS_EINVAL;
642     }
643   else
644     {
645       /* Make sure there aren't any other component behind the '/'s, if
646          any */
647       if (remaining.length > 0)
648         return -SOS_EINVAL;
649     }
650 
651   /* Make sure the parent directory is writeable */
652   if (! (parent_fsnode->access_rights & SOS_FS_WRITABLE) )
653     return -SOS_EACCES;
654 
655   /* Make sure that the entries are located on the same FS */
656   if (fsnode->fs != parent_fsnode->fs)
657     return -SOS_EXDEV;
658 
659   /* Make sure that the nsnode won't be destroyed */
660   sos_fs_nscache_ref_node(parent_nsnode);
661 
662   /* Allocate the node in directory */
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   /* Success: Consider the directory as dirty */
675   mark_dirty_fsnode(parent_fsnode, FALSE);
676 
677   /* Allocate the node in nscache cache */
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 /** It is assumed that parent does not already have a child with the
687     given name. We make sure that the "path" is a single entity (ie
688     not "a/b"). Return a NEW reference to the newly-created NS node */
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   /* Make sure that the nsnode won't be destroyed */
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   /* The function does not need it anymore */
722   sos_fs_unref_fsnode(fsnode);
723 
724   return retval;
725 }
726 
727 
728 /**
729  * It is assumed that parent does not already have a child with the
730  * given name, and that the new child does not have a parent yet. We
731  * make sure that the "path" is a single entity (ie not "a/b") @return
732  * Error if fsnode is not on the same FS as parent_nsnode
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       /* Make sure the given name is exactly a single path component
759          (ie no '/') */
760       if (slashes_after_first_component)
761         return -SOS_EINVAL;
762     }
763   else
764     {
765       /* Make sure there aren't any other component behind the '/'s, if
766          any */
767       if (remaining.length > 0)
768         return -SOS_EINVAL;
769     }
770 
771   /* Make sure the parent directory is writeable */
772   if (! (parent_fsnode->access_rights & SOS_FS_WRITABLE) )
773     return -SOS_EACCES;
774 
775   /* Make sure that the entries are located on the same FS */
776   if (fsnode->fs != parent_fsnode->fs)
777     return -SOS_EXDEV;
778 
779   /* Make sure that the nsnode won't be destroyed */
780   sos_fs_nscache_ref_node(parent_nsnode);
781 
782   /* Allocate the node in directory */
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   /* Success: Consider the directory as dirty */
795   mark_dirty_fsnode(parent_fsnode, FALSE);
796 
797   /* Allocate the node in nscache cache */
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 /** Return a new reference to the new node inserted unless
807     result_nsnode is NULL */
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       /* Found the exact match ! */
843       sos_fs_nscache_unref_node(nsnode);
844       return -SOS_EEXIST;
845     }
846 
847   /* Create a new entry in the file system */
848   retval = fs_create_child_node(nsnode,
849                                 & path,
850                                 type,
851                                 /* flags */0,
852                                 creator, access_rights,
853                                 & new_nsnode);
854   sos_fs_nscache_unref_node(nsnode);
855 
856   /* node not needed by this function ? */
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   /* Refuse to do anything if this is the root of a mounted FS */
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   /* Make sure FS is writable ! */
885   if (parent_fsnode->fs->flags & SOS_FS_MOUNT_READONLY)
886     return -SOS_EPERM;
887 
888   /* Make sure the parent directory is writeable */
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   /* Unallocate the node */
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  * Exported functions
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   /* O_DIR | O_CREAT combination not supported */
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       /* Found the exact match ! */
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       /* Did not find an exact match. Should create the node ! */
1026       if (! (open_flags & SOS_FS_OPEN_CREAT))
1027         {
1028           sos_fs_nscache_unref_node(parent_nsnode);
1029           return -SOS_ENOENT;
1030         }
1031 
1032       /* Create a new entry in the file system */
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   /* Recompute access rights */
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    * Ok, open it right now !
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   /* This function should never get called if the FS is read-only */
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 * /* in/ou */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 * /* in/out */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   /* Translate VM requested rights into FS equivalent */
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   /* Make sure that the opened file allowed this access */
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 /* Usually: sos_uaddr_t */)
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   /* Resolve target FS node using "old_path" */
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 /* don't follow symlink */,
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       /* Could not resolve full path ! */
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   /* Not allowed to link directories ! */
1263   if (fsnode->type == SOS_FS_NODE_DIRECTORY)
1264     {
1265       sos_fs_nscache_unref_node(old_nsnode);
1266       return -SOS_ENOENT;
1267     }
1268 
1269   /* Resolve destination path */
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 /* Follow symlink */,
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       /* Found the exact match ! Not allowed to overwrite it ! */
1294       sos_fs_nscache_unref_node(dest_parent_nsnode);
1295       sos_fs_nscache_unref_node(old_nsnode);
1296       return -SOS_EEXIST;
1297     }
1298 
1299   /* Create a new entry in the file system */
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   /* Resolve target FS node using "old_path" */
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 /* don't follow symlink */,
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       /* Could not resolve full path ! */
1352       sos_fs_nscache_unref_node(old_nsnode);
1353       return -SOS_ENOENT;
1354     }
1355 
1356   /* Not allowed to rename mountpoints ! */
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   /* Keep a reference on this node's parent, in case we must undo the
1364      rename */
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   /* Resolve destination path */
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 /* Follow symlink */,
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   /* Nothing to do ? */
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   /* Remove old nsnode from file ns cache */
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       /* Found the exact match ! We disconnect it from the namespace,
1418          but keep it aside */
1419 
1420       /* Not allowed to replace directories */
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       /* Retrieve the parent of the node to replace */
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       /* Disconnect this node from its parent */
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   /* Create a new entry in the file system */
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   /* Handle special case: the node replaced something. In case the
1467      previous operation failed, we try to reinsert the replaced
1468      node */
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   /* Make sure the whole path has been resolved */
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   /* Artificially open the symlink to change its contents */
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   /* Make sure the whole path has been resolved */
1634   if (path.length > 0)
1635     {
1636       sos_fs_nscache_unref_node(nsnode);
1637       return -SOS_ENOENT;
1638     }
1639 
1640   /* Cannot rmdir non-dir nodes */
1641   if (sos_fs_nscache_get_fs_node(nsnode)->type != SOS_FS_NODE_DIRECTORY)
1642     retval = -SOS_ENOTDIR;
1643 
1644   /* Cannot remove directory if it is still used by somebody else */
1645   else if (sos_fs_nscache_get_ref_cnt(nsnode) > 1)
1646     retval = -SOS_EBUSY;
1647 
1648   /* Cannot remove directory if it is still has children stored on
1649      disk */
1650   else if (sos_fs_nscache_get_fs_node(nsnode)->ondisk_lnk_cnt > 1)
1651     retval = -SOS_ENOTEMPTY;
1652 
1653   /* Otherwise, yes : suppress the node on disk */
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   /* Make sure the whole path has been resolved */
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   /* Make sure the whole path has been resolved */
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   /* Make sure the whole path has been resolved */
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 /** This function is resilient against mounting/unmounting of other FS */
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       /* Iterate over the FS types */
1813       struct sos_fs_manager_type * fstype;
1814       int ntype;
1815       list_foreach(fs_list, fstype, ntype)
1816         {
1817           /* Iterate over the FS instances */
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               /* We must NOT continue the loops because the
1830                  prev/next/current fs types/instances might have been
1831                  removed or added (sync blocks, by definition) ! */
1832               goto lookup_next_fs;
1833             }
1834         }
1835 
1836     lookup_next_fs:
1837       /* Loop over */
1838       dummy ++;
1839     }
1840 
1841   return SOS_OK;
1842 }
1843 
1844 
1845 
1846 /* *************************************************************
1847  * mount/umount stuff
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  * _src_path may be empty
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   /* Look for the FS manager type */
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   /* Compute the start_nsnode for the source */
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   /* Lookup the source node */
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       /* Make sure the whole path has been resolved */
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   /* Compute the start_nsnode for the destination */
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   /* Lookup the destination node */
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   /* Actually call the mount callback of the FS */
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   /* Make sure the nodecache was created */
2013   SOS_ASSERT_FATAL(NULL != new_fs->nodecache);
2014   SOS_ASSERT_FATAL(NULL != new_fs->root);
2015 
2016   /* Update some reserved fields */
2017   sos_fs_nscache_get_fs_node(new_fs->root)->fs = new_fs;
2018 
2019   /* Register the mountpoint in the nscache */
2020   retval = sos_fs_nscache_mount(dst_nsnode, new_fs->root);
2021   SOS_ASSERT_FATAL(SOS_OK == retval);
2022 
2023   /* Un-reference the temporary nsnodes */
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   /* Compute the start_nsnode for the mounted_root */
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   /* Lookup the mounted_root node */
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   /* Make sure the whole path has been resolved */
2065   if (mounted_root_path.length > 0)
2066     {
2067       sos_fs_nscache_unref_node(mounted_root_nsnode);
2068       return -SOS_ENOENT;
2069     }
2070 
2071   /* Make sure this node is the real root of the FS */
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   /* Disconnect this FS mounted_root from namespace cache */
2080   retval = sos_fs_nscache_umount(mounted_root_nsnode);
2081 
2082   /* Mounted_Root not needed anymore */
2083   sos_fs_nscache_unref_node(mounted_root_nsnode);
2084   if (SOS_OK != retval)
2085     return retval;
2086 
2087   fs->root = NULL;
2088 
2089   /* Flush any changes to disk */
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 }

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