Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:49

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @brief MicroMonitor TFS Hookup to RTEMS FS
0007  */
0008 
0009 /*
0010  *  Initial release: Oct 1, 2004   by Ed Sutter
0011  *
0012  *  Modifications to support reference counting in the file system are
0013  *  Copyright (c) 2012 embedded brains GmbH & Co. KG
0014  *
0015  *  This code was derived from the tftpDriver.c code written by
0016  *  W. Eric Norum, which was apparently derived from the IMFS driver.
0017  *
0018  *  This code was reformatted by Joel Sherrill from OAR Corporation and
0019  *  Fernando Nicodemos <fgnicodemos@terra.com.br> from NCB - Sistemas
0020  *  Embarcados Ltda. (Brazil) to be more compliant with RTEMS coding
0021  *  standards and to eliminate C++ style comments.
0022  *
0023  * Redistribution and use in source and binary forms, with or without
0024  * modification, are permitted provided that the following conditions
0025  * are met:
0026  * 1. Redistributions of source code must retain the above copyright
0027  *    notice, this list of conditions and the following disclaimer.
0028  * 2. Redistributions in binary form must reproduce the above copyright
0029  *    notice, this list of conditions and the following disclaimer in the
0030  *    documentation and/or other materials provided with the distribution.
0031  *
0032  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0033  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0034  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0035  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0036  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0037  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0038  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0039  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0040  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0041  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0042  * POSSIBILITY OF SUCH DAMAGE.
0043  */
0044 
0045 #include <stdio.h>
0046 #include <stdlib.h>
0047 #include <string.h>
0048 #include <unistd.h>
0049 #include <errno.h>
0050 #include <fcntl.h>
0051 #include <inttypes.h>
0052 #include <rtems.h>
0053 #include <rtems/libio.h>
0054 #include <rtems/libio_.h>
0055 #include <rtems/seterr.h>
0056 #include <rtems/bspIo.h>
0057 #include <rtems/umon.h>
0058 
0059 #include <umon/tfs.h>
0060 #include <umon/monlib.h>
0061 
0062 #ifdef RTEMS_TFS_DRIVER_DEBUG
0063 #define RTEMS_TFS_DEBUG 1
0064 #else
0065 #define RTEMS_TFS_DEBUG 0
0066 #endif
0067 
0068 #define MAXFILESIZE 0x4000
0069 #define MAXTFDS  15
0070 
0071 /* Define these for thread safety...
0072  */
0073 #ifndef newlib_tfdlock
0074 #define newlib_tfdlock()
0075 #endif
0076 
0077 #ifndef newlib_tfdunlock
0078 #define newlib_tfdunlock()
0079 #endif
0080 
0081 /* TFS file descriptor info:
0082  */
0083 struct tfdinfo {
0084   int   inuse;
0085   int   tfd;
0086   char *buf;
0087   char  name[TFSNAMESIZE+1];
0088   char  info[TFSNAMESIZE+1];
0089 } tfdtable[MAXTFDS];
0090 
0091 /*
0092  * Pathname prefix
0093  */
0094 char TFS_PATHNAME_PREFIX[128];
0095 
0096 static const rtems_filesystem_operations_table  rtems_tfs_ops;
0097 static const rtems_filesystem_file_handlers_r   rtems_tfs_handlers;
0098 
0099 static bool rtems_tfs_is_directory(
0100     const char *path,
0101     size_t pathlen
0102 )
0103 {
0104     return path [pathlen - 1] == '/';
0105 }
0106 
0107 static int rtems_tfs_mount_me(
0108   rtems_filesystem_mount_table_entry_t *mt_entry,
0109   const void                           *data
0110 )
0111 {
0112   char *root_path = strdup("/");
0113 
0114   if (root_path == NULL) {
0115     rtems_set_errno_and_return_minus_one(ENOMEM);
0116   }
0117 
0118   mt_entry->ops = &rtems_tfs_ops;
0119   mt_entry->mt_fs_root->location.handlers = &rtems_tfs_handlers;
0120   mt_entry->mt_fs_root->location.node_access = root_path;
0121 
0122   return 0;
0123 }
0124 
0125 /* Initialize the TFS-RTEMS file system
0126  */
0127 int rtems_initialize_tfs_filesystem(
0128   const char *path
0129 )
0130 {
0131   int status;
0132 
0133   if (!path) {
0134     printk( "TFS: No mount point specified\n" );
0135     return -1;
0136   }
0137 
0138   strncpy( TFS_PATHNAME_PREFIX, path, sizeof(TFS_PATHNAME_PREFIX) );
0139 
0140   status = mkdir( TFS_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
0141   if ( status == -1 ) {
0142     printk( "TFS: Unable to mkdir %s\n", TFS_PATHNAME_PREFIX );
0143     return status;
0144   }
0145 
0146   if (rtems_filesystem_register( "tfs", rtems_tfs_mount_me ) < 0)
0147     return -1;
0148 
0149   status = mount( "umon", TFS_PATHNAME_PREFIX, "tfs", RTEMS_FILESYSTEM_READ_WRITE, NULL);
0150 
0151   if (status < 0) {
0152     printk( "TFS: Unable to mount on %s\n", TFS_PATHNAME_PREFIX );
0153     perror("TFS mount failed");
0154   }
0155 
0156   return(status);
0157 }
0158 
0159 /*
0160  * Convert a path to canonical form
0161  */
0162 static void fixPath(char *path)
0163 {
0164   char *inp, *outp, *base;
0165 
0166   outp = inp = path;
0167   base = NULL;
0168   for (;;) {
0169     if (inp[0] == '.') {
0170       if (inp[1] == '\0')
0171           break;
0172       if (inp[1] == '/') {
0173           inp += 2;
0174           continue;
0175       }
0176       if (inp[1] == '.') {
0177         if (inp[2] == '\0') {
0178           if ((base != NULL) && (outp > base)) {
0179             outp--;
0180             while ((outp > base) && (outp[-1] != '/'))
0181               outp--;
0182           }
0183           break;
0184         }
0185         if (inp[2] == '/') {
0186           inp += 3;
0187           if (base == NULL)
0188             continue;
0189           if (outp > base) {
0190             outp--;
0191             while ((outp > base) && (outp[-1] != '/'))
0192               outp--;
0193           }
0194           continue;
0195         }
0196       }
0197     }
0198     if (base == NULL)
0199       base = inp;
0200     while (inp[0] != '/') {
0201       if ((*outp++ = *inp++) == '\0')
0202         return;
0203     }
0204     *outp++ = '/';
0205     while (inp[0] == '/')
0206       inp++;
0207   }
0208   *outp = '\0';
0209 }
0210 
0211 static void rtems_tfs_eval_path(rtems_filesystem_eval_path_context_t *self)
0212 {
0213   int eval_flags = rtems_filesystem_eval_path_get_flags(self);
0214 
0215   if ((eval_flags & RTEMS_FS_MAKE) == 0) {
0216     int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE;
0217 
0218     if ((eval_flags & rw) != rw) {
0219       rtems_filesystem_location_info_t *currentloc =
0220         rtems_filesystem_eval_path_get_currentloc(self);
0221       char *current = currentloc->node_access;
0222       size_t currentlen = strlen(current);
0223       const char *path = rtems_filesystem_eval_path_get_path(self);
0224       size_t pathlen = rtems_filesystem_eval_path_get_pathlen(self);
0225       size_t len = currentlen + pathlen;
0226 
0227       rtems_filesystem_eval_path_clear_path(self);
0228 
0229       current = realloc(current, len + 1);
0230       if (current != NULL) {
0231         memcpy(current + currentlen, path, pathlen);
0232         current [len] = '\0';
0233         if (!rtems_tfs_is_directory(current, len)) {
0234           fixPath (current);
0235         }
0236         currentloc->node_access = current;
0237       } else {
0238         rtems_filesystem_eval_path_error(self, ENOMEM);
0239       }
0240     } else {
0241       rtems_filesystem_eval_path_error(self, EINVAL);
0242     }
0243   } else {
0244     rtems_filesystem_eval_path_error(self, EIO);
0245   }
0246 }
0247 
0248 /*
0249  * The routine which does most of the work for the IMFS open handler
0250  * The full_path_name here is all text AFTER the TFS_PATHNAME_PREFIX
0251  * string, so if the filename is "/TFS/abc", the full_path_name string
0252  * is "abc"...
0253  *
0254  * Attempts to remap the incoming flags to TFS equivalent.
0255  * Its not a perfect mapping, but gets pretty close.
0256  * A comma-delimited path is supported to allow the user
0257  * to specify TFS-stuff (flag string, info string, and a buffer).
0258  * For example:
0259  *  abc,e,script,0x400000
0260  *  This is a file called "abc" that will have the TFS 'e' flag
0261  *  and the TFS info field of "script".  The storage buffer is
0262  *  supplied by the user at 0x400000.
0263  */
0264 static int rtems_tfs_open_worker(
0265   rtems_libio_t *iop,
0266   char          *path,
0267   int            oflag,
0268   mode_t         mode
0269 )
0270 {
0271   static int beenhere = 0;
0272   long flagmode;
0273   int  tfdidx, tfd;
0274   struct tfdinfo *tip;
0275   char *buf, *fstr, *istr, *bstr, pathcopy[TFSNAMESIZE*3+1];
0276 
0277   if (RTEMS_TFS_DEBUG)
0278     printk("_open_r(%s,0x%x,0x%" PRIx32 ")\n",path,oflag,mode);
0279 
0280   if (!beenhere) {
0281     newlib_tfdlock();
0282     for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++)
0283       tfdtable[tfdidx].inuse = 0;
0284 
0285     tfdtable[0].inuse = 1;    /* fake entry for stdin */
0286     tfdtable[1].inuse = 1;    /* fake entry for stdout */
0287     tfdtable[2].inuse = 1;    /* fake entry for stderr */
0288     newlib_tfdunlock();
0289     beenhere = 1;
0290   }
0291 
0292   istr = fstr = bstr = buf = (char *)0;
0293 
0294   /* Copy the incoming path to a local array so that we can safely
0295    * modify the string...
0296     */
0297   if (strlen(path) > TFSNAMESIZE*3) {
0298     return(ENAMETOOLONG);
0299   }
0300   strcpy(pathcopy,path);
0301 
0302   /* The incoming string may have commas that are used to delimit the
0303    * name from the TFS flag string, TFS info string and buffer.
0304    * Check for the commas and test for maximum string length...
0305    */
0306   fstr = strchr(pathcopy,',');
0307   if (fstr)  {
0308     *fstr++ = 0;
0309     istr = strchr(fstr,',');
0310     if (istr) {
0311       *istr++ = 0;
0312       bstr = strchr(istr,',');
0313       if (bstr)
0314         *bstr++ = 0;
0315     }
0316   }
0317   if (strlen(pathcopy) > TFSNAMESIZE) {
0318     return(ENAMETOOLONG);
0319   }
0320   if (istr) {
0321     if (strlen(istr) > TFSNAMESIZE) {
0322       return(ENAMETOOLONG);
0323     }
0324   }
0325 
0326   /* If O_EXCL and O_CREAT are set, then fail if the file exists...
0327    */
0328   if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
0329     if (mon_tfsstat((char *)pathcopy)) {
0330       return(EEXIST);
0331     }
0332   }
0333 
0334   /* Only a few flag combinations are supported...
0335    * O_RDONLY             Simple read-only
0336    * O_WRONLY | O_APPEND       Each write starts at end of file
0337    * O_WRONLY | O_TRUNC       If file exists, truncate it
0338    * O_WRONLY | O_CREAT       Create if it doesn't exist
0339    * O_WRONLY | O_CREAT | O_EXCL   Fail if file exists
0340    */
0341   switch(oflag & O_ACCMODE) {
0342     case O_RDONLY:
0343       flagmode = TFS_RDONLY;
0344       break;
0345     case O_WRONLY|O_APPEND:
0346       flagmode = TFS_APPEND;
0347       break;
0348     case O_WRONLY|O_TRUNC:
0349     case O_WRONLY|O_CREAT|O_TRUNC:
0350       mon_tfsunlink((char *)pathcopy);
0351       flagmode = TFS_CREATE|TFS_APPEND;
0352       break;
0353     case O_WRONLY|O_CREAT:
0354     case O_WRONLY|O_CREAT|O_APPEND:
0355       flagmode = TFS_CREATE|TFS_APPEND;
0356       break;
0357     case O_RDWR:
0358     case O_WRONLY|O_CREAT|O_EXCL:
0359       flagmode = TFS_CREATE|TFS_APPEND;
0360       break;
0361     default:
0362       printk("_open_r(): flag 0x%i not supported\n",oflag);
0363       return(ENOTSUP);
0364   }
0365 
0366   /* Find an open slot in our tfd table:
0367    */
0368   newlib_tfdlock();
0369   for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++) {
0370     if (tfdtable[tfdidx].inuse == 0)
0371       break;
0372   }
0373   if (tfdidx == MAXTFDS) {
0374     newlib_tfdunlock();
0375     return(EMFILE);
0376   }
0377   tip = &tfdtable[tfdidx];
0378   tip->inuse = 1;
0379   newlib_tfdunlock();
0380 
0381   /* If file is opened for something other than O_RDONLY, then
0382    * we need to allocate a buffer for the file..
0383    * WARNING: It is the user's responsibility to make sure that
0384    * the file size does not exceed this buffer.  Note that the
0385    * buffer may be specified as part of the comma-delimited path.
0386    */
0387   if (flagmode == TFS_RDONLY) {
0388     buf = (char *)0;
0389   } else {
0390     if (bstr)
0391       buf = (char *)strtol(bstr,0,0);
0392     else
0393       buf = malloc(MAXFILESIZE);
0394     if (!buf) {
0395       newlib_tfdlock();
0396       tip->inuse = 0;
0397       newlib_tfdunlock();
0398       return(ENOMEM);
0399     }
0400   }
0401 
0402   /* Deal with tfs flags and tfs info fields if necessary:
0403    */
0404   if (fstr) {
0405     long bflag;
0406 
0407     bflag = mon_tfsctrl(TFS_FATOB,(long)fstr,0);
0408     if (bflag == -1) {
0409       return(EINVAL);
0410     }
0411     flagmode |= bflag;
0412   }
0413 
0414   if (istr)
0415     strcpy(tip->info,istr);
0416   else
0417     tip->info[0] = 0;
0418 
0419   tfd = mon_tfsopen((char *)pathcopy,flagmode,buf);
0420   if (tfd >= 0) {
0421     tip->tfd = tfd;
0422     tip->buf = buf;
0423     strcpy(tip->name,pathcopy);
0424     iop->data0 = (uint32_t)tfdidx;
0425     return(0);
0426   } else {
0427     printk("%s: %s\n",pathcopy,
0428       (char *)mon_tfsctrl(TFS_ERRMSG,tfd,0));
0429   }
0430 
0431   if (buf)
0432     free(buf);
0433 
0434   newlib_tfdlock();
0435   tip->inuse = 0;
0436   newlib_tfdunlock();
0437   return(EINVAL);
0438 }
0439 
0440 /*
0441  * The IMFS open handler
0442  */
0443 static int rtems_tfs_open(
0444   rtems_libio_t *iop,
0445   const char    *new_name,
0446   int            oflag,
0447   mode_t         mode
0448 )
0449 {
0450   char *full_path_name;
0451   int err;
0452 
0453   full_path_name = iop->pathinfo.node_access;
0454 
0455   if (RTEMS_TFS_DEBUG)
0456     printk("rtems_tfs_open(%s)\n",full_path_name);
0457 
0458   if (rtems_tfs_is_directory(full_path_name, strlen(full_path_name))) {
0459     rtems_set_errno_and_return_minus_one (ENOTSUP);
0460   }
0461 
0462   err = rtems_tfs_open_worker (iop, full_path_name, oflag, mode);
0463   if (err != 0) {
0464      rtems_set_errno_and_return_minus_one (err);
0465   }
0466 
0467   return err;
0468 }
0469 
0470 /*
0471  * Read from an open TFS file...
0472  */
0473 static ssize_t rtems_tfs_read(
0474   rtems_libio_t *iop,
0475   void          *buffer,
0476   size_t         count
0477 )
0478 {
0479   int  ret, fd;
0480 
0481   fd = (int) iop->data0;
0482 
0483   if (RTEMS_TFS_DEBUG)
0484     printk("_read_r(%d,%zi)\n",fd,count);
0485 
0486   if ((fd < 3) || (fd >= MAXTFDS))
0487     return(EBADF);
0488 
0489   ret = mon_tfsread(tfdtable[fd].tfd,buffer,count);
0490   if (ret == TFSERR_EOF)
0491     ret = 0;
0492 
0493   return(ret);
0494 }
0495 
0496 /*
0497  * Close the open tfs file.
0498  */
0499 static int rtems_tfs_close(
0500   rtems_libio_t *iop
0501 )
0502 {
0503   int  fd;
0504   char *info;
0505   struct tfdinfo *tip;
0506 
0507   fd = (int)iop->data0;
0508 
0509   if (RTEMS_TFS_DEBUG)
0510     printk("rtems_tfs_close(%d)\n",fd);
0511 
0512   if ((fd < 3) || (fd >= MAXTFDS)) {
0513     rtems_set_errno_and_return_minus_one (EBADF);
0514   }
0515 
0516   tip = &tfdtable[fd];
0517 
0518   if (tip->info[0])
0519     info = tip->info;
0520   else
0521     info = (char *)0;
0522 
0523   mon_tfsclose(tip->tfd,info);
0524 
0525   if (tip->buf)
0526     free(tip->buf);
0527 
0528   newlib_tfdlock();
0529   tip->inuse = 0;
0530   newlib_tfdunlock();
0531   return RTEMS_SUCCESSFUL;
0532 }
0533 
0534 static ssize_t rtems_tfs_write(
0535   rtems_libio_t *iop,
0536   const void    *buffer,
0537   size_t         count
0538 )
0539 {
0540   int  ret, fd;
0541 
0542   fd = (int) iop->data0;
0543 
0544   if (RTEMS_TFS_DEBUG)
0545     printk("rtems_tfs_write(%d,%zi)\n",fd,count);
0546 
0547   if ((fd <= 0) || (fd >= MAXTFDS)) {
0548     rtems_set_errno_and_return_minus_one (EBADF);
0549   }
0550 
0551   ret = mon_tfswrite(tfdtable[fd].tfd,(char *)buffer,count);
0552   if (ret < 0)
0553     return(-1);
0554 
0555   return(ret);
0556 }
0557 
0558 static off_t rtems_tfs_lseek(
0559   rtems_libio_t *iop,
0560   off_t          offset,
0561   int            whence
0562 )
0563 {
0564   int ret, fd;
0565 
0566   fd = (int) iop->data0;
0567 
0568   if (RTEMS_TFS_DEBUG)
0569     printk("rtems_tfs_lseek(%d,%ld,%d)\n",fd,(long)offset,whence);
0570 
0571   switch (whence) {
0572     case SEEK_END:
0573       printk("rtems_tfs_lseek doesn't support SEEK_END\n");
0574       return(-1);
0575     case SEEK_CUR:
0576       whence = TFS_CURRENT;
0577       break;
0578     case SEEK_SET:
0579       whence = TFS_BEGIN;
0580       break;
0581   }
0582   ret = mon_tfsseek(tfdtable[fd].tfd,offset,whence);
0583 
0584   if (ret < 0)
0585     return(-1);
0586 
0587   return (off_t)ret;
0588 }
0589 
0590 /*
0591  *
0592  */
0593 static int rtems_tfs_ftruncate(
0594   rtems_libio_t *iop,
0595   off_t          count
0596 )
0597 {
0598   int ret, fd;
0599 
0600   fd = (int) iop->data0;
0601   ret = mon_tfstruncate(tfdtable[fd].tfd,count);
0602   if (ret != TFS_OKAY)
0603     return(-1);
0604 
0605   return(0);
0606 }
0607 
0608 static int rtems_tfs_ioctl(
0609   rtems_libio_t *iop,
0610   uint32_t       cmd,
0611   void          *buf
0612 )
0613 {
0614   int ret;
0615 
0616   ret = mon_tfsctrl(cmd,(long)buf,0);
0617   if (ret != TFS_OKAY)
0618     return(-1);
0619 
0620   return(0);
0621 }
0622 
0623 static int rtems_tfs_fstat(
0624   const rtems_filesystem_location_info_t *loc,
0625   struct stat *buf
0626 )
0627 {
0628   const char *path = loc->node_access;
0629   size_t pathlen = strlen(path);
0630 
0631   buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO
0632     | (rtems_tfs_is_directory(path, pathlen) ?  S_IFDIR : S_IFREG);
0633 
0634   return 0;
0635 }
0636 
0637 static int rtems_tfs_clone_node_info(
0638   rtems_filesystem_location_info_t *loc
0639 )
0640 {
0641   int rv = 0;
0642 
0643   loc->node_access = strdup(loc->node_access);
0644 
0645   if (loc->node_access == NULL) {
0646     errno = ENOMEM;
0647     rv = -1;
0648   }
0649 
0650   return rv;
0651 }
0652 
0653 static void rtems_tfs_free_node_info(
0654   const rtems_filesystem_location_info_t *loc
0655 )
0656 {
0657   free(loc->node_access);
0658 }
0659 
0660 static bool rtems_tfs_are_nodes_equal(
0661   const rtems_filesystem_location_info_t *a,
0662   const rtems_filesystem_location_info_t *b
0663 )
0664 {
0665   return strcmp(a->node_access, b->node_access) == 0;
0666 }
0667 
0668 static const rtems_filesystem_operations_table  rtems_tfs_ops = {
0669   .lock_h = rtems_filesystem_default_lock,
0670   .unlock_h = rtems_filesystem_default_unlock,
0671   .eval_path_h = rtems_tfs_eval_path,
0672   .link_h = rtems_filesystem_default_link,
0673   .are_nodes_equal_h = rtems_tfs_are_nodes_equal,
0674   .mknod_h = rtems_filesystem_default_mknod,
0675   .rmnod_h = rtems_filesystem_default_rmnod,
0676   .fchmod_h = rtems_filesystem_default_fchmod,
0677   .chown_h = rtems_filesystem_default_chown,
0678   .clonenod_h = rtems_tfs_clone_node_info,
0679   .freenod_h = rtems_tfs_free_node_info,
0680   .mount_h = rtems_filesystem_default_mount,
0681   .unmount_h = rtems_filesystem_default_unmount,
0682   .fsunmount_me_h = rtems_filesystem_default_fsunmount,
0683   .utimens_h = rtems_filesystem_default_utimens,
0684   .symlink_h = rtems_filesystem_default_symlink,
0685   .readlink_h = rtems_filesystem_default_readlink,
0686   .rename_h = rtems_filesystem_default_rename,
0687   .statvfs_h = rtems_filesystem_default_statvfs
0688 };
0689 
0690 static const rtems_filesystem_file_handlers_r rtems_tfs_handlers = {
0691   .open_h = rtems_tfs_open,
0692   .close_h = rtems_tfs_close,
0693   .read_h = rtems_tfs_read,
0694   .write_h = rtems_tfs_write,
0695   .ioctl_h = rtems_tfs_ioctl,
0696   .lseek_h = rtems_tfs_lseek,
0697   .fstat_h = rtems_tfs_fstat,
0698   .ftruncate_h = rtems_tfs_ftruncate,
0699   .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
0700   .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
0701   .fcntl_h = rtems_filesystem_default_fcntl,
0702   .kqfilter_h = rtems_filesystem_default_kqfilter,
0703   .poll_h = rtems_filesystem_default_poll,
0704   .readv_h = rtems_filesystem_default_readv,
0705   .writev_h = rtems_filesystem_default_writev
0706 };