]> git.sesse.net Git - betaftpd/blobdiff - cmds.c
Added a notice about a (not yet fixed) dcache bug.
[betaftpd] / cmds.c
diff --git a/cmds.c b/cmds.c
index 3af02a354c25f39f893b21b5d9b568a0154a77f5..a2e047bc51eef0a54ffc3d8d46ea4f74c74108ba 100644 (file)
--- a/cmds.c
+++ b/cmds.c
 #include <cmds.h>
 #include <nonroot.h>
 
+#if WANT_DCACHE
+#include <dcache.h>
+#endif
+
 #define lstat stat
 
 extern struct conn *first_conn;
@@ -806,7 +810,7 @@ int cmd_rnfr(struct conn * const c)
        snprintf(c->rename_from, 256, "%s/%s", cwd, fname);
 
        /* Just check that the file exists. */
-       TRAP_ERROR(lstat(c->rename_from, &buf) == -1, 550, return 1);
+       TRAP_ERROR(lstat(c->rename_from, &buf) == -1, 550, c->rename_from[0] = '\0'; return 1);
 
        numeric(c, 350, "File exists, send RNTO.");
        return 1;
@@ -825,9 +829,10 @@ int cmd_rnto(struct conn * const c)
                return 1;
        }
 
-       TRAP_ERROR(rename(c->rename_from, fname) == -1, 550, return 1);
+       TRAP_ERROR(rename(c->rename_from, fname) == -1, 550, c->rename_from[0] = '\0'; return 1);
+       c->rename_from[0] = '\0';
 
-       numeric(c, 250, "File renamed successfulyy.");
+       numeric(c, 250, "File renamed successfully.");
        return 1;
 }
 
@@ -984,9 +989,14 @@ int _mwrite(const char * const buf, const struct ftran * const f,
 
 /*
  * mwrite:     This is a short_hand define, making calls to _mwrite() very
- *             similiar to calls to write().
+ *             similiar to calls to write(). It works both with and without
+ *             mmap().
  */
+#if HAVE_MMAP
 #define mwrite(buf, count) pos = _mwrite((buf), (f), (pos), (count), (size));
+#else
+#define mwrite(buf, count) write(f->local_file, buf, count);
+#endif
 
 /*
  * long_listing():
@@ -1057,9 +1067,9 @@ int long_listing(char * const retbuf, const char * const pathname, const int do_
                        return 0;
                }
 
-               i = snprintf(temp, 1024, "%c%s %3u %-8s %-8s %8lu %12s %s\r\n",
+               snprintf(temp, 1024, "%c%s %3u %-8s %-8s %8lu %12s %s\r\n",
 #else
-               i = snprintf(temp, 1024, "%c%c%c%c%c%c%c%c%c%c %3u %-8s %-8s %8lu %12s %s",
+               snprintf(temp, 1024, "%c%c%c%c%c%c%c%c%c%c %3u %-8s %-8s %8lu %12s %s",
 #endif
                        decode_mode(buf.st_mode),
 #if WANT_NONROOT
@@ -1077,7 +1087,8 @@ int long_listing(char * const retbuf, const char * const pathname, const int do_
 #endif
                        buf.st_nlink, username, groupname,
                        (unsigned long)(buf.st_size), newd, pathname);
-
+               i = strlen(temp);
+       
 #if 0
                /*
                 * vim needs this extra character for some reason... It's too 
@@ -1108,7 +1119,7 @@ int cmd_list(struct conn * const c)
 {
        struct list_options lo;
 
-/*     lo.recursive = 0; */
+       lo.recursive = 0;
        lo.long_listing = 1;
        lo.classify = 0;
 
@@ -1127,7 +1138,7 @@ int cmd_nlst(struct conn * const c)
 {
        struct list_options lo;
 
-/*     lo.recursive = 0; */
+       lo.recursive = 0;
        lo.long_listing = 0;
        lo.classify = 0;
 
@@ -1212,30 +1223,14 @@ void do_listing(struct conn * const c, struct list_options * const lo)
                size = num_files * 160;
                f->file_data = malloc(size + 1);
                TRAP_ERROR(f->file_data == NULL, 550, return);
-               list_core(c, ptr, lo, size);
+               list_core(c, ptr, "", lo, size, 0);
        }
 #else
-       list_core(c, ptr, lo);
+       list_core(c, ptr, "", lo);
 #endif
 
 #if WANT_DCACHE
-       /* populate the directory listing cache */
-       {
-               struct stat buf;
-               struct dcache *d = alloc_new_dcache();
-               if (d != NULL && stat(cwd, &buf) > -1) {
-                       d->use_count++;
-                       f->dir_cache = d;
-                       d->dir_data = f->file_data;
-                       d->dir_size = f->size;
-                       d->generated = buf.st_mtime;
-
-                       strcpy(d->dir_name, cwd);
-                       strncpy(d->pattern, ptr, 255);
-                       d->pattern[255] = 0;
-                       d->lo = *lo;
-               }
-       }
+       populate_dcache(f, cwd, ptr, lo);
 #endif
 
 #if HAVE_MMAP
@@ -1272,8 +1267,8 @@ int get_num_files(struct conn * const c, const char * const pathname,
                return -1;
        }
 
-#if 0  /* the rest of the code doesn't support recursion yet */
        if (lo->recursive) {
+               int i;
                        for (i = 0; i < pglob.gl_pathc; i++) {
                        char *temp = pglob.gl_pathv[i];
                        struct stat buf;
@@ -1286,7 +1281,8 @@ int get_num_files(struct conn * const c, const char * const pathname,
                        }
                }
        }
-#endif
+
+       globfree(&pglob);
 
        return num_files;
 }
