📄 ftp.c
字号:
} response = get_ftp_response(conn, rb, 2, NULL); if (response == -1) { abort_conn_with_state(conn, S_FTP_ERROR); return; } if (!response) { read_from_socket(conn, &conn->socket, rb, ftp_retr_file); set_connection_state(conn, S_GETH); return; } if (response >= 100 && response < 200) { /* We only need to parse response after RETR to * get filesize if needed. */ if (!c_i->dir && conn->est_length == -1) { long int file_len = get_filesize_from_RETR(rb->data, rb->len); if (file_len > 0) { /* FIXME: ..when downloads resuming * implemented.. */ conn->est_length = file_len + conn->progress.start; } } } set_handlers(conn->data_socket.fd, (void (*)(void *)) got_something_from_data_connection, NULL, NULL, conn); /* read_from_socket(conn, &conn->socket, rb, ftp_got_final_response); */ ftp_got_final_response(conn, rb);}static voidftp_got_final_response(struct connection *conn, struct read_buffer *rb){ struct ftp_connection_info *c_i = conn->info; int response = get_ftp_response(conn, rb, 0, NULL); if (response == -1) { abort_conn_with_state(conn, S_FTP_ERROR); return; } if (!response) { read_from_socket(conn, &conn->socket, rb, ftp_got_final_response); if (conn->state != S_TRANS) set_connection_state(conn, S_GETH); return; } if (response >= 550 || response == 450) { /* Requested action not taken. * File unavailable (e.g., file not found, no access). */ if (!conn->cached) conn->cached = get_cache_entry(conn->uri); if (!conn->cached || !redirect_cache(conn->cached, "/", 1, 0)) { abort_conn_with_state(conn, S_OUT_OF_MEM); return; } abort_conn_with_state(conn, S_OK); return; } if (response >= 400) { abort_conn_with_state(conn, S_FTP_FILE_ERROR); return; } if (c_i->conn_state == 2) { ftp_end_request(conn, S_OK); } else { c_i->conn_state = 1; if (conn->state != S_TRANS) set_connection_state(conn, S_GETH); }}/* Display directory entry formatted in HTML. */static intdisplay_dir_entry(struct cache_entry *cached, int *pos, int *tries, int colorize_dir, unsigned char *dircolor, struct ftp_file_info *ftp_info){ struct string string; unsigned char permissions[10] = "---------"; if (!init_string(&string)) return -1; add_char_to_string(&string, ftp_info->type); if (ftp_info->permissions) { int p = ftp_info->permissions;#define FTP_PERM(perms, buffer, flag, index, id) \ if ((perms) & (flag)) (buffer)[(index)] = (id); FTP_PERM(p, permissions, S_IRUSR, 0, 'r'); FTP_PERM(p, permissions, S_IWUSR, 1, 'w'); FTP_PERM(p, permissions, S_IXUSR, 2, 'x'); FTP_PERM(p, permissions, S_ISUID, 2, (p & S_IXUSR ? 's' : 'S')); FTP_PERM(p, permissions, S_IRGRP, 3, 'r'); FTP_PERM(p, permissions, S_IWGRP, 4, 'w'); FTP_PERM(p, permissions, S_IXGRP, 5, 'x'); FTP_PERM(p, permissions, S_ISGID, 5, (p & S_IXGRP ? 's' : 'S')); FTP_PERM(p, permissions, S_IROTH, 6, 'r'); FTP_PERM(p, permissions, S_IWOTH, 7, 'w'); FTP_PERM(p, permissions, S_IXOTH, 8, 'x'); FTP_PERM(p, permissions, S_ISVTX, 8, (p & 0001 ? 't' : 'T'));#undef FTP_PERM } add_to_string(&string, permissions); add_char_to_string(&string, ' '); add_to_string(&string, " 1 ftp ftp "); if (ftp_info->size != FTP_SIZE_UNKNOWN) { add_format_to_string(&string, "%12lu ", ftp_info->size); } else { add_to_string(&string, " - "); }#ifdef HAVE_STRFTIME if (ftp_info->mtime > 0) { time_t current_time = time(NULL); time_t when = ftp_info->mtime; struct tm *when_tm; unsigned char *fmt; unsigned char date[13]; int wr; if (ftp_info->local_time_zone) when_tm = localtime(&when); else when_tm = gmtime(&when); if (current_time > when + 6L * 30L * 24L * 60L * 60L || current_time < when - 60L * 60L) fmt = "%b %e %Y"; else fmt = "%b %e %H:%M"; wr = strftime(date, sizeof(date), fmt, when_tm); while (wr < sizeof(date) - 1) date[wr++] = ' '; date[sizeof(date) - 1] = '\0'; add_to_string(&string, date); } else#endif add_to_string(&string, " "); add_char_to_string(&string, ' '); if (ftp_info->type == FTP_FILE_DIRECTORY && colorize_dir) { add_to_string(&string, "<font color=\""); add_to_string(&string, dircolor); add_to_string(&string, "\"><b>"); } add_to_string(&string, "<a href=\""); add_html_to_string(&string, ftp_info->name.source, ftp_info->name.length); if (ftp_info->type == FTP_FILE_DIRECTORY) add_char_to_string(&string, '/'); add_to_string(&string, "\">"); add_html_to_string(&string, ftp_info->name.source, ftp_info->name.length); add_to_string(&string, "</a>"); if (ftp_info->type == FTP_FILE_DIRECTORY && colorize_dir) { add_to_string(&string, "</b></font>"); } if (ftp_info->symlink.length) { add_to_string(&string, " -> "); add_html_to_string(&string, ftp_info->symlink.source, ftp_info->symlink.length); } add_char_to_string(&string, '\n'); if (add_fragment(cached, *pos, string.source, string.length)) *tries = 0; *pos += string.length; done_string(&string); return 0;}/* List a directory in html format. */static intftp_process_dirlist(struct cache_entry *cached, int *pos, unsigned char *buffer, int buflen, int last, int *tries, int colorize_dir, unsigned char *dircolor){ int ret = 0;#ifdef DEBUG_FTP_PARSER static int debug_ftp_parser = 1; int buflen_orig = buflen; unsigned char *response_orig = NULL; if (debug_ftp_parser) { buffer = get_ftp_debug_parse_responses(buffer, buflen); buflen = strlen(buffer); response_orig = buffer; debug_ftp_parser = 0; }#define end_ftp_dirlist_processing() do { mem_free_if(response_orig); } while (0)#define get_ftp_dirlist_offset(retval) int_min(retval, buflen_orig)#else#define end_ftp_dirlist_processing() /* Nothing to free */#define get_ftp_dirlist_offset(retval) (retval)#endif while (1) { struct ftp_file_info ftp_info = INIT_FTP_FILE_INFO; unsigned char *buf = buffer + ret; int bufl = buflen - ret; int bufp; int newline = 0; /* Newline quest. */ for (bufp = 0; bufp < bufl; bufp++) { if (buf[bufp] == ASCII_LF) { newline = 1; break; } } if (newline) { ret += bufp + 1; if (bufp && buf[bufp - 1] == ASCII_CR) bufp--; } else { if (!bufp || (!last && bufl < FTP_BUF_SIZE)) { end_ftp_dirlist_processing(); return get_ftp_dirlist_offset(ret); } ret += bufp; } /* Process line whose end we've already found. */ if (parse_ftp_file_info(&ftp_info, buf, bufp)) { int retv; if ((ftp_info.name.length == 1 && ftp_info.name.source[0] == '.') || (ftp_info.name.length == 2 && ftp_info.name.source[0] == '.' && ftp_info.name.source[1] == '.')) continue; retv = display_dir_entry(cached, pos, tries, colorize_dir, dircolor, &ftp_info); if (retv < 0) { end_ftp_dirlist_processing(); return get_ftp_dirlist_offset(ret); } }#ifdef DEBUG_FTP_PARSER else { ERROR("Error parsing: [%.*s]", bufp, buf); }#endif }}static intftp_data_accept(struct connection *conn){ struct ftp_connection_info *c_i = conn->info; int newsock; if (c_i->has_data) return 0; c_i->has_data = 1; clear_handlers(conn->data_socket.fd); if ((conn->protocol_family != 1 && c_i->use_pasv)#ifdef CONFIG_IPV6 || (conn->protocol_family == 1 && c_i->use_epsv)#endif ) { newsock = conn->data_socket.fd; } else { newsock = accept(conn->data_socket.fd, NULL, NULL); if (newsock < 0) { retry_conn_with_state(conn, -errno); return -1; } close(conn->data_socket.fd); } conn->data_socket.fd = newsock; set_handlers(newsock, (void (*)(void *)) got_something_from_data_connection, NULL, NULL, conn); return 0;}static voidgot_something_from_data_connection(struct connection *conn){ struct ftp_connection_info *c_i = conn->info; unsigned char dircolor[8]; int colorize_dir = 0; int len; /* XXX: This probably belongs rather to connect.c ? */ set_connection_timeout(conn); if (ftp_data_accept(conn)) return; if (!conn->cached) conn->cached = get_cache_entry(conn->uri); if (!conn->cached) {out_of_mem: abort_conn_with_state(conn, S_OUT_OF_MEM); return; } if (c_i->dir) { colorize_dir = get_opt_bool("document.browse.links.color_dirs"); if (colorize_dir) { color_to_string(get_opt_color("document.colors.dirs"), (unsigned char *) &dircolor); } } if (c_i->dir && !conn->from) { struct string string; unsigned char *uristring; if (!conn->uri->data) { abort_conn_with_state(conn, S_FTP_ERROR); return; } uristring = get_uri_string(conn->uri, URI_PUBLIC); if (!uristring) goto out_of_mem; if (!init_string(&string)) { mem_free(uristring); goto out_of_mem; } add_html_to_string(&string, uristring, strlen(uristring)); mem_free(uristring);#define ADD_CONST(str) { \ add_fragment(conn->cached, conn->from, str, sizeof(str) - 1); \ conn->from += (sizeof(str) - 1); }#define ADD_STRING() { \ add_fragment(conn->cached, conn->from, string.source, string.length); \ conn->from += string.length; } ADD_CONST("<html>\n<head><title>"); ADD_STRING(); ADD_CONST("</title></head>\n<body>\n<h2>FTP directory "); ADD_STRING(); ADD_CONST("</h2>\n<pre>"); done_string(&string); if (conn->uri->datalen) { struct ftp_file_info ftp_info = INIT_FTP_FILE_INFO_ROOT; display_dir_entry(conn->cached, &conn->from, &conn->tries, colorize_dir, dircolor, &ftp_info); } mem_free_set(&conn->cached->content_type, stracpy("text/html")); } len = safe_read(conn->data_socket.fd, c_i->ftp_buffer + c_i->buf_pos, FTP_BUF_SIZE - c_i->buf_pos); if (len < 0) { retry_conn_with_state(conn, -errno); return; } if (len > 0) { if (!c_i->dir) { conn->received += len; if (add_fragment(conn->cached, conn->from, c_i->ftp_buffer, len) == 1) conn->tries = 0; conn->from += len; } else { int proceeded; conn->received += len; proceeded = ftp_process_dirlist(conn->cached, &conn->from, c_i->ftp_buffer, len + c_i->buf_pos, 0, &conn->tries, colorize_dir, (unsigned char *) dircolor); if (proceeded == -1) goto out_of_mem; c_i->buf_pos += len - proceeded; memmove(c_i->ftp_buffer, c_i->ftp_buffer + proceeded, c_i->buf_pos); } set_connection_state(conn, S_TRANS); return; } if (ftp_process_dirlist(conn->cached, &conn->from, c_i->ftp_buffer, c_i->buf_pos, 1, &conn->tries, colorize_dir, (unsigned char *) dircolor) == -1) goto out_of_mem; if (c_i->dir) ADD_CONST("</pre>\n<hr>\n</body>\n</html>"); clear_handlers(conn->data_socket.fd); close_socket(NULL, &conn->data_socket); if (c_i->conn_state == 1) { ftp_end_request(conn, S_OK); } else { c_i->conn_state = 2; set_connection_state(conn, S_TRANS); }}static voidftp_end_request(struct connection *conn, enum connection_state state){ set_connection_state(conn, state); if (conn->state == S_OK && conn->cached) { truncate_entry(conn->cached, conn->from, 1); conn->cached->incomplete = 0; } add_keepalive_connection(conn, FTP_KEEPALIVE_TIMEOUT, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -