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

4.11
Last change on this file since 8851c0a was 8851c0a, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 2, 2010 at 6:27:23 PM

2010-08-02 Joel Sherrill <joel.sherrill@…>

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