source: rtems/c/src/lib/libbsp/shared/umon/tfsDriver.c @ da154e14

4.11
Last change on this file since da154e14 was da154e14, checked in by Sebastian Huber <sebastian.huber@…>, on May 14, 2012 at 2:55:41 PM

Filesystem: Move operations to mount table entry

The scope of the file system operations is the file system instance.
The scope of the file system node handlers is the file location. The
benefit of moving the operations to the mount table entry is a size
reduction of the file location (rtems_filesystem_location_info_t). The
code size is slightly increased due to additional load instructions.

Restructure rtems_filesystem_mount_table_entry_t to improve cache
efficiency.

  • Property mode set to 100644
File size: 15.4 KB
Line 
1/*
2 *  tfsDriver.c - MicroMonitor TFS Hookup to RTEMS FS
3 *
4 *  Initial release: Oct 1, 2004   by Ed Sutter
5 *
6 *  Modifications to support reference counting in the file system are
7 *  Copyright (c) 2012 embedded brains GmbH.
8 *
9 *  This code was derived from the tftpDriver.c code written by
10 *  W. Eric Norum, which was apparently derived from the IMFS driver.
11 *
12 *  This code was reformatted by Joel Sherrill from OAR Corporation and
13 *  Fernando Nicodemos <fgnicodemos@terra.com.br> from NCB - Sistemas
14 *  Embarcados Ltda. (Brazil) to be more compliant with RTEMS coding
15 *  standards and to eliminate C++ style comments.
16 *
17 *  The license and distribution terms for this file may be
18 *  found in the file LICENSE in this distribution or at
19 *  http://www.rtems.com/license/LICENSE.
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <inttypes.h>
29#include <rtems.h>
30#include <rtems/libio.h>
31#include <rtems/libio_.h>
32#include <rtems/seterr.h>
33#include <rtems/bspIo.h>
34#include <rtems/umon.h>
35
36#include <umon/tfs.h>
37#include <umon/monlib.h>
38
39#ifdef RTEMS_TFS_DRIVER_DEBUG
40#define RTEMS_TFS_DEBUG 1
41#else
42#define RTEMS_TFS_DEBUG 0
43#endif
44
45#define MAXFILESIZE 0x4000
46#define MAXTFDS  15
47
48/* Define these for thread safety...
49 */
50#ifndef newlib_tfdlock
51#define newlib_tfdlock()
52#endif
53
54#ifndef newlib_tfdunlock
55#define newlib_tfdunlock()
56#endif
57
58/* TFS file descriptor info:
59 */
60struct tfdinfo {
61  int   inuse;
62  int   tfd;
63  char *buf;
64  char  name[TFSNAMESIZE+1];
65  char  info[TFSNAMESIZE+1];
66} tfdtable[MAXTFDS];
67
68/*
69 * Pathname prefix
70 */
71char TFS_PATHNAME_PREFIX[128];
72
73static const rtems_filesystem_operations_table  rtems_tfs_ops;
74static const rtems_filesystem_file_handlers_r   rtems_tfs_handlers;
75
76static bool rtems_tfs_is_directory(
77    const char *path,
78    size_t pathlen
79)
80{
81    return path [pathlen - 1] == '/';
82}
83
84static int rtems_tfs_mount_me(
85  rtems_filesystem_mount_table_entry_t *mt_entry,
86  const void                           *data
87)
88{
89  char *root_path = strdup("/");
90
91  if (root_path == NULL) {
92    rtems_set_errno_and_return_minus_one(ENOMEM);
93  }
94
95  mt_entry->ops = &rtems_tfs_ops;
96  mt_entry->mt_fs_root->location.handlers = &rtems_tfs_handlers;
97  mt_entry->mt_fs_root->location.node_access = root_path;
98
99  return 0;
100}
101
102/* Initialize the TFS-RTEMS file system
103 */
104int rtems_initialize_tfs_filesystem(
105  const char *path
106)
107{
108  int status;
109
110  if (!path) {
111    printk( "TFS: No mount point specified\n" );
112    return -1;
113  }
114
115  strncpy( TFS_PATHNAME_PREFIX, path, sizeof(TFS_PATHNAME_PREFIX) );
116
117  status = mkdir( TFS_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
118  if ( status == -1 ) {
119    printk( "TFS: Unable to mkdir %s\n", TFS_PATHNAME_PREFIX );
120    return status;
121  }
122
123  if (rtems_filesystem_register( "tfs", rtems_tfs_mount_me ) < 0)
124    return -1;
125
126  status = mount( "umon", TFS_PATHNAME_PREFIX, "tfs", RTEMS_FILESYSTEM_READ_WRITE, NULL);
127
128  if (status < 0) {
129    printk( "TFS: Unable to mount on %s\n", TFS_PATHNAME_PREFIX );
130    perror("TFS mount failed");
131  }
132
133  return(status);
134}
135
136/*
137 * Convert a path to canonical form
138 */
139static void fixPath(char *path)
140{
141  char *inp, *outp, *base;
142
143  outp = inp = path;
144  base = NULL;
145  for (;;) {
146    if (inp[0] == '.') {
147      if (inp[1] == '\0')
148          break;
149      if (inp[1] == '/') {
150          inp += 2;
151          continue;
152      }
153      if (inp[1] == '.') {
154        if (inp[2] == '\0') {
155          if ((base != NULL) && (outp > base)) {
156            outp--;
157            while ((outp > base) && (outp[-1] != '/'))
158              outp--;
159          }
160          break;
161        }
162        if (inp[2] == '/') {
163          inp += 3;
164          if (base == NULL)
165            continue;
166          if (outp > base) {
167            outp--;
168            while ((outp > base) && (outp[-1] != '/'))
169              outp--;
170          }
171          continue;
172        }
173      }
174    }
175    if (base == NULL)
176      base = inp;
177    while (inp[0] != '/') {
178      if ((*outp++ = *inp++) == '\0')
179        return;
180    }
181    *outp++ = '/';
182    while (inp[0] == '/')
183      inp++;
184  }
185  *outp = '\0';
186}
187
188static void rtems_tfs_eval_path(rtems_filesystem_eval_path_context_t *self)
189{
190  int eval_flags = rtems_filesystem_eval_path_get_flags(self);
191
192  if ((eval_flags & RTEMS_FS_MAKE) == 0) {
193    int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE;
194
195    if ((eval_flags & rw) != rw) {
196      rtems_filesystem_location_info_t *currentloc =
197        rtems_filesystem_eval_path_get_currentloc(self);
198      char *current = currentloc->node_access;
199      size_t currentlen = strlen(current);
200      const char *path = rtems_filesystem_eval_path_get_path(self);
201      size_t pathlen = rtems_filesystem_eval_path_get_pathlen(self);
202      size_t len = currentlen + pathlen;
203
204      rtems_filesystem_eval_path_clear_path(self);
205
206      current = realloc(current, len + 1);
207      if (current != NULL) {
208        memcpy(current + currentlen, path, pathlen);
209        current [len] = '\0';
210        if (!rtems_tfs_is_directory(current, len)) {
211          fixPath (current);
212        }
213        currentloc->node_access = current;
214      } else {
215        rtems_filesystem_eval_path_error(self, ENOMEM);
216      }
217    } else {
218      rtems_filesystem_eval_path_error(self, EINVAL);
219    }
220  } else {
221    rtems_filesystem_eval_path_error(self, EIO);
222  }
223}
224
225/*
226 * The routine which does most of the work for the IMFS open handler
227 * The full_path_name here is all text AFTER the TFS_PATHNAME_PREFIX
228 * string, so if the filename is "/TFS/abc", the full_path_name string
229 * is "abc"...
230 *
231 * Attempts to remap the incoming flags to TFS equivalent.
232 * Its not a perfect mapping, but gets pretty close.
233 * A comma-delimited path is supported to allow the user
234 * to specify TFS-stuff (flag string, info string, and a buffer).
235 * For example:
236 *  abc,e,script,0x400000
237 *  This is a file called "abc" that will have the TFS 'e' flag
238 *  and the TFS info field of "script".  The storage buffer is
239 *  supplied by the user at 0x400000.
240 */
241static int rtems_tfs_open_worker(
242  rtems_libio_t *iop,
243  char          *path,
244  int            oflag,
245  mode_t         mode
246)
247{
248  static int beenhere = 0;
249  long flagmode;
250  int  tfdidx, tfd;
251  struct tfdinfo *tip;
252  char *buf, *fstr, *istr, *bstr, pathcopy[TFSNAMESIZE*3+1];
253
254  if (RTEMS_TFS_DEBUG)
255    printk("_open_r(%s,0x%" PRIx32 ",0x%" PRIx32 ")\n",path,oflag,mode);
256
257  if (!beenhere) {
258    newlib_tfdlock();
259    for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++)
260      tfdtable[tfdidx].inuse = 0;
261
262    tfdtable[0].inuse = 1;    /* fake entry for stdin */
263    tfdtable[1].inuse = 1;    /* fake entry for stdout */
264    tfdtable[2].inuse = 1;    /* fake entry for stderr */
265    newlib_tfdunlock();
266    beenhere = 1;
267  }
268
269  istr = fstr = bstr = buf = (char *)0;
270
271  /* Copy the incoming path to a local array so that we can safely
272   * modify the string...
273    */
274  if (strlen(path) > TFSNAMESIZE*3) {
275    return(ENAMETOOLONG);
276  }
277  strcpy(pathcopy,path);
278
279  /* The incoming string may have commas that are used to delimit the
280   * name from the TFS flag string, TFS info string and buffer.
281   * Check for the commas and test for maximum string length...
282   */
283  fstr = strchr(pathcopy,',');
284  if (fstr)  {
285    *fstr++ = 0;
286    istr = strchr(fstr,',');
287    if (istr) {
288      *istr++ = 0;
289      bstr = strchr(istr,',');
290      if (bstr)
291        *bstr++ = 0;
292    }
293  }
294  if (strlen(pathcopy) > TFSNAMESIZE) {
295    return(ENAMETOOLONG);
296  }
297  if (istr) {
298    if (strlen(istr) > TFSNAMESIZE) {
299      return(ENAMETOOLONG);
300    }
301  }
302
303  /* If O_EXCL and O_CREAT are set, then fail if the file exists...
304   */
305  if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
306    if (mon_tfsstat((char *)pathcopy)) {
307      return(EEXIST);
308    }
309  }
310
311  /* Only a few flag combinations are supported...
312   * O_RDONLY             Simple read-only
313   * O_WRONLY | O_APPEND       Each write starts at end of file
314   * O_WRONLY | O_TRUNC       If file exists, truncate it
315   * O_WRONLY | O_CREAT       Create if it doesn't exist
316   * O_WRONLY | O_CREAT | O_EXCL   Fail if file exists
317   */
318  switch(oflag & O_ACCMODE) {
319    case O_RDONLY:
320      flagmode = TFS_RDONLY;
321      break;
322    case O_WRONLY|O_APPEND:
323      flagmode = TFS_APPEND;
324      break;
325    case O_WRONLY|O_TRUNC:
326    case O_WRONLY|O_CREAT|O_TRUNC:
327      mon_tfsunlink((char *)pathcopy);
328      flagmode = TFS_CREATE|TFS_APPEND;
329      break;
330    case O_WRONLY|O_CREAT:
331    case O_WRONLY|O_CREAT|O_APPEND:
332      flagmode = TFS_CREATE|TFS_APPEND;
333      break;
334    case O_RDWR:
335    case O_WRONLY|O_CREAT|O_EXCL:
336      flagmode = TFS_CREATE|TFS_APPEND;
337      break;
338    default:
339      printk("_open_r(): flag 0x%i not supported\n",oflag);
340      return(ENOTSUP);
341  }
342
343  /* Find an open slot in our tfd table:
344   */
345  newlib_tfdlock();
346  for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++) {
347    if (tfdtable[tfdidx].inuse == 0)
348      break;
349  }
350  if (tfdidx == MAXTFDS) {
351    newlib_tfdunlock();
352    return(EMFILE);
353  }
354  tip = &tfdtable[tfdidx];
355  tip->inuse = 1;
356  newlib_tfdunlock();
357
358  /* If file is opened for something other than O_RDONLY, then
359   * we need to allocate a buffer for the file..
360   * WARNING: It is the user's responsibility to make sure that
361   * the file size does not exceed this buffer.  Note that the
362   * buffer may be specified as part of the comma-delimited path.
363   */
364  if (flagmode == TFS_RDONLY) {
365    buf = (char *)0;
366  } else {
367    if (bstr)
368      buf = (char *)strtol(bstr,0,0);
369    else
370      buf = malloc(MAXFILESIZE);
371    if (!buf) {
372      newlib_tfdlock();
373      tip->inuse = 0;
374      newlib_tfdunlock();
375      return(ENOMEM);
376    }
377  }
378
379  /* Deal with tfs flags and tfs info fields if necessary:
380   */
381  if (fstr) {
382    long bflag;
383
384    bflag = mon_tfsctrl(TFS_FATOB,(long)fstr,0);
385    if (bflag == -1) {
386      return(EINVAL);
387    }
388    flagmode |= bflag;
389  }
390
391  if (istr)
392    strcpy(tip->info,istr);
393  else
394    tip->info[0] = 0;
395
396  tfd = mon_tfsopen((char *)pathcopy,flagmode,buf);
397  if (tfd >= 0) {
398    tip->tfd = tfd;
399    tip->buf = buf;
400    strcpy(tip->name,pathcopy);
401    iop->data0 = (uint32_t)tfdidx;
402    return(0);
403  } else {
404    printk("%s: %s\n",pathcopy,
405      (char *)mon_tfsctrl(TFS_ERRMSG,tfd,0));
406  }
407
408  if (buf)
409    free(buf);
410
411  newlib_tfdlock();
412  tip->inuse = 0;
413  newlib_tfdunlock();
414  return(EINVAL);
415}
416
417/*
418 * The IMFS open handler
419 */
420static int rtems_tfs_open(
421  rtems_libio_t *iop,
422  const char    *new_name,
423  int            oflag,
424  mode_t         mode
425)
426{
427  char *full_path_name;
428  int err;
429
430  full_path_name = iop->pathinfo.node_access;
431
432  if (RTEMS_TFS_DEBUG)
433    printk("rtems_tfs_open(%s)\n",full_path_name);
434
435  if (rtems_tfs_is_directory(full_path_name, strlen(full_path_name))) {
436    rtems_set_errno_and_return_minus_one (ENOTSUP);
437  }
438
439  err = rtems_tfs_open_worker (iop, full_path_name, oflag, mode);
440  if (err != 0) {
441     rtems_set_errno_and_return_minus_one (err);
442  }
443
444  return err;
445}
446
447/*
448 * Read from an open TFS file...
449 */
450static ssize_t rtems_tfs_read(
451  rtems_libio_t *iop,
452  void          *buffer,
453  uint32_t       count
454)
455{
456  int  ret, fd;
457
458  fd = (int) iop->data0;
459
460  if (RTEMS_TFS_DEBUG)
461    printk("_read_r(%d,%" PRId32 ")\n",fd,count);
462
463  if ((fd < 3) || (fd >= MAXTFDS))
464    return(EBADF);
465
466  ret = mon_tfsread(tfdtable[fd].tfd,buffer,count);
467  if (ret == TFSERR_EOF)
468    ret = 0;
469
470  return(ret);
471}
472
473/*
474 * Close the open tfs file.
475 */
476static int rtems_tfs_close(
477  rtems_libio_t *iop
478)
479{
480  int  fd;
481  char *info;
482  struct tfdinfo *tip;
483
484  fd = (int)iop->data0;
485
486  if (RTEMS_TFS_DEBUG)
487    printk("rtems_tfs_close(%d)\n",fd);
488
489  if ((fd < 3) || (fd >= MAXTFDS)) {
490    rtems_set_errno_and_return_minus_one (EBADF);
491  }
492
493  tip = &tfdtable[fd];
494
495  if (tip->info[0])
496    info = tip->info;
497  else
498    info = (char *)0;
499
500  mon_tfsclose(tip->tfd,info);
501
502  if (tip->buf)
503    free(tip->buf);
504
505  newlib_tfdlock();
506  tip->inuse = 0;
507  newlib_tfdunlock();
508  return RTEMS_SUCCESSFUL;
509}
510
511static ssize_t rtems_tfs_write(
512  rtems_libio_t *iop,
513  const void    *buffer,
514  uint32_t       count
515)
516{
517  int  ret, fd;
518
519  fd = (int) iop->data0;
520
521  if (RTEMS_TFS_DEBUG)
522    printk("rtems_tfs_write(%d,%" PRId32" )\n",fd,count);
523
524  if ((fd <= 0) || (fd >= MAXTFDS)) {
525    rtems_set_errno_and_return_minus_one (EBADF);
526  }
527
528  ret = mon_tfswrite(tfdtable[fd].tfd,(char *)buffer,count);
529  if (ret < 0)
530    return(-1);
531
532  return(ret);
533}
534
535static off_t rtems_tfs_lseek(
536  rtems_libio_t *iop,
537  off_t          offset,
538  int            whence
539)
540{
541  int ret, fd;
542
543  fd = (int) iop->data0;
544
545  if (RTEMS_TFS_DEBUG)
546    printk("rtems_tfs_lseek(%d,%ld,%d)\n",fd,(long)offset,whence);
547
548  switch (whence) {
549    case SEEK_END:
550      printk("rtems_tfs_lseek doesn't support SEEK_END\n");
551      return(-1);
552    case SEEK_CUR:
553      whence = TFS_CURRENT;
554      break;
555    case SEEK_SET:
556      whence = TFS_BEGIN;
557      break;
558  }
559  ret = mon_tfsseek(tfdtable[fd].tfd,offset,whence);
560
561  if (ret < 0)
562    return(-1);
563
564  return (off_t)ret;
565}
566
567/*
568 *
569 */
570static int rtems_tfs_ftruncate(
571  rtems_libio_t *iop,
572  off_t          count
573)
574{
575  int ret, fd;
576
577  fd = (int) iop->data0;
578  ret = mon_tfstruncate(tfdtable[fd].tfd,count);
579  if (ret != TFS_OKAY)
580    return(-1);
581
582  return(0);
583}
584
585static int rtems_tfs_ioctl(
586  rtems_libio_t *iop,
587  uint32_t       cmd,
588  void          *buf
589)
590{
591  int ret;
592
593  ret = mon_tfsctrl(cmd,(long)buf,0);
594  if (ret != TFS_OKAY)
595    return(-1);
596
597  return(0);
598}
599
600static rtems_filesystem_node_types_t rtems_tfs_node_type(
601  const rtems_filesystem_location_info_t *loc
602)
603{
604  const char *path = loc->node_access;
605  size_t pathlen = strlen(path);
606
607  return rtems_tfs_is_directory(path, pathlen) ?
608    RTEMS_FILESYSTEM_DIRECTORY
609      : RTEMS_FILESYSTEM_MEMORY_FILE;
610}
611
612static int rtems_tfs_clone_node_info(
613  rtems_filesystem_location_info_t *loc
614)
615{
616  int rv = 0;
617
618  loc->node_access = strdup(loc->node_access);
619
620  if (loc->node_access == NULL) {
621    errno = ENOMEM;
622    rv = -1;
623  }
624
625  return rv;
626}
627
628static void rtems_tfs_free_node_info(
629  const rtems_filesystem_location_info_t *loc
630)
631{
632  free(loc->node_access);
633}
634
635static bool rtems_tfs_are_nodes_equal(
636  const rtems_filesystem_location_info_t *a,
637  const rtems_filesystem_location_info_t *b
638)
639{
640  return strcmp(a->node_access, b->node_access) == 0;
641}
642
643static const rtems_filesystem_operations_table  rtems_tfs_ops = {
644  .lock_h = rtems_filesystem_default_lock,
645  .unlock_h = rtems_filesystem_default_unlock,
646  .eval_path_h = rtems_tfs_eval_path,
647  .link_h = rtems_filesystem_default_link,
648  .are_nodes_equal_h = rtems_tfs_are_nodes_equal,
649  .node_type_h = rtems_tfs_node_type,
650  .mknod_h = rtems_filesystem_default_mknod,
651  .rmnod_h = rtems_filesystem_default_rmnod,
652  .fchmod_h = rtems_filesystem_default_fchmod,
653  .chown_h = rtems_filesystem_default_chown,
654  .clonenod_h = rtems_tfs_clone_node_info,
655  .freenod_h = rtems_tfs_free_node_info,
656  .mount_h = rtems_filesystem_default_mount,
657  .fsmount_me_h = rtems_tfs_mount_me,
658  .unmount_h = rtems_filesystem_default_unmount,
659  .fsunmount_me_h = rtems_filesystem_default_fsunmount,
660  .utime_h = rtems_filesystem_default_utime,
661  .symlink_h = rtems_filesystem_default_symlink,
662  .readlink_h = rtems_filesystem_default_readlink,
663  .rename_h = rtems_filesystem_default_rename,
664  .statvfs_h = rtems_filesystem_default_statvfs
665};
666
667static const rtems_filesystem_file_handlers_r rtems_tfs_handlers = {
668  .open_h = rtems_tfs_open,
669  .close_h = rtems_tfs_close,
670  .read_h = rtems_tfs_read,
671  .write_h = rtems_tfs_write,
672  .ioctl_h = rtems_tfs_ioctl,
673  .lseek_h = rtems_tfs_lseek,
674  .fstat_h = rtems_filesystem_default_fstat,
675  .ftruncate_h = rtems_tfs_ftruncate,
676  .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
677  .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
678  .fcntl_h = rtems_filesystem_default_fcntl
679};
Note: See TracBrowser for help on using the repository browser.