forked from Imagelibrary/rtems
707 lines
17 KiB
C
707 lines
17 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* @brief MicroMonitor TFS Hookup to RTEMS FS
|
|
*/
|
|
|
|
/*
|
|
* Initial release: Oct 1, 2004 by Ed Sutter
|
|
*
|
|
* Modifications to support reference counting in the file system are
|
|
* Copyright (c) 2012 embedded brains GmbH & Co. KG
|
|
*
|
|
* This code was derived from the tftpDriver.c code written by
|
|
* W. Eric Norum, which was apparently derived from the IMFS driver.
|
|
*
|
|
* This code was reformatted by Joel Sherrill from OAR Corporation and
|
|
* Fernando Nicodemos <fgnicodemos@terra.com.br> from NCB - Sistemas
|
|
* Embarcados Ltda. (Brazil) to be more compliant with RTEMS coding
|
|
* standards and to eliminate C++ style comments.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <inttypes.h>
|
|
#include <rtems.h>
|
|
#include <rtems/libio.h>
|
|
#include <rtems/libio_.h>
|
|
#include <rtems/seterr.h>
|
|
#include <rtems/bspIo.h>
|
|
#include <rtems/umon.h>
|
|
|
|
#include <umon/tfs.h>
|
|
#include <umon/monlib.h>
|
|
|
|
#ifdef RTEMS_TFS_DRIVER_DEBUG
|
|
#define RTEMS_TFS_DEBUG 1
|
|
#else
|
|
#define RTEMS_TFS_DEBUG 0
|
|
#endif
|
|
|
|
#define MAXFILESIZE 0x4000
|
|
#define MAXTFDS 15
|
|
|
|
/* Define these for thread safety...
|
|
*/
|
|
#ifndef newlib_tfdlock
|
|
#define newlib_tfdlock()
|
|
#endif
|
|
|
|
#ifndef newlib_tfdunlock
|
|
#define newlib_tfdunlock()
|
|
#endif
|
|
|
|
/* TFS file descriptor info:
|
|
*/
|
|
struct tfdinfo {
|
|
int inuse;
|
|
int tfd;
|
|
char *buf;
|
|
char name[TFSNAMESIZE+1];
|
|
char info[TFSNAMESIZE+1];
|
|
} tfdtable[MAXTFDS];
|
|
|
|
/*
|
|
* Pathname prefix
|
|
*/
|
|
char TFS_PATHNAME_PREFIX[128];
|
|
|
|
static const rtems_filesystem_operations_table rtems_tfs_ops;
|
|
static const rtems_filesystem_file_handlers_r rtems_tfs_handlers;
|
|
|
|
static bool rtems_tfs_is_directory(
|
|
const char *path,
|
|
size_t pathlen
|
|
)
|
|
{
|
|
return path [pathlen - 1] == '/';
|
|
}
|
|
|
|
static int rtems_tfs_mount_me(
|
|
rtems_filesystem_mount_table_entry_t *mt_entry,
|
|
const void *data
|
|
)
|
|
{
|
|
char *root_path = strdup("/");
|
|
|
|
if (root_path == NULL) {
|
|
rtems_set_errno_and_return_minus_one(ENOMEM);
|
|
}
|
|
|
|
mt_entry->ops = &rtems_tfs_ops;
|
|
mt_entry->mt_fs_root->location.handlers = &rtems_tfs_handlers;
|
|
mt_entry->mt_fs_root->location.node_access = root_path;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Initialize the TFS-RTEMS file system
|
|
*/
|
|
int rtems_initialize_tfs_filesystem(
|
|
const char *path
|
|
)
|
|
{
|
|
int status;
|
|
|
|
if (!path) {
|
|
printk( "TFS: No mount point specified\n" );
|
|
return -1;
|
|
}
|
|
|
|
strncpy( TFS_PATHNAME_PREFIX, path, sizeof(TFS_PATHNAME_PREFIX) );
|
|
|
|
status = mkdir( TFS_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
|
|
if ( status == -1 ) {
|
|
printk( "TFS: Unable to mkdir %s\n", TFS_PATHNAME_PREFIX );
|
|
return status;
|
|
}
|
|
|
|
if (rtems_filesystem_register( "tfs", rtems_tfs_mount_me ) < 0)
|
|
return -1;
|
|
|
|
status = mount( "umon", TFS_PATHNAME_PREFIX, "tfs", RTEMS_FILESYSTEM_READ_WRITE, NULL);
|
|
|
|
if (status < 0) {
|
|
printk( "TFS: Unable to mount on %s\n", TFS_PATHNAME_PREFIX );
|
|
perror("TFS mount failed");
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
/*
|
|
* Convert a path to canonical form
|
|
*/
|
|
static void fixPath(char *path)
|
|
{
|
|
char *inp, *outp, *base;
|
|
|
|
outp = inp = path;
|
|
base = NULL;
|
|
for (;;) {
|
|
if (inp[0] == '.') {
|
|
if (inp[1] == '\0')
|
|
break;
|
|
if (inp[1] == '/') {
|
|
inp += 2;
|
|
continue;
|
|
}
|
|
if (inp[1] == '.') {
|
|
if (inp[2] == '\0') {
|
|
if ((base != NULL) && (outp > base)) {
|
|
outp--;
|
|
while ((outp > base) && (outp[-1] != '/'))
|
|
outp--;
|
|
}
|
|
break;
|
|
}
|
|
if (inp[2] == '/') {
|
|
inp += 3;
|
|
if (base == NULL)
|
|
continue;
|
|
if (outp > base) {
|
|
outp--;
|
|
while ((outp > base) && (outp[-1] != '/'))
|
|
outp--;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (base == NULL)
|
|
base = inp;
|
|
while (inp[0] != '/') {
|
|
if ((*outp++ = *inp++) == '\0')
|
|
return;
|
|
}
|
|
*outp++ = '/';
|
|
while (inp[0] == '/')
|
|
inp++;
|
|
}
|
|
*outp = '\0';
|
|
}
|
|
|
|
static void rtems_tfs_eval_path(rtems_filesystem_eval_path_context_t *self)
|
|
{
|
|
int eval_flags = rtems_filesystem_eval_path_get_flags(self);
|
|
|
|
if ((eval_flags & RTEMS_FS_MAKE) == 0) {
|
|
int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE;
|
|
|
|
if ((eval_flags & rw) != rw) {
|
|
rtems_filesystem_location_info_t *currentloc =
|
|
rtems_filesystem_eval_path_get_currentloc(self);
|
|
char *current = currentloc->node_access;
|
|
size_t currentlen = strlen(current);
|
|
const char *path = rtems_filesystem_eval_path_get_path(self);
|
|
size_t pathlen = rtems_filesystem_eval_path_get_pathlen(self);
|
|
size_t len = currentlen + pathlen;
|
|
|
|
rtems_filesystem_eval_path_clear_path(self);
|
|
|
|
current = realloc(current, len + 1);
|
|
if (current != NULL) {
|
|
memcpy(current + currentlen, path, pathlen);
|
|
current [len] = '\0';
|
|
if (!rtems_tfs_is_directory(current, len)) {
|
|
fixPath (current);
|
|
}
|
|
currentloc->node_access = current;
|
|
} else {
|
|
rtems_filesystem_eval_path_error(self, ENOMEM);
|
|
}
|
|
} else {
|
|
rtems_filesystem_eval_path_error(self, EINVAL);
|
|
}
|
|
} else {
|
|
rtems_filesystem_eval_path_error(self, EIO);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The routine which does most of the work for the IMFS open handler
|
|
* The full_path_name here is all text AFTER the TFS_PATHNAME_PREFIX
|
|
* string, so if the filename is "/TFS/abc", the full_path_name string
|
|
* is "abc"...
|
|
*
|
|
* Attempts to remap the incoming flags to TFS equivalent.
|
|
* Its not a perfect mapping, but gets pretty close.
|
|
* A comma-delimited path is supported to allow the user
|
|
* to specify TFS-stuff (flag string, info string, and a buffer).
|
|
* For example:
|
|
* abc,e,script,0x400000
|
|
* This is a file called "abc" that will have the TFS 'e' flag
|
|
* and the TFS info field of "script". The storage buffer is
|
|
* supplied by the user at 0x400000.
|
|
*/
|
|
static int rtems_tfs_open_worker(
|
|
rtems_libio_t *iop,
|
|
char *path,
|
|
int oflag,
|
|
mode_t mode
|
|
)
|
|
{
|
|
static int beenhere = 0;
|
|
long flagmode;
|
|
int tfdidx, tfd;
|
|
struct tfdinfo *tip;
|
|
char *buf, *fstr, *istr, *bstr, pathcopy[TFSNAMESIZE*3+1];
|
|
|
|
if (RTEMS_TFS_DEBUG)
|
|
printk("_open_r(%s,0x%x,0x%" PRIx32 ")\n",path,oflag,mode);
|
|
|
|
if (!beenhere) {
|
|
newlib_tfdlock();
|
|
for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++)
|
|
tfdtable[tfdidx].inuse = 0;
|
|
|
|
tfdtable[0].inuse = 1; /* fake entry for stdin */
|
|
tfdtable[1].inuse = 1; /* fake entry for stdout */
|
|
tfdtable[2].inuse = 1; /* fake entry for stderr */
|
|
newlib_tfdunlock();
|
|
beenhere = 1;
|
|
}
|
|
|
|
istr = fstr = bstr = buf = (char *)0;
|
|
|
|
/* Copy the incoming path to a local array so that we can safely
|
|
* modify the string...
|
|
*/
|
|
if (strlen(path) > TFSNAMESIZE*3) {
|
|
return(ENAMETOOLONG);
|
|
}
|
|
strcpy(pathcopy,path);
|
|
|
|
/* The incoming string may have commas that are used to delimit the
|
|
* name from the TFS flag string, TFS info string and buffer.
|
|
* Check for the commas and test for maximum string length...
|
|
*/
|
|
fstr = strchr(pathcopy,',');
|
|
if (fstr) {
|
|
*fstr++ = 0;
|
|
istr = strchr(fstr,',');
|
|
if (istr) {
|
|
*istr++ = 0;
|
|
bstr = strchr(istr,',');
|
|
if (bstr)
|
|
*bstr++ = 0;
|
|
}
|
|
}
|
|
if (strlen(pathcopy) > TFSNAMESIZE) {
|
|
return(ENAMETOOLONG);
|
|
}
|
|
if (istr) {
|
|
if (strlen(istr) > TFSNAMESIZE) {
|
|
return(ENAMETOOLONG);
|
|
}
|
|
}
|
|
|
|
/* If O_EXCL and O_CREAT are set, then fail if the file exists...
|
|
*/
|
|
if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
|
|
if (mon_tfsstat((char *)pathcopy)) {
|
|
return(EEXIST);
|
|
}
|
|
}
|
|
|
|
/* Only a few flag combinations are supported...
|
|
* O_RDONLY Simple read-only
|
|
* O_WRONLY | O_APPEND Each write starts at end of file
|
|
* O_WRONLY | O_TRUNC If file exists, truncate it
|
|
* O_WRONLY | O_CREAT Create if it doesn't exist
|
|
* O_WRONLY | O_CREAT | O_EXCL Fail if file exists
|
|
*/
|
|
switch(oflag & O_ACCMODE) {
|
|
case O_RDONLY:
|
|
flagmode = TFS_RDONLY;
|
|
break;
|
|
case O_WRONLY|O_APPEND:
|
|
flagmode = TFS_APPEND;
|
|
break;
|
|
case O_WRONLY|O_TRUNC:
|
|
case O_WRONLY|O_CREAT|O_TRUNC:
|
|
mon_tfsunlink((char *)pathcopy);
|
|
flagmode = TFS_CREATE|TFS_APPEND;
|
|
break;
|
|
case O_WRONLY|O_CREAT:
|
|
case O_WRONLY|O_CREAT|O_APPEND:
|
|
flagmode = TFS_CREATE|TFS_APPEND;
|
|
break;
|
|
case O_RDWR:
|
|
case O_WRONLY|O_CREAT|O_EXCL:
|
|
flagmode = TFS_CREATE|TFS_APPEND;
|
|
break;
|
|
default:
|
|
printk("_open_r(): flag 0x%i not supported\n",oflag);
|
|
return(ENOTSUP);
|
|
}
|
|
|
|
/* Find an open slot in our tfd table:
|
|
*/
|
|
newlib_tfdlock();
|
|
for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++) {
|
|
if (tfdtable[tfdidx].inuse == 0)
|
|
break;
|
|
}
|
|
if (tfdidx == MAXTFDS) {
|
|
newlib_tfdunlock();
|
|
return(EMFILE);
|
|
}
|
|
tip = &tfdtable[tfdidx];
|
|
tip->inuse = 1;
|
|
newlib_tfdunlock();
|
|
|
|
/* If file is opened for something other than O_RDONLY, then
|
|
* we need to allocate a buffer for the file..
|
|
* WARNING: It is the user's responsibility to make sure that
|
|
* the file size does not exceed this buffer. Note that the
|
|
* buffer may be specified as part of the comma-delimited path.
|
|
*/
|
|
if (flagmode == TFS_RDONLY) {
|
|
buf = (char *)0;
|
|
} else {
|
|
if (bstr)
|
|
buf = (char *)strtol(bstr,0,0);
|
|
else
|
|
buf = malloc(MAXFILESIZE);
|
|
if (!buf) {
|
|
newlib_tfdlock();
|
|
tip->inuse = 0;
|
|
newlib_tfdunlock();
|
|
return(ENOMEM);
|
|
}
|
|
}
|
|
|
|
/* Deal with tfs flags and tfs info fields if necessary:
|
|
*/
|
|
if (fstr) {
|
|
long bflag;
|
|
|
|
bflag = mon_tfsctrl(TFS_FATOB,(long)fstr,0);
|
|
if (bflag == -1) {
|
|
return(EINVAL);
|
|
}
|
|
flagmode |= bflag;
|
|
}
|
|
|
|
if (istr)
|
|
strcpy(tip->info,istr);
|
|
else
|
|
tip->info[0] = 0;
|
|
|
|
tfd = mon_tfsopen((char *)pathcopy,flagmode,buf);
|
|
if (tfd >= 0) {
|
|
tip->tfd = tfd;
|
|
tip->buf = buf;
|
|
strcpy(tip->name,pathcopy);
|
|
iop->data0 = (uint32_t)tfdidx;
|
|
return(0);
|
|
} else {
|
|
printk("%s: %s\n",pathcopy,
|
|
(char *)mon_tfsctrl(TFS_ERRMSG,tfd,0));
|
|
}
|
|
|
|
if (buf)
|
|
free(buf);
|
|
|
|
newlib_tfdlock();
|
|
tip->inuse = 0;
|
|
newlib_tfdunlock();
|
|
return(EINVAL);
|
|
}
|
|
|
|
/*
|
|
* The IMFS open handler
|
|
*/
|
|
static int rtems_tfs_open(
|
|
rtems_libio_t *iop,
|
|
const char *new_name,
|
|
int oflag,
|
|
mode_t mode
|
|
)
|
|
{
|
|
char *full_path_name;
|
|
int err;
|
|
|
|
full_path_name = iop->pathinfo.node_access;
|
|
|
|
if (RTEMS_TFS_DEBUG)
|
|
printk("rtems_tfs_open(%s)\n",full_path_name);
|
|
|
|
if (rtems_tfs_is_directory(full_path_name, strlen(full_path_name))) {
|
|
rtems_set_errno_and_return_minus_one (ENOTSUP);
|
|
}
|
|
|
|
err = rtems_tfs_open_worker (iop, full_path_name, oflag, mode);
|
|
if (err != 0) {
|
|
rtems_set_errno_and_return_minus_one (err);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Read from an open TFS file...
|
|
*/
|
|
static ssize_t rtems_tfs_read(
|
|
rtems_libio_t *iop,
|
|
void *buffer,
|
|
size_t count
|
|
)
|
|
{
|
|
int ret, fd;
|
|
|
|
fd = (int) iop->data0;
|
|
|
|
if (RTEMS_TFS_DEBUG)
|
|
printk("_read_r(%d,%zi)\n",fd,count);
|
|
|
|
if ((fd < 3) || (fd >= MAXTFDS))
|
|
return(EBADF);
|
|
|
|
ret = mon_tfsread(tfdtable[fd].tfd,buffer,count);
|
|
if (ret == TFSERR_EOF)
|
|
ret = 0;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/*
|
|
* Close the open tfs file.
|
|
*/
|
|
static int rtems_tfs_close(
|
|
rtems_libio_t *iop
|
|
)
|
|
{
|
|
int fd;
|
|
char *info;
|
|
struct tfdinfo *tip;
|
|
|
|
fd = (int)iop->data0;
|
|
|
|
if (RTEMS_TFS_DEBUG)
|
|
printk("rtems_tfs_close(%d)\n",fd);
|
|
|
|
if ((fd < 3) || (fd >= MAXTFDS)) {
|
|
rtems_set_errno_and_return_minus_one (EBADF);
|
|
}
|
|
|
|
tip = &tfdtable[fd];
|
|
|
|
if (tip->info[0])
|
|
info = tip->info;
|
|
else
|
|
info = (char *)0;
|
|
|
|
mon_tfsclose(tip->tfd,info);
|
|
|
|
if (tip->buf)
|
|
free(tip->buf);
|
|
|
|
newlib_tfdlock();
|
|
tip->inuse = 0;
|
|
newlib_tfdunlock();
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
static ssize_t rtems_tfs_write(
|
|
rtems_libio_t *iop,
|
|
const void *buffer,
|
|
size_t count
|
|
)
|
|
{
|
|
int ret, fd;
|
|
|
|
fd = (int) iop->data0;
|
|
|
|
if (RTEMS_TFS_DEBUG)
|
|
printk("rtems_tfs_write(%d,%zi)\n",fd,count);
|
|
|
|
if ((fd <= 0) || (fd >= MAXTFDS)) {
|
|
rtems_set_errno_and_return_minus_one (EBADF);
|
|
}
|
|
|
|
ret = mon_tfswrite(tfdtable[fd].tfd,(char *)buffer,count);
|
|
if (ret < 0)
|
|
return(-1);
|
|
|
|
return(ret);
|
|
}
|
|
|
|
static off_t rtems_tfs_lseek(
|
|
rtems_libio_t *iop,
|
|
off_t offset,
|
|
int whence
|
|
)
|
|
{
|
|
int ret, fd;
|
|
|
|
fd = (int) iop->data0;
|
|
|
|
if (RTEMS_TFS_DEBUG)
|
|
printk("rtems_tfs_lseek(%d,%ld,%d)\n",fd,(long)offset,whence);
|
|
|
|
switch (whence) {
|
|
case SEEK_END:
|
|
printk("rtems_tfs_lseek doesn't support SEEK_END\n");
|
|
return(-1);
|
|
case SEEK_CUR:
|
|
whence = TFS_CURRENT;
|
|
break;
|
|
case SEEK_SET:
|
|
whence = TFS_BEGIN;
|
|
break;
|
|
}
|
|
ret = mon_tfsseek(tfdtable[fd].tfd,offset,whence);
|
|
|
|
if (ret < 0)
|
|
return(-1);
|
|
|
|
return (off_t)ret;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static int rtems_tfs_ftruncate(
|
|
rtems_libio_t *iop,
|
|
off_t count
|
|
)
|
|
{
|
|
int ret, fd;
|
|
|
|
fd = (int) iop->data0;
|
|
ret = mon_tfstruncate(tfdtable[fd].tfd,count);
|
|
if (ret != TFS_OKAY)
|
|
return(-1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int rtems_tfs_ioctl(
|
|
rtems_libio_t *iop,
|
|
uint32_t cmd,
|
|
void *buf
|
|
)
|
|
{
|
|
int ret;
|
|
|
|
ret = mon_tfsctrl(cmd,(long)buf,0);
|
|
if (ret != TFS_OKAY)
|
|
return(-1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int rtems_tfs_fstat(
|
|
const rtems_filesystem_location_info_t *loc,
|
|
struct stat *buf
|
|
)
|
|
{
|
|
const char *path = loc->node_access;
|
|
size_t pathlen = strlen(path);
|
|
|
|
buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO
|
|
| (rtems_tfs_is_directory(path, pathlen) ? S_IFDIR : S_IFREG);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rtems_tfs_clone_node_info(
|
|
rtems_filesystem_location_info_t *loc
|
|
)
|
|
{
|
|
int rv = 0;
|
|
|
|
loc->node_access = strdup(loc->node_access);
|
|
|
|
if (loc->node_access == NULL) {
|
|
errno = ENOMEM;
|
|
rv = -1;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
static void rtems_tfs_free_node_info(
|
|
const rtems_filesystem_location_info_t *loc
|
|
)
|
|
{
|
|
free(loc->node_access);
|
|
}
|
|
|
|
static bool rtems_tfs_are_nodes_equal(
|
|
const rtems_filesystem_location_info_t *a,
|
|
const rtems_filesystem_location_info_t *b
|
|
)
|
|
{
|
|
return strcmp(a->node_access, b->node_access) == 0;
|
|
}
|
|
|
|
static const rtems_filesystem_operations_table rtems_tfs_ops = {
|
|
.lock_h = rtems_filesystem_default_lock,
|
|
.unlock_h = rtems_filesystem_default_unlock,
|
|
.eval_path_h = rtems_tfs_eval_path,
|
|
.link_h = rtems_filesystem_default_link,
|
|
.are_nodes_equal_h = rtems_tfs_are_nodes_equal,
|
|
.mknod_h = rtems_filesystem_default_mknod,
|
|
.rmnod_h = rtems_filesystem_default_rmnod,
|
|
.fchmod_h = rtems_filesystem_default_fchmod,
|
|
.chown_h = rtems_filesystem_default_chown,
|
|
.clonenod_h = rtems_tfs_clone_node_info,
|
|
.freenod_h = rtems_tfs_free_node_info,
|
|
.mount_h = rtems_filesystem_default_mount,
|
|
.unmount_h = rtems_filesystem_default_unmount,
|
|
.fsunmount_me_h = rtems_filesystem_default_fsunmount,
|
|
.utimens_h = rtems_filesystem_default_utimens,
|
|
.symlink_h = rtems_filesystem_default_symlink,
|
|
.readlink_h = rtems_filesystem_default_readlink,
|
|
.rename_h = rtems_filesystem_default_rename,
|
|
.statvfs_h = rtems_filesystem_default_statvfs
|
|
};
|
|
|
|
static const rtems_filesystem_file_handlers_r rtems_tfs_handlers = {
|
|
.open_h = rtems_tfs_open,
|
|
.close_h = rtems_tfs_close,
|
|
.read_h = rtems_tfs_read,
|
|
.write_h = rtems_tfs_write,
|
|
.ioctl_h = rtems_tfs_ioctl,
|
|
.lseek_h = rtems_tfs_lseek,
|
|
.fstat_h = rtems_tfs_fstat,
|
|
.ftruncate_h = rtems_tfs_ftruncate,
|
|
.fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
|
|
.fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
|
|
.fcntl_h = rtems_filesystem_default_fcntl,
|
|
.kqfilter_h = rtems_filesystem_default_kqfilter,
|
|
.poll_h = rtems_filesystem_default_poll,
|
|
.readv_h = rtems_filesystem_default_readv,
|
|
.writev_h = rtems_filesystem_default_writev
|
|
};
|