📄 file.c
字号:
const gchar *ct; gchar buf[256]; ssize_t buf_size; if (!(ct = File_ext(filename))) { /* everything failed, let's analyze the data... */ if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) != -1) { if ((buf_size = read(fd, buf, 256)) == 256 ) { ct = File_get_content_type_from_data(buf, (size_t)buf_size); } else if (stat(filename, &sb) != -1 && buf_size > 0 && buf_size == sb.st_size) { ct = File_get_content_type_from_data(buf, (size_t)buf_size); } File_close(fd); } } return ct;}/* * Try to stat the file and determine if it's readable. */static void File_get(ClientInfo *Client, const char *filename, const char *orig_url){ int res; struct stat sb; char *msg = NULL, *d_cmd; if (stat(filename, &sb) != 0) { /* stat failed, prepare a file-not-found error. */ res = FILE_NOT_FOUND; } else if (S_ISDIR(sb.st_mode)) { /* set up for reading directory */ res = File_get_dir(Client, filename, orig_url); } else { /* set up for reading a file */ res = File_get_file(Client, filename, &sb, orig_url); } if (res == FILE_NOT_FOUND) { msg = g_strdup_printf("%s Not Found: %s", S_ISDIR(sb.st_mode) ? "Directory" : "File", filename); } else if (res == FILE_NO_ACCESS) { msg = g_strdup_printf("Access denied to %s: %s", S_ISDIR(sb.st_mode) ? "Directory" : "File", filename); } if (msg) { d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "send_status_message", msg); sock_handler_write_str(Client->sh, d_cmd, 1); g_free(d_cmd); g_free(msg); }}/* * */static gint File_get_dir(ClientInfo *Client, const gchar *DirName, const char *orig_url){ GString *g_dirname; DilloDir *Ddir; /* Let's make sure this directory url has a trailing slash */ g_dirname = g_string_new(DirName); if ( g_dirname->str[g_dirname->len - 1] != '/' ) g_string_append(g_dirname, "/"); /* Let's get a structure ready for transfer */ Ddir = File_dillodir_new(g_dirname->str); g_string_free(g_dirname, TRUE); if ( Ddir ) { File_transfer_dir(Client, Ddir, orig_url); File_dillodir_free(Ddir); return FILE_OK; } else return FILE_NO_ACCESS;}/* * Send the MIME content/type and then send the file itself. */static gint File_get_file(ClientInfo *Client, const gchar *filename, struct stat *sb, const char *orig_url){#define LBUF 16*1024 const gchar *ct; char buf[LBUF], *d_cmd; gint fd, st; if ( (fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) return FILE_NO_ACCESS; /* Content-Type info is based on filename extension. If there's no * known extension, then we do data sniffing. If this doesn't lead * to a conclusion, "application/octet-stream" is sent. */ if (!(ct = File_content_type(filename))) ct = "application/octet-stream"; /* Send DPI command */ d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", orig_url); sock_handler_write_str(Client->sh, d_cmd, 1); g_free(d_cmd); /* Send HTTP stream */ sock_handler_printf(Client->sh, 0, "Content-Type: %s\n" "Content-length: %ld\n\n", ct, sb->st_size); /* Send raw file contents */ do { if ((st = read(fd, buf, LBUF)) > 0) { if (sock_handler_write(Client->sh, buf, (size_t)st, 0) != 0) break; } else if (st < 0) { perror("[read]"); if (errno == EINTR || errno == EAGAIN) continue; } } while (st > 0); /* todo: It may be better to send an error report to dillo instead of * calling abort from g_error() */ if (st == -1) g_error("ERROR while reading from file \"%s\", error was \"%s\"\n", filename, strerror(errno)); File_close(fd); return FILE_OK;}/* * Given an hex octet (e3, 2F, 20), return the corresponding * character if the octet is valid, and -1 otherwise */static int File_parse_hex_octet(const gchar *s){ gint hex_value; gchar *tail, hex[3]; if ( (hex[0] = s[0]) && (hex[1] = s[1]) ) { hex[2] = 0; hex_value = strtol(hex, &tail, 16); if (tail - hex == 2) return hex_value; } return -1;}static void File_parse_hex_octets(char **str){ gchar *dest, *tmp, *orig = *str; int i, val; if (strchr(orig, '%')) { dest = tmp = g_new(gchar, strlen(orig) + 1); for (i = 0; orig[i]; i++) { if (orig[i] == '%' && (val = File_parse_hex_octet(orig + i + 1)) >= 0) { *dest++ = val; i += 2; } else { *dest++ = orig[i]; } } *dest = '\0'; g_free(orig); *str = tmp; }}/* * Make a file URL into a human (and machine) readable path. * The idea is to always have a path that starts with only one slash. * Embedded slashes are ignored. */static char *File_normalize_path(const char *orig){ char *str = (char *) orig, *basename = NULL, *ret, *p; /* Make sure the string starts with file: (it should, but...) */ if (strncmp(str, "file:", 5) != 0) return NULL; str += 5; /* Skip slashes */ while (str[0] == '/' && str[1] != '\0' && str[1] == '/') str++; if (*str == '\0') { /* Give CWD if the string is only "file:" */ basename = g_get_current_dir(); } else if (*str == '~') { if (str[1] == '\0' || str[1] == '/') { /* Expand 'tilde' to user's home */ basename = g_strdup(g_get_home_dir()); str++; } } else if (*str == '.') { if (str[1] == '\0' || str[1] == '/') { /* User wants the CWD */ basename = g_get_current_dir(); str++; } else if (str[1] == '.') { /* One level down from the CWD */ char *tmp1 = g_get_current_dir(); char *tmp2 = strrchr(tmp1, '/'); if (tmp2) { basename = g_strndup(tmp1, (guint)(tmp2 - tmp1)); } str += 2; g_free(tmp1); } } else if (*str != '/') { return NULL; } ret = g_strdup_printf("%s%s%s", basename ? basename : "", basename ? "/" : "", str); g_free(basename); /* remove the fragment if present */ if ((p = strrchr(ret, '#')) != NULL) *p = 0; /* Parse possible hexadecimal octets in the URI path */ File_parse_hex_octets(&ret); return ret;}/* * Set the style flag and ask for a reload, so it shows inmediatly. */static void File_toggle_html_style(ClientInfo *Client){ char *d_cmd; OLD_STYLE = !OLD_STYLE; d_cmd = a_Dpip_build_cmd("cmd=%s", "reload_request"); sock_handler_write_str(Client->sh, d_cmd, 1); g_free(d_cmd);}/* * Perform any necessary cleanups upon abnormal termination */static void termination_handler(int signum){ exit(signum);}/* Client handling ----------------------------------------------------------*//* * Add a new client to the list. */static ClientInfo *File_add_client(gint sock_fd){ ClientInfo *NewClient; NewClient = g_new(ClientInfo, 1); NewClient->sh = sock_handler_new(sock_fd, sock_fd, 8*1024); NewClient->status = 0; NewClient->done = 0; NewClient->old_style = OLD_STYLE; pthread_mutex_lock(&ClMut); Clients = g_list_append(Clients, NewClient); pthread_mutex_unlock(&ClMut); return NewClient;}/* * Get client record by number */static void *File_get_client_n(guint n){ void *client; pthread_mutex_lock(&ClMut); client = g_list_nth_data(Clients, n); pthread_mutex_unlock(&ClMut); return client;}/* * Remove a client from the list. */static void File_remove_client_n(guint n){ ClientInfo *Client; pthread_mutex_lock(&ClMut); Client = g_list_nth_data(Clients, n); Clients = g_list_remove(Clients, (void *)Client); pthread_mutex_unlock(&ClMut); _MSG("Closing Socket Handler\n"); sock_handler_close(Client->sh); sock_handler_free(Client->sh); g_free(Client);}/* * Return the number of clients. */static gint File_num_clients(void){ guint n; pthread_mutex_lock(&ClMut); n = g_list_length(Clients); pthread_mutex_unlock(&ClMut); return n;}/* * Serve this client. * (this function runs on its own thread) */static void *File_serve_client(void *data){ char *dpip_tag, *cmd = NULL, *url = NULL, *path; ClientInfo *Client = data; /* Read the dpi command */ dpip_tag = sock_handler_read(Client->sh); MSG("dpip_tag={%s}\n", dpip_tag); if (dpip_tag) { cmd = a_Dpip_get_attr(dpip_tag, strlen(dpip_tag), "cmd"); if (cmd) { if (strcmp(cmd, "DpiBye") == 0) { DPIBYE = 1; } else { url = a_Dpip_get_attr(dpip_tag, strlen(dpip_tag), "url"); if (!url) MSG("file.dpi:: Failed to parse 'url'\n"); } } } g_free(cmd); g_free(dpip_tag); if (!DPIBYE && url) { _MSG("url = '%s'\n", url); path = File_normalize_path(url); if (path) { _MSG("path = '%s'\n", path); File_get(Client, path, url); } else if (strcmp(url, "dpi:/file/toggle") == 0) { File_toggle_html_style(Client); } else { MSG("ERROR: URL path was %s\n", url); } g_free(path); } g_free(url); /* flag the the transfer finished */ Client->done = 1; return NULL;}/* * Serve the client queue. * (this function runs on its own thread) */static void *File_serve_clients(void *client){ /* switch to detached state */ pthread_detach(pthread_self()); while (File_num_clients()) { client = File_get_client_n((guint)0); File_serve_client(client); File_remove_client_n((guint)0); } ThreadRunning = 0; return NULL;}/* --------------------------------------------------------------------------*//* * Check a fd for activity, with a max timeout. * return value: 0 if timeout, 1 if input available, -1 if error. */int File_check_fd(int filedes, unsigned int seconds){ int st; fd_set set; struct timeval timeout; /* Initialize the file descriptor set. */ FD_ZERO (&set); FD_SET (filedes, &set); /* Initialize the timeout data structure. */ timeout.tv_sec = seconds; timeout.tv_usec = 0; do { st = select(FD_SETSIZE, &set, NULL, NULL, &timeout); } while (st == -1 && errno == EINTR); return st;}int main(void){ ClientInfo *NewClient; struct sockaddr_un spun; gint temp_sock_descriptor; gint address_size, c_st, st = 1; guint i; /* Arrange the cleanup function for abnormal terminations */ if (signal (SIGINT, termination_handler) == SIG_IGN) signal (SIGINT, SIG_IGN); if (signal (SIGHUP, termination_handler) == SIG_IGN) signal (SIGHUP, SIG_IGN); if (signal (SIGTERM, termination_handler) == SIG_IGN) signal (SIGTERM, SIG_IGN); MSG("(v.1) accepting connections...\n"); /* initialize mutex */ pthread_mutex_init(&ClMut, NULL); /* some OSes may need this... */ address_size = sizeof(struct sockaddr_un); /* start the service loop */ while (!DPIBYE) { /* wait for a connection */ do { c_st = File_check_fd(STDIN_FILENO, 1); } while (c_st == 0 && !DPIBYE); if (c_st < 0) { perror("[select]"); break; } if (DPIBYE) break; temp_sock_descriptor = accept(STDIN_FILENO, (struct sockaddr *)&spun, &address_size); if (temp_sock_descriptor == -1) { perror("[accept]"); break; } /* Create and initialize a new client */ NewClient = File_add_client(temp_sock_descriptor); if (!ThreadRunning) { ThreadRunning = 1; /* Serve the client from a thread (avoids deadlocks) */ if (pthread_create(&NewClient->thrID, NULL, File_serve_clients, NewClient) != 0) { perror("[pthread_create]"); ThreadRunning = 0; break; } } } /* todo: handle a running thread better. */ for (i = 0; i < 5 && ThreadRunning; ++i) { MSG("sleep i=%u", i); sleep(i); } if (DPIBYE) st = 0; return st;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -