[9] | 1 | /* tar - tape archiver Author: Michiel Huisjes */
|
---|
| 2 |
|
---|
| 3 | /* Usage: tar [cxt][vo][F][f] tapefile [files]
|
---|
| 4 | *
|
---|
| 5 | * attempt to make tar to conform to POSIX 1003.1
|
---|
| 6 | * disclaimer: based on an old (1986) POSIX draft.
|
---|
| 7 | * Klamer Schutte, 20/9/89
|
---|
| 8 | *
|
---|
| 9 | * Changes:
|
---|
| 10 | * Changed to handle the original minix-tar format. KS 22/9/89
|
---|
| 11 | * Changed to handle BSD4.3 tar format. KS 22/9/89
|
---|
| 12 | * Conform to current umask if not super-user. KS 22/9/89
|
---|
| 13 | * Update usage message to show f option KS 22/9/89
|
---|
| 14 | *
|
---|
| 15 | *
|
---|
| 16 | * 1) tar will back itself up, should check archive inode num(&dev) and
|
---|
| 17 | then check the target inode number. In verbose mode, issue
|
---|
| 18 | warning, in all cases ignore target.
|
---|
| 19 | marks@mgse Mon Sep 25 10:38:58 CDT 1989
|
---|
| 20 | added global varaibles, made changes to main() and add_file();
|
---|
| 21 | maks@mgse Mon Sep 25 12:09:20 CDT 1989
|
---|
| 22 |
|
---|
| 23 | 2) tar will not notice that a file has changed size while it was being
|
---|
| 24 | backed up. should issue warning.
|
---|
| 25 | marks@mgse Mon Sep 25 10:38:58 CDT 1989
|
---|
| 26 |
|
---|
| 27 | 3) the 'f' option was not documented in usage[].
|
---|
| 28 | marks@mgse Mon Sep 25 12:03:20 CDT 1989
|
---|
| 29 | changed both usage[] defines. Why are there two (one is commented out)?
|
---|
| 30 | ( deleted by me (was done twice) -- KS, 2/10/89 )
|
---|
| 31 | *
|
---|
| 32 | * changed stat on tar_fd to an fstat KS 2/10/89
|
---|
| 33 | * deleted mkfifo() code -- belongs in libc.a KS 2/10/89
|
---|
| 34 | * made ar_dev default to -1 : an illegal device KS 2/10/89
|
---|
| 35 | * made impossible to chown if normal user KS 2/10/89
|
---|
| 36 | * if names in owner fields not known use numirical values KS 2/10/89
|
---|
| 37 | * creat with mask 666 -- use umask if to liberal KS 2/10/89
|
---|
| 38 | * allow to make directories as ../directory KS 2/10/89
|
---|
| 39 | * allow tmagic field to end with a space (instead of \0) KS 2/10/89
|
---|
| 40 | * correct usage of tmagic field KS 3/10/89
|
---|
| 41 | * made mkdir() to return a value if directory == "." KS 3/10/89
|
---|
| 42 | * made lint complains less (On a BSD 4.3 system) KS 3/10/89
|
---|
| 43 | * use of directory(3) routines KS 3/10/89
|
---|
| 44 | * deleted use of d_namlen selector of struct dirent KS 18/10/89
|
---|
| 45 | * support mknod4(2) EC 7/7/90
|
---|
| 46 | * forget inodes when link count expires EC 6/4/91
|
---|
| 47 | * don't remember directories *twice*!
|
---|
| 48 | * added 'p' flag to ignore umask for normal user KJB 6/10/92
|
---|
| 49 | * mknod4(2) out KJB 30/10/94
|
---|
| 50 | * added 'D' flag to not recurse into directories KJB 19/12/94
|
---|
| 51 | * status output to stdout unless 'tar cvf -' KJB 3/5/97
|
---|
| 52 | *
|
---|
| 53 | * Bugs:
|
---|
| 54 | * verbose mode is not reporting consistent
|
---|
| 55 | * code needs cleanup
|
---|
| 56 | * prefix field is not used
|
---|
| 57 | * timestamp of a directory will not be correct if there are files to be
|
---|
| 58 | * unpacked in the directory
|
---|
| 59 | * (add you favorite bug here (or two (or three (or ...))))
|
---|
| 60 | */
|
---|
| 61 |
|
---|
| 62 | #include <sys/types.h>
|
---|
| 63 | #include <sys/stat.h>
|
---|
| 64 | #include <fcntl.h>
|
---|
| 65 | #include <pwd.h>
|
---|
| 66 | #include <grp.h>
|
---|
| 67 | #include <tar.h>
|
---|
| 68 | #include <stdarg.h>
|
---|
| 69 | #include <stdlib.h>
|
---|
| 70 | #include <string.h>
|
---|
| 71 | #include <unistd.h>
|
---|
| 72 | #include <utime.h>
|
---|
| 73 | #include <sys/wait.h>
|
---|
| 74 | #include <stdio.h> /* need NULL */
|
---|
| 75 | #include <errno.h>
|
---|
| 76 |
|
---|
| 77 | #define POSIX_COMP /* POSIX compatible */
|
---|
| 78 | #define DIRECT_3 /* use directory(3) routines */
|
---|
| 79 |
|
---|
| 80 | #ifdef DIRECT_3
|
---|
| 81 | #ifndef BSD
|
---|
| 82 | /* To all minix users: i am sorry, developed this piece of code on a
|
---|
| 83 | * BSD system. KS 18/10/89 */
|
---|
| 84 | #include <dirent.h>
|
---|
| 85 | #define direct dirent /* stupid BSD non-POSIX compatible name! */
|
---|
| 86 | #else /* BSD */
|
---|
| 87 | #include <sys/dir.h>
|
---|
| 88 | #include <dir.h>
|
---|
| 89 | #endif /* BSD */
|
---|
| 90 | #endif /* DIRECT_3 */
|
---|
| 91 |
|
---|
| 92 | #ifdef S_IFIFO
|
---|
| 93 | #define HAVE_FIFO /* have incorporated Simon Pooles' changes */
|
---|
| 94 | #endif
|
---|
| 95 | #ifdef S_IFLNK
|
---|
| 96 | #define HAVE_SYMLINK
|
---|
| 97 | #endif
|
---|
| 98 |
|
---|
| 99 | typedef char BOOL;
|
---|
| 100 | #define TRUE 1
|
---|
| 101 | #define FALSE 0
|
---|
| 102 |
|
---|
| 103 | #define STRING_SIZE 256 /* string buffer size */
|
---|
| 104 | #define HEADER_SIZE TBLOCK
|
---|
| 105 | #define NAME_SIZE NAMSIZ
|
---|
| 106 | /* #define BLOCK_BOUNDARY 20 -- not in POSIX ! */
|
---|
| 107 |
|
---|
| 108 | typedef union hblock HEADER;
|
---|
| 109 |
|
---|
| 110 | /* Make the MINIX member names overlap to the POSIX names */
|
---|
| 111 | #define m_name name
|
---|
| 112 | #define m_mode mode
|
---|
| 113 | #define m_uid uid
|
---|
| 114 | #define m_gid gid
|
---|
| 115 | #define m_size size
|
---|
| 116 | #define m_time mtime
|
---|
| 117 | #define m_checksum chksum
|
---|
| 118 | #define m_linked typeflag
|
---|
| 119 | #define m_link linkname
|
---|
| 120 | #define hdr_block dummy
|
---|
| 121 | #define m header
|
---|
| 122 | #define member dbuf
|
---|
| 123 |
|
---|
| 124 | #if 0 /* original structure -- see tar.h for new
|
---|
| 125 | * structure */
|
---|
| 126 | typedef union {
|
---|
| 127 | char hdr_block[HEADER_SIZE];
|
---|
| 128 | struct m {
|
---|
| 129 | char m_name[NAME_SIZE];
|
---|
| 130 | char m_mode[8];
|
---|
| 131 | char m_uid[8];
|
---|
| 132 | char m_gid[8];
|
---|
| 133 | char m_size[12];
|
---|
| 134 | char m_time[12];
|
---|
| 135 | char m_checksum[8];
|
---|
| 136 | char m_linked;
|
---|
| 137 | char m_link[NAME_SIZE];
|
---|
| 138 | } member;
|
---|
| 139 | } HEADER;
|
---|
| 140 |
|
---|
| 141 | #endif
|
---|
| 142 |
|
---|
| 143 | /* Structure used to note links */
|
---|
| 144 | struct link {
|
---|
| 145 | ino_t ino;
|
---|
| 146 | dev_t dev;
|
---|
| 147 | nlink_t nlink;
|
---|
| 148 | struct link *next;
|
---|
| 149 | char name[1];
|
---|
| 150 | } *link_top = NULL;
|
---|
| 151 |
|
---|
| 152 | HEADER header;
|
---|
| 153 |
|
---|
| 154 | #define INT_TYPE (sizeof(header.member.m_uid))
|
---|
| 155 | #define LONG_TYPE (sizeof(header.member.m_size))
|
---|
| 156 |
|
---|
| 157 | #define NIL_HEADER ((HEADER *) 0)
|
---|
| 158 | #define NIL_PTR ((char *) 0)
|
---|
| 159 | #define TBLOCK_SIZE TBLOCK
|
---|
| 160 |
|
---|
| 161 | #define flush() print(NIL_PTR)
|
---|
| 162 |
|
---|
| 163 | BOOL show_fl, creat_fl, ext_fl;
|
---|
| 164 |
|
---|
| 165 | int tar_fd;
|
---|
| 166 | /* Char usage[] = "Usage: tar [cxt] tarfile [files]."; */
|
---|
| 167 | char usage[] = "Usage: tar [cxt][vo][F][f] tarfile [files].";
|
---|
| 168 | char io_buffer[TBLOCK_SIZE];
|
---|
| 169 | char path[NAME_SIZE];
|
---|
| 170 | char pathname[NAME_SIZE];
|
---|
| 171 | int force_flag = 0;
|
---|
| 172 | #ifdef ORIGINAL_DEFAULTS
|
---|
| 173 | int chown_flag = 1;
|
---|
| 174 | int verbose_flag = 1;
|
---|
| 175 | #else
|
---|
| 176 | int chown_flag = 0;
|
---|
| 177 | int verbose_flag = 0;
|
---|
| 178 | #endif
|
---|
| 179 | int norec_flag = 0;
|
---|
| 180 |
|
---|
| 181 | /* Make sure we don't tar ourselves. marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
|
---|
| 182 | ino_t ar_inode; /* archive inode number */
|
---|
| 183 | dev_t ar_dev; /* archive device number */
|
---|
| 184 |
|
---|
| 185 | int total_blocks;
|
---|
| 186 | int u_mask; /* one's complement of current umask */
|
---|
| 187 |
|
---|
| 188 | #define block_size() (int) ((convert(header.member.m_size, LONG_TYPE) \
|
---|
| 189 | + (long) TBLOCK_SIZE - 1) / (long) TBLOCK_SIZE)
|
---|
| 190 |
|
---|
| 191 | _PROTOTYPE(int main, (int argc, char **argv));
|
---|
| 192 | _PROTOTYPE(void error, (char *s1, char *s2));
|
---|
| 193 | _PROTOTYPE(BOOL get_header, (void));
|
---|
| 194 | _PROTOTYPE(void tarfile, (void));
|
---|
| 195 | _PROTOTYPE(void skip_entry, (void));
|
---|
| 196 | _PROTOTYPE(void extract, (char *file));
|
---|
| 197 | _PROTOTYPE(void delete, (char *file));
|
---|
| 198 | _PROTOTYPE(void do_chown, (char *file));
|
---|
| 199 | _PROTOTYPE(void timestamp, (char *file));
|
---|
| 200 | _PROTOTYPE(void copy, (char *file, int from, int to, long bytes));
|
---|
| 201 | _PROTOTYPE(long convert, (char str[], int type));
|
---|
| 202 | _PROTOTYPE(int checksum, (void));
|
---|
| 203 | _PROTOTYPE(int is_dir, (char *file));
|
---|
| 204 | _PROTOTYPE(char *path_name, (char *file));
|
---|
| 205 | _PROTOTYPE(void add_path, (char *name));
|
---|
| 206 | _PROTOTYPE(void add_file, (char *file));
|
---|
| 207 | _PROTOTYPE(void verb_print, (char *s1, char *s2));
|
---|
| 208 | _PROTOTYPE(void add_close, (int fd));
|
---|
| 209 | _PROTOTYPE(int add_open, (char *file, struct stat * st));
|
---|
| 210 | _PROTOTYPE(void make_header, (char *file, struct stat * st));
|
---|
| 211 | _PROTOTYPE(void is_added, (struct stat * st, char *file));
|
---|
| 212 | _PROTOTYPE(void is_deleted, (struct stat * st));
|
---|
| 213 | _PROTOTYPE(char *is_linked, (struct stat * st));
|
---|
| 214 | _PROTOTYPE(void clear_header, (void));
|
---|
| 215 | _PROTOTYPE(void adjust_boundary, (void));
|
---|
| 216 | _PROTOTYPE(void mread, (int fd, char *address, int bytes));
|
---|
| 217 | _PROTOTYPE(void mwrite, (int fd, char *address, int bytes));
|
---|
| 218 | _PROTOTYPE(int bread, (int fd, char *address, int bytes));
|
---|
| 219 | _PROTOTYPE(int bwrite, (int fd, char *address, int bytes));
|
---|
| 220 | _PROTOTYPE(void print, (char *str));
|
---|
| 221 | _PROTOTYPE(char *num_out, (long number));
|
---|
| 222 | _PROTOTYPE(void string_print, (char *buffer, char *fmt,...));
|
---|
| 223 |
|
---|
| 224 | void error(s1, s2)
|
---|
| 225 | char *s1, *s2;
|
---|
| 226 | {
|
---|
| 227 | string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : "");
|
---|
| 228 | flush();
|
---|
| 229 | exit(1);
|
---|
| 230 | }
|
---|
| 231 |
|
---|
| 232 | int main(argc, argv)
|
---|
| 233 | int argc;
|
---|
| 234 | register char *argv[];
|
---|
| 235 | {
|
---|
| 236 | register char *mem_name;
|
---|
| 237 | register char *ptr;
|
---|
| 238 | struct stat st;
|
---|
| 239 | int i;
|
---|
| 240 |
|
---|
| 241 | if (argc < 3) error(usage, NIL_PTR);
|
---|
| 242 |
|
---|
| 243 | for (ptr = argv[1]; *ptr; ptr++) {
|
---|
| 244 | /* Ignore - as first char */
|
---|
| 245 | if(*ptr == '-' && ptr == argv[1]) continue;
|
---|
| 246 | switch (*ptr) {
|
---|
| 247 | case 'c': creat_fl = TRUE; break;
|
---|
| 248 | case 'x': ext_fl = TRUE; break;
|
---|
| 249 | case 't': show_fl = TRUE; break;
|
---|
| 250 | case 'v': /* verbose output -Dal */
|
---|
| 251 | verbose_flag = !verbose_flag;
|
---|
| 252 | break;
|
---|
| 253 | case 'o': /* chown/chgrp files -Dal */
|
---|
| 254 | chown_flag = TRUE;
|
---|
| 255 | break;
|
---|
| 256 | case 'F': /* IGNORE ERRORS -Dal */
|
---|
| 257 | force_flag = TRUE;
|
---|
| 258 | break;
|
---|
| 259 | case 'f': /* standard U*IX usage -KS */
|
---|
| 260 | break;
|
---|
| 261 | case 'p': /* restore file modes right, ignore umask. */
|
---|
| 262 | (void) umask(0);
|
---|
| 263 | break;
|
---|
| 264 | case 'D': /* do not recursively add directories. */
|
---|
| 265 | norec_flag = TRUE;
|
---|
| 266 | break;
|
---|
| 267 | default: error(usage, NIL_PTR);
|
---|
| 268 | }
|
---|
| 269 | }
|
---|
| 270 |
|
---|
| 271 | if (creat_fl + ext_fl + show_fl != 1) error(usage, NIL_PTR);
|
---|
| 272 |
|
---|
| 273 | if (strcmp(argv[2], "-") == 0)/* only - means stdin/stdout - KS */
|
---|
| 274 | tar_fd = creat_fl ? 1 : 0; /* '-' means used
|
---|
| 275 | * stdin/stdout -Dal */
|
---|
| 276 | else
|
---|
| 277 | tar_fd = creat_fl ? creat(argv[2], 0666) : open(argv[2], O_RDONLY);
|
---|
| 278 |
|
---|
| 279 | if (tar_fd < 0) error("Cannot open ", argv[2]);
|
---|
| 280 |
|
---|
| 281 | if (geteuid()) { /* check if super-user */
|
---|
| 282 | int save_umask;
|
---|
| 283 | save_umask = umask(0);
|
---|
| 284 | u_mask = ~save_umask;
|
---|
| 285 | umask(save_umask);
|
---|
| 286 | chown_flag = TRUE; /* normal user can't chown */
|
---|
| 287 | } else
|
---|
| 288 | u_mask = ~0; /* don't restrict if 'privileged utility' */
|
---|
| 289 |
|
---|
| 290 | ar_dev = -1; /* impossible device nr */
|
---|
| 291 | if (creat_fl) {
|
---|
| 292 | if (tar_fd > 1 && fstat(tar_fd, &st) < 0)
|
---|
| 293 | error("Can't stat ", argv[2]); /* will never be here,
|
---|
| 294 | * right? */
|
---|
| 295 | else { /* get archive inode & device */
|
---|
| 296 | ar_inode = st.st_ino; /* save files inode */
|
---|
| 297 | ar_dev = st.st_dev; /* save files device */
|
---|
| 298 | } /* marks@mgse Mon Sep 25 11:30:45 CDT 1989 */
|
---|
| 299 |
|
---|
| 300 | for (i = 3; i < argc; i++) {
|
---|
| 301 | add_file(argv[i]);
|
---|
| 302 | path[0] = '\0';
|
---|
| 303 | }
|
---|
| 304 | adjust_boundary();
|
---|
| 305 | } else if (ext_fl) {
|
---|
| 306 | /* Extraction code moved here from tarfile() MSP */
|
---|
| 307 | while (get_header()) {
|
---|
| 308 | mem_name = header.member.m_name;
|
---|
| 309 | if (is_dir(mem_name)) {
|
---|
| 310 | for (ptr = mem_name; *ptr; ptr++);
|
---|
| 311 | *(ptr - 1) = '\0';
|
---|
| 312 | header.dbuf.typeflag = '5';
|
---|
| 313 | }
|
---|
| 314 | for (i = 3; i < argc; i++)
|
---|
| 315 | if (!strncmp(argv[i], mem_name, strlen(argv[i])))
|
---|
| 316 | break;
|
---|
| 317 | if (argc == 3 || (i < argc)) {
|
---|
| 318 | extract(mem_name);
|
---|
| 319 | } else if (header.dbuf.typeflag == '0' ||
|
---|
| 320 | header.dbuf.typeflag == 0 ||
|
---|
| 321 | header.dbuf.typeflag == ' ')
|
---|
| 322 | skip_entry();
|
---|
| 323 | flush();
|
---|
| 324 | }
|
---|
| 325 | } else
|
---|
| 326 | tarfile(); /* tarfile() justs prints info. now MSP */
|
---|
| 327 |
|
---|
| 328 | flush();
|
---|
| 329 | return(0);
|
---|
| 330 | }
|
---|
| 331 |
|
---|
| 332 | BOOL get_header()
|
---|
| 333 | {
|
---|
| 334 | register int check;
|
---|
| 335 |
|
---|
| 336 | mread(tar_fd, (char *) &header, sizeof(header));
|
---|
| 337 | if (header.member.m_name[0] == '\0') return FALSE;
|
---|
| 338 |
|
---|
| 339 | if (force_flag) /* skip checksum verification -Dal */
|
---|
| 340 | return TRUE;
|
---|
| 341 |
|
---|
| 342 | check = (int) convert(header.member.m_checksum, INT_TYPE);
|
---|
| 343 |
|
---|
| 344 | if (check != checksum()) error("Tar: header checksum error.", NIL_PTR);
|
---|
| 345 |
|
---|
| 346 | return TRUE;
|
---|
| 347 | }
|
---|
| 348 |
|
---|
| 349 | /* Tarfile() just lists info about archive now; as of the t flag. */
|
---|
| 350 | /* Extraction has been moved into main() as that needs access to argv[] */
|
---|
| 351 |
|
---|
| 352 | void tarfile()
|
---|
| 353 | {
|
---|
| 354 | register char *mem_name;
|
---|
| 355 |
|
---|
| 356 | while (get_header()) {
|
---|
| 357 | mem_name = header.member.m_name;
|
---|
| 358 | string_print(NIL_PTR, "%s%s", mem_name,
|
---|
| 359 | (verbose_flag ? " " : "\n"));
|
---|
| 360 | switch (header.dbuf.typeflag) {
|
---|
| 361 | case '1':
|
---|
| 362 | verb_print("linked to", header.dbuf.linkname);
|
---|
| 363 | break;
|
---|
| 364 | case '2':
|
---|
| 365 | verb_print("symbolic link to", header.dbuf.linkname);
|
---|
| 366 | break;
|
---|
| 367 | case '6': verb_print("", "fifo"); break;
|
---|
| 368 | case '3':
|
---|
| 369 | case '4':
|
---|
| 370 | if (verbose_flag) {
|
---|
| 371 | char sizebuf[TSIZLEN + 1];
|
---|
| 372 |
|
---|
| 373 | strncpy(sizebuf, header.dbuf.size, (size_t) TSIZLEN);
|
---|
| 374 | sizebuf[TSIZLEN] = 0;
|
---|
| 375 | string_print(NIL_PTR,
|
---|
| 376 | "%s special file major %s minor %s\n",
|
---|
| 377 | (header.dbuf.typeflag == '3' ?
|
---|
| 378 | "character" : "block"),
|
---|
| 379 | header.dbuf.devmajor,
|
---|
| 380 | header.dbuf.devminor,
|
---|
| 381 | sizebuf);
|
---|
| 382 | }
|
---|
| 383 | break;
|
---|
| 384 | case '0': /* official POSIX */
|
---|
| 385 | case 0: /* also mentioned in POSIX */
|
---|
| 386 | case ' ': /* ofetn used */
|
---|
| 387 | if (!is_dir(mem_name)) {
|
---|
| 388 | if (verbose_flag)
|
---|
| 389 | string_print(NIL_PTR, "%d tape blocks\n",
|
---|
| 390 | block_size());
|
---|
| 391 | skip_entry();
|
---|
| 392 | break;
|
---|
| 393 | } else /* FALL TROUGH */
|
---|
| 394 | case '5':
|
---|
| 395 | verb_print("", "directory");
|
---|
| 396 | break;
|
---|
| 397 | default:
|
---|
| 398 | string_print(NIL_PTR, "not recogised item %d\n",
|
---|
| 399 | header.dbuf.typeflag);
|
---|
| 400 | }
|
---|
| 401 | flush();
|
---|
| 402 | }
|
---|
| 403 | }
|
---|
| 404 |
|
---|
| 405 | void skip_entry()
|
---|
| 406 | {
|
---|
| 407 | register int blocks = block_size();
|
---|
| 408 |
|
---|
| 409 | while (blocks--) (void) bread(tar_fd, io_buffer, TBLOCK_SIZE);
|
---|
| 410 | }
|
---|
| 411 |
|
---|
| 412 | void extract(file)
|
---|
| 413 | register char *file;
|
---|
| 414 | {
|
---|
| 415 | register int fd, r;
|
---|
| 416 | char *pd1, *pd2; /* walk thru failed directory path */
|
---|
| 417 |
|
---|
| 418 | switch (header.dbuf.typeflag) {
|
---|
| 419 | case '1': /* Link */
|
---|
| 420 | delete(file);
|
---|
| 421 | if (link(header.member.m_link, file) < 0)
|
---|
| 422 | string_print(NIL_PTR, "Cannot link %s to %s: %s\n",
|
---|
| 423 | header.member.m_link, file, strerror(errno));
|
---|
| 424 | else if (verbose_flag)
|
---|
| 425 | string_print(NIL_PTR, "Linked %s to %s\n",
|
---|
| 426 | header.member.m_link, file);
|
---|
| 427 | return;
|
---|
| 428 | case '5': /* directory */
|
---|
| 429 | if (!(file[0] == '.' && file[1] == '\0')) delete(file);
|
---|
| 430 | if ((file[0] == '.' && file[1] == '\0') || mkdir(file, 0700) == 0) {
|
---|
| 431 | do_chown(file);
|
---|
| 432 | verb_print("created directory", file);
|
---|
| 433 | } else {
|
---|
| 434 | string_print(NIL_PTR, "Can't make directory %s: %s\n",
|
---|
| 435 | file, strerror(errno));
|
---|
| 436 | }
|
---|
| 437 | return;
|
---|
| 438 | case '3': /* character special */
|
---|
| 439 | case '4': /* block special */
|
---|
| 440 | {
|
---|
| 441 | int dmajor, dminor, mode;
|
---|
| 442 |
|
---|
| 443 | dmajor = (int) convert(header.dbuf.devmajor, INT_TYPE);
|
---|
| 444 | dminor = (int) convert(header.dbuf.devminor, INT_TYPE);
|
---|
| 445 | mode = (header.dbuf.typeflag == '3' ? S_IFCHR : S_IFBLK);
|
---|
| 446 | delete(file);
|
---|
| 447 | if (mknod(file, mode, (dmajor << 8 | dminor)) == 0) {
|
---|
| 448 | if (verbose_flag) string_print(NIL_PTR,
|
---|
| 449 | "made %s special file major %s minor %s\n",
|
---|
| 450 | (header.dbuf.typeflag == '3' ?
|
---|
| 451 | "character" : "block"),
|
---|
| 452 | header.dbuf.devmajor,
|
---|
| 453 | header.dbuf.devminor);
|
---|
| 454 | do_chown(file);
|
---|
| 455 | }
|
---|
| 456 | else
|
---|
| 457 | {
|
---|
| 458 | string_print(NIL_PTR,
|
---|
| 459 | "cannot make %s special file major %s minor %s: %s\n",
|
---|
| 460 | (header.dbuf.typeflag == '3' ?
|
---|
| 461 | "character" : "block"),
|
---|
| 462 | header.dbuf.devmajor,
|
---|
| 463 | header.dbuf.devminor,
|
---|
| 464 | strerror(errno));
|
---|
| 465 | }
|
---|
| 466 | return;
|
---|
| 467 | }
|
---|
| 468 | case '2': /* symbolic link */
|
---|
| 469 | #ifdef HAVE_SYMLINK
|
---|
| 470 | delete(file);
|
---|
| 471 | if (symlink(header.member.m_link, file) < 0)
|
---|
| 472 | string_print(NIL_PTR, "Cannot make symbolic link %s to %s: %s\n",
|
---|
| 473 | header.member.m_link, file, strerror(errno));
|
---|
| 474 | else if (verbose_flag)
|
---|
| 475 | string_print(NIL_PTR, "Symbolic link %s to %s\n",
|
---|
| 476 | header.member.m_link, file);
|
---|
| 477 | return;
|
---|
| 478 | #endif
|
---|
| 479 | case '7': /* contiguous file -- what is this (KS) */
|
---|
| 480 | print("Not implemented file type\n");
|
---|
| 481 | return; /* not implemented, but break out */
|
---|
| 482 | #ifdef HAVE_FIFO
|
---|
| 483 | case '6': /* fifo */
|
---|
| 484 | delete(file);
|
---|
| 485 | if (mkfifo(file, 0) == 0) { /* is chmod'ed in do_chown */
|
---|
| 486 | do_chown(file);
|
---|
| 487 | verb_print("made fifo", file);
|
---|
| 488 | } else
|
---|
| 489 | string_print(NIL_PTR, "Can't make fifo %s: %s\n",
|
---|
| 490 | file, strerror(errno));
|
---|
| 491 | return;
|
---|
| 492 | #endif
|
---|
| 493 | }
|
---|
| 494 |
|
---|
| 495 | /* Create regular file. If failure, try to make missing directories. */
|
---|
| 496 | if ((fd = creat(file, 0600)) < 0) {
|
---|
| 497 | pd1 = file;
|
---|
| 498 | while ((pd2 = index(pd1, '/')) > (char *) 0) {
|
---|
| 499 | *pd2 = '\0';
|
---|
| 500 | if (access(file, 1) < 0)
|
---|
| 501 | if (mkdir(file, 0777) < 0) {
|
---|
| 502 | string_print(NIL_PTR, "Cannot mkdir %s: %s\n",
|
---|
| 503 | file, strerror(errno));
|
---|
| 504 | return;
|
---|
| 505 | } else
|
---|
| 506 | string_print(NIL_PTR, "Made directory %s\n", file);
|
---|
| 507 | *pd2 = '/';
|
---|
| 508 | pd1 = ++pd2;
|
---|
| 509 | }
|
---|
| 510 | if ((fd = creat(file, 0600)) < 0) {
|
---|
| 511 | string_print(NIL_PTR, "Cannot create %s: %s\n",
|
---|
| 512 | file, strerror(errno));
|
---|
| 513 | return;
|
---|
| 514 | }
|
---|
| 515 | }
|
---|
| 516 | copy(file, tar_fd, fd, convert(header.member.m_size, LONG_TYPE));
|
---|
| 517 | (void) close(fd);
|
---|
| 518 |
|
---|
| 519 | do_chown(file);
|
---|
| 520 | }
|
---|
| 521 |
|
---|
| 522 | void delete(file)
|
---|
| 523 | char *file;
|
---|
| 524 | {
|
---|
| 525 | /* remove a file or an empty directory */
|
---|
| 526 | struct stat stbuf;
|
---|
| 527 |
|
---|
| 528 | if (stat(file, &stbuf) < 0) return;
|
---|
| 529 |
|
---|
| 530 | if (S_ISDIR(stbuf.st_mode)) (void) rmdir(file); else (void) unlink(file);
|
---|
| 531 | /* leave error reporting to the create following soon. */
|
---|
| 532 | }
|
---|
| 533 |
|
---|
| 534 | void do_chown(file)
|
---|
| 535 | char *file;
|
---|
| 536 | {
|
---|
| 537 | int uid = -1, gid = -1; /* these are illegal ??? -- KS */
|
---|
| 538 |
|
---|
| 539 | if (!chown_flag) { /* set correct owner and group -Dal */
|
---|
| 540 | if (header.dbuf.magic[TMAGLEN] == ' ')
|
---|
| 541 | header.dbuf.magic[TMAGLEN] = '\0'; /* some tars out there
|
---|
| 542 | * ... */
|
---|
| 543 | if (strncmp(TMAGIC, header.dbuf.magic, (size_t) TMAGLEN)) {
|
---|
| 544 | struct passwd *pwd;
|
---|
| 545 | struct group *grp;
|
---|
| 546 |
|
---|
| 547 | pwd = getpwnam(header.dbuf.uname);
|
---|
| 548 | if (pwd != NULL) uid = pwd->pw_uid;
|
---|
| 549 | grp = getgrnam(header.dbuf.gname);
|
---|
| 550 | if (grp != NULL) gid = grp->gr_gid;
|
---|
| 551 | }
|
---|
| 552 | if (uid == -1) uid = (int) convert(header.member.m_uid, INT_TYPE);
|
---|
| 553 | if (gid == -1) gid = (int) convert(header.member.m_gid, INT_TYPE);
|
---|
| 554 | chown(file, uid, gid);
|
---|
| 555 | }
|
---|
| 556 | chmod(file, u_mask & (int) convert(header.member.m_mode, INT_TYPE));
|
---|
| 557 |
|
---|
| 558 | /* Should there be a timestamp if the chown failes? -- KS */
|
---|
| 559 | timestamp(file);
|
---|
| 560 |
|
---|
| 561 | }
|
---|
| 562 |
|
---|
| 563 | void timestamp(file)
|
---|
| 564 | char *file;
|
---|
| 565 | {
|
---|
| 566 | struct utimbuf buf;
|
---|
| 567 |
|
---|
| 568 | buf.modtime = buf.actime = convert(header.dbuf.mtime, LONG_TYPE);
|
---|
| 569 | utime(file, &buf);
|
---|
| 570 | }
|
---|
| 571 |
|
---|
| 572 | void copy(file, from, to, bytes)
|
---|
| 573 | char *file;
|
---|
| 574 | int from, to;
|
---|
| 575 | register long bytes;
|
---|
| 576 | {
|
---|
| 577 | register int rest;
|
---|
| 578 | int blocks = (int) ((bytes + (long) TBLOCK_SIZE - 1) / (long) TBLOCK_SIZE);
|
---|
| 579 |
|
---|
| 580 | if (verbose_flag)
|
---|
| 581 | string_print(NIL_PTR, "%s, %d tape blocks\n", file, blocks);
|
---|
| 582 |
|
---|
| 583 | while (blocks--) {
|
---|
| 584 | (void) bread(from, io_buffer, TBLOCK_SIZE);
|
---|
| 585 | rest = (bytes > (long) TBLOCK_SIZE) ? TBLOCK_SIZE : (int) bytes;
|
---|
| 586 | mwrite(to, io_buffer, (to == tar_fd) ? TBLOCK_SIZE : rest);
|
---|
| 587 | bytes -= (long) rest;
|
---|
| 588 | }
|
---|
| 589 | }
|
---|
| 590 |
|
---|
| 591 | long convert(str, type)
|
---|
| 592 | char str[];
|
---|
| 593 | int type;
|
---|
| 594 | {
|
---|
| 595 | register long ac = 0L;
|
---|
| 596 | register int i;
|
---|
| 597 |
|
---|
| 598 | for (i = 0; i < type; i++) {
|
---|
| 599 | if (str[i] >= '0' && str[i] <= '7') {
|
---|
| 600 | ac <<= 3;
|
---|
| 601 | ac += (long) (str[i] - '0');
|
---|
| 602 | }
|
---|
| 603 | }
|
---|
| 604 |
|
---|
| 605 | return ac;
|
---|
| 606 | }
|
---|
| 607 |
|
---|
| 608 | int checksum()
|
---|
| 609 | {
|
---|
| 610 | register char *ptr = header.member.m_checksum;
|
---|
| 611 | register int ac = 0;
|
---|
| 612 |
|
---|
| 613 | while (ptr < &header.member.m_checksum[INT_TYPE]) *ptr++ = ' ';
|
---|
| 614 |
|
---|
| 615 | ptr = header.hdr_block;
|
---|
| 616 | while (ptr < &header.hdr_block[TBLOCK_SIZE]) ac += *ptr++;
|
---|
| 617 |
|
---|
| 618 | return ac;
|
---|
| 619 | }
|
---|
| 620 |
|
---|
| 621 | int is_dir(file)
|
---|
| 622 | register char *file;
|
---|
| 623 | {
|
---|
| 624 | while (*file++ != '\0');
|
---|
| 625 |
|
---|
| 626 | return(*(file - 2) == '/');
|
---|
| 627 | }
|
---|
| 628 |
|
---|
| 629 |
|
---|
| 630 | char *path_name(file)
|
---|
| 631 | register char *file;
|
---|
| 632 | {
|
---|
| 633 |
|
---|
| 634 | string_print(pathname, "%s%s", path, file);
|
---|
| 635 | return pathname;
|
---|
| 636 | }
|
---|
| 637 |
|
---|
| 638 | void add_path(name)
|
---|
| 639 | register char *name;
|
---|
| 640 | {
|
---|
| 641 | register char *path_ptr = path;
|
---|
| 642 |
|
---|
| 643 | while (*path_ptr) path_ptr++;
|
---|
| 644 |
|
---|
| 645 | if (name == NIL_PTR) {
|
---|
| 646 | while (*path_ptr-- != '/');
|
---|
| 647 | while (*path_ptr != '/' && path_ptr != path) path_ptr--;
|
---|
| 648 | if (*path_ptr == '/') path_ptr++;
|
---|
| 649 | *path_ptr = '\0';
|
---|
| 650 | } else {
|
---|
| 651 | while (*name) {
|
---|
| 652 | if (path_ptr == &path[NAME_SIZE])
|
---|
| 653 | error("Pathname too long", NIL_PTR);
|
---|
| 654 | *path_ptr++ = *name++;
|
---|
| 655 | }
|
---|
| 656 | *path_ptr++ = '/';
|
---|
| 657 | *path_ptr = '\0';
|
---|
| 658 | }
|
---|
| 659 | }
|
---|
| 660 |
|
---|
| 661 | /*
|
---|
| 662 | * add a file to the archive
|
---|
| 663 | */
|
---|
| 664 | void add_file(file)
|
---|
| 665 | register char *file;
|
---|
| 666 | {
|
---|
| 667 | struct stat st;
|
---|
| 668 | char *linkname;
|
---|
| 669 | register int fd = -1;
|
---|
| 670 | char namebuf[16]; /* -Dal */
|
---|
| 671 | char cwd[129]; /* -KS */
|
---|
| 672 |
|
---|
| 673 | #ifdef HAVE_SYMLINK
|
---|
| 674 | if (lstat(file, &st) < 0) {
|
---|
| 675 | #else
|
---|
| 676 | if (stat(file, &st) < 0) {
|
---|
| 677 | #endif
|
---|
| 678 | string_print(NIL_PTR, "%s: %s\n", file, strerror(errno));
|
---|
| 679 | return;
|
---|
| 680 | }
|
---|
| 681 | if (st.st_dev == ar_dev && st.st_ino == ar_inode) {
|
---|
| 682 | string_print(NIL_PTR, "Cannot tar current archive file (%s)\n", file);
|
---|
| 683 | return;
|
---|
| 684 | } /* marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
|
---|
| 685 | if ((fd = add_open(file, &st)) < 0) {
|
---|
| 686 | string_print(NIL_PTR, "Cannot open %s\n", file);
|
---|
| 687 | return;
|
---|
| 688 | }
|
---|
| 689 | make_header(path_name(file), &st);
|
---|
| 690 | if ((linkname = is_linked(&st)) != NULL) {
|
---|
| 691 | strncpy(header.dbuf.linkname, linkname, (size_t) NAMSIZ);
|
---|
| 692 | header.dbuf.typeflag = '1';
|
---|
| 693 | if (verbose_flag) string_print(NIL_PTR, "linked %s to %s\n",
|
---|
| 694 | header.dbuf.linkname, file);
|
---|
| 695 | string_print(header.member.m_checksum, "%I ", checksum());
|
---|
| 696 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 697 | } else {
|
---|
| 698 | is_added(&st, file);
|
---|
| 699 | switch (st.st_mode & S_IFMT) {
|
---|
| 700 | case S_IFREG:
|
---|
| 701 | header.dbuf.typeflag = '0';
|
---|
| 702 | string_print(header.member.m_checksum, "%I ", checksum());
|
---|
| 703 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 704 | copy(path_name(file), fd, tar_fd, (long) st.st_size);
|
---|
| 705 | break;
|
---|
| 706 | case S_IFDIR:
|
---|
| 707 | header.dbuf.typeflag = '5';
|
---|
| 708 | string_print(header.member.m_checksum, "%I ", checksum());
|
---|
| 709 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 710 | verb_print("read directory", file);
|
---|
| 711 | if (norec_flag) break;
|
---|
| 712 | if (NULL == getcwd(cwd, (int) sizeof cwd))
|
---|
| 713 | string_print(NIL_PTR, "Error: cannot getcwd()\n");
|
---|
| 714 | else if (chdir(file) < 0)
|
---|
| 715 | string_print(NIL_PTR, "Cannot chdir to %s: %s\n",
|
---|
| 716 | file, strerror(errno));
|
---|
| 717 | else {
|
---|
| 718 | add_path(file);
|
---|
| 719 | #ifdef DIRECT_3
|
---|
| 720 | {
|
---|
| 721 | DIR *dirp;
|
---|
| 722 | struct direct *dp;
|
---|
| 723 | struct stat dst;
|
---|
| 724 |
|
---|
| 725 | add_close(fd);
|
---|
| 726 | fd= 0;
|
---|
| 727 | dirp = opendir(".");
|
---|
| 728 | while (NULL != (dp = readdir(dirp)))
|
---|
| 729 | if (strcmp(dp->d_name, ".") == 0)
|
---|
| 730 | is_linked(&st);
|
---|
| 731 | else if (strcmp(dp->d_name, "..") == 0) {
|
---|
| 732 | if (stat("..", &dst) == 0)
|
---|
| 733 | is_linked(&dst);
|
---|
| 734 | } else {
|
---|
| 735 | strcpy(namebuf, dp->d_name);
|
---|
| 736 | add_file(namebuf);
|
---|
| 737 | }
|
---|
| 738 | closedir(dirp);
|
---|
| 739 | }
|
---|
| 740 | #else
|
---|
| 741 | {
|
---|
| 742 | int i;
|
---|
| 743 | struct direct dir;
|
---|
| 744 | struct stat dst;
|
---|
| 745 |
|
---|
| 746 | for (i = 0; i < 2; i++) { /* . and .. */
|
---|
| 747 | mread(fd, &dir, sizeof(dir));
|
---|
| 748 | if (strcmp(dir.d_name, ".") == 0)
|
---|
| 749 | is_linked(&st);
|
---|
| 750 | else if (strcmp(dir.d_name, "..") == 0) {
|
---|
| 751 | if (stat("..", &dst) == 0)
|
---|
| 752 | is_linked(&dst);
|
---|
| 753 | } else
|
---|
| 754 | break;
|
---|
| 755 | }
|
---|
| 756 | while (bread(fd, &dir, sizeof(dir)) == sizeof(dir))
|
---|
| 757 | if (dir.d_ino) {
|
---|
| 758 | strncpy(namebuf, dir.d_name,
|
---|
| 759 | (size_t) DIRSIZ);
|
---|
| 760 | namebuf[DIRSIZ] = '\0';
|
---|
| 761 | add_file(namebuf);
|
---|
| 762 | }
|
---|
| 763 | }
|
---|
| 764 | #endif
|
---|
| 765 | chdir(cwd);
|
---|
| 766 | add_path(NIL_PTR);
|
---|
| 767 | *file = 0;
|
---|
| 768 | }
|
---|
| 769 | break;
|
---|
| 770 | #ifdef HAVE_SYMLINK
|
---|
| 771 | case S_IFLNK:
|
---|
| 772 | {
|
---|
| 773 | int i;
|
---|
| 774 |
|
---|
| 775 | header.dbuf.typeflag = '2';
|
---|
| 776 | verb_print("read symlink", file);
|
---|
| 777 | i = readlink(file,
|
---|
| 778 | header.dbuf.linkname,
|
---|
| 779 | sizeof(header.dbuf.linkname) - 1);
|
---|
| 780 | if (i < 0) {
|
---|
| 781 | string_print(NIL_PTR,
|
---|
| 782 | "Cannot read symbolic link %s: %s\n",
|
---|
| 783 | file, strerror(errno));
|
---|
| 784 | return;
|
---|
| 785 | }
|
---|
| 786 | header.dbuf.linkname[i] = 0;
|
---|
| 787 | string_print(header.member.m_checksum, "%I ", checksum());
|
---|
| 788 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 789 | break;
|
---|
| 790 | }
|
---|
| 791 | #endif
|
---|
| 792 | #ifdef HAVE_FIFO
|
---|
| 793 | case S_IFIFO:
|
---|
| 794 | header.dbuf.typeflag = '6';
|
---|
| 795 | verb_print("read fifo", file);
|
---|
| 796 | string_print(header.member.m_checksum, "%I ", checksum());
|
---|
| 797 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 798 | break;
|
---|
| 799 | #endif
|
---|
| 800 | case S_IFBLK:
|
---|
| 801 | header.dbuf.typeflag = '4';
|
---|
| 802 | if (verbose_flag) {
|
---|
| 803 | char sizebuf[TSIZLEN + 1];
|
---|
| 804 |
|
---|
| 805 | strncpy(sizebuf, header.dbuf.size, (size_t) TSIZLEN);
|
---|
| 806 | sizebuf[TSIZLEN] = 0;
|
---|
| 807 | string_print(NIL_PTR,
|
---|
| 808 | "read block device %s major %s minor %s\n",
|
---|
| 809 | file, header.dbuf.devmajor, header.dbuf.devminor, sizebuf);
|
---|
| 810 | }
|
---|
| 811 | string_print(header.member.m_checksum, "%I ", checksum());
|
---|
| 812 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 813 | break;
|
---|
| 814 | case S_IFCHR:
|
---|
| 815 | header.dbuf.typeflag = '3';
|
---|
| 816 | if (verbose_flag) string_print(NIL_PTR,
|
---|
| 817 | "read character device %s major %s minor %s\n",
|
---|
| 818 | file, header.dbuf.devmajor, header.dbuf.devminor);
|
---|
| 819 | string_print(header.member.m_checksum, "%I ", checksum());
|
---|
| 820 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 821 | break;
|
---|
| 822 | default:
|
---|
| 823 | is_deleted(&st);
|
---|
| 824 | string_print(NIL_PTR, "Tar: %s unknown file type. Not added.\n", file);
|
---|
| 825 | *file = 0;
|
---|
| 826 | }
|
---|
| 827 | }
|
---|
| 828 |
|
---|
| 829 | flush();
|
---|
| 830 | add_close(fd);
|
---|
| 831 | }
|
---|
| 832 |
|
---|
| 833 | void verb_print(s1, s2)
|
---|
| 834 | char *s1, *s2;
|
---|
| 835 | {
|
---|
| 836 | if (verbose_flag) string_print(NIL_PTR, "%s: %s\n", s1, s2);
|
---|
| 837 | }
|
---|
| 838 |
|
---|
| 839 | void add_close(fd)
|
---|
| 840 | int fd;
|
---|
| 841 | {
|
---|
| 842 | if (fd != 0) close(fd);
|
---|
| 843 | }
|
---|
| 844 |
|
---|
| 845 | /*
|
---|
| 846 | * open file 'file' to be added to archive, return file descriptor
|
---|
| 847 | */
|
---|
| 848 | int add_open(file, st)
|
---|
| 849 | char *file;
|
---|
| 850 | struct stat *st;
|
---|
| 851 | {
|
---|
| 852 | int fd;
|
---|
| 853 | if (((st->st_mode & S_IFMT) != S_IFREG) &&
|
---|
| 854 | ((st->st_mode & S_IFMT) != S_IFDIR))
|
---|
| 855 | return 0;
|
---|
| 856 | fd = open(file, O_RDONLY);
|
---|
| 857 | if (fd == -1)
|
---|
| 858 | fprintf(stderr, "open failed: %s\n", strerror(errno));
|
---|
| 859 | return fd;
|
---|
| 860 | }
|
---|
| 861 |
|
---|
| 862 | void make_header(file, st)
|
---|
| 863 | char *file;
|
---|
| 864 | register struct stat *st;
|
---|
| 865 | {
|
---|
| 866 | register char *ptr = header.member.m_name;
|
---|
| 867 | struct passwd *pwd;
|
---|
| 868 | struct group *grp;
|
---|
| 869 |
|
---|
| 870 | clear_header();
|
---|
| 871 |
|
---|
| 872 | while (*ptr++ = *file++);
|
---|
| 873 |
|
---|
| 874 | if ((st->st_mode & S_IFMT) == S_IFDIR) { /* fixed test -Dal */
|
---|
| 875 | *(ptr - 1) = '/';
|
---|
| 876 | }
|
---|
| 877 | string_print(header.member.m_mode, "%I ", st->st_mode & 07777);
|
---|
| 878 | string_print(header.member.m_uid, "%I ", st->st_uid);
|
---|
| 879 | string_print(header.member.m_gid, "%I ", st->st_gid);
|
---|
| 880 | if ((st->st_mode & S_IFMT) == S_IFREG)
|
---|
| 881 | string_print(header.member.m_size, "%L ", st->st_size);
|
---|
| 882 | else
|
---|
| 883 | strncpy(header.dbuf.size, "0", (size_t) TSIZLEN);
|
---|
| 884 | string_print(header.member.m_time, "%L ", st->st_mtime);
|
---|
| 885 | strncpy(header.dbuf.magic, TMAGIC, (size_t) TMAGLEN);
|
---|
| 886 | header.dbuf.version[0] = 0;
|
---|
| 887 | header.dbuf.version[1] = 0;
|
---|
| 888 | pwd = getpwuid(st->st_uid);
|
---|
| 889 | strncpy(header.dbuf.uname,
|
---|
| 890 | (pwd != NULL ? pwd->pw_name : "nobody"), TUNMLEN);
|
---|
| 891 | grp = getgrgid(st->st_gid);
|
---|
| 892 | strncpy(header.dbuf.gname,
|
---|
| 893 | (grp != NULL ? grp->gr_name : "nobody"), TGNMLEN);
|
---|
| 894 | if (st->st_mode & (S_IFBLK | S_IFCHR)) {
|
---|
| 895 | string_print(header.dbuf.devmajor, "%I ", (st->st_rdev >> 8));
|
---|
| 896 | string_print(header.dbuf.devminor, "%I ", (st->st_rdev & 0xFF));
|
---|
| 897 | }
|
---|
| 898 | header.dbuf.prefix[0] = 0;
|
---|
| 899 | }
|
---|
| 900 |
|
---|
| 901 | void is_added(st, file)
|
---|
| 902 | struct stat *st;
|
---|
| 903 | char *file;
|
---|
| 904 | {
|
---|
| 905 | struct link *new;
|
---|
| 906 | char *name;
|
---|
| 907 |
|
---|
| 908 | if ((*file == 0) || (st->st_nlink == 1)) return;
|
---|
| 909 | name = path_name(file);
|
---|
| 910 | new = (struct link *) malloc(sizeof(struct link) + strlen(name));
|
---|
| 911 | if (new == NULL) {
|
---|
| 912 | print("Out of memory\n");
|
---|
| 913 | return;
|
---|
| 914 | }
|
---|
| 915 | new->next = link_top;
|
---|
| 916 | new->dev = st->st_dev;
|
---|
| 917 | new->ino = st->st_ino;
|
---|
| 918 | new->nlink = st->st_nlink - 1;
|
---|
| 919 | strcpy(new->name, name);
|
---|
| 920 | link_top = new;
|
---|
| 921 | }
|
---|
| 922 |
|
---|
| 923 | void is_deleted(st)
|
---|
| 924 | struct stat *st;
|
---|
| 925 | {
|
---|
| 926 | struct link *old;
|
---|
| 927 |
|
---|
| 928 | if ((old = link_top) != NULL) {
|
---|
| 929 | link_top = old->next;
|
---|
| 930 | free(old);
|
---|
| 931 | }
|
---|
| 932 | }
|
---|
| 933 |
|
---|
| 934 | char *is_linked(st)
|
---|
| 935 | struct stat *st;
|
---|
| 936 | {
|
---|
| 937 | struct link *cur = link_top;
|
---|
| 938 | struct link **pre = &link_top;
|
---|
| 939 | static char name[NAMSIZ];
|
---|
| 940 |
|
---|
| 941 | while (cur != NULL)
|
---|
| 942 | if ((cur->dev != st->st_dev) || (cur->ino != st->st_ino)) {
|
---|
| 943 | pre = &cur->next;
|
---|
| 944 | cur = cur->next;
|
---|
| 945 | } else {
|
---|
| 946 | if (--cur->nlink == 0) {
|
---|
| 947 | *pre = cur->next;
|
---|
| 948 | strncpy(name, cur->name, NAMSIZ);
|
---|
| 949 | return name;
|
---|
| 950 | }
|
---|
| 951 | return cur->name;
|
---|
| 952 | }
|
---|
| 953 | return NULL;
|
---|
| 954 | }
|
---|
| 955 |
|
---|
| 956 | void clear_header()
|
---|
| 957 | {
|
---|
| 958 | register char *ptr = header.hdr_block;
|
---|
| 959 |
|
---|
| 960 | while (ptr < &header.hdr_block[TBLOCK_SIZE]) *ptr++ = '\0';
|
---|
| 961 | }
|
---|
| 962 |
|
---|
| 963 | void adjust_boundary()
|
---|
| 964 | {
|
---|
| 965 | clear_header();
|
---|
| 966 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 967 | #ifndef POSIX_COMP
|
---|
| 968 | while (total_blocks++ < BLOCK_BOUNDARY)
|
---|
| 969 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 970 | #else
|
---|
| 971 | mwrite(tar_fd, (char *) &header, sizeof(header));
|
---|
| 972 | #endif
|
---|
| 973 | (void) close(tar_fd);
|
---|
| 974 | }
|
---|
| 975 |
|
---|
| 976 | void mread(fd, address, bytes)
|
---|
| 977 | int fd, bytes;
|
---|
| 978 | char *address;
|
---|
| 979 | {
|
---|
| 980 | if (bread(fd, address, bytes) != bytes) error("Tar: read error.", NIL_PTR);
|
---|
| 981 | }
|
---|
| 982 |
|
---|
| 983 | void mwrite(fd, address, bytes)
|
---|
| 984 | int fd, bytes;
|
---|
| 985 | char *address;
|
---|
| 986 | {
|
---|
| 987 | if (bwrite(fd, address, bytes) != bytes) error("Tar: write error.", NIL_PTR);
|
---|
| 988 |
|
---|
| 989 | total_blocks++;
|
---|
| 990 | }
|
---|
| 991 |
|
---|
| 992 | int bread(fd, address, bytes)
|
---|
| 993 | int fd, bytes;
|
---|
| 994 | char *address;
|
---|
| 995 | {
|
---|
| 996 | int n = 0, r;
|
---|
| 997 |
|
---|
| 998 | while (n < bytes) {
|
---|
| 999 | if ((r = read(fd, address + n, bytes - n)) <= 0) {
|
---|
| 1000 | if (r < 0) return r;
|
---|
| 1001 | break;
|
---|
| 1002 | }
|
---|
| 1003 | n += r;
|
---|
| 1004 | }
|
---|
| 1005 | return n;
|
---|
| 1006 | }
|
---|
| 1007 |
|
---|
| 1008 | int bwrite(fd, address, bytes)
|
---|
| 1009 | int fd, bytes;
|
---|
| 1010 | char *address;
|
---|
| 1011 | {
|
---|
| 1012 | int n = 0, r;
|
---|
| 1013 |
|
---|
| 1014 | while (n < bytes) {
|
---|
| 1015 | if ((r = write(fd, address + n, bytes - n)) <= 0) {
|
---|
| 1016 | if (r < 0) return r;
|
---|
| 1017 | break;
|
---|
| 1018 | }
|
---|
| 1019 | n += r;
|
---|
| 1020 | }
|
---|
| 1021 | return n;
|
---|
| 1022 | }
|
---|
| 1023 |
|
---|
| 1024 | char output[TBLOCK_SIZE];
|
---|
| 1025 | void print(str)
|
---|
| 1026 | register char *str;
|
---|
| 1027 | {
|
---|
| 1028 | int fd = (tar_fd == 1 ? 2 : 1);
|
---|
| 1029 | static int indx = 0;
|
---|
| 1030 |
|
---|
| 1031 | if (str == NIL_PTR) {
|
---|
| 1032 | write(fd, output, indx);
|
---|
| 1033 | indx = 0;
|
---|
| 1034 | return;
|
---|
| 1035 | }
|
---|
| 1036 | while (*str) {
|
---|
| 1037 | output[indx++] = *str++;
|
---|
| 1038 | if (indx == TBLOCK_SIZE) {
|
---|
| 1039 | write(fd, output, TBLOCK_SIZE);
|
---|
| 1040 | indx = 0;
|
---|
| 1041 | }
|
---|
| 1042 | }
|
---|
| 1043 | }
|
---|
| 1044 |
|
---|
| 1045 | char *num_out(number)
|
---|
| 1046 | register long number;
|
---|
| 1047 | {
|
---|
| 1048 | static char num_buf[12];
|
---|
| 1049 | register int i;
|
---|
| 1050 |
|
---|
| 1051 | for (i = 11; i--;) {
|
---|
| 1052 | num_buf[i] = (number & 07) + '0';
|
---|
| 1053 | number >>= 3;
|
---|
| 1054 | }
|
---|
| 1055 |
|
---|
| 1056 | return num_buf;
|
---|
| 1057 | }
|
---|
| 1058 |
|
---|
| 1059 | /*VARARGS2*/
|
---|
| 1060 | #if __STDC__
|
---|
| 1061 | void string_print(char *buffer, char *fmt,...)
|
---|
| 1062 | #else
|
---|
| 1063 | void string_print(buffer, fmt)
|
---|
| 1064 | char *buffer;
|
---|
| 1065 | char *fmt;
|
---|
| 1066 | #endif
|
---|
| 1067 | {
|
---|
| 1068 | va_list args;
|
---|
| 1069 | register char *buf_ptr;
|
---|
| 1070 | char *scan_ptr;
|
---|
| 1071 | char buf[STRING_SIZE];
|
---|
| 1072 | BOOL pr_fl, i;
|
---|
| 1073 |
|
---|
| 1074 | if (pr_fl = (buffer == NIL_PTR)) buffer = buf;
|
---|
| 1075 |
|
---|
| 1076 | va_start(args, fmt);
|
---|
| 1077 | buf_ptr = buffer;
|
---|
| 1078 | while (*fmt) {
|
---|
| 1079 | if (*fmt == '%') {
|
---|
| 1080 | fmt++;
|
---|
| 1081 | switch (*fmt++) {
|
---|
| 1082 | case 's':
|
---|
| 1083 | scan_ptr = (char *) (va_arg(args, char *));
|
---|
| 1084 | break;
|
---|
| 1085 | case 'I':
|
---|
| 1086 | scan_ptr = num_out((long) (va_arg(args, int)));
|
---|
| 1087 | for (i = 0; i < 5; i++) scan_ptr++;
|
---|
| 1088 | break;
|
---|
| 1089 | case 'L':
|
---|
| 1090 | scan_ptr = num_out((long) va_arg(args, long));
|
---|
| 1091 | break;
|
---|
| 1092 | case 'd':
|
---|
| 1093 | scan_ptr = num_out((long) va_arg(args, int));
|
---|
| 1094 | while (*scan_ptr == '0') scan_ptr++;
|
---|
| 1095 | scan_ptr--;
|
---|
| 1096 | break;
|
---|
| 1097 | default: scan_ptr = "";
|
---|
| 1098 | }
|
---|
| 1099 | while (*buf_ptr++ = *scan_ptr++);
|
---|
| 1100 | buf_ptr--;
|
---|
| 1101 | } else
|
---|
| 1102 | *buf_ptr++ = *fmt++;
|
---|
| 1103 | }
|
---|
| 1104 | *buf_ptr = '\0';
|
---|
| 1105 |
|
---|
| 1106 | if (pr_fl) print(buffer);
|
---|
| 1107 | va_end(args);
|
---|
| 1108 | }
|
---|