@@ -1301,20 +1297,20 @@ int get_num_files(struct conn * const c, const char * const pathname,
  *             under 80 for long listings, and a little under 160 for
  *             short listings), the list will be truncated. Fix...
  *
+ *             The return value only makes sense if mmap()'ing, since it
+ *             returns the number of bytes written into the buffer.
+ *
  *             This function is rather long.
  */
-void list_core(struct conn * const c, const char * const pathname,
-              struct list_options * const lo
+int list_core(struct conn * const c, const char * const pathname,
+             char * const disp_pathname, struct list_options * const lo
 #if HAVE_MMAP
-               , const int size
+               , const int size, int pos
 #endif
                )
 {
        int i;
        glob_t pglob;
-#if HAVE_MMAP
-       int pos = 0;
-#endif
        struct ftran * const f = c->transfer;
 
         /*
@@ -1326,12 +1322,28 @@ void list_core(struct conn * const c, const char * const pathname,
 #ifdef GLOB_NOMATCH
        case GLOB_NOMATCH:
 #endif
-                break;
+                break;         /* note: break, not return */
         default:
                 numeric(c, 550, strerror(EACCES));
-                return;
+#if HAVE_MMAP
+               return pos;
+#else
+                return 0;
+#endif
         }
 
+       if (lo->recursive) {
+               if (disp_pathname[0] == '\0') {
+                       mwrite(".:\r\n", 4);
+               } else {
+                       char temp[1024];
+                       int i;
+
+                       snprintf(temp, 1024, "%s:\r\n", disp_pathname);
+                       i = strlen(temp);
+                       mwrite(temp, i);
+               }
+       }
        if (lo->long_listing) {
                /* FIX: we may get too high total number if we are running nonroot! */
                struct stat buf;
@@ -1343,12 +1355,9 @@ void list_core(struct conn * const c, const char * const pathname,
                                total += buf.st_blocks;
                        }
                }
-               i = snprintf(temp, 1024, "total %lu\r\n", total >> 1); 
-#if HAVE_MMAP
+               snprintf(temp, 1024, "total %lu\r\n", total >> 1);
+               i = strlen(temp);
                mwrite(temp, i);
-#else
-               write(f->local_file, temp, i);
-#endif
        }
 
        for (i = 0; i < pglob.gl_pathc; i++) {
@@ -1379,15 +1388,43 @@ void list_core(struct conn * const c, const char * const pathname,
                        }
                }
 
