sltar.c (4274B)
1 /* sltar - suckless tar 2 * Copyright (C) <2007> Enno boland <g s01 de> 3 * 4 * See LICENSE for further informations 5 */ 6 #include <stdlib.h> 7 #include <unistd.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <sys/stat.h> 11 #include <sys/types.h> 12 #include <limits.h> 13 #include <ftw.h> 14 #include <grp.h> 15 #include <pwd.h> 16 17 #define MIN(a, b) (((a)<(b))?(a):(b)) 18 19 enum Header { 20 NAME=0, MODE = 100, UID = 108, GID = 116, SIZE = 124, MTIME = 136, CHKSUM=148, 21 TYPE = 156, LINK = 157, MAGIC=257, VERS=263, UNAME=265, GNAME=297, MAJ = 329, 22 MIN = 337, END = 512 23 }; 24 25 enum Type { 26 REG = '0', HARDLINK = '1', SYMLINK = '2', CHARDEV='3', BLOCKDEV='4', 27 DIRECTORY='5', FIFO='6' 28 }; 29 30 int archive(const char* path, const struct stat* sta, int type){ 31 char b[END]; 32 FILE *f = NULL; 33 struct stat s = *sta, *st = &s; 34 lstat(path, st); 35 memset(b, 0, END); 36 snprintf(b+NAME, 100, "%s", path); 37 snprintf(b+MODE, 8, "%.7o", (unsigned)st->st_mode&0777); 38 snprintf(b+UID, 8, "%.7o", (unsigned)st->st_uid); 39 snprintf(b+GID, 8, "%.7o", (unsigned)st->st_gid); 40 snprintf(b+SIZE, 12, "%.11o", 0); 41 snprintf(b+MTIME,12, "%.11o", (unsigned)st->st_mtime); 42 memcpy(b+MAGIC, "ustar", strlen("ustar")+1); 43 memcpy(b+VERS, "00", strlen("00")); 44 struct passwd *pw = getpwuid(st->st_uid); 45 snprintf(b+UNAME, 32, "%s", pw->pw_name); 46 struct group *gr = getgrgid(st->st_gid); 47 snprintf(b+GNAME, 32, "%s", gr->gr_name); 48 mode_t mode = st->st_mode; 49 if(S_ISREG(mode)){ 50 b[TYPE] = REG; 51 snprintf(b+SIZE, 12, "%.11o", (unsigned)st->st_size); 52 f = fopen(path, "r"); 53 }else if(S_ISDIR(mode)){ 54 b[TYPE] = DIRECTORY; 55 }else if(S_ISLNK(mode)){ 56 b[TYPE] = SYMLINK; 57 readlink(path, b+LINK, 99); 58 }else if(S_ISCHR(mode)){ 59 b[TYPE] = CHARDEV; 60 snprintf(b+MAJ, 8, "%.7o", (unsigned)major(st->st_dev)); 61 snprintf(b+MIN, 8, "%.7o", (unsigned)minor(st->st_dev)); 62 }else if(S_ISBLK(mode)){ 63 b[TYPE] = BLOCKDEV; 64 snprintf(b+MAJ, 8, "%.7o", (unsigned)major(st->st_dev)); 65 snprintf(b+MIN, 8, "%.7o", (unsigned)minor(st->st_dev)); 66 }else if(S_ISFIFO(mode)){ 67 b[TYPE] = FIFO; 68 } 69 unsigned sum=0, x; 70 memset(b+CHKSUM, ' ', 8); 71 for(x=0; x<END; x++) 72 sum+=b[x]; 73 snprintf(b+CHKSUM, 8, "%.7o", sum); 74 fwrite(b, END, 1, stdout); 75 if(!f) 76 return 0; 77 int l; 78 while((l = fread(b, 1, END, f))>0){ 79 if(l<END) 80 memset(b+l, 0, END-l); 81 fwrite(b, END, 1, stdout); 82 } 83 fclose(f); 84 return 0; 85 } 86 87 int unarchive(char *fname, int l, char b[END]){ 88 static char lname[101] = {0}; 89 FILE *f = NULL; 90 memcpy(lname, b+LINK, 100); 91 92 unlink(fname); 93 switch(b[TYPE]) { 94 case REG: 95 if(!(f = fopen(fname,"w")) || chmod(fname,strtoul(b + MODE,0,8))) 96 perror(fname); 97 break; 98 case HARDLINK: 99 if(!link(lname,fname)) 100 perror(fname); 101 break; 102 case SYMLINK: 103 if(!symlink(lname,fname)) 104 perror(fname); 105 break; 106 case DIRECTORY: 107 if(mkdir(fname,(mode_t) strtoull(b + MODE,0,8))) 108 perror(fname); 109 break; 110 case CHARDEV: 111 case BLOCKDEV: 112 if(mknod(fname, (b[TYPE] == '3' ? S_IFCHR : S_IFBLK) | strtoul(b + MODE,0,8), 113 makedev(strtoul(b + MAJ,0,8), 114 strtoul(b + MIN,0,8)))) 115 perror(fname); 116 break; 117 case FIFO: 118 if(mknod(fname, S_IFIFO | strtoul(b + MODE,0,8), 0)) 119 perror(fname); 120 break; 121 default: 122 fprintf(stderr,"not supported filetype %c\n",b[TYPE]); 123 } 124 if(getuid() == 0 && chown(fname, strtoul(b + UID,0,8),strtoul(b + GID,0,8))) 125 perror(fname); 126 127 for(;l>0; l-=END){ 128 fread(b, END, 1, stdin); 129 if(f) 130 fwrite(b, MIN(l, 512), 1, f); 131 } 132 if(f) 133 fclose(f); 134 return 0; 135 } 136 137 int print(char * fname, int l, char b[END]){ 138 puts(fname); 139 for(;l>0; l-=END) 140 fread(b, END, 1, stdin); 141 return 0; 142 } 143 144 int c(char * dir) { 145 ftw(dir, archive, 128);//OPEN_MAX); 146 return EXIT_SUCCESS; 147 } 148 149 int xt(int (*fn)(char*, int, char[END])) { 150 int l; 151 char b[END],fname[101]; 152 fname[100] = '\0'; 153 154 while(fread(b, END, 1, stdin)){ 155 if(*b == '\0') 156 break; 157 memcpy(fname, b, 100); 158 l = strtol(b+SIZE, 0, 8); 159 fn(fname, l, b); 160 } 161 return EXIT_SUCCESS; 162 } 163 164 void usage(){ 165 fputs("sltar-" VERSION " - suckless tar\nsltar [ctx]\n",stderr); 166 exit(EXIT_SUCCESS); 167 } 168 169 int main(int argc, char *argv[]) { 170 if(argc < 2 || argc > 3 || strlen(argv[1])!=1) 171 usage(); 172 switch(argv[1][0]) { 173 case 'c': 174 if(argc<3) 175 usage(); 176 return c(argv[2]); 177 case 'x': 178 return xt(unarchive); 179 case 't': 180 return xt(print); 181 default: 182 usage(); 183 } 184 return EXIT_FAILURE; 185 }