📄 cmds.c
字号:
* Note that this function returns the new position in the * `file'. The caller is expected to send this information * back in `pos' at the next call to _mwrite(). */int _mwrite(const char * const buf, const struct ftran * const f, const int pos, const int count, const int size){ if (pos + count >= size) return size; /* out of space */ memcpy(f->file_data + pos, buf, count); return pos + count;}#endif/* * mwrite: This is a short_hand define, making calls to _mwrite() very * 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(): * Formats output in `ls -l' style. It returns one line for the * file PATHNAME, and returns it in retbuf. Setting do_classify * to nonzero has the same effect as `ls -F'. * * This command is so long, because simply there is so much to * be done. GNU ls has some extra functions, but it's close to * 3000 lines too... */int long_listing(char * const retbuf, const char * const pathname, const int do_classify){ int i, year; char newd[512], temp[1026]; struct stat buf; struct tm *t; time_t now; char username[17], groupname[17]; time(&now); year = localtime(&now)->tm_year; {#if !WANT_NONROOT struct passwd *p; struct group *g;#endif if (lstat(pathname, &buf) == -1) return 0;#if WANT_NONROOT strcpy(username, nr_get_uname(buf.st_uid)); strcpy(groupname, nr_get_gname(buf.st_gid));#else p = getpwuid(buf.st_uid); if (p != NULL) { strncpy(username, p->pw_name, 16); username[16] = 0; } else { snprintf(username, 16, "%u", buf.st_uid); } g = getgrgid(buf.st_gid); if (g != NULL) { strncpy(groupname, g->gr_name, 16); groupname[16] = 0; } else { snprintf(groupname, 16, "%u", buf.st_gid); }#endif } /* * This POSIX approximation is based on GNU ls code (and obfuscated * a bit...), to be compatible with `real' ls implementations. */ t = localtime(&(buf.st_mtime)); strftime(newd, 512, ((now > buf.st_mtime + 6L * 30L * 24L * 60L * 60L) || (now < buf.st_mtime - 60L * 60L)) ? "%b %e %Y" : "%b %e %H:%M", t); {#if WANT_NONROOT char rights[16]; if (nr_check_permission(0, pathname, 0, (S_ISDIR(buf.st_mode)), rights) == -1) { /* no permission to even see this file */ return 0; } snprintf(temp, 1024, "%c%s %3u %-8s %-8s %8lu %12s %s\r\n",#else 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 rights,#else (buf.st_mode & S_IRUSR) ? 'r' : '-', (buf.st_mode & S_IWUSR) ? 'w' : '-', (buf.st_mode & S_IXUSR) ? ((buf.st_mode & S_ISUID) ? 's' : 'x') : '-', (buf.st_mode & S_IRGRP) ? 'r' : '-', (buf.st_mode & S_IWGRP) ? 'w' : '-', (buf.st_mode & S_IXGRP) ? ((buf.st_mode & S_ISGID) ? 's' : 'x') : '-', (buf.st_mode & S_IROTH) ? 'r' : '-', (buf.st_mode & S_IWOTH) ? 'w' : '-', (buf.st_mode & S_IXOTH) ? ((buf.st_mode & S_ISVTX) ? 't' : 'x') : '-',#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 * bad I'll have to do it this way, but syntax colouring * that works properly is almost a `must' for me :-) */ )#endif /* add an extra classification `sign' if we got -F */ if (do_classify) { int len = strlen(temp); temp[len] = classify(buf.st_mode); temp[len + 1] = '\0'; } } strcpy(retbuf, temp); return 1;}/* * cmd_list(): Handles the LIST command (directory listing). Does a * long listing (of type `ls -l'). The listing work is * done by do_listing(), below. */int cmd_list(struct conn * const c){ struct list_options lo; lo.recursive = 0; lo.long_listing = 1; lo.classify = 0; do_listing(c, &lo); return 1;}/* * cmd_nlst(): Handles the NLST command (plain directory listing). * Does a plain listing (no dates etc.), unless overridden * by the `-l' or `-L' flag (case insensitivity because most * FTP clients don't have a clue about what they send out). * The listing work is done by do_listing(), below. */ int cmd_nlst(struct conn * const c){ struct list_options lo; lo.recursive = 0; lo.long_listing = 0; lo.classify = 0; do_listing(c, &lo); return 1;}/* * do_listing(): * Prepares any listing buffers, temp files, etc., before * pushing the work one step further :-) * * If the directory listing cache is enabled, the cache * is checked first, to see if we still have a valid entry. */void do_listing(struct conn * const c, struct list_options * const lo){ int i; char *ptr;#if HAVE_MMAP int size;#endif struct ftran * const f = c->transfer;#if WANT_DCACHE char cwd[256];#endif#if WANT_NONROOT#warning No nonroot checking for list_core() yet#endif i = prepare_for_listing(c, &ptr, lo); if (i == -1) { destroy_ftran(c->transfer); return; }#if WANT_DCACHE getcwd(cwd, 256);#endif#if HAVE_MMAP strcpy(f->filename, "(directory listing)");#endif#if WANT_DCACHE { 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; prepare_for_transfer(f); return; } }#endif#if HAVE_MMAP { int num_files = get_num_files(c, ptr, lo); if (num_files == -1) 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, 0); }#else list_core(c, ptr, "", lo);#endif#if WANT_DCACHE populate_dcache(f, cwd, ptr, lo);#endif#if HAVE_MMAP f->pos = 0;#endif prepare_for_transfer(f);}/* * get_num_files(): * Get the number of files in PATHNAME (optionally matching * a pattern). Note that c is needed for TRAP_ERROR. */int get_num_files(struct conn * const c, const char * const pathname, struct list_options * const lo){ int num_files; glob_t pglob; /* * glob() fails to set errno correctly, so we simply guess on * `permission denied'... The others are far less likely to happen. */ switch (glob(pathname, 0, NULL, &pglob)) {#ifdef GLOB_NOMATCH case GLOB_NOMATCH: return 0;#endif case 0: num_files = pglob.gl_pathc; break; default: numeric(c, 550, strerror(EACCES)); return -1; } if (lo->recursive) { int i; for (i = 0; i < pglob.gl_pathc; i++) { char *temp = pglob.gl_pathv[i]; struct stat buf; lstat(temp, &buf); if (S_ISDIR(buf.st_mode)) { chdir(temp); num_files += get_num_files(c, "*", lo); chdir(".."); } } } globfree(&pglob); return num_files;}/* * list_core(): Enumerate all the files in PATHNAME, and formats them * according to list_options (calling format functions if * required). * * Note that we don't do any realloc() yet, so if your * _average_ file name length is over a certain size (a little * 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. */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, int pos#endif ){ int i; glob_t pglob; struct ftran * const f = c->transfer; /* * glob() fails to set errno correctly, so we simply guess on * `permission denied'... The others are far less likely to happen. */ switch (glob(pathname, GLOB_MARK, NULL, &pglob)) { case 0:#ifdef GLOB_NOMATCH case GLOB_NOMATCH:#endif break; /* note: break, not return */ default: numeric(c, 550, strerror(EACCES));#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; long unsigned int total = 0; char temp[1024]; for (i = 0; i < pglob.gl_pathc; i++) { if (lstat(pglob.gl_pathv[i], &buf) != -1) { total += buf.st_blocks; } } snprintf(temp, 1024, "total %lu\r\n", total >> 1); i = strlen(temp); mwrite(temp, i); } for (i = 0; i < pglob.gl_pathc; i++) { char * const temp = pglob.gl_pathv[i]; char buf[2048]; /* strip `/' away from the pathname -- add it later if -F */ { int len = strlen(temp); if (temp[len - 1] == '/') { temp[len - 1] = '\0'; } } if (lo->long_listing) { if (long_listing(buf, temp, lo->classify) == 0) continue; } else { strcpy(buf, temp); if (lo->classify) { struct stat statbuf; if (lstat(buf, &statbuf) != -1) { const int len = strlen(buf); buf[len] = classify(statbuf.st_mode); buf[len + 1] = 0; } } } mwrite(buf, strlen(buf)); mwrite("\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 f->size = pos;#else lseek(f->local_file, 0, SEEK_SET);#endif globfree(&pglob);#if HAVE_MMAP return pos;#else return 0;#endif}/* * cmd_noop(): Handles the NOOP command. Does nothing, doesn't even * reset the timeout. */int cmd_noop(struct conn * const c){ numeric(c, 200, "NOOP command successful."); return 1;}/* * cmd_syst(): Handles the SYST command. Returns the system identification. */int cmd_syst(struct conn * const c){ numeric(c, 215, "UNIX Type: L%u", NBBY); return 1;}/* * cmd_type(): Handles the TYPE command. */int cmd_type(struct conn * const c){#if WANT_ASCII c->recv_buf[0] &= (255-32); /* convert to upper case */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -