source: rtems/cpukit/libfs/src/imfs/imfs_eval.c @ 3eb8f288

4.115
Last change on this file since 3eb8f288 was 3eb8f288, checked in by Ralf Corsepius <ralf.corsepius@…>, on 12/02/11 at 13:39:58

2011-12-02 Ralf Corsépius <ralf.corsepius@…>

  • libfs/src/imfs/imfs_eval.c: Make IMFS_evaluate_permission, IMFS_evaluate_hard_link, IMFS_evaluate_sym_link static.
  • libfs/src/imfs/imfs_fifo.c: Make IMFS_fifo_open, IMFS_fifo_close, IMFS_fifo_read, IMFS_fifo_write, IMFS_fifo_ioctl static.
  • Property mode set to 100644
File size: 17.3 KB
Line 
1/*
2 *  Evaluation IMFS Node Support Routines
3 *
4 *  COPYRIGHT (c) 1989-1999.
5 *  On-Line Applications Research Corporation (OAR).
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#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <errno.h>
23#include <stdlib.h>
24
25#include "imfs.h"
26#include <rtems/libio_.h>
27#include <rtems/seterr.h>
28
29#define RTEMS_LIBIO_PERMS_RX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_READ)
30#define RTEMS_LIBIO_PERMS_WX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_WRITE)
31
32#define MAXSYMLINK 5
33
34int IMFS_Set_handlers(
35  rtems_filesystem_location_info_t   *loc
36)
37{
38  IMFS_jnode_t    *node = loc->node_access;
39  IMFS_fs_info_t  *fs_info;
40
41  fs_info = loc->mt_entry->fs_info;
42  switch( node->type ) {
43    case IMFS_DIRECTORY:
44      loc->handlers = fs_info->directory_handlers;
45      break;
46    case IMFS_DEVICE:
47      loc->handlers = &IMFS_device_handlers;
48      break;
49    case IMFS_SYM_LINK:
50    case IMFS_HARD_LINK:
51      loc->handlers = &IMFS_link_handlers;
52      break;
53    case IMFS_LINEAR_FILE:
54      loc->handlers = fs_info->memfile_handlers;
55      break;
56    case IMFS_MEMORY_FILE:
57      loc->handlers = fs_info->memfile_handlers;
58      break;
59    case IMFS_FIFO:
60      loc->handlers = fs_info->fifo_handlers;
61      break;
62  }
63
64  return 0;
65}
66
67/*
68 *  IMFS_evaluate_permission
69 *
70 *  The following routine evaluates that we have permission
71 *  to do flags on the node.
72 */
73static int IMFS_evaluate_permission(
74  rtems_filesystem_location_info_t  *node,
75  int                                flags
76)
77{
78  uid_t         st_uid;
79  gid_t         st_gid;
80  IMFS_jnode_t *jnode;
81  int           flags_to_test;
82
83  if ( !rtems_libio_is_valid_perms( flags ) )
84    rtems_set_errno_and_return_minus_one( EPERM );
85
86  jnode = node->node_access;
87
88#if defined(RTEMS_POSIX_API)
89  st_uid = geteuid();
90  st_gid = getegid();
91#else
92  st_uid = jnode->st_uid;
93  st_gid = jnode->st_gid;
94#endif
95
96  /*
97   * Check if I am owner or a group member or someone else.
98   */
99
100  flags_to_test = flags;
101
102  if ( st_uid == jnode->st_uid )
103    flags_to_test <<= 6;
104  else if ( st_gid == jnode->st_gid )
105    flags_to_test <<= 3;
106  else {
107    /* must be other - do nothing */;
108  }
109
110  /*
111   * If all of the flags are set we have permission
112   * to do this.
113   */
114  if ( ( flags_to_test & jnode->st_mode) == flags_to_test )
115    return 1;
116
117  return 0;
118}
119
120/*
121 *  IMFS_evaluate_hard_link
122 *
123 *  The following routine evaluates a hardlink to the actual node.
124 */
125
126static int IMFS_evaluate_hard_link(
127  rtems_filesystem_location_info_t  *node,   /* IN/OUT */
128  int                                flags   /* IN     */
129)
130{
131  IMFS_jnode_t                     *jnode  = node->node_access;
132  int                               result = 0;
133
134  /*
135   * Check for things that should never happen.
136   */
137  IMFS_assert( jnode->type == IMFS_HARD_LINK );
138
139  /*
140   * Set the hard link value and the handlers.
141   */
142  node->node_access = jnode->info.hard_link.link_node;
143
144  IMFS_Set_handlers( node );
145
146  /*
147   * Verify we have the correct permissions for this node.
148   */
149
150  if ( !IMFS_evaluate_permission( node, flags ) )
151    rtems_set_errno_and_return_minus_one( EACCES );
152
153  return result;
154}
155
156
157/*
158 *  IMFS_evaluate_sym_link
159 *
160 *  The following routine evaluates a symbolic link to the actual node.
161 */
162
163static int IMFS_evaluate_sym_link(
164  rtems_filesystem_location_info_t  *node,   /* IN/OUT */
165  int                                flags   /* IN     */
166)
167{
168  IMFS_jnode_t                     *jnode  = node->node_access;
169  int                               result = 0;
170  int                               i;
171
172  /*
173   * Check for things that should never happen.
174   */
175  IMFS_assert( jnode->type == IMFS_SYM_LINK );
176  IMFS_assert( jnode->Parent );
177
178  /*
179   * Move the node_access to either the symbolic links parent or
180   * root depending on the symbolic links path.
181   */
182  node->node_access = jnode->Parent;
183
184  rtems_filesystem_get_sym_start_loc(
185    jnode->info.sym_link.name,
186    &i,
187    node
188  );
189
190  /*
191   * Use eval path to evaluate the path of the symbolic link.
192   */
193  result = IMFS_eval_path(
194    &jnode->info.sym_link.name[i],
195    strlen( &jnode->info.sym_link.name[i] ),
196    flags,
197    node
198  );
199
200  IMFS_Set_handlers( node );
201
202  /*
203   * Verify we have the correct permissions for this node.
204   */
205  if ( !IMFS_evaluate_permission( node, flags ) )
206    rtems_set_errno_and_return_minus_one( EACCES );
207
208  return result;
209}
210
211/*
212 *  IMFS_evaluate_link
213 *
214 *  The following routine returns the real node pointed to by a link.
215 */
216int IMFS_evaluate_link(
217  rtems_filesystem_location_info_t  *node,   /* IN/OUT */
218  int                                flags   /* IN     */
219)
220{
221  IMFS_jnode_t                     *jnode;
222  int                               result = 0;
223
224  do {
225    jnode  = node->node_access;
226
227    /*
228     * Increment and check the link counter.
229     */
230
231    rtems_filesystem_link_counts ++;
232    if ( rtems_filesystem_link_counts > MAXSYMLINK ) {
233      rtems_filesystem_link_counts = 0;
234      rtems_set_errno_and_return_minus_one( ELOOP );
235    }
236
237    /*
238     *  Follow the Link node.
239     */
240
241    if ( jnode->type == IMFS_HARD_LINK )
242      result = IMFS_evaluate_hard_link( node, flags );
243
244    else if (jnode->type == IMFS_SYM_LINK )
245      result = IMFS_evaluate_sym_link( node, flags );
246
247  } while ( ( result == 0 ) && ( ( jnode->type == IMFS_SYM_LINK  ) ||
248                                 ( jnode->type == IMFS_HARD_LINK ) ) );
249
250  /*
251   * Clear link counter.
252   */
253
254  rtems_filesystem_link_counts = 0;
255
256  return result;
257}
258
259/*
260 * IMFS_skip_separator
261 *
262 * Skip the separator in the path.
263 */
264static void IMFS_skip_separator (
265   const char *path,       /* IN     */
266   size_t     *len,        /* IN/OUT */
267   int        *index       /* IN/OUT */
268)
269{
270  while ( IMFS_is_separator( path[*index] ) && path[*index] && *len ) {
271    ++(*index);
272    --(*len);
273  }
274}
275
276/*
277 *  IMFS_evaluate_for_make
278 *
279 *  The following routine evaluate path for a new node to be created.
280 *  pathloc is returned with a pointer to the parent of the new node.
281 *  name is returned with a pointer to the first character in the
282 *  new node name.  The parent node is verified to be a directory.
283 */
284
285int IMFS_evaluate_for_make(
286  const char                         *path,       /* IN     */
287  rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */
288  const char                        **name        /* OUT    */
289                           )
290{
291  int               i = 0;
292  int               len;
293  IMFS_token_types  type;
294  char              token[ IMFS_NAME_MAX + 1 ];
295  IMFS_jnode_t     *node;
296  bool              done = false;
297  size_t            pathlen;
298  int               result;
299
300  /*
301   * This was filled in by the caller and is valid in the
302   * mount table.
303   */
304  node = pathloc->node_access;
305
306  /*
307   * Get the path length.
308   */
309  pathlen = strlen( path );
310  /*
311   *  Evaluate all tokens until we are done or an error occurs.
312   */
313
314  while( !done ) {
315
316    type = IMFS_get_token( &path[i], pathlen, token, &len );
317    pathlen -= len;
318    i +=  len;
319
320    if ( !pathloc->node_access )
321      rtems_set_errno_and_return_minus_one( ENOENT );
322
323    /*
324     * I cannot move out of this directory without execute permission.
325     */
326
327    if ( type != IMFS_NO_MORE_PATH )
328      if ( node->type == IMFS_DIRECTORY )
329        if ( !IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_SEARCH ) )
330          rtems_set_errno_and_return_minus_one( EACCES );
331
332    node = pathloc->node_access;
333
334    switch( type ) {
335
336      case IMFS_UP_DIR:
337        /*
338         *  Am I at the root of all filesystems? (chroot'ed?)
339         */
340
341        if ( pathloc->node_access == rtems_filesystem_root.node_access )
342          break;       /* Throw out the .. in this case */
343
344
345        /*
346         * Am I at the root of this mounted filesystem?
347         */
348
349        if ( rtems_filesystem_is_root_location( pathloc ) ) {
350
351          /*
352           *  Am I at the root of all filesystems?
353           */
354
355          if ( pathloc->node_access == rtems_filesystem_root.node_access ) {
356            break;
357
358          } else {
359            *pathloc = pathloc->mt_entry->mt_point_node;
360            return (*pathloc->ops->evalformake_h)( &path[i-len], pathloc, name );
361          }
362        } else {
363
364          if ( !node->Parent )
365            rtems_set_errno_and_return_minus_one( ENOENT );
366
367          node = node->Parent;
368        }
369
370        pathloc->node_access = node;
371        break;
372
373      case IMFS_NAME:
374
375        if ( node->type == IMFS_HARD_LINK ) {
376
377          result = IMFS_evaluate_link( pathloc, 0 );
378          if ( result == -1 )
379            return -1;
380
381        } else if ( node->type == IMFS_SYM_LINK ) {
382
383          result = IMFS_evaluate_link( pathloc, 0 );
384
385          if ( result == -1 )
386            return -1;
387        }
388
389        node = pathloc->node_access;
390        if ( !node )
391          rtems_set_errno_and_return_minus_one( ENOTDIR );
392
393        /*
394         * Only a directory can be decended into.
395         */
396
397        if ( node->type != IMFS_DIRECTORY )
398          rtems_set_errno_and_return_minus_one( ENOTDIR );
399
400        /*
401         * Find the token name in the present location.
402         */
403
404        node = IMFS_find_match_in_dir( node, token );
405
406        /*
407         * If there is no node we have found the name of the node we
408         * wish to create.
409         */
410
411        if ( ! node )
412          done = true;
413        else {
414        if (( node->type == IMFS_DIRECTORY ) && ( node->info.directory.mt_fs != NULL )) {
415            IMFS_skip_separator( path, &pathlen, &i);
416            if ((path[i] != '.') || (path[i + 1] != '.')) {
417              *pathloc = node->info.directory.mt_fs->mt_fs_root;
418              return (*pathloc->ops->evalformake_h)( &path[i],
419                                                     pathloc,
420                                                     name );
421            }
422            i += 2;
423            pathlen -= 2;
424            node = node->Parent;
425          }
426          pathloc->node_access = node;
427        }
428        break;
429
430      case IMFS_NO_MORE_PATH:
431        rtems_set_errno_and_return_minus_one( EEXIST );
432        break;
433
434      case IMFS_INVALID_TOKEN:
435        rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
436        break;
437
438      case IMFS_CURRENT_DIR:
439        break;
440    }
441  }
442
443  *name = &path[ i - len ];
444
445  /*
446   * We have evaluated the path as far as we can.
447   * Verify there is not any invalid stuff at the end of the name.
448   */
449
450  for( ; path[i] != '\0'; i++) {
451    if ( !IMFS_is_separator( path[ i ] ) )
452      rtems_set_errno_and_return_minus_one( ENOENT );
453  }
454
455  /*
456   * Verify we can execute and write to this directory.
457   */
458
459  result = IMFS_Set_handlers( pathloc );
460
461  /*
462   * The returned node must be a directory
463   */
464  node = pathloc->node_access;
465  if ( node->type != IMFS_DIRECTORY )
466    rtems_set_errno_and_return_minus_one( ENOTDIR );
467
468  /*
469   * We must have Write and execute permission on the returned node.
470   */
471
472  if ( !IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_WX ) )
473    rtems_set_errno_and_return_minus_one( EACCES );
474
475  return result;
476}
477
478/*
479 *  IMFS_eval_path
480 *
481 *  The following routine evaluate path for a node that wishes to be
482 *  accessed with mode.  pathloc is returned with a pointer to the
483 *  node to be accessed.
484 */
485
486int IMFS_eval_path(
487  const char                        *pathname,     /* IN     */
488  size_t                             pathnamelen,  /* IN     */
489  int                                flags,        /* IN     */
490  rtems_filesystem_location_info_t  *pathloc       /* IN/OUT */
491                   )
492{
493  int               i = 0;
494  int               len;
495  IMFS_token_types  type = IMFS_CURRENT_DIR;
496  char              token[ IMFS_NAME_MAX + 1 ];
497  IMFS_jnode_t     *node;
498  int               result;
499
500  if ( !rtems_libio_is_valid_perms( flags ) ) {
501    rtems_set_errno_and_return_minus_one( EIO );
502  }
503
504  /*
505   *  This was filled in by the caller and is valid in the
506   *  mount table.
507   */
508
509  node = pathloc->node_access;
510
511  /*
512   *  Evaluate all tokens until we are done or an error occurs.
513   */
514
515  while( (type != IMFS_NO_MORE_PATH) && (type != IMFS_INVALID_TOKEN) ) {
516
517    type = IMFS_get_token( &pathname[i], pathnamelen, token, &len );
518    pathnamelen -= len;
519    i += len;
520
521    if ( !pathloc->node_access )
522      rtems_set_errno_and_return_minus_one( ENOENT );
523
524    /*
525     * I cannot move out of this directory without execute permission.
526     */
527    if ( type != IMFS_NO_MORE_PATH )
528      if ( node->type == IMFS_DIRECTORY )
529        if ( !IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_SEARCH ) )
530          rtems_set_errno_and_return_minus_one( EACCES );
531
532    node = pathloc->node_access;
533
534    switch( type ) {
535      case IMFS_UP_DIR:
536        /*
537         *  Am I at the root of all filesystems? (chroot'ed?)
538         */
539
540        if ( pathloc->node_access == rtems_filesystem_root.node_access )
541          break;       /* Throw out the .. in this case */
542
543        /*
544         *  Am I at the root of this mounted filesystem?
545         */
546
547        if ( rtems_filesystem_is_root_location( pathloc ) ) {
548
549          /*
550           *  Am I at the root of all filesystems?
551           */
552
553          if ( pathloc->node_access == rtems_filesystem_root.node_access ) {
554            break;       /* Throw out the .. in this case */
555          } else {
556            *pathloc = pathloc->mt_entry->mt_point_node;
557            return (*pathloc->ops->evalpath_h)(&(pathname[i-len]),
558                                               pathnamelen+len,
559                                               flags,pathloc);
560          }
561        } else {
562
563          if ( !node->Parent )
564            rtems_set_errno_and_return_minus_one( ENOENT );
565
566          node = node->Parent;
567          pathloc->node_access = node;
568
569        }
570
571        pathloc->node_access = node;
572        break;
573
574      case IMFS_NAME:
575        /*
576         *  If we are at a link follow it.
577         */
578        if ( node->type == IMFS_HARD_LINK ) {
579          IMFS_evaluate_hard_link( pathloc, 0 );
580          node = pathloc->node_access;
581
582          /*
583           * It would be a design error if we evaluated the link and
584           * was broken.
585           */
586          IMFS_assert( node );
587
588        } else if ( node->type == IMFS_SYM_LINK ) {
589          result = IMFS_evaluate_sym_link( pathloc, 0 );
590
591          /*
592           *  In contrast to a hard link, it is possible to have a broken
593           *  symbolic link.
594           */
595          node = pathloc->node_access;
596          if ( result == -1 )
597            return -1;
598        }
599
600        /*
601         *  Only a directory can be decended into.
602         */
603        if ( node->type != IMFS_DIRECTORY )
604          rtems_set_errno_and_return_minus_one( ENOTDIR );
605
606        /*
607         *  Find the token name in the current node.
608         */
609        node = IMFS_find_match_in_dir( node, token );
610        if ( !node )
611          rtems_set_errno_and_return_minus_one( ENOENT );
612
613        /*
614         *  If we are at a node that is a mount point so current directory
615         *  actually exists on the mounted file system and not in the node that
616         *  contains the mount point node. For example a stat of the mount
617         *  point should return the details of the root of the mounted file
618         *  system not the mount point node of parent file system.
619         *
620         *  If the node we have just moved to is a mount point do not loop and
621         *  get the token because the token may be suitable for the mounted
622         *  file system and not the IMFS. For example the IMFS length is
623         *  limited. If the token is a parent directory move back up otherwise
624         *  set loc to the new fs root node and let them finish evaluating the
625         *  path.
626         */
627        if (( node->type == IMFS_DIRECTORY ) && ( node->info.directory.mt_fs != NULL )) {
628          IMFS_skip_separator( pathname, &pathnamelen, &i);
629          if ((pathname[i] != '.') || (pathname[i + 1] != '.')) {
630            *pathloc = node->info.directory.mt_fs->mt_fs_root;
631            return (*pathloc->ops->evalpath_h)( &pathname[i],
632                                                pathnamelen,
633                                                flags, pathloc );
634          }
635          i += 2;
636          pathnamelen -= 2;
637          node = node->Parent;
638        }
639
640        /*
641         *  Set the node access to the point we have found.
642         */
643        pathloc->node_access = node;
644        break;
645
646      case IMFS_NO_MORE_PATH:
647      case IMFS_CURRENT_DIR:
648        break;
649
650      case IMFS_INVALID_TOKEN:
651        rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
652        break;
653
654    }
655  }
656
657  /*
658   *  Always return the root node.
659   *
660   *  If we are at a node that is a mount point. Set loc to the
661   *  new fs root node and let let the mounted filesystem set the handlers.
662   *
663   *  NOTE: The behavior of stat() on a mount point appears to be questionable.
664   */
665
666  if ( node->type == IMFS_DIRECTORY ) {
667    if ( node->info.directory.mt_fs != NULL ) {
668      *pathloc = node->info.directory.mt_fs->mt_fs_root;
669      return (*pathloc->ops->evalpath_h)( &pathname[i-len],
670                                          pathnamelen+len,
671                                          flags, pathloc );
672    } else {
673      result = IMFS_Set_handlers( pathloc );
674    }
675  } else {
676    result = IMFS_Set_handlers( pathloc );
677  }
678
679  /*
680   * Verify we have the correct permissions for this node.
681   */
682
683  if ( !IMFS_evaluate_permission( pathloc, flags ) )
684    rtems_set_errno_and_return_minus_one( EACCES );
685
686  return result;
687}
Note: See TracBrowser for help on using the repository browser.