📄 file.c
字号:
/* * File: file.c :) * * Copyright (C) 2000 - 2004 Jorge Arellano Cid <jcid@dillo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * Directory scanning is no longer streamed, but it gets sorted instead! * Directory entries on top, files next. * Not forked anymore; pthread handled. * With new HTML layout. */#include <pthread.h>#include <ctype.h> /* for tolower */#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <dirent.h>#include <fcntl.h>#include <string.h>#include <time.h>#include <stdio.h>#include <signal.h>#include <math.h> /* for rint */#include <errno.h> /* for errno */#include "Url.h"#include "IO.h"#include "../list.h"#include "../misc.h"#include "../web.h"#include "../interface.h"#define DEBUG_LEVEL 5#include "../debug.h"typedef struct _DilloDir { gint FD_Write, FD_Read; char *dirname; DIR *dir; gboolean scanned; /* Flag: Have we scanned it? */ gint parent_dir; /* Flag: Have we shown parent directory? */ char **dlist; /* List of subdirectories (for sorting) */ gint dlist_size; gint dlist_max; gint dlist_idx; char **flist; /* List of files (for sorting) */ gint flist_size; gint flist_max; gint flist_idx; pthread_t th1; /* This transfer's thread id. */} DilloDir;typedef struct { gint FD_Write, /* Where we write */ FD_Read; /* Where our clients read */ gint FD; /* Our local-file descriptor */ char *FileName; glong FileSize; pthread_t th1; /* This transfer's thread id. */} DilloFile;/* * Local data *//* * Forward references */static const char *File_content_type(const char *filename);static gint File_get_file(const gchar *FileName);static gint File_get_dir(const gchar *DirName);static GString *File_dir2html(DilloDir *Ddir);static void File_not_found_msg(DilloWeb *web, const char *filename, int fd);static gchar *File_html_escape(const gchar *str);/* * Close a file descriptor, but handling EINTR */static void File_close(int fd){ gint st; while ((st = close(fd)) < 0 && errno == EINTR);}/* * Escape unsafe characters as html entities. * Return value: NULL if there's no need to escape, New string otherwise. */static gchar *File_html_escape(const gchar *str){ static const char *unsafe_chars = "&<>\"'"; static const char *unsafe_rep[] = { "&", "<", ">", """, "'" }; gchar *p; GString *gstr; gint i; if ((p = strpbrk(str, unsafe_chars))) { gstr = g_string_sized_new(64); for (i = 0; str[i]; ++i) { if ((p = strchr(unsafe_chars, str[i]))) g_string_append(gstr, unsafe_rep[p - unsafe_chars]); else g_string_append_c(gstr, str[i]); } p = gstr->str; g_string_free(gstr, FALSE); } return p;}/* * Allocate a DilloFile structure, and set working values in it. */static DilloFile *File_dillofile_new(const char *filename){ gint fds[2], fd; struct stat sb; DilloFile *Dfile; if ( (fd = open(filename, O_RDONLY)) < 0 || pipe(fds) ) return NULL; Dfile = g_new(DilloFile, 1); Dfile->FD_Read = fds[0]; Dfile->FD_Write = fds[1]; Dfile->FD = fd; Dfile->FileName = g_strdup(filename); Dfile->FileSize = fstat(fd, &sb) ? -1 : (glong) sb.st_size; return Dfile;}/* * Deallocate a DilloFile structure. */static void File_dillofile_free(DilloFile *Dfile){ g_free(Dfile->FileName); g_free(Dfile);}/* * Allocate a DilloDir structure, and set safe values in it. */static DilloDir *File_dillodir_new(char *dirname){ DIR *dir; gint fds[2]; DilloDir *Ddir; if ( !(dir = opendir(dirname)) || pipe(fds) ) return NULL; Ddir = g_new(DilloDir, 1); Ddir->dir = dir; Ddir->scanned = FALSE; Ddir->parent_dir = FALSE; Ddir->dirname = g_strdup(dirname); Ddir->FD_Read = fds[0]; Ddir->FD_Write = fds[1]; Ddir->dlist = NULL; Ddir->dlist_size = 0; Ddir->dlist_max = 256; Ddir->dlist_idx = 0; Ddir->flist = NULL; Ddir->flist_size = 0; Ddir->flist_max = 256; Ddir->flist_idx = 0; return Ddir;}/* * Deallocate a DilloDir structure. */static void File_dillodir_free(DilloDir *Ddir){ g_free(Ddir->dirname); g_free(Ddir);}/* * Read a local file, and send it through a pipe. * (This function runs on its own thread) */static void *File_transfer_file(void *data){#define LBUF 16*1024 char buf[LBUF]; DilloFile *Dfile = data; ssize_t nbytes; const gchar *ct; /* Set this thread to detached state */ pthread_detach(Dfile->th1); /* Content type info: as we may misdetect a lot of files, * every unknown type is rendered as "text/plain". * todo: a better approach could be to detect&reject those types we know * for sure we don't handle (as gzip, bzip, ELF, etc) */ ct = File_content_type(Dfile->FileName); if (!strcmp(ct, "application/octet-stream")) ct = "text/plain"; /* Send content type info */ g_snprintf(buf, LBUF, "Content-Type: %s\n", ct); write(Dfile->FD_Write, buf, strlen(buf)); /* Send File Size info */ if (Dfile->FileSize != -1) { g_snprintf(buf, LBUF, "Content-length: %ld\n", Dfile->FileSize); write(Dfile->FD_Write, buf, strlen(buf)); } /* Send end-of-header */ strcpy(buf, "\n"); write(Dfile->FD_Write, buf, strlen(buf)); /* Append raw file contents */ while ( (nbytes = read(Dfile->FD, buf, LBUF)) != 0 ) { write(Dfile->FD_Write, buf, nbytes); } File_close(Dfile->FD); File_close(Dfile->FD_Write); File_dillofile_free(Dfile); return NULL;}/* * Read a local directory, translate it to html, and send it through a pipe. * (This function runs on its own thread) */static void *File_transfer_dir(void *data){ char *s1, *s2, *s3, *Hdirname, *Cdirname, *HCdirname; GString *gstr, *gs; DilloDir *Ddir = data; FILE *F_Write; /* Set this thread to detached state */ pthread_detach(Ddir->th1); /* With a stream, the buffering speeds up the transfer */ F_Write = fdopen(Ddir->FD_Write, "w"); gstr = g_string_sized_new(128); /* Send MIME content/type info */ g_string_sprintf(gstr, "Content-Type: %s\n\n", File_content_type("dir.html")); fwrite(gstr->str, gstr->len, 1, F_Write); /* Send page title */ Cdirname = (s1 = a_Misc_escape_chars(Ddir->dirname, "%#:' ")) ? s1 : Ddir->dirname; HCdirname = (s2 = File_html_escape(Cdirname)) ? s2 : Cdirname; Hdirname = (s3 = File_html_escape(Ddir->dirname)) ? s3 : Ddir->dirname; g_string_sprintf(gstr, "<HTML>\n<HEAD>\n <BASE href='%s%s'>\n" " <TITLE>%s%s</TITLE>\n</HEAD>\n", "file:", HCdirname, "file:", Hdirname); fwrite(gstr->str, gstr->len, 1, F_Write); g_string_sprintf(gstr, "<BODY><H1>%s %s</H1>\n<pre>\n", "Directory listing of", Hdirname); fwrite(gstr->str, gstr->len, 1, F_Write); g_free(s3); g_free(s2); g_free(s1); /* Append formatted directory contents */ while ( (gs = File_dir2html(Ddir)) ){ fwrite(gs->str, gs->len, 1, F_Write); g_string_free(gs, TRUE); } /* Close open HTML tags */ g_string_sprintf(gstr, "\n</pre></BODY></HTML>\n"); fwrite(gstr->str, gstr->len, 1, F_Write); fclose(F_Write); File_close(Ddir->FD_Write); closedir(Ddir->dir); Ddir->dir = NULL; File_dillodir_free(Ddir); g_string_free(gstr, TRUE); return NULL;}/* * Return 1 if the extension matches that of the filename. */static gint File_ext(const char *filename, const char *ext){ char *e; if ( !(e = strrchr(filename, '.')) ) return 0; return (g_strcasecmp(ext, ++e) == 0);}/* * Based on the extension, return the content_type for the file. * (if there's no extension, analize the data and try to figure it out) */static const char *File_content_type(const char *filename){ gint fd; gchar buf[256]; const gchar *ct; ssize_t buf_size; ct = "text/plain"; if (File_ext(filename, "gif")) { ct = "image/gif"; } else if (File_ext(filename, "jpg") || File_ext(filename, "jpeg")) { ct = "image/jpeg"; } else if (File_ext(filename, "png")) { ct = "image/png"; } else if (File_ext(filename, "html") || File_ext(filename, "htm") || File_ext(filename, "shtml")) { ct = "text/html"; } else { /* everything failed, let's analize the data... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -