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

4.10
Last change on this file since 8434594 was 8434594, checked in by Chris Johns <chrisj@…>, on 05/17/11 at 04:45:52

2011-05-17 Chris Johns <chrisj@…>

PR 1774/filesystem

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