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

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