source: rtems/cpukit/libfs/src/rfs/rtems-rfs-rtems.c @ 9788279

4.115
Last change on this file since 9788279 was 9788279, checked in by Sebastian Huber <sebastian.huber@…>, on 08/25/10 at 09:37:49

2010-08-25 Sebastian Huber <sebastian.huber@…>

  • libfs/src/imfs/imfs_fcntl.c: Removed file.
  • libfs/Makefile.am: Reflect change from above.
  • libfs/src/defaults/default_fcntl.c: Return 0 instead of -1 and errno.
  • libfs/src/imfs/imfs.h, libfs/src/imfs/imfs_fifo.c, libfs/src/imfs/imfs_handlers_directory.c, libfs/src/imfs/imfs_handlers_memfile.c, libfs/src/nfsclient/src/nfs.c, libfs/src/rfs/rtems-rfs-rtems-dir.c, libfs/src/rfs/rtems-rfs-rtems-file.c, libfs/src/rfs/rtems-rfs-rtems.c, libfs/src/rfs/rtems-rfs-rtems.h: Use default file system handlers.
  • Property mode set to 100644
File size: 36.3 KB
Line 
1/*
2 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.com/license/LICENSE.
7 *
8 *  $Id$
9 */
10/**
11 * @file
12 *
13 * @ingroup rtems-rfs
14 *
15 * RTEMS File System Interface for RTEMS.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <inttypes.h>
23#include <stdlib.h>
24
25#if SIZEOF_MODE_T == 8
26#define PRIomode_t PRIo64
27#elif SIZEOF_MODE_T == 4
28#define PRIomode_t PRIo32
29#else
30#error "unsupport size of mode_t"
31#endif
32
33#include <rtems/rfs/rtems-rfs-file.h>
34#include <rtems/rfs/rtems-rfs-dir.h>
35#include <rtems/rfs/rtems-rfs-link.h>
36#include "rtems-rfs-rtems.h"
37
38/**
39 * The libio permissions for read/execute.
40 */
41#define RTEMS_LIBIO_PERMS_RX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_READ)
42/**
43 * The libio permissions for write/execute.
44 */
45#define RTEMS_LIBIO_PERMS_WX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_WRITE)
46
47/**
48 * Evaluate the path to a node that wishes to be accessed. The pathloc is
49 * returned with the ino to the node to be accessed.
50 *
51 * The routine starts from the root stripping away any leading path separators
52 * breaking the path up into the node names and checking an inode exists for
53 * that node name. Permissions are checked to insure access to the node is
54 * allowed. A path to a node must be accessable all the way even if the end
55 * result is directly accessable. As a user on Linux try "ls /root/../tmp" and
56 * you will see if fails.
57 *
58 * The whole process is complicated by crossmount paths where we head down into
59 * this file system only to return to the top and out to a another mounted file
60 * system. For example we are mounted on '/e' and the user enters "ls
61 * /e/a/b/../../dev". We need to head down then back up.
62 *
63 * @param path
64 * @param pathlen
65 * @param flags
66 * @param pathloc
67 */
68int
69rtems_rfs_rtems_eval_path (const char*                       path,
70                           size_t                            pathlen,
71                           int                               flags,
72                           rtems_filesystem_location_info_t* pathloc)
73{
74  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
75  rtems_rfs_inode_handle inode;
76  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
77  uint32_t               doff = 0;
78  const char*            node;
79  size_t                 node_len;
80  int                    stripped;
81  int                    rc;
82
83  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
84    printf ("rtems-rfs-rtems: eval-path: in: path:%s pathlen:%zi ino:%" PRId32 "\n",
85            path, pathlen, ino);
86 
87  /*
88   * Eat any separators at the start of the path.
89   */
90  stripped = rtems_filesystem_prefix_separators (path, pathlen);
91  path += stripped;
92  pathlen -= stripped;
93
94  rtems_rfs_rtems_lock (fs);
95 
96  while (true)
97  {
98    /*
99     * Open and load the inode.
100     */
101    rc = rtems_rfs_inode_open (fs, ino, &inode, true);
102    if (rc > 0)
103    {
104      rtems_rfs_rtems_unlock (fs);
105      return rtems_rfs_rtems_error ("eval_path: opening inode", rc);
106    }
107   
108    /*
109     * Is this the end of the pathname we where given ?
110     */
111    if ((*path == '\0') || (pathlen == 0))
112      break;
113
114    /*
115     * If a directory the execute bit must be set for us to enter.
116     */
117    if (RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)) &&
118        !rtems_rfs_rtems_eval_perms (&inode, RTEMS_LIBIO_PERMS_SEARCH))
119    {
120      rtems_rfs_inode_close (fs, &inode);
121      rtems_rfs_rtems_unlock (fs);
122      return rtems_rfs_rtems_error ("eval_path: eval perms", EACCES);
123    }
124   
125    /*
126     * Extract the node name we will look for this time around.
127     */
128    node = path;
129    node_len = 0;
130    while (!rtems_filesystem_is_separator (*path) &&
131           (*path != '\0') && pathlen &&
132           ((node_len + 1) < rtems_rfs_fs_max_name (fs)))
133    {
134      path++;
135      pathlen--;
136      node_len++;
137    }
138
139    /*
140     * Eat any separators at start of the path.
141     */
142    stripped = rtems_filesystem_prefix_separators (path, pathlen);
143    path += stripped;
144    pathlen -= stripped;
145    node_len += stripped;
146
147    /*
148     * If the node is the current directory and there is more path to come move
149     * on it else we are at the inode we want.
150     */
151    if (rtems_rfs_current_dir (node))
152    {
153      if (*path)
154        continue;
155      break;
156    }
157
158    /*
159     * If the node is a parent we must move up one directory. If the location
160     * is on another file system we have a crossmount so we call that file
161     * system to handle the remainder of the path.
162     */
163    if (rtems_rfs_parent_dir (node))
164    {
165      /*
166       * If we are at root inode of the file system we have a crossmount path.
167       */
168      if (ino == RTEMS_RFS_ROOT_INO)
169      {
170        if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
171          printf("rtems-rfs-rtems: eval-path: crossmount: path:%s (%zd)\n",
172                 path - node_len, pathlen + node_len);
173        rtems_rfs_inode_close (fs, &inode);
174        rtems_rfs_rtems_unlock (fs);
175        *pathloc = pathloc->mt_entry->mt_point_node;
176        return (*pathloc->ops->evalpath_h)(path - node_len, pathlen + node_len,
177                                           flags, pathloc);
178      }
179
180      /*
181       * We need to find the parent of this node.
182       */
183      rc = rtems_rfs_dir_lookup_ino (fs, &inode, "..", 2, &ino, &doff);
184      if (rc > 0)
185      {
186        rtems_rfs_inode_close (fs, &inode);
187        rtems_rfs_rtems_unlock (fs);
188        return rtems_rfs_rtems_error ("eval_path: read parent inode", rc);
189      }
190      if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
191        printf("rtems-rfs-rtems: eval-path: parent: ino:%" PRId32 "\n", ino);
192    }
193    else
194    {
195      /*
196       * Look up the node name in this directory. If found drop through, close
197       * the current inode and let the loop open the inode so the mode can be
198       * read and handlers set.
199       */
200      rc = rtems_rfs_dir_lookup_ino (fs, &inode,
201                                     node, node_len - stripped, &ino, &doff);
202      if (rc > 0)
203      {
204        rtems_rfs_inode_close (fs, &inode);
205        rtems_rfs_rtems_unlock (fs);
206        return ((errno = rc) == 0) ? 0 : -1;
207      }   
208      if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
209        printf("rtems-rfs-rtems: eval-path: down: path:%s ino:%" PRId32 "\n", node, ino);
210    }
211
212    rc = rtems_rfs_inode_close (fs, &inode);
213    if (rc > 0)
214    {
215      rtems_rfs_inode_close (fs, &inode);
216      rtems_rfs_rtems_unlock (fs);
217      return rtems_rfs_rtems_error ("eval_path: closing node", rc);
218    }   
219  }
220 
221  rtems_rfs_rtems_set_pathloc_ino (pathloc, ino);
222  rtems_rfs_rtems_set_pathloc_doff (pathloc, doff);
223
224  rc = rtems_rfs_rtems_set_handlers (pathloc, &inode) ? 0 : EIO;
225 
226  rtems_rfs_inode_close (fs, &inode);
227  rtems_rfs_rtems_unlock (fs);
228
229  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
230    printf("rtems-rfs-rtems: eval-path: ino:%" PRId32 "\n", ino);
231
232  return rc;
233}
234
235/**
236 * The following routine evaluates a path for a new node to be created. The
237 * pathloc is returned with a pointer to the parent of the new node. The name
238 * is returned with a pointer to the first character in the new node name. The
239 * parent node is verified to be a directory.
240 *
241 * @param path
242 * @param pathloc
243 * @param name
244 * @return int
245 */
246int
247rtems_rfs_rtems_eval_for_make (const char*                       path,
248                               rtems_filesystem_location_info_t* pathloc,
249                               const char**                      name)
250{
251  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
252  rtems_rfs_inode_handle inode;
253  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
254  rtems_rfs_ino          node_ino;
255  uint32_t               doff = 0;
256  const char*            node;
257  int                    node_len;
258  int                    stripped;
259  int                    rc;
260
261  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
262    printf ("rtems-rfs-rtems: eval-for-make: path:%s ino:%" PRId32 "\n", path, ino);
263 
264  *name = path + strlen (path);
265
266  while (*name != path)
267  {
268    (*name)--;
269    if (rtems_filesystem_is_separator (**name))
270    {
271      (*name)++;
272      break;
273    }
274  }
275     
276  /*
277   * Eat any separators at start of the path.
278   */
279  stripped = rtems_filesystem_prefix_separators (path, strlen(path));
280  path += stripped;
281
282  rtems_rfs_rtems_lock (fs);
283 
284  while (true)
285  {
286    /*
287     * Open and load the inode.
288     */
289    rc = rtems_rfs_inode_open (fs, ino, &inode, true);
290    if (rc > 0)
291    {
292      rtems_rfs_rtems_unlock (fs);
293      return rtems_rfs_rtems_error ("eval_for_make: read ino", rc);
294    }
295 
296    /*
297     * If a directory the execute bit must be set for us to enter.
298     */
299    if (RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)) &&
300        !rtems_rfs_rtems_eval_perms (&inode, RTEMS_LIBIO_PERMS_SEARCH))
301    {
302      rtems_rfs_inode_close (fs, &inode);
303      rtems_rfs_rtems_unlock (fs);
304      return rtems_rfs_rtems_error ("eval_for_make: eval perms", EACCES);
305    }
306   
307    /*
308     * Is this the end of the pathname we where given ?
309     */
310    if (path == *name)
311      break;
312   
313    /*
314     * Extract the node name we will look for this time around.
315     */
316    node = path;
317    node_len = 0;
318    while (!rtems_filesystem_is_separator(*path) &&
319           (*path != '\0') &&
320           (node_len < (rtems_rfs_fs_max_name (fs) - 1)))
321    {
322      node_len++;
323      path++;
324    }
325
326    /*
327     * Eat any separators at start of the new path.
328     */
329    stripped = rtems_filesystem_prefix_separators (path, strlen (path));
330    path += stripped;
331    node_len += stripped;
332
333    /*
334     * If the node is the current directory and there is more path to come move
335     * on it else we are at the inode we want.
336     */
337    if (rtems_rfs_current_dir (node))
338    {
339      if (*path)
340        continue;
341      break;
342    }
343     
344    /*
345     * If the node is a parent we must move up one directory. If the location
346     * is on another file system we have a crossmount so we call that file
347     * system to handle the remainder of the path.
348     */
349    if (rtems_rfs_parent_dir (path))
350    {
351      /*
352       * If we are at the root inode of the file system we have a crossmount
353       * path.
354       */
355      if (ino == RTEMS_RFS_ROOT_INO)
356      {
357        if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
358          printf("rtems-rfs-rtems: eval-for-make: crossmount: path:%s\n",
359                 path - node_len);
360
361        rtems_rfs_inode_close (fs, &inode);
362        rtems_rfs_rtems_unlock (fs);
363        *pathloc = pathloc->mt_entry->mt_point_node;
364        return (*pathloc->ops->evalformake_h)(path - node_len, pathloc, name);
365      }
366
367      /*
368       * If not a directory give and up return. We cannot change dir from a
369       * regular file or device node.
370       */
371      if (!RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)))
372      {
373        rtems_rfs_inode_close (fs, &inode);
374        rtems_rfs_rtems_unlock (fs);
375        return rtems_rfs_rtems_error ("eval_for_make: not dir", ENOTSUP);
376      }
377     
378      /*
379       * We need to find the parent of this node.
380       */
381      rc = rtems_rfs_dir_lookup_ino (fs, &inode, "..", 2, &ino, &doff);
382      if (rc > 0)
383      {
384        rtems_rfs_inode_close (fs, &inode);
385        rtems_rfs_rtems_unlock (fs);
386        return rtems_rfs_rtems_error ("eval_for_make: read parent inode", rc);
387      }
388      if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
389        printf ("rtems-rfs-rtems: eval-for-make: parent: ino:%" PRId32 "\n", ino);
390    }
391    else
392    {
393      /*
394       * Read the inode so we know it exists and what type it is.
395       */
396      rc = rtems_rfs_dir_lookup_ino (fs, &inode,
397                                     node, node_len - stripped, &ino, &doff);
398      if (rc > 0)
399      {
400        rtems_rfs_inode_close (fs, &inode);
401        rtems_rfs_rtems_unlock (fs);
402        return rtems_rfs_rtems_error ("eval_for_make: reading inode", rc);
403      }
404      if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
405        printf("rtems-rfs-rtems: eval-for-make: down: path:%s ino:%" PRId32 "\n",
406               node, ino);
407    }
408
409    rc = rtems_rfs_inode_close (fs, &inode);
410    if (rc > 0)
411    {
412      rtems_rfs_rtems_unlock (fs);
413      return rtems_rfs_rtems_error ("eval_for_make: closing node", rc);
414    }   
415  }
416
417  if (!RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)))
418  {
419    rtems_rfs_inode_close (fs, &inode);
420    rtems_rfs_rtems_unlock (fs);
421    return rtems_rfs_rtems_error ("eval_for_make: not dir", ENOTDIR);
422  }
423
424  if (!rtems_rfs_rtems_eval_perms (&inode, RTEMS_LIBIO_PERMS_WX))
425  {
426    rtems_rfs_inode_close (fs, &inode);
427    rtems_rfs_rtems_unlock (fs);
428    return rtems_rfs_rtems_error ("eval_for_make: cannot write", EACCES);
429  }
430 
431  /*
432   * Make sure the name does not already exists in the directory.
433   */
434  rc = rtems_rfs_dir_lookup_ino (fs, &inode, *name, strlen (*name),
435                                 &node_ino, &doff);
436  if (rc == 0)
437  {
438    rtems_rfs_inode_close (fs, &inode);
439    rtems_rfs_rtems_unlock (fs);
440    return rtems_rfs_rtems_error ("eval_for_make: found name", EEXIST);
441  }
442
443  if (rc != ENOENT)
444  {
445    rtems_rfs_inode_close (fs, &inode);
446    rtems_rfs_rtems_unlock (fs);
447    return rtems_rfs_rtems_error ("eval_for_make: look up", rc);
448  }
449 
450  /*
451   * Set the parent ino in the path location.
452   */
453
454  rtems_rfs_rtems_set_pathloc_ino (pathloc, ino);
455  rtems_rfs_rtems_set_pathloc_doff (pathloc, doff);
456
457  rc = rtems_rfs_rtems_set_handlers (pathloc, &inode) ? 0 : EIO;
458
459  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
460    printf("rtems-rfs-rtems: eval-for-make: parent ino:%" PRId32 " name:%s\n",
461           ino, *name);
462
463  rtems_rfs_inode_close (fs, &inode);
464  rtems_rfs_rtems_unlock (fs);
465 
466  return rc;
467}
468
469/**
470 * The following rouine creates a new link node under parent with the name
471 * given in name. The link node is set to point to the node at to_loc.
472 *
473 * @param to_loc
474 * @param parent_loc
475 * @param name
476 * @return int
477 */
478int
479rtems_rfs_rtems_link (rtems_filesystem_location_info_t* to_loc,
480                      rtems_filesystem_location_info_t* parent_loc,
481                      const char*                       name)
482{
483  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (to_loc);
484  rtems_rfs_ino          target = rtems_rfs_rtems_get_pathloc_ino (to_loc);
485  rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parent_loc);
486  int                    rc;
487
488  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_LINK))
489    printf ("rtems-rfs-rtems: link: in: parent:%" PRId32 " target:%" PRId32 "\n",
490            parent, target);
491 
492  rtems_rfs_rtems_lock (fs);
493 
494  rc = rtems_rfs_link (fs, name, strlen (name), parent, target, false);
495  if (rc)
496  {
497    rtems_rfs_rtems_unlock (fs);
498    return rtems_rfs_rtems_error ("link: linking", rc);
499        }
500
501  rtems_rfs_rtems_unlock (fs);
502 
503        return 0;
504}
505
506/**
507 * Routine to remove a link node from the file system.
508 *
509 * @param parent_loc
510 * @param loc
511 * @return int
512 */
513
514int
515rtems_rfs_rtems_unlink (rtems_filesystem_location_info_t* parent_loc,
516                        rtems_filesystem_location_info_t* loc)
517{
518  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (parent_loc);
519  rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parent_loc);
520  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (loc);
521  uint32_t               doff = rtems_rfs_rtems_get_pathloc_doff (loc);
522  int                    rc;
523
524  rtems_rfs_rtems_lock (fs);
525 
526  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_UNLINK))
527    printf("rtems-rfs-rtems: unlink: parent:%" PRId32 " doff:%" PRIu32 " ino:%" PRId32 "\n",
528           parent, doff, ino);
529 
530  rc = rtems_rfs_unlink (fs, parent, ino, doff, rtems_rfs_unlink_dir_denied);
531  if (rc)
532  {
533    rtems_rfs_rtems_unlock (fs);
534    return rtems_rfs_rtems_error ("unlink: unlink inode", rc);
535  }
536 
537  rtems_rfs_rtems_unlock (fs);
538 
539  return 0;
540}
541
542/**
543 * The following verifies that and returns the type of node that the loc refers
544 * to.
545 *
546 * @param pathloc
547 * @return rtems_filesystem_node_types_t
548 */
549
550rtems_filesystem_node_types_t
551rtems_rfs_rtems_node_type (rtems_filesystem_location_info_t* pathloc)
552{
553  rtems_rfs_file_system*        fs = rtems_rfs_rtems_pathloc_dev (pathloc);
554  rtems_rfs_ino                 ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
555  rtems_filesystem_node_types_t type;
556  rtems_rfs_inode_handle        inode;
557  uint16_t                      mode;
558  int                           rc;
559
560  rtems_rfs_rtems_lock (fs);
561
562  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
563  if (rc > 0)
564  {
565    rtems_rfs_rtems_unlock (fs);
566    return rtems_rfs_rtems_error ("node_type: opening inode", rc);
567  }
568 
569  /*
570   * Do not return RTEMS_FILESYSTEM_HARD_LINK because this would result in an
571   * eval link which does not make sense in the case of the RFS file
572   * system. All directory entries are links to an inode. A link such as a HARD
573   * link is actually the normal path to a regular file, directory, device
574   * etc's inode. Links to inodes can be considered "the real" one, yet they
575   * are all links.
576   */
577  mode = rtems_rfs_inode_get_mode (&inode);
578  if (RTEMS_RFS_S_ISDIR (mode))
579    type = RTEMS_FILESYSTEM_DIRECTORY;
580  else if (RTEMS_RFS_S_ISLNK (mode))
581    type = RTEMS_FILESYSTEM_SYM_LINK;
582  else if (RTEMS_RFS_S_ISBLK (mode) || RTEMS_RFS_S_ISCHR (mode))
583    type = RTEMS_FILESYSTEM_DEVICE;
584  else
585    type = RTEMS_FILESYSTEM_MEMORY_FILE;
586
587  rc = rtems_rfs_inode_close (fs, &inode);
588  if (rc > 0)
589  {
590    rtems_rfs_rtems_unlock (fs);
591    return rtems_rfs_rtems_error ("node_type: closing inode", rc);
592  }
593 
594  rtems_rfs_rtems_unlock (fs);
595 
596  return type;
597}
598
599/**
600 * This routine is the implementation of the chown() system call for the
601 * RFS.
602 *
603 * @param pathloc
604 * @param owner
605 * @param group
606 * return int
607 */
608
609static int
610rtems_rfs_rtems_chown (rtems_filesystem_location_info_t *pathloc,
611                       uid_t                             owner,
612                       gid_t                             group)
613{
614  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
615  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
616  rtems_rfs_inode_handle inode;
617#if defined (RTEMS_POSIX_API)
618  uid_t                  uid;
619#endif
620  int                    rc;
621 
622  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_CHOWN))
623    printf ("rtems-rfs-rtems: chown: in: ino:%" PRId32 " uid:%d gid:%d\n",
624            ino, owner, group);
625 
626  rtems_rfs_rtems_lock (fs);
627 
628  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
629  if (rc > 0)
630  {
631    rtems_rfs_rtems_unlock (fs);
632    return rtems_rfs_rtems_error ("chown: opening inode", rc);
633  }
634 
635  /*
636   *  Verify I am the owner of the node or the super user.
637   */
638
639#if defined (RTEMS_POSIX_API)
640  uid = geteuid();
641
642  if ((uid != rtems_rfs_inode_get_uid (&inode)) && (uid != 0))
643  {
644    rtems_rfs_inode_close (fs, &inode);
645    rtems_rfs_rtems_unlock (fs);
646    return rtems_rfs_rtems_error ("chown: not able", EPERM);
647  }
648#endif
649
650  rtems_rfs_inode_set_uid_gid (&inode, owner, group);
651
652  rc = rtems_rfs_inode_close (fs, &inode);
653  if (rc)
654  {
655    rtems_rfs_rtems_unlock (fs);
656    return rtems_rfs_rtems_error ("chown: closing inode", rc);
657  }
658
659  rtems_rfs_rtems_unlock (fs);
660 
661  return 0;
662}
663
664/**
665 * This routine is the implementation of the utime() system call for the
666 * RFS.
667 *
668 * @param pathloc
669 * @param atime
670 * @param mtime
671 * return int
672 */
673
674int
675rtems_rfs_rtems_utime(rtems_filesystem_location_info_t* pathloc,
676                      time_t                            atime,
677                      time_t                            mtime)
678{
679  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
680  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
681  rtems_rfs_inode_handle inode;
682  int                    rc;
683
684  rtems_rfs_rtems_lock (fs);
685 
686  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
687  if (rc)
688  {
689    rtems_rfs_rtems_unlock (fs);
690    return rtems_rfs_rtems_error ("utime: read inode", rc);
691  }
692
693  rtems_rfs_inode_set_atime (&inode, atime);
694  rtems_rfs_inode_set_mtime (&inode, mtime);
695
696  rc = rtems_rfs_inode_close (fs, &inode);
697  if (rc)
698  {
699    rtems_rfs_rtems_unlock (fs);
700    return rtems_rfs_rtems_error ("utime: closing inode", rc);
701  }
702 
703  rtems_rfs_rtems_unlock (fs);
704 
705  return 0;
706}
707
708/**
709 * The following rouine creates a new symbolic link node under parent with the
710 * name given in name. The node is set to point to the node at to_loc.
711 *
712 * @param parent_loc
713 * @param link_name
714 * @param node_name
715 * return int
716 */
717
718int
719rtems_rfs_rtems_symlink (rtems_filesystem_location_info_t* parent_loc,
720                         const char*                       link_name,
721                         const char*                       node_name)
722{
723  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (parent_loc);
724  rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parent_loc);
725  uid_t                  uid;
726  gid_t                  gid;
727  int                    rc;
728
729#if defined(RTEMS_POSIX_API)
730  uid = geteuid ();
731  gid = getegid ();
732#else
733  uid = 0;
734  gid = 0;
735#endif
736
737  rtems_rfs_rtems_lock (fs);
738 
739  rc = rtems_rfs_symlink (fs, node_name, strlen (node_name),
740                          link_name, strlen (link_name),
741                          uid, gid, parent);
742  if (rc)
743  {
744    rtems_rfs_rtems_unlock (fs);
745    return rtems_rfs_rtems_error ("symlink: linking", rc);
746  }
747 
748  rtems_rfs_rtems_unlock (fs);
749 
750  return 0;
751}
752
753/**
754 * The following rouine puts the symblic links destination name into buf.
755 *
756 * @param loc
757 * @param buf
758 * @param bufsize
759 * @return int
760 */
761
762ssize_t
763rtems_rfs_rtems_readlink (rtems_filesystem_location_info_t* pathloc,
764                          char*                             buf,
765                          size_t                            bufsize)
766{
767  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (pathloc);
768  rtems_rfs_ino           ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
769  size_t                  length;
770  int                     rc;
771 
772  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_READLINK))
773    printf ("rtems-rfs-rtems: readlink: in: ino:%" PRId32 "\n", ino);
774 
775  rtems_rfs_rtems_lock (fs);
776 
777  rc = rtems_rfs_symlink_read (fs, ino, buf, bufsize, &length);
778  if (rc)
779  {
780    rtems_rfs_rtems_unlock (fs);
781    return rtems_rfs_rtems_error ("readlink: reading link", rc);
782  }
783
784  rtems_rfs_rtems_unlock (fs);
785
786  return (int) length;
787}
788
789/**
790 * File change mode routine.
791 *
792 * @param pathloc
793 * @param mode
794 * @return int
795 */
796int
797rtems_rfs_rtems_fchmod (rtems_filesystem_location_info_t* pathloc,
798                        mode_t                            mode)
799{
800  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (pathloc);
801  rtems_rfs_ino           ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
802  rtems_rfs_inode_handle  inode;
803  uint16_t                imode;
804#if defined (RTEMS_POSIX_API)
805  uid_t                   uid;
806#endif
807  int                     rc;
808
809  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FCHMOD))
810    printf ("rtems-rfs-rtems: fchmod: in: ino:%" PRId32 " mode:%06" PRIomode_t "\n",
811            ino, mode);
812 
813  rtems_rfs_rtems_lock (fs);
814 
815  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
816  if (rc)
817  {
818    rtems_rfs_rtems_unlock (fs);
819    return rtems_rfs_rtems_error ("fchmod: opening inode", rc);
820  }
821
822  imode = rtems_rfs_inode_get_mode (&inode);
823 
824  /*
825   *  Verify I am the owner of the node or the super user.
826   */
827#if defined (RTEMS_POSIX_API)
828  uid = geteuid();
829
830  if ((uid != rtems_rfs_inode_get_uid (&inode)) && (uid != 0))
831  {
832    rtems_rfs_inode_close (fs, &inode);
833    rtems_rfs_rtems_unlock (fs);
834    return rtems_rfs_rtems_error ("fchmod: not owner", EPERM);
835  }
836#endif
837
838  imode &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
839  imode |= mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
840
841  rtems_rfs_inode_set_mode (&inode, imode);
842 
843  rc = rtems_rfs_inode_close (fs, &inode);
844  if (rc > 0)
845  {
846    rtems_rfs_rtems_unlock (fs);
847    return rtems_rfs_rtems_error ("fchmod: closing inode", rc);
848  }
849 
850  rtems_rfs_rtems_unlock (fs);
851 
852  return 0;
853}
854
855/**
856 * The following routine does a stat on a node.
857 *
858 * @param pathloc
859 * @param buf
860 * @return int
861 */
862
863int
864rtems_rfs_rtems_stat (rtems_filesystem_location_info_t* pathloc,
865                      struct stat*                      buf)
866{
867  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (pathloc);
868  rtems_rfs_ino           ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
869  rtems_rfs_inode_handle  inode;
870  rtems_rfs_file_shared*  shared;
871  uint16_t                mode;
872  int                     rc;
873
874  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_STAT))
875    printf ("rtems-rfs-rtems: stat: in: ino:%" PRId32 "\n", ino);
876
877  rtems_rfs_rtems_lock (fs);
878 
879  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
880  if (rc)
881  {
882    rtems_rfs_rtems_unlock (fs);
883    return rtems_rfs_rtems_error ("stat: opening inode", rc);
884  }
885
886  mode = rtems_rfs_inode_get_mode (&inode);
887 
888  if (RTEMS_RFS_S_ISCHR (mode) || RTEMS_RFS_S_ISBLK (mode))
889  {
890    buf->st_rdev =
891      rtems_filesystem_make_dev_t (rtems_rfs_inode_get_block (&inode, 0),
892                                   rtems_rfs_inode_get_block (&inode, 1));
893  }
894 
895  buf->st_dev     = rtems_rfs_fs_device (fs);
896  buf->st_ino     = ino;
897  buf->st_mode    = rtems_rfs_rtems_mode (mode);
898  buf->st_nlink   = rtems_rfs_inode_get_links (&inode);
899  buf->st_uid     = rtems_rfs_inode_get_uid (&inode);
900  buf->st_gid     = rtems_rfs_inode_get_gid (&inode);
901
902  /*
903   * Need to check is the ino is an open file. If so we take the values from
904   * the open file rather than the inode.
905   */
906  shared = rtems_rfs_file_get_shared (fs, ino);
907
908  if (shared)
909  {
910    buf->st_atime   = rtems_rfs_file_shared_get_atime (shared);
911    buf->st_mtime   = rtems_rfs_file_shared_get_mtime (shared);
912    buf->st_ctime   = rtems_rfs_file_shared_get_ctime (shared);
913    buf->st_blocks  = rtems_rfs_file_shared_get_block_count (shared);
914
915    if (S_ISLNK (buf->st_mode))
916      buf->st_size = rtems_rfs_file_shared_get_block_offset (shared);
917    else
918      buf->st_size = rtems_rfs_file_shared_get_size (fs, shared);
919  }
920  else
921  {
922    buf->st_atime   = rtems_rfs_inode_get_atime (&inode);
923    buf->st_mtime   = rtems_rfs_inode_get_mtime (&inode);
924    buf->st_ctime   = rtems_rfs_inode_get_ctime (&inode);
925    buf->st_blocks  = rtems_rfs_inode_get_block_count (&inode);
926
927    if (S_ISLNK (buf->st_mode))
928      buf->st_size = rtems_rfs_inode_get_block_offset (&inode);
929    else
930      buf->st_size = rtems_rfs_inode_get_size (fs, &inode);
931  }
932 
933  buf->st_blksize = rtems_rfs_fs_block_size (fs);
934 
935  rc = rtems_rfs_inode_close (fs, &inode);
936  if (rc > 0)
937  {
938    rtems_rfs_rtems_unlock (fs);
939    return rtems_rfs_rtems_error ("stat: closing inode", rc);
940  }
941 
942  rtems_rfs_rtems_unlock (fs);
943  return 0;
944}
945
946/**
947 * Routine to create a node in the RFS file system.
948 *
949 * @param name
950 * @param mode
951 * @param dev
952 * @param pathloc
953 * @return int
954 */
955
956int
957rtems_rfs_rtems_mknod (const char                       *name,
958                       mode_t                            mode,
959                       dev_t                             dev,
960                       rtems_filesystem_location_info_t *pathloc)
961{
962  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (pathloc);
963  rtems_rfs_ino           parent = rtems_rfs_rtems_get_pathloc_ino (pathloc);
964  rtems_rfs_ino           ino;
965  rtems_rfs_inode_handle  inode;
966  uid_t                   uid;
967  gid_t                   gid;
968  int                     rc;
969
970#if defined(RTEMS_POSIX_API)
971  uid = geteuid ();
972  gid = getegid ();
973#else
974  uid = 0;
975  gid = 0;
976#endif
977
978  rtems_rfs_rtems_lock (fs);
979 
980  rc = rtems_rfs_inode_create (fs, parent, name, strlen (name),
981                               rtems_rfs_rtems_imode (mode),
982                               1, uid, gid, &ino);
983  if (rc > 0)
984  {
985    rtems_rfs_rtems_unlock (fs);
986    return rtems_rfs_rtems_error ("mknod: inode create", rc);
987  }
988
989  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
990  if (rc > 0)
991  {
992    rtems_rfs_rtems_unlock (fs);
993    return rtems_rfs_rtems_error ("mknod: inode open", rc);
994  }
995   
996  if (S_ISDIR(mode) || S_ISREG(mode))
997  {
998  }
999  else if (S_ISCHR (mode) || S_ISBLK (mode))
1000  {
1001    int major;
1002    int minor;
1003    rtems_filesystem_split_dev_t (dev, major, minor);
1004    rtems_rfs_inode_set_block (&inode, 0, major);
1005    rtems_rfs_inode_set_block (&inode, 1, minor);
1006  }
1007  else
1008  {
1009    rtems_rfs_inode_close (fs, &inode);
1010    rtems_rfs_rtems_unlock (fs);
1011    return rtems_rfs_rtems_error ("mknod: bad mode", EINVAL);
1012  }
1013
1014  rc = rtems_rfs_inode_close (fs, &inode);
1015  if (rc > 0)
1016  {
1017    rtems_rfs_rtems_unlock (fs);
1018    return rtems_rfs_rtems_error ("mknod: closing inode", rc);
1019  }
1020 
1021  rtems_rfs_rtems_unlock (fs);
1022  return 0;
1023}
1024
1025/**
1026 * Routine to remove a node from the RFS file system.
1027 *
1028 * @param parent_pathloc
1029 * @param pathloc
1030 * @return int
1031 */
1032int
1033rtems_rfs_rtems_rmnod (rtems_filesystem_location_info_t* parent_pathloc,
1034                       rtems_filesystem_location_info_t* pathloc)
1035{
1036  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
1037  rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parent_pathloc);
1038  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
1039  uint32_t               doff = rtems_rfs_rtems_get_pathloc_doff (pathloc);
1040  int                    rc;
1041
1042  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_RMNOD))
1043    printf ("rtems-rfs: rmnod: parent:%" PRId32 " doff:%" PRIu32 ", ino:%" PRId32 "\n",
1044            parent, doff, ino);
1045
1046  rtems_rfs_rtems_lock (fs);
1047 
1048  rc = rtems_rfs_unlink (fs, parent, ino, doff, rtems_rfs_unlink_dir_denied);
1049  if (rc)
1050  {
1051    rtems_rfs_rtems_unlock (fs);
1052    return rtems_rfs_rtems_error ("rmnod: unlinking", rc);
1053  }
1054
1055  rtems_rfs_rtems_unlock (fs);
1056  return 0;
1057}
1058
1059/**
1060 * The following routine does a sync on an inode node. Currently it flushes
1061 * everything related to this device.
1062 *
1063 * @param iop
1064 * @return int
1065 */
1066int
1067rtems_rfs_rtems_fdatasync (rtems_libio_t* iop)
1068{
1069  int rc;
1070 
1071  rc = rtems_rfs_buffer_sync (rtems_rfs_rtems_pathloc_dev (&iop->pathinfo));
1072  if (rc)
1073    return rtems_rfs_rtems_error ("fdatasync: sync", rc);
1074
1075  return 0;
1076}
1077
1078/**
1079 * Rename the node.
1080 *
1081 * @param old_parent_loc The old name's parent location.
1082 * @param old_loc The old name's location.
1083 * @param new_parent_loc The new name's parent location.
1084 * @param new_name The new name.
1085 * @return int
1086 */
1087int
1088rtems_rfs_rtems_rename(rtems_filesystem_location_info_t* old_parent_loc,
1089                       rtems_filesystem_location_info_t* old_loc,
1090                       rtems_filesystem_location_info_t* new_parent_loc,
1091                       const char*                       new_name)
1092{
1093  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (old_loc);
1094  rtems_rfs_ino           old_parent;
1095  rtems_rfs_ino           new_parent;
1096  rtems_rfs_ino           ino;
1097  uint32_t                doff;
1098  int                     rc;
1099 
1100  old_parent = rtems_rfs_rtems_get_pathloc_ino (old_parent_loc);
1101  new_parent = rtems_rfs_rtems_get_pathloc_ino (new_parent_loc);
1102
1103  ino  = rtems_rfs_rtems_get_pathloc_ino (old_loc);
1104  doff = rtems_rfs_rtems_get_pathloc_doff (old_loc);
1105
1106  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_RENAME))
1107    printf ("rtems-rfs: rename: ino:%" PRId32 " doff:%" PRIu32 ", new parent:%" PRId32 " new name:%s\n",
1108            ino, doff, new_parent, new_name);
1109
1110  rtems_rfs_rtems_lock (fs);
1111
1112  /*
1113   * Link to the inode before unlinking so the inode is not erased when
1114   * unlinked.
1115   */
1116  rc = rtems_rfs_link (fs, new_name, strlen (new_name), new_parent, ino, true);
1117  if (rc)
1118  {
1119    rtems_rfs_rtems_unlock (fs);
1120    return rtems_rfs_rtems_error ("rename: linking", rc);
1121  }
1122 
1123  /*
1124   * Unlink all inodes even directories with the dir option as false because a
1125   * directory may not be empty.
1126   */
1127  rc = rtems_rfs_unlink (fs, old_parent, ino, doff,
1128                         rtems_rfs_unlink_dir_allowed);
1129  if (rc)
1130  {
1131    rtems_rfs_rtems_unlock (fs);
1132    return rtems_rfs_rtems_error ("rename: unlinking", rc);
1133  }
1134
1135  rtems_rfs_rtems_unlock (fs);
1136
1137  return 0;
1138}
1139
1140/**
1141 * Return the file system stat data.
1142 *
1143 * @param pathloc
1144 * @param sb
1145 * @return int
1146 */
1147int
1148rtems_rfs_rtems_statvfs (rtems_filesystem_location_info_t* pathloc,
1149                         struct statvfs*                   sb)
1150{
1151  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
1152  size_t                 blocks;
1153  size_t                 inodes;
1154
1155  rtems_rfs_group_usage (fs, &blocks, &inodes);
1156 
1157  sb->f_bsize   = rtems_rfs_fs_block_size (fs);
1158  sb->f_frsize  = rtems_rfs_fs_media_block_size (fs);
1159  sb->f_blocks  = rtems_rfs_fs_media_blocks (fs);
1160  sb->f_bfree   = rtems_rfs_fs_blocks (fs) - blocks;
1161  sb->f_bavail  = sb->f_bfree;
1162  sb->f_files   = rtems_rfs_fs_inodes (fs);
1163  sb->f_ffree   = rtems_rfs_fs_inodes (fs) - inodes;
1164  sb->f_favail  = sb->f_ffree;
1165  sb->f_fsid    = RTEMS_RFS_SB_MAGIC;
1166  sb->f_flag    = rtems_rfs_fs_flags (fs);
1167  sb->f_namemax = rtems_rfs_fs_max_name (fs);
1168 
1169  return 0;
1170}
1171
1172/**
1173 *  Handler table for RFS link nodes
1174 */
1175const rtems_filesystem_file_handlers_r rtems_rfs_rtems_link_handlers =
1176{
1177  .open_h      = rtems_filesystem_default_open,
1178  .close_h     = rtems_filesystem_default_close,
1179  .read_h      = rtems_filesystem_default_read,
1180  .write_h     = rtems_filesystem_default_write,
1181  .ioctl_h     = rtems_filesystem_default_ioctl,
1182  .lseek_h     = rtems_filesystem_default_lseek,
1183  .fstat_h     = rtems_rfs_rtems_stat,
1184  .fchmod_h    = rtems_filesystem_default_fchmod,
1185  .ftruncate_h = rtems_filesystem_default_ftruncate,
1186  .fpathconf_h = rtems_filesystem_default_fpathconf,
1187  .fsync_h     = rtems_filesystem_default_fsync,
1188  .fdatasync_h = rtems_filesystem_default_fdatasync,
1189  .fcntl_h     = rtems_filesystem_default_fcntl,
1190  .rmnod_h     = rtems_rfs_rtems_rmnod
1191};
1192
1193/**
1194 * Forward decl for the ops table.
1195 */
1196
1197int rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t *mt_entry,
1198                                const void                           *data);
1199int rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t *mt_entry);
1200
1201/**
1202 * RFS file system operations table.
1203 */
1204const rtems_filesystem_operations_table rtems_rfs_ops =
1205{
1206  .evalpath_h     = rtems_rfs_rtems_eval_path,
1207  .evalformake_h  = rtems_rfs_rtems_eval_for_make,
1208  .link_h         = rtems_rfs_rtems_link,
1209  .unlink_h       = rtems_rfs_rtems_unlink,
1210  .node_type_h    = rtems_rfs_rtems_node_type,
1211  .mknod_h        = rtems_rfs_rtems_mknod,
1212  .chown_h        = rtems_rfs_rtems_chown,
1213  .freenod_h      = rtems_filesystem_default_freenode,
1214  .mount_h        = rtems_filesystem_default_mount,
1215  .fsmount_me_h   = rtems_rfs_rtems_initialise,
1216  .unmount_h      = rtems_filesystem_default_unmount,
1217  .fsunmount_me_h = rtems_rfs_rtems_shutdown,
1218  .utime_h        = rtems_rfs_rtems_utime,
1219  .eval_link_h    = rtems_filesystem_default_evaluate_link, /* never called cause we lie in the node type */
1220  .symlink_h      = rtems_rfs_rtems_symlink,
1221  .readlink_h     = rtems_rfs_rtems_readlink,
1222  .rename_h       = rtems_rfs_rtems_rename,
1223  .statvfs_h      = rtems_rfs_rtems_statvfs
1224};
1225
1226/**
1227 * Open the file system.
1228 */
1229
1230int
1231rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t* mt_entry,
1232                            const void*                           data)
1233{
1234  rtems_rfs_rtems_private* rtems;
1235  rtems_rfs_file_system*   fs;
1236  int                      rc;
1237
1238  rtems = malloc (sizeof (rtems_rfs_rtems_private));
1239  if (!rtems)
1240    return rtems_rfs_rtems_error ("initialise: local data", ENOMEM);
1241
1242  memset (rtems, 0, sizeof (rtems_rfs_rtems_private));
1243 
1244  rc = rtems_rfs_mutex_create (&rtems->access);
1245  if (rc > 0)
1246  {
1247    free (rtems);
1248    return rtems_rfs_rtems_error ("initialise: cannot create mutex", rc);
1249  }
1250
1251  rc = rtems_rfs_mutex_lock (&rtems->access);
1252  if (rc > 0)
1253  {
1254    rtems_rfs_mutex_destroy (&rtems->access);
1255    free (rtems);
1256    return rtems_rfs_rtems_error ("initialise: cannot lock access  mutex", rc);
1257  }
1258 
1259  rc = rtems_rfs_fs_open (mt_entry->dev, rtems, 0, &fs);
1260  if (rc)
1261  {
1262    free (rtems);
1263    return rtems_rfs_rtems_error ("initialise: open", rc);
1264  }
1265 
1266  mt_entry->fs_info = fs;
1267
1268  mt_entry->mt_fs_root.node_access = (void*) RTEMS_RFS_ROOT_INO;
1269  mt_entry->mt_fs_root.handlers    = &rtems_rfs_rtems_dir_handlers;
1270  mt_entry->mt_fs_root.ops         = &rtems_rfs_ops;
1271
1272  rtems_rfs_rtems_unlock (fs);
1273 
1274  return 0;
1275}
1276
1277/**
1278 * Shutdown the file system.
1279 */
1280int
1281rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry)
1282{
1283  rtems_rfs_file_system*   fs = mt_entry->fs_info;
1284  rtems_rfs_rtems_private* rtems;
1285  int                      rc;
1286
1287  rtems = rtems_rfs_fs_user (fs);
1288 
1289  rc = rtems_rfs_fs_close(fs);
1290 
1291  rtems_rfs_mutex_destroy (&rtems->access);
1292  free (rtems);
1293 
1294  return rtems_rfs_rtems_error ("shutdown: close", rc);
1295}
Note: See TracBrowser for help on using the repository browser.