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

4.115
Last change on this file since acb92e3 was acb92e3, checked in by Chris Johns <chrisj@…>, on 07/04/11 at 00:31:25

2011-07-04 Chris Johns <chrisj@…>

PR 1827/filesystem

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