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

4.104.114.84.95
Last change on this file since b6a2d2fa was b6a2d2fa, checked in by Joel Sherrill <joel.sherrill@…>, on 08/09/01 at 22:09:36

2001-08-09 Fernando-Ruiz Casas <correo@…>

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