source: rtems/c/src/exec/libfs/src/imfs/imfs_eval.c @ 07a3253d

4.104.114.84.95
Last change on this file since 07a3253d was 07a3253d, checked in by Joel Sherrill <joel.sherrill@…>, on 11/23/98 at 19:07:58

Added base version of file system infrastructure. This includes a major
overhaul of the RTEMS system call interface. This base file system is
the "In-Memory File System" aka IMFS.

The design and implementation was done by the following people:

+ Joel Sherrill (joel@…)
+ Jennifer Averett (jennifer@…)
+ Steve "Mr Mount" Salitasc (salitasc@…)
+ Kerwin Wade (wade@…)

PROBLEMS
========

+ It is VERY likely that merging this will break the UNIX port. This

can/will be fixed.

+ There is likely some reentrancy/mutual exclusion needed.

+ Eventually, there should be a "mini-IMFS" description table to

eliminate links, symlinks, etc to save memory. All you need to
have "classic RTEMS" functionality is technically directories
and device IO. All the rest could be left out to save memory.

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