Restored REST functionality (reimplementation) since some clients use it
authorMatthew Mondor <mmondor@pulsar-zone.net>
Tue, 11 Mar 2008 17:09:55 +0000 (17:09 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Tue, 11 Mar 2008 17:09:55 +0000 (17:09 +0000)
with STREAM with a byte offset to resume files.

mmsoftware/mmftpd/src/mmftpd.c
mmsoftware/mmftpd/src/mmftpd.h

index 2072d77..0324333 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmftpd.c,v 1.76 2008/03/11 04:25:29 mmondor Exp $ */
+/* $Id: mmftpd.c,v 1.77 2008/03/11 17:09:55 mmondor Exp $ */
 
 /*
  * Copyright (C) 2001-2008, Matthew Mondor
@@ -92,7 +92,7 @@
 
 MMCOPYRIGHT("@(#) Copyright (c) 2001-2004\n\
 \tMatthew Mondor. All rights reserved.\n");
-MMRCSID("$Id: mmftpd.c,v 1.76 2008/03/11 04:25:29 mmondor Exp $");
+MMRCSID("$Id: mmftpd.c,v 1.77 2008/03/11 17:09:55 mmondor Exp $");
 
 
 
@@ -171,7 +171,7 @@ static struct command commands[] = {
     {2, "STOU", "[<file>]", "Store unique file"},
     {2, "APPE", "<file>", "Permits upload to append on file"},
     {3, "ALLO", "<bytes> [<frame>]", "Allocate storage"},
-    {2, "REST", "<marker>", NULL},
+    {2, "REST", "<bytes>", "Restore at byte offset"},
     {3, "RNFR", "<file>", "Rename from"},
     {3, "RNTO", "<file>", "Rename to"},
     {3, "ABOR", "", "Abort command"},
@@ -263,7 +263,7 @@ static int (*state_main[])(clientenv *) = {
        main_stou,              /* STOU */
        main_appe,              /* APPE */
        main_allo,              /* ALLO */
-       NULL,                   /* REST */
+       main_rest,              /* REST */
        main_rnfr,              /* RNFR */
        main_rnto,              /* RNTO */
        main_abor,              /* ABOR */
@@ -1256,6 +1256,11 @@ main_retr(clientenv *clenv)
                if (msg->port != 0) {
                    if (!msg->ongoing) {
                        if ((file = open(path, O_RDONLY)) != -1) {
+                           if (clenv->rest != 0) {
+                               if (lseek(file, clenv->rest, SEEK_SET) == -1)
+                                   DEBUG_PRINTF("main_retr", "lseek()");
+                           }
+                           clenv->rest = 0;
                            msg->file = file;
                            msg->list = 0;
                            msg->download = TRUE;
@@ -1319,7 +1324,8 @@ main_stor(clientenv *clenv)
     long fsize;
 
     /* We only permit uploading if user has upload permissions. We however only
-     * allow overwriting an existing file if user also has modify permissions.
+     * allow overwriting an existing file or appending to it if user also has
+     * modify permissions.
      */
     if (clenv->upload) {
        if (path_valid(path, cpath, clenv->home, clenv->cwd,
@@ -1342,18 +1348,33 @@ main_stor(clientenv *clenv)
                                 * use to exceed the quota, but, to make sure,
                                 * check for minfilesize first.
                                 */
-                               if (treesize_edit(clenv,
+                               if (clenv->rest != 0 || treesize_edit(clenv,
                                            clenv->minfilesize)) {
-                                   if ((file = open(path,
+                                   if (clenv->rest != 0 && i != MMPATH_NONE) {
+                                       file = open(path, O_WRONLY, mode);
+                                       if (file != -1) {
+                                           if (lseek(file, clenv->rest,
+                                                       SEEK_SET) == -1) {
+                                               (void) close(file);
+                                               file = -1;
+                                           }
+                                       }
+                                   } else
+                                       file = open(path,
                                                O_WRONLY | O_CREAT | O_TRUNC,
-                                               mode)) != -1) {
-                                       if (i != MMPATH_NONE && fsize > 0)
+                                               mode);
+                                   if (file != -1) {
+                                       if (i != MMPATH_NONE && fsize > 0 &&
+                                               clenv->rest == 0)
                                            treesize_edit(clenv,
                                                 (clenv->minfilesize - fsize));
-                                       if ((fchown(file, -1, clenv->gid))
-                                               == -1)
-                                           DEBUG_PRINTF("main_stor",
-                                                   "fchown(%s)", path);
+                                       if (clenv->rest == 0) {
+                                           if ((fchown(file, -1, clenv->gid))
+                                                   == -1)
+                                               DEBUG_PRINTF("main_stor",
+                                                       "fchown(%s)", path);
+                                       }
+                                       clenv->rest = 0;
                                        msg->file = file;
                                        msg->list = 0;
                                        msg->download = FALSE;
@@ -1667,6 +1688,33 @@ main_allo(clientenv *clenv)
 
 
 static int
+main_rest(clientenv *clenv)
+{
+    char       *args[3], *t;
+    off_t      rest;
+
+    clenv->rest = 0;
+    if ((mm_straspl(args, clenv->buffer, 2)) == 2) {
+       rest = (off_t)strtoull(args[1], &t, 10);
+       if (*args[1] != '\0' && *t == '\0' && rest != 0) {
+           clenv->rest = rest;
+           reply(clenv->fdb, 350, FALSE,
+                   "Restarting at %lld, waiting for STOR/RETR",
+                   (int64_t)clenv->rest);
+       } else {
+           reply(clenv->fdb, 550, FALSE, "Invalid value");
+           REGISTER_ERROR();
+       }
+    } else {
+       reply(clenv->fdb, 550, FALSE, "Command syntax error");
+       REGISTER_ERROR();
+    }
+
+    return (STATE_CURRENT);
+}
+
+
+static int
 main_rnfr(clientenv *clenv)
 {
     int t = MMPATH_DENIED;
@@ -1759,6 +1807,7 @@ main_abor(clientenv *clenv)
     transfermsg *msg = &(clenv->tmsg);
 
     if ((mm_straspl(args, clenv->buffer, 1)) == 1) {
+       clenv->rest = 0;
        if (clenv->rnfr)
            clenv->rnfr = mmstrfree(clenv->rnfr);
        reply(clenv->fdb, 226, FALSE, "Aborted");
@@ -3550,6 +3599,7 @@ handleclient(unsigned long cid, int fd, clientlistnode *clientlnode,
                clenv->id = cid;
                clenv->iface = iface;
                clenv->aclenv = aclenv;
+               clenv->rest = 0;
 
                mmstat(&clenv->vstat, STAT_UPDATE, 1,
                        "mmftpd|current|connections");
index 4da54c5..15b5cad 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmftpd.h,v 1.31 2008/03/11 04:22:55 mmondor Exp $ */
+/* $Id: mmftpd.h,v 1.32 2008/03/11 17:09:55 mmondor Exp $ */
 
 /*
  * Copyright (C) 2001-2008, Matthew Mondor
@@ -222,6 +222,7 @@ typedef struct clientenv {
     long maxlogins;              /* Allowed simultanious logins for user */
     off_t maxhomesize;           /* Maximum home directory size (or -1) */
     off_t minfilesize;           /* If limits used, minimum file size */
+    off_t rest;                          /* Restore at byte offset */
     mode_t umask;                /* Current umask */
     bool anonymous;              /* TRUE if anonymous login acount */
     bool login;                          /* TRUE if user currently logged in */
@@ -382,6 +383,7 @@ static int main_stor(clientenv *);
 static int main_stou(clientenv *);
 static int main_appe(clientenv *);
 static int main_allo(clientenv *);
+static int main_rest(clientenv *);
 static int main_rnfr(clientenv *);
 static int main_rnto(clientenv *);
 static int main_abor(clientenv *);