]> git.sesse.net Git - betaftpd/blobdiff - cmds.c
Updated the version number to 0.0.8pre18 (forgot to do so upon the release of 0.0...
[betaftpd] / cmds.c
diff --git a/cmds.c b/cmds.c
index a8453def6aacbc4f01c3076a0fae9611cb0382ea..500d6c28e4d20e900fc5afafbcfd3ec34b90d29d 100644 (file)
--- a/cmds.c
+++ b/cmds.c
@@ -2,7 +2,7 @@
     Copyright (C) 1999-2000 Steinar H. Gunderson
 
     This program is is free software; you can redistribute it and/or modify
     Copyright (C) 1999-2000 Steinar H. Gunderson
 
     This program is is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License, version 2 if the
+    it under the terms of the GNU General Public License, version 2 of the
     License as published by the Free Software Foundation.
 
     This program is distributed in the hope that it will be useful,
     License as published by the Free Software Foundation.
 
     This program is distributed in the hope that it will be useful,
 #include <config.h>
 #endif
 
 #include <config.h>
 #endif
 
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
 #if HAVE_STROPTS_H
 #include <stropts.h>
 #endif
 #if HAVE_STROPTS_H
 #include <stropts.h>
 #endif
 #include <fcntl.h>
 #endif
 
 #include <fcntl.h>
 #endif
 
-#if HAVE_PWD_H
-#include <pwd.h>
-#endif
-
 #if HAVE_GRP_H
 #include <grp.h>
 #endif
 #if HAVE_GRP_H
 #include <grp.h>
 #endif
 #include <sys/ioctl.h>
 #endif
 
 #include <sys/ioctl.h>
 #endif
 
-#if HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
 #include <sys/conf.h>
 #endif
 
 #include <sys/conf.h>
 #endif
 
-#if HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
 #if HAVE_SHADOW_H
 #include <shadow.h>
 #endif
 #if HAVE_SHADOW_H
 #include <shadow.h>
 #endif
 #include <cmds.h>
 #include <nonroot.h>
 
 #include <cmds.h>
 #include <nonroot.h>
 
+#if WANT_DCACHE
+#include <dcache.h>
+#endif
+
 #define lstat stat
 
 extern struct conn *first_conn;
 #define lstat stat
 
 extern struct conn *first_conn;
@@ -985,9 +973,14 @@ int _mwrite(const char * const buf, const struct ftran * const f,
 
 /*
  * mwrite:     This is a short_hand define, making calls to _mwrite() very
 
 /*
  * 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));
 #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():
 
 /*
  * long_listing():
@@ -1058,9 +1051,9 @@ int long_listing(char * const retbuf, const char * const pathname, const int do_
                        return 0;
                }
 
                        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
 #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
 #endif
                        decode_mode(buf.st_mode),
 #if WANT_NONROOT
@@ -1078,7 +1071,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);
 #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 
 #if 0
                /*
                 * vim needs this extra character for some reason... It's too 
@@ -1109,7 +1103,7 @@ int cmd_list(struct conn * const c)
 {
        struct list_options lo;
 
 {
        struct list_options lo;
 
-/*     lo.recursive = 0; */
+       lo.recursive = 0;
        lo.long_listing = 1;
        lo.classify = 0;
 
        lo.long_listing = 1;
        lo.classify = 0;
 
@@ -1128,7 +1122,7 @@ int cmd_nlst(struct conn * const c)
 {
        struct list_options lo;
 
 {
        struct list_options lo;
 
-/*     lo.recursive = 0; */
+       lo.recursive = 0;
        lo.long_listing = 0;
        lo.classify = 0;
 
        lo.long_listing = 0;
        lo.classify = 0;
 
@@ -1177,30 +1171,17 @@ void do_listing(struct conn * const c, struct list_options * const lo)
 
 #if WANT_DCACHE
        {
 
 #if WANT_DCACHE
        {
-               struct dcache *d = NULL, *next = first_dcache->next_dcache;
-               struct stat buf;
+               struct dcache *d = find_dcache(cwd, ptr, lo);
+               if (d != NULL) {
+                       d->use_count++;
+                       f->dir_cache = d;
+                       f->file_data = d->dir_data;
+                       f->size = d->dir_size;
+                       f->dir_listing = 1;
+                       f->pos = 0;
 
 
-               if (stat(cwd, &buf) > -1) {
-                       /* run through the linked list */
-                       while (next != NULL) {
-                               d = next;
-                               next = d->next_dcache;
-       
-                               if (buf.st_mtime <= d->generated &&
-                                   strcmp(d->dir_name, cwd) == 0 &&
-                                   strcmp(d->pattern, ptr) == 0 &&
-                                   memcmp(&(d->lo), lo,
-                                          sizeof(struct list_options)) == 0) {
-                                       d->use_count++;
-                                       f->dir_cache = d;
-                                       f->file_data = d->dir_data;
-                                       f->size = d->dir_size;
-                                       f->dir_listing = 1;
-                                       f->pos = 0;
-                                       prepare_for_transfer(f);
-                                       return;
-                               }
-                       }
+                       prepare_for_transfer(f);
+                       return;
                }
        }
 #endif
                }
        }
 #endif
@@ -1213,30 +1194,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);
                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
        }
 #else
-       list_core(c, ptr, lo);
+       list_core(c, ptr, "", lo);
 #endif
 
 #if WANT_DCACHE
 #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
 #endif
 
 #if HAVE_MMAP
@@ -1273,8 +1238,8 @@ int get_num_files(struct conn * const c, const char * const pathname,
                return -1;
        }
 
                return -1;
        }
 
-#if 0  /* the rest of the code doesn't support recursion yet */
        if (lo->recursive) {
        if (lo->recursive) {
+               int i;
                        for (i = 0; i < pglob.gl_pathc; i++) {
                        char *temp = pglob.gl_pathv[i];
                        struct stat buf;
                        for (i = 0; i < pglob.gl_pathc; i++) {
                        char *temp = pglob.gl_pathv[i];
                        struct stat buf;
@@ -1287,7 +1252,8 @@ int get_num_files(struct conn * const c, const char * const pathname,
                        }
                }
        }
                        }
                }
        }
-#endif
+
+       globfree(&pglob);
 
        return num_files;
 }
 
        return num_files;
 }
@@ -1302,20 +1268,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...
  *
  *             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.
  */
  *             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
 #if HAVE_MMAP
-               , const int size
+               , const int size, int pos
 #endif
                )
 {
        int i;
        glob_t pglob;
 #endif
                )
 {
        int i;
        glob_t pglob;
-#if HAVE_MMAP
-       int pos = 0;
-#endif
        struct ftran * const f = c->transfer;
 
         /*
        struct ftran * const f = c->transfer;
 
         /*
@@ -1327,12 +1293,28 @@ void list_core(struct conn * const c, const char * const pathname,
 #ifdef GLOB_NOMATCH
        case GLOB_NOMATCH:
 #endif
 #ifdef GLOB_NOMATCH
        case GLOB_NOMATCH:
 #endif
-                break;
+                break;         /* note: break, not return */
         default:
                 numeric(c, 550, strerror(EACCES));
         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;
        if (lo->long_listing) {
                /* FIX: we may get too high total number if we are running nonroot! */
                struct stat buf;
@@ -1344,12 +1326,9 @@ void list_core(struct conn * const c, const char * const pathname,
                                total += buf.st_blocks;
                        }
                }
                                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);
                mwrite(temp, i);
-#else
-               write(f->local_file, temp, i);
-#endif
        }
 
        for (i = 0; i < pglob.gl_pathc; i++) {
        }
 
        for (i = 0; i < pglob.gl_pathc; i++) {
@@ -1380,15 +1359,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);
                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
 #endif
+                               chdir("..");
+                       }
+               }
        }
 
 #if HAVE_MMAP
        }
 
 #if HAVE_MMAP
@@ -1398,6 +1405,11 @@ void list_core(struct conn * const c, const char * const pathname,
 #endif
 
        globfree(&pglob);
 #endif
 
        globfree(&pglob);
+#if HAVE_MMAP
+       return pos;
+#else
+       return 0;
+#endif
 }
 
 /*
 }
 
 /*
@@ -1442,22 +1454,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)
 {
  */
 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;
 }
 
 /*
        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)
 {
  */
 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;
 }
 
        return 1;
 }
 
@@ -1803,11 +1823,9 @@ int prepare_for_listing(struct conn * const c, char ** const ptr,
        if (optr != NULL) {
                while (*++optr) {
                        switch (*optr & (255-32)) {     /* uppercase */
        if (optr != NULL) {
                while (*++optr) {
                        switch (*optr & (255-32)) {     /* uppercase */
-#if 0
                        case 'R':       /* actually case sensitive... */
                                lo->recursive = 1;
                                break;
                        case 'R':       /* actually case sensitive... */
                                lo->recursive = 1;
                                break;
-#endif
                        case 'L':
                                lo->long_listing = 1;
                                break;
                        case 'L':
                                lo->long_listing = 1;
                                break;
@@ -1838,7 +1856,16 @@ int prepare_for_listing(struct conn * const c, char ** const ptr,
        }
 
        /* if no argument, choose all files */
        }
 
        /* if no argument, choose all files */
-       if (fptr == NULL || fptr[0] == 0) fptr = "*";
+       if (fptr == NULL || fptr[0] == 0) {
+               fptr = "*";
+       } else {
+               /* we need to check if the last part is a directory (no -d switch) */
+               struct stat buf;
+               if (stat(fptr, &buf) == 0 && S_ISDIR(buf.st_mode)) {
+                       TRAP_ERROR(chdir(fptr) == -1, 550, return -1);
+                       fptr = "*";
+               }
+       }
        *ptr = fptr;
 
 #if WANT_NONROOT
        *ptr = fptr;
 
 #if WANT_NONROOT