-               /* support recursion here some day... */
-
-#if HAVE_MMAP
                mwrite(buf, strlen(buf));
                mwrite("\r\n", 2);
-#else
-               write(f->local_file, buf, strlen(buf));
-               write(f->local_file, "\r\n", 2);
+       }
+
+       /*
+        * If recursion is on, dive into any subdirectories now -- note
+        * that each entry is stat()'ed twice, hopefully the OS will manage,
+        * and we've got our own dcache anyways -- this could be fixed at
+        * the expense of some memory, consider for later inclusion.
+        */
+       if (lo->recursive) {
+               for (i = 0; i < pglob.gl_pathc; i++) {
+                       struct stat buf;
+                       const char * const temp = pglob.gl_pathv[i];
+
+                       /* don't dive into `.' or `..' */
+                        if (lstat(temp, &buf) != -1 && S_ISDIR(buf.st_mode) &&
+                               (temp[0] != '.' || (temp[1] != '.' && temp[1] != '\0'))) {
+                               char tmp2[1024];
+
+                               mwrite("\r\n", 2);
+
+                               /* attach the pathname to the end of the displayed path */
+                               if (disp_pathname[0] == '\0') {
+                                       snprintf(tmp2, 1024, "%s", temp);
+                               } else {
+                                       snprintf(tmp2, 1024, "%s/%s", disp_pathname, temp);
+                               }
+
+                               chdir(temp);
+                               pos = list_core(c, "*", tmp2, lo, 
+#if HAVE_MMAP
+                                       size, pos);
 #endif
+                               chdir("..");
+                       }
+               }
        }
 
 #if HAVE_MMAP
@@ -1397,6 +1434,11 @@ void list_core(struct conn * const c, const char * const pathname,
 #endif
 
        globfree(&pglob);
+#if HAVE_MMAP
+       return pos;
+#else
+       return 0;
+#endif
 }
 
 /*
@@ -1441,22 +1483,30 @@ int cmd_type(struct conn * const c)
 }
 
 /*
- * cmd_mode(): Handles the MODE command. We always use stream mode,
- *             so the argument is ignored.
+ * cmd_mode(): Handles the MODE command. Only stream mode is supported.
  */
 int cmd_mode(struct conn * const c)
 {
-       numeric(c, 200, "MODE ignored (always S)");
+       c->recv_buf[0] &= (255-32);     /* convert to upper case */
+       if (c->recv_buf[0] == 'S') {
+               numeric(c, 200, "Mode is STREAM.");
+       } else {
+               numeric(c, 504, "Unknown mode.");
+       }
        return 1;
 }
 
 /*
- * cmd_stru(): Handles the STRU command. We always use file mode,
- *             so the argument is ignored.
+ * cmd_stru(): Handles the STRU command. Only file mode is supported.
  */
 int cmd_stru(struct conn * const c)
 {
-       numeric(c, 200, "STRU ignored (always F)");
+       c->recv_buf[0] &= (255-32);     /* convert to upper case */
+       if (c->recv_buf[0] == 'F') {
+               numeric(c, 200, "Structure is FILE.");
+       } else {
+               numeric(c, 504, "Unknown structure.");
+       }
        return 1;
 }
 
@@ -1802,11 +1852,9 @@ int prepare_for_listing(struct conn * const c, char ** const ptr,
        if (optr != NULL) {
                while (*++optr) {
                        switch (*optr & (255-32)) {     /* uppercase */
-#if 0
                        case 'R':       /* actually case sensitive... */
                                lo->recursive = 1;
                                break;
-#endif
                        case 'L':
                                lo->long_listing = 1;
                                break;