📄 ftp-ls.c
字号:
tok = strtok(NULL, ":"); if (tok == NULL) continue; hour = atoi(tok); tok = strtok(NULL, "M"); if (tok == NULL) continue; min = atoi(tok); /* Adjust hour from AM/PM. Just for the record, the sequence goes 11:00AM, 12:00PM, 01:00PM ... 11:00PM, 12:00AM, 01:00AM . */ tok+=2; if (hour == 12) hour = 0; if (*tok == 'P') hour += 12; DEBUGP(("YYYY/MM/DD HH:MM - %d/%02d/%02d %02d:%02d\n", year+1900, month, day, hour, min)); /* Build the time-stamp (copy & paste from above) */ timestruct.tm_sec = 0; timestruct.tm_min = min; timestruct.tm_hour = hour; timestruct.tm_mday = day; timestruct.tm_mon = month; timestruct.tm_year = year; timestruct.tm_wday = 0; timestruct.tm_yday = 0; timestruct.tm_isdst = -1; cur.tstamp = mktime (×truct); /* store the time-stamp */ DEBUGP(("Timestamp: %ld\n", cur.tstamp)); /* Third column: Either file length, or <DIR>. We also set the permissions (guessed as 0644 for plain files and 0755 for directories as the listing does not give us a clue) and filetype here. */ tok = strtok(NULL, " "); if (tok == NULL) continue; while ((tok != NULL) && (*tok == '\0')) tok = strtok(NULL, " "); if (tok == NULL) continue; if (*tok == '<') { cur.type = FT_DIRECTORY; cur.size = 0; cur.perms = 0755; DEBUGP(("Directory\n")); } else { wgint size; cur.type = FT_PLAINFILE; errno = 0; size = str_to_wgint (tok, NULL, 10); if (size == WGINT_MAX && errno == ERANGE) cur.size = 0; /* overflow */ else cur.size = size; cur.perms = 0644; DEBUGP(("File, size %s bytes\n", number_to_static_string (cur.size))); } cur.linkto = NULL; /* And put everything into the linked list */ if (!dir) { l = dir = xnew (struct fileinfo); memcpy (l, &cur, sizeof (cur)); l->prev = l->next = NULL; } else { cur.prev = l; l->next = xnew (struct fileinfo); l = l->next; memcpy (l, &cur, sizeof (cur)); l->next = NULL; } xfree (line); } fclose(fp); return dir;}/* Converts VMS symbolic permissions to number-style ones, e.g. string RWED,RWE,RE to 755. "D" (delete) is taken to be equal to "W" (write). Inspired by a patch of Stoyan Lekov <lekov@eda.bg>. */static intvmsperms (const char *s){ int perms = 0; do { switch (*s) { case ',': perms <<= 3; break; case 'R': perms |= 4; break; case 'W': perms |= 2; break; case 'D': perms |= 2; break; case 'E': perms |= 1; break; default: DEBUGP(("wrong VMS permissons!\n")); } } while (*++s); return perms;}static struct fileinfo *ftp_parse_vms_ls (const char *file){ FILE *fp; /* #### A third copy of more-or-less the same array ? */ static const char *months[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; int i; int year, month, day; /* for time analysis */ int hour, min, sec; struct tm timestruct; char *line, *tok; /* tokenizer */ struct fileinfo *dir, *l, cur; /* list creation */ fp = fopen (file, "rb"); if (!fp) { logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); return NULL; } dir = l = NULL; /* Skip empty line. */ line = read_whole_line (fp); xfree_null (line); /* Skip "Directory PUB$DEVICE[PUB]" */ line = read_whole_line (fp); xfree_null (line); /* Skip empty line. */ line = read_whole_line (fp); xfree_null (line); /* Line loop to end of file: */ while ((line = read_whole_line (fp)) != NULL) { char *p; i = clean_line (line); if (!i) { xfree (line); break; } /* First column: Name. A bit of black magic again. The name my be either ABCD.EXT or ABCD.EXT;NUM and it might be on a separate line. Therefore we will first try to get the complete name until the first space character; if it fails, we assume that the name occupies the whole line. After that we search for the version separator ";", we remove it and check the extension of the file; extension .DIR denotes directory. */ tok = strtok(line, " "); if (tok == NULL) tok = line; DEBUGP(("file name: '%s'\n", tok)); for (p = tok ; *p && *p != ';' ; p++) ; if (*p == ';') *p = '\0'; p = tok + strlen(tok) - 4; if (!strcmp(p, ".DIR")) *p = '\0'; cur.name = xstrdup(tok); DEBUGP(("Name: '%s'\n", cur.name)); /* If the name ends on .DIR or .DIR;#, it's a directory. We also set the file size to zero as the listing does tell us only the size in filesystem blocks - for an integrity check (when mirroring, for example) we would need the size in bytes. */ if (! *p) { cur.type = FT_DIRECTORY; cur.size = 0; DEBUGP(("Directory\n")); } else { cur.type = FT_PLAINFILE; DEBUGP(("File\n")); } cur.size = 0; /* Second column, if exists, or the first column of the next line contain file size in blocks. We will skip it. */ tok = strtok(NULL, " "); if (tok == NULL) { DEBUGP(("Getting additional line\n")); xfree (line); line = read_whole_line (fp); if (!line) { DEBUGP(("empty line read, leaving listing parser\n")); break; } i = clean_line (line); if (!i) { DEBUGP(("confusing VMS listing item, leaving listing parser\n")); xfree (line); break; } tok = strtok(line, " "); } DEBUGP(("second token: '%s'\n", tok)); /* Third/Second column: Date DD-MMM-YYYY. */ tok = strtok(NULL, "-"); if (tok == NULL) continue; DEBUGP(("day: '%s'\n",tok)); day = atoi(tok); tok = strtok(NULL, "-"); if (!tok) { /* If the server produces garbage like 'EA95_0PS.GZ;1 No privilege for attempted operation' the first strtok(NULL, "-") will return everything until the end of the line and only the next strtok() call will return NULL. */ DEBUGP(("nonsense in VMS listing, skipping this line\n")); xfree (line); break; } for (i=0; i<12; i++) if (!strcmp(tok,months[i])) break; /* Uknown months are mapped to January */ month = i % 12 ; tok = strtok (NULL, " "); if (tok == NULL) continue; year = atoi (tok) - 1900; DEBUGP(("date parsed\n")); /* Fourth/Third column: Time hh:mm[:ss] */ tok = strtok (NULL, " "); if (tok == NULL) continue; min = sec = 0; p = tok; hour = atoi (p); for (; *p && *p != ':'; ++p) ; if (*p) min = atoi (++p); for (; *p && *p != ':'; ++p) ; if (*p) sec = atoi (++p); DEBUGP(("YYYY/MM/DD HH:MM:SS - %d/%02d/%02d %02d:%02d:%02d\n", year+1900, month, day, hour, min, sec)); /* Build the time-stamp (copy & paste from above) */ timestruct.tm_sec = sec; timestruct.tm_min = min; timestruct.tm_hour = hour; timestruct.tm_mday = day; timestruct.tm_mon = month; timestruct.tm_year = year; timestruct.tm_wday = 0; timestruct.tm_yday = 0; timestruct.tm_isdst = -1; cur.tstamp = mktime (×truct); /* store the time-stamp */ DEBUGP(("Timestamp: %ld\n", cur.tstamp)); /* Skip the fifth column */ tok = strtok(NULL, " "); if (tok == NULL) continue; /* Sixth column: Permissions */ tok = strtok(NULL, ","); /* Skip the VMS-specific SYSTEM permissons */ if (tok == NULL) continue; tok = strtok(NULL, ")"); if (tok == NULL) { DEBUGP(("confusing VMS permissions, skipping line\n")); xfree (line); continue; } /* Permissons have the format "RWED,RWED,RE" */ cur.perms = vmsperms(tok); DEBUGP(("permissions: %s -> 0%o\n", tok, cur.perms)); cur.linkto = NULL; /* And put everything into the linked list */ if (!dir) { l = dir = xnew (struct fileinfo); memcpy (l, &cur, sizeof (cur)); l->prev = l->next = NULL; } else { cur.prev = l; l->next = xnew (struct fileinfo); l = l->next; memcpy (l, &cur, sizeof (cur)); l->next = NULL; } xfree (line); } fclose (fp); return dir;}/* This function switches between the correct parsing routine depending on the SYSTEM_TYPE. The system type should be based on the result of the "SYST" response of the FTP server. According to this repsonse we will use on of the three different listing parsers that cover the most of FTP servers used nowadays. */struct fileinfo *ftp_parse_ls (const char *file, const enum stype system_type){ switch (system_type) { case ST_UNIX: return ftp_parse_unix_ls (file, 0); case ST_WINNT: { /* Detect whether the listing is simulating the UNIX format */ FILE *fp; int c; fp = fopen (file, "rb"); if (!fp) { logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); return NULL; } c = fgetc(fp); fclose(fp); /* If the first character of the file is '0'-'9', it's WINNT format. */ if (c >= '0' && c <='9') return ftp_parse_winnt_ls (file); else return ftp_parse_unix_ls (file, 1); } case ST_VMS: return ftp_parse_vms_ls (file); case ST_MACOS: return ftp_parse_unix_ls (file, 1); default: logprintf (LOG_NOTQUIET, _("\Unsupported listing type, trying Unix listing parser.\n")); return ftp_parse_unix_ls (file, 0); }}/* Stuff for creating FTP index. *//* The function creates an HTML index containing references to given directories and files on the appropriate host. The references are FTP. */uerr_tftp_index (const char *file, struct url *u, struct fileinfo *f){ FILE *fp; char *upwd; char *htclfile; /* HTML-clean file name */ if (!output_stream) { fp = fopen (file, "wb"); if (!fp) { logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); return FOPENERR; } } else fp = output_stream; if (u->user) { char *tmpu, *tmpp; /* temporary, clean user and passwd */ tmpu = url_escape (u->user); tmpp = u->passwd ? url_escape (u->passwd) : NULL; if (tmpp) upwd = concat_strings (tmpu, ":", tmpp, "@", (char *) 0); else upwd = concat_strings (tmpu, "@", (char *) 0); xfree (tmpu); xfree_null (tmpp); } else upwd = xstrdup (""); fprintf (fp, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"); fprintf (fp, "<html>\n<head>\n<title>"); fprintf (fp, _("Index of /%s on %s:%d"), u->dir, u->host, u->port); fprintf (fp, "</title>\n</head>\n<body>\n<h1>"); fprintf (fp, _("Index of /%s on %s:%d"), u->dir, u->host, u->port); fprintf (fp, "</h1>\n<hr>\n<pre>\n"); while (f) { fprintf (fp, " "); if (f->tstamp != -1) { /* #### Should we translate the months? Or, even better, use ISO 8601 dates? */ static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; struct tm *ptm = localtime ((time_t *)&f->tstamp); fprintf (fp, "%d %s %02d ", ptm->tm_year + 1900, months[ptm->tm_mon], ptm->tm_mday); if (ptm->tm_hour) fprintf (fp, "%02d:%02d ", ptm->tm_hour, ptm->tm_min); else fprintf (fp, " "); } else fprintf (fp, _("time unknown ")); switch (f->type) { case FT_PLAINFILE: fprintf (fp, _("File ")); break; case FT_DIRECTORY: fprintf (fp, _("Directory ")); break; case FT_SYMLINK: fprintf (fp, _("Link ")); break; default: fprintf (fp, _("Not sure ")); break; } htclfile = html_quote_string (f->name); fprintf (fp, "<a href=\"ftp://%s%s:%d", upwd, u->host, u->port); if (*u->dir != '/') putc ('/', fp); fprintf (fp, "%s", u->dir); if (*u->dir) putc ('/', fp); fprintf (fp, "%s", htclfile); if (f->type == FT_DIRECTORY) putc ('/', fp); fprintf (fp, "\">%s", htclfile); if (f->type == FT_DIRECTORY) putc ('/', fp); fprintf (fp, "</a> "); if (f->type == FT_PLAINFILE) fprintf (fp, _(" (%s bytes)"), number_to_static_string (f->size)); else if (f->type == FT_SYMLINK) fprintf (fp, "-> %s", f->linkto ? f->linkto : "(nil)"); putc ('\n', fp); xfree (htclfile); f = f->next; } fprintf (fp, "</pre>\n</body>\n</html>\n"); xfree (upwd); if (!output_stream) fclose (fp); else fflush (fp); return FTPOK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -