aboutsummaryrefslogtreecommitdiff
path: root/tar.c
diff options
context:
space:
mode:
authorErik Andersen <andersen@codepoet.org>2000-02-08 19:58:47 +0000
committerErik Andersen <andersen@codepoet.org>2000-02-08 19:58:47 +0000
commite49d5ecbbe51718fa925b6890a735e5937cc2aa2 (patch)
treec90bda10731ad9333ce3b404f993354c9fc104b8 /tar.c
parentc0bf817bbc5c7867fbe8fb76d5c39f8ee802692f (diff)
downloadbusybox-w32-e49d5ecbbe51718fa925b6890a735e5937cc2aa2.tar.gz
busybox-w32-e49d5ecbbe51718fa925b6890a735e5937cc2aa2.tar.bz2
busybox-w32-e49d5ecbbe51718fa925b6890a735e5937cc2aa2.zip
Some formatting updates (ran the code through indent)
-Erik
Diffstat (limited to 'tar.c')
-rw-r--r--tar.c1857
1 files changed, 932 insertions, 925 deletions
diff --git a/tar.c b/tar.c
index 6496231ae..87b5d2176 100644
--- a/tar.c
+++ b/tar.c
@@ -1,3 +1,4 @@
1/* vi: set sw=4 ts=4: */
1/* 2/*
2 * Mini tar implementation for busybox based on code taken from sash. 3 * Mini tar implementation for busybox based on code taken from sash.
3 * 4 *
@@ -40,27 +41,29 @@
40#include <utime.h> 41#include <utime.h>
41#include <sys/types.h> 42#include <sys/types.h>
42#include <sys/sysmacros.h> 43#include <sys/sysmacros.h>
43#include <sys/param.h> /* for PATH_MAX */ 44#include <sys/param.h> /* for PATH_MAX */
44 45
45 46
46#ifdef BB_FEATURE_TAR_CREATE 47#ifdef BB_FEATURE_TAR_CREATE
47 48
48static const char tar_usage[] = 49static const char tar_usage[] =
49"tar -[cxtvOf] [tarFileName] [FILE] ...\n\n" 50 "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n"
50"Create, extract, or list files from a tar file.\n\n" 51 "Create, extract, or list files from a tar file.\n\n"
51"Options:\n" 52 "Options:\n"
52"\tc=create, x=extract, t=list contents, v=verbose,\n" 53
53"\tO=extract to stdout, f=tarfile or \"-\" for stdin\n"; 54 "\tc=create, x=extract, t=list contents, v=verbose,\n"
55 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
54 56
55#else 57#else
56 58
57static const char tar_usage[] = 59static const char tar_usage[] =
58"tar -[xtvOf] [tarFileName] [FILE] ...\n\n" 60 "tar -[xtvOf] [tarFileName] [FILE] ...\n\n"
59"Extract, or list files stored in a tar file. This\n" 61 "Extract, or list files stored in a tar file. This\n"
60"version of tar does not support creation of tar files.\n\n" 62 "version of tar does not support creation of tar files.\n\n"
61"Options:\n" 63 "Options:\n"
62"\tx=extract, t=list contents, v=verbose,\n" 64
63"\tO=extract to stdout, f=tarfile or \"-\" for stdin\n"; 65 "\tx=extract, t=list contents, v=verbose,\n"
66 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
64 67
65#endif 68#endif
66 69
@@ -78,22 +81,22 @@ static const char tar_usage[] =
78 * with zero padding. We only process this information minimally. 81 * with zero padding. We only process this information minimally.
79 */ 82 */
80typedef struct { 83typedef struct {
81 char name[TAR_NAME_SIZE]; 84 char name[TAR_NAME_SIZE];
82 char mode[8]; 85 char mode[8];
83 char uid[8]; 86 char uid[8];
84 char gid[8]; 87 char gid[8];
85 char size[12]; 88 char size[12];
86 char mtime[12]; 89 char mtime[12];
87 char checkSum[8]; 90 char checkSum[8];
88 char typeFlag; 91 char typeFlag;
89 char linkName[TAR_NAME_SIZE]; 92 char linkName[TAR_NAME_SIZE];
90 char magic[6]; 93 char magic[6];
91 char version[2]; 94 char version[2];
92 char uname[32]; 95 char uname[32];
93 char gname[32]; 96 char gname[32];
94 char devMajor[8]; 97 char devMajor[8];
95 char devMinor[8]; 98 char devMinor[8];
96 char prefix[155]; 99 char prefix[155];
97} TarHeader; 100} TarHeader;
98 101
99#define TAR_MAGIC "ustar" 102#define TAR_MAGIC "ustar"
@@ -113,7 +116,7 @@ static int createFlag;
113static int verboseFlag; 116static int verboseFlag;
114static int tostdoutFlag; 117static int tostdoutFlag;
115 118
116static int inHeader; // <- check me 119static int inHeader; // <- check me
117static int badHeader; 120static int badHeader;
118static int errorFlag; 121static int errorFlag;
119static int skipFileFlag; 122static int skipFileFlag;
@@ -140,141 +143,145 @@ static ino_t tarInode;
140/* 143/*
141 * Local procedures to restore files from a tar file. 144 * Local procedures to restore files from a tar file.
142 */ 145 */
143static void readTarFile (int fileCount, char **fileTable); 146static void readTarFile(int fileCount, char **fileTable);
144static void readData (const char *cp, int count); 147static void readData(const char *cp, int count);
145static long getOctal (const char *cp, int len); 148static long getOctal(const char *cp, int len);
149
150static void readHeader(const TarHeader * hp,
146 151
147static void readHeader (const TarHeader * hp, 152 int fileCount, char **fileTable);
148 int fileCount, char **fileTable);
149 153
150static int wantFileName (const char *fileName, 154static int wantFileName(const char *fileName,
151 int fileCount, char **fileTable); 155
156 int fileCount, char **fileTable);
152 157
153#ifdef BB_FEATURE_TAR_CREATE 158#ifdef BB_FEATURE_TAR_CREATE
154/* 159/*
155 * Local procedures to save files into a tar file. 160 * Local procedures to save files into a tar file.
156 */ 161 */
157static void saveFile (const char *fileName, int seeLinks); 162static void saveFile(const char *fileName, int seeLinks);
163
164static void saveRegularFile(const char *fileName,
158 165
159static void saveRegularFile (const char *fileName, 166 const struct stat *statbuf);
160 const struct stat *statbuf);
161 167
162static void saveDirectory (const char *fileName, 168static void saveDirectory(const char *fileName,
163 const struct stat *statbuf);
164 169
165static void writeHeader (const char *fileName, const struct stat *statbuf); 170 const struct stat *statbuf);
166 171
167static void writeTarFile (int fileCount, char **fileTable); 172static void writeHeader(const char *fileName, const struct stat *statbuf);
168static void writeTarBlock (const char *buf, int len); 173
169static int putOctal (char *cp, int len, long value); 174static void writeTarFile(int fileCount, char **fileTable);
175static void writeTarBlock(const char *buf, int len);
176static int putOctal(char *cp, int len, long value);
170 177
171#endif 178#endif
172 179
173 180
174extern int tar_main (int argc, char **argv) 181extern int tar_main(int argc, char **argv)
175{ 182{
176 const char *options; 183 const char *options;
177 184
178 argc--; 185 argc--;
179 argv++; 186 argv++;
180 187
181 if (argc < 1) 188 if (argc < 1)
182 usage( tar_usage); 189 usage(tar_usage);
183 190
184 191
185 errorFlag = FALSE; 192 errorFlag = FALSE;
186 extractFlag = FALSE; 193 extractFlag = FALSE;
187 createFlag = FALSE; 194 createFlag = FALSE;
188 listFlag = FALSE; 195 listFlag = FALSE;
189 verboseFlag = FALSE; 196 verboseFlag = FALSE;
190 tostdoutFlag = FALSE; 197 tostdoutFlag = FALSE;
191 tarName = NULL; 198 tarName = NULL;
192 tarDev = 0; 199 tarDev = 0;
193 tarInode = 0; 200 tarInode = 0;
194 tarFd = -1; 201 tarFd = -1;
195 202
196 /* 203 /*
197 * Parse the options. 204 * Parse the options.
198 */ 205 */
199 if (**argv == '-') 206 if (**argv == '-')
200 options = (*argv++) + 1; 207 options = (*argv++) + 1;
201 else 208 else
202 options = (*argv++); 209 options = (*argv++);
203 argc--; 210 argc--;
204 211
205 for (; *options; options++) { 212 for (; *options; options++) {
206 switch (*options) { 213 switch (*options) {
207 case 'f': 214 case 'f':
208 if (tarName != NULL) { 215 if (tarName != NULL) {
209 fprintf (stderr, "Only one 'f' option allowed\n"); 216 fprintf(stderr, "Only one 'f' option allowed\n");
210 217
211 exit (FALSE); 218 exit(FALSE);
212 } 219 }
213 220
214 tarName = *argv++; 221 tarName = *argv++;
215 argc--; 222 argc--;
216 223
217 break; 224 break;
218 225
219 case 't': 226 case 't':
220 if (extractFlag == TRUE || createFlag == TRUE ) 227 if (extractFlag == TRUE || createFlag == TRUE)
221 goto flagError; 228 goto flagError;
222 listFlag = TRUE; 229 listFlag = TRUE;
223 break; 230 break;
224 231
225 case 'x': 232 case 'x':
226 if (listFlag == TRUE || createFlag == TRUE ) 233 if (listFlag == TRUE || createFlag == TRUE)
227 goto flagError; 234 goto flagError;
228 extractFlag = TRUE; 235 extractFlag = TRUE;
229 break; 236 break;
230 case 'c': 237 case 'c':
231 if (extractFlag == TRUE || listFlag == TRUE) 238 if (extractFlag == TRUE || listFlag == TRUE)
232 goto flagError; 239 goto flagError;
233 createFlag = TRUE; 240 createFlag = TRUE;
234 break; 241 break;
235 242
236 case 'v': 243 case 'v':
237 verboseFlag = TRUE; 244 verboseFlag = TRUE;
238 break; 245 break;
239 246
240 case 'O': 247 case 'O':
241 tostdoutFlag = TRUE; 248 tostdoutFlag = TRUE;
242 break; 249 break;
243 250
244 case '-': 251 case '-':
245 usage( tar_usage); 252 usage(tar_usage);
246 break; 253 break;
247 254
248 default: 255 default:
249 fprintf (stderr, "Unknown tar flag '%c'\n" 256 fprintf(stderr, "Unknown tar flag '%c'\n"
250 "Try `tar --help' for more information\n", 257 "Try `tar --help' for more information\n", *options);
251 *options); 258 exit(FALSE);
252 exit (FALSE); 259 }
253 } 260 }
254 }
255 261
256 /* 262 /*
257 * Do the correct type of action supplying the rest of the 263 * Do the correct type of action supplying the rest of the
258 * command line arguments as the list of files to process. 264 * command line arguments as the list of files to process.
259 */ 265 */
260 if (createFlag==TRUE) { 266 if (createFlag == TRUE) {
261#ifndef BB_FEATURE_TAR_CREATE 267#ifndef BB_FEATURE_TAR_CREATE
262 fprintf (stderr, "This version of tar was not compiled with tar creation support.\n" ); 268 fprintf(stderr,
263 exit (FALSE); 269 "This version of tar was not compiled with tar creation support.\n");
270 exit(FALSE);
264#else 271#else
265 writeTarFile (argc, argv); 272 writeTarFile(argc, argv);
266#endif 273#endif
267 } else { 274 } else {
268 readTarFile (argc, argv); 275 readTarFile(argc, argv);
269 } 276 }
270 if (errorFlag==TRUE) { 277 if (errorFlag == TRUE) {
271 fprintf (stderr, "\n"); 278 fprintf(stderr, "\n");
272 } 279 }
273 exit (!errorFlag); 280 exit(!errorFlag);
274 281
275flagError: 282 flagError:
276 fprintf (stderr, "Exactly one of 'c', 'x' or 't' must be specified\n"); 283 fprintf(stderr, "Exactly one of 'c', 'x' or 't' must be specified\n");
277 exit (FALSE); 284 exit(FALSE);
278} 285}
279 286
280 287
@@ -282,120 +289,120 @@ flagError:
282 * Read a tar file and extract or list the specified files within it. 289 * Read a tar file and extract or list the specified files within it.
283 * If the list is empty than all files are extracted or listed. 290 * If the list is empty than all files are extracted or listed.
284 */ 291 */
285static void readTarFile (int fileCount, char **fileTable) 292static void readTarFile(int fileCount, char **fileTable)
286{ 293{
287 const char *cp; 294 const char *cp;
288 int cc; 295 int cc;
289 int inCc; 296 int inCc;
290 int blockSize; 297 int blockSize;
291 char buf[BUF_SIZE]; 298 char buf[BUF_SIZE];
292 299
293 skipFileFlag = FALSE; 300 skipFileFlag = FALSE;
294 badHeader = FALSE; 301 badHeader = FALSE;
295 warnedRoot = FALSE; 302 warnedRoot = FALSE;
296 eofFlag = FALSE; 303 eofFlag = FALSE;
297 inHeader = TRUE; 304 inHeader = TRUE;
298 inCc = 0; 305 inCc = 0;
299 dataCc = 0; 306 dataCc = 0;
300 outFd = -1; 307 outFd = -1;
301 blockSize = sizeof (buf); 308 blockSize = sizeof(buf);
302 cp = buf; 309 cp = buf;
303 310
304 /*
305 * Open the tar file for reading.
306 */
307 if ((tarName == NULL) || !strcmp (tarName, "-")) {
308 tarFd = fileno(stdin);
309 } else
310 tarFd = open (tarName, O_RDONLY);
311
312 if (tarFd < 0) {
313 perror (tarName);
314 errorFlag = TRUE;
315 return;
316 }
317
318 /*
319 * Read blocks from the file until an end of file header block
320 * has been seen. (A real end of file from a read is an error.)
321 */
322 while (eofFlag==FALSE) {
323 /* 311 /*
324 * Read the next block of data if necessary. 312 * Open the tar file for reading.
325 * This will be a large block if possible, which we will
326 * then process in the small tar blocks.
327 */ 313 */
328 if (inCc <= 0) { 314 if ((tarName == NULL) || !strcmp(tarName, "-")) {
329 cp = buf; 315 tarFd = fileno(stdin);
330 inCc = fullRead (tarFd, buf, blockSize); 316 } else
331 317 tarFd = open(tarName, O_RDONLY);
332 if (inCc < 0) {
333 perror (tarName);
334 errorFlag = TRUE;
335 goto done;
336 }
337 318
338 if (inCc == 0) { 319 if (tarFd < 0) {
339 fprintf (stderr, 320 perror(tarName);
340 "Unexpected end of file from \"%s\"", tarName);
341 errorFlag = TRUE; 321 errorFlag = TRUE;
342 goto done; 322 return;
343 }
344 } 323 }
345 324
346 /* 325 /*
347 * If we are expecting a header block then examine it. 326 * Read blocks from the file until an end of file header block
327 * has been seen. (A real end of file from a read is an error.)
348 */ 328 */
349 if (inHeader==TRUE) { 329 while (eofFlag == FALSE) {
350 readHeader ((const TarHeader *) cp, fileCount, fileTable); 330 /*
351 331 * Read the next block of data if necessary.
352 cp += TAR_BLOCK_SIZE; 332 * This will be a large block if possible, which we will
353 inCc -= TAR_BLOCK_SIZE; 333 * then process in the small tar blocks.
354 334 */
355 continue; 335 if (inCc <= 0) {
336 cp = buf;
337 inCc = fullRead(tarFd, buf, blockSize);
338
339 if (inCc < 0) {
340 perror(tarName);
341 errorFlag = TRUE;
342 goto done;
343 }
344
345 if (inCc == 0) {
346 fprintf(stderr,
347 "Unexpected end of file from \"%s\"", tarName);
348 errorFlag = TRUE;
349 goto done;
350 }
351 }
352
353 /*
354 * If we are expecting a header block then examine it.
355 */
356 if (inHeader == TRUE) {
357 readHeader((const TarHeader *) cp, fileCount, fileTable);
358
359 cp += TAR_BLOCK_SIZE;
360 inCc -= TAR_BLOCK_SIZE;
361
362 continue;
363 }
364
365 /*
366 * We are currently handling the data for a file.
367 * Process the minimum of the amount of data we have available
368 * and the amount left to be processed for the file.
369 */
370 cc = inCc;
371
372 if (cc > dataCc)
373 cc = dataCc;
374
375 readData(cp, cc);
376
377 /*
378 * If the amount left isn't an exact multiple of the tar block
379 * size then round it up to the next block boundary since there
380 * is padding at the end of the file.
381 */
382 if (cc % TAR_BLOCK_SIZE)
383 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
384
385 cp += cc;
386 inCc -= cc;
356 } 387 }
357 388
389 done:
358 /* 390 /*
359 * We are currently handling the data for a file. 391 * Close the tar file if needed.
360 * Process the minimum of the amount of data we have available
361 * and the amount left to be processed for the file.
362 */ 392 */
363 cc = inCc; 393 if ((tarFd >= 0) && (close(tarFd) < 0))
364 394 perror(tarName);
365 if (cc > dataCc)
366 cc = dataCc;
367
368 readData (cp, cc);
369 395
370 /* 396 /*
371 * If the amount left isn't an exact multiple of the tar block 397 * Close the output file if needed.
372 * size then round it up to the next block boundary since there 398 * This is only done here on a previous error and so no
373 * is padding at the end of the file. 399 * message is required on errors.
374 */ 400 */
375 if (cc % TAR_BLOCK_SIZE) 401 if (tostdoutFlag == FALSE) {
376 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE); 402 if (outFd >= 0) {
377 403 close(outFd);
378 cp += cc; 404 }
379 inCc -= cc;
380 }
381
382 done:
383 /*
384 * Close the tar file if needed.
385 */
386 if ((tarFd >= 0) && (close (tarFd) < 0))
387 perror (tarName);
388
389 /*
390 * Close the output file if needed.
391 * This is only done here on a previous error and so no
392 * message is required on errors.
393 */
394 if (tostdoutFlag == FALSE) {
395 if (outFd >= 0) {
396 close (outFd);
397 } 405 }
398 }
399} 406}
400 407
401 408
@@ -405,304 +412,305 @@ static void readTarFile (int fileCount, char **fileTable)
405 * the end of the tar file. 412 * the end of the tar file.
406 */ 413 */
407static void 414static void
408readHeader (const TarHeader * hp, int fileCount, char **fileTable) 415readHeader(const TarHeader * hp, int fileCount, char **fileTable)
409{ 416{
410 int checkSum; 417 int checkSum;
411 int cc; 418 int cc;
412 int hardLink; 419 int hardLink;
413 int softLink; 420 int softLink;
414 int devFileFlag; 421 int devFileFlag;
415 unsigned int major; 422 unsigned int major;
416 unsigned int minor; 423 unsigned int minor;
417 long size; 424 long size;
418 struct utimbuf utb; 425 struct utimbuf utb;
419 426
420 /* 427 /*
421 * If the block is completely empty, then this is the end of the 428 * If the block is completely empty, then this is the end of the
422 * archive file. If the name is null, then just skip this header. 429 * archive file. If the name is null, then just skip this header.
423 */ 430 */
424 outName = hp->name; 431 outName = hp->name;
425 432
426 if (*outName == '\0') { 433 if (*outName == '\0') {
427 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) { 434 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
428 if (*outName++) 435 if (*outName++)
436 return;
437 }
438
439 eofFlag = TRUE;
440
429 return; 441 return;
430 } 442 }
431 443
432 eofFlag = TRUE; 444 /*
433 445 * There is another file in the archive to examine.
434 return; 446 * Extract the encoded information and check it.
435 } 447 */
436 448 mode = getOctal(hp->mode, sizeof(hp->mode));
437 /* 449 uid = getOctal(hp->uid, sizeof(hp->uid));
438 * There is another file in the archive to examine. 450 gid = getOctal(hp->gid, sizeof(hp->gid));
439 * Extract the encoded information and check it. 451 size = getOctal(hp->size, sizeof(hp->size));
440 */ 452 mtime = getOctal(hp->mtime, sizeof(hp->mtime));
441 mode = getOctal (hp->mode, sizeof (hp->mode)); 453 checkSum = getOctal(hp->checkSum, sizeof(hp->checkSum));
442 uid = getOctal (hp->uid, sizeof (hp->uid)); 454 major = getOctal(hp->devMajor, sizeof(hp->devMajor));
443 gid = getOctal (hp->gid, sizeof (hp->gid)); 455 minor = getOctal(hp->devMinor, sizeof(hp->devMinor));
444 size = getOctal (hp->size, sizeof (hp->size));
445 mtime = getOctal (hp->mtime, sizeof (hp->mtime));
446 checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
447 major = getOctal (hp->devMajor, sizeof (hp->devMajor));
448 minor = getOctal (hp->devMinor, sizeof (hp->devMinor));
449
450 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
451 if (badHeader==FALSE)
452 fprintf (stderr, "Bad tar header, skipping\n");
453
454 badHeader = TRUE;
455
456 return;
457 }
458
459 badHeader = FALSE;
460 skipFileFlag = FALSE;
461 devFileFlag = FALSE;
462
463 /*
464 * Check for the file modes.
465 */
466 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
467 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
468
469 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
470 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
471
472 /*
473 * Check for a directory.
474 */
475 if (outName[strlen (outName) - 1] == '/')
476 mode |= S_IFDIR;
477
478 /*
479 * Check for absolute paths in the file.
480 * If we find any, then warn the user and make them relative.
481 */
482 if (*outName == '/') {
483 while (*outName == '/')
484 outName++;
485
486 if (warnedRoot==FALSE) {
487 fprintf (stderr,
488 "Absolute path detected, removing leading slashes\n");
489 }
490 456
491 warnedRoot = TRUE; 457 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
492 } 458 if (badHeader == FALSE)
493 459 fprintf(stderr, "Bad tar header, skipping\n");
494 /*
495 * See if we want this file to be restored.
496 * If not, then set up to skip it.
497 */
498 if (wantFileName (outName, fileCount, fileTable) == FALSE) {
499 if ( !hardLink && !softLink && (S_ISREG (mode) || S_ISCHR (mode)
500 || S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) {
501 inHeader = (size == 0)? TRUE : FALSE;
502 dataCc = size;
503 }
504 460
505 skipFileFlag = TRUE; 461 badHeader = TRUE;
506 462
507 return; 463 return;
508 }
509
510 /*
511 * This file is to be handled.
512 * If we aren't extracting then just list information about the file.
513 */
514 if (extractFlag==FALSE) {
515 if (verboseFlag==TRUE) {
516 printf ("%s %3d/%-d ", modeString (mode), uid, gid);
517 if( S_ISCHR (mode) || S_ISBLK (mode) )
518 printf ("%4d,%4d %s ", major,minor, timeString (mtime));
519 else
520 printf ("%9ld %s ", size, timeString (mtime));
521 }
522 printf ("%s", outName);
523
524 if (hardLink)
525 printf (" (link to \"%s\")", hp->linkName);
526 else if (softLink)
527 printf (" (symlink to \"%s\")", hp->linkName);
528 else if (S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode) ||
529 S_ISSOCK(mode) || S_ISFIFO(mode) ) {
530 inHeader = (size == 0)? TRUE : FALSE;
531 dataCc = size;
532 } 464 }
533 465
534 printf ("\n"); 466 badHeader = FALSE;
467 skipFileFlag = FALSE;
468 devFileFlag = FALSE;
535 469
536 return; 470 /*
537 } 471 * Check for the file modes.
472 */
473 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
474 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
475
476 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
477 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
478
479 /*
480 * Check for a directory.
481 */
482 if (outName[strlen(outName) - 1] == '/')
483 mode |= S_IFDIR;
484
485 /*
486 * Check for absolute paths in the file.
487 * If we find any, then warn the user and make them relative.
488 */
489 if (*outName == '/') {
490 while (*outName == '/')
491 outName++;
538 492
539 /* 493 if (warnedRoot == FALSE) {
540 * We really want to extract the file. 494 fprintf(stderr,
541 */ 495 "Absolute path detected, removing leading slashes\n");
542 if (verboseFlag==TRUE) 496 }
543 printf ("x %s\n", outName);
544 497
545 if (hardLink) { 498 warnedRoot = TRUE;
546 if (link (hp->linkName, outName) < 0) {
547 perror (outName);
548 return;
549 } 499 }
550 /* Set the file time */ 500
551 utb.actime = mtime; 501 /*
552 utb.modtime = mtime; 502 * See if we want this file to be restored.
553 utime (outName, &utb); 503 * If not, then set up to skip it.
554 /* Set the file permissions */ 504 */
555 chown(outName, uid, gid); 505 if (wantFileName(outName, fileCount, fileTable) == FALSE) {
556 chmod(outName, mode); 506 if (!hardLink && !softLink && (S_ISREG(mode) || S_ISCHR(mode)
557 return; 507 || S_ISBLK(mode) || S_ISSOCK(mode)
558 } 508 || S_ISFIFO(mode))) {
559 509 inHeader = (size == 0) ? TRUE : FALSE;
560 if (softLink) { 510 dataCc = size;
561#ifdef S_ISLNK 511 }
562 if (symlink (hp->linkName, outName) < 0) { 512
563 perror (outName); 513 skipFileFlag = TRUE;
564 return; 514
515 return;
565 } 516 }
566 /* Try to change ownership of the symlink. 517
567 * If libs doesn't support that, don't bother. 518 /*
568 * Changing the pointed-to file is the Wrong Thing(tm). 519 * This file is to be handled.
520 * If we aren't extracting then just list information about the file.
569 */ 521 */
522 if (extractFlag == FALSE) {
523 if (verboseFlag == TRUE) {
524 printf("%s %3d/%-d ", modeString(mode), uid, gid);
525 if (S_ISCHR(mode) || S_ISBLK(mode))
526 printf("%4d,%4d %s ", major, minor, timeString(mtime));
527 else
528 printf("%9ld %s ", size, timeString(mtime));
529 }
530 printf("%s", outName);
531
532 if (hardLink)
533 printf(" (link to \"%s\")", hp->linkName);
534 else if (softLink)
535 printf(" (symlink to \"%s\")", hp->linkName);
536 else if (S_ISREG(mode) || S_ISCHR(mode) || S_ISBLK(mode) ||
537 S_ISSOCK(mode) || S_ISFIFO(mode)) {
538 inHeader = (size == 0) ? TRUE : FALSE;
539 dataCc = size;
540 }
541
542 printf("\n");
543
544 return;
545 }
546
547 /*
548 * We really want to extract the file.
549 */
550 if (verboseFlag == TRUE)
551 printf("x %s\n", outName);
552
553 if (hardLink) {
554 if (link(hp->linkName, outName) < 0) {
555 perror(outName);
556 return;
557 }
558 /* Set the file time */
559 utb.actime = mtime;
560 utb.modtime = mtime;
561 utime(outName, &utb);
562 /* Set the file permissions */
563 chown(outName, uid, gid);
564 chmod(outName, mode);
565 return;
566 }
567
568 if (softLink) {
569#ifdef S_ISLNK
570 if (symlink(hp->linkName, outName) < 0) {
571 perror(outName);
572 return;
573 }
574 /* Try to change ownership of the symlink.
575 * If libs doesn't support that, don't bother.
576 * Changing the pointed-to file is the Wrong Thing(tm).
577 */
570#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) 578#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
571 lchown(outName, uid, gid); 579 lchown(outName, uid, gid);
572#endif 580#endif
573 581
574 /* Do not change permissions or date on symlink, 582 /* Do not change permissions or date on symlink,
575 * since it changes the pointed to file instead. duh. */ 583 * since it changes the pointed to file instead. duh. */
576#else 584#else
577 fprintf (stderr, "Cannot create symbolic links\n"); 585 fprintf(stderr, "Cannot create symbolic links\n");
578#endif 586#endif
579 return; 587 return;
580 }
581
582 /* Set the umask for this process so it doesn't
583 * screw things up. */
584 umask(0);
585
586 /*
587 * If the file is a directory, then just create the path.
588 */
589 if (S_ISDIR (mode)) {
590 if (createPath (outName, mode)==TRUE) {
591 /* Set the file time */
592 utb.actime = mtime;
593 utb.modtime = mtime;
594 utime (outName, &utb);
595 /* Set the file permissions */
596 chown(outName, uid, gid);
597 chmod(outName, mode);
598 return;
599 } 588 }
600 return; 589
601 } 590 /* Set the umask for this process so it doesn't
602 591 * screw things up. */
603 /* 592 umask(0);
604 * There is a file to write. 593
605 * First create the path to it if necessary with default permissions. 594 /*
606 */ 595 * If the file is a directory, then just create the path.
607 createPath (outName, 0777); 596 */
608 597 if (S_ISDIR(mode)) {
609 inHeader = (size == 0)? TRUE : FALSE; 598 if (createPath(outName, mode) == TRUE) {
610 dataCc = size; 599 /* Set the file time */
611 600 utb.actime = mtime;
612 /* 601 utb.modtime = mtime;
613 * Start the output file. 602 utime(outName, &utb);
614 */ 603 /* Set the file permissions */
615 if (tostdoutFlag == TRUE) 604 chown(outName, uid, gid);
616 outFd = fileno(stdout); 605 chmod(outName, mode);
617 else { 606 return;
618 if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) { 607 }
619 devFileFlag = TRUE; 608 return;
620 outFd = mknod (outName, mode, makedev(major, minor) );
621 } 609 }
622 else if (S_ISFIFO(mode) ) { 610
623 devFileFlag = TRUE; 611 /*
624 outFd = mkfifo(outName, mode); 612 * There is a file to write.
625 } else { 613 * First create the path to it if necessary with default permissions.
626 outFd = open (outName, O_WRONLY | O_CREAT | O_TRUNC, mode); 614 */
615 createPath(outName, 0777);
616
617 inHeader = (size == 0) ? TRUE : FALSE;
618 dataCc = size;
619
620 /*
621 * Start the output file.
622 */
623 if (tostdoutFlag == TRUE)
624 outFd = fileno(stdout);
625 else {
626 if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode)) {
627 devFileFlag = TRUE;
628 outFd = mknod(outName, mode, makedev(major, minor));
629 } else if (S_ISFIFO(mode)) {
630 devFileFlag = TRUE;
631 outFd = mkfifo(outName, mode);
632 } else {
633 outFd = open(outName, O_WRONLY | O_CREAT | O_TRUNC, mode);
634 }
635 if (outFd < 0) {
636 perror(outName);
637 skipFileFlag = TRUE;
638 return;
639 }
640 /* Set the file time */
641 utb.actime = mtime;
642 utb.modtime = mtime;
643 utime(outName, &utb);
644 /* Set the file permissions */
645 chown(outName, uid, gid);
646 chmod(outName, mode);
627 } 647 }
628 if (outFd < 0) { 648
629 perror (outName); 649
630 skipFileFlag = TRUE; 650 /*
631 return; 651 * If the file is empty, then that's all we need to do.
652 */
653 if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
654 close(outFd);
655 outFd = -1;
632 } 656 }
633 /* Set the file time */
634 utb.actime = mtime;
635 utb.modtime = mtime;
636 utime (outName, &utb);
637 /* Set the file permissions */
638 chown(outName, uid, gid);
639 chmod(outName, mode);
640 }
641
642
643 /*
644 * If the file is empty, then that's all we need to do.
645 */
646 if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
647 close (outFd);
648 outFd = -1;
649 }
650} 657}
651 658
652 659
653/* 660/*
654 * Handle a data block of some specified size that was read. 661 * Handle a data block of some specified size that was read.
655 */ 662 */
656static void readData (const char *cp, int count) 663static void readData(const char *cp, int count)
657{ 664{
658 /* 665 /*
659 * Reduce the amount of data left in this file. 666 * Reduce the amount of data left in this file.
660 * If there is no more data left, then we need to read 667 * If there is no more data left, then we need to read
661 * the header again. 668 * the header again.
662 */ 669 */
663 dataCc -= count; 670 dataCc -= count;
664
665 if (dataCc <= 0)
666 inHeader = TRUE;
667 671
668 /* 672 if (dataCc <= 0)
669 * If we aren't extracting files or this file is being 673 inHeader = TRUE;
670 * skipped then do nothing more. 674
671 */ 675 /*
672 if (extractFlag==FALSE || skipFileFlag==TRUE) 676 * If we aren't extracting files or this file is being
673 return; 677 * skipped then do nothing more.
674 678 */
675 /* 679 if (extractFlag == FALSE || skipFileFlag == TRUE)
676 * Write the data to the output file. 680 return;
677 */ 681
678 if (fullWrite (outFd, cp, count) < 0) { 682 /*
679 perror (outName); 683 * Write the data to the output file.
680 if (tostdoutFlag == FALSE) { 684 */
681 close (outFd); 685 if (fullWrite(outFd, cp, count) < 0) {
682 outFd = -1; 686 perror(outName);
687 if (tostdoutFlag == FALSE) {
688 close(outFd);
689 outFd = -1;
690 }
691 skipFileFlag = TRUE;
692 return;
683 } 693 }
684 skipFileFlag = TRUE;
685 return;
686 }
687
688 /*
689 * Check if we are done writing to the file now.
690 */
691 if (dataCc <= 0 && tostdoutFlag == FALSE) {
692 struct utimbuf utb;
693 if (close (outFd))
694 perror (outName);
695 694
696 /* Set the file time */ 695 /*
697 utb.actime = mtime; 696 * Check if we are done writing to the file now.
698 utb.modtime = mtime; 697 */
699 utime (outName, &utb); 698 if (dataCc <= 0 && tostdoutFlag == FALSE) {
700 /* Set the file permissions */ 699 struct utimbuf utb;
701 chown(outName, uid, gid); 700
702 chmod(outName, mode); 701 if (close(outFd))
702 perror(outName);
703 703
704 outFd = -1; 704 /* Set the file time */
705 } 705 utb.actime = mtime;
706 utb.modtime = mtime;
707 utime(outName, &utb);
708 /* Set the file permissions */
709 chown(outName, uid, gid);
710 chmod(outName, mode);
711
712 outFd = -1;
713 }
706} 714}
707 715
708 716
@@ -712,40 +720,40 @@ static void readData (const char *cp, int count)
712 * Returns TRUE if the file is selected. 720 * Returns TRUE if the file is selected.
713 */ 721 */
714static int 722static int
715wantFileName (const char *fileName, int fileCount, char **fileTable) 723wantFileName(const char *fileName, int fileCount, char **fileTable)
716{ 724{
717 const char *pathName; 725 const char *pathName;
718 int fileLength; 726 int fileLength;
719 int pathLength; 727 int pathLength;
720 728
721 /* 729 /*
722 * If there are no files in the list, then the file is wanted. 730 * If there are no files in the list, then the file is wanted.
723 */ 731 */
724 if (fileCount == 0) 732 if (fileCount == 0)
725 return TRUE; 733 return TRUE;
726 734
727 fileLength = strlen (fileName); 735 fileLength = strlen(fileName);
728 736
729 /* 737 /*
730 * Check each of the test paths. 738 * Check each of the test paths.
731 */ 739 */
732 while (fileCount-- > 0) { 740 while (fileCount-- > 0) {
733 pathName = *fileTable++; 741 pathName = *fileTable++;
734 742
735 pathLength = strlen (pathName); 743 pathLength = strlen(pathName);
736 744
737 if (fileLength < pathLength) 745 if (fileLength < pathLength)
738 continue; 746 continue;
739 747
740 if (memcmp (fileName, pathName, pathLength) != 0) 748 if (memcmp(fileName, pathName, pathLength) != 0)
741 continue; 749 continue;
742 750
743 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) { 751 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
744 return TRUE; 752 return TRUE;
753 }
745 } 754 }
746 }
747 755
748 return FALSE; 756 return FALSE;
749} 757}
750 758
751/* 759/*
@@ -753,34 +761,34 @@ wantFileName (const char *fileName, int fileCount, char **fileTable)
753 * spaces on both sides of the number and with an optional null character 761 * spaces on both sides of the number and with an optional null character
754 * at the end. Returns -1 on an illegal format. 762 * at the end. Returns -1 on an illegal format.
755 */ 763 */
756static long getOctal (const char *cp, int len) 764static long getOctal(const char *cp, int len)
757{ 765{
758 long val; 766 long val;
759 767
760 while ((len > 0) && (*cp == ' ')) { 768 while ((len > 0) && (*cp == ' ')) {
761 cp++; 769 cp++;
762 len--; 770 len--;
763 } 771 }
764 772
765 if ((len == 0) || !isOctal (*cp)) 773 if ((len == 0) || !isOctal(*cp))
766 return -1; 774 return -1;
767 775
768 val = 0; 776 val = 0;
769 777
770 while ((len > 0) && isOctal (*cp)) { 778 while ((len > 0) && isOctal(*cp)) {
771 val = val * 8 + *cp++ - '0'; 779 val = val * 8 + *cp++ - '0';
772 len--; 780 len--;
773 } 781 }
774 782
775 while ((len > 0) && (*cp == ' ')) { 783 while ((len > 0) && (*cp == ' ')) {
776 cp++; 784 cp++;
777 len--; 785 len--;
778 } 786 }
779 787
780 if ((len > 0) && *cp) 788 if ((len > 0) && *cp)
781 return -1; 789 return -1;
782 790
783 return val; 791 return val;
784} 792}
785 793
786 794
@@ -795,65 +803,65 @@ static long getOctal (const char *cp, int len)
795/* 803/*
796 * Write a tar file containing the specified files. 804 * Write a tar file containing the specified files.
797 */ 805 */
798static void writeTarFile (int fileCount, char **fileTable) 806static void writeTarFile(int fileCount, char **fileTable)
799{ 807{
800 struct stat statbuf; 808 struct stat statbuf;
801 809
802 /* 810 /*
803 * Make sure there is at least one file specified. 811 * Make sure there is at least one file specified.
804 */ 812 */
805 if (fileCount <= 0) { 813 if (fileCount <= 0) {
806 fprintf (stderr, "No files specified to be saved\n"); 814 fprintf(stderr, "No files specified to be saved\n");
807 errorFlag = TRUE; 815 errorFlag = TRUE;
808 } 816 }
809 817
810 /* 818 /*
811 * Create the tar file for writing. 819 * Create the tar file for writing.
812 */ 820 */
813 if ((tarName == NULL) || !strcmp (tarName, "-")) { 821 if ((tarName == NULL) || !strcmp(tarName, "-")) {
814 tostdoutFlag = TRUE; 822 tostdoutFlag = TRUE;
815 tarFd = fileno(stdout); 823 tarFd = fileno(stdout);
816 } else 824 } else
817 tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666); 825 tarFd = open(tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
818 826
819 if (tarFd < 0) { 827 if (tarFd < 0) {
820 perror (tarName); 828 perror(tarName);
821 errorFlag = TRUE; 829 errorFlag = TRUE;
822 return; 830 return;
823 } 831 }
824 832
825 /* 833 /*
826 * Get the device and inode of the tar file for checking later. 834 * Get the device and inode of the tar file for checking later.
827 */ 835 */
828 if (fstat (tarFd, &statbuf) < 0) { 836 if (fstat(tarFd, &statbuf) < 0) {
829 perror (tarName); 837 perror(tarName);
830 errorFlag = TRUE; 838 errorFlag = TRUE;
831 goto done; 839 goto done;
832 } 840 }
833 841
834 tarDev = statbuf.st_dev; 842 tarDev = statbuf.st_dev;
835 tarInode = statbuf.st_ino; 843 tarInode = statbuf.st_ino;
836 844
837 /* 845 /*
838 * Append each file name into the archive file. 846 * Append each file name into the archive file.
839 * Follow symbolic links for these top level file names. 847 * Follow symbolic links for these top level file names.
840 */ 848 */
841 while (errorFlag==FALSE && (fileCount-- > 0)) { 849 while (errorFlag == FALSE && (fileCount-- > 0)) {
842 saveFile (*fileTable++, FALSE); 850 saveFile(*fileTable++, FALSE);
843 } 851 }
844 852
845 /* 853 /*
846 * Now write an empty block of zeroes to end the archive. 854 * Now write an empty block of zeroes to end the archive.
847 */ 855 */
848 writeTarBlock ("", 1); 856 writeTarBlock("", 1);
849 857
850 858
851 done: 859 done:
852 /* 860 /*
853 * Close the tar file and check for errors if it was opened. 861 * Close the tar file and check for errors if it was opened.
854 */ 862 */
855 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0)) 863 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close(tarFd) < 0))
856 perror (tarName); 864 perror(tarName);
857} 865}
858 866
859/* 867/*
@@ -863,73 +871,73 @@ static void writeTarFile (int fileCount, char **fileTable)
863 * flag indicates whether or not we want to see symbolic links as 871 * flag indicates whether or not we want to see symbolic links as
864 * they really are, instead of blindly following them. 872 * they really are, instead of blindly following them.
865 */ 873 */
866static void saveFile (const char *fileName, int seeLinks) 874static void saveFile(const char *fileName, int seeLinks)
867{ 875{
868 int status; 876 int status;
869 struct stat statbuf; 877 struct stat statbuf;
870 878
871 if (verboseFlag==TRUE) 879 if (verboseFlag == TRUE)
872 printf ("a %s\n", fileName); 880 printf("a %s\n", fileName);
873 881
874 /* 882 /*
875 * Check that the file name will fit in the header. 883 * Check that the file name will fit in the header.
876 */ 884 */
877 if (strlen (fileName) >= TAR_NAME_SIZE) { 885 if (strlen(fileName) >= TAR_NAME_SIZE) {
878 fprintf (stderr, "%s: File name is too long\n", fileName); 886 fprintf(stderr, "%s: File name is too long\n", fileName);
879 887
880 return; 888 return;
881 } 889 }
882 890
883 /* 891 /*
884 * Find out about the file. 892 * Find out about the file.
885 */ 893 */
886#ifdef S_ISLNK 894#ifdef S_ISLNK
887 if (seeLinks==TRUE) 895 if (seeLinks == TRUE)
888 status = lstat (fileName, &statbuf); 896 status = lstat(fileName, &statbuf);
889 else 897 else
890#endif 898#endif
891 status = stat (fileName, &statbuf); 899 status = stat(fileName, &statbuf);
892 900
893 if (status < 0) { 901 if (status < 0) {
894 perror (fileName); 902 perror(fileName);
903
904 return;
905 }
895 906
896 return; 907 /*
897 } 908 * Make sure we aren't trying to save our file into itself.
909 */
910 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
911 fprintf(stderr, "Skipping saving of archive file itself\n");
898 912
899 /* 913 return;
900 * Make sure we aren't trying to save our file into itself. 914 }
901 */
902 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
903 fprintf (stderr, "Skipping saving of archive file itself\n");
904 915
905 return; 916 /*
906 } 917 * Check the type of file.
918 */
919 mode = statbuf.st_mode;
907 920
908 /* 921 if (S_ISDIR(mode)) {
909 * Check the type of file. 922 saveDirectory(fileName, &statbuf);
910 */
911 mode = statbuf.st_mode;
912 923
913 if (S_ISDIR (mode)) { 924 return;
914 saveDirectory (fileName, &statbuf); 925 }
926 if (S_ISREG(mode)) {
927 saveRegularFile(fileName, &statbuf);
915 928
916 return; 929 return;
917 } 930 }
918 if (S_ISREG (mode)) {
919 saveRegularFile (fileName, &statbuf);
920 931
921 return; 932 /* Some day add support for tarring these up... but not today. :) */
922 }
923
924 /* Some day add support for tarring these up... but not today. :) */
925// if (S_ISLNK(mode) || S_ISFIFO(mode) || S_ISBLK(mode) || S_ISCHR (mode) ) { 933// if (S_ISLNK(mode) || S_ISFIFO(mode) || S_ISBLK(mode) || S_ISCHR (mode) ) {
926// fprintf (stderr, "%s: This version of tar can't store this type of file\n", fileName); 934// fprintf (stderr, "%s: This version of tar can't store this type of file\n", fileName);
927// } 935// }
928 936
929 /* 937 /*
930 * The file is a strange type of file, ignore it. 938 * The file is a strange type of file, ignore it.
931 */ 939 */
932 fprintf (stderr, "%s: not a directory or regular file\n", fileName); 940 fprintf(stderr, "%s: not a directory or regular file\n", fileName);
933} 941}
934 942
935 943
@@ -937,173 +945,172 @@ static void saveFile (const char *fileName, int seeLinks)
937 * Save a regular file to the tar file. 945 * Save a regular file to the tar file.
938 */ 946 */
939static void 947static void
940saveRegularFile (const char *fileName, const struct stat *statbuf) 948saveRegularFile(const char *fileName, const struct stat *statbuf)
941{ 949{
942 int sawEof; 950 int sawEof;
943 int fileFd; 951 int fileFd;
944 int cc; 952 int cc;
945 int dataCount; 953 int dataCount;
946 long fullDataCount; 954 long fullDataCount;
947 char data[TAR_BLOCK_SIZE * 16]; 955 char data[TAR_BLOCK_SIZE * 16];
948
949 /*
950 * Open the file for reading.
951 */
952 fileFd = open (fileName, O_RDONLY);
953
954 if (fileFd < 0) {
955 perror (fileName);
956
957 return;
958 }
959
960 /*
961 * Write out the header for the file.
962 */
963 writeHeader (fileName, statbuf);
964
965 /*
966 * Write the data blocks of the file.
967 * We must be careful to write the amount of data that the stat
968 * buffer indicated, even if the file has changed size. Otherwise
969 * the tar file will be incorrect.
970 */
971 fullDataCount = statbuf->st_size;
972 sawEof = FALSE;
973
974 while (fullDataCount > 0) {
975 /*
976 * Get the amount to write this iteration which is
977 * the minumum of the amount left to write and the
978 * buffer size.
979 */
980 dataCount = sizeof (data);
981
982 if (dataCount > fullDataCount)
983 dataCount = (int) fullDataCount;
984 956
985 /* 957 /*
986 * Read the data from the file if we haven't seen the 958 * Open the file for reading.
987 * end of file yet.
988 */ 959 */
989 cc = 0; 960 fileFd = open(fileName, O_RDONLY);
990
991 if (sawEof==FALSE) {
992 cc = fullRead (fileFd, data, dataCount);
993 961
994 if (cc < 0) { 962 if (fileFd < 0) {
995 perror (fileName); 963 perror(fileName);
996
997 (void) close (fileFd);
998 errorFlag = TRUE;
999 964
1000 return; 965 return;
1001 }
1002
1003 /*
1004 * If the file ended too soon, complain and set
1005 * a flag so we will zero fill the rest of it.
1006 */
1007 if (cc < dataCount) {
1008 fprintf (stderr,
1009 "%s: Short read - zero filling", fileName);
1010
1011 sawEof = TRUE;
1012 }
1013 } 966 }
1014 967
1015 /* 968 /*
1016 * Zero fill the rest of the data if necessary. 969 * Write out the header for the file.
1017 */ 970 */
1018 if (cc < dataCount) 971 writeHeader(fileName, statbuf);
1019 memset (data + cc, 0, dataCount - cc);
1020 972
1021 /* 973 /*
1022 * Write the buffer to the TAR file. 974 * Write the data blocks of the file.
975 * We must be careful to write the amount of data that the stat
976 * buffer indicated, even if the file has changed size. Otherwise
977 * the tar file will be incorrect.
1023 */ 978 */
1024 writeTarBlock (data, dataCount); 979 fullDataCount = statbuf->st_size;
1025 980 sawEof = FALSE;
1026 fullDataCount -= dataCount; 981
1027 } 982 while (fullDataCount > 0) {
983 /*
984 * Get the amount to write this iteration which is
985 * the minumum of the amount left to write and the
986 * buffer size.
987 */
988 dataCount = sizeof(data);
989
990 if (dataCount > fullDataCount)
991 dataCount = (int) fullDataCount;
992
993 /*
994 * Read the data from the file if we haven't seen the
995 * end of file yet.
996 */
997 cc = 0;
998
999 if (sawEof == FALSE) {
1000 cc = fullRead(fileFd, data, dataCount);
1001
1002 if (cc < 0) {
1003 perror(fileName);
1004
1005 (void) close(fileFd);
1006 errorFlag = TRUE;
1007
1008 return;
1009 }
1010
1011 /*
1012 * If the file ended too soon, complain and set
1013 * a flag so we will zero fill the rest of it.
1014 */
1015 if (cc < dataCount) {
1016 fprintf(stderr, "%s: Short read - zero filling", fileName);
1017
1018 sawEof = TRUE;
1019 }
1020 }
1021
1022 /*
1023 * Zero fill the rest of the data if necessary.
1024 */
1025 if (cc < dataCount)
1026 memset(data + cc, 0, dataCount - cc);
1027
1028 /*
1029 * Write the buffer to the TAR file.
1030 */
1031 writeTarBlock(data, dataCount);
1032
1033 fullDataCount -= dataCount;
1034 }
1028 1035
1029 /* 1036 /*
1030 * Close the file. 1037 * Close the file.
1031 */ 1038 */
1032 if ((tostdoutFlag == FALSE) && close (fileFd) < 0) 1039 if ((tostdoutFlag == FALSE) && close(fileFd) < 0)
1033 fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno)); 1040 fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno));
1034} 1041}
1035 1042
1036 1043
1037/* 1044/*
1038 * Save a directory and all of its files to the tar file. 1045 * Save a directory and all of its files to the tar file.
1039 */ 1046 */
1040static void saveDirectory (const char *dirName, const struct stat *statbuf) 1047static void saveDirectory(const char *dirName, const struct stat *statbuf)
1041{ 1048{
1042 DIR *dir; 1049 DIR *dir;
1043 struct dirent *entry; 1050 struct dirent *entry;
1044 int needSlash; 1051 int needSlash;
1045 char fullName[PATH_MAX + 1]; 1052 char fullName[PATH_MAX + 1];
1046 1053
1047 /* 1054 /*
1048 * Construct the directory name as used in the tar file by appending 1055 * Construct the directory name as used in the tar file by appending
1049 * a slash character to it. 1056 * a slash character to it.
1050 */ 1057 */
1051 strcpy (fullName, dirName); 1058 strcpy(fullName, dirName);
1052 strcat (fullName, "/"); 1059 strcat(fullName, "/");
1053 1060
1054 /* 1061 /*
1055 * Write out the header for the directory entry. 1062 * Write out the header for the directory entry.
1056 */ 1063 */
1057 writeHeader (fullName, statbuf); 1064 writeHeader(fullName, statbuf);
1058
1059 /*
1060 * Open the directory.
1061 */
1062 dir = opendir (dirName);
1063
1064 if (dir == NULL) {
1065 fprintf (stderr, "Cannot read directory \"%s\": %s\n",
1066 dirName, strerror (errno));
1067
1068 return;
1069 }
1070
1071 /*
1072 * See if a slash is needed.
1073 */
1074 needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
1075
1076 /*
1077 * Read all of the directory entries and check them,
1078 * except for the current and parent directory entries.
1079 */
1080 while (errorFlag==FALSE && ((entry = readdir (dir)) != NULL)) {
1081 if ((strcmp (entry->d_name, ".") == 0) ||
1082 (strcmp (entry->d_name, "..") == 0)) {
1083 continue;
1084 }
1085 1065
1086 /* 1066 /*
1087 * Build the full path name to the file. 1067 * Open the directory.
1088 */ 1068 */
1089 strcpy (fullName, dirName); 1069 dir = opendir(dirName);
1070
1071 if (dir == NULL) {
1072 fprintf(stderr, "Cannot read directory \"%s\": %s\n",
1073 dirName, strerror(errno));
1090 1074
1091 if (needSlash) 1075 return;
1092 strcat (fullName, "/"); 1076 }
1093 1077
1094 strcat (fullName, entry->d_name); 1078 /*
1079 * See if a slash is needed.
1080 */
1081 needSlash = (*dirName && (dirName[strlen(dirName) - 1] != '/'));
1095 1082
1096 /* 1083 /*
1097 * Write this file to the tar file, noticing whether or not 1084 * Read all of the directory entries and check them,
1098 * the file is a symbolic link. 1085 * except for the current and parent directory entries.
1099 */ 1086 */
1100 saveFile (fullName, TRUE); 1087 while (errorFlag == FALSE && ((entry = readdir(dir)) != NULL)) {
1101 } 1088 if ((strcmp(entry->d_name, ".") == 0) ||
1089 (strcmp(entry->d_name, "..") == 0)) {
1090 continue;
1091 }
1092
1093 /*
1094 * Build the full path name to the file.
1095 */
1096 strcpy(fullName, dirName);
1097
1098 if (needSlash)
1099 strcat(fullName, "/");
1100
1101 strcat(fullName, entry->d_name);
1102
1103 /*
1104 * Write this file to the tar file, noticing whether or not
1105 * the file is a symbolic link.
1106 */
1107 saveFile(fullName, TRUE);
1108 }
1102 1109
1103 /* 1110 /*
1104 * All done, close the directory. 1111 * All done, close the directory.
1105 */ 1112 */
1106 closedir (dir); 1113 closedir(dir);
1107} 1114}
1108 1115
1109 1116
@@ -1111,54 +1118,54 @@ static void saveDirectory (const char *dirName, const struct stat *statbuf)
1111 * Write a tar header for the specified file name and status. 1118 * Write a tar header for the specified file name and status.
1112 * It is assumed that the file name fits. 1119 * It is assumed that the file name fits.
1113 */ 1120 */
1114static void writeHeader (const char *fileName, const struct stat *statbuf) 1121static void writeHeader(const char *fileName, const struct stat *statbuf)
1115{ 1122{
1116 long checkSum; 1123 long checkSum;
1117 const unsigned char *cp; 1124 const unsigned char *cp;
1118 int len; 1125 int len;
1119 TarHeader header; 1126 TarHeader header;
1120 1127
1121 /* 1128 /*
1122 * Zero the header block in preparation for filling it in. 1129 * Zero the header block in preparation for filling it in.
1123 */ 1130 */
1124 memset ((char *) &header, 0, sizeof (header)); 1131 memset((char *) &header, 0, sizeof(header));
1125 1132
1126 /* 1133 /*
1127 * Fill in the header. 1134 * Fill in the header.
1128 */ 1135 */
1129 strcpy (header.name, fileName); 1136 strcpy(header.name, fileName);
1130 1137
1131 strncpy (header.magic, TAR_MAGIC, sizeof (header.magic)); 1138 strncpy(header.magic, TAR_MAGIC, sizeof(header.magic));
1132 strncpy (header.version, TAR_VERSION, sizeof (header.version)); 1139 strncpy(header.version, TAR_VERSION, sizeof(header.version));
1133 1140
1134 putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777); 1141 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777);
1135 putOctal (header.uid, sizeof (header.uid), statbuf->st_uid); 1142 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
1136 putOctal (header.gid, sizeof (header.gid), statbuf->st_gid); 1143 putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
1137 putOctal (header.size, sizeof (header.size), statbuf->st_size); 1144 putOctal(header.size, sizeof(header.size), statbuf->st_size);
1138 putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime); 1145 putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
1139 1146
1140 header.typeFlag = TAR_TYPE_REGULAR; 1147 header.typeFlag = TAR_TYPE_REGULAR;
1141 1148
1142 /* 1149 /*
1143 * Calculate and store the checksum. 1150 * Calculate and store the checksum.
1144 * This is the sum of all of the bytes of the header, 1151 * This is the sum of all of the bytes of the header,
1145 * with the checksum field itself treated as blanks. 1152 * with the checksum field itself treated as blanks.
1146 */ 1153 */
1147 memset (header.checkSum, ' ', sizeof (header.checkSum)); 1154 memset(header.checkSum, ' ', sizeof(header.checkSum));
1148 1155
1149 cp = (const unsigned char *) &header; 1156 cp = (const unsigned char *) &header;
1150 len = sizeof (header); 1157 len = sizeof(header);
1151 checkSum = 0; 1158 checkSum = 0;
1152 1159
1153 while (len-- > 0) 1160 while (len-- > 0)
1154 checkSum += *cp++; 1161 checkSum += *cp++;
1155 1162
1156 putOctal (header.checkSum, sizeof (header.checkSum), checkSum); 1163 putOctal(header.checkSum, sizeof(header.checkSum), checkSum);
1157 1164
1158 /* 1165 /*
1159 * Write the tar header. 1166 * Write the tar header.
1160 */ 1167 */
1161 writeTarBlock ((const char *) &header, sizeof (header)); 1168 writeTarBlock((const char *) &header, sizeof(header));
1162} 1169}
1163 1170
1164 1171
@@ -1167,56 +1174,56 @@ static void writeHeader (const char *fileName, const struct stat *statbuf)
1167 * The data is always padded out to a multiple of TAR_BLOCK_SIZE. 1174 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1168 * The errorFlag static variable is set on an error. 1175 * The errorFlag static variable is set on an error.
1169 */ 1176 */
1170static void writeTarBlock (const char *buf, int len) 1177static void writeTarBlock(const char *buf, int len)
1171{ 1178{
1172 int partialLength; 1179 int partialLength;
1173 int completeLength; 1180 int completeLength;
1174 char fullBlock[TAR_BLOCK_SIZE]; 1181 char fullBlock[TAR_BLOCK_SIZE];
1175 1182
1176 /* 1183 /*
1177 * If we had a write error before, then do nothing more. 1184 * If we had a write error before, then do nothing more.
1178 */ 1185 */
1179 if (errorFlag==TRUE) 1186 if (errorFlag == TRUE)
1180 return; 1187 return;
1181 1188
1182 /* 1189 /*
1183 * Get the amount of complete and partial blocks. 1190 * Get the amount of complete and partial blocks.
1184 */ 1191 */
1185 partialLength = len % TAR_BLOCK_SIZE; 1192 partialLength = len % TAR_BLOCK_SIZE;
1186 completeLength = len - partialLength; 1193 completeLength = len - partialLength;
1187 1194
1188 /* 1195 /*
1189 * Write all of the complete blocks. 1196 * Write all of the complete blocks.
1190 */ 1197 */
1191 if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) { 1198 if ((completeLength > 0) && !fullWrite(tarFd, buf, completeLength)) {
1192 perror (tarName); 1199 perror(tarName);
1193 1200
1194 errorFlag = TRUE; 1201 errorFlag = TRUE;
1195 1202
1196 return; 1203 return;
1197 } 1204 }
1198 1205
1199 /* 1206 /*
1200 * If there are no partial blocks left, we are done. 1207 * If there are no partial blocks left, we are done.
1201 */ 1208 */
1202 if (partialLength == 0) 1209 if (partialLength == 0)
1203 return; 1210 return;
1204 1211
1205 /* 1212 /*
1206 * Copy the partial data into a complete block, and pad the rest 1213 * Copy the partial data into a complete block, and pad the rest
1207 * of it with zeroes. 1214 * of it with zeroes.
1208 */ 1215 */
1209 memcpy (fullBlock, buf + completeLength, partialLength); 1216 memcpy(fullBlock, buf + completeLength, partialLength);
1210 memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength); 1217 memset(fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
1211 1218
1212 /* 1219 /*
1213 * Write the last complete block. 1220 * Write the last complete block.
1214 */ 1221 */
1215 if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) { 1222 if (!fullWrite(tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1216 perror (tarName); 1223 perror(tarName);
1217 1224
1218 errorFlag = TRUE; 1225 errorFlag = TRUE;
1219 } 1226 }
1220} 1227}
1221 1228
1222 1229
@@ -1225,48 +1232,48 @@ static void writeTarBlock (const char *buf, int len)
1225 * The number is zero and space padded and possibly null padded. 1232 * The number is zero and space padded and possibly null padded.
1226 * Returns TRUE if successful. 1233 * Returns TRUE if successful.
1227 */ 1234 */
1228static int putOctal (char *cp, int len, long value) 1235static int putOctal(char *cp, int len, long value)
1229{ 1236{
1230 int tempLength; 1237 int tempLength;
1231 char *tempString; 1238 char *tempString;
1232 char tempBuffer[32]; 1239 char tempBuffer[32];
1233
1234 /*
1235 * Create a string of the specified length with an initial space,
1236 * leading zeroes and the octal number, and a trailing null.
1237 */
1238 tempString = tempBuffer;
1239
1240 sprintf (tempString, " %0*lo", len - 2, value);
1241
1242 tempLength = strlen (tempString) + 1;
1243
1244 /*
1245 * If the string is too large, suppress the leading space.
1246 */
1247 if (tempLength > len) {
1248 tempLength--;
1249 tempString++;
1250 }
1251
1252 /*
1253 * If the string is still too large, suppress the trailing null.
1254 */
1255 if (tempLength > len)
1256 tempLength--;
1257
1258 /*
1259 * If the string is still too large, fail.
1260 */
1261 if (tempLength > len)
1262 return FALSE;
1263 1240
1264 /* 1241 /*
1265 * Copy the string to the field. 1242 * Create a string of the specified length with an initial space,
1266 */ 1243 * leading zeroes and the octal number, and a trailing null.
1267 memcpy (cp, tempString, len); 1244 */
1245 tempString = tempBuffer;
1268 1246
1269 return TRUE; 1247 sprintf(tempString, " %0*lo", len - 2, value);
1248
1249 tempLength = strlen(tempString) + 1;
1250
1251 /*
1252 * If the string is too large, suppress the leading space.
1253 */
1254 if (tempLength > len) {
1255 tempLength--;
1256 tempString++;
1257 }
1258
1259 /*
1260 * If the string is still too large, suppress the trailing null.
1261 */
1262 if (tempLength > len)
1263 tempLength--;
1264
1265 /*
1266 * If the string is still too large, fail.
1267 */
1268 if (tempLength > len)
1269 return FALSE;
1270
1271 /*
1272 * Copy the string to the field.
1273 */
1274 memcpy(cp, tempString, len);
1275
1276 return TRUE;
1270} 1277}
1271#endif 1278#endif
1272 1279