summaryrefslogtreecommitdiffstats
path: root/cpukit/include/rtems/imfs.h
blob: 57c498cfe89a3679b4ed906746b2f6c864566798 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
/* SPDX-License-Identifier: BSD-2-Clause */

/**
 * @file
 *
 * @brief Header File for the In-Memory File System
 */

/*
 * COPYRIGHT (C) 1989, 2021 On-Line Applications Research Corporation (OAR).
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _RTEMS_IMFS_H
#define _RTEMS_IMFS_H

#include <sys/time.h>
#include <limits.h>

#include <rtems/libio_.h>
#include <rtems/pipe.h>
#include <rtems/score/timecounter.h>

/**
 * @brief In-Memory File System Support.
 *
 * @defgroup IMFS In-Memory File System Support
 *
 * @ingroup FileSystemTypesAndMount
 */
/**@{*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 *  Data types
 */

struct IMFS_jnode_tt;
typedef struct IMFS_jnode_tt IMFS_jnode_t;

/**
 *  IMFS "memfile" information
 *
 *  The data structure for the in-memory "memfiles" is based on classic UNIX.
 *
 *  block_ptr is a pointer to a block of IMFS_MEMFILE_BYTES_PER_BLOCK in
 *  length which could be data or a table of pointers to blocks.
 *
 *  Setting IMFS_MEMFILE_BYTES_PER_BLOCK to different values has a significant
 *  impact on the maximum file size supported as well as the amount of
 *  memory wasted due to internal file fragmentation.  The following
 *  is a list of maximum file sizes based on various settings
 *
 *  @code
 *    max_filesize with blocks of   16 is         1,328
 *    max_filesize with blocks of   32 is        18,656
 *    max_filesize with blocks of   64 is       279,488
 *    max_filesize with blocks of  128 is     4,329,344
 *    max_filesize with blocks of  256 is    68,173,568
 *    max_filesize with blocks of  512 is 1,082,195,456
 *  @endcode
 */
#define IMFS_MEMFILE_DEFAULT_BYTES_PER_BLOCK     128
  extern const int imfs_memfile_bytes_per_block;

#define IMFS_MEMFILE_BYTES_PER_BLOCK imfs_memfile_bytes_per_block
#define IMFS_MEMFILE_BLOCK_SLOTS \
  (IMFS_MEMFILE_BYTES_PER_BLOCK / sizeof(void *))

typedef uint8_t *block_p;
typedef block_p *block_ptr;

/*
 *  Important block numbers for "memfiles"
 */
#define FIRST_INDIRECT           (0)
#define LAST_INDIRECT            (IMFS_MEMFILE_BLOCK_SLOTS - 1)

#define FIRST_DOUBLY_INDIRECT    (LAST_INDIRECT + 1)
#define LAST_DOUBLY_INDIRECT     \
   (LAST_INDIRECT + \
     (IMFS_MEMFILE_BLOCK_SLOTS * IMFS_MEMFILE_BLOCK_SLOTS))

#define FIRST_TRIPLY_INDIRECT    (LAST_DOUBLY_INDIRECT + 1)
#define LAST_TRIPLY_INDIRECT \
   (LAST_DOUBLY_INDIRECT +\
     (IMFS_MEMFILE_BLOCK_SLOTS * \
        IMFS_MEMFILE_BLOCK_SLOTS * IMFS_MEMFILE_BLOCK_SLOTS))

#define IMFS_MEMFILE_MAXIMUM_SIZE \
  (LAST_TRIPLY_INDIRECT * IMFS_MEMFILE_BYTES_PER_BLOCK)

/** @} */

/**
 * @addtogroup IMFSGenericNodes
 */
/**@{*/

/**
 * @brief Initializes an IMFS node.
 *
 * @param[in] node The IMFS node.
 * @param[in] arg The user provided argument pointer.  It may contain node
 *   specific initialization information.
 *
 * @retval node Successful operation.
 * @retval NULL An error occurred.  The @c errno indicates the error.  This
 * will abort the make operation.
 *
 * @see IMFS_node_control, IMFS_node_initialize_default(), and
 * IMFS_node_initialize_generic().
 */
typedef IMFS_jnode_t *(*IMFS_node_control_initialize)(
  IMFS_jnode_t *node,
  void *arg
);

/**
 * @brief Returns the node and does nothing else.
 *
 * @param[in] node The IMFS node.
 * @param[in] arg The user provided argument pointer.  It is not used.
 *
 * @retval node Returns always the node passed as parameter.
 *
 * @see IMFS_node_control.
 */
IMFS_jnode_t *IMFS_node_initialize_default(
  IMFS_jnode_t *node,
  void *arg
);

IMFS_jnode_t *IMFS_node_initialize_directory(
  IMFS_jnode_t *node,
  void *arg
);

/**
 * @brief Returns the node and sets the generic node context.
 *
 * @param[in] node The IMFS node.
 * @param[in] arg The user provided argument pointer.  It must contain the
 *   generic context.
 *
 * @retval node Returns always the node passed as parameter.
 *
 * @see IMFS_node_control.
 */
IMFS_jnode_t *IMFS_node_initialize_generic(
  IMFS_jnode_t *node,
  void *arg
);

/**
 * @brief Prepares the removal of an IMFS node from its parent directory.
 *
 * @param[in] node The IMFS node.
 *
 * @retval node Successful operation.
 * @retval NULL An error occurred.  The @c errno indicates the error.  This
 * will abort the removal operation.
 *
 * @see IMFS_node_control and IMFS_node_remove_default().
 */
typedef IMFS_jnode_t *(*IMFS_node_control_remove)(
  IMFS_jnode_t *node
);

/**
 * @brief Returns the node and does nothing else.
 *
 * @param[in] node The IMFS node.
 *
 * @retval node Returns always the node passed as parameter.
 *
 * @see IMFS_node_control.
 */
IMFS_jnode_t *IMFS_node_remove_default(
  IMFS_jnode_t *node
);

IMFS_jnode_t *IMFS_node_remove_directory( IMFS_jnode_t *node );

/**
 * @brief Destroys an IMFS node.
 *
 * @param[in] node The IMFS node.
 *
 * @see IMFS_node_control and IMFS_node_destroy_default().
 */
typedef void (*IMFS_node_control_destroy)( IMFS_jnode_t *node );

/**
 * @brief Frees the node.
 *
 * @param[in] node The IMFS node.
 *
 * @see IMFS_node_control.
 */
void IMFS_node_destroy_default( IMFS_jnode_t *node );

/**
 * @brief Does nothing.
 *
 * @param node The IMFS node.
 *
 * @see IMFS_node_control.
 */
void IMFS_do_nothing_destroy( IMFS_jnode_t *node );

/**
 * @brief IMFS node control.
 */
typedef struct {
  const rtems_filesystem_file_handlers_r *handlers;
  IMFS_node_control_initialize node_initialize;
  IMFS_node_control_remove node_remove;
  IMFS_node_control_destroy node_destroy;
} IMFS_node_control;

typedef struct {
  IMFS_node_control node_control;
  size_t node_size;
} IMFS_mknod_control;

/** @} */

/**
 * @addtogroup IMFS
 */
/**@{*/

/*
 *  Maximum length of a "basename" of an IMFS file/node.
 */

#define IMFS_NAME_MAX _POSIX_NAME_MAX

/*

 *  The control structure for an IMFS jnode.
 */

struct IMFS_jnode_tt {
  rtems_chain_node    Node;                  /* for chaining them together */
  IMFS_jnode_t       *Parent;                /* Parent node */
  const char         *name;                  /* "basename" (not \0 terminated) */
  uint16_t            namelen;               /* Length of "basename" */
  mode_t              st_mode;               /* File mode */
  unsigned short      reference_count;
  nlink_t             st_nlink;              /* Link count */

  uid_t               st_uid;                /* User ID of owner */
  gid_t               st_gid;                /* Group ID of owner */

  time_t              stat_atime;            /* Time of last access */
  time_t              stat_mtime;            /* Time of last modification */
  time_t              stat_ctime;            /* Time of last status change */
  const IMFS_node_control *control;
};

