X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=cmds.c;h=500d6c28e4d20e900fc5afafbcfd3ec34b90d29d;hb=e0caa4ef5e987cbea6b570cb5e011e8fd082355a;hp=a8453def6aacbc4f01c3076a0fae9611cb0382ea;hpb=33c9b9cc3e941981540fb3ff15f4355bd649190d;p=betaftpd diff --git a/cmds.c b/cmds.c index a8453de..500d6c2 100644 --- 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 - 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, @@ -21,10 +21,6 @@ #include #endif -#if HAVE_SYS_TYPES_H -#include -#endif - #if HAVE_STROPTS_H #include #endif @@ -77,10 +73,6 @@ #include #endif -#if HAVE_PWD_H -#include -#endif - #if HAVE_GRP_H #include #endif @@ -89,10 +81,6 @@ #include #endif -#if HAVE_SYS_SOCKET_H -#include -#endif - #if HAVE_SYS_STAT_H #include #endif @@ -109,10 +97,6 @@ #include #endif -#if HAVE_NETINET_IN_H -#include -#endif - #if HAVE_SHADOW_H #include #endif @@ -141,6 +125,10 @@ #include #include +#if WANT_DCACHE +#include +#endif + #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 - * 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 +1051,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 +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); - + i = strlen(temp); + #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; -/* lo.recursive = 0; */ + lo.recursive = 0; lo.long_listing = 1; lo.classify = 0; @@ -1128,7 +1122,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; @@ -1177,30 +1171,17 @@ void do_listing(struct conn * const c, struct list_options * const lo) #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 @@ -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); - 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 @@ -1273,8 +1238,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 +1252,8 @@ int get_num_files(struct conn * const c, const char * const pathname, } } } -#endif + + globfree(&pglob); 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... * + * 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 +1293,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 +1326,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 +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); -#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 +1405,11 @@ void list_core(struct conn * const c, const char * const pathname, #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) { - 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; } @@ -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 0 case 'R': /* actually case sensitive... */ lo->recursive = 1; break; -#endif 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 (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