void create_archive() { register char *p; char *name_from_list(); open_archive(0); /* Open for writing */ if(f_gnudump) { char buf[MAXNAMLEN],*q,*bufp; collect_and_sort_names(); while(p=name_from_list()) dump_file(p,-1); /* if(!f_dironly) { */ blank_name_list(); while(p=name_from_list()) { strcpy(buf,p); if(p[strlen(p)-1]!='/') strcat(buf,"/"); bufp=buf+strlen(buf); for(q=gnu_list_name->dir_contents;*q;q+=strlen(q)+1) { if(*q=='Y') { strcpy(bufp,q+1); dump_file(buf,-1); } } } /* } */ } else { while (p = name_next(1)) { dump_file(p, -1); } } write_eot(); close_archive(); name_close(); }
/* Read incremental snapshot file (directory file). If the file has older incremental version, make sure that it is processed correctly and that tar will use the most conservative backup method among possible alternatives (i.e. prefer ALL_CHILDREN over CHANGED_CHILDREN, etc.) This ensures that the snapshots are updated to the recent version without any loss of data. */ void read_directory_file (void) { int fd; char *buf = NULL; size_t bufsize = 0; int flags = O_RDWR | O_CREAT; if (incremental_level == 0) flags |= O_TRUNC; /* Open the file for both read and write. That way, we can write it later without having to reopen it, and don't have to worry if we chdir in the meantime. */ fd = open (listed_incremental_option, flags, MODE_RW); if (fd < 0) { open_error (listed_incremental_option); return; } listed_incremental_stream = fdopen (fd, "r+"); if (! listed_incremental_stream) { open_error (listed_incremental_option); close (fd); return; } /* Consume the first name from the name list and reset the list afterwards. This is done to change to the new directory, if the first name is a chdir request (-C dir), which is necessary to recreate absolute file names. */ name_from_list (); blank_name_list (); if (0 < getline (&buf, &bufsize, listed_incremental_stream)) { char *ebuf; uintmax_t incremental_version; if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0) { ebuf = buf + sizeof PACKAGE_NAME - 1; if (*ebuf++ != '-') ERROR((1, 0, _("Bad incremental file format"))); for (; *ebuf != '-'; ebuf++) if (!*ebuf) ERROR((1, 0, _("Bad incremental file format"))); incremental_version = strtoumax (ebuf + 1, NULL, 10); } else incremental_version = 0; switch (incremental_version) { case 0: case 1: read_incr_db_01 (incremental_version, buf); break; case TAR_INCREMENTAL_VERSION: read_incr_db_2 (); break; default: ERROR ((1, 0, _("Unsupported incremental format version: %"PRIuMAX), incremental_version)); } } if (ferror (listed_incremental_stream)) read_error (listed_incremental_option); if (buf) free (buf); }
/* Implement the 'r' (add files to end of archive), and 'u' (add files to end of archive if they aren't there, or are more up to date than the version in the archive) commands. */ void update_archive (void) { enum read_header previous_status = HEADER_STILL_UNREAD; bool found_end = false; name_gather (); open_archive (ACCESS_UPDATE); xheader_write_global (); while (!found_end) { enum read_header status = read_header (false); switch (status) { case HEADER_STILL_UNREAD: case HEADER_SUCCESS_EXTENDED: abort (); case HEADER_SUCCESS: { struct name *name; decode_header (current_header, ¤t_stat_info, ¤t_format, 0); archive_format = current_format; if (subcommand_option == UPDATE_SUBCOMMAND && (name = name_scan (current_stat_info.file_name)) != NULL) { struct stat s; chdir_do (name->change_dir); if (deref_stat (dereference_option, current_stat_info.file_name, &s) == 0 && s.st_mtime <= current_stat_info.stat.st_mtime) add_avoided_name (current_stat_info.file_name); } skip_member (); break; } case HEADER_ZERO_BLOCK: current_block = current_header; found_end = true; break; case HEADER_END_OF_FILE: found_end = true; break; case HEADER_FAILURE: set_next_block_after (current_header); switch (previous_status) { case HEADER_STILL_UNREAD: WARN ((0, 0, _("This does not look like a tar archive"))); /* Fall through. */ case HEADER_SUCCESS: case HEADER_ZERO_BLOCK: ERROR ((0, 0, _("Skipping to next header"))); /* Fall through. */ case HEADER_FAILURE: break; case HEADER_END_OF_FILE: case HEADER_SUCCESS_EXTENDED: abort (); } break; } tar_stat_destroy (¤t_stat_info); xheader_destroy (&extended_header); previous_status = status; } reset_eof (); time_to_start_writing = true; output_start = current_block->buffer; { char *file_name; while ((file_name = name_from_list ()) != NULL) { if (excluded_name (file_name)) continue; if (interactive_option && !confirm ("add", file_name)) continue; if (subcommand_option == CAT_SUBCOMMAND) append_file (file_name); else dump_file (file_name, 1, (dev_t) 0); } } write_eot (); close_archive (); names_notfound (); }
/* Implement the 'r' (add files to end of archive), and 'u' (add files to end of archive if they arent there, or are more up to date than the version in the archive.) commands.*/ void update_archive () { int found_end = 0; int status = 3; int prev_status; char *p; struct name *name; extern void dump_file (); name_gather (); if (cmd_mode == CMD_UPDATE) name_expand (); open_archive (2); /* Open for updating */ do { prev_status = status; status = read_header (); switch (status) { case EOF: found_end = 1; break; case 0: /* A bad record */ userec (head); switch (prev_status) { case 3: msg ("This doesn't look like a tar archive."); /* FALL THROUGH */ case 2: case 1: msg ("Skipping to next header"); case 0: break; } break; /* A good record */ case 1: /* printf("File %s\n",head->header.name); */ /* head->header.name[NAMSIZ-1]='\0'; */ if (cmd_mode == CMD_UPDATE && (name = name_scan (current_file_name))) { /* struct stat hstat; */ struct stat nstat; int head_standard; decode_header (head, &hstat, &head_standard, 0); if (stat (current_file_name, &nstat) < 0) { msg_perror ("can't stat %s:", current_file_name); } else { if (hstat.st_mtime >= nstat.st_mtime) name->found++; } } userec (head); if (head->header.isextended) skip_extended_headers (); skip_file ((long) hstat.st_size); break; case 2: ar_record = head; found_end = 1; break; } } while (!found_end); reset_eof (); time_to_start_writing = 1; output_start = ar_record->charptr; while (p = name_from_list ()) { if (f_confirm && !confirm ("add", p)) continue; if (cmd_mode == CMD_CAT) append_file (p); else dump_file (p, -1, 1); } write_eot (); close_archive (); names_notfound (); }