int
cdb_make_put(struct cdb_make *cdbmp,
	     const void *key, unsigned klen,
	     const void *val, unsigned vlen,
	     enum cdb_put_mode mode)
{
  unsigned hval = cdb_hash(key, klen);
  int r;

  switch(mode) {
    case CDB_PUT_REPLACE:
    case CDB_PUT_INSERT:
    case CDB_PUT_WARN:
    case CDB_PUT_REPLACE0:
      r = findrec(cdbmp, key, klen, hval, mode);
      if (r < 0)
        return -1;
      if (r && mode == CDB_PUT_INSERT)
        return errno = EEXIST, 1;
      break;

    case CDB_PUT_ADD:
      r = 0;
      break;

    default:
      return errno = EINVAL, -1;
  }

  if (_cdb_make_add(cdbmp, hval, key, klen, val, vlen) < 0)
    return -1;

  return r;
}
int
cdb_make_find(struct cdb_make *cdbmp,
              const void *key, unsigned klen,
              enum cdb_put_mode mode)
{
  return findrec(cdbmp, key, klen, cdb_hash(key, klen), mode);
}
示例#3
0
/*
 * Extract a file from the archive.
 */
void
extract_archive ()
{
  register char *data;
  int fd, check, namelen, written, openflag;
  long size;
  struct utimbuf acc_upd_times;
  register int skipcrud;
  register int i;
  /*	int sparse_ind = 0;*/
  union record *exhdr;
  struct saved_dir_info *tmp;
  /*	int end_nulls; */

  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 */

  if ((f_confirm && !confirm ("extract", current_file_name)) ||
      (f_exstdout && head->header.linkflag != LF_OLDNORMAL &&
       head->header.linkflag != LF_NORMAL &&
       head->header.linkflag != LF_CONTIG))
    {
      if (head->header.isextended)
	skip_extended_headers ();
      skip_file ((long) hstat.st_size);
      saverec ((union record **) 0);
      return;
    }

  /* Print the record from 'head' and 'hstat' */
  if (f_verbose)
    print_header ();

  /*
	 * Check for fully specified pathnames and other atrocities.
	 *
	 * Note, we can't just make a pointer to the new file name,
	 * since saverec() might move the header and adjust "head".
	 * We have to start from "head" every time we want to touch
	 * the header record.
	 */
  skipcrud = 0;
  while (!f_absolute_paths
	 && '/' == current_file_name[skipcrud])
    {
      static int warned_once = 0;

      skipcrud++;		/* Force relative path */
      if (!warned_once++)
	{
	  msg ("Removing leading / from absolute path names in the archive.");
	}
    }

  switch (head->header.linkflag)
    {

    default:
      msg ("Unknown file type '%c' for %s, extracted as normal file",
	   head->header.linkflag, skipcrud + current_file_name);
      /* FALL THRU */

      /*
	  * JK - What we want to do if the file is sparse is loop through
	  * the array of sparse structures in the header and read in
	  * and translate the character strings representing  1) the offset
	  * at which to write and 2) how many bytes to write into numbers,
	  * which we store into the scratch array, "sparsearray".  This
	  * array makes our life easier the same way it did in creating
	  * the tar file that had to deal with a sparse file.
	  *
	  * After we read in the first five (at most) sparse structures,
	  * we check to see if the file has an extended header, i.e.,
	  * if more sparse structures are needed to describe the contents
	  * of the new file.  If so, we read in the extended headers
	  * and continue to store their contents into the sparsearray.
	  */
    case LF_SPARSE:
      sp_array_size = 10;
      sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
      for (i = 0; i < SPARSE_IN_HDR; i++)
	{
	  sparsearray[i].offset =
	    from_oct (1 + 12, head->header.sp[i].offset);
	  sparsearray[i].numbytes =
	    from_oct (1 + 12, head->header.sp[i].numbytes);
	  if (!sparsearray[i].numbytes)
	    break;
	}

      /*		end_nulls = from_oct(1+12, head->header.ending_blanks);*/

      if (head->header.isextended)
	{
	  /* read in the list of extended headers
			    and translate them into the sparsearray
			    as before */

	  /* static */ int ind = SPARSE_IN_HDR;

	  for (;;)
	    {

	      exhdr = findrec ();
	      for (i = 0; i < SPARSE_EXT_HDR; i++)
		{

		  if (i + ind > sp_array_size - 1)
		    {
		      /*
					  * realloc the scratch area
					  * since we've run out of room --
					  */
		      sparsearray = (struct sp_array *)
			ck_realloc (sparsearray,
			    2 * sp_array_size * (sizeof (struct sp_array)));
		      sp_array_size *= 2;
		    }
		  if (!exhdr->ext_hdr.sp[i].numbytes)
		    break;
		  sparsearray[i + ind].offset =
		    from_oct (1 + 12, exhdr->ext_hdr.sp[i].offset);
		  sparsearray[i + ind].numbytes =
		    from_oct (1 + 12, exhdr->ext_hdr.sp[i].numbytes);
		}
	      if (!exhdr->ext_hdr.isextended)
		break;
	      else
		{
		  ind += SPARSE_EXT_HDR;
		  userec (exhdr);
		}
	    }
	  userec (exhdr);
	}

      /* FALL THRU */
    case LF_OLDNORMAL:
    case LF_NORMAL:
    case LF_CONTIG:
      /*
		  * Appears to be a file.
		  * See if it's really a directory.
		  */
      namelen = strlen (skipcrud + current_file_name) - 1;
      if (current_file_name[skipcrud + namelen] == '/')
	goto really_dir;

      /* FIXME, deal with protection issues */
    again_file:
      openflag = (f_keep ?
		  O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
		  O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
	| ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
      /*
			  * JK - The last | is a kludge to solve the problem
			  * the O_APPEND flag  causes with files we are
			  * trying to make sparse:  when a file is opened
			  * with O_APPEND, it writes  to the last place
			  * that something was written, thereby ignoring
			  * any lseeks that we have done.  We add this
			  * extra condition to make it able to lseek when
			  * a file is sparse, i.e., we don't open the new
			  * file with this flag.  (Grump -- this bug caused
			  * me to waste a good deal of time, I might add)
			  */

      if (f_exstdout)
	{
	  fd = 1;
	  goto extract_file;
	}

      if (f_unlink && !f_keep) {
	if (unlink(skipcrud + current_file_name) == -1)
		if (errno != ENOENT)
		   msg_perror ("Could not unlink %s",
                      skipcrud + current_file_name);
      }

#ifdef O_CTG
      /*
		  * Contiguous files (on the Masscomp) have to specify
		  * the size in the open call that creates them.
		  */
      if (head->header.linkflag == LF_CONTIG)
	fd = open ((longname ? longname : head->header.name)
		   + skipcrud,
		   openflag | O_CTG,
		   hstat.st_mode, hstat.st_size);
      else
#endif
	{
#ifdef NO_OPEN3
	  /*
			  * On raw V7 we won't let them specify -k (f_keep), but
			  * we just bull ahead and create the files.
			  */
	  fd = creat ((longname
		       ? longname
		       : head->header.name) + skipcrud,
		      hstat.st_mode);
#else
	  /*
			  * With 3-arg open(), we can do this up right.
			  */
	  fd = open (skipcrud + current_file_name,
		     openflag, hstat.st_mode);
#endif
	}

      if (fd < 0)
	{
	  if (make_dirs (skipcrud + current_file_name))
	    goto again_file;
	  msg_perror ("Could not create file %s",
		      skipcrud + current_file_name);
	  if (head->header.isextended)
	    skip_extended_headers ();
	  skip_file ((long) hstat.st_size);
	  goto quit;
	}

    extract_file:
      if (head->header.linkflag == LF_SPARSE)
	{
	  char *name;
	  int namelen;

	  /*
			  * Kludge alert.  NAME is assigned to header.name
			  * because during the extraction, the space that
			  * contains the header will get scribbled on, and
			  * the name will get munged, so any error messages
			  * that happen to contain the filename will look
			  * REAL interesting unless we do this.
			  */
	  namelen = strlen (skipcrud + current_file_name) + 1;
	  name = (char *) ck_malloc ((sizeof (char)) * namelen);
	  bcopy (skipcrud + current_file_name, name, namelen);
	  size = hstat.st_size;
	  extract_sparse_file (fd, &size, hstat.st_size, name);
	}
      else
	for (size = hstat.st_size;
	     size > 0;
	     size -= written)
	  {

	    /*			long	offset,
				 numbytes;*/

	    if (f_multivol)
	      {
		save_name = current_file_name;
		save_totsize = hstat.st_size;
		save_sizeleft = size;
	      }

	    /*
			  * Locate data, determine max length
			  * writeable, write it, record that
			  * we have used the data, then check
			  * if the write worked.
			  */
	    data = findrec ()->charptr;
	    if (data == NULL)
	      {			/* Check it... */
		msg ("Unexpected EOF on archive file");
		break;
	      }
	    /*
			  * JK - If the file is sparse, use the sparsearray
			  * that we created before to lseek into the new
			  * file the proper amount, and to see how many
			  * bytes we want to write at that position.
			  */
	    /*			if (head->header.linkflag == LF_SPARSE) {
				 off_t pos;

				 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
				 printf("%d at %d\n", (int) pos, sparse_ind);
				 written = sparsearray[sparse_ind++].numbytes;
			 } else*/
	    written = endofrecs ()->charptr - data;
	    if (written > size)
	      written = size;
	    errno = 0;
	    check = write (fd, data, written);
	    /*
			  * The following is in violation of strict
			  * typing, since the arg to userec
			  * should be a struct rec *.  FIXME.
			  */
	    userec ((union record *) (data + written - 1));
	    if (check == written)
	      continue;
	    /*
			  * Error in writing to file.
			  * Print it, skip to next file in archive.
			  */
	    if (check < 0)
	      msg_perror ("couldn't write to file %s",
			  skipcrud + current_file_name);
	    else
	      msg ("could only write %d of %d bytes to file %s",
		   check, written, skipcrud + current_file_name);
	    skip_file ((long) (size - written));
	    break;		/* Still do the close, mod time, chmod, etc */
	  }

      if (f_multivol)
	save_name = 0;

      /* If writing to stdout, don't try to do anything
			    to the filename; it doesn't exist, or we don't
			    want to touch it anyway */
      if (f_exstdout)
	break;

      /*		if (head->header.isextended) {
			 register union record *exhdr;
			 register int i;

			 for (i = 0; i < 21; i++) {
				 long offset;

				 if (!exhdr->ext_hdr.sp[i].numbytes)
					 break;
				 offset = from_oct(1+12,
						 exhdr->ext_hdr.sp[i].offset);
				 written = from_oct(1+12,
						 exhdr->ext_hdr.sp[i].numbytes);
				 lseek(fd, offset, 0);
				 check = write(fd, data, written);
				 if (check == written) continue;

			 }


		 }*/
      check = close (fd);
      if (check < 0)
	{
	  msg_perror ("Error while closing %s",
		      skipcrud + current_file_name);
	}


    set_filestat:

      /*
		  * If we are root, set the owner and group of the extracted
		  * file.  This does what is wanted both on real Unix and on
		  * System V.  If we are running as a user, we extract as that
		  * user; if running as root, we extract as the original owner.
		  */
      if (we_are_root || f_do_chown)
	{
	  if (chown (skipcrud + current_file_name,
		     hstat.st_uid, hstat.st_gid) < 0)
	    {
	      msg_perror ("cannot chown file %s to uid %d gid %d",
			  skipcrud + current_file_name,
			  hstat.st_uid, hstat.st_gid);
	    }
	}

      /*
       * Set the modified time of the file.
       *
       * Note that we set the accessed time to "now", which
       * is really "the time we started extracting files".
       * unless f_gnudump is used, in which case .st_atime is used
       */
      if (!f_modified)
	{
	  /* fixme if f_gnudump should set ctime too, but how? */
	  if (f_gnudump)
	    acc_upd_times.actime = hstat.st_atime;
	  else
	    acc_upd_times.actime = now;	/* Accessed now */
	  acc_upd_times.modtime = hstat.st_mtime;	/* Mod'd */
	  if (utime (skipcrud + current_file_name,
		     &acc_upd_times) < 0)
	    {
	      msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name);
	    }
	}
      /* We do the utime before the chmod because some versions of
		   utime are broken and trash the modes of the file.  Since
		   we then change the mode anyway, we don't care. . . */

      /*
		 * If '-k' is not set, open() or creat() could have saved
		 * the permission bits from a previously created file,
		 * ignoring the ones we specified.
		 * Even if -k is set, if the file has abnormal
		 * mode bits, we must chmod since writing or chown() has
		 * probably reset them.
		 *
		 * If -k is set, we know *we* created this file, so the mode
		 * bits were set by our open().   If the file is "normal", we
		 * skip the chmod.  This works because we did umask(0) if -p
		 * is set, so umask will have left the specified mode alone.
		 */
      if ((!f_keep)
	  || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
	{
	  if (chmod (skipcrud + current_file_name,
		     notumask & (int) hstat.st_mode) < 0)
	    {
	      msg_perror ("cannot change mode of file %s to 0%o",
			  skipcrud + current_file_name,
			  notumask & (int) hstat.st_mode);
	    }
	}

    quit:
      break;

    case LF_LINK:
    again_link:
      {
	struct stat st1, st2;

        if (f_unlink && !f_keep) {
	  if (unlink(skipcrud + current_file_name) == -1)
		if (errno != ENOENT)
		   msg_perror ("Could not unlink %s",
                      skipcrud + current_file_name);
        }

	check = link (current_link_name, skipcrud + current_file_name);

	if (check == 0)
	  break;
	if (make_dirs (skipcrud + current_file_name))
	  goto again_link;
	if (f_gnudump && errno == EEXIST)
	  break;
	if (stat (current_link_name, &st1) == 0
	    && stat (current_file_name + skipcrud, &st2) == 0
	    && st1.st_dev == st2.st_dev
	    && st1.st_ino == st2.st_ino)
	  break;
	msg_perror ("Could not link %s to %s",
		    skipcrud + current_file_name,
		    current_link_name);
      }
      break;

#ifdef S_ISLNK
    case LF_SYMLINK:
    again_symlink:
      if (f_unlink && !f_keep) {
	  if (unlink(skipcrud + current_file_name) == -1)
		if (errno != ENOENT)
		   msg_perror ("Could not unlink %s",
                      skipcrud + current_file_name);
      }

      check = symlink (current_link_name,
		       skipcrud + current_file_name);
      /* FIXME, don't worry uid, gid, etc... */
      if (check == 0)
	break;
      if (make_dirs (current_file_name + skipcrud))
	goto again_symlink;
      msg_perror ("Could not create symlink to %s",
		  current_link_name);
      break;
#endif

#ifdef S_IFCHR
    case LF_CHR:
      hstat.st_mode |= S_IFCHR;
      goto make_node;
#endif

#ifdef S_IFBLK
    case LF_BLK:
      hstat.st_mode |= S_IFBLK;
#endif
#if defined(S_IFCHR) || defined(S_IFBLK)
    make_node:
      if (f_unlink && !f_keep) {
	  if (unlink(skipcrud + current_file_name) == -1)
		if (errno != ENOENT)
		   msg_perror ("Could not unlink %s",
                      skipcrud + current_file_name);
      }

      check = mknod (current_file_name + skipcrud,
		     (int) hstat.st_mode, (int) hstat.st_rdev);
      if (check != 0)
	{
	  if (make_dirs (skipcrud + current_file_name))
	    goto make_node;
	  msg_perror ("Could not make %s",
		      current_file_name + skipcrud);
	  break;
	};
      goto set_filestat;
#endif

#ifdef S_ISFIFO
      /* If local system doesn't support FIFOs, use default case */
    case LF_FIFO:
    make_fifo:
      if (f_unlink && !f_keep) {
	  if (unlink(skipcrud + current_file_name) == -1)
		if (errno != ENOENT)
		   msg_perror ("Could not unlink %s",
                      skipcrud + current_file_name);
      }

      check = mkfifo (current_file_name + skipcrud,
		      (int) hstat.st_mode);
      if (check != 0)
	{
	  if (make_dirs (current_file_name + skipcrud))
	    goto make_fifo;
	  msg_perror ("Could not make %s",
		      skipcrud + current_file_name);
	  break;
	};
      goto set_filestat;
#endif

    case LF_DIR:
    case LF_DUMPDIR:
      namelen = strlen (current_file_name + skipcrud) - 1;
    really_dir:
      /* Check for trailing /, and zap as many as we find. */
      while (namelen
	     && current_file_name[skipcrud + namelen] == '/')
	current_file_name[skipcrud + namelen--] = '\0';
      if (f_gnudump)
	{			/* Read the entry and delete files
					   that aren't listed in the archive */
	  gnu_restore (skipcrud);

	}
      else if (head->header.linkflag == LF_DUMPDIR)
	skip_file ((long) (hstat.st_size));


    again_dir:
      check = mkdir (skipcrud + current_file_name,
		     (we_are_root ? 0 : 0300) | (int) hstat.st_mode);
      if (check != 0)
	{
	  struct stat st1;

	  if (make_dirs (skipcrud + current_file_name))
	    goto again_dir;
	  /* If we're trying to create '.', let it be. */
	  if (current_file_name[skipcrud + namelen] == '.' &&
	      (namelen == 0 ||
	       current_file_name[skipcrud + namelen - 1] == '/'))
	    goto check_perms;
	  if (errno == EEXIST
	      && stat (skipcrud + current_file_name, &st1) == 0
	      && (S_ISDIR (st1.st_mode)))
	    break;
	  msg_perror ("Could not create directory %s", skipcrud + current_file_name);
	  break;
	}

    check_perms:
      if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode))
	{
	  hstat.st_mode |= 0300;
	  msg ("Added write and execute permission to directory %s",
	       skipcrud + current_file_name);
	}

      /*
       * If we are root, set the owner and group of the extracted
       * file.  This does what is wanted both on real Unix and on
       * System V.  If we are running as a user, we extract as that
       * user; if running as root, we extract as the original owner.
       */
      if (we_are_root || f_do_chown)
	{
	  if (chown (skipcrud + current_file_name,
		     hstat.st_uid, hstat.st_gid) < 0)
	    {
	      msg_perror ("cannot chown file %s to uid %d gid %d",
			  skipcrud + current_file_name,
			  hstat.st_uid, hstat.st_gid);
	    }
	}

      if (!f_modified)
	{
	  tmp = ((struct saved_dir_info *)
		 ck_malloc (sizeof (struct saved_dir_info)));
	  tmp->path = (char *) ck_malloc (strlen (skipcrud
						  + current_file_name) + 1);
	  strcpy (tmp->path, skipcrud + current_file_name);
	  tmp->mode = hstat.st_mode;
	  tmp->atime = hstat.st_atime;
	  tmp->mtime = hstat.st_mtime;
	  tmp->next = saved_dir_info_head;
	  saved_dir_info_head = tmp;
	}
      else
	{
	  /* This functions exactly as the code for set_filestat above. */
	  if ((!f_keep)
	      || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
	    {
	      if (chmod (skipcrud + current_file_name,
			 notumask & (int) hstat.st_mode) < 0)
		{
		  msg_perror ("cannot change mode of file %s to 0%o",
			      skipcrud + current_file_name,
			      notumask & (int) hstat.st_mode);
		}
	    }
	}
      break;

    case LF_VOLHDR:
      if (f_verbose)
	{
	  printf ("Reading %s\n", current_file_name);
	}
      break;

    case LF_NAMES:
      extract_mangle (head);
      break;

    case LF_MULTIVOL:
      msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name);
      skip_file ((long) hstat.st_size);
      break;

    case LF_LONGNAME:
    case LF_LONGLINK:
      msg ("Visible long name error\n");
      skip_file ((long) hstat.st_size);
      break;
    }

  /* We don't need to save it any longer. */
  saverec ((union record **) 0);/* Unsave it */
}
示例#4
0
文件: loadnkconf.c 项目: tjyang/abmon
nkconf_t *get_nkconfig(char *key, int flags, char **resultkey)
{
	static RbtHandle handle;
	static char *realkey = NULL;
	void *k1, *k2;
	nkconf_t *result = NULL;
	int isclone;

	if (resultkey) *resultkey = NULL;

	switch (flags) {
	  case NKCONF_TIMEFILTER:
		handle = findrec(key);
		/* We may have hit a cloned record, so use the real key for further searches */
		if (handle != rbtEnd(rbconf)) {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			realkey = k1;
		}

		while (handle != rbtEnd(rbconf)) {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			result = (nkconf_t *)k2;
			if (timecheck(result->starttime, result->endtime, result->nktime)) return result;

			/* Go to the next */
			handle = rbtNext(rbconf, handle);
			if (handle != rbtEnd(rbconf)) {
				rbtKeyValue(rbconf, handle, &k1, &k2);
				if (strncmp(realkey, ((nkconf_t *)k2)->key, strlen(realkey)) != 0) handle=rbtEnd(rbconf);
			}
		}
		realkey = NULL;
		break;

	  case NKCONF_FIRSTMATCH:
		handle = findrec(key);
		realkey = NULL;
		if (handle != rbtEnd(rbconf)) {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			realkey = (char *)k1;
		}
		break;

	  case NKCONF_FIRST:
		realkey = NULL;
		handle = rbtBegin(rbconf);
		if (handle == rbtEnd(rbconf)) return NULL;
		do {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			realkey = (char *)k1;
			isclone = (*(realkey + strlen(realkey) - 1) == '=');
			if (isclone) handle = rbtNext(rbconf, handle);
		} while (isclone && (handle != rbtEnd(rbconf)));
		break;


	  case NKCONF_NEXT:
		if (!realkey || (handle == rbtEnd(rbconf))) return NULL;
		isclone = 1;
		while (isclone && (handle != rbtEnd(rbconf))) {
			handle = rbtNext(rbconf, handle);
			if (handle) {
				rbtKeyValue(rbconf, handle, &k1, &k2);
				realkey = (char *)k1;
				isclone = (*(realkey + strlen(realkey) - 1) == '=');
			}
		}
		break;

	  case NKCONF_RAW_FIRST:
		handle = rbtBegin(rbconf);
		realkey = NULL;
		break;

	  case NKCONF_RAW_NEXT:
		handle = rbtNext(rbconf, handle);
		realkey = NULL;
		break;

	  case NKCONF_FIRSTHOSTMATCH:
		do {
			int found = 0;
			char *delim;

			realkey = NULL;
			handle = rbtBegin(rbconf);
			while (!found && (handle != rbtEnd(rbconf))) {
				rbtKeyValue(rbconf, handle, &k1, &k2);
				realkey = (char *)k1;
				delim = realkey + strlen(key); /* OK even if past end of realkey */
				found = ((strncmp(realkey, key, strlen(key)) == 0) &&
					((*delim == '|') || (*delim == '=')));
				if (!found) { handle = rbtNext(rbconf, handle); realkey = NULL; }
			}

			if ((handle != rbtEnd(rbconf)) && (*(realkey + strlen(realkey) - 1) == '=')) {
				key = (char *)k2;
				isclone = 1;
			}
			else isclone = 0;

		} while (isclone && (handle != rbtEnd(rbconf)));
		break;
	}

	if (handle == rbtEnd(rbconf)) { realkey = NULL; return NULL; }

	rbtKeyValue(rbconf, handle, &k1, &k2);
	if (resultkey) *resultkey = (char *)k1;
	result = (nkconf_t *)k2;

	return result;
}
示例#5
0
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);
    }
}
示例#6
0
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;
    }
}