source: rtems/cpukit/include/rtems/libio_.h @ c2287ba2

5
Last change on this file since c2287ba2 was c2287ba2, checked in by Sebastian Huber <sebastian.huber@…>, on 03/10/20 at 16:07:19

libio: Robust file descriptor reference counting

There was a race conditon in the reference counting of file descriptors
during a close() operation. After the call to the close handler, the
rtems_libio_free() function cleared the flags to zero. However, at this
point in time there may still exist some holders of the file descriptor.
With RTEMS_DEBUG enabled this could lead to failed assertions in
rtems_libio_iop_drop().

Change the code to use only atomic read-modify-write operations on the
rtems_libio_iop::flags.

  • Property mode set to 100644
File size: 25.4 KB
Line 
1/**
2 * @file
3 *
4 * @brief LibIO Internal Interface
5 *
6 * This file is the libio internal interface.
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2011.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  Modifications to support reference counting in the file system are
14 *  Copyright (c) 2012 embedded brains GmbH.
15 *
16 *  The license and distribution terms for this file may be
17 *  found in the file LICENSE in this distribution or at
18 *  http://www.rtems.org/license/LICENSE.
19 */
20
21#ifndef _RTEMS_RTEMS_LIBIO__H
22#define _RTEMS_RTEMS_LIBIO__H
23
24#include <sys/uio.h>
25#include <errno.h>
26#include <limits.h>
27#include <pthread.h>
28
29#include <rtems.h>
30#include <rtems/libio.h>
31#include <rtems/seterr.h>
32#include <rtems/score/assert.h>
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37
38/**
39 * @defgroup LibIOInternal IO Internal Library
40 *
41 * @ingroup LibIO
42 *
43 * @brief Internal IO library API and implementation.
44 *
45 */
46/**@{**/
47
48#define RTEMS_FILESYSTEM_SYMLOOP_MAX 32
49
50/*
51 * Not defined in newlib so provide here. Users should use dup2 and
52 * not this non-portable fcntl command. Provided here to allow the
53 * RTEMS implementation to work.
54 */
55#define F_DUP2FD 20
56
57/*
58 *  File descriptor Table Information
59 */
60
61extern const uint32_t rtems_libio_number_iops;
62extern rtems_libio_t rtems_libio_iops[];
63extern void *rtems_libio_iop_free_head;
64extern void **rtems_libio_iop_free_tail;
65
66extern const rtems_filesystem_file_handlers_r rtems_filesystem_null_handlers;
67
68extern rtems_filesystem_mount_table_entry_t rtems_filesystem_null_mt_entry;
69
70/**
71 * @brief The global null location.
72 *
73 * Every operation and the open and fstat handlers of this location returns an
74 * error status.  The errno is not touched by these operations and handlers.
75 * The purpose of this location is to deliver the error return status for a
76 * previous error condition which must set the errno accordingly.
77 *
78 * The usage of this null location instead of the NULL pointer eliminates
79 * a lot of branches.
80 *
81 * The user environment root and current directory are statically initialized
82 * with the null location.  Due to that all file system services are in a
83 * defined state even if no root file system was mounted.
84 */
85extern rtems_filesystem_global_location_t rtems_filesystem_global_location_null;
86
87/**
88 * @brief Sets the specified flags in the iop.
89 *
90 * @param[in] iop The iop.
91 * @param[in] set The flags to set.
92 *
93 * @return The previous flags.
94 */
95static inline unsigned int rtems_libio_iop_flags_set(
96  rtems_libio_t *iop,
97  unsigned int   set
98)
99{
100  return _Atomic_Fetch_or_uint( &iop->flags, set, ATOMIC_ORDER_RELAXED );
101}
102
103/**
104 * @brief Clears the specified flags in the iop.
105 *
106 * @param[in] iop The iop.
107 * @param[in] clear The flags to clear.
108 *
109 * @return The previous flags.
110 */
111static inline unsigned int rtems_libio_iop_flags_clear(
112  rtems_libio_t *iop,
113  unsigned int   clear
114)
115{
116  return _Atomic_Fetch_and_uint( &iop->flags, ~clear, ATOMIC_ORDER_RELAXED );
117}
118
119/**
120 * @brief Maps a file descriptor to the iop.
121 *
122 * The file descriptor must be a valid index into the iop table.
123 *
124 * @param[in] fd The file descriptor.
125 *
126 * @return The iop corresponding to the specified file descriptor.
127 */
128static inline rtems_libio_t *rtems_libio_iop( int fd )
129{
130  return &rtems_libio_iops[ fd ];
131}
132
133/**
134 * @brief Holds a refernece to the iop.
135 *
136 * @param[in] iop The iop.
137 *
138 * @return The flags corresponding to the specified iop.
139 */
140static inline unsigned int rtems_libio_iop_hold( rtems_libio_t *iop )
141{
142  return _Atomic_Fetch_add_uint(
143    &iop->flags,
144    LIBIO_FLAGS_REFERENCE_INC,
145    ATOMIC_ORDER_ACQUIRE
146  );
147}
148
149/**
150 * @brief Drops a refernece to the iop.
151 *
152 * @param[in] iop The iop.
153 */
154static inline void rtems_libio_iop_drop( rtems_libio_t *iop )
155{
156#if defined(RTEMS_DEBUG)
157  unsigned int flags;
158  bool         success;
159
160  flags = _Atomic_Load_uint( &iop->flags, ATOMIC_ORDER_RELAXED );
161
162  do {
163    unsigned int desired;
164
165    _Assert( flags >= LIBIO_FLAGS_REFERENCE_INC );
166
167    desired = flags - LIBIO_FLAGS_REFERENCE_INC;
168    success = _Atomic_Compare_exchange_uint(
169      &iop->flags,
170      &flags,
171      desired,
172      ATOMIC_ORDER_RELEASE,
173      ATOMIC_ORDER_RELAXED
174    );
175  } while ( !success );
176#else
177  _Atomic_Fetch_sub_uint(
178    &iop->flags,
179    LIBIO_FLAGS_REFERENCE_INC,
180    ATOMIC_ORDER_RELEASE
181  );
182#endif
183}
184
185/*
186 *  rtems_libio_iop_to_descriptor
187 *
188 *  Macro to convert an internal file descriptor pointer (iop) into
189 *  the integer file descriptor used by the "section 2" system calls.
190 */
191
192#define rtems_libio_iop_to_descriptor(_iop) \
193  ((_iop) - &rtems_libio_iops[0])
194
195/*
196 *  rtems_libio_check_is_open
197 *
198 *  Macro to check if a file descriptor is actually open.
199 */
200
201#define rtems_libio_check_is_open(_iop) \
202  do {                                               \
203      if ((rtems_libio_iop_flags(_iop) & LIBIO_FLAGS_OPEN) == 0) { \
204          errno = EBADF;                             \
205          return -1;                                 \
206      }                                              \
207  } while (0)
208
209/**
210 * @brief Macro to get the iop for the specified file descriptor.
211 *
212 * Checks that the file descriptor is in the valid range and open.
213 */
214#define LIBIO_GET_IOP( _fd, _iop ) \
215  do { \
216    unsigned int _flags; \
217    if ( (uint32_t) ( _fd ) >= rtems_libio_number_iops ) { \
218      rtems_set_errno_and_return_minus_one( EBADF ); \
219    } \
220    _iop = rtems_libio_iop( _fd ); \
221    _flags = rtems_libio_iop_hold( _iop ); \
222    if ( ( _flags & LIBIO_FLAGS_OPEN ) == 0 ) { \
223      rtems_libio_iop_drop( _iop ); \
224      rtems_set_errno_and_return_minus_one( EBADF ); \
225    } \
226  } while ( 0 )
227
228/**
229 * @brief Macro to get the iop for the specified file descriptor with access
230 * flags and error.
231 *
232 * Checks that the file descriptor is in the valid range and open.
233 */
234#define LIBIO_GET_IOP_WITH_ACCESS( _fd, _iop, _access_flags, _access_error ) \
235  do { \
236    unsigned int _flags; \
237    unsigned int _mandatory; \
238    if ( (uint32_t) ( _fd ) >= rtems_libio_number_iops ) { \
239      rtems_set_errno_and_return_minus_one( EBADF ); \
240    } \
241    _iop = rtems_libio_iop( _fd ); \
242    _flags = rtems_libio_iop_hold( _iop ); \
243    _mandatory = LIBIO_FLAGS_OPEN | ( _access_flags ); \
244    if ( ( _flags & _mandatory ) != _mandatory ) { \
245      int _error; \
246      rtems_libio_iop_drop( _iop ); \
247      if ( ( _flags & LIBIO_FLAGS_OPEN ) == 0 ) { \
248        _error = EBADF; \
249      } else { \
250        _error = _access_error; \
251      } \
252      rtems_set_errno_and_return_minus_one( _error ); \
253    } \
254  } while ( 0 )
255
256/*
257 *  rtems_libio_check_buffer
258 *
259 *  Macro to check if a buffer pointer is valid.
260 */
261
262#define rtems_libio_check_buffer(_buffer) \
263  do {                                    \
264      if ((_buffer) == 0) {               \
265          errno = EINVAL;                 \
266          return -1;                      \
267      }                                   \
268  } while (0)
269
270/*
271 *  rtems_libio_check_count
272 *
273 *  Macro to check if a count or length is valid.
274 */
275
276#define rtems_libio_check_count(_count) \
277  do {                                  \
278      if ((_count) == 0) {              \
279          return 0;                     \
280      }                                 \
281  } while (0)
282
283/**
284 * @brief Clones a node.
285 *
286 * The caller must hold the file system instance lock.
287 *
288 * @param[out] clone The cloned location.
289 * @param[in] master The master location.
290 *
291 * @see rtems_filesystem_instance_lock().
292 */
293void rtems_filesystem_location_clone(
294  rtems_filesystem_location_info_t *clone,
295  const rtems_filesystem_location_info_t *master
296);
297
298/**
299 * @brief Releases all resources of a location.
300 *
301 * This function may block on a mutex and may complete an unmount process.
302 *
303 * @param[in] loc The location to free.
304 *
305 * @note The file system root location is released by the file system
306 * instance destruction handler (see @ref rtems_filesystem_fsunmount_me_t).
307 *
308 * @see rtems_filesystem_freenode_t.
309 */
310void rtems_filesystem_location_free( rtems_filesystem_location_info_t *loc );
311
312/*
313 *  External structures
314 */
315#include <rtems/userenv.h>
316
317void rtems_libio_lock( void );
318
319void rtems_libio_unlock( void );
320
321static inline void rtems_filesystem_mt_lock( void )
322{
323  rtems_libio_lock();
324}
325
326static inline void rtems_filesystem_mt_unlock( void )
327{
328  rtems_libio_unlock();
329}
330
331extern rtems_interrupt_lock rtems_filesystem_mt_entry_lock_control;
332
333#define rtems_filesystem_mt_entry_declare_lock_context( ctx ) \
334  rtems_interrupt_lock_context ctx
335
336#define rtems_filesystem_mt_entry_lock( ctx ) \
337  rtems_interrupt_lock_acquire( &rtems_filesystem_mt_entry_lock_control, &ctx )
338
339#define rtems_filesystem_mt_entry_unlock( ctx ) \
340  rtems_interrupt_lock_release( &rtems_filesystem_mt_entry_lock_control, &ctx )
341
342static inline void rtems_filesystem_instance_lock(
343  const rtems_filesystem_location_info_t *loc
344)
345{
346  const rtems_filesystem_mount_table_entry_t *mt_entry = loc->mt_entry;
347
348  (*mt_entry->ops->lock_h)( mt_entry );
349}
350
351static inline void rtems_filesystem_instance_unlock(
352  const rtems_filesystem_location_info_t *loc
353)
354{
355  const rtems_filesystem_mount_table_entry_t *mt_entry = loc->mt_entry;
356
357  (*mt_entry->ops->unlock_h)( mt_entry );
358}
359
360/*
361 *  File Descriptor Routine Prototypes
362 */
363
364/**
365 * This routine searches the IOP Table for an unused entry.  If it
366 * finds one, it returns it.  Otherwise, it returns NULL.
367 */
368rtems_libio_t *rtems_libio_allocate(void);
369
370/**
371 * Convert UNIX fnctl(2) flags to ones that RTEMS drivers understand
372 */
373unsigned int rtems_libio_fcntl_flags( int fcntl_flags );
374
375/**
376 * Convert RTEMS internal flags to UNIX fnctl(2) flags
377 */
378int rtems_libio_to_fcntl_flags( unsigned int flags );
379
380/**
381 * This routine frees the resources associated with an IOP (file descriptor)
382 * and clears the slot in the IOP Table.
383 */
384void rtems_libio_free(
385  rtems_libio_t *iop
386);
387
388/*
389 *  File System Routine Prototypes
390 */
391
392rtems_filesystem_location_info_t *
393rtems_filesystem_eval_path_start(
394  rtems_filesystem_eval_path_context_t *ctx,
395  const char *path,
396  int eval_flags
397);
398
399rtems_filesystem_location_info_t *
400rtems_filesystem_eval_path_start_with_parent(
401  rtems_filesystem_eval_path_context_t *ctx,
402  const char *path,
403  int eval_flags,
404  rtems_filesystem_location_info_t *parentloc,
405  int parent_eval_flags
406);
407
408rtems_filesystem_location_info_t *
409rtems_filesystem_eval_path_start_with_root_and_current(
410  rtems_filesystem_eval_path_context_t *ctx,
411  const char *path,
412  size_t pathlen,
413  int eval_flags,
414  rtems_filesystem_global_location_t *const *global_root_ptr,
415  rtems_filesystem_global_location_t *const *global_current_ptr
416);
417
418void rtems_filesystem_eval_path_continue(
419  rtems_filesystem_eval_path_context_t *ctx
420);
421
422void rtems_filesystem_eval_path_cleanup(
423  rtems_filesystem_eval_path_context_t *ctx
424);
425
426void rtems_filesystem_eval_path_recursive(
427  rtems_filesystem_eval_path_context_t *ctx,
428  const char *path,
429  size_t pathlen
430);
431
432void rtems_filesystem_eval_path_cleanup_with_parent(
433  rtems_filesystem_eval_path_context_t *ctx,
434  rtems_filesystem_location_info_t *parentloc
435);
436
437/**
438 * @brief Requests a path evaluation restart.
439 *
440 * Sets the start and current location to the new start location.  The caller
441 * must terminate its current evaluation process.  The path evaluation
442 * continues in the next loop iteration within
443 * rtems_filesystem_eval_path_continue().  This avoids recursive invocations.
444 * The function obtains the new start location and clones it to set the new
445 * current location.  The previous start and current locations are released.
446 *
447 * @param[in, out] ctx The path evaluation context.
448 * @param[in, out] newstartloc_ptr Pointer to the new start location.
449 */
450void rtems_filesystem_eval_path_restart(
451  rtems_filesystem_eval_path_context_t *ctx,
452  rtems_filesystem_global_location_t **newstartloc_ptr
453);
454
455typedef enum {
456  RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE,
457  RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE,
458  RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY
459} rtems_filesystem_eval_path_generic_status;
460
461/**
462 * @brief Tests if the current location is a directory.
463 *
464 * @param[in, out] ctx The path evaluation context.
465 * @param[in, out] arg The handler argument.
466 *
467 * @retval true The current location is a directory.
468 * @retval false Otherwise.
469 *
470 * @see rtems_filesystem_eval_path_generic().
471 */
472typedef bool (*rtems_filesystem_eval_path_is_directory)(
473  rtems_filesystem_eval_path_context_t *ctx,
474  void *arg
475);
476
477/**
478 * @brief Evaluates a token.
479 *
480 * @param[in, out] ctx The path evaluation context.
481 * @param[in, out] arg The handler argument.
482 * @param[in] token The token contents.
483 * @param[in] tokenlen The token length in characters.
484 *
485 * @retval status The generic path evaluation status.
486 *
487 * @see rtems_filesystem_eval_path_generic().
488 */
489typedef rtems_filesystem_eval_path_generic_status
490(*rtems_filesystem_eval_path_eval_token)(
491  rtems_filesystem_eval_path_context_t *ctx,
492  void *arg,
493  const char *token,
494  size_t tokenlen
495);
496
497typedef struct {
498  rtems_filesystem_eval_path_is_directory is_directory;
499  rtems_filesystem_eval_path_eval_token eval_token;
500} rtems_filesystem_eval_path_generic_config;
501
502void rtems_filesystem_eval_path_generic(
503  rtems_filesystem_eval_path_context_t *ctx,
504  void *arg,
505  const rtems_filesystem_eval_path_generic_config *config
506);
507
508void rtems_filesystem_initialize(void);
509
510/**
511 * @brief Copies a location.
512 *
513 * A bitwise copy is performed.  The destination location will be added to the
514 * corresponding mount entry.
515 *
516 * @param[out] dst The destination location.
517 * @param[in] src The  source location.
518 *
519 * @retval dst The destination location.
520 *
521 * @see rtems_filesystem_location_clone().
522 */
523rtems_filesystem_location_info_t *rtems_filesystem_location_copy(
524  rtems_filesystem_location_info_t *dst,
525  const rtems_filesystem_location_info_t *src
526);
527
528static inline rtems_filesystem_location_info_t *
529rtems_filesystem_location_initialize_to_null(
530  rtems_filesystem_location_info_t *loc
531)
532{
533  return rtems_filesystem_location_copy(
534    loc,
535    &rtems_filesystem_global_location_null.location
536  );
537}
538
539rtems_filesystem_global_location_t *
540rtems_filesystem_location_transform_to_global(
541  rtems_filesystem_location_info_t *loc
542);
543
544/**
545 * @brief Assigns a global file system location.
546 *
547 * @param[in, out] lhs_global_loc_ptr Pointer to the global left hand side file
548 * system location.  The current left hand side location will be released.
549 * @param[in] rhs_global_loc The global right hand side file system location.
550 */
551void rtems_filesystem_global_location_assign(
552  rtems_filesystem_global_location_t **lhs_global_loc_ptr,
553  rtems_filesystem_global_location_t *rhs_global_loc
554);
555
556/**
557 * @brief Obtains a global file system location.
558 *
559 * Deferred releases will be processed in this function.
560 *
561 * This function must be called from normal thread context and may block on a
562 * mutex.  Thread dispatching is disabled to protect some critical sections.
563 *
564 * @param[in] global_loc_ptr Pointer to the global file system location.
565 *
566 * @return A global file system location.  It returns always a valid object.
567 * In case of an error, the global null location will be returned.  Each
568 * operation or handler of the null location returns an error status.  The
569 * errno indicates the error.  The NULL pointer is never returned.
570 *
571 * @see rtems_filesystem_location_transform_to_global(),
572 * rtems_filesystem_global_location_obtain_null(), and
573 * rtems_filesystem_global_location_release().
574 */
575rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain(
576  rtems_filesystem_global_location_t *const *global_loc_ptr
577);
578
579/**
580 * @brief Releases a global file system location.
581 *
582 * In case the reference count reaches zero, all associated resources will be
583 * released.  This may include the complete unmount of the corresponding file
584 * system instance.
585 *
586 * This function may block on a mutex.  It may be called within critical
587 * sections of the operating system.  In this case the release will be
588 * deferred.  The next obtain call will do the actual release.
589 *
590 * @param[in] global_loc The global file system location.  It must not be NULL.
591 * @param[in] deferred If true, then do a deferred release, otherwise release
592 *   it immediately.
593 *
594 * @see rtems_filesystem_global_location_obtain().
595 */
596void rtems_filesystem_global_location_release(
597  rtems_filesystem_global_location_t *global_loc,
598  bool deferred
599);
600
601void rtems_filesystem_location_detach(
602  rtems_filesystem_location_info_t *detach
603);
604
605void rtems_filesystem_location_copy_and_detach(
606  rtems_filesystem_location_info_t *copy,
607  rtems_filesystem_location_info_t *detach
608);
609
610static inline rtems_filesystem_global_location_t *
611rtems_filesystem_global_location_obtain_null(void)
612{
613  rtems_filesystem_global_location_t *global_loc = NULL;
614
615  return rtems_filesystem_global_location_obtain( &global_loc );
616}
617
618static inline bool rtems_filesystem_location_is_null(
619  const rtems_filesystem_location_info_t *loc
620)
621{
622  return loc->handlers == &rtems_filesystem_null_handlers;
623}
624
625static inline bool rtems_filesystem_global_location_is_null(
626  const rtems_filesystem_global_location_t *global_loc
627)
628{
629  return rtems_filesystem_location_is_null( &global_loc->location );
630}
631
632static inline void rtems_filesystem_location_error(
633  const rtems_filesystem_location_info_t *loc,
634  int eno
635)
636{
637  if ( !rtems_filesystem_location_is_null( loc ) ) {
638    errno = eno;
639  }
640}
641
642int rtems_filesystem_mknod(
643  const rtems_filesystem_location_info_t *parentloc,
644  const char *name,
645  size_t namelen,
646  mode_t mode,
647  dev_t dev
648);
649
650int rtems_filesystem_chdir( rtems_filesystem_location_info_t *loc );
651
652int rtems_filesystem_chmod(
653  const rtems_filesystem_location_info_t *loc,
654  mode_t mode
655);
656
657int rtems_filesystem_chown(
658  const rtems_filesystem_location_info_t *loc,
659  uid_t owner,
660  gid_t group
661);
662
663static inline bool rtems_filesystem_is_ready_for_unmount(
664  rtems_filesystem_mount_table_entry_t *mt_entry
665)
666{
667  bool ready = !mt_entry->mounted
668    && rtems_chain_has_only_one_node( &mt_entry->location_chain )
669    && mt_entry->mt_fs_root->reference_count == 1;
670
671  if ( ready ) {
672    rtems_chain_initialize_empty( &mt_entry->location_chain );
673  }
674
675  return ready;
676}
677
678static inline void rtems_filesystem_location_add_to_mt_entry(
679  rtems_filesystem_location_info_t *loc
680)
681{
682  rtems_filesystem_mt_entry_declare_lock_context( lock_context );
683
684  rtems_filesystem_mt_entry_lock( lock_context );
685  rtems_chain_append_unprotected(
686    &loc->mt_entry->location_chain,
687    &loc->mt_entry_node
688  );
689  rtems_filesystem_mt_entry_unlock( lock_context );
690}
691
692void rtems_filesystem_location_remove_from_mt_entry(
693  rtems_filesystem_location_info_t *loc
694);
695
696void rtems_filesystem_do_unmount(
697  rtems_filesystem_mount_table_entry_t *mt_entry
698);
699
700static inline bool rtems_filesystem_location_is_instance_root(
701  const rtems_filesystem_location_info_t *loc
702)
703{
704  const rtems_filesystem_mount_table_entry_t *mt_entry = loc->mt_entry;
705
706  return (*mt_entry->ops->are_nodes_equal_h)(
707    loc,
708    &mt_entry->mt_fs_root->location
709  );
710}
711
712static inline const char *rtems_filesystem_eval_path_get_path(
713  const rtems_filesystem_eval_path_context_t *ctx
714)
715{
716  return ctx->path;
717}
718
719static inline size_t rtems_filesystem_eval_path_get_pathlen(
720  const rtems_filesystem_eval_path_context_t *ctx
721)
722{
723  return ctx->pathlen;
724}
725
726static inline void rtems_filesystem_eval_path_set_path(
727  rtems_filesystem_eval_path_context_t *ctx,
728  const char *path,
729  size_t pathlen
730)
731{
732  ctx->path = path;
733  ctx->pathlen = pathlen;
734}
735
736static inline void rtems_filesystem_eval_path_clear_path(
737  rtems_filesystem_eval_path_context_t *ctx
738)
739{
740  ctx->pathlen = 0;
741}
742
743static inline const char *rtems_filesystem_eval_path_get_token(
744  const rtems_filesystem_eval_path_context_t *ctx
745)
746{
747  return ctx->token;
748}
749
750static inline size_t rtems_filesystem_eval_path_get_tokenlen(
751  const rtems_filesystem_eval_path_context_t *ctx
752)
753{
754  return ctx->tokenlen;
755}
756
757static inline void rtems_filesystem_eval_path_set_token(
758  rtems_filesystem_eval_path_context_t *ctx,
759  const char *token,
760  size_t tokenlen
761)
762{
763  ctx->token = token;
764  ctx->tokenlen = tokenlen;
765}
766
767static inline void rtems_filesystem_eval_path_clear_token(
768  rtems_filesystem_eval_path_context_t *ctx
769)
770{
771  ctx->tokenlen = 0;
772}
773
774static inline void rtems_filesystem_eval_path_put_back_token(
775  rtems_filesystem_eval_path_context_t *ctx
776)
777{
778  size_t tokenlen = ctx->tokenlen;
779
780  ctx->path -= tokenlen;
781  ctx->pathlen += tokenlen;
782  ctx->tokenlen = 0;
783}
784
785void rtems_filesystem_eval_path_eat_delimiter(
786  rtems_filesystem_eval_path_context_t *ctx
787);
788
789void rtems_filesystem_eval_path_next_token(
790  rtems_filesystem_eval_path_context_t *ctx
791);
792
793static inline void rtems_filesystem_eval_path_get_next_token(
794  rtems_filesystem_eval_path_context_t *ctx,
795  const char **token,
796  size_t *tokenlen
797)
798{
799  rtems_filesystem_eval_path_next_token(ctx);
800  *token = ctx->token;
801  *tokenlen = ctx->tokenlen;
802}
803
804static inline rtems_filesystem_location_info_t *
805rtems_filesystem_eval_path_get_currentloc(
806  rtems_filesystem_eval_path_context_t *ctx
807)
808{
809  return &ctx->currentloc;
810}
811
812static inline bool rtems_filesystem_eval_path_has_path(
813  const rtems_filesystem_eval_path_context_t *ctx
814)
815{
816  return ctx->pathlen > 0;
817}
818
819static inline bool rtems_filesystem_eval_path_has_token(
820  const rtems_filesystem_eval_path_context_t *ctx
821)
822{
823  return ctx->tokenlen > 0;
824}
825
826static inline int rtems_filesystem_eval_path_get_flags(
827  const rtems_filesystem_eval_path_context_t *ctx
828)
829{
830  return ctx->flags;
831}
832
833static inline void rtems_filesystem_eval_path_set_flags(
834  rtems_filesystem_eval_path_context_t *ctx,
835  int flags
836)
837{
838  ctx->flags = flags;
839}
840
841static inline void rtems_filesystem_eval_path_clear_and_set_flags(
842  rtems_filesystem_eval_path_context_t *ctx,
843  int clear,
844  int set
845)
846{
847  int flags = ctx->flags;
848
849  flags &= ~clear;
850  flags |= set;
851
852  ctx->flags = flags;
853}
854
855static inline void rtems_filesystem_eval_path_extract_currentloc(
856  rtems_filesystem_eval_path_context_t *ctx,
857  rtems_filesystem_location_info_t *get
858)
859{
860  rtems_filesystem_location_copy_and_detach(
861    get,
862    &ctx->currentloc
863  );
864}
865
866void rtems_filesystem_eval_path_error(
867  rtems_filesystem_eval_path_context_t *ctx,
868  int eno
869);
870
871/**
872 * @brief Checks that the locations exist in the same file system instance.
873 *
874 * @retval 0 The locations exist and are in the same file system instance.
875 * @retval -1 An error occurred.  The @c errno indicates the error.
876 */
877int rtems_filesystem_location_exists_in_same_instance_as(
878  const rtems_filesystem_location_info_t *a,
879  const rtems_filesystem_location_info_t *b
880);
881
882/**
883 * @brief Checks if access to an object is allowed for the current user.
884 *
885 * If the effective UID is zero or equals the UID of the object, then the user
886 * permission flags of the object will be used.  Otherwise if the effective GID
887 * is zero or equals the GID of the object or one of the supplementary group
888 * IDs is equal to the GID of the object, then the group permission flags of
889 * the object will be used.  Otherwise the other permission flags of the object
890 * will be used.
891 *
892 * @param[in] flags The flags determining the access type.  It can be
893 *   RTEMS_FS_PERMS_READ, RTEMS_FS_PERMS_WRITE or RTEMS_FS_PERMS_EXEC.
894 * @param[in] object_mode The mode of the object specifying the permission flags.
895 * @param[in] object_uid The UID of the object.
896 * @param[in] object_gid The GID of the object.
897 *
898 * @retval true Access is allowed.
899 * @retval false Otherwise.
900 */
901bool rtems_filesystem_check_access(
902  int flags,
903  mode_t object_mode,
904  uid_t object_uid,
905  gid_t object_gid
906);
907
908bool rtems_filesystem_eval_path_check_access(
909  rtems_filesystem_eval_path_context_t *ctx,
910  int eval_flags,
911  mode_t node_mode,
912  uid_t node_uid,
913  gid_t node_gid
914);
915
916static inline bool rtems_filesystem_is_delimiter(char c)
917{
918  return c == '/' || c == '\\';
919}
920
921static inline bool rtems_filesystem_is_current_directory(
922  const char *token,
923  size_t tokenlen
924)
925{
926  return tokenlen == 1 && token [0] == '.';
927}
928
929static inline bool rtems_filesystem_is_parent_directory(
930  const char *token,
931  size_t tokenlen
932)
933{
934  return tokenlen == 2 && token [0] == '.' && token [1] == '.';
935}
936
937typedef ssize_t ( *rtems_libio_iovec_adapter )(
938  rtems_libio_t      *iop,
939  const struct iovec *iov,
940  int                 iovcnt,
941  ssize_t             total
942);
943
944static inline ssize_t rtems_libio_iovec_eval(
945  int                        fd,
946  const struct iovec        *iov,
947  int                        iovcnt,
948  unsigned int               flags,
949  rtems_libio_iovec_adapter  adapter
950)
951{
952  ssize_t        total;
953  int            v;
954  rtems_libio_t *iop;
955
956  /*
957   *  Argument validation on IO vector
958   */
959  if ( iov == NULL )
960    rtems_set_errno_and_return_minus_one( EINVAL );
961
962  if ( iovcnt <= 0 )
963    rtems_set_errno_and_return_minus_one( EINVAL );
964
965  if ( iovcnt > IOV_MAX )
966    rtems_set_errno_and_return_minus_one( EINVAL );
967
968  /*
969   *  OpenGroup says that you are supposed to return EINVAL if the
970   *  sum of the iov_len values in the iov array would overflow a
971   *  ssize_t.
972   */
973  total = 0;
974  for ( v = 0 ; v < iovcnt ; ++v ) {
975    size_t len = iov[ v ].iov_len;
976
977    if ( len > ( size_t ) ( SSIZE_MAX - total ) ) {
978      rtems_set_errno_and_return_minus_one( EINVAL );
979    }
980
981    total += ( ssize_t ) len;
982
983    if ( iov[ v ].iov_base == NULL && len != 0 ) {
984      rtems_set_errno_and_return_minus_one( EINVAL );
985    }
986  }
987
988  LIBIO_GET_IOP_WITH_ACCESS( fd, iop, flags, EBADF );
989
990  if ( total > 0 ) {
991    total = ( *adapter )( iop, iov, iovcnt, total );
992  }
993
994  rtems_libio_iop_drop( iop );
995  return total;
996}
997
998/**
999 * @brief Returns the file type of the file referenced by the filesystem
1000 * location.
1001 *
1002 * @brief[in] loc The filesystem location.
1003 *
1004 * @return The type of the file or an invalid file type in case of an error.
1005 */
1006static inline mode_t rtems_filesystem_location_type(
1007  const rtems_filesystem_location_info_t *loc
1008)
1009{
1010  struct stat st;
1011
1012  st.st_mode = 0;
1013  (void) ( *loc->handlers->fstat_h )( loc, &st );
1014
1015  return st.st_mode;
1016}
1017
1018/** @} */
1019
1020#ifdef __cplusplus
1021}
1022#endif
1023
1024#endif
1025/* end of include file */
Note: See TracBrowser for help on using the repository browser.