[rtems commit] ftpfs: Fix SIZE command handling

Sebastian Huber sebh at rtems.org
Mon Jan 28 15:43:03 UTC 2013


Module:    rtems
Branch:    master
Commit:    b63c8f9b50c45d33e12a3776cbf03e498b2a6b99
Changeset: http://git.rtems.org/rtems/commit/?id=b63c8f9b50c45d33e12a3776cbf03e498b2a6b99

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon Jan 28 10:23:28 2013 +0100

ftpfs: Fix SIZE command handling

It is invalid to issue a SIZE command once a data transfer is
in progress.  For reads we issue the SIZE command before the RETR
command and get a snapshot of the file size.  For writes the file size
is initialized to zero and incremented for each write chunk.

---

 cpukit/libnetworking/lib/ftpfs.c    |  174 ++++++++++++++++++++---------------
 testsuites/libtests/ftp01/ftp01.scn |    4 +
 testsuites/libtests/ftp01/init.c    |   26 +++++-
 3 files changed, 124 insertions(+), 80 deletions(-)

diff --git a/cpukit/libnetworking/lib/ftpfs.c b/cpukit/libnetworking/lib/ftpfs.c
index 6ce2543..784ff48 100644
--- a/cpukit/libnetworking/lib/ftpfs.c
+++ b/cpukit/libnetworking/lib/ftpfs.c
@@ -64,6 +64,8 @@
  * Connection entry for each open file stream.
  */
 typedef struct {
+  off_t file_size;
+
   /**
    * Control connection socket.
    */
@@ -931,6 +933,93 @@ static int rtems_ftpfs_open_data_connection_passive(
   return 0;
 }
 
+typedef enum {
+  RTEMS_FTPFS_SIZE_START = 0,
+  RTEMS_FTPFS_SIZE_SPACE,
+  RTEMS_FTPFS_SIZE_NUMBER,
+  RTEMS_FTPFS_SIZE_NL
+} rtems_ftpfs_size_state;
+
+typedef struct {
+  rtems_ftpfs_size_state state;
+  size_t index;
+  off_t size;
+} rtems_ftpfs_size_entry;
+
+static void rtems_ftpfs_size_parser(
+  const char* buf,
+  size_t len,
+  void *arg
+)
+{
+  rtems_ftpfs_size_entry *se = arg;
+  size_t i = 0;
+
+  for (i = 0; se->size >= 0 && i < len; ++i, ++se->index) {
+    int c = buf [i];
+
+    switch (se->state) {
+      case RTEMS_FTPFS_SIZE_START:
+        if (se->index == 2) {
+          se->state = RTEMS_FTPFS_SIZE_SPACE;
+        }
+        break;
+      case RTEMS_FTPFS_SIZE_SPACE:
+        if (c == ' ') {
+          se->state = RTEMS_FTPFS_SIZE_NUMBER;
+        } else {
+          se->size = -1;
+        }
+        break;
+      case RTEMS_FTPFS_SIZE_NUMBER:
+        if (isdigit(c)) {
+          se->size = 10 * se->size + c - '0';
+        } else if (c == '\r') {
+          se->state = RTEMS_FTPFS_SIZE_NL;
+        } else {
+          se->size = -1;
+        }
+        break;
+      case RTEMS_FTPFS_SIZE_NL:
+        if (c != '\n') {
+          se->size = -1;
+        }
+        break;
+      default:
+        se->size = -1;
+        break;
+    }
+  }
+}
+
+static void rtems_ftpfs_get_file_size(rtems_ftpfs_entry *e, bool verbose)
+{
+  if (e->file_size < 0) {
+    if (e->write) {
+      e->file_size = 0;
+    } else {
+      rtems_ftpfs_size_entry se;
+      rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
+
+      memset(&se, 0, sizeof(se));
+
+      reply = rtems_ftpfs_send_command_with_parser(
+        e,
+        "SIZE ",
+        e->filename,
+        rtems_ftpfs_size_parser,
+        &se,
+        verbose
+      );
+      if (reply == RTEMS_FTPFS_REPLY_2 && se.size >= 0) {
+        e->file_size = se.size;
+      } else {
+        e->file_size = 0;
+      }
+    }
+  }
+}
+
 static int rtems_ftpfs_open(
   rtems_libio_t *iop,
   const char *path,
@@ -955,6 +1044,10 @@ static int rtems_ftpfs_open(
   }
 
   if (eno == 0) {
+    rtems_ftpfs_get_file_size(e, verbose);
+  }
+
+  if (eno == 0) {
     const char *file_command = e->write ? "STOR " : "RETR ";
 
     /* Open passive data connection */
@@ -1052,6 +1145,8 @@ static ssize_t rtems_ftpfs_write(
 
     out += rv;
     todo -= (size_t) rv;
+
+    e->file_size += rv;
   }
 
   return (ssize_t) (count - todo);
@@ -1119,6 +1214,7 @@ static void rtems_ftpfs_eval_path(
         e->ino = me->ino;
         rtems_libio_unlock();
 
+        e->file_size = -1;
         e->ctrl_socket = -1;
 
         eno = rtems_ftpfs_open_ctrl_connection(
@@ -1238,65 +1334,6 @@ static int rtems_ftpfs_ioctl(
   return 0;
 }
 
-typedef enum {
-  RTEMS_FTPFS_SIZE_START = 0,
-  RTEMS_FTPFS_SIZE_SPACE,
-  RTEMS_FTPFS_SIZE_NUMBER,
-  RTEMS_FTPFS_SIZE_NL
-} rtems_ftpfs_size_state;
-
-typedef struct {
-  rtems_ftpfs_size_state state;
-  size_t index;
-  off_t size;
-} rtems_ftpfs_size_entry;
-
-static void rtems_ftpfs_size_parser(
-  const char* buf,
-  size_t len,
-  void *arg
-)
-{
-  rtems_ftpfs_size_entry *se = arg;
-  size_t i = 0;
-
-  for (i = 0; se->size >= 0 && i < len; ++i, ++se->index) {
-    int c = buf [i];
-
-    switch (se->state) {
-      case RTEMS_FTPFS_SIZE_START:
-        if (se->index == 2) {
-          se->state = RTEMS_FTPFS_SIZE_SPACE;
-        }
-        break;
-      case RTEMS_FTPFS_SIZE_SPACE:
-        if (c == ' ') {
-          se->state = RTEMS_FTPFS_SIZE_NUMBER;
-        } else {
-          se->size = -1;
-        }
-        break;
-      case RTEMS_FTPFS_SIZE_NUMBER:
-        if (isdigit(c)) {
-          se->size = 10 * se->size + c - '0';
-        } else if (c == '\r') {
-          se->state = RTEMS_FTPFS_SIZE_NL;
-        } else {
-          se->size = -1;
-        }
-        break;
-      case RTEMS_FTPFS_SIZE_NL:
-        if (c != '\n') {
-          se->size = -1;
-        }
-        break;
-      default:
-        se->size = -1;
-        break;
-    }
-  }
-}
-
 /*
  * The stat() support is intended only for the cp shell command.  Each request
  * will return that we have a regular file with read, write and execute
@@ -1319,24 +1356,9 @@ static int rtems_ftpfs_fstat(
 
   if (e->do_size_command) {
     const rtems_ftpfs_mount_entry *me = loc->mt_entry->fs_info;
-    rtems_ftpfs_size_entry se;
-    rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
 
-    memset(&se, 0, sizeof(se));
-
-    reply = rtems_ftpfs_send_command_with_parser(
-      e,
-      "SIZE ",
-      e->filename,
-      rtems_ftpfs_size_parser,
-      &se,
-      me->verbose
-    );
-    if (reply == RTEMS_FTPFS_REPLY_2 && se.size >= 0) {
-      st->st_size = se.size;
-    } else {
-      eno = EIO;
-    }
+    rtems_ftpfs_get_file_size(e, me->verbose);
+    st->st_size = e->file_size;
   } else {
     e->do_size_command = true;
   }
diff --git a/testsuites/libtests/ftp01/ftp01.scn b/testsuites/libtests/ftp01/ftp01.scn
index a329296..a27da4b 100644
--- a/testsuites/libtests/ftp01/ftp01.scn
+++ b/testsuites/libtests/ftp01/ftp01.scn
@@ -17,6 +17,8 @@ USER anonymous
 230 User logged in.
 TYPE I
 200 Type set to I.
+SIZE a.txt
+213 1102
 PASV
 227 Entering passive mode (127,0,0,1,4,4).
 RETR a.txt
@@ -41,6 +43,8 @@ USER anonymous
 230 User logged in.
 TYPE I
 200 Type set to I.
+SIZE b.txt
+213 1102
 PASV
 227 Entering passive mode (127,0,0,1,4,10).
 RETR b.txt
diff --git a/testsuites/libtests/ftp01/init.c b/testsuites/libtests/ftp01/init.c
index 354c0f0..369aebe 100644
--- a/testsuites/libtests/ftp01/init.c
+++ b/testsuites/libtests/ftp01/init.c
@@ -104,7 +104,7 @@ static void change_self_priority(void)
   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
 }
 
-static void create_file(const char *path)
+static void create_file(const char *path, const void *begin, size_t size)
 {
   int rv = 0;
   int fd = open(path, O_WRONLY);
@@ -112,8 +112,8 @@ static void create_file(const char *path)
 
   rtems_test_assert(fd >= 0);
 
-  n = write(fd, &content [0], sizeof(content));
-  rtems_test_assert(n == (ssize_t) sizeof(content));
+  n = write(fd, begin, size);
+  rtems_test_assert(n == (ssize_t) size);
 
   rv = close(fd);
   rtems_test_assert(rv == 0);
@@ -126,15 +126,33 @@ static void copy_file(const char *src_path, const char *dest_path)
   int out = open(dest_path, O_WRONLY);
   ssize_t n_in = 0;
   char buf [64];
+  struct stat st_in;
+  struct stat st_out;
+
+  memset(&st_in, 0xff, sizeof(st_in));
+  memset(&st_out, 0xff, sizeof(st_out));
 
   rtems_test_assert(in >= 0);
   rtems_test_assert(out >= 0);
 
+  rv = fstat(out, &st_out);
+  rtems_test_assert(rv == 0);
+
+  rtems_test_assert(st_out.st_size == 0);
+
   while ((n_in = read(in, buf, sizeof(buf))) > 0) {
     ssize_t n_out = write(out, buf, (size_t) n_in);
     rtems_test_assert(n_out == n_in);
   }
 
+  rv = fstat(out, &st_out);
+  rtems_test_assert(rv == 0);
+
+  rv = fstat(in, &st_in);
+  rtems_test_assert(rv == 0);
+
+  rtems_test_assert(st_in.st_size == st_out.st_size);
+
   rv = close(out);
   rtems_test_assert(rv == 0);
 
@@ -189,7 +207,7 @@ static void test(void)
 
   initialize_ftpfs();
   change_self_priority();
-  create_file(file_a);
+  create_file(file_a, &content [0], sizeof(content));
   copy_file(file_a, file_b);
   check_file(file_b);
   check_file_size(file_a, sizeof(content));




More information about the vc mailing list