mod_tar.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:18k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. #include "conf.h"
  2. #include <tar.h>
  3. typedef struct tar_dir {
  4.   struct tar_dir *next;
  5.   char *t_path;
  6.   char *t_dir;
  7.   umode_t t_mode;
  8.   int t_islink;
  9.   uid_t t_uid;
  10.   gid_t t_gid;
  11.   size_t t_size;
  12.   time_t t_mtime;
  13.   char *t_uname;
  14.   char *t_gname;
  15.   union {
  16.     char *linkname;
  17.     struct {
  18.       unsigned int devmajor;
  19.       unsigned int devminor;
  20.     } device;
  21.     unsigned long offset;
  22.     struct tar_dir *directory;
  23.   } i;
  24. } tardir_t;
  25. typedef struct tar_file {
  26.   pool *p;
  27.   char *path;
  28.   int fd,fd_open;
  29.   fsdir_t *f;
  30.   tardir_t *dir,*tf_cwd;
  31.   unsigned long pos;
  32.   time_t tf_mtime;
  33.   uid_t tf_uid;
  34.   gid_t tf_gid;
  35.   char *tf_uname;
  36.   char *tf_gname;
  37.   struct stat tf_stat;
  38. } tarfile_t;
  39. typedef struct tar_internal {
  40.   unsigned long offset,pos,size;
  41. } tarinternal_t;
  42. #define MAX_OPEN_INTERNAL_FILES  32
  43. static int of_marker = 0;
  44. static tarinternal_t *open_files[MAX_OPEN_INTERNAL_FILES];
  45. static tardir_t *create_tar_dirlink(tarfile_t *tf, tardir_t *t, const char *name)
  46. {
  47.   tardir_t *newt;
  48.   newt = (tardir_t*)pcalloc(tf->p,sizeof(tardir_t));
  49.   newt->t_path = newt->t_dir = pstrdup(tf->p,name);
  50.   if(!t) {
  51.     newt->t_mode = 0755 | S_IFDIR;
  52.     newt->t_mtime = tf->tf_mtime;
  53.     newt->t_uid = tf->tf_uid;
  54.     newt->t_gid = tf->tf_gid;
  55.     newt->t_uname = tf->tf_uname;
  56.     newt->t_gname = tf->tf_gname;
  57.   } else {
  58.     newt->t_mode = t->t_mode;
  59.     newt->t_mtime = t->t_mtime;
  60.     newt->t_uid = t->t_uid;
  61.     newt->t_gid = t->t_gid;
  62.     newt->t_uname = t->t_uname;
  63.     newt->t_gname = t->t_gname;
  64.   }
  65.   newt->i.directory = t;
  66.   return newt;
  67. }
  68. static tardir_t *create_tar_directory(tarfile_t *tf, tardir_t *parent, const char *path)
  69. {
  70.   tardir_t *t,*dott,*dotdott;
  71.   t = (tardir_t*)pcalloc(tf->p,sizeof(tardir_t));
  72.   t->t_path = t->t_dir = pstrdup(tf->p,path);
  73.   t->t_mode = 0755 | S_IFDIR;
  74.   t->t_mtime = tf->tf_mtime;
  75.   t->t_uid = tf->tf_uid;
  76.   t->t_gid = tf->tf_gid;
  77.   t->t_uname = tf->tf_uname;
  78.   t->t_gname = tf->tf_gname;
  79.   dott = create_tar_dirlink(tf,t,".");
  80.   t->i.directory = dott;
  81.   dotdott = create_tar_dirlink(tf,parent,"..");
  82.   dott->next = dotdott;
  83.   return t;
  84. }
  85. static unsigned long _cvt_octal(char *buf, int size)
  86. {
  87.   unsigned long l;
  88.   char tmp[33];
  89.   char *endp;
  90.   sstrncpy(tmp, buf, size);
  91.   
  92.   l = strtol(tmp,&endp,8);
  93.   return l;  
  94. }
  95. static tardir_t *readtarfile_ent(tarfile_t *tf)
  96. {
  97.   pool *p;
  98.   tardir_t *t;
  99.   unsigned char buf[512],tmpbuf[256],*cp;
  100.   unsigned long chksum,blocks;
  101.   unsigned char filetype;
  102.   uid_t uid;
  103.   gid_t gid;
  104.   unsigned int tmode;
  105.   int len,i;
  106.   p = tf->p;
  107.   /* read the header */
  108.   len = tf->f->read(tf->f,tf->fd,buf,sizeof(buf));
  109.   if(len < 512)
  110.     return NULL;
  111.   tf->pos += 512;
  112.   chksum = _cvt_octal(&buf[148],8);
  113.   memcpy(&buf[148],"        ",8);
  114.   for(i = 0; i < 512; i++)
  115.     chksum -= buf[i];
  116.   if(chksum)
  117.     return NULL;
  118.   t = (tardir_t*)pcalloc(p,sizeof(tardir_t));
  119.   sstrncpy(tmpbuf, &buf[345], 155);
  120.   t->t_path = pstrdup(p, tmpbuf);
  121.   sstrncpy(tmpbuf, &buf[0], 100);
  122.   t->t_path = pdircat(p,t->t_path,tmpbuf,NULL);
  123.   if(!strncmp(t->t_path,"./",2))
  124.     t->t_path += 2;
  125.   if(!strncmp(t->t_path,"../",3))
  126.     t->t_path += 3;
  127.   if(*t->t_path == '/')
  128.     t->t_path++;
  129.   if(*(t->t_path + strlen(t->t_path) - 1) == '/') {
  130.     *(t->t_path + strlen(t->t_path) - 1) = '';
  131.   }
  132.   sstrncpy(tmpbuf,t->t_path,sizeof(tmpbuf));
  133.   if((cp = rindex(tmpbuf,'/')) != NULL) {
  134.     *cp = '';
  135.     t->t_dir = pstrdup(p,tmpbuf);
  136.   } else
  137.     t->t_dir = "";
  138.   t->t_uid = _cvt_octal(&buf[108],8);
  139.   t->t_gid = _cvt_octal(&buf[116],8);
  140.   t->t_size = _cvt_octal(&buf[124],12);
  141.   t->t_mtime = _cvt_octal(&buf[136],12);
  142.   sstrncpy(tmpbuf,&buf[265],32);
  143.   t->t_uname = pstrdup(p,tmpbuf);
  144.   sstrncpy(tmpbuf,&buf[297],32);
  145.   t->t_gname = pstrdup(p,tmpbuf);
  146.   tmode = _cvt_octal(&buf[100],8);
  147.   if(tmode & TSUID)
  148.     t->t_mode |= S_ISUID;
  149.   if(tmode & TSGID)
  150.     t->t_mode |= S_ISGID;
  151.   if(tmode & TSVTX)
  152.     t->t_mode |= S_ISVTX;
  153.   if(tmode & TUREAD)
  154.     t->t_mode |= S_IRUSR;
  155.   if(tmode & TUWRITE)
  156.     t->t_mode |= S_IWUSR;
  157.   if(tmode & TUEXEC)
  158.     t->t_mode |= S_IXUSR;
  159.   if(tmode & TGREAD)
  160.     t->t_mode |= S_IRGRP;
  161.   if(tmode & TGWRITE)
  162.     t->t_mode |= S_IWGRP;
  163.   if(tmode & TGEXEC)
  164.     t->t_mode |= S_IXGRP;
  165.   if(tmode & TOREAD)
  166.     t->t_mode |= S_IROTH;
  167.   if(tmode & TOWRITE)
  168.     t->t_mode |= S_IWOTH;
  169.   if(tmode & TOEXEC)
  170.     t->t_mode |= S_IXOTH;
  171.   filetype = buf[156];
  172.   switch(filetype) {
  173.   case LNKTYPE:
  174.     t->t_islink = 1;
  175.     break;
  176.   case SYMTYPE:
  177.     t->t_mode |= S_IFLNK;
  178.     sstrncpy(tmpbuf,&buf[157],100);
  179.     t->i.linkname = pstrdup(p,tmpbuf);
  180.     break;
  181.   case CHRTYPE:
  182.     t->t_mode |= S_IFCHR;
  183.     t->i.device.devmajor = _cvt_octal(&buf[329],8);
  184.     t->i.device.devminor = _cvt_octal(&buf[337],8);
  185.     break;
  186.   case BLKTYPE:
  187.     t->t_mode |= S_IFBLK;
  188.     t->i.device.devmajor = _cvt_octal(&buf[329],8);
  189.     t->i.device.devminor = _cvt_octal(&buf[337],8);
  190.     break;
  191.   case DIRTYPE:
  192.     t->t_mode |= S_IFDIR;
  193.     t->t_dir = t->t_path;
  194.     break;
  195.   case FIFOTYPE:
  196.     t->t_mode |= S_IFIFO;
  197.     break;
  198.   default:
  199.     t->t_mode |= S_IFREG;
  200.     t->i.offset = tf->pos;
  201.     break;
  202.   }
  203.   blocks = t->t_size / 512;
  204.   if(t->t_size % 512)
  205.     blocks++;
  206.   if(blocks) {
  207.     tf->f->lseek(tf->f,tf->fd,blocks*512,SEEK_CUR);
  208.     tf->pos += (blocks * 512);
  209.   }
  210.   /* fixup uid and gid if possible */
  211.   uid = auth_name_uid(p,t->t_uname);
  212.   gid = auth_name_gid(p,t->t_gname);
  213.   if(uid != -1)
  214.     t->t_uname = pstrdup(p,auth_uid_name(p,uid));
  215.   if(gid != -1)
  216.     t->t_gname = pstrdup(p,auth_gid_name(p,gid));
  217.   return t;
  218. }
  219. static void _dump(tardir_t *t, int tab)
  220. {
  221.   int i;
  222.   for(; t; t=t->next) {
  223.     for(i = 0; i < tab; i++)
  224.       printf("  ");
  225.     printf("%s",t->t_path);
  226.     if(S_ISDIR(t->t_mode)) {
  227.       if(!strcmp(t->t_path,"..") || !strcmp(t->t_path,".")) {
  228.         printf(" -> ");
  229.         printf("%sn",(t->i.directory ? t->i.directory->t_path : "ROOT"));
  230.       } else if(t->i.directory) {
  231.         printf("n");
  232.         _dump(t->i.directory,tab+1);
  233.       } else
  234.         printf("n");
  235.     } else
  236.       printf("n");
  237.   }
  238. }
  239. static int readtarfile_directory(tarfile_t *tf)
  240. {
  241.   int ret = -1,found;
  242.   tardir_t *t,*newdir,**head,*parent;
  243.   char path[MAXPATHLEN],*ptr,*dir;
  244.   tf->pos = 0;
  245.   tf->dir = create_tar_dirlink(tf,NULL,".");
  246.   tf->dir->i.directory = tf->dir;
  247.   while((t = readtarfile_ent(tf)) != NULL) {
  248.     sstrncpy(path,t->t_dir,sizeof(path));
  249.     ptr = dir = path;
  250.     if(*ptr && *ptr == '/') {
  251.       ptr++; dir++;
  252.     }
  253.     head = &tf->dir->i.directory; parent = tf->dir;
  254.     while(ptr) {
  255.       ptr = index(ptr,'/');
  256.       if(ptr)
  257.         *ptr = '';
  258.       found = 0;
  259.       /* insert into the directory list */
  260.       while(*head) {
  261.         if(S_ISDIR((*head)->t_mode) && !strcmp((*head)->t_dir,dir)) {
  262.           found++;
  263.           break;
  264.         } else
  265.           head = &(*head)->next;
  266.       }
  267.       if(S_ISDIR(t->t_mode)) {
  268.         if(*head) {
  269.           if(S_ISDIR((*head)->t_mode) && !strcmp((*head)->t_path,t->t_path)) {
  270.             ptr = NULL;
  271.             ret = 0;
  272.           } else {
  273.             parent = *head;
  274.             head = &(*head)->i.directory;
  275.           }
  276.         } else {
  277.           if(ptr) {
  278.             newdir = create_tar_directory(tf,parent,dir);
  279.             *head = parent = newdir;
  280.             head = &newdir->i.directory;
  281.           } else {
  282.             tardir_t *dott,*dotdott;
  283.             dott = create_tar_dirlink(tf,t,".");
  284.             dotdott = create_tar_dirlink(tf,parent,"..");
  285.  
  286.             dott->next = dotdott;
  287.             t->i.directory = dott;
  288.             t->next = *head;
  289.             *head = parent = t;
  290.             ret = 0;
  291.           }
  292.         }
  293.       } else {
  294.         if(!ptr) {
  295.           /* insert here */
  296.           if(*head && S_ISDIR((*head)->t_mode)) {
  297.             parent = *head;
  298.             head = &(*head)->i.directory;
  299.           } t->next = *head;
  300.           *head = t;
  301.           ret = 0;
  302.         } else if(!*head) {
  303.           /* need to add this directory */
  304.           newdir = create_tar_directory(tf,parent,dir);
  305.           *head = parent = newdir;
  306.           head = &newdir->i.directory;
  307.         } else {
  308.           parent = *head;
  309.           head = &(*head)->i.directory;
  310.         }
  311.       }
  312.       if(ptr)
  313.         *ptr++ = '/';
  314.     }
  315.     if(ret == -1)
  316.       break;
  317.   }
  318. #if 1
  319.   _dump(tf->dir,0);
  320. #endif
  321.   return ret;
  322. }
  323. static tarfile_t *opentarfile(fsdir_t *f, const char *name)
  324. {
  325.   int fd;
  326.   tarfile_t *tf;
  327.   struct stat sbuf;
  328.   pool *p;
  329.   if(f->stat(f,name,&sbuf) == -1)
  330.     return NULL;
  331.   fd = f->open(f,name,O_RDONLY);
  332.   if(fd == -1)
  333.     return NULL;
  334.   p = make_sub_pool(permanent_pool);
  335.   tf = (tarfile_t*)pcalloc(p,sizeof(tarfile_t));
  336.   tf->p = p;
  337.   tf->fd = fd;
  338.   tf->fd_open = -1;
  339.   tf->f = f;
  340.   tf->path = pstrdup(p,name);
  341.   tf->tf_mtime = sbuf.st_mtime;
  342.   tf->tf_uid = sbuf.st_uid;
  343.   tf->tf_gid = sbuf.st_gid;
  344.   tf->tf_uname = pstrdup(tf->p,auth_uid_name(tf->p,sbuf.st_uid));
  345.   tf->tf_gname = pstrdup(tf->p,auth_gid_name(tf->p,sbuf.st_gid));
  346.   memcpy(&tf->tf_stat,&sbuf,sizeof(sbuf));
  347.   readtarfile_directory(tf);
  348.   f->close(f,fd);
  349.   tf->fd = -1;
  350.   return tf;
  351. }
  352. static void closetarfile(fsdir_t *f)
  353. {
  354.   tarfile_t *tf;
  355.   tf = (tarfile_t*)f->private;
  356.   if(tf && tf->fd != -1 && tf->fd_open == -1) {
  357.     f->parent->close(f->parent,tf->fd);
  358.     tf->fd = -1;
  359.   }
  360. }
  361. static tarfile_t *checktarfile(fsdir_t *f)
  362. {
  363.   tarfile_t *tf;
  364.  
  365.   tf = (tarfile_t*)f->private;
  366.   if(!tf) {
  367.     f->private = tf = opentarfile(f->parent,f->name);
  368.     if(tf) {
  369.       f->parent->lseek(f->parent,tf->fd,0,SEEK_SET);
  370.       tf->pos = 0;
  371.     }
  372.   } else {
  373.     if(tf->fd == -1) {
  374.       tf->fd = f->parent->open(f->parent,f->name,O_RDONLY);
  375.       tf->pos = 0;
  376.       if(tf->fd == -1)
  377.         return NULL;
  378.     }
  379.   }
  380.   return tf;
  381. }
  382. static tardir_t *tarfile_gettardir(tarfile_t *tf, tardir_t *t, const char *path)
  383. {
  384.   if(*path == '/')
  385.     path++;
  386.   if(!*path)
  387.     return tarfile_gettardir(tf,tf->dir,".");
  388.   if(!t)
  389.     t = tf->dir->i.directory;
  390.   while(t) {
  391.     if(!strcmp(t->t_path,path))
  392.       break;
  393.     if(S_ISDIR(t->t_mode) && !strncmp(t->t_path,path,strlen(t->t_path)) &&
  394.        strcmp(t->t_path,"."))
  395.       t = t->i.directory;
  396.     else
  397.       t = t->next;
  398.   }
  399.   return t;
  400. }
  401. static char local[MAXPATHLEN];
  402. static char local_cwd[MAXPATHLEN] = "/";
  403. static int get_local(fsdir_t *f, const char *path, char *buf, int maxlen)
  404. {
  405.   char tmp[MAXPATHLEN];
  406.   register int l = strlen(f->name);
  407.   if(*path == '/' && !strncmp(f->name,path,l))
  408.     sstrncpy(tmp,path+l,maxlen - l);
  409.   else {
  410.     *tmp = '';
  411.     fs_dircat(tmp,sizeof(tmp),local_cwd,path);
  412.   }
  413.   fs_clean_path(tmp,buf,maxlen);
  414.   return 0;
  415. }
  416. static int tar_chdir(fsdir_t *f, const char *path)
  417. {
  418.   tarfile_t *tf;
  419.   tardir_t *t;
  420.   tf = checktarfile(f);
  421.   if(!tf)
  422.     return -1;
  423.   get_local(f,path,local,sizeof(local));
  424.   t = tarfile_gettardir(tf,NULL,local);
  425.   if(!t) {
  426.     errno = ENOENT;
  427.     return -1;
  428.   }
  429.   if(!S_ISDIR(t->t_mode)) {
  430.     errno = ENOTDIR;
  431.     return -1;
  432.   }
  433.   tf->tf_cwd = t->i.directory;
  434.   sstrncpy(local_cwd,local,sizeof(local));
  435.   closetarfile(f);
  436.   return 0;
  437. }
  438. static int tar_readlink(fsdir_t *f, const char *path, char *buf, size_t bufsiz)
  439. {
  440.   tarfile_t *tf;
  441.   tardir_t *t;
  442.   tf = checktarfile(f);
  443.   if(!tf)
  444.     return -1;
  445.   get_local(f,path,local,sizeof(local));
  446.   t = tarfile_gettardir(tf,NULL,local);
  447.   if(!t) {
  448.     errno = ENOENT;
  449.     return -1;
  450.   }
  451.   if(!S_ISLNK(t->t_mode)) {
  452.     errno = EINVAL;
  453.     return -1;
  454.   }
  455.   sstrncpy(buf,t->i.linkname,bufsiz);
  456.   closetarfile(f);
  457.   return strlen(buf);
  458. }
  459. static int tar_lstat(fsdir_t *f, const char *path, struct stat *sbuf)
  460. {
  461.   tarfile_t *tf;
  462.   tardir_t *t;
  463.   tf = checktarfile(f);
  464.   if(!tf)
  465.     return -1;
  466.   get_local(f,path,local,sizeof(local));
  467.   t = tarfile_gettardir(tf,NULL,local);
  468.   if(!t) {
  469.     closetarfile(f);
  470.     errno = ENOENT;
  471.     return -1;
  472.   }
  473.   if(!strcmp(local,"/")) {
  474.     memcpy(sbuf,&tf->tf_stat,sizeof(struct stat));
  475.     sbuf->st_mode = t->t_mode;
  476.   } else {
  477.     bzero(sbuf,sizeof(struct stat));
  478.     sbuf->st_ino = (ino_t)t;
  479.     sbuf->st_mode = t->t_mode;
  480.     sbuf->st_nlink = 1;
  481.     sbuf->st_uid = t->t_uid;
  482.     sbuf->st_gid = t->t_gid;
  483.     sbuf->st_size = t->t_size;
  484.     sbuf->st_atime = sbuf->st_mtime = sbuf->st_ctime = t->t_mtime;
  485.     if(S_ISREG(t->t_mode)) {
  486.       sbuf->st_blksize = 512;
  487.       sbuf->st_blocks = t->t_size / 512;
  488.       if(t->t_size % 512)
  489.         sbuf->st_blocks++;
  490.     }
  491.   }
  492.   closetarfile(f);
  493.   return 0;
  494. }
  495. static int tar_stat(fsdir_t *f, const char *path, struct stat *sbuf)
  496. {
  497.   if(tar_lstat(f,path,sbuf) == -1)
  498.     return -1;
  499.   if(S_ISLNK(sbuf->st_mode)) {
  500.     char linkbuf[MAXPATHLEN];
  501.     if(tar_readlink(f,path,linkbuf,sizeof(linkbuf)) == -1)
  502.       return -1;
  503.     return fs_stat(linkbuf,sbuf);
  504.   }
  505.   return 0;
  506. }
  507. static int tar_close(fsdir_t *f, int fd)
  508. {
  509.   tarfile_t *tf;
  510.   tf = checktarfile(f);
  511.   if(!tf)
  512.     return -1;
  513.   if(!open_files[fd]) {
  514.     errno = EBADF;
  515.     return -1;
  516.   }
  517.   free(open_files[fd]);
  518.   open_files[fd] = NULL;
  519.   while(of_marker && !open_files[of_marker])
  520.     of_marker--;
  521.   if(!of_marker) {
  522.     tf->fd_open = -1;
  523.     closetarfile(f);
  524.   }
  525.   return 0;
  526. }
  527. static int tar_open(fsdir_t *f, const char *path, int access)
  528. {
  529.   tarinternal_t *ti;
  530.   tarfile_t *tf;
  531.   tardir_t *t;
  532.   tf = checktarfile(f);
  533.   if(!tf)
  534.     return -1;
  535.   get_local(f,path,local,sizeof(local));
  536.   t = tarfile_gettardir(tf,NULL,local);
  537.   if(!t) {
  538.     closetarfile(f);
  539.     errno = ENOENT;
  540.     return -1;
  541.   }
  542.   if(!S_ISREG(t->t_mode)) {
  543.     closetarfile(f);
  544.     errno = EACCES;
  545.     return -1;
  546.   }
  547.   if(session.uid == t->t_uid) {
  548.     if((t->t_mode & S_IRUSR) == 0) {
  549.       closetarfile(f);
  550.       errno = EACCES;
  551.       return -1;
  552.     }
  553.   } else if(session.gid == t->t_gid) {
  554.     if((t->t_mode & S_IRGRP) == 0) {
  555.       closetarfile(f);
  556.       errno = EACCES;
  557.       return -1;
  558.     }
  559.   } else {
  560.     if((t->t_mode & S_IROTH) == 0) {
  561.       closetarfile(f);
  562.       errno = EACCES;
  563.       return -1;
  564.     }
  565.   }
  566.   
  567.   if(of_marker == MAX_OPEN_INTERNAL_FILES) {
  568.     closetarfile(f);
  569.     errno = ENFILE;
  570.     return -1;
  571.   }
  572.   ti = open_files[of_marker++] = malloc(sizeof(tarinternal_t));
  573.   if(!ti) {
  574.     closetarfile(f);
  575.     errno = ENOMEM;
  576.     return -1;
  577.   }
  578.   ti->pos = ti->offset = t->i.offset;
  579.   ti->size = t->t_size;
  580.   if(f->parent->lseek(f->parent,tf->fd,ti->pos,SEEK_SET) == -1) {
  581.     int hold_errno = errno;
  582.     closetarfile(f);
  583.     return -1;
  584.   }
  585.   tf->fd_open = tf->fd;
  586.   return of_marker-1;
  587. }
  588. static int tar_write(fsdir_t *f, int fd, const char *buf, size_t size)
  589. {
  590.   errno = EACCES;
  591.   return -1;
  592. }
  593.   
  594. static int tar_read(fsdir_t *f, int fd, char *buf, size_t size)
  595. {
  596.   tarinternal_t *ti;
  597.   tarfile_t *tf;
  598.   int bread;
  599.   tf = checktarfile(f);
  600.   if(!tf)
  601.     return -1;
  602.   if(fd < 0 || fd >= MAX_OPEN_INTERNAL_FILES || (ti = open_files[fd]) == NULL) {
  603.     closetarfile(f);
  604.     errno = EBADF;
  605.     return -1;
  606.   }
  607.   
  608.   if(ti->pos >= (ti->offset + ti->size))
  609.     return 0;
  610.   if((ti->pos - ti->offset) + size >= ti->size)
  611.     size = ti->size - (ti->pos - ti->offset);
  612.   if(tf->pos != ti->pos) {
  613.     if(f->parent->lseek(f->parent,tf->fd,ti->pos,SEEK_SET) == -1)
  614.       return -1;
  615.     tf->pos = ti->pos;
  616.   }
  617.   
  618.   bread = f->parent->read(f->parent,tf->fd,buf,size);
  619.   if(bread <= 0)
  620.     return bread;
  621.   tf->pos += bread;
  622.   ti->pos += bread;
  623.   return bread;
  624. }
  625. static off_t tar_lseek(fsdir_t *f, int fd, off_t offset, int whence)
  626. {
  627.   tarinternal_t *ti;
  628.   tarfile_t *tf;
  629.   tf = checktarfile(f);
  630.   if(!tf)
  631.     return -1;
  632.   if(fd < 0 || fd >= MAX_OPEN_INTERNAL_FILES || (ti = open_files[fd]) == NULL) {
  633.     closetarfile(f);
  634.     errno = EBADF;
  635.     return -1;
  636.   }
  637.   switch(whence) {
  638.   case SEEK_CUR:
  639.     offset += (ti->pos - ti->offset);
  640.     break;
  641.   case SEEK_END:
  642.     offset += ti->size;
  643.     break;
  644.   }
  645.   if(offset < 0)
  646.     offset = 0;
  647.   if(offset > ti->size)
  648.     offset = ti->size;
  649.   ti->pos = ti->offset + offset;
  650.   return offset;
  651. }
  652. static void *tar_opendir(fsdir_t *f, const char *path)
  653. {
  654.   tarfile_t *tf;
  655.   tardir_t *t,**cursor;
  656.   tf = checktarfile(f);
  657.   if(!tf)
  658.     return NULL;
  659.   get_local(f,path,local,sizeof(local));
  660.   t = tarfile_gettardir(tf,NULL,local);
  661.   if(!t) {
  662.     closetarfile(f);
  663.     errno = ENOENT;
  664.     return NULL;
  665.   }
  666.   if(!S_ISDIR(t->t_mode)) {
  667.     closetarfile(f);
  668.     errno = ENOTDIR;
  669.     return NULL;
  670.   }
  671.   cursor = malloc(sizeof(tardir_t*));
  672.   *cursor = t->i.directory;
  673.   return cursor;
  674. }
  675.  
  676. static struct dirent *tar_readdir(fsdir_t *f, void *_dir)
  677. {
  678.   tardir_t *t,**cursor = (tardir_t**)_dir;
  679.   char tmpbuf[MAXPATHLEN],*cp;
  680.   static struct dirent dir;
  681.   if(!cursor || !*cursor)
  682.     return NULL;
  683.   t = *cursor;
  684.   dir.d_ino = (long)t;
  685.   dir.d_off = 0;
  686.   dir.d_reclen = sizeof(struct dirent);
  687.   dir.d_type = 0;
  688.   
  689.   sstrncpy(tmpbuf,t->t_path,sizeof(tmpbuf));
  690.   if((cp = rindex(tmpbuf,'/')) != NULL)
  691.     *cp++ = '';
  692.   else
  693.     cp = tmpbuf;
  694.   sstrncpy(dir.d_name,cp,NAME_MAX);
  695.   *cursor = t->next;
  696.   return &dir;
  697. }  
  698. static int tar_closedir(fsdir_t *f, void *_dir)
  699. {
  700.   tardir_t **cursor = (tardir_t**)_dir;
  701.   if(cursor)
  702.     free(cursor);
  703.   closetarfile(f);
  704.   return 0;
  705. }
  706.   
  707. static int tar_hit(fsdir_t *f, const char *path, int op)
  708. {
  709.   fsdir_t *newfs;
  710.   struct stat sbuf;
  711.   char buf[MAXPATHLEN];
  712. #if 0
  713.   if(op == FSOP_OPEN) {
  714. #endif
  715.     if(f->stat(f,path,&sbuf) == -1)
  716.       return -1;
  717.     if(!S_ISREG(sbuf.st_mode))
  718.       return 0;
  719.     fs_resolve_path(path,buf,sizeof(buf),0);
  720.     newfs = fs_register(buf);
  721.     newfs->chdir = &tar_chdir;
  722.     newfs->lstat = &tar_lstat;
  723.     newfs->stat = &tar_stat;
  724.     newfs->readlink = &tar_readlink;
  725.     newfs->open = &tar_open;
  726.     newfs->close = &tar_close;
  727.     newfs->read = &tar_read;
  728.     newfs->write = &tar_write;
  729.     newfs->lseek = &tar_lseek;
  730.     newfs->opendir = &tar_opendir;
  731.     newfs->readdir = &tar_readdir;
  732.     newfs->closedir = &tar_closedir;
  733. #if 0
  734.     newfs->open = &html_open;
  735.     newfs->close = &html_close;
  736.     newfs->read = &html_read;
  737.     newfs->write = &html_write;
  738. #endif
  739.     return 1;
  740. #if 0
  741.   }
  742. #endif
  743.   return 0;
  744. }
  745. static int tar_init()
  746. {
  747.   fsmatch_t *fm;
  748.   bzero(open_files,sizeof(open_files));
  749.   fm = fs_register_match("*.tar",0xffffffff);
  750.   fm->dir_hit = fm->file_hit = tar_hit;
  751.   return 0;
  752. }
  753. module tar_module = {
  754.   NULL,NULL,
  755.   0x20,
  756.   "tar",
  757.   NULL,
  758.   NULL,
  759.   NULL,
  760.   tar_init,NULL
  761. };