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

4.104.114.84.95
Last change on this file since 13e47e2e was 13e47e2e, checked in by Jennifer Averett <Jennifer.Averett@…>, on Nov 17, 2000 at 6:46:03 PM

2000-11-17 Jennifer Averret <jennifer@…>

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