18.3.11 SHTTPD生成目录下文件列表文件的实现
当客户端请求的是一个目录名的时候,需要判断是否当前目录下有一个与默认文件名一致的文件。如果没有,则需要将当前目录下面的所有目录列表出来,并形成超级链接,目录文件列表的实现代码如下:
(1)先打开目录,并打开一个临时文件。
int GenerateDirFile(struct worker_ctl *wctl)
{
struct conn_request *req = &wctl->conn.con_req;
struct conn_response *res = &wctl->conn.con_res;
char *command = strstr(req->uri, CGISTR) + strlen(CGISTR);
char *arg[ARGNUM];
int num = 0;
char *rpath = wctl->conn.con_req.rpath;
stat *fs = &wctl->conn.con_res.fsate;
/*打开目录*/
DIR *dir = opendir(rpath);
if(dir == NULL)
{
/*错误*/
res->status = 500;
retval = -1;
goto EXITgenerateIndex;
}
/*建立临时文件保存目录列表*/
File *tmpfile;
char tmpbuff[2048];
int filesize = 0;
char *uri = wctl->conn.con_req.uri;
tmpfile = tmpfile();
(2)建立标题部分字符串,标题为当前的URI。
/*标题部分*/
sprintf(tmpbuff,
"%s%s%s",
"<!DOCTYPE HTML PUBLIC /"-//W3C//DTD HTML 3.2 Final//EN/">/n<HTML>
<HEAD><TITLE>",
uri,
"</TITLE></HEAD>/n" );
fprintf(tmpfile, "%s", tmpbuff);
filesize += strlen(tmpbuff);
目录下的文件列表的格式为:
文件名 日期 大小
形式的东西,先将上述的格式打印出来。
/*标识部分*/
sprintf(tmpbuff,
"%s %s %s",
"<BODY><H1>Index of:",
uri,
" </H1> <HR><P><I>Date: </I> <I>Size: </I></P><HR>");
fprintf(tmpfile, "%s", tmpbuff);
filesize += strlen(tmpbuff);
(3)下面进入主要的部分获得目录下面的文件列表。
这个文件列表主要分为3类:一类为“.”和“..”等特殊的目录;一类为正常的目录;最后一类为正规文件。其中当前目录“.”不用显示,而表示其上层目录的“..”需要显示的将其名称用“父目录”表示出来。
对于正规的文件需要获得文件的日期和大小等参数。最后,当目录下所有的文件遍历完毕之后,需要更新用于表示客户端访问资源属性的参数fs,将它的修改时间、建立时间等设置为当前,主要是设置其大小,以便之后进行访问。为了防止出现问题,需要将文件的指针移到文件的首部。
/* 读取目录中的文件列表 */
struct dirent *de;
#define PATHLENGTH 2048
char path[PATHLENGTH];
char tmpath[PATHLENGTH];
char linkname[PATHLENGTH];
struct stat fs;
strcpy(path, rpath);
if(rpath[strlen(rpath)]!='/')
{
rpath[strlen(rpath)]='/';
}
while ((de = readdir(dir)) != NULL) /*读取一个文件*/
{
menset(tmpath, 0, sizeof(tmpath));
menset(linkname, 0, sizeof(linkname));
if(strcmp(de->d_name, ".")) /*不是当前目录*/
{
if(strcmp(de->d_name, "..")) /*不是父目录*/
{
strcpy(linkname,de->d_name); /*将目录名称作为链接名称*/
}
else/*是父目录*/
{
strcpy(linkname, "Parent Directory");
/*将父目录作为链接名称*/
}
sprintf(tmpath, "%s%s",path, de->d_name);
/*构建当前文件的全路径*/
stat(tmpath, &fs); /*获得文件信息*/
if(S_ISDIR(fs.st_mode)) /*是一个目录*/
{
/*打印目录的链接为目录名称*/
sprintf(tmpbuff, "<A HREF=/"%s//">%s/</A><BR>/n", de->d_
name,tmpath);
}
else/*正常文件*/
{
char size_str[32];
off_t size_int;
size_int = fs.st_size; /*文件大小*/
if (size_int < 1024) /*不到1K*/
sprintf(size_str, "%d bytes", (int) size_int);
else if (size_int < 1024*1024) /*不到1M*/
sprintf(size_str, "%1.2f Kbytes", (float) size_int /
1024);
else/*其他*/
sprintf(size_str, "%1.2f Mbytes", (float) size_int /
(1024*1024));
/*输出文件大小*/
sprintf(tmpbuff, "<A HREF=/"%s/">%s</A> (%s)<BR>/n", de->
d_name, linkname, size_int);
}
/*将形成的字符串写入临时文件*/
fprintf(tmpfile, "%s", tmpbuff);
filesize += strlen(tmpbuff);
}
}
/*生成临时的文件信息,主要是文件大小*/
fs.st_ctime = time(NULL);
fs.st_mtime = time(NULL);
fs.st_size = filesize;
fseek(tmpfile, (long) 0, SEEK_SET); /*移动文件指针到头部*/
}