typedef struct {
  IMFS_jnode_t                          Node;
  rtems_chain_control                   Entries;
  rtems_filesystem_mount_table_entry_t *mt_fs;
} IMFS_directory_t;

typedef struct {
  IMFS_jnode_t              Node;
  rtems_device_major_number major;
  rtems_device_minor_number minor;
} IMFS_device_t;

typedef struct {
  IMFS_jnode_t  Node;
  IMFS_jnode_t *link_node;
} IMFS_link_t;

typedef struct {
  IMFS_jnode_t  Node;
  char         *name;
} IMFS_sym_link_t;

typedef struct {
  IMFS_jnode_t Node;
  size_t       size;             /* size of file in bytes */
} IMFS_filebase_t;

typedef struct {
  IMFS_filebase_t File;
  block_ptr       indirect;         /* array of 128 data blocks pointers */
  block_ptr       doubly_indirect;  /* 128 indirect blocks */
  block_ptr       triply_indirect;  /* 128 doubly indirect blocks */
} IMFS_memfile_t;

typedef struct {
  IMFS_filebase_t File;
  block_p         direct;           /* pointer to file image */
} IMFS_linearfile_t;

/* Support copy on write for linear files */
typedef union {
  IMFS_jnode_t      Node;
  IMFS_filebase_t   File;
  IMFS_memfile_t    Memfile;
  IMFS_linearfile_t Linearfile;
} IMFS_file_t;

typedef struct {
  IMFS_jnode_t    Node;
  pipe_control_t *pipe;
} IMFS_fifo_t;

typedef struct {
  IMFS_jnode_t  Node;
  void         *context;
} IMFS_generic_t;

typedef struct {
  const void *data;
  size_t      size;
} IMFS_linearfile_context;

static inline IMFS_jnode_t *IMFS_iop_to_node( const rtems_libio_t *iop )
{
  return (IMFS_jnode_t *) iop->pathinfo.node_access;
}

static inline IMFS_directory_t *IMFS_iop_to_directory(
  const rtems_libio_t *iop
)
{
  return (IMFS_directory_t *) iop->pathinfo.node_access;
}

static inline IMFS_device_t *IMFS_iop_to_device( const rtems_libio_t *iop )
{
  return (IMFS_device_t *) iop->pathinfo.node_access;
}

static inline IMFS_file_t *IMFS_iop_to_file( const rtems_libio_t *iop )
{
  return (IMFS_file_t *) iop->pathinfo.node_access;
}

static inline IMFS_memfile_t *IMFS_iop_to_memfile( const rtems_libio_t *iop )
{
  return (IMFS_memfile_t *) iop->pathinfo.node_access;
}

static inline time_t _IMFS_get_time( void )
{
  struct bintime now;

  /* Use most efficient way to get the time in seconds (CLOCK_REALTIME) */
  _Timecounter_Getbintime( &now );

  return now.sec;
}

static inline void IMFS_update_atime( IMFS_jnode_t *jnode )
{
  jnode->stat_atime = _IMFS_get_time();
}

static inline void IMFS_update_mtime( IMFS_jnode_t *jnode )
{
  jnode->stat_mtime = _IMFS_get_time();
}

static inline void IMFS_update_ctime( IMFS_jnode_t *jnode )
{
  jnode->stat_ctime = _IMFS_get_time();
}

static inline void IMFS_mtime_ctime_update( IMFS_jnode_t *jnode )
{
  time_t now;

  now = _IMFS_get_time();

  jnode->stat_mtime = now;
  jnode->stat_ctime = now;
}

typedef struct {
  const IMFS_mknod_control *directory;
  const IMFS_mknod_control *device;
  const IMFS_mknod_control *file;
  const IMFS_mknod_control *fifo;
} IMFS_mknod_controls;

typedef struct {
  IMFS_directory_t Root_directory;
  const IMFS_mknod_controls *mknod_controls;
} IMFS_fs_info_t;

