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

4.115
Last change on this file since 183af89 was 2563410, checked in by Sebastian Huber <sebastian.huber@…>, on 03/13/12 at 08:22:11

Filesystem: Rename defines

o Removed RTEMS_LIBIO_PERMS_SEARCH.
o Renamed RTEMS_LIBIO_PERMS_READ in RTEMS_FS_PERMS_READ.
o Renamed RTEMS_LIBIO_PERMS_WRITE in RTEMS_FS_PERMS_WRITE.
o Renamed RTEMS_LIBIO_PERMS_EXEC in RTEMS_FS_PERMS_EXEC.
o Renamed RTEMS_LIBIO_FOLLOW_HARD_LINK in RTEMS_FS_FOLLOW_HARD_LINK.
o Renamed RTEMS_LIBIO_FOLLOW_SYM_LINK in RTEMS_FS_FOLLOW_SYM_LINK.
o Renamed RTEMS_LIBIO_MAKE in RTEMS_FS_MAKE.
o Renamed RTEMS_LIBIO_EXCLUSIVE in RTEMS_FS_EXCLUSIVE.
o Renamed RTEMS_LIBIO_ACCEPT_RESIDUAL_DELIMITERS in

RTEMS_FS_ACCEPT_RESIDUAL_DELIMITERS.

o Renamed RTEMS_LIBIO_REJECT_TERMINAL_DOT in
RTEMS_FS_REJECT_TERMINAL_DOT.

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