char * xgetcwd () { char *cwd; char *ret; unsigned path_max; errno = 0; path_max = (unsigned) PATH_MAX; path_max += 2; /* The getcwd docs say to do this. */ cwd = tar_xmalloc (path_max); errno = 0; while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) { path_max += PATH_INCR; cwd = tar_realloc (cwd, path_max); errno = 0; } if (ret == NULL) { int save_errno = errno; free (cwd); errno = save_errno; return NULL; } return cwd; }
static void __tar_add_dir (char *name, dev_t dev, ino_t ino, const char *text) { struct dirname *dp; dp = (struct dirname *) tar_xmalloc (sizeof (struct dirname)); dp->next = dir_list; dir_list = dp; dp->dev = dev; dp->ino = ino; dp->name = __tar_xstrdup (name); dp->dir_text = text; dp->allnew = 0; }
void diff_archive (void) { register char *data; int check, namelen; int err; off_t offset; struct stat filestat; #ifndef __MSDOS__ dev_t dev; ino_t ino; #endif errno = EPIPE; /* FIXME, remove perrors */ saverec (&head); /* make sure it sticks around */ userec (head); /* and go past it in the archive */ decode_header (head, &hstat, &head_standard, 1); /* snarf fields */ /* Print the record from `head' and `hstat'. */ if (flag_verbose) { if (now_verifying) fprintf (stdlis, _("Verify ")); print_header (); } switch (head->header.linkflag) { default: WARN ((0, 0, _("Unknown file type '%c' for %s, diffed as normal file"), head->header.linkflag, current_file_name)); /* Fall through. */ case LF_OLDNORMAL: case LF_NORMAL: case LF_SPARSE: case LF_CONTIG: /* Appears to be a file. See if it's really a directory. */ namelen = strlen (current_file_name) - 1; if (current_file_name[namelen] == '/') goto really_dir; if (do_stat (&filestat)) { if (head->header.isextended) skip_extended_headers (); skip_file ((long) hstat.st_size); different++; goto quit; } if (!S_ISREG (filestat.st_mode)) { fprintf (stdlis, _("%s: Not a regular file\n"), current_file_name); skip_file ((long) hstat.st_size); different++; goto quit; } filestat.st_mode &= 07777; if (filestat.st_mode != hstat.st_mode) sigh (_("Mode")); if (filestat.st_uid != hstat.st_uid) sigh (_("Uid")); if (filestat.st_gid != hstat.st_gid) sigh (_("Gid")); if (filestat.st_mtime != hstat.st_mtime) sigh (_("Mod time")); if (head->header.linkflag != LF_SPARSE && filestat.st_size != hstat.st_size) { sigh (_("Size")); skip_file ((long) hstat.st_size); goto quit; } diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY); if (diff_fd < 0 && !flag_absolute_names) { char *tmpbuf = tar_xmalloc (strlen (current_file_name) + 2); *tmpbuf = '/'; strcpy (tmpbuf + 1, current_file_name); diff_fd = open (tmpbuf, O_NDELAY | O_RDONLY); free (tmpbuf); } if (diff_fd < 0) { ERROR ((0, errno, _("Cannot open %s"), current_file_name)); if (head->header.isextended) skip_extended_headers (); skip_file ((long) hstat.st_size); different++; goto quit; } /* Need to treat sparse files completely differently here. */ if (head->header.linkflag == LF_SPARSE) diff_sparse_files (hstat.st_size); else { if (flag_multivol) { assign_string (&save_name, current_file_name); save_totsize = hstat.st_size; /* save_size is set in wantbytes (). */ } wantbytes ((long) (hstat.st_size), compare_chunk); if (flag_multivol) assign_string (&save_name, NULL); } check = close (diff_fd); if (check < 0) ERROR ((0, errno, _("Error while closing %s"), current_file_name)); quit: break; #ifndef __MSDOS__ case LF_LINK: if (do_stat (&filestat)) break; dev = filestat.st_dev; ino = filestat.st_ino; err = stat (current_link_name, &filestat); if (err < 0) { if (errno == ENOENT) fprintf (stdlis, _("%s: Does not exist\n"), current_file_name); else WARN ((0, errno, _("Cannot stat file %s"), current_file_name)); different++; break; } if (filestat.st_dev != dev || filestat.st_ino != ino) { fprintf (stdlis, _("%s: Not linked to %s\n"), current_file_name, current_link_name); break; } break; #endif #ifdef S_ISLNK case LF_SYMLINK: { char linkbuf[NAMSIZ + 3]; /* FIXME: may be too short. */ check = readlink (current_file_name, linkbuf, (sizeof linkbuf) - 1); if (check < 0) { if (errno == ENOENT) fprintf (stdlis, _("%s: No such file or directory\n"), current_file_name); else WARN ((0, errno, _("Cannot read link %s"), current_file_name)); different++; break; } linkbuf[check] = '\0'; /* null-terminate it */ if (strncmp (current_link_name, linkbuf, (size_t) check) != 0) { fprintf (stdlis, _("%s: Symlink differs\n"), current_link_name); different++; } } break; #endif #ifdef S_IFCHR case LF_CHR: hstat.st_mode |= S_IFCHR; goto check_node; #endif #ifdef S_IFBLK /* If local system doesn't support block devices, use default case. */ case LF_BLK: hstat.st_mode |= S_IFBLK; goto check_node; #endif #ifdef S_ISFIFO /* If local system doesn't support FIFOs, use default case. */ case LF_FIFO: #ifdef S_IFIFO hstat.st_mode |= S_IFIFO; #endif hstat.st_rdev = 0; /* FIXME, do we need this? */ goto check_node; #endif check_node: /* FIXME, deal with umask. */ if (do_stat (&filestat)) break; if (hstat.st_rdev != filestat.st_rdev) { fprintf (stdlis, _("%s: Device numbers changed\n"), current_file_name); different++; break; } if ( #ifdef S_IFMT hstat.st_mode != filestat.st_mode #else /* POSIX lossage */ (hstat.st_mode & 07777) != (filestat.st_mode & 07777) #endif ) { fprintf (stdlis, _("%s: Mode or device-type changed\n"), current_file_name); different++; break; } break; case LF_DUMPDIR: data = diff_dir = get_dir_contents (current_file_name, 0); if (flag_multivol) { assign_string (&save_name, current_file_name); save_totsize = hstat.st_size; /* save_size is set in wantbytes (). */ } if (data) { wantbytes ((long) (hstat.st_size), compare_dir); free (data); } else wantbytes ((long) (hstat.st_size), no_op); if (flag_multivol) assign_string (&save_name, NULL); /* Fall through. */ case LF_DIR: /* Check for trailing /. */ namelen = strlen (current_file_name) - 1; really_dir: while (namelen && current_file_name[namelen] == '/') current_file_name[namelen--] = '\0'; /* zap / */ if (do_stat (&filestat)) break; if (!S_ISDIR (filestat.st_mode)) { fprintf (stdlis, _("%s: No longer a directory\n"), current_file_name); different++; break; } if ((filestat.st_mode & 07777) != (hstat.st_mode & 07777)) sigh (_("Mode")); break; case LF_VOLHDR: break; case LF_MULTIVOL: namelen = strlen (current_file_name) - 1; if (current_file_name[namelen] == '/') goto really_dir; if (do_stat (&filestat)) break; if (!S_ISREG (filestat.st_mode)) { fprintf (stdlis, _("%s: Not a regular file\n"), current_file_name); skip_file ((long) hstat.st_size); different++; break; } filestat.st_mode &= 07777; offset = from_oct (1 + 12, head->header.offset); if (filestat.st_size != hstat.st_size + offset) { sigh (_("Size")); skip_file ((long) hstat.st_size); different++; break; } diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY); if (diff_fd < 0) { WARN ((0, errno, _("Cannot open file %s"), current_file_name)); skip_file ((long) hstat.st_size); different++; break; } err = lseek (diff_fd, offset, 0); if (err != offset) { WARN ((0, errno, _("Cannot seek to %ld in file %s"), offset, current_file_name)); different++; break; } if (flag_multivol) { assign_string (&save_name, current_file_name); save_totsize = filestat.st_size; /* save_size is set in wantbytes (). */ } wantbytes ((long) (hstat.st_size), compare_chunk); if (flag_multivol) assign_string (&save_name, NULL); check = close (diff_fd); if (check < 0) ERROR ((0, errno, _("Error while closing %s"), current_file_name)); break; } /* We don't need to save it any longer. */ saverec ((union record **) 0); /* unsave it */ }
static void fill_in_sparse_array (void) { int ind; /* Allocate space for our scratch space; it's initially 10 elements long, but can change in this routine if necessary. */ sp_array_size = 10; sparsearray = (struct sp_array *) tar_xmalloc (sp_array_size * sizeof (struct sp_array)); /* There are at most five of these structures in the header itself; read these in first. */ for (ind = 0; ind < SPARSE_IN_HDR; ind++) { /* Compare to 0, or use !(int)..., for Pyramid's dumb compiler. */ if (head->header.sp[ind].numbytes == 0) break; sparsearray[ind].offset = from_oct (1 + 12, head->header.sp[ind].offset); sparsearray[ind].numbytes = from_oct (1 + 12, head->header.sp[ind].numbytes); } /* If the header's extended, we gotta read in exhdr's till we're done. */ if (head->header.isextended) { /* How far into the sparsearray we are `so far'. */ static int so_far_ind = SPARSE_IN_HDR; union record *exhdr; while (1) { exhdr = findrec (); for (ind = 0; ind < SPARSE_EXT_HDR; ind++) { if (ind + so_far_ind > sp_array_size - 1) { /* We just ran out of room in our scratch area - realloc it. */ sp_array_size *= 2; sparsearray = (struct sp_array *) tar_realloc (sparsearray, sp_array_size * sizeof (struct sp_array)); } /* Convert the character strings into longs. */ sparsearray[ind + so_far_ind].offset = from_oct (1 + 12, exhdr->ext_hdr.sp[ind].offset); sparsearray[ind + so_far_ind].numbytes = from_oct (1 + 12, exhdr->ext_hdr.sp[ind].numbytes); } /* If this is the last extended header for this file, we can stop. */ if (!exhdr->ext_hdr.isextended) break; else { so_far_ind += SPARSE_EXT_HDR; userec (exhdr); } } /* Be sure to skip past the last one. */ userec (exhdr); } }
static void diff_sparse_files (int filesize) { int sparse_ind = 0; char *buf; int buf_size = RECORDSIZE; union record *datarec; int err; long numbytes; #if 0 int amt_read = 0; #endif int size = filesize; /* FIXME: `datarec' might be used uninitialized in this function. Reported by Bruno Haible. */ buf = (char *) tar_xmalloc (buf_size * sizeof (char)); fill_in_sparse_array (); while (size > 0) { datarec = findrec (); if (!sparsearray[sparse_ind].numbytes) break; /* `numbytes' is nicer to write than `sparsearray[sparse_ind].numbytes' all the time... */ numbytes = sparsearray[sparse_ind].numbytes; lseek (diff_fd, sparsearray[sparse_ind].offset, 0); /* Take care to not run out of room in our buffer. */ while (buf_size < numbytes) { buf_size *= 2; buf = (char *) tar_realloc (buf, buf_size * sizeof (char)); } while (numbytes > RECORDSIZE) { if (err = read (diff_fd, buf, RECORDSIZE), err != RECORDSIZE) { if (err < 0) WARN ((0, errno, _("Cannot read %s"), current_file_name)); else fprintf (stdlis, _("%s: Could only read %d of %ld bytes\n"), current_file_name, err, numbytes); break; } if (memcmp (buf, datarec->charptr, RECORDSIZE)) { different++; break; } numbytes -= err; size -= err; userec (datarec); datarec = findrec (); } if (err = read (diff_fd, buf, (size_t) numbytes), err != numbytes) { if (err < 0) WARN ((0, errno, _("Cannot read %s"), current_file_name)); else fprintf (stdlis, _("%s: Could only read %d of %ld bytes\n"), current_file_name, err, numbytes); break; } if (memcmp (buf, datarec->charptr, (size_t) numbytes)) { different++; break; } #if 0 amt_read += numbytes; if (amt_read >= RECORDSIZE) { amt_read = 0; userec (datarec); datarec = findrec (); } #endif userec (datarec); sparse_ind++; size -= numbytes; } /* If the number of bytes read isn't the number of bytes supposedly in the file, they're different. */ #if 0 if (amt_read != filesize) different++; #endif userec (datarec); free (sparsearray); if (different) { fprintf (stdlis, _("%s: Data differs\n"), current_file_name); if (exit_status == TAREXIT_SUCCESS) exit_status = TAREXIT_DIFFERS; } }
static void __tar_read_dir_file (void) { dev_t dev; ino_t ino; char *strp; FILE *fp; char buf[512]; static char *path = 0; if (path == 0) path = tar_xmalloc (PATH_MAX); time (&this_time); if (gnu_dumpfile[0] != '/') { #ifdef HAVE_GETCWD if (!getcwd (path, PATH_MAX)) ERROR ((TAREXIT_FAILURE, 0, _("Could not get current directory"))); #else char *getwd (); if (!getwd (path)) ERROR ((TAREXIT_FAILURE, 0, _("Could not get current directory: %s"), path)); #endif /* If this doesn't fit, we're in serious trouble. */ strcat (path, "/"); strcat (path, gnu_dumpfile); gnu_dumpfile = path; } fp = fopen (gnu_dumpfile, "r"); if (fp == 0 && errno != ENOENT) { ERROR ((0, errno, _("Cannot open %s"), gnu_dumpfile)); return; } if (!fp) return; fgets (buf, sizeof (buf), fp); if (!flag_new_files) { flag_new_files++; new_time = atol (buf); } while (fgets (buf, sizeof (buf), fp)) { strp = &buf[strlen (buf)]; if (strp[-1] == '\n') strp[-1] = '\0'; strp = buf; dev = atol (strp); while (ISDIGIT (*strp)) strp++; ino = atol (strp); while (ISSPACE (*strp)) strp++; while (ISDIGIT (*strp)) strp++; strp++; __tar_add_dir (__tar_un_quote_string (strp), dev, ino, (char *) 0); } fclose (fp); }
static void __tar_add_dir_name (char *p, int device) { char *new_buf; char *p_buf; char *namebuf; int buflen; register int len; int sublen; #if 0 voidstar the_buffer; char *buf; char **vec,**p_vec; int n_strs,n_size; #endif struct name *n; new_buf = __tar_get_dir_contents (p, device); for (n = namelist; n; n = n->next) { if (!strcmp (n->name, p)) { n->dir_contents = new_buf ? new_buf : "\0\0\0\0"; break; } } if (new_buf) { len = strlen (p); buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ; namebuf = tar_xmalloc ((size_t) (buflen + 1)); strcpy (namebuf, p); if (namebuf[len - 1] != '/') { namebuf[len++] = '/'; namebuf[len] = '\0'; } for (p_buf = new_buf; p_buf && *p_buf; p_buf += sublen + 1) { sublen = strlen (p_buf); if (*p_buf == 'D') { if (len + sublen >= buflen) { buflen += NAMSIZ; namebuf = (char *) tar_realloc (namebuf, (size_t) (buflen + 1)); } strcpy (namebuf + len, p_buf + 1); __tar_addname (namebuf); __tar_add_dir_name (namebuf, device); } } free (namebuf); } }
char * __tar_get_dir_contents (char *p, int device) { DIR *dirp; register struct dirent *d; char *new_buf; char *namebuf; int bufsiz; int len; voidstar the_buffer; char *buf; size_t n_strs; #if 0 int n_size; #endif char *p_buf; char **vec, **p_vec; errno = 0; dirp = opendir (p); bufsiz = strlen (p) + NAMSIZ; namebuf = tar_xmalloc ((size_t) (bufsiz + 2)); if (!dirp) { ERROR ((0, errno, _("Cannot open directory %s"), p)); new_buf = NULL; } else { struct dirname *dp; int all_children; dp = __tar_get_dir (p); all_children = dp ? dp->allnew : 0; strcpy (namebuf, p); if (p[strlen (p) - 1] != '/') strcat (namebuf, "/"); len = strlen (namebuf); the_buffer = __tar_init_buffer (); while (d = readdir (dirp), d) { struct stat hs; /* Skip `.' and `..'. */ if (__tar_is_dot_or_dotdot (d->d_name)) continue; if ((int) NAMLEN (d) + len >= bufsiz) { bufsiz += NAMSIZ; namebuf = (char *) tar_realloc (namebuf, (size_t) (bufsiz + 2)); } strcpy (namebuf + len, d->d_name); #ifdef AIX if (flag_follow_links ? statx (namebuf, &hs, STATSIZE, STX_HIDDEN) : statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK)) #else if (flag_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs)) #endif { ERROR ((0, errno, _("Cannot stat %s"), namebuf)); continue; } if ((flag_local_filesys && device != hs.st_dev) || (flag_exclude && __tar_check_exclude (namebuf))) __tar_add_buffer (the_buffer, "N", 1); #ifdef AIX else if (S_ISHIDDEN (hs.st_mode)) { __tar_add_buffer (the_buffer, "D", 1); strcat (d->d_name, "A"); d->d_namlen++; } #endif /* AIX */ else if (S_ISDIR (hs.st_mode)) { if (dp = __tar_get_dir (namebuf), dp) { if (dp->dev != hs.st_dev || dp->ino != hs.st_ino) { if (flag_verbose) WARN ((0, 0, _("Directory %s has been renamed"), namebuf)); dp->allnew = 1; dp->dev = hs.st_dev; dp->ino = hs.st_ino; } dp->dir_text = ""; } else { if (flag_verbose) WARN ((0, 0, _("Directory %s is new"), namebuf)); __tar_add_dir (namebuf, hs.st_dev, hs.st_ino, ""); dp = __tar_get_dir (namebuf); dp->allnew = 1; } if (all_children && dp) dp->allnew = 1; __tar_add_buffer (the_buffer, "D", 1); } else if (!all_children && flag_new_files && new_time > hs.st_mtime && (flag_new_files > 1 || new_time > hs.st_ctime)) __tar_add_buffer (the_buffer, "N", 1); else __tar_add_buffer (the_buffer, "Y", 1); __tar_add_buffer (the_buffer, d->d_name, (int) (NAMLEN (d) + 1)); } __tar_add_buffer (the_buffer, "\000\000", 2); closedir (dirp); /* Well, we've read in the contents of the dir, now sort them. */ buf = __tar_get_buffer (the_buffer); if (buf[0] == '\0') { __tar_flush_buffer (the_buffer); new_buf = NULL; } else { n_strs = 0; for (p_buf = buf; *p_buf;) { int tmp; tmp = strlen (p_buf) + 1; n_strs++; p_buf += tmp; } vec = (char **) tar_xmalloc (sizeof (char *) * (n_strs + 1)); for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1) *p_vec++ = p_buf; *p_vec = 0; qsort ((voidstar) vec, n_strs, sizeof (char *), __tar_dirent_cmp); new_buf = (char *) tar_xmalloc ((size_t) (p_buf - buf + 2)); for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++) { char *p_tmp; for (p_tmp = *p_vec; (*p_buf++ = *p_tmp++); ) ; } *p_buf++ = '\0'; free (vec); __tar_flush_buffer (the_buffer); } } free (namebuf); return new_buf; }