typedef struct {
  IMFS_fs_info_t *fs_info;
  const rtems_filesystem_operations_table *ops;
  const IMFS_mknod_controls *mknod_controls;
} IMFS_mount_data;

/*
 *  Shared Data
 */

extern const IMFS_mknod_control IMFS_mknod_control_dir_default;
extern const IMFS_mknod_control IMFS_mknod_control_dir_minimal;
extern const IMFS_mknod_control IMFS_mknod_control_device;
extern const IMFS_mknod_control IMFS_mknod_control_memfile;
extern const IMFS_node_control IMFS_node_control_linfile;
extern const IMFS_mknod_control IMFS_mknod_control_fifo;
extern const IMFS_mknod_control IMFS_mknod_control_enosys;

extern const rtems_filesystem_limits_and_options_t  IMFS_LIMITS_AND_OPTIONS;

/*
 *  Routines
 */

extern int IMFS_initialize(
   rtems_filesystem_mount_table_entry_t *mt_entry,
   const void                           *data
);

extern int IMFS_initialize_support(
  rtems_filesystem_mount_table_entry_t *mt_entry,
  const void                           *data
);

/**
 * @brief Unmount this instance of IMFS.
 */
extern void IMFS_fsunmount(
   rtems_filesystem_mount_table_entry_t *mt_entry
);

/**
 * @brief RTEMS load tarfs.
 * 
 * This file implements the "mount" procedure for tar-based IMFS
 * extensions.  The TAR is not actually mounted under the IMFS.
 * Directories from the TAR file are created as usual in the IMFS.
 * File entries are created as IMFS_LINEAR_FILE nodes with their nods
 * pointing to addresses in the TAR image.
 *
 * Here we create the mountpoint directory and load the tarfs at
 * that node.  Once the IMFS has been mounted, we work through the
 * tar image and perform as follows:
 *  - For directories, simply call mkdir().  The IMFS creates nodes as
 *    needed.
 *  - For files, we make our own calls to IMFS eval_for_make and
 *    create_node.
 * 
 * TAR file format:
 *
 * @code
 *   Offset   Length                 Contents
 *     0    100  bytes  File name ('\0' terminated, 99 maxmum length)
 *   100      8  bytes  File mode (in octal ascii)
 *   108      8  bytes  User ID (in octal ascii)
 *   116      8  bytes  Group ID (in octal ascii)
 *   124     12  bytes  File size (s) (in octal ascii)
 *   136     12  bytes  Modify time (in octal ascii)
 *   148      8  bytes  Header checksum (in octal ascii)
 *   156      1  bytes  Link flag
 *   157    100  bytes  Linkname ('\0' terminated, 99 maxmum length)
 *   257      8  bytes  Magic PAX ("ustar\0" + 2 bytes padding)
 *   257      8  bytes  Magic GNU tar ("ustar  \0")
 *   265     32  bytes  User name ('\0' terminated, 31 maxmum length)
 *   297     32  bytes  Group name ('\0' terminated, 31 maxmum length)
 *   329      8  bytes  Major device ID (in octal ascii)
 *   337      8  bytes  Minor device ID (in octal ascii)
 *   345    167  bytes  Padding
 *   512   (s+p) bytes  File contents (s+p) := (((s) + 511) & ~511),
 *                      round up to 512 bytes
 * @endcode
 *
 *  Checksum:
 *  @code
 *    int   i, sum;
 *    char *header = tar_header_pointer;
 *
 *    sum = 0;
 *    for (i = 0; i < 512; i++)
 *        sum += 0xFF & header[i];
 * @endcode
 */
extern int rtems_tarfs_load(
   const char *mountpoint,
   uint8_t *tar_image,
   size_t tar_size
);

/**
 * @brief Destroy an IMFS node.
 */
extern void IMFS_node_destroy( IMFS_jnode_t *node );

/**
 * @brief Clone an IMFS node.
 */
extern int IMFS_node_clone( rtems_filesystem_location_info_t *loc );

/**
 * @brief Free an IMFS node.
 */
extern void IMFS_node_free( const rtems_filesystem_location_info_t *loc );

