2 * Copyright (c) 1993 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
6 * The "tar" built-in command.
12 #include <sys/types.h>
33 char linkname
[NAMSIZ
];
42 static BOOL badheader
;
44 static BOOL extracting
;
45 static BOOL warnedroot
;
50 static char outname
[NAMSIZ
];
52 static void doheader();
54 static void createpath();
55 static long getoctal();
75 fprintf(stderr
, "Too few arguments for tar\n");
92 blocksize
= sizeof(buf
);
94 for (str
= argv
[1]; *str
; str
++) {
96 case 'f': fileflag
= TRUE
; break;
97 case 't': listflag
= TRUE
; break;
98 case 'x': extracting
= TRUE
; break;
99 case 'v': verbose
= TRUE
; break;
103 fprintf(stderr
, "Writing is not supported\n");
107 fprintf(stderr
, "Unknown tar flag\n");
113 fprintf(stderr
, "The 'f' flag must be specified\n");
118 fprintf(stderr
, "Missing input name\n");
123 if (extracting
+ listflag
!= 1) {
124 fprintf(stderr
, "Exactly one of 'x' or 't' must be specified\n");
128 devfd
= open(devname
, 0);
135 if ((incc
== 0) && !eof
) {
136 while (incc
< blocksize
) {
137 cc
= read(devfd
, &buf
[incc
], blocksize
- incc
);
152 if (extracting
&& (outfd
>= 0))
159 if ((incc
== 0) || eof
)
163 fprintf(stderr
, "Short block for header\n");
167 doheader((struct header
*) cp
);
182 cc
+= TBLOCK
- (cc
% TBLOCK
);
209 * If the block is completely empty, then this is the end of the
210 * archive file. If the name is null, then just skip this header.
214 for (cc
= TBLOCK
; cc
> 0; cc
--) {
223 mode
= getoctal(hp
->mode
, sizeof(hp
->mode
));
224 uid
= getoctal(hp
->uid
, sizeof(hp
->uid
));
225 gid
= getoctal(hp
->gid
, sizeof(hp
->gid
));
226 size
= getoctal(hp
->size
, sizeof(hp
->size
));
227 mtime
= getoctal(hp
->mtime
, sizeof(hp
->mtime
));
228 chksum
= getoctal(hp
->chksum
, sizeof(hp
->chksum
));
230 if ((mode
< 0) || (uid
< 0) || (gid
< 0) || (size
< 0)) {
232 fprintf(stderr
, "Bad tar header, skipping\n");
240 hardlink
= ((hp
->linkflag
== 1) || (hp
->linkflag
== '1'));
241 softlink
= ((hp
->linkflag
== 2) || (hp
->linkflag
== '2'));
243 if (name
[strlen(name
) - 1] == '/')
245 else if ((mode
& S_IFMT
) == 0)
253 fprintf(stderr
, "Absolute paths detected, removing leading slashes\n");
259 printf("%s %3d/%-d %9d %s %s", modestring(mode
),
260 uid
, gid
, size
, timestring(mtime
), name
);
265 printf(" (link to \"%s\")", hp
->linkname
);
267 printf(" (symlink to \"%s\")", hp
->linkname
);
268 else if (S_ISREG(mode
)) {
269 inheader
= (size
== 0);
278 printf("x %s\n", name
);
282 if (link(hp
->linkname
, name
) < 0)
289 if (symlink(hp
->linkname
, name
) < 0)
292 fprintf(stderr
, "Cannot create symbolic links\n");
298 createpath(name
, mode
);
302 createpath(name
, 0777);
304 inheader
= (size
== 0);
307 outfd
= creat(name
, mode
);
323 * Handle a data block of some specified size.
335 if (badwrite
|| !extracting
)
339 cc
= write(outfd
, cp
, count
);
359 * Attempt to create the directories along the specified path, except for
360 * the final component. The mode is given for the final directory only,
361 * while all previous ones get default protections. Errors are not reported
362 * here, as failures to restore files can be reported later.
365 createpath(name
, mode
)
374 cp
= strchr(buf
, '/');
378 cp
= strchr(cp
+ 1, '/');
381 if (mkdir(buf
, cp
? 0777 : mode
) == 0)
382 printf("Directory \"%s\" created\n", buf
);
390 * Read an octal value in a field of the specified width, with optional
391 * spaces on both sides of the number and with an optional null character
392 * at the end. Returns -1 on an illegal format.
400 while ((len
> 0) && (*cp
== ' ')) {
405 if ((len
== 0) || !isoctal(*cp
))
409 while ((len
> 0) && isoctal(*cp
)) {
410 val
= val
* 8 + *cp
++ - '0';
414 while ((len
> 0) && (*cp
== ' ')) {
419 if ((len
> 0) && *cp
)