|
|
1.1 root 1: #include <stdio.h>
2: #include <string.h>
3: #include <time.h>
4: #include <sys/types.h>
5: #include <sys/stat.h>
6: #include <fcntl.h>
7: #include <unistd.h>
8: #include <utime.h>
9: #include <libv.h>
10: #include "tar.h"
11: #include "misc.h"
12:
13: #ifndef S_ISDIR
14: #define S_ISDIR(M) (((M) & S_IFMT) == S_IFDIR)
15: #endif
16:
17: #define MIN(A, B) ((A) < (B) ? (A) : (B))
18:
19: int fflag;
20: int tflag;
21: int vflag;
22:
23: int nerr;
24:
25: struct chtmug {
26: char *path;
27: time_t mtime;
28: int mode;
29: int uid;
30: int gid;
31: struct chtmug *next;
32: };
33:
34: struct chtmug *chtmuglist;
35:
36: void
37: chtmug(char *path, time_t mtime, int mode, int uid, int gid)
38: {
39: struct utimbuf ut;
40:
41: time(&ut.actime);
42: ut.modtime = mtime;
43: utime(path, &ut);
44: chmod(path, mode);
45: chown(path, uid, gid);
46: chmod(path, mode); /* fix possibly cleared s[ug]id bits */
47: }
48:
49: void
50: chtmugs(void)
51: {
52: struct chtmug *ch;
53:
54: /* we handle the chtmug list in the reverse order of which it
55: was built, which is just right for nested directories created
56: from tar files */
57: for (ch = chtmuglist; ch; ch = ch->next)
58: chtmug(ch->path, ch->mtime, ch->mode, ch->uid, ch->gid);
59: }
60:
61: void
62: mkchtmug(char *path, time_t mtime, int mode, int uid, int gid)
63: {
64: struct chtmug *ch;
65:
66: ch = xmalloc(sizeof (struct chtmug));
67: ch->path = xstrdup(path);
68: ch->mtime = mtime;
69: ch->mode = mode;
70: ch->uid = uid;
71: ch->gid = gid;
72: ch->next = chtmuglist;
73: chtmuglist= ch;
74: }
75:
76: void
77: mkdirs(char *path)
78: {
79: char *slash;
80:
81: slash = strrchr(path, '/');
82: if (slash == path)
83: return;
84: if (slash) {
85: *slash = '\0';
86: if (access(path, F_OK) != 0) {
87: mkdirs(path);
88: mkdir(path, 0777);
89: }
90: *slash = '/';
91: }
92: }
93:
94: int
95: isdir(char *path)
96: {
97: struct stat st;
98:
99: if (stat(path, &st) == 0)
100: return S_ISDIR(st.st_mode);
101: return 0;
102: }
103:
104: int
105: extract(FILE *ifp)
106: {
107: struct tarbuf buf;
108: struct tarhdr hdr;
109: int fd, blocks;
110: FILE *ofp;
111: static char zeroes[TSIZE];
112:
113: if (fread(&buf, sizeof buf, 1, ifp) != 1)
114: return 0;
115: if (memcmp(&buf, zeroes, sizeof zeroes) == 0)
116: return 0;
117: if (thdrget(&hdr, &buf) != 0) {
118: ++nerr;
119: fprintf(stderr, "tarx: bad input header\n");
120: return 0;
121: }
122: if (tflag)
123: printf("%s\n", hdr.name);
124: if (vflag)
125: fprintf(stderr, "%s\n", hdr.name);
126: mkdirs(hdr.name);
127: switch (hdr.typeflag) {
128: case REGTYPE:
129: blocks = (hdr.size + TSIZE - 1) / TSIZE;
130: fd = creat(hdr.name, hdr.mode);
131: if (fd < 0) {
132: remove(hdr.name);
133: fd = creat(hdr.name, hdr.mode);
134: if (fd < 0) {
135: ++nerr;
136: fprintf(stderr, "tarx: can't create '%s'\n",
137: hdr.name);
138: discard(ifp, blocks * TSIZE);
139: return 1;
140: }
141: }
142: ofp = fdopen(fd, "w");
143: fpcopy(ofp, ifp, hdr.size);
144: fclose(ofp);
145: close(fd); /* paranoia */
146: discard(ifp, blocks * TSIZE - hdr.size);
147: chtmug(hdr.name, hdr.mtime, hdr.mode, hdr.uid, hdr.gid);
148: break;
149:
150: case DIRTYPE:
151: mkchtmug(hdr.name, hdr.mtime, hdr.mode, hdr.uid, hdr.gid);
152: if (!isdir(hdr.name)) {
153: remove(hdr.name);
154: if (mkdir(hdr.name, hdr.mode) < 0) {
155: ++nerr;
156: fprintf(stderr, "tarx: can't mkdir '%s'\n",
157: hdr.name);
158: return 1;
159: }
160: }
161: break;
162:
163: case LNKTYPE:
164: remove(hdr.name);
165: if (link(hdr.linkname, hdr.name) < 0) {
166: ++nerr;
167: fprintf(stderr, "tarx: can't link '%s' to '%s'\n",
168: hdr.linkname, hdr.name);
169: return 1;
170: }
171: break;
172:
173: case SYMTYPE:
174: remove(hdr.name);
175: if (symlink(hdr.linkname, hdr.name) < 0) {
176: ++nerr;
177: fprintf(stderr, "tarx: can't symlink '%s' to '%s'\n",
178: hdr.linkname, hdr.name);
179: return 1;
180: }
181: break;
182:
183: default:
184: fprintf(stderr, "tarx: unknown typeflag '%c'\n", hdr.typeflag);
185: return 1;
186: }
187: return 1;
188: }
189:
190: void
191: usage(void)
192: {
193: fprintf(stderr, "usage: tarx [-ftv]\n");
194: exit(1);
195: }
196:
197: int
198: main(int argc, char *argv[])
199: {
200: int c, i;
201: prog = argv[0];
202:
203: while ((c = getopt(argc, argv, "ftv")) != EOF)
204: switch (c) {
205: case 'f':
206: ++fflag;
207: break;
208: case 't':
209: ++tflag;
210: break;
211: case 'v':
212: ++vflag;
213: break;
214: default:
215: usage();
216: break;
217: }
218: if (optind != argc)
219: usage();
220: if (fflag) {
221: setbuf(stdin, NULL);
222: extract(stdin);
223: } else
224: while (extract(stdin))
225: ;
226: chtmugs();
227: if (ferror(stdin))
228: return 1;
229: return nerr ? 1 : 0;
230: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.