/**
 * @brief Perform a status processing for the IMFS.
 * 
 * This routine provides a stat for the IMFS file system.
 */
extern int IMFS_stat(
  const rtems_filesystem_location_info_t *loc,
  struct stat *buf
);

extern int IMFS_stat_file(
  const rtems_filesystem_location_info_t *loc,
  struct stat *buf
);

/**
 * @brief IMFS evaluation node support.
 */
extern void IMFS_eval_path(
  rtems_filesystem_eval_path_context_t *ctx
);

/**
 * @brief IMFS device filesystem evaluation node support.
 */
extern void IMFS_eval_path_devfs(
  rtems_filesystem_eval_path_context_t *ctx
);

/**
 * @brief Create a new IMFS link node.
 * 
 * The following rouine creates a new link node under parent with the
 * name given in name.  The link node is set to point to the node at
 * to_loc.
 */
extern int IMFS_link(
  const rtems_filesystem_location_info_t *parentloc,
  const rtems_filesystem_location_info_t *targetloc,
  const char *name,
  size_t namelen
);

/**
 * @brief Change the owner of IMFS.
 * 
 * This routine is the implementation of the chown() system
 * call for the IMFS.
 */
extern int IMFS_chown(
  const rtems_filesystem_location_info_t *loc,
  uid_t owner,
  gid_t group
);

/**
 * @brief Create an IMFS node.
 * 
 * Routine to create a node in the IMFS file system.
 */
extern int IMFS_mknod(
  const rtems_filesystem_location_info_t *parentloc,
  const char *name,
  size_t namelen,
  mode_t mode,
  dev_t dev
);

extern IMFS_jnode_t *IMFS_initialize_node(
  IMFS_jnode_t *node,
  const IMFS_node_control *node_control,
  const char *name,
  size_t namelen,
  mode_t mode,
  void *arg
);

/**
 * @brief Create an IMFS node.
 * 
 * Create an IMFS filesystem node of an arbitrary type that is NOT
 * the root directory node.
 */
extern IMFS_jnode_t *IMFS_create_node(
  const rtems_filesystem_location_info_t *parentloc,
  const IMFS_node_control *node_control,
  size_t node_size,
  const char *name,
  size_t namelen,
  mode_t mode,
  void *arg
);

static inline bool IMFS_is_imfs_instance(
  const rtems_filesystem_location_info_t *loc
)
{
  return loc->mt_entry->ops->clonenod_h == IMFS_node_clone;
}

/**
 * @brief Initializer for an IMFS node control.
 *
 * @param handlers The file system node handlers.
 * @param init The node initialization method.
 * @param destroy The node destruction method.
 */
#define IMFS_NODE_CONTROL_INITIALIZER( handlers, init, destroy ) \
  { \
    ( handlers ), \
    ( init ), \
    IMFS_node_remove_default, \
    ( destroy ) \
  }

/**
 * @brief Initializer for an IMFS node.
 *
 * Initialize the node control with IMFS_NODE_CONTROL_INITIALIZER().
 *
 * @param node_control The node control of the IMFS node.
 * @param name The name of the IMFS node.
 * @param namelen The length of the name of the IMFS node.
 * @param mode The mode of the IMFS node.
 *
 * @see IMFS_node_preinitialize().
 */
#define IMFS_NODE_INITIALIZER( node_control, name, namelen, mode ) \
  { \
    { NULL, NULL }, \
    NULL, \
    ( name ), \
    ( namelen ), \
    ( mode ), \
    0, \
    0, \
    0, \
    0, \
    0, \
    0, \
    0, \
    ( node_control ) \
  }

/**
 * @brief Preinitializes an IMFS node.
 *
 * Initialize the node control with IMFS_NODE_CONTROL_INITIALIZER().
 *
 * @param node The IMFS node to preinitialize.
 * @param node_control The node control of the IMFS node.
 * @param name The name of the IMFS node.
 * @param namelen The length of the name of the IMFS node.
 * @param mode The mode of the IMFS node.
 *
 * @see IMFS_NODE_INITIALIZER().
 */
