mod_tar.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:18k
- #include "conf.h"
- #include <tar.h>
- typedef struct tar_dir {
- struct tar_dir *next;
- char *t_path;
- char *t_dir;
- umode_t t_mode;
- int t_islink;
- uid_t t_uid;
- gid_t t_gid;
- size_t t_size;
- time_t t_mtime;
- char *t_uname;
- char *t_gname;
- union {
- char *linkname;
- struct {
- unsigned int devmajor;
- unsigned int devminor;
- } device;
- unsigned long offset;
- struct tar_dir *directory;
- } i;
- } tardir_t;
- typedef struct tar_file {
- pool *p;
- char *path;
- int fd,fd_open;
- fsdir_t *f;
- tardir_t *dir,*tf_cwd;
- unsigned long pos;
- time_t tf_mtime;
- uid_t tf_uid;
- gid_t tf_gid;
- char *tf_uname;
- char *tf_gname;
- struct stat tf_stat;
- } tarfile_t;
- typedef struct tar_internal {
- unsigned long offset,pos,size;
- } tarinternal_t;
- #define MAX_OPEN_INTERNAL_FILES 32
- static int of_marker = 0;
- static tarinternal_t *open_files[MAX_OPEN_INTERNAL_FILES];
- static tardir_t *create_tar_dirlink(tarfile_t *tf, tardir_t *t, const char *name)
- {
- tardir_t *newt;
- newt = (tardir_t*)pcalloc(tf->p,sizeof(tardir_t));
- newt->t_path = newt->t_dir = pstrdup(tf->p,name);
- if(!t) {
- newt->t_mode = 0755 | S_IFDIR;
- newt->t_mtime = tf->tf_mtime;
- newt->t_uid = tf->tf_uid;
- newt->t_gid = tf->tf_gid;
- newt->t_uname = tf->tf_uname;
- newt->t_gname = tf->tf_gname;
- } else {
- newt->t_mode = t->t_mode;
- newt->t_mtime = t->t_mtime;
- newt->t_uid = t->t_uid;
- newt->t_gid = t->t_gid;
- newt->t_uname = t->t_uname;
- newt->t_gname = t->t_gname;
- }
- newt->i.directory = t;
- return newt;
- }
- static tardir_t *create_tar_directory(tarfile_t *tf, tardir_t *parent, const char *path)
- {
- tardir_t *t,*dott,*dotdott;
- t = (tardir_t*)pcalloc(tf->p,sizeof(tardir_t));
- t->t_path = t->t_dir = pstrdup(tf->p,path);
- t->t_mode = 0755 | S_IFDIR;
- t->t_mtime = tf->tf_mtime;
- t->t_uid = tf->tf_uid;
- t->t_gid = tf->tf_gid;
- t->t_uname = tf->tf_uname;
- t->t_gname = tf->tf_gname;
- dott = create_tar_dirlink(tf,t,".");
- t->i.directory = dott;
- dotdott = create_tar_dirlink(tf,parent,"..");
- dott->next = dotdott;
- return t;
- }
- static unsigned long _cvt_octal(char *buf, int size)
- {
- unsigned long l;
- char tmp[33];
- char *endp;
- sstrncpy(tmp, buf, size);
-
- l = strtol(tmp,&endp,8);
- return l;
- }
- static tardir_t *readtarfile_ent(tarfile_t *tf)
- {
- pool *p;
- tardir_t *t;
- unsigned char buf[512],tmpbuf[256],*cp;
- unsigned long chksum,blocks;
- unsigned char filetype;
- uid_t uid;
- gid_t gid;
- unsigned int tmode;
- int len,i;
- p = tf->p;
- /* read the header */
- len = tf->f->read(tf->f,tf->fd,buf,sizeof(buf));
- if(len < 512)
- return NULL;
- tf->pos += 512;
- chksum = _cvt_octal(&buf[148],8);
- memcpy(&buf[148]," ",8);
- for(i = 0; i < 512; i++)
- chksum -= buf[i];
- if(chksum)
- return NULL;
- t = (tardir_t*)pcalloc(p,sizeof(tardir_t));
- sstrncpy(tmpbuf, &buf[345], 155);
- t->t_path = pstrdup(p, tmpbuf);
- sstrncpy(tmpbuf, &buf[0], 100);
- t->t_path = pdircat(p,t->t_path,tmpbuf,NULL);
- if(!strncmp(t->t_path,"./",2))
- t->t_path += 2;
- if(!strncmp(t->t_path,"../",3))
- t->t_path += 3;
- if(*t->t_path == '/')
- t->t_path++;
- if(*(t->t_path + strlen(t->t_path) - 1) == '/') {
- *(t->t_path + strlen(t->t_path) - 1) = ' ';
- }
- sstrncpy(tmpbuf,t->t_path,sizeof(tmpbuf));
- if((cp = rindex(tmpbuf,'/')) != NULL) {
- *cp = ' ';
- t->t_dir = pstrdup(p,tmpbuf);
- } else
- t->t_dir = "";
- t->t_uid = _cvt_octal(&buf[108],8);
- t->t_gid = _cvt_octal(&buf[116],8);
- t->t_size = _cvt_octal(&buf[124],12);
- t->t_mtime = _cvt_octal(&buf[136],12);
- sstrncpy(tmpbuf,&buf[265],32);
- t->t_uname = pstrdup(p,tmpbuf);
- sstrncpy(tmpbuf,&buf[297],32);
- t->t_gname = pstrdup(p,tmpbuf);
- tmode = _cvt_octal(&buf[100],8);
- if(tmode & TSUID)
- t->t_mode |= S_ISUID;
- if(tmode & TSGID)
- t->t_mode |= S_ISGID;
- if(tmode & TSVTX)
- t->t_mode |= S_ISVTX;
- if(tmode & TUREAD)
- t->t_mode |= S_IRUSR;
- if(tmode & TUWRITE)
- t->t_mode |= S_IWUSR;
- if(tmode & TUEXEC)
- t->t_mode |= S_IXUSR;
- if(tmode & TGREAD)
- t->t_mode |= S_IRGRP;
- if(tmode & TGWRITE)
- t->t_mode |= S_IWGRP;
- if(tmode & TGEXEC)
- t->t_mode |= S_IXGRP;
- if(tmode & TOREAD)
- t->t_mode |= S_IROTH;
- if(tmode & TOWRITE)
- t->t_mode |= S_IWOTH;
- if(tmode & TOEXEC)
- t->t_mode |= S_IXOTH;
- filetype = buf[156];
- switch(filetype) {
- case LNKTYPE:
- t->t_islink = 1;
- break;
- case SYMTYPE:
- t->t_mode |= S_IFLNK;
- sstrncpy(tmpbuf,&buf[157],100);
- t->i.linkname = pstrdup(p,tmpbuf);
- break;
- case CHRTYPE:
- t->t_mode |= S_IFCHR;
- t->i.device.devmajor = _cvt_octal(&buf[329],8);
- t->i.device.devminor = _cvt_octal(&buf[337],8);
- break;
- case BLKTYPE:
- t->t_mode |= S_IFBLK;
- t->i.device.devmajor = _cvt_octal(&buf[329],8);
- t->i.device.devminor = _cvt_octal(&buf[337],8);
- break;
- case DIRTYPE:
- t->t_mode |= S_IFDIR;
- t->t_dir = t->t_path;
- break;
- case FIFOTYPE:
- t->t_mode |= S_IFIFO;
- break;
- default:
- t->t_mode |= S_IFREG;
- t->i.offset = tf->pos;
- break;
- }
- blocks = t->t_size / 512;
- if(t->t_size % 512)
- blocks++;
- if(blocks) {
- tf->f->lseek(tf->f,tf->fd,blocks*512,SEEK_CUR);
- tf->pos += (blocks * 512);
- }
- /* fixup uid and gid if possible */
- uid = auth_name_uid(p,t->t_uname);
- gid = auth_name_gid(p,t->t_gname);
- if(uid != -1)
- t->t_uname = pstrdup(p,auth_uid_name(p,uid));
- if(gid != -1)
- t->t_gname = pstrdup(p,auth_gid_name(p,gid));
- return t;
- }
- static void _dump(tardir_t *t, int tab)
- {
- int i;
- for(; t; t=t->next) {
- for(i = 0; i < tab; i++)
- printf(" ");
- printf("%s",t->t_path);
- if(S_ISDIR(t->t_mode)) {
- if(!strcmp(t->t_path,"..") || !strcmp(t->t_path,".")) {
- printf(" -> ");
- printf("%sn",(t->i.directory ? t->i.directory->t_path : "ROOT"));
- } else if(t->i.directory) {
- printf("n");
- _dump(t->i.directory,tab+1);
- } else
- printf("n");
- } else
- printf("n");
- }
- }
- static int readtarfile_directory(tarfile_t *tf)
- {
- int ret = -1,found;
- tardir_t *t,*newdir,**head,*parent;
- char path[MAXPATHLEN],*ptr,*dir;
- tf->pos = 0;
- tf->dir = create_tar_dirlink(tf,NULL,".");
- tf->dir->i.directory = tf->dir;
- while((t = readtarfile_ent(tf)) != NULL) {
- sstrncpy(path,t->t_dir,sizeof(path));
- ptr = dir = path;
- if(*ptr && *ptr == '/') {
- ptr++; dir++;
- }
- head = &tf->dir->i.directory; parent = tf->dir;
- while(ptr) {
- ptr = index(ptr,'/');
- if(ptr)
- *ptr = ' ';
- found = 0;
- /* insert into the directory list */
- while(*head) {
- if(S_ISDIR((*head)->t_mode) && !strcmp((*head)->t_dir,dir)) {
- found++;
- break;
- } else
- head = &(*head)->next;
- }
- if(S_ISDIR(t->t_mode)) {
- if(*head) {
- if(S_ISDIR((*head)->t_mode) && !strcmp((*head)->t_path,t->t_path)) {
- ptr = NULL;
- ret = 0;
- } else {
- parent = *head;
- head = &(*head)->i.directory;
- }
- } else {
- if(ptr) {
- newdir = create_tar_directory(tf,parent,dir);
- *head = parent = newdir;
- head = &newdir->i.directory;
- } else {
- tardir_t *dott,*dotdott;
- dott = create_tar_dirlink(tf,t,".");
- dotdott = create_tar_dirlink(tf,parent,"..");
-
- dott->next = dotdott;
- t->i.directory = dott;
- t->next = *head;
- *head = parent = t;
- ret = 0;
- }
- }
- } else {
- if(!ptr) {
- /* insert here */
- if(*head && S_ISDIR((*head)->t_mode)) {
- parent = *head;
- head = &(*head)->i.directory;
- } t->next = *head;
- *head = t;
- ret = 0;
- } else if(!*head) {
- /* need to add this directory */
- newdir = create_tar_directory(tf,parent,dir);
- *head = parent = newdir;
- head = &newdir->i.directory;
- } else {
- parent = *head;
- head = &(*head)->i.directory;
- }
- }
- if(ptr)
- *ptr++ = '/';
- }
- if(ret == -1)
- break;
- }
- #if 1
- _dump(tf->dir,0);
- #endif
- return ret;
- }
- static tarfile_t *opentarfile(fsdir_t *f, const char *name)
- {
- int fd;
- tarfile_t *tf;
- struct stat sbuf;
- pool *p;
- if(f->stat(f,name,&sbuf) == -1)
- return NULL;
- fd = f->open(f,name,O_RDONLY);
- if(fd == -1)
- return NULL;
- p = make_sub_pool(permanent_pool);
- tf = (tarfile_t*)pcalloc(p,sizeof(tarfile_t));
- tf->p = p;
- tf->fd = fd;
- tf->fd_open = -1;
- tf->f = f;
- tf->path = pstrdup(p,name);
- tf->tf_mtime = sbuf.st_mtime;
- tf->tf_uid = sbuf.st_uid;
- tf->tf_gid = sbuf.st_gid;
- tf->tf_uname = pstrdup(tf->p,auth_uid_name(tf->p,sbuf.st_uid));
- tf->tf_gname = pstrdup(tf->p,auth_gid_name(tf->p,sbuf.st_gid));
- memcpy(&tf->tf_stat,&sbuf,sizeof(sbuf));
- readtarfile_directory(tf);
- f->close(f,fd);
- tf->fd = -1;
- return tf;
- }
- static void closetarfile(fsdir_t *f)
- {
- tarfile_t *tf;
- tf = (tarfile_t*)f->private;
- if(tf && tf->fd != -1 && tf->fd_open == -1) {
- f->parent->close(f->parent,tf->fd);
- tf->fd = -1;
- }
- }
- static tarfile_t *checktarfile(fsdir_t *f)
- {
- tarfile_t *tf;
-
- tf = (tarfile_t*)f->private;
- if(!tf) {
- f->private = tf = opentarfile(f->parent,f->name);
- if(tf) {
- f->parent->lseek(f->parent,tf->fd,0,SEEK_SET);
- tf->pos = 0;
- }
- } else {
- if(tf->fd == -1) {
- tf->fd = f->parent->open(f->parent,f->name,O_RDONLY);
- tf->pos = 0;
- if(tf->fd == -1)
- return NULL;
- }
- }
- return tf;
- }
- static tardir_t *tarfile_gettardir(tarfile_t *tf, tardir_t *t, const char *path)
- {
- if(*path == '/')
- path++;
- if(!*path)
- return tarfile_gettardir(tf,tf->dir,".");
- if(!t)
- t = tf->dir->i.directory;
- while(t) {
- if(!strcmp(t->t_path,path))
- break;
- if(S_ISDIR(t->t_mode) && !strncmp(t->t_path,path,strlen(t->t_path)) &&
- strcmp(t->t_path,"."))
- t = t->i.directory;
- else
- t = t->next;
- }
- return t;
- }
- static char local[MAXPATHLEN];
- static char local_cwd[MAXPATHLEN] = "/";
- static int get_local(fsdir_t *f, const char *path, char *buf, int maxlen)
- {
- char tmp[MAXPATHLEN];
- register int l = strlen(f->name);
- if(*path == '/' && !strncmp(f->name,path,l))
- sstrncpy(tmp,path+l,maxlen - l);
- else {
- *tmp = ' ';
- fs_dircat(tmp,sizeof(tmp),local_cwd,path);
- }
- fs_clean_path(tmp,buf,maxlen);
- return 0;
- }
- static int tar_chdir(fsdir_t *f, const char *path)
- {
- tarfile_t *tf;
- tardir_t *t;
- tf = checktarfile(f);
- if(!tf)
- return -1;
- get_local(f,path,local,sizeof(local));
- t = tarfile_gettardir(tf,NULL,local);
- if(!t) {
- errno = ENOENT;
- return -1;
- }
- if(!S_ISDIR(t->t_mode)) {
- errno = ENOTDIR;
- return -1;
- }
- tf->tf_cwd = t->i.directory;
- sstrncpy(local_cwd,local,sizeof(local));
- closetarfile(f);
- return 0;
- }
- static int tar_readlink(fsdir_t *f, const char *path, char *buf, size_t bufsiz)
- {
- tarfile_t *tf;
- tardir_t *t;
- tf = checktarfile(f);
- if(!tf)
- return -1;
- get_local(f,path,local,sizeof(local));
- t = tarfile_gettardir(tf,NULL,local);
- if(!t) {
- errno = ENOENT;
- return -1;
- }
- if(!S_ISLNK(t->t_mode)) {
- errno = EINVAL;
- return -1;
- }
- sstrncpy(buf,t->i.linkname,bufsiz);
- closetarfile(f);
- return strlen(buf);
- }
- static int tar_lstat(fsdir_t *f, const char *path, struct stat *sbuf)
- {
- tarfile_t *tf;
- tardir_t *t;
- tf = checktarfile(f);
- if(!tf)
- return -1;
- get_local(f,path,local,sizeof(local));
- t = tarfile_gettardir(tf,NULL,local);
- if(!t) {
- closetarfile(f);
- errno = ENOENT;
- return -1;
- }
- if(!strcmp(local,"/")) {
- memcpy(sbuf,&tf->tf_stat,sizeof(struct stat));
- sbuf->st_mode = t->t_mode;
- } else {
- bzero(sbuf,sizeof(struct stat));
- sbuf->st_ino = (ino_t)t;
- sbuf->st_mode = t->t_mode;
- sbuf->st_nlink = 1;
- sbuf->st_uid = t->t_uid;
- sbuf->st_gid = t->t_gid;
- sbuf->st_size = t->t_size;
- sbuf->st_atime = sbuf->st_mtime = sbuf->st_ctime = t->t_mtime;
- if(S_ISREG(t->t_mode)) {
- sbuf->st_blksize = 512;
- sbuf->st_blocks = t->t_size / 512;
- if(t->t_size % 512)
- sbuf->st_blocks++;
- }
- }
- closetarfile(f);
- return 0;
- }
- static int tar_stat(fsdir_t *f, const char *path, struct stat *sbuf)
- {
- if(tar_lstat(f,path,sbuf) == -1)
- return -1;
- if(S_ISLNK(sbuf->st_mode)) {
- char linkbuf[MAXPATHLEN];
- if(tar_readlink(f,path,linkbuf,sizeof(linkbuf)) == -1)
- return -1;
- return fs_stat(linkbuf,sbuf);
- }
- return 0;
- }
- static int tar_close(fsdir_t *f, int fd)
- {
- tarfile_t *tf;
- tf = checktarfile(f);
- if(!tf)
- return -1;
- if(!open_files[fd]) {
- errno = EBADF;
- return -1;
- }
- free(open_files[fd]);
- open_files[fd] = NULL;
- while(of_marker && !open_files[of_marker])
- of_marker--;
- if(!of_marker) {
- tf->fd_open = -1;
- closetarfile(f);
- }
- return 0;
- }
- static int tar_open(fsdir_t *f, const char *path, int access)
- {
- tarinternal_t *ti;
- tarfile_t *tf;
- tardir_t *t;
- tf = checktarfile(f);
- if(!tf)
- return -1;
- get_local(f,path,local,sizeof(local));
- t = tarfile_gettardir(tf,NULL,local);
- if(!t) {
- closetarfile(f);
- errno = ENOENT;
- return -1;
- }
- if(!S_ISREG(t->t_mode)) {
- closetarfile(f);
- errno = EACCES;
- return -1;
- }
- if(session.uid == t->t_uid) {
- if((t->t_mode & S_IRUSR) == 0) {
- closetarfile(f);
- errno = EACCES;
- return -1;
- }
- } else if(session.gid == t->t_gid) {
- if((t->t_mode & S_IRGRP) == 0) {
- closetarfile(f);
- errno = EACCES;
- return -1;
- }
- } else {
- if((t->t_mode & S_IROTH) == 0) {
- closetarfile(f);
- errno = EACCES;
- return -1;
- }
- }
-
- if(of_marker == MAX_OPEN_INTERNAL_FILES) {
- closetarfile(f);
- errno = ENFILE;
- return -1;
- }
- ti = open_files[of_marker++] = malloc(sizeof(tarinternal_t));
- if(!ti) {
- closetarfile(f);
- errno = ENOMEM;
- return -1;
- }
- ti->pos = ti->offset = t->i.offset;
- ti->size = t->t_size;
- if(f->parent->lseek(f->parent,tf->fd,ti->pos,SEEK_SET) == -1) {
- int hold_errno = errno;
- closetarfile(f);
- return -1;
- }
- tf->fd_open = tf->fd;
- return of_marker-1;
- }
- static int tar_write(fsdir_t *f, int fd, const char *buf, size_t size)
- {
- errno = EACCES;
- return -1;
- }
-
- static int tar_read(fsdir_t *f, int fd, char *buf, size_t size)
- {
- tarinternal_t *ti;
- tarfile_t *tf;
- int bread;
- tf = checktarfile(f);
- if(!tf)
- return -1;
- if(fd < 0 || fd >= MAX_OPEN_INTERNAL_FILES || (ti = open_files[fd]) == NULL) {
- closetarfile(f);
- errno = EBADF;
- return -1;
- }
-
- if(ti->pos >= (ti->offset + ti->size))
- return 0;
- if((ti->pos - ti->offset) + size >= ti->size)
- size = ti->size - (ti->pos - ti->offset);
- if(tf->pos != ti->pos) {
- if(f->parent->lseek(f->parent,tf->fd,ti->pos,SEEK_SET) == -1)
- return -1;
- tf->pos = ti->pos;
- }
-
- bread = f->parent->read(f->parent,tf->fd,buf,size);
- if(bread <= 0)
- return bread;
- tf->pos += bread;
- ti->pos += bread;
- return bread;
- }
- static off_t tar_lseek(fsdir_t *f, int fd, off_t offset, int whence)
- {
- tarinternal_t *ti;
- tarfile_t *tf;
- tf = checktarfile(f);
- if(!tf)
- return -1;
- if(fd < 0 || fd >= MAX_OPEN_INTERNAL_FILES || (ti = open_files[fd]) == NULL) {
- closetarfile(f);
- errno = EBADF;
- return -1;
- }
- switch(whence) {
- case SEEK_CUR:
- offset += (ti->pos - ti->offset);
- break;
- case SEEK_END:
- offset += ti->size;
- break;
- }
- if(offset < 0)
- offset = 0;
- if(offset > ti->size)
- offset = ti->size;
- ti->pos = ti->offset + offset;
- return offset;
- }
- static void *tar_opendir(fsdir_t *f, const char *path)
- {
- tarfile_t *tf;
- tardir_t *t,**cursor;
- tf = checktarfile(f);
- if(!tf)
- return NULL;
- get_local(f,path,local,sizeof(local));
- t = tarfile_gettardir(tf,NULL,local);
- if(!t) {
- closetarfile(f);
- errno = ENOENT;
- return NULL;
- }
- if(!S_ISDIR(t->t_mode)) {
- closetarfile(f);
- errno = ENOTDIR;
- return NULL;
- }
- cursor = malloc(sizeof(tardir_t*));
- *cursor = t->i.directory;
- return cursor;
- }
-
- static struct dirent *tar_readdir(fsdir_t *f, void *_dir)
- {
- tardir_t *t,**cursor = (tardir_t**)_dir;
- char tmpbuf[MAXPATHLEN],*cp;
- static struct dirent dir;
- if(!cursor || !*cursor)
- return NULL;
- t = *cursor;
- dir.d_ino = (long)t;
- dir.d_off = 0;
- dir.d_reclen = sizeof(struct dirent);
- dir.d_type = 0;
-
- sstrncpy(tmpbuf,t->t_path,sizeof(tmpbuf));
- if((cp = rindex(tmpbuf,'/')) != NULL)
- *cp++ = ' ';
- else
- cp = tmpbuf;
- sstrncpy(dir.d_name,cp,NAME_MAX);
- *cursor = t->next;
- return &dir;
- }
- static int tar_closedir(fsdir_t *f, void *_dir)
- {
- tardir_t **cursor = (tardir_t**)_dir;
- if(cursor)
- free(cursor);
- closetarfile(f);
- return 0;
- }
-
- static int tar_hit(fsdir_t *f, const char *path, int op)
- {
- fsdir_t *newfs;
- struct stat sbuf;
- char buf[MAXPATHLEN];
- #if 0
- if(op == FSOP_OPEN) {
- #endif
- if(f->stat(f,path,&sbuf) == -1)
- return -1;
- if(!S_ISREG(sbuf.st_mode))
- return 0;
- fs_resolve_path(path,buf,sizeof(buf),0);
- newfs = fs_register(buf);
- newfs->chdir = &tar_chdir;
- newfs->lstat = &tar_lstat;
- newfs->stat = &tar_stat;
- newfs->readlink = &tar_readlink;
- newfs->open = &tar_open;
- newfs->close = &tar_close;
- newfs->read = &tar_read;
- newfs->write = &tar_write;
- newfs->lseek = &tar_lseek;
- newfs->opendir = &tar_opendir;
- newfs->readdir = &tar_readdir;
- newfs->closedir = &tar_closedir;
- #if 0
- newfs->open = &html_open;
- newfs->close = &html_close;
- newfs->read = &html_read;
- newfs->write = &html_write;
- #endif
- return 1;
- #if 0
- }
- #endif
- return 0;
- }
- static int tar_init()
- {
- fsmatch_t *fm;
- bzero(open_files,sizeof(open_files));
- fm = fs_register_match("*.tar",0xffffffff);
- fm->dir_hit = fm->file_hit = tar_hit;
- return 0;
- }
- module tar_module = {
- NULL,NULL,
- 0x20,
- "tar",
- NULL,
- NULL,
- NULL,
- tar_init,NULL
- };