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

4.115
Last change on this file since 3b7c123 was 3b7c123, checked in by Sebastian Huber <sebastian.huber@…>, on 03/13/12 at 10:33:51

Filesystem: Reference counting for locations

o A new data structure rtems_filesystem_global_location_t was

introduced to be used for

o the mount point location in the mount table entry,
o the file system root location in the mount table entry,
o the root directory location in the user environment, and
o the current directory location in the user environment.

During the path evaluation global start locations are obtained to
ensure that the current file system instance will be not unmounted in
the meantime.

o The user environment uses now reference counting and is protected

from concurrent access.

o The path evaluation process was completely rewritten and simplified.

The IMFS, RFS, NFS, and DOSFS use now a generic path evaluation
method. Recursive calls in the path evaluation have been replaced
with iteration to avoid stack overflows. Only the evaluation of
symbolic links is recursive. No dynamic memory allocations and
intermediate buffers are used in the high level path evaluation. No
global locks are held during the file system instance specific path
evaluation process.

o Recursive symbolic link evaluation is now limited by

RTEMS_FILESYSTEM_SYMLOOP_MAX. Applications can retrieve this value
via sysconf().

o The device file system (devFS) uses now no global variables and

allocation from the workspace. Node names are allocated from the
heap.

o The upper layer lseek() performs now some parameter checks.
o The upper layer ftruncate() performs now some parameter checks.
o unmask() is now restricted to the RWX flags and protected from

concurrent access.

o The fchmod_h and rmnod_h file system node handlers are now a file

system operation.

o The unlink_h operation has been removed. All nodes are now destroyed

with the rmnod_h operation.

o New lock_h, unlock_h, clonenod_h, and are_nodes_equal_h file system

operations.

o The path evaluation and file system operations are now protected by

per file system instance lock and unlock operations.

o Fix and test file descriptor duplicate in fcntl().
o New test fstests/fsnofs01.

  • Property mode set to 100644
File size: 26.7 KB
Line 
1/*
2 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
3 *
4 *  Modifications to support reference counting in the file system are
5 *  Copyright (c) 2012 embedded brains GmbH.
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 *  $Id$
12 */
13/**
14 * @file
15 *
16 * @ingroup rtems-rfs
17 *
18 * RTEMS File System Interface for RTEMS.
19 */
20
21#if HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include <inttypes.h>
26#include <stdlib.h>
27
28#if SIZEOF_MODE_T == 8
29#define PRIomode_t PRIo64
30#elif SIZEOF_MODE_T == 4
31#define PRIomode_t PRIo32
32#else
33#error "unsupport size of mode_t"
34#endif
35
36#include <rtems/rfs/rtems-rfs-file.h>
37#include <rtems/rfs/rtems-rfs-dir.h>
38#include <rtems/rfs/rtems-rfs-link.h>
39#include "rtems-rfs-rtems.h"
40
41static bool
42rtems_rfs_rtems_eval_perms (rtems_filesystem_eval_path_context_t *ctx,
43                            int eval_flags,
44                            rtems_rfs_inode_handle* inode)
45{
46  return rtems_filesystem_eval_path_check_access(
47    ctx,
48    eval_flags,
49    rtems_rfs_inode_get_mode (inode),
50    rtems_rfs_inode_get_uid (inode),
51    rtems_rfs_inode_get_gid (inode)
52  );
53}
54
55static rtems_filesystem_node_types_t
56rtems_rfs_rtems_node_type_by_inode (rtems_rfs_inode_handle* inode)
57{
58  /*
59   * Do not return RTEMS_FILESYSTEM_HARD_LINK because this would result in an
60   * eval link which does not make sense in the case of the RFS file
61   * system. All directory entries are links to an inode. A link such as a HARD
62   * link is actually the normal path to a regular file, directory, device
63   * etc's inode. Links to inodes can be considered "the real" one, yet they
64   * are all links.
65   */
66  uint16_t mode = rtems_rfs_inode_get_mode (inode);
67  if (RTEMS_RFS_S_ISDIR (mode))
68    return RTEMS_FILESYSTEM_DIRECTORY;
69  else if (RTEMS_RFS_S_ISLNK (mode))
70    return RTEMS_FILESYSTEM_SYM_LINK;
71  else if (RTEMS_RFS_S_ISBLK (mode) || RTEMS_RFS_S_ISCHR (mode))
72    return RTEMS_FILESYSTEM_DEVICE;
73  else
74    return RTEMS_FILESYSTEM_MEMORY_FILE;
75}
76
77static void
78rtems_rfs_rtems_lock_by_mt_entry (rtems_filesystem_mount_table_entry_t *mt_entry)
79{
80  rtems_rfs_file_system* fs = mt_entry->fs_info;
81
82  rtems_rfs_rtems_lock (fs);
83}
84
85static void
86rtems_rfs_rtems_unlock_by_mt_entry (rtems_filesystem_mount_table_entry_t *mt_entry)
87{
88  rtems_rfs_file_system* fs = mt_entry->fs_info;
89
90  rtems_rfs_rtems_unlock (fs);
91}
92
93static bool
94rtems_rfs_rtems_is_directory(
95  rtems_filesystem_eval_path_context_t *ctx,
96  void *arg
97)
98{
99  rtems_rfs_inode_handle* inode = arg;
100
101  return rtems_rfs_rtems_node_type_by_inode (inode)
102    == RTEMS_FILESYSTEM_DIRECTORY;
103}
104
105static void rtems_rfs_rtems_follow_link(
106  rtems_filesystem_eval_path_context_t* ctx,
107  rtems_rfs_file_system* fs,
108  rtems_rfs_ino ino
109)
110{
111  size_t len = MAXPATHLEN;
112  char *link = malloc(len + 1);
113
114  if (link != NULL) {
115    int rc = rtems_rfs_symlink_read (fs, ino, link, len, &len);
116
117    if (rc == 0) {
118      rtems_filesystem_eval_path_recursive (ctx, link, len);
119    } else {
120      rtems_filesystem_eval_path_error (ctx, 0);
121    }
122
123    free(link);
124  } else {
125    rtems_filesystem_eval_path_error (ctx, ENOMEM);
126  }
127}
128
129static rtems_filesystem_eval_path_generic_status
130rtems_rfs_rtems_eval_token(
131  rtems_filesystem_eval_path_context_t *ctx,
132  void *arg,
133  const char *token,
134  size_t tokenlen
135)
136{
137  rtems_filesystem_eval_path_generic_status status =
138    RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
139  rtems_rfs_inode_handle* inode = arg;
140  bool access_ok = rtems_rfs_rtems_eval_perms (ctx, RTEMS_LIBIO_PERMS_SEARCH, inode);
141
142  if (access_ok) {
143    if (rtems_filesystem_is_current_directory (token, tokenlen)) {
144      rtems_filesystem_eval_path_clear_token (ctx);
145    } else {
146      rtems_filesystem_location_info_t *currentloc =
147        rtems_filesystem_eval_path_get_currentloc( ctx );
148      rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (currentloc);
149      rtems_rfs_ino entry_ino;
150      uint32_t entry_doff;
151      int rc = rtems_rfs_dir_lookup_ino (
152        fs,
153        inode,
154        token,
155        tokenlen,
156        &entry_ino,
157        &entry_doff
158      );
159
160      if (rc == 0) {
161        rc = rtems_rfs_inode_close (fs, inode);
162        if (rc == 0) {
163          rc = rtems_rfs_inode_open (fs, entry_ino, inode, true);
164        }
165
166        if (rc != 0) {
167          /*
168           * This prevents the rtems_rfs_inode_close() from doing something in
169           * rtems_rfs_rtems_eval_path().
170           */
171          memset (inode, 0, sizeof(*inode));
172        }
173      } else {
174        status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
175        rc = -1;
176      }
177
178      if (rc == 0) {
179        bool is_sym_link = rtems_rfs_rtems_node_type_by_inode (inode)
180          == RTEMS_FILESYSTEM_SYM_LINK;
181        int eval_flags = rtems_filesystem_eval_path_get_flags (ctx);
182        bool follow_sym_link = (eval_flags & RTEMS_LIBIO_FOLLOW_SYM_LINK) != 0;
183        bool terminal = !rtems_filesystem_eval_path_has_path (ctx);
184
185        rtems_filesystem_eval_path_clear_token (ctx);
186
187        if (is_sym_link && (follow_sym_link || !terminal)) {
188          rtems_rfs_rtems_follow_link (ctx, fs, entry_ino);
189        } else {
190          rc = rtems_rfs_rtems_set_handlers (currentloc, inode) ? 0 : EIO;
191          if (rc == 0) {
192            rtems_rfs_rtems_set_pathloc_ino (currentloc, entry_ino);
193            rtems_rfs_rtems_set_pathloc_doff (currentloc, entry_doff);
194
195            if (!terminal) {
196              status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
197            }
198          } else {
199            rtems_filesystem_eval_path_error (
200              ctx,
201              rtems_rfs_rtems_error ("eval_path: set handlers", rc)
202            );
203          }
204        }
205      }
206    }
207  }
208
209  return status;
210}
211
212static const rtems_filesystem_eval_path_generic_config
213rtems_rfs_rtems_eval_config = {
214  .is_directory = rtems_rfs_rtems_is_directory,
215  .eval_token = rtems_rfs_rtems_eval_token
216};
217
218static void
219rtems_rfs_rtems_eval_path (rtems_filesystem_eval_path_context_t *ctx)
220{
221  rtems_filesystem_location_info_t *currentloc =
222    rtems_filesystem_eval_path_get_currentloc (ctx);
223  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (currentloc);
224  rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (currentloc);
225  rtems_rfs_inode_handle inode;
226  int rc;
227
228  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
229  if (rc == 0) {
230    rtems_filesystem_eval_path_generic (
231      ctx,
232      &inode,
233      &rtems_rfs_rtems_eval_config
234    );
235    rc = rtems_rfs_inode_close (fs, &inode);
236    if (rc != 0) {
237      rtems_filesystem_eval_path_error (
238        ctx,
239        rtems_rfs_rtems_error ("eval_path: closing inode", rc)
240      );
241    }
242  } else {
243    rtems_filesystem_eval_path_error (
244      ctx,
245      rtems_rfs_rtems_error ("eval_path: opening inode", rc)
246    );
247  }
248}
249
250/**
251 * The following rouine creates a new link node under parent with the name
252 * given in name. The link node is set to point to the node at targetloc.
253 */
254static int
255rtems_rfs_rtems_link (const rtems_filesystem_location_info_t *parentloc,
256                      const rtems_filesystem_location_info_t *targetloc,
257                      const char *name,
258                      size_t namelen)
259{
260  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (targetloc);
261  rtems_rfs_ino          target = rtems_rfs_rtems_get_pathloc_ino (targetloc);
262  rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parentloc);
263  int                    rc;
264
265  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_LINK))
266    printf ("rtems-rfs-rtems: link: in: parent:%" PRId32 " target:%" PRId32 "\n",
267            parent, target);
268
269  rc = rtems_rfs_link (fs, name, namelen, parent, target, false);
270  if (rc)
271  {
272    return rtems_rfs_rtems_error ("link: linking", rc);
273        }
274
275
276        return 0;
277}
278
279/**
280 * The following verifies that and returns the type of node that the loc refers
281 * to.
282 *
283 * @param pathloc
284 * @return rtems_filesystem_node_types_t
285 */
286
287static rtems_filesystem_node_types_t
288rtems_rfs_rtems_node_type (const rtems_filesystem_location_info_t* pathloc)
289{
290  rtems_rfs_file_system*        fs = rtems_rfs_rtems_pathloc_dev (pathloc);
291  rtems_rfs_ino                 ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
292  rtems_filesystem_node_types_t type;
293  rtems_rfs_inode_handle        inode;
294  int                           rc;
295
296  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
297  if (rc > 0)
298  {
299    return rtems_rfs_rtems_error ("node_type: opening inode", rc);
300  }
301
302  type = rtems_rfs_rtems_node_type_by_inode (&inode);
303
304  rc = rtems_rfs_inode_close (fs, &inode);
305  if (rc > 0)
306  {
307    return rtems_rfs_rtems_error ("node_type: closing inode", rc);
308  }
309
310  return type;
311}
312
313/**
314 * This routine is the implementation of the chown() system call for the
315 * RFS.
316 *
317 * @param pathloc
318 * @param owner
319 * @param group
320 * return int
321 */
322
323static int
324rtems_rfs_rtems_chown (const rtems_filesystem_location_info_t *pathloc,
325                       uid_t                                   owner,
326                       gid_t                                   group)
327{
328  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
329  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
330  rtems_rfs_inode_handle inode;
331#if defined (RTEMS_POSIX_API)
332  uid_t                  uid;
333#endif
334  int                    rc;
335
336  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_CHOWN))
337    printf ("rtems-rfs-rtems: chown: in: ino:%" PRId32 " uid:%d gid:%d\n",
338            ino, owner, group);
339
340  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
341  if (rc > 0)
342  {
343    return rtems_rfs_rtems_error ("chown: opening inode", rc);
344  }
345
346  /*
347   *  Verify I am the owner of the node or the super user.
348   */
349
350#if defined (RTEMS_POSIX_API)
351  uid = geteuid();
352
353  if ((uid != rtems_rfs_inode_get_uid (&inode)) && (uid != 0))
354  {
355    rtems_rfs_inode_close (fs, &inode);
356    return rtems_rfs_rtems_error ("chown: not able", EPERM);
357  }
358#endif
359
360  rtems_rfs_inode_set_uid_gid (&inode, owner, group);
361
362  rc = rtems_rfs_inode_close (fs, &inode);
363  if (rc)
364  {
365    return rtems_rfs_rtems_error ("chown: closing inode", rc);
366  }
367
368  return 0;
369}
370
371/**
372 * This routine is the implementation of the utime() system call for the
373 * RFS.
374 *
375 * @param pathloc
376 * @param atime
377 * @param mtime
378 * return int
379 */
380
381static int
382rtems_rfs_rtems_utime(const rtems_filesystem_location_info_t* pathloc,
383                      time_t                                  atime,
384                      time_t                                  mtime)
385{
386  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
387  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
388  rtems_rfs_inode_handle inode;
389  int                    rc;
390
391  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
392  if (rc)
393  {
394    return rtems_rfs_rtems_error ("utime: read inode", rc);
395  }
396
397  rtems_rfs_inode_set_atime (&inode, atime);
398  rtems_rfs_inode_set_mtime (&inode, mtime);
399
400  rc = rtems_rfs_inode_close (fs, &inode);
401  if (rc)
402  {
403    return rtems_rfs_rtems_error ("utime: closing inode", rc);
404  }
405
406  return 0;
407}
408
409/**
410 * The following routine creates a new symbolic link node under parent with the
411 * name given in node_name.
412 */
413
414static int
415rtems_rfs_rtems_symlink (const rtems_filesystem_location_info_t* parent_loc,
416                         const char*                             node_name,
417                         size_t                                  node_name_len,
418                         const char*                             target)
419{
420  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (parent_loc);
421  rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parent_loc);
422  int                    rc;
423
424  rc = rtems_rfs_symlink (fs, node_name, node_name_len,
425                          target, strlen (target),
426                          geteuid(), getegid(), parent);
427  if (rc)
428  {
429    return rtems_rfs_rtems_error ("symlink: linking", rc);
430  }
431
432  return 0;
433}
434
435/**
436 * The following rouine puts the symblic links destination name into buf.
437 */
438
439static ssize_t
440rtems_rfs_rtems_readlink (const rtems_filesystem_location_info_t* pathloc,
441                          char*                                   buf,
442                          size_t                                  bufsize)
443{
444  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (pathloc);
445  rtems_rfs_ino           ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
446  size_t                  length;
447  int                     rc;
448
449  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_READLINK))
450    printf ("rtems-rfs-rtems: readlink: in: ino:%" PRId32 "\n", ino);
451
452  rc = rtems_rfs_symlink_read (fs, ino, buf, bufsize, &length);
453  if (rc)
454  {
455    return rtems_rfs_rtems_error ("readlink: reading link", rc);
456  }
457
458  return (ssize_t) length;
459}
460
461static int
462rtems_rfs_rtems_fchmod (const rtems_filesystem_location_info_t* pathloc,
463                        mode_t                                  mode)
464{
465  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (pathloc);
466  rtems_rfs_ino           ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
467  rtems_rfs_inode_handle  inode;
468  uint16_t                imode;
469#if defined (RTEMS_POSIX_API)
470  uid_t                   uid;
471#endif
472  int                     rc;
473
474  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FCHMOD))
475    printf ("rtems-rfs-rtems: fchmod: in: ino:%" PRId32 " mode:%06" PRIomode_t "\n",
476            ino, mode);
477
478  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
479  if (rc)
480  {
481    return rtems_rfs_rtems_error ("fchmod: opening inode", rc);
482  }
483
484  imode = rtems_rfs_inode_get_mode (&inode);
485
486  /*
487   *  Verify I am the owner of the node or the super user.
488   */
489#if defined (RTEMS_POSIX_API)
490  uid = geteuid();
491
492  if ((uid != rtems_rfs_inode_get_uid (&inode)) && (uid != 0))
493  {
494    rtems_rfs_inode_close (fs, &inode);
495    return rtems_rfs_rtems_error ("fchmod: checking uid", EPERM);
496  }
497#endif
498
499  imode &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
500  imode |= mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
501
502  rtems_rfs_inode_set_mode (&inode, imode);
503
504  rc = rtems_rfs_inode_close (fs, &inode);
505  if (rc > 0)
506  {
507    return rtems_rfs_rtems_error ("fchmod: closing inode", rc);
508  }
509
510  return 0;
511}
512
513int
514rtems_rfs_rtems_fstat (const rtems_filesystem_location_info_t* pathloc,
515                       struct stat*                            buf)
516{
517  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
518  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
519  rtems_rfs_inode_handle inode;
520  rtems_rfs_file_shared* shared;
521  uint16_t               mode;
522  int                    rc;
523
524  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_STAT))
525    printf ("rtems-rfs-rtems: stat: in: ino:%" PRId32 "\n", ino);
526
527  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
528  if (rc)
529  {
530    return rtems_rfs_rtems_error ("stat: opening inode", rc);
531  }
532
533  mode = rtems_rfs_inode_get_mode (&inode);
534
535  if (RTEMS_RFS_S_ISCHR (mode) || RTEMS_RFS_S_ISBLK (mode))
536  {
537    buf->st_rdev =
538      rtems_filesystem_make_dev_t (rtems_rfs_inode_get_block (&inode, 0),
539                                   rtems_rfs_inode_get_block (&inode, 1));
540  }
541
542  buf->st_dev     = rtems_rfs_fs_device (fs);
543  buf->st_ino     = rtems_rfs_inode_ino (&inode);
544  buf->st_mode    = rtems_rfs_rtems_mode (mode);
545  buf->st_nlink   = rtems_rfs_inode_get_links (&inode);
546  buf->st_uid     = rtems_rfs_inode_get_uid (&inode);
547  buf->st_gid     = rtems_rfs_inode_get_gid (&inode);
548
549  /*
550   * Need to check is the ino is an open file. If so we take the values from
551   * the open file rather than the inode.
552   */
553  shared = rtems_rfs_file_get_shared (fs, rtems_rfs_inode_ino (&inode));
554
555  if (shared)
556  {
557    buf->st_atime   = rtems_rfs_file_shared_get_atime (shared);
558    buf->st_mtime   = rtems_rfs_file_shared_get_mtime (shared);
559    buf->st_ctime   = rtems_rfs_file_shared_get_ctime (shared);
560    buf->st_blocks  = rtems_rfs_file_shared_get_block_count (shared);
561
562    if (S_ISLNK (buf->st_mode))
563      buf->st_size = rtems_rfs_file_shared_get_block_offset (shared);
564    else
565      buf->st_size = rtems_rfs_file_shared_get_size (fs, shared);
566  }
567  else
568  {
569    buf->st_atime   = rtems_rfs_inode_get_atime (&inode);
570    buf->st_mtime   = rtems_rfs_inode_get_mtime (&inode);
571    buf->st_ctime   = rtems_rfs_inode_get_ctime (&inode);
572    buf->st_blocks  = rtems_rfs_inode_get_block_count (&inode);
573
574    if (S_ISLNK (buf->st_mode))
575      buf->st_size = rtems_rfs_inode_get_block_offset (&inode);
576    else
577      buf->st_size = rtems_rfs_inode_get_size (fs, &inode);
578  }
579
580  buf->st_blksize = rtems_rfs_fs_block_size (fs);
581
582  rc = rtems_rfs_inode_close (fs, &inode);
583  if (rc > 0)
584  {
585    return rtems_rfs_rtems_error ("stat: closing inode", rc);
586  }
587
588  return 0;
589}
590
591/**
592 * Routine to create a node in the RFS file system.
593 */
594
595static int
596rtems_rfs_rtems_mknod (const rtems_filesystem_location_info_t *parentloc,
597                       const char                             *name,
598                       size_t                                  namelen,
599                       mode_t                                  mode,
600                       dev_t                                   dev)
601{
602  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (parentloc);
603  rtems_rfs_ino           parent = rtems_rfs_rtems_get_pathloc_ino (parentloc);
604  rtems_rfs_ino           ino;
605  rtems_rfs_inode_handle  inode;
606  uid_t                   uid;
607  gid_t                   gid;
608  int                     rc;
609
610#if defined(RTEMS_POSIX_API)
611  uid = geteuid ();
612  gid = getegid ();
613#else
614  uid = 0;
615  gid = 0;
616#endif
617
618  rc = rtems_rfs_inode_create (fs, parent, name, namelen,
619                               rtems_rfs_rtems_imode (mode),
620                               1, uid, gid, &ino);
621  if (rc > 0)
622  {
623    return rtems_rfs_rtems_error ("mknod: inode create", rc);
624  }
625
626  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
627  if (rc > 0)
628  {
629    return rtems_rfs_rtems_error ("mknod: inode open", rc);
630  }
631
632  if (S_ISDIR(mode) || S_ISREG(mode))
633  {
634  }
635  else if (S_ISCHR (mode) || S_ISBLK (mode))
636  {
637    int major;
638    int minor;
639    rtems_filesystem_split_dev_t (dev, major, minor);
640    rtems_rfs_inode_set_block (&inode, 0, major);
641    rtems_rfs_inode_set_block (&inode, 1, minor);
642  }
643  else
644  {
645    rtems_rfs_inode_close (fs, &inode);
646    return rtems_rfs_rtems_error ("mknod: bad mode", EINVAL);
647  }
648
649  rc = rtems_rfs_inode_close (fs, &inode);
650  if (rc > 0)
651  {
652    return rtems_rfs_rtems_error ("mknod: closing inode", rc);
653  }
654
655  return 0;
656}
657
658/**
659 * Routine to remove a node from the RFS file system.
660 *
661 * @param parent_pathloc
662 * @param pathloc
663 * @return int
664 */
665int
666rtems_rfs_rtems_rmnod (const rtems_filesystem_location_info_t* parent_pathloc,
667                       const rtems_filesystem_location_info_t* pathloc)
668{
669  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
670  rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parent_pathloc);
671  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
672  uint32_t               doff = rtems_rfs_rtems_get_pathloc_doff (pathloc);
673  int                    rc;
674
675  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_RMNOD))
676    printf ("rtems-rfs: rmnod: parent:%" PRId32 " doff:%" PRIu32 ", ino:%" PRId32 "\n",
677            parent, doff, ino);
678
679  if (ino == RTEMS_RFS_ROOT_INO)
680    return rtems_rfs_rtems_error ("rmnod: root inode", EBUSY);
681
682  rc = rtems_rfs_unlink (fs, parent, ino, doff, rtems_rfs_unlink_dir_if_empty);
683  if (rc)
684  {
685    return rtems_rfs_rtems_error ("rmnod: unlinking", rc);
686  }
687
688  return 0;
689}
690
691/**
692 * The following routine does a sync on an inode node. Currently it flushes
693 * everything related to this device.
694 *
695 * @param iop
696 * @return int
697 */
698int
699rtems_rfs_rtems_fdatasync (rtems_libio_t* iop)
700{
701  int rc;
702
703  rc = rtems_rfs_buffer_sync (rtems_rfs_rtems_pathloc_dev (&iop->pathinfo));
704  if (rc)
705    return rtems_rfs_rtems_error ("fdatasync: sync", rc);
706
707  return 0;
708}
709
710/**
711 * Rename the node.
712 */
713static int
714rtems_rfs_rtems_rename(const rtems_filesystem_location_info_t* old_parent_loc,
715                       const rtems_filesystem_location_info_t* old_loc,
716                       const rtems_filesystem_location_info_t* new_parent_loc,
717                       const char*                             new_name,
718                       size_t                                  new_name_len)
719{
720  rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (old_loc);
721  rtems_rfs_ino           old_parent;
722  rtems_rfs_ino           new_parent;
723  rtems_rfs_ino           ino;
724  uint32_t                doff;
725  int                     rc;
726
727  old_parent = rtems_rfs_rtems_get_pathloc_ino (old_parent_loc);
728  new_parent = rtems_rfs_rtems_get_pathloc_ino (new_parent_loc);
729
730  ino  = rtems_rfs_rtems_get_pathloc_ino (old_loc);
731  doff = rtems_rfs_rtems_get_pathloc_doff (old_loc);
732
733  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_RENAME))
734    printf ("rtems-rfs: rename: ino:%" PRId32 " doff:%" PRIu32 ", new parent:%" PRId32 "\n",
735            ino, doff, new_parent);
736
737  /*
738   * Link to the inode before unlinking so the inode is not erased when
739   * unlinked.
740   */
741  rc = rtems_rfs_link (fs, new_name, new_name_len, new_parent, ino, true);
742  if (rc)
743  {
744    return rtems_rfs_rtems_error ("rename: linking", rc);
745  }
746
747  /*
748   * Unlink all inodes even directories with the dir option as false because a
749   * directory may not be empty.
750   */
751  rc = rtems_rfs_unlink (fs, old_parent, ino, doff,
752                         rtems_rfs_unlink_dir_allowed);
753  if (rc)
754  {
755    return rtems_rfs_rtems_error ("rename: unlinking", rc);
756  }
757
758  return 0;
759}
760
761/**
762 * Return the file system stat data.
763 *
764 * @param pathloc
765 * @param sb
766 * @return int
767 */
768static int
769rtems_rfs_rtems_statvfs (const rtems_filesystem_location_info_t* pathloc,
770                         struct statvfs*                         sb)
771{
772  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
773  size_t                 blocks;
774  size_t                 inodes;
775
776  rtems_rfs_group_usage (fs, &blocks, &inodes);
777
778  sb->f_bsize   = rtems_rfs_fs_block_size (fs);
779  sb->f_frsize  = rtems_rfs_fs_media_block_size (fs);
780  sb->f_blocks  = rtems_rfs_fs_media_blocks (fs);
781  sb->f_bfree   = rtems_rfs_fs_blocks (fs) - blocks;
782  sb->f_bavail  = sb->f_bfree;
783  sb->f_files   = rtems_rfs_fs_inodes (fs);
784  sb->f_ffree   = rtems_rfs_fs_inodes (fs) - inodes;
785  sb->f_favail  = sb->f_ffree;
786  sb->f_fsid    = RTEMS_RFS_SB_MAGIC;
787  sb->f_flag    = rtems_rfs_fs_flags (fs);
788  sb->f_namemax = rtems_rfs_fs_max_name (fs);
789
790  return 0;
791}
792
793/**
794 *  Handler table for RFS link nodes
795 */
796const rtems_filesystem_file_handlers_r rtems_rfs_rtems_link_handlers =
797{
798  .open_h      = rtems_filesystem_default_open,
799  .close_h     = rtems_filesystem_default_close,
800  .read_h      = rtems_filesystem_default_read,
801  .write_h     = rtems_filesystem_default_write,
802  .ioctl_h     = rtems_filesystem_default_ioctl,
803  .lseek_h     = rtems_filesystem_default_lseek,
804  .fstat_h     = rtems_rfs_rtems_fstat,
805  .ftruncate_h = rtems_filesystem_default_ftruncate,
806  .fsync_h     = rtems_filesystem_default_fsync,
807  .fdatasync_h = rtems_filesystem_default_fdatasync,
808  .fcntl_h     = rtems_filesystem_default_fcntl
809};
810
811/**
812 * Forward decl for the ops table.
813 */
814
815int rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t *mt_entry,
816                                const void                           *data);
817void rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t *mt_entry);
818
819/**
820 * RFS file system operations table.
821 */
822const rtems_filesystem_operations_table rtems_rfs_ops =
823{
824  .lock_h         = rtems_rfs_rtems_lock_by_mt_entry,
825  .unlock_h       = rtems_rfs_rtems_unlock_by_mt_entry,
826  .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal,
827  .eval_path_h    = rtems_rfs_rtems_eval_path,
828  .link_h         = rtems_rfs_rtems_link,
829  .node_type_h    = rtems_rfs_rtems_node_type,
830  .fchmod_h       = rtems_rfs_rtems_fchmod,
831  .mknod_h        = rtems_rfs_rtems_mknod,
832  .rmnod_h        = rtems_rfs_rtems_rmnod,
833  .chown_h        = rtems_rfs_rtems_chown,
834  .clonenod_h     = rtems_filesystem_default_clonenode,
835  .freenod_h      = rtems_filesystem_default_freenode,
836  .mount_h        = rtems_filesystem_default_mount,
837  .fsmount_me_h   = rtems_rfs_rtems_initialise,
838  .unmount_h      = rtems_filesystem_default_unmount,
839  .fsunmount_me_h = rtems_rfs_rtems_shutdown,
840  .utime_h        = rtems_rfs_rtems_utime,
841  .symlink_h      = rtems_rfs_rtems_symlink,
842  .readlink_h     = rtems_rfs_rtems_readlink,
843  .rename_h       = rtems_rfs_rtems_rename,
844  .statvfs_h      = rtems_rfs_rtems_statvfs
845};
846
847/**
848 * Open the file system.
849 */
850
851int
852rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t* mt_entry,
853                            const void*                           data)
854{
855  rtems_rfs_rtems_private* rtems;
856  rtems_rfs_file_system*   fs;
857  uint32_t                 flags = 0;
858  uint32_t                 max_held_buffers = RTEMS_RFS_FS_MAX_HELD_BUFFERS;
859  const char*              options = data;
860  int                      rc;
861
862  /*
863   * Parse the options the user specifiies.
864   */
865  while (options)
866  {
867    printf ("options=%s\n", options);
868    if (strncmp (options, "hold-bitmaps",
869                 sizeof ("hold-bitmaps") - 1) == 0)
870      flags |= RTEMS_RFS_FS_BITMAPS_HOLD;
871    else if (strncmp (options, "no-local-cache",
872                      sizeof ("no-local-cache") - 1) == 0)
873      flags |= RTEMS_RFS_FS_NO_LOCAL_CACHE;
874    else if (strncmp (options, "max-held-bufs",
875                      sizeof ("max-held-bufs") - 1) == 0)
876    {
877      max_held_buffers = strtoul (options + sizeof ("max-held-bufs"), 0, 0);
878    }
879    else
880      return rtems_rfs_rtems_error ("initialise: invalid option", EINVAL);
881
882    options = strchr (options, ',');
883    if (options)
884    {
885      ++options;
886      if (*options == '\0')
887        options = NULL;
888    }
889  }
890
891  rtems = malloc (sizeof (rtems_rfs_rtems_private));
892  if (!rtems)
893    return rtems_rfs_rtems_error ("initialise: local data", ENOMEM);
894
895  memset (rtems, 0, sizeof (rtems_rfs_rtems_private));
896
897  rc = rtems_rfs_mutex_create (&rtems->access);
898  if (rc > 0)
899  {
900    free (rtems);
901    return rtems_rfs_rtems_error ("initialise: cannot create mutex", rc);
902  }
903
904  rc = rtems_rfs_mutex_lock (&rtems->access);
905  if (rc > 0)
906  {
907    rtems_rfs_mutex_destroy (&rtems->access);
908    free (rtems);
909    return rtems_rfs_rtems_error ("initialise: cannot lock access  mutex", rc);
910  }
911
912  rc = rtems_rfs_fs_open (mt_entry->dev, rtems, flags, max_held_buffers, &fs);
913  if (rc)
914  {
915    free (rtems);
916    return rtems_rfs_rtems_error ("initialise: open", rc);
917  }
918
919  mt_entry->fs_info = fs;
920
921  mt_entry->mt_fs_root->location.node_access = (void*) RTEMS_RFS_ROOT_INO;
922  mt_entry->mt_fs_root->location.handlers    = &rtems_rfs_rtems_dir_handlers;
923  mt_entry->mt_fs_root->location.ops         = &rtems_rfs_ops;
924
925  rtems_rfs_rtems_unlock (fs);
926
927  return 0;
928}
929
930/**
931 * Shutdown the file system.
932 */
933void
934rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry)
935{
936  rtems_rfs_file_system*   fs = mt_entry->fs_info;
937  rtems_rfs_rtems_private* rtems;
938
939  rtems = rtems_rfs_fs_user (fs);
940
941  /* FIXME: Return value? */
942  rtems_rfs_fs_close(fs);
943
944  rtems_rfs_mutex_destroy (&rtems->access);
945  free (rtems);
946}
Note: See TracBrowser for help on using the repository browser.