static inline void IMFS_node_preinitialize(
  IMFS_jnode_t            *node,
  const IMFS_node_control *node_control,
  const char              *name,
  size_t                   namelen,
  mode_t                   mode
)
{
  node->control = node_control;
  node->name = name;
  node->namelen = namelen;
  node->st_mode = mode;
}

/**
 * @brief Adds an IMFS node.
 *
 * Initialize the node with IMFS_NODE_INITIALIZER(), IMFS_node_preinitialize(),
 * IMFS_GENERIC_NODE_INITIALIZER(), or IMFS_generic_node_preinitialize().
 *
 * @param path The path of parent directories for the IMFS node to add.
 * @param node The IMFS node to add.
 * @param arg The argument passed to the node initialization method.
 *
 * @retval 0 Successful operation.
 * @retval -1 An error occurred.  The @c errno indicates the error.
 */
int IMFS_add_node( const char *path, IMFS_jnode_t *node, void *arg );

extern int IMFS_make_node(
  const char              *path,
  mode_t                   mode,
  const IMFS_node_control *node_control,
  size_t                   node_size,
  void                    *context
);

/**
 * @brief Makes a linear IMFS file.
 *
 * @param path The path to the new linear IMFS file.
 * @param mode The file mode permissions.  S_IFREG is set by the function.
 * @param data The begin of linear file data area.
 * @param size The size of the linear file data area in bytes.
 *
 * @retval 0 Successful operation.
 * @retval -1 An error occurred.  The @c errno indicates the error.
 */
extern int IMFS_make_linearfile(
  const char *path,
  mode_t      mode,
  const void *data,
  size_t      size
);

/** @} */

/**
 * @defgroup IMFSGenericNodes IMFS Generic Nodes
 *
 * @ingroup LibIO
 *
 * @brief Generic nodes are an alternative to standard drivers in RTEMS.
 *
 * The handlers of a generic node are called with less overhead compared to the
 * standard driver operations.  The usage of file system node handlers enable
 * more features like support for fsync() and fdatasync().  The generic nodes
 * use the reference counting of the IMFS.  This provides automatic node
 * destruction when the last reference vanishes.
 *
 * @{
 */

/* Provided for backward compatibility */
#define IMFS_GENERIC_INITIALIZER( handlers, init, destroy ) \
  IMFS_NODE_CONTROL_INITIALIZER( handlers, init, destroy )

/**
 * @brief Initializer for a generic node control.
 *
 * @param handlers The file system node handlers.
 * @param init The node initialization method.
 * @param destroy The node destruction method.
 */
#define IMFS_GENERIC_CONTROL_INITIALIZER( handlers, init, destroy ) \
  IMFS_NODE_CONTROL_INITIALIZER( handlers, init, destroy )

/**
 * @brief Initializer for a generic node.
 *
 * Initialize the node control with IMFS_GENERIC_CONTROL_INITIALIZER().
 *
 * @param node_control The node control of the IMFS generic node.
 * @param name The name of the IMFS generic node.
 * @param namelen The length of the name of the IMFS generic node.
 * @param mode The mode of the IMFS generic node.
 */
#define IMFS_GENERIC_NODE_INITIALIZER( node_control, name, namelen, mode ) \
  { IMFS_NODE_INITIALIZER( node_control, name, namelen, mode ), NULL }

/**
 * @brief Preinitializes a generic IMFS node.
 *
 * Initialize the node control with IMFS_GENERIC_CONTROL_INITIALIZER().
 *
 * @param node The generic IMFS node to preinitialize.
 * @param node_control The node control of the generic IMFS node.
 * @param name The name of the generic IMFS node.
 * @param namelen The length of the name of the generic IMFS node.
 * @param mode The mode of the generic IMFS node.
 *
 * @see IMFS_GENERIC_NODE_INITIALIZER().
 */
static inline void IMFS_generic_node_preinitialize(
  IMFS_generic_t          *node,
  const IMFS_node_control *node_control,
  const char              *name,
  size_t                   namelen,
  mode_t                   mode
)
{
  IMFS_node_preinitialize( &node->Node, node_control, name, namelen, mode );
}

