Back to index

avfs  1.0.1
uar.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 1998  Miklos Szeredi <miklos@szeredi.hu>
00004     
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 
00008     AR module
00009 */
00010 
00011 #include "archive.h"
00012 #include "oper.h"
00013 #include "version.h"
00014 
00015 #define ARMAGIC     "!<arch>\n"
00016 #define ARMAGICLEN  8
00017 #define ENDMAGIC    "`\n"
00018 
00019 struct ar_header {
00020     char name[16];
00021     char date[12];
00022     char uid[6];
00023     char gid[6];
00024     char mode[8];
00025     char size[10];
00026     char endmagic[2];
00027 };
00028 
00029 struct ar_values {
00030     avtime_t mtime;
00031     avuid_t  uid;
00032     avgid_t  gid;
00033     avmode_t mode;
00034     avsize_t size;
00035     avoff_t offset;
00036 };
00037 
00038 struct ar_nametab {
00039     char *names;
00040     avsize_t size;
00041 };
00042 
00043 static void fill_arentry(struct archive *arch, struct entry *ent,
00044                          struct ar_values *arv)
00045 {
00046     struct archnode *nod;
00047 
00048     nod = av_arch_new_node(arch, ent, 0);
00049     
00050     nod->offset = arv->offset;
00051     nod->realsize = arv->size;
00052 
00053     nod->st.mode       = arv->mode;
00054     nod->st.uid        = arv->uid;
00055     nod->st.gid        = arv->gid;
00056     nod->st.blocks     = AV_BLOCKS(arv->size);
00057     nod->st.blksize    = 1024;
00058     nod->st.mtime.sec  = arv->mtime;
00059     nod->st.mtime.nsec = 0;
00060     nod->st.atime      = nod->st.mtime;
00061     nod->st.ctime      = nod->st.mtime;
00062     nod->st.size       = arv->size;
00063 }
00064 
00065 static void insert_arentry(struct archive *arch, struct ar_values *arv,
00066                            const char *name)
00067 {
00068     struct entry *ent;
00069 
00070     if(!name[0]) {
00071         av_log(AVLOG_WARNING, "AR: Empty name");
00072         return;
00073     }
00074     if((arv->mode & AV_IFMT) == 0) {
00075         av_log(AVLOG_WARNING, "AR: Illegal type");
00076         return;
00077     }
00078         
00079     ent = av_arch_create(arch, name, 0);
00080     if(ent == NULL)
00081         return;
00082 
00083     fill_arentry(arch, ent, arv);
00084     av_unref_obj(ent);
00085 }
00086 
00087 static avulong getnum(const char *s, int len, int base)
00088 {
00089     avulong num;
00090     int i;
00091   
00092     num = 0;
00093     for(i = 0; i < len; i++) {
00094         if(s[i] >= '0' && s[i] < '0' + base) num = (num * base) + (s[i] - '0');
00095         else break;
00096     }
00097   
00098     return num;
00099 }
00100 
00101 static int interpret_header(struct ar_header *hbuf, struct ar_values *arv)
00102 {
00103     if(strncmp(hbuf->endmagic, ENDMAGIC, 2) != 0)
00104         return -1;
00105 
00106     arv->mtime = getnum(hbuf->date, 12, 10);
00107     arv->uid   = getnum(hbuf->uid,  6,  10);
00108     arv->gid   = getnum(hbuf->gid,  6,  10);
00109     arv->mode  = getnum(hbuf->mode, 8,  8);
00110     arv->size  = getnum(hbuf->size, 10, 10);
00111 
00112     return 0;
00113 }
00114 
00115 static int read_longnames(vfile *vf, struct ar_values *arv,
00116                           struct ar_nametab *nt)
00117 {
00118     avssize_t rres;
00119     avsize_t i;
00120     
00121     if(nt->names != NULL) {
00122         av_log(AVLOG_WARNING, "AR: Multiple name tables");
00123         return 1;
00124     }
00125     
00126     if(arv->size == 0)
00127         return 1;
00128 
00129     if(arv->size >= (1 << 22)) {
00130         av_log(AVLOG_WARNING, "AR: name table too long");
00131         return 1;
00132     }
00133 
00134     nt->size = arv->size;
00135     nt->names = av_malloc(nt->size);
00136     
00137     rres = av_read(vf, nt->names, nt->size);
00138     if(rres < 0)
00139         return rres;
00140         
00141     if(rres != nt->size) {
00142         av_log(AVLOG_WARNING, "AR: Broken archive");
00143         return 0;
00144     }
00145 
00146     for(i = 0; i < nt->size; i++)
00147         if(nt->names[i] == '/' || nt->names[i] == '\\' || nt->names[i] == '\n')
00148             nt->names[i] = '\0';
00149 
00150     nt->names[nt->size - 1] = '\0';
00151     
00152     return 1;
00153 }
00154                          
00155 static int read_bsd_longname(vfile *vf, struct archive *arch,
00156                              struct ar_values *arv, char *shortname)
00157 {
00158     avssize_t rres;
00159     avsize_t namelen;
00160     char *name;
00161     
00162     namelen = getnum(shortname + 3, 13, 10);
00163 
00164     name = av_malloc(namelen + 1);
00165     rres = av_read(vf, name, namelen);
00166     if(rres == namelen) {
00167         arv->size -= namelen;
00168         arv->offset += namelen;
00169 
00170         insert_arentry(arch, arv, name);
00171         av_free(name);
00172         return 1;
00173     }
00174 
00175     av_free(name);
00176     
00177     if(rres < 0)
00178         return rres;
00179 
00180     av_log(AVLOG_WARNING, "AR: Broken archive");
00181     return 0;
00182 }
00183 
00184 static void insert_longname(struct archive *arch, struct ar_values *arv,
00185                             char *shortname, struct ar_nametab *nt)
00186 {
00187     if(nt->names != NULL) {
00188         avsize_t nameoffs;
00189        
00190         nameoffs = getnum(shortname + 1, 15, 10);
00191         if(nameoffs < nt->size)
00192             insert_arentry(arch, arv, nt->names + nameoffs);
00193         else
00194             av_log(AVLOG_WARNING, "AR: Bad filename table");            
00195     }
00196     else
00197         av_log(AVLOG_WARNING, "AR: Missing filename table");
00198 }
00199 
00200 static void insert_shortname(struct archive *arch, struct ar_values *arv,
00201                              char *name)
00202 {
00203     int i;
00204 
00205     for(i = 0; i < 16; i++) 
00206         if(name[i] == '/') {
00207             name[i] = '\0';
00208             break;
00209         }
00210 
00211     /* If no slash was found, strip spaces from end */
00212     if(i == 16) 
00213         for(i = 15; i >= 0 && name[i] == ' '; i--) name[i] = '\0';
00214     
00215     insert_arentry(arch, arv, name);
00216 }
00217 
00218 static int process_name(vfile *vf, struct archive *arch, struct ar_values *arv,
00219                         char *name, struct ar_nametab *nt)
00220 {
00221     if((strncmp(name, "//              ", 16) == 0 ||
00222         strncmp(name, "ARFILENAMES/    ", 16) == 0))
00223         return read_longnames(vf, arv, nt);
00224 
00225     if(name[0] == '#' && name[1] == '1' && name[2] == '/' &&
00226        name[3] >= '0' && name[3] <= '9') 
00227         return read_bsd_longname(vf, arch, arv, name);
00228 
00229     if((name[0] == '/' || name[0] == ' ') &&
00230        name[1] >= '0' && name[1] <= '9') {
00231         insert_longname(arch, arv, name, nt);
00232         return 1;
00233     }
00234 
00235     if(name[0] == '/' || strncmp(name, "__.SYMDEF       ", 16) == 0)
00236         return 1;
00237 
00238     insert_shortname(arch, arv, name);
00239     return 1;
00240 }
00241 
00242 
00243 static int read_entry(vfile *vf, struct archive *arch, struct ar_nametab *nt)
00244 {
00245     int res;
00246     avssize_t rres;
00247     struct ar_header hbuf;
00248     struct ar_values arv;
00249     avoff_t sres, noff;
00250     
00251     rres = av_read(vf, (char *) &hbuf, sizeof(hbuf));
00252     if(rres <= 0) 
00253         return rres;
00254     
00255     if(rres != sizeof(hbuf)) {
00256         av_log(AVLOG_WARNING, "AR: Broken archive");
00257         return 0;
00258     }
00259 
00260     if(interpret_header(&hbuf, &arv) == -1) {
00261         av_log(AVLOG_WARNING, "AR: Broken archive");
00262         return 0;
00263     }
00264 
00265     arv.offset = vf->ptr;
00266 
00267     res = process_name(vf, arch, &arv, hbuf.name, nt);
00268     if(res <= 0)
00269         return res;
00270 
00271     noff = arv.offset + arv.size;
00272     if((noff & 1) != 0) noff++;
00273     
00274     sres = av_lseek(vf, noff, AVSEEK_SET);
00275     if(sres < 0)
00276         return sres;
00277     
00278     return 1;
00279 }
00280 
00281 
00282 static int read_arfile(vfile *vf, struct archive *arch)
00283 {
00284     int res;
00285     char magic[ARMAGICLEN];
00286     avssize_t rres;
00287     struct ar_nametab nt;
00288   
00289     rres = av_read(vf, magic, ARMAGICLEN);
00290     if(rres < 0) 
00291         return rres;
00292     if(rres != ARMAGICLEN || strncmp(magic, ARMAGIC, ARMAGICLEN) != 0)
00293         return -EIO;
00294   
00295     nt.names = NULL;
00296     nt.size = 0;
00297     do res = read_entry(vf, arch, &nt);
00298     while(res == 1);
00299 
00300     av_free(nt.names);
00301 
00302     return res;
00303 }
00304 
00305 static int parse_arfile(void *data, ventry *ve, struct archive *arch)
00306 {
00307     int res;
00308     vfile *vf;
00309 
00310     res = av_open(ve->mnt->base, AVO_RDONLY, 0, &vf);
00311     if(res < 0)
00312         return res;
00313 
00314     res = read_arfile(vf, arch);
00315     av_close(vf);
00316     
00317     return res;  
00318 }
00319 
00320 int av_init_module_uar(struct vmodule *module);
00321 
00322 int av_init_module_uar(struct vmodule *module)
00323 {
00324     int res;
00325     struct avfs *avfs;
00326     struct ext_info arexts[3];
00327     struct archparams *ap;
00328     
00329     arexts[0].from = ".a",   arexts[0].to = NULL;
00330     arexts[1].from = ".deb", arexts[1].to = NULL;
00331     arexts[2].from = NULL;
00332 
00333     res = av_archive_init("uar", arexts, AV_VER, module, &avfs);
00334     if(res < 0)
00335         return res;
00336     
00337     ap = (struct archparams *) avfs->data;
00338     ap->parse = parse_arfile;
00339 
00340     av_add_avfs(avfs);
00341 
00342     return 0;
00343 }
00344