/* jtar.c : Jon's Tar */ /* Copyright 2001 Jon Mayo * Updated May 14, 2008 - Jon Mayo */ #include #include #include #include #include #include #define RECORD_LEN 512 #define NAME_LEN 100 #define USER_LEN 32 #define GROUP_LEN 32 #define MAGIC_TAR "ustar " #define MAGIC_GNUTAR "GNUtar " struct record { char name[NAME_LEN+1]; uint32_t mode; uint32_t uid; uint32_t gid; uint64_t size; time_t mtime; uint32_t chksum; char linkflag; char linkname[NAME_LEN+1]; /* char magic[8]; */ char uname[USER_LEN+1]; char gname[GROUP_LEN+1]; uint32_t devmajor; uint32_t devminor; }; /* make room to null terminate everything */ struct record_str { char name[NAME_LEN+1]; char mode[8+1]; char uid[8+1]; char gid[8+1]; char size[12+1]; char mtime[12+1]; char chksum[8+1]; char linkflag; char linkname[NAME_LEN+1]; char magic[8+1]; char uname[USER_LEN+1]; char gname[GROUP_LEN+1]; char devmajor[8+1]; char devminor[8+1]; }; /* loads data. * dest destination pointer to record * src source pointer from buffer * len length to read * ofs current offset. gets incremented * term NULL terminate the field after len */ /* TODO: handle legths and things */ void ldata(void *dest, const void *src, int len, int *ofs, int term) { memcpy(dest,(char*)src+*ofs,len); if(term) ((char*)dest)[len]=0; (*ofs)+=len; } const char *type2str(char linktype) { const char *ret; switch(linktype) { case '\0': ret="file-old"; break; case '0': ret="file"; break; case '1': ret="link"; break; /* link to previously dumped file */ case '2': ret="symlink"; break; /* symbolic link */ case '3': ret="dev-char"; break; /* character device */ case '4': ret="dev-block"; break; /* block device */ case '5': ret="directory"; break; /* directory */ case '6': ret="fifo"; break; /* fifo */ case '7': ret="file-contiguous"; break; /* contiguous file */ default: ret="unknown"; } return ret; } int convrec(struct record *r, const struct record_str *s) { if(strcmp(s->magic,MAGIC_TAR) && strcmp(s->magic,MAGIC_GNUTAR)) { return 0; } strcpy(r->name,s->name); r->mode=strtoul(s->mode,NULL,8); r->uid=strtoul(s->uid,NULL,8); r->gid=strtoul(s->gid,NULL,8); r->size=strtoul(s->size,NULL,8); r->mtime=strtoul(s->mtime,NULL,8); r->chksum=strtoul(s->chksum,NULL,8); r->linkflag=s->linkflag; strcpy(r->linkname,s->linkname); strcpy(r->uname,s->uname); strcpy(r->gname,s->gname); r->devmajor=strtoul(s->devmajor,NULL,8); r->devminor=strtoul(s->devminor,NULL,8); return 1; } void fillrec(struct record_str *r, const char *buf) { int i; i=0; ldata(&r->name,buf,NAME_LEN,&i,1); ldata(&r->mode,buf,8,&i,1); ldata(&r->uid,buf,8,&i,1); ldata(&r->gid,buf,8,&i,1); ldata(&r->size,buf,12,&i,1); ldata(&r->mtime,buf,12,&i,1); ldata(&r->chksum,buf,8,&i,1); ldata(&r->linkflag,buf,1,&i,0); ldata(&r->linkname,buf,NAME_LEN,&i,1); ldata(&r->magic,buf,8,&i,1); ldata(&r->uname,buf,USER_LEN,&i,1); ldata(&r->gname,buf,GROUP_LEN,&i,1); ldata(&r->devmajor,buf,8,&i,1); ldata(&r->devminor,buf,8,&i,1); } void dumprec(struct record *r) { struct tm *tm; char timebuf[32]; tm=gmtime(&r->mtime); strftime(timebuf,sizeof timebuf,"%c",tm); printf( "name :%s\n" "mode :%" PRIo32 "\n" "uid :%" PRIu32 "\n" "gid :%" PRIu32 "\n" "size :%" PRIu64 "\n" "mtime :%s\n" "chksum :%" PRIu32 "\n" "linkflag :(%s)\n" "linkname :%s\n" /* "magic :%s\n" */ "uname :%s\n" "gname :%s\n" "devmajor :%" PRIu32 "\n" "devminor :%" PRIu32 "\n" "-----------:------------------------------------------------------------------\n", r->name, r->mode, r->uid, r->gid, r->size, timebuf, r->chksum, type2str(r->linkflag), r->linkname, /* r->magic, */ r->uname, r->gname, r->devmajor, r->devminor ); } int procdata(FILE *in, struct record *r) { char buf[RECORD_LEN]; int cnt; /* number of blocks. assume we're padded */ int i; /* Eats the Data */ cnt=(r->size+RECORD_LEN-1)/RECORD_LEN; for(i=0;i