/**
 * @brief Makes a generic IMFS node.
 *
 * @param[in] path The path to the new generic IMFS node.
 * @param[in] mode The node mode.
 * @param[in] node_control The node control.
 * @param[in] context The node control handler context.
 *
 * @retval 0 Successful operation.
 * @retval -1 An error occurred.  The @c errno indicates the error.
 *
 * @code
 * #include <sys/stat.h>
 * #include <assert.h>
 * #include <fcntl.h>
 *
 * #include <rtems/imfs.h>
 *
 * static const rtems_filesystem_file_handlers_r some_node_handlers = {
 *   ...
 * };
 *
 * static IMFS_jnode_t *some_node_init(IMFS_jnode_t *node, void *arg)
 * {
 *   void *context;
 *
 *   node = IMFS_node_initialize_generic(node, arg);
 *   context = IMFS_generic_get_context_by_node(node);
 *
 *   return node;
 * }
 *
 * static void some_node_destroy(IMFS_jnode_t *node)
 * {
 *   void *context = IMFS_generic_get_context_by_node(node);
 *
 *   IMFS_node_destroy_default(node);
 * }
 *
 * static const IMFS_node_control
 * some_node_control = IMFS_GENERIC_CONTROL_INITIALIZER(
 *   &some_node_handlers,
 *   some_node_init,
 *   some_node_destroy
 * );
 *
 * void example(void *some_node_context)
 * {
 *   int rv;
 *
 *   rv = IMFS_make_generic_node(
 *     "/path/to/some/generic/node",
 *     S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
 *     &some_node_control,
 *     some_node_context
 *   );
 *   assert(rv == 0);
 * }
 * @endcode
 */
extern int IMFS_make_generic_node(
  const char *path,
  mode_t mode,
  const IMFS_node_control *node_control,
  void *context
);

/** @} */

/**
 * @addtogroup IMFS
 */
/**@{*/

/**
 * @brief Mount an IMFS.
 */
extern int IMFS_mount(
  rtems_filesystem_mount_table_entry_t *mt_entry  /* IN */
);

/**
 * @brief Unmount an IMFS.
 */
extern int IMFS_unmount(
  rtems_filesystem_mount_table_entry_t *mt_entry  /* IN */
);

/**
 * @name IMFS Memory File Handlers
 *
 * This section contains the set of handlers used to process operations on
 * IMFS memory file nodes.  The memory files are created in memory using
 * malloc'ed memory.  Thus any data stored in one of these files is lost
 * at system shutdown unless special arrangements to copy the data to
 * some type of non-volailte storage are made by the application.
 */
/**@{*/

extern ssize_t IMFS_memfile_write(
  IMFS_memfile_t      *memfile,
  off_t                start,
  const unsigned char *source,
  unsigned int         length
);

/** @} */

/**
 * @name IMFS Device Node Handlers
 *
 * This section contains the set of handlers used to map operations on
 * IMFS device nodes onto calls to the RTEMS Classic API IO Manager.
 */
/**@{*/

extern int device_open(
  rtems_libio_t *iop,            /* IN  */
  const char    *pathname,       /* IN  */
  int            oflag,          /* IN  */
  mode_t         mode            /* IN  */
);

extern int device_close(
  rtems_libio_t *iop             /* IN  */
);

extern ssize_t device_read(
  rtems_libio_t *iop,            /* IN  */
  void          *buffer,         /* IN  */
  size_t         count           /* IN  */
);

extern ssize_t device_write(
  rtems_libio_t *iop,               /* IN  */
  const void    *buffer,            /* IN  */
  size_t         count              /* IN  */
);

extern int device_ioctl(
  rtems_libio_t   *iop,
  ioctl_command_t  command,
  void            *buffer
);

extern int device_ftruncate(
  rtems_libio_t *iop,               /* IN  */
  off_t          length             /* IN  */
);

/** @} */

/**
 * @brief Set IMFS file access and modification times.
 * 
 * 
 * This routine is the implementation of the utime() system
 * call for the IMFS.
 */
