File indexing completed on 2025-05-11 08:24:17
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 #ifdef HAVE_CONFIG_H
0045 #include "config.h"
0046 #endif
0047
0048 #include <stdio.h>
0049 #include <stdlib.h>
0050 #include <inttypes.h>
0051 #include <errno.h>
0052 #include <malloc.h>
0053 #include <string.h>
0054 #include <unistd.h>
0055 #include <fcntl.h>
0056 #include <rtems.h>
0057 #include <rtems/libio_.h>
0058 #include <rtems/seterr.h>
0059 #include <rtems/tftp.h>
0060 #include <rtems/thread.h>
0061
0062 #include "tftp_driver.h"
0063
0064
0065
0066
0067 #define TFTPFS_VERBOSE (1 << 0)
0068
0069
0070
0071
0072 typedef struct tftpfs_info_s {
0073 uint32_t flags;
0074 rtems_mutex tftp_mutex;
0075 size_t nStreams;
0076 void ** volatile tftpStreams;
0077 tftp_net_config tftp_config;
0078 } tftpfs_info_t;
0079
0080 #define tftpfs_info_mount_table(_mt) ((tftpfs_info_t*) ((_mt)->fs_info))
0081 #define tftpfs_info_pathloc(_pl) ((tftpfs_info_t*) ((_pl)->mt_entry->fs_info))
0082 #define tftpfs_info_iop(_iop) (tftpfs_info_pathloc (&((_iop)->pathinfo)))
0083
0084
0085 static const rtems_filesystem_operations_table rtems_tftp_ops;
0086 static const rtems_filesystem_file_handlers_r rtems_tftp_handlers;
0087
0088 static bool rtems_tftp_is_directory(
0089 const char *path,
0090 size_t pathlen
0091 )
0092 {
0093 return path [pathlen - 1] == '/';
0094 }
0095
0096
0097
0098
0099
0100
0101 ssize_t _Tftpfs_Parse_options(
0102 const char *option_str,
0103 tftp_net_config *tftp_config,
0104 uint32_t *flags
0105 )
0106 {
0107 const char *cur_pos = option_str;
0108 size_t verbose_len = strlen ("verbose");
0109 size_t rfc1350_len = strlen ("rfc1350");
0110 int len;
0111
0112 while(cur_pos != NULL && *cur_pos != '\0') {
0113 if (strncmp (cur_pos, "verbose", verbose_len) == 0) {
0114 *flags |= TFTPFS_VERBOSE;
0115 len = (int) verbose_len;
0116 } else if (strncmp (cur_pos, "rfc1350", rfc1350_len) == 0) {
0117 tftp_config->options.block_size = TFTP_RFC1350_BLOCK_SIZE;
0118 tftp_config->options.window_size = TFTP_RFC1350_WINDOW_SIZE;
0119 len = (int) rfc1350_len;
0120 } else if (sscanf(
0121 cur_pos,
0122 "blocksize=%"SCNu16"%n",
0123 &tftp_config->options.block_size,
0124 &len
0125 ) == 1) {
0126 } else if (sscanf(
0127 cur_pos,
0128 "windowsize=%"SCNu16"%n",
0129 &tftp_config->options.window_size,
0130 &len
0131 ) == 1) {
0132 } else if (*cur_pos == ',') {
0133 len = 0;
0134 } else {
0135 return cur_pos - option_str + 1;
0136 }
0137
0138 cur_pos += len;
0139 if (*cur_pos != ',' && *cur_pos != '\0') {
0140 return cur_pos - option_str + 1;
0141 }
0142 if (*cur_pos == ',') {
0143 cur_pos++;
0144 }
0145 }
0146
0147 return 0;
0148 }
0149
0150 int rtems_tftpfs_initialize(
0151 rtems_filesystem_mount_table_entry_t *mt_entry,
0152 const void *data
0153 )
0154 {
0155 const char *device = mt_entry->dev;
0156 size_t devicelen = strlen (device);
0157 tftpfs_info_t *fs = NULL;
0158 char *root_path;
0159 size_t err_pos;
0160 int errno_store = ENOMEM;
0161
0162 if (devicelen == 0) {
0163 root_path = malloc (1);
0164 if (root_path == NULL)
0165 goto error;
0166 root_path [0] = '\0';
0167 }
0168 else {
0169 root_path = malloc (devicelen + 2);
0170 if (root_path == NULL)
0171 goto error;
0172
0173 root_path = memcpy (root_path, device, devicelen);
0174 root_path [devicelen] = '/';
0175 root_path [devicelen + 1] = '\0';
0176 }
0177
0178 fs = malloc (sizeof (*fs));
0179 if (fs == NULL)
0180 goto error;
0181 fs->flags = 0;
0182 fs->nStreams = 0;
0183 fs->tftpStreams = 0;
0184
0185 tftp_initialize_net_config (&fs->tftp_config);
0186 err_pos = _Tftpfs_Parse_options (data, &fs->tftp_config, &fs->flags);
0187 if (err_pos != 0) {
0188 printf(
0189 "TFTP FS: ERROR in mount options '%s'.\n"
0190 "TFTP FS: Cannot parse from this point: '%s'\n",
0191 ((char *) data),
0192 ((char *) data) + (err_pos - 1)
0193 );
0194 errno_store = EINVAL;
0195 goto error;
0196 }
0197
0198 mt_entry->fs_info = fs;
0199 mt_entry->mt_fs_root->location.node_access = root_path;
0200 mt_entry->mt_fs_root->location.handlers = &rtems_tftp_handlers;
0201 mt_entry->ops = &rtems_tftp_ops;
0202
0203
0204
0205
0206
0207
0208
0209 rtems_mutex_init (&fs->tftp_mutex, "TFTPFS");
0210
0211 return 0;
0212
0213 error:
0214
0215 free (fs);
0216 free (root_path);
0217
0218 rtems_set_errno_and_return_minus_one (errno_store);
0219 }
0220
0221
0222
0223
0224 static void
0225 releaseStream (tftpfs_info_t *fs, size_t s)
0226 {
0227 rtems_mutex_lock (&fs->tftp_mutex);
0228 fs->tftpStreams[s] = NULL;
0229 rtems_mutex_unlock (&fs->tftp_mutex);
0230 }
0231
0232 static void
0233 rtems_tftpfs_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry)
0234 {
0235 tftpfs_info_t *fs = tftpfs_info_mount_table (mt_entry);
0236 size_t s;
0237 void *tp;
0238 for (s = 0; s < fs->nStreams; s++) {
0239 tp = fs->tftpStreams[s];
0240 releaseStream (fs, s);
0241 _Tftp_Destroy(tp);
0242 }
0243 rtems_mutex_destroy (&fs->tftp_mutex);
0244 free (fs);
0245 free (mt_entry->mt_fs_root->location.node_access);
0246 }
0247
0248
0249
0250
0251 static void
0252 fixPath (char *path)
0253 {
0254 char *inp, *outp, *base;
0255
0256 outp = inp = path;
0257 base = NULL;
0258 for (;;) {
0259 if (inp[0] == '.') {
0260 if (inp[1] == '\0')
0261 break;
0262 if (inp[1] == '/') {
0263 inp += 2;
0264 continue;
0265 }
0266 if (inp[1] == '.') {
0267 if (inp[2] == '\0') {
0268 if ((base != NULL) && (outp > base)) {
0269 outp--;
0270 while ((outp > base) && (outp[-1] != '/'))
0271 outp--;
0272 }
0273 break;
0274 }
0275 if (inp[2] == '/') {
0276 inp += 3;
0277 if (base == NULL)
0278 continue;
0279 if (outp > base) {
0280 outp--;
0281 while ((outp > base) && (outp[-1] != '/'))
0282 outp--;
0283 }
0284 continue;
0285 }
0286 }
0287 }
0288 if (base == NULL)
0289 base = inp;
0290 while (inp[0] != '/') {
0291 if ((*outp++ = *inp++) == '\0')
0292 return;
0293 }
0294 *outp++ = '/';
0295 while (inp[0] == '/')
0296 inp++;
0297 }
0298 *outp = '\0';
0299 return;
0300 }
0301
0302 static void rtems_tftp_eval_path(rtems_filesystem_eval_path_context_t *self)
0303 {
0304 int eval_flags = rtems_filesystem_eval_path_get_flags (self);
0305
0306 if ((eval_flags & RTEMS_FS_MAKE) == 0) {
0307 int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE;
0308
0309 if ((eval_flags & rw) != rw) {
0310 rtems_filesystem_location_info_t *currentloc =
0311 rtems_filesystem_eval_path_get_currentloc (self);
0312 char *current = currentloc->node_access;
0313 size_t currentlen = strlen (current);
0314 const char *path = rtems_filesystem_eval_path_get_path (self);
0315 size_t pathlen = rtems_filesystem_eval_path_get_pathlen (self);
0316 size_t len = currentlen + pathlen;
0317
0318 rtems_filesystem_eval_path_clear_path (self);
0319
0320 current = realloc (current, len + 1);
0321 if (current != NULL) {
0322 memcpy (current + currentlen, path, pathlen);
0323 current [len] = '\0';
0324 if (!rtems_tftp_is_directory (current, len)) {
0325 fixPath (current);
0326 }
0327 currentloc->node_access = current;
0328 } else {
0329 rtems_filesystem_eval_path_error (self, ENOMEM);
0330 }
0331 } else {
0332 rtems_filesystem_eval_path_error (self, EINVAL);
0333 }
0334 } else {
0335 rtems_filesystem_eval_path_error (self, EIO);
0336 }
0337 }
0338
0339
0340
0341
0342 static int rtems_tftp_open_worker(
0343 rtems_libio_t *iop,
0344 char *full_path_name,
0345 int oflag
0346 )
0347 {
0348 tftpfs_info_t *fs;
0349 void *tp;
0350 size_t s;
0351 char *cp1;
0352 char *remoteFilename;
0353 char *hostname;
0354 int err;
0355
0356
0357
0358
0359 fs = tftpfs_info_iop (iop);
0360
0361
0362
0363
0364 if (*full_path_name == '/')
0365 full_path_name++;
0366
0367 hostname = full_path_name;
0368 cp1 = strchr (full_path_name, ':');
0369 if (!cp1) {
0370 return EINVAL;
0371 } else {
0372 *cp1 = '\0';
0373 ++cp1;
0374 }
0375
0376
0377
0378
0379 if (*cp1 == '\0')
0380 return ENOENT;
0381 remoteFilename = cp1;
0382
0383
0384
0385
0386 err = tftp_open (
0387 hostname,
0388 remoteFilename,
0389 (oflag & O_ACCMODE) == O_RDONLY,
0390 &fs->tftp_config,
0391 &tp
0392 );
0393 if (err != 0) {
0394 return err;
0395 }
0396
0397
0398
0399
0400 rtems_mutex_lock (&fs->tftp_mutex);
0401 for (s = 0 ; s < fs->nStreams ; s++) {
0402 if (fs->tftpStreams[s] == NULL)
0403 break;
0404 }
0405 if (s == fs->nStreams) {
0406
0407
0408
0409
0410 void **np;
0411
0412 np = realloc (fs->tftpStreams, ++fs->nStreams * sizeof *fs->tftpStreams);
0413 if (np == NULL) {
0414 rtems_mutex_unlock (&fs->tftp_mutex);
0415 tftp_close( tp );
0416 return ENOMEM;
0417 }
0418 fs->tftpStreams = np;
0419 }
0420 fs->tftpStreams[s] = tp;
0421 rtems_mutex_unlock (&fs->tftp_mutex);
0422 iop->data0 = s;
0423 iop->data1 = tp;
0424
0425 return 0;
0426 }
0427
0428 static int rtems_tftp_open(
0429 rtems_libio_t *iop,
0430 const char *new_name,
0431 int oflag,
0432 mode_t mode
0433 )
0434 {
0435 tftpfs_info_t *fs;
0436 char *full_path_name;
0437 int err;
0438
0439 full_path_name = iop->pathinfo.node_access;
0440
0441 if (rtems_tftp_is_directory (full_path_name, strlen (full_path_name))) {
0442 rtems_set_errno_and_return_minus_one (ENOTSUP);
0443 }
0444
0445
0446
0447
0448 fs = tftpfs_info_iop (iop);
0449
0450 if (fs->flags & TFTPFS_VERBOSE)
0451 printf ("TFTPFS: %s\n", full_path_name);
0452
0453 err = rtems_tftp_open_worker (iop, full_path_name, oflag);
0454 if (err != 0) {
0455 rtems_set_errno_and_return_minus_one (err);
0456 }
0457
0458 return 0;
0459 }
0460
0461
0462
0463
0464 static ssize_t rtems_tftp_read(
0465 rtems_libio_t *iop,
0466 void *buffer,
0467 size_t count
0468 )
0469 {
0470 void *tp = iop->data1;
0471 ssize_t result = tftp_read (tp, buffer, count);
0472
0473 if (result < 0) {
0474 rtems_set_errno_and_return_minus_one (-result);
0475 }
0476 return result;
0477 }
0478
0479
0480
0481
0482 static int rtems_tftp_close(
0483 rtems_libio_t *iop
0484 )
0485 {
0486 tftpfs_info_t *fs;
0487 void *tp = iop->data1;
0488 int e = 0;
0489
0490
0491
0492
0493 fs = tftpfs_info_iop (iop);
0494
0495 if (!tp)
0496 rtems_set_errno_and_return_minus_one (EIO);
0497
0498 releaseStream (fs, iop->data0);
0499 e = tftp_close (tp);
0500 if (e)
0501 rtems_set_errno_and_return_minus_one (e);
0502 return 0;
0503 }
0504
0505 static ssize_t rtems_tftp_write(
0506 rtems_libio_t *iop,
0507 const void *buffer,
0508 size_t count
0509 )
0510 {
0511 void *tp = iop->data1;
0512 ssize_t result = tftp_write (tp, buffer, count);
0513
0514 if (result < 0) {
0515 rtems_set_errno_and_return_minus_one (-result);
0516 }
0517 return result;
0518 }
0519
0520
0521
0522
0523 static int rtems_tftp_ftruncate(
0524 rtems_libio_t *iop RTEMS_UNUSED,
0525 off_t count RTEMS_UNUSED
0526 )
0527 {
0528 return 0;
0529 }
0530
0531 static int rtems_tftp_fstat(
0532 const rtems_filesystem_location_info_t *loc,
0533 struct stat *buf
0534 )
0535 {
0536 const char *path = loc->node_access;
0537 size_t pathlen = strlen (path);
0538
0539 buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO
0540 | (rtems_tftp_is_directory (path, pathlen) ? S_IFDIR : S_IFREG);
0541
0542 return 0;
0543 }
0544
0545 static int rtems_tftp_clone(
0546 rtems_filesystem_location_info_t *loc
0547 )
0548 {
0549 int rv = 0;
0550
0551 loc->node_access = strdup (loc->node_access);
0552
0553 if (loc->node_access == NULL) {
0554 errno = ENOMEM;
0555 rv = -1;
0556 }
0557
0558 return rv;
0559 }
0560
0561 static void rtems_tftp_free_node_info(
0562 const rtems_filesystem_location_info_t *loc
0563 )
0564 {
0565 free (loc->node_access);
0566 }
0567
0568 static bool rtems_tftp_are_nodes_equal(
0569 const rtems_filesystem_location_info_t *a,
0570 const rtems_filesystem_location_info_t *b
0571 )
0572 {
0573 return strcmp (a->node_access, b->node_access) == 0;
0574 }
0575
0576 static const rtems_filesystem_operations_table rtems_tftp_ops = {
0577 .lock_h = rtems_filesystem_default_lock,
0578 .unlock_h = rtems_filesystem_default_unlock,
0579 .eval_path_h = rtems_tftp_eval_path,
0580 .link_h = rtems_filesystem_default_link,
0581 .are_nodes_equal_h = rtems_tftp_are_nodes_equal,
0582 .mknod_h = rtems_filesystem_default_mknod,
0583 .rmnod_h = rtems_filesystem_default_rmnod,
0584 .fchmod_h = rtems_filesystem_default_fchmod,
0585 .chown_h = rtems_filesystem_default_chown,
0586 .clonenod_h = rtems_tftp_clone,
0587 .freenod_h = rtems_tftp_free_node_info,
0588 .mount_h = rtems_filesystem_default_mount,
0589 .unmount_h = rtems_filesystem_default_unmount,
0590 .fsunmount_me_h = rtems_tftpfs_shutdown,
0591 .utimens_h = rtems_filesystem_default_utimens,
0592 .symlink_h = rtems_filesystem_default_symlink,
0593 .readlink_h = rtems_filesystem_default_readlink,
0594 .rename_h = rtems_filesystem_default_rename,
0595 .statvfs_h = rtems_filesystem_default_statvfs
0596 };
0597
0598 static const rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
0599 .open_h = rtems_tftp_open,
0600 .close_h = rtems_tftp_close,
0601 .read_h = rtems_tftp_read,
0602 .write_h = rtems_tftp_write,
0603 .ioctl_h = rtems_filesystem_default_ioctl,
0604 .lseek_h = rtems_filesystem_default_lseek,
0605 .fstat_h = rtems_tftp_fstat,
0606 .ftruncate_h = rtems_tftp_ftruncate,
0607 .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
0608 .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
0609 .fcntl_h = rtems_filesystem_default_fcntl,
0610 .kqfilter_h = rtems_filesystem_default_kqfilter,
0611 .mmap_h = rtems_filesystem_default_mmap,
0612 .poll_h = rtems_filesystem_default_poll,
0613 .readv_h = rtems_filesystem_default_readv,
0614 .writev_h = rtems_filesystem_default_writev
0615 };