From dbb6799580c29ff7a1cc193f6d8ca3711579a81f Mon Sep 17 00:00:00 2001 From: sgunderson Date: Sun, 20 Aug 2000 17:26:49 +0000 Subject: [PATCH] Implemented directory listing recursion (not very much testing yet). Both mmap() and non-mmap() now use mwrite(). We no longer depend on the return value of snprintf(). --- cmds.c | 111 +++++++++++++++++++++++++++++++++++++++++---------------- cmds.h | 15 ++++++-- 2 files changed, 92 insertions(+), 34 deletions(-) diff --git a/cmds.c b/cmds.c index ef471ee..422f52f 100644 --- a/cmds.c +++ b/cmds.c @@ -985,9 +985,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(): @@ -1058,9 +1063,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 @@ -1078,7 +1083,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 @@ -1109,7 +1115,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; @@ -1128,7 +1134,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; @@ -1213,10 +1219,10 @@ 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 @@ -1273,8 +1279,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; @@ -1287,7 +1293,6 @@ int get_num_files(struct conn * const c, const char * const pathname, } } } -#endif return num_files; } @@ -1302,20 +1307,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; /* @@ -1327,12 +1332,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; @@ -1344,12 +1365,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++) { @@ -1380,15 +1398,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 @@ -1398,6 +1444,11 @@ void list_core(struct conn * const c, const char * const pathname, #endif globfree(&pglob); +#if HAVE_MMAP + return pos; +#else + return 0; +#endif } /* @@ -1811,11 +1862,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; diff --git a/cmds.h b/cmds.h index b7735ff..88b04d1 100644 --- a/cmds.h +++ b/cmds.h @@ -108,13 +108,22 @@ int prepare_for_listing(struct conn * const c, char ** const ptr, void do_listing(struct conn * const c, struct list_options * const lo); int get_num_files(struct conn * const c, const char * const pathname, struct list_options * const lo); -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 ); char classify(const mode_t mode); void do_store(struct conn * const c, int append); char *do_pwd(struct conn * const c, char * const retbuf, const char * const dir); +#ifndef HAVE_POLL +/* + * Even on select()-only systems, we use some poll() constants, so + * we'll have to make them up if we don't already have them. These + * are taken from my glibc 2.1 system. + */ +#define POLLIN 0x001 +#define POLLOUT 0x004 +#endif -- 2.39.2