extern int IMFS_utimens(
  const rtems_filesystem_location_info_t *loc,
  struct timespec times[2]
);

/**
 * @brief Change the IMFS file mode.
 */
extern int IMFS_fchmod(
  const rtems_filesystem_location_info_t *loc,
  mode_t mode
);

/**
 * @brief Create a new IMFS symbolic link node.
 * 
 * The following rouine creates a new symbolic link node under parent
 * with the name given in name.  The node is set to point to the node at
 * to_loc.
 */
extern int IMFS_symlink(
  const rtems_filesystem_location_info_t *parentloc,
  const char *name,
  size_t namelen,
  const char *target
);

/**
 * @brief Put IMFS symbolic link into buffer.
 * 
 * The following rouine puts the symbolic links destination name into
 * buff.
 * 
 */
extern ssize_t IMFS_readlink(
  const rtems_filesystem_location_info_t *loc,
  char *buf,
  size_t bufsize
);

/**
 * @brief Rename the IMFS.
 * 
 * The following rouine creates a new link node under parent with the
 * name given in name and removes the old.
 */
extern int IMFS_rename(
  const rtems_filesystem_location_info_t *oldparentloc,
  const rtems_filesystem_location_info_t *oldloc,
  const rtems_filesystem_location_info_t *newparentloc,
  const char *name,
  size_t namelen
);
/**
 * @brief IMFS node removal handler.
 * 
 * This file contains the handler used to remove a node when a file type
 * does not require special actions.
 */
extern int IMFS_rmnod(
  const rtems_filesystem_location_info_t *parentloc,
  const rtems_filesystem_location_info_t *loc
);

/*
 *  Turn on IMFS assertions when RTEMS_DEBUG is defined.
 */
#ifdef RTEMS_DEBUG
  #include <assert.h>

  #define IMFS_assert(_x) assert(_x)
#else
  #define IMFS_assert(_x)
#endif

static inline void IMFS_Set_handlers( rtems_filesystem_location_info_t *loc )
{
  IMFS_jnode_t *node = (IMFS_jnode_t *) loc->node_access;

  loc->handlers = node->control->handlers;
}

static inline void IMFS_add_to_directory(
  IMFS_jnode_t *dir_node,
  IMFS_jnode_t *entry_node
)
{
  IMFS_directory_t *dir = (IMFS_directory_t *) dir_node;

  entry_node->Parent = dir_node;
  rtems_chain_append_unprotected( &dir->Entries, &entry_node->Node );
}

static inline void IMFS_remove_from_directory( IMFS_jnode_t *node )
{
  IMFS_assert( node->Parent != NULL );
  node->Parent = NULL;
  rtems_chain_extract_unprotected( &node->Node );
}

static inline bool IMFS_is_directory( const IMFS_jnode_t *node )
{
  return S_ISDIR( node->st_mode );
}

#define IMFS_STAT_FMT_HARD_LINK 0

static inline bool IMFS_is_hard_link( mode_t mode )
{
  return ( mode & S_IFMT ) == IMFS_STAT_FMT_HARD_LINK;
}

static inline ino_t IMFS_node_to_ino( const IMFS_jnode_t *node )
{
  return (ino_t) ((uintptr_t) node);
}

/** @} */

/**
 * @addtogroup IMFSGenericNodes
 */
/**@{*/

static inline void *IMFS_generic_get_context_by_node(
  const IMFS_jnode_t *node
)
{
  const IMFS_generic_t *generic = (const IMFS_generic_t *) node;

  return generic->context;
}

static inline void *IMFS_generic_get_context_by_location(
  const rtems_filesystem_location_info_t *loc
)
{
  return loc->node_access_2;
}

static inline void *IMFS_generic_get_context_by_iop(
  const rtems_libio_t *iop
)
{
  return IMFS_generic_get_context_by_location( &iop->pathinfo );
}

static inline dev_t IMFS_generic_get_device_identifier_by_node(
  const IMFS_jnode_t *node
)
{
  return rtems_filesystem_make_dev_t_from_pointer( node );
}

#ifdef __cplusplus
}
#endif
/** @} */
#endif
/* end of include file */