RTEMS  5.1
libio_.h
Go to the documentation of this file.
1 
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
35 extern "C" {
36 #endif
37 
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 
61 extern const uint32_t rtems_libio_number_iops;
62 extern rtems_libio_t rtems_libio_iops[];
63 extern void *rtems_libio_iop_free_head;
64 extern void **rtems_libio_iop_free_tail;
65 
66 extern const rtems_filesystem_file_handlers_r rtems_filesystem_null_handlers;
67 
68 extern rtems_filesystem_mount_table_entry_t rtems_filesystem_null_mt_entry;
69 
86 
95 static 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 
111 static 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 
128 static inline rtems_libio_t *rtems_libio_iop( int fd )
129 {
130  return &rtems_libio_iops[ fd ];
131 }
132 
140 static 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 
154 static 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 
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 
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 
296 );
297 
311 
312 /*
313  * External structures
314  */
315 #include <rtems/userenv.h>
316 
317 void rtems_libio_lock( void );
318 
319 void rtems_libio_unlock( void );
320 
321 static inline void rtems_filesystem_mt_lock( void )
322 {
323  rtems_libio_lock();
324 }
325 
326 static inline void rtems_filesystem_mt_unlock( void )
327 {
328  rtems_libio_unlock();
329 }
330 
331 extern 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 
342 static inline void rtems_filesystem_instance_lock(
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 
351 static inline void rtems_filesystem_instance_unlock(
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 
369 
373 unsigned int rtems_libio_fcntl_flags( int fcntl_flags );
374 
378 int rtems_libio_to_fcntl_flags( unsigned int flags );
379 
384 void rtems_libio_free(
385  rtems_libio_t *iop
386 );
387 
388 /*
389  * File System Routine Prototypes
390  */
391 
393 rtems_filesystem_eval_path_start(
395  const char *path,
396  int eval_flags
397 );
398 
400 rtems_filesystem_eval_path_start_with_parent(
402  const char *path,
403  int eval_flags,
405  int parent_eval_flags
406 );
407 
409 rtems_filesystem_eval_path_start_with_root_and_current(
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 
418 void rtems_filesystem_eval_path_continue(
420 );
421 
422 void rtems_filesystem_eval_path_cleanup(
424 );
425 
426 void rtems_filesystem_eval_path_recursive(
428  const char *path,
429  size_t pathlen
430 );
431 
432 void rtems_filesystem_eval_path_cleanup_with_parent(
435 );
436 
452  rtems_filesystem_global_location_t **newstartloc_ptr
453 );
454 
455 typedef 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 
474  void *arg
475 );
476 
489 typedef rtems_filesystem_eval_path_generic_status
492  void *arg,
493  const char *token,
494  size_t tokenlen
495 );
496 
497 typedef struct {
501 
502 void rtems_filesystem_eval_path_generic(
504  void *arg,
506 );
507 
508 void rtems_filesystem_initialize(void);
509 
526 );
527 
528 static inline rtems_filesystem_location_info_t *
529 rtems_filesystem_location_initialize_to_null(
531 )
532 {
534  loc,
536  );
537 }
538 
540 rtems_filesystem_location_transform_to_global(
542 );
543 
552  rtems_filesystem_global_location_t **lhs_global_loc_ptr,
553  rtems_filesystem_global_location_t *rhs_global_loc
554 );
555 
576  rtems_filesystem_global_location_t *const *global_loc_ptr
577 );
578 
598  bool deferred
599 );
600 
601 void rtems_filesystem_location_detach(
603 );
604 
605 void rtems_filesystem_location_copy_and_detach(
608 );
609 
611 rtems_filesystem_global_location_obtain_null(void)
612 {
614 
615  return rtems_filesystem_global_location_obtain( &global_loc );
616 }
617 
618 static inline bool rtems_filesystem_location_is_null(
620 )
621 {
622  return loc->handlers == &rtems_filesystem_null_handlers;
623 }
624 
625 static 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 
632 static inline void rtems_filesystem_location_error(
634  int eno
635 )
636 {
637  if ( !rtems_filesystem_location_is_null( loc ) ) {
638  errno = eno;
639  }
640 }
641 
642 int 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 
650 int rtems_filesystem_chdir( rtems_filesystem_location_info_t *loc );
651 
652 int rtems_filesystem_chmod(
654  mode_t mode
655 );
656 
657 int rtems_filesystem_chown(
659  uid_t owner,
660  gid_t group
661 );
662 
663 static inline bool rtems_filesystem_is_ready_for_unmount(
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 
678 static inline void rtems_filesystem_location_add_to_mt_entry(
680 )
681 {
682  rtems_filesystem_mt_entry_declare_lock_context( lock_context );
683 
684  rtems_filesystem_mt_entry_lock( lock_context );
686  &loc->mt_entry->location_chain,
687  &loc->mt_entry_node
688  );
689  rtems_filesystem_mt_entry_unlock( lock_context );
690 }
691 
692 void rtems_filesystem_location_remove_from_mt_entry(
694 );
695 
696 void rtems_filesystem_do_unmount(
698 );
699 
700 static inline bool rtems_filesystem_location_is_instance_root(
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 
712 static inline const char *rtems_filesystem_eval_path_get_path(
714 )
715 {
716  return ctx->path;
717 }
718 
719 static inline size_t rtems_filesystem_eval_path_get_pathlen(
721 )
722 {
723  return ctx->pathlen;
724 }
725 
726 static inline void rtems_filesystem_eval_path_set_path(
728  const char *path,
729  size_t pathlen
730 )
731 {
732  ctx->path = path;
733  ctx->pathlen = pathlen;
734 }
735 
736 static inline void rtems_filesystem_eval_path_clear_path(
738 )
739 {
740  ctx->pathlen = 0;
741 }
742 
743 static inline const char *rtems_filesystem_eval_path_get_token(
745 )
746 {
747  return ctx->token;
748 }
749 
750 static inline size_t rtems_filesystem_eval_path_get_tokenlen(
752 )
753 {
754  return ctx->tokenlen;
755 }
756 
757 static inline void rtems_filesystem_eval_path_set_token(
759  const char *token,
760  size_t tokenlen
761 )
762 {
763  ctx->token = token;
764  ctx->tokenlen = tokenlen;
765 }
766 
767 static inline void rtems_filesystem_eval_path_clear_token(
769 )
770 {
771  ctx->tokenlen = 0;
772 }
773 
774 static inline void rtems_filesystem_eval_path_put_back_token(
776 )
777 {
778  size_t tokenlen = ctx->tokenlen;
779 
780  ctx->path -= tokenlen;
781  ctx->pathlen += tokenlen;
782  ctx->tokenlen = 0;
783 }
784 
785 void rtems_filesystem_eval_path_eat_delimiter(
787 );
788 
789 void rtems_filesystem_eval_path_next_token(
791 );
792 
793 static inline void rtems_filesystem_eval_path_get_next_token(
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 
804 static inline rtems_filesystem_location_info_t *
805 rtems_filesystem_eval_path_get_currentloc(
807 )
808 {
809  return &ctx->currentloc;
810 }
811 
812 static inline bool rtems_filesystem_eval_path_has_path(
814 )
815 {
816  return ctx->pathlen > 0;
817 }
818 
819 static inline bool rtems_filesystem_eval_path_has_token(
821 )
822 {
823  return ctx->tokenlen > 0;
824 }
825 
826 static inline int rtems_filesystem_eval_path_get_flags(
828 )
829 {
830  return ctx->flags;
831 }
832 
833 static inline void rtems_filesystem_eval_path_set_flags(
835  int flags
836 )
837 {
838  ctx->flags = flags;
839 }
840 
841 static inline void rtems_filesystem_eval_path_clear_and_set_flags(
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 
855 static inline void rtems_filesystem_eval_path_extract_currentloc(
858 )
859 {
860  rtems_filesystem_location_copy_and_detach(
861  get,
862  &ctx->currentloc
863  );
864 }
865 
866 void rtems_filesystem_eval_path_error(
868  int eno
869 );
870 
880 );
881 
902  int flags,
903  mode_t object_mode,
904  uid_t object_uid,
905  gid_t object_gid
906 );
907 
908 bool rtems_filesystem_eval_path_check_access(
910  int eval_flags,
911  mode_t node_mode,
912  uid_t node_uid,
913  gid_t node_gid
914 );
915 
916 static inline bool rtems_filesystem_is_delimiter(char c)
917 {
918  return c == '/' || c == '\\';
919 }
920 
921 static 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 
929 static 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 
937 typedef 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 
944 static 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 )
961 
962  if ( iovcnt <= 0 )
964 
965  if ( iovcnt > IOV_MAX )
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 ) ) {
979  }
980 
981  total += ( ssize_t ) len;
982 
983  if ( iov[ v ].iov_base == NULL && len != 0 ) {
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 
1006 static inline mode_t rtems_filesystem_location_type(
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 
1020 #ifdef __cplusplus
1021 }
1022 #endif
1023 
1024 #endif
1025 /* end of include file */
RTEMS_INLINE_ROUTINE bool rtems_chain_has_only_one_node(const rtems_chain_control *the_chain)
Does this chain have only one node.
Definition: chain.h:522
#define LIBIO_GET_IOP_WITH_ACCESS(_fd, _iop, _access_flags, _access_error)
Macro to get the iop for the specified file descriptor with access flags and error.
Definition: libio_.h:234
const char * token
Definition: libio.h:99
RTEMS_INLINE_ROUTINE void rtems_chain_initialize_empty(rtems_chain_control *the_chain)
Initialize this chain as empty.
Definition: chain.h:168
int rtems_filesystem_location_exists_in_same_instance_as(const rtems_filesystem_location_info_t *a, const rtems_filesystem_location_info_t *b)
Checks that the locations exist in the same file system instance.
Definition: sup_fs_exist_in_same_instance.c:28
Definition: deflate.c:115
void rtems_filesystem_global_location_release(rtems_filesystem_global_location_t *global_loc, bool deferred)
Releases a global file system location.
Definition: sup_fs_location.c:186
Basic IO API.
Data which Ease the Burden of Consistently Setting Errno.
User Environment Support.
int flags
Definition: libio.h:119
int rtems_libio_to_fcntl_flags(unsigned int flags)
Definition: libio.c:86
POSIX Threads Private Support.
rtems_filesystem_global_location_t rtems_filesystem_global_location_null
The global null location.
Definition: __usrenv.c:229
Definition: if_em.h:352
void rtems_libio_free(rtems_libio_t *iop)
Definition: libio.c:133
void rtems_filesystem_global_location_assign(rtems_filesystem_global_location_t **lhs_global_loc_ptr, rtems_filesystem_global_location_t *rhs_global_loc)
Assigns a global file system location.
Definition: sup_fs_location.c:96
size_t tokenlen
Definition: libio.h:105
ISR lock control.
Definition: isrlock.h:56
File system node operations table.
Definition: libio.h:1005
RTEMS_INLINE_ROUTINE void rtems_chain_append_unprotected(rtems_chain_control *the_chain, rtems_chain_node *the_node)
Append a node on the end of a chain (unprotected).
Definition: chain.h:679
Information for the Assert Handler.
void rtems_filesystem_location_clone(rtems_filesystem_location_info_t *clone, const rtems_filesystem_location_info_t *master)
Clones a node.
Definition: clonenode.c:28
bool(* rtems_filesystem_eval_path_is_directory)(rtems_filesystem_eval_path_context_t *ctx, void *arg)
Tests if the current location is a directory.
Definition: libio_.h:472
rtems_filesystem_location_info_t currentloc
Definition: libio.h:135
void rtems_filesystem_location_free(rtems_filesystem_location_info_t *loc)
Releases all resources of a location.
Definition: freenode.c:25
rtems_filesystem_eval_path_generic_status(* rtems_filesystem_eval_path_eval_token)(rtems_filesystem_eval_path_context_t *ctx, void *arg, const char *token, size_t tokenlen)
Evaluates a token.
Definition: libio_.h:490
Mount table entry.
Definition: libio.h:1604
Path evaluation context.
Definition: libio.h:84
unsigned int rtems_libio_fcntl_flags(int fcntl_flags)
Definition: libio.c:61
An open file data structure.
Definition: libio.h:1320
bool rtems_filesystem_check_access(int flags, mode_t object_mode, uid_t object_uid, gid_t object_gid)
Checks if access to an object is allowed for the current user.
Definition: sup_fs_check_permissions.c:89
const char * path
Definition: libio.h:88
rtems_libio_t * rtems_libio_allocate(void)
Definition: libio.c:109
rtems_filesystem_global_location_t * rtems_filesystem_global_location_obtain(rtems_filesystem_global_location_t *const *global_loc_ptr)
Obtains a global file system location.
Definition: sup_fs_location.c:163
#define rtems_set_errno_and_return_minus_one(_error)
Definition: seterr.h:48
size_t pathlen
Definition: libio.h:93
unsigned v
Definition: tte.h:73
void rtems_filesystem_eval_path_restart(rtems_filesystem_eval_path_context_t *ctx, rtems_filesystem_global_location_t **newstartloc_ptr)
Requests a path evaluation restart.
Definition: sup_fs_eval_path.c:317
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:100
rtems_filesystem_location_info_t * rtems_filesystem_location_copy(rtems_filesystem_location_info_t *dst, const rtems_filesystem_location_info_t *src)
Copies a location.
Global file system location.
Definition: fs.h:81
void rtems_filesystem_initialize(void)
Base File System Initialization.
Definition: base_fs.c:32
#define NULL
Requests a GPIO pin group configuration.
Definition: bestcomm_api.h:77
File system location.
Definition: fs.h:53