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

4.104.115
Last change on this file since cd469f2 was cd469f2, checked in by Ralf Corsepius <ralf.corsepius@…>, on 05/27/10 at 16:24:47

2010-05-27 Ralf Corsépius <ralf.corsepius@…>

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