⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 incremen.c

📁 gnu tar 源码包。 tar 软件是 Unix 系统下的一个打包软件
💻 C
📖 第 1 页 / 共 3 页
字号:
      pval->tv_sec = u;    }  if (c || read_num (fp, BILLION - 1, &u))    FATAL_ERROR ((0, 0, "%s: %s",		  quotearg_colon (listed_incremental_option),		  _("Unexpected EOF in snapshot file")));  pval->tv_nsec = u;}/* Read incremental snapshot format 2 */static voidread_incr_db_2 (){  uintmax_t u;  struct obstack stk;  obstack_init (&stk);  read_timespec (listed_incremental_stream, &newer_mtime_option);  for (;;)    {      struct timespec mtime;      dev_t dev;      ino_t ino;      bool nfs;      char *name;      char *content;      size_t s;      if (read_num (listed_incremental_stream, 1, &u))	return; /* Normal return */      nfs = u;      read_timespec (listed_incremental_stream, &mtime);      if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u))	break;      dev = u;      if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u))	break;      ino = u;      if (read_obstack (listed_incremental_stream, &stk, &s))	break;      name = obstack_finish (&stk);      while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)	;      if (getc (listed_incremental_stream) != 0)	FATAL_ERROR ((0, 0, "%s: %s",		      quotearg_colon (listed_incremental_option),		      _("Missing record terminator")));      content = obstack_finish (&stk);      note_directory (name, mtime, dev, ino, nfs, false, content);      obstack_free (&stk, content);    }  FATAL_ERROR ((0, 0, "%s: %s",		quotearg_colon (listed_incremental_option),		_("Unexpected EOF in snapshot file")));}/* 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. */voidread_directory_file (void){  int fd;  char *buf = 0;  size_t bufsize;  /* 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, O_RDWR | O_CREAT, 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;    }  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);}/* Output incremental data for the directory ENTRY to the file DATA.   Return nonzero if successful, preserving errno on write failure.  */static boolwrite_directory_file_entry (void *entry, void *data){  struct directory const *directory = entry;  FILE *fp = data;  if (DIR_IS_FOUND (directory))    {      char buf[UINTMAX_STRSIZE_BOUND];      char *s;      s = DIR_IS_NFS (directory) ? "1" : "0";      fwrite (s, 2, 1, fp);      s = (TYPE_SIGNED (time_t)	   ? imaxtostr (directory->mtime.tv_sec, buf)	   : umaxtostr (directory->mtime.tv_sec, buf));      fwrite (s, strlen (s) + 1, 1, fp);      s = umaxtostr (directory->mtime.tv_nsec, buf);      fwrite (s, strlen (s) + 1, 1, fp);      s = umaxtostr (directory->device_number, buf);      fwrite (s, strlen (s) + 1, 1, fp);      s = umaxtostr (directory->inode_number, buf);      fwrite (s, strlen (s) + 1, 1, fp);      fwrite (directory->name, strlen (directory->name) + 1, 1, fp);      if (directory->dump)	{	  const char *p;	  dumpdir_iter_t itr;	  for (p = dumpdir_first (directory->dump, 0, &itr);	       p;	       p = dumpdir_next (itr))	    fwrite (p, strlen (p) + 1, 1, fp);	  free (itr);	}      fwrite ("\0\0", 2, 1, fp);    }  return ! ferror (fp);}voidwrite_directory_file (void){  FILE *fp = listed_incremental_stream;  char buf[UINTMAX_STRSIZE_BOUND];  char *s;  if (! fp)    return;  if (fseek (fp, 0L, SEEK_SET) != 0)    seek_error (listed_incremental_option);  if (sys_truncate (fileno (fp)) != 0)    truncate_error (listed_incremental_option);  fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,	   TAR_INCREMENTAL_VERSION);  s = (TYPE_SIGNED (time_t)       ? imaxtostr (start_time.tv_sec, buf)       : umaxtostr (start_time.tv_sec, buf));  fwrite (s, strlen (s) + 1, 1, fp);  s = umaxtostr (start_time.tv_nsec, buf);  fwrite (s, strlen (s) + 1, 1, fp);  if (! ferror (fp) && directory_table)    hash_do_for_each (directory_table, write_directory_file_entry, fp);  if (ferror (fp))    write_error (listed_incremental_option);  if (fclose (fp) != 0)    close_error (listed_incremental_option);}/* Restoration of incremental dumps.  */static voidget_gnu_dumpdir (struct tar_stat_info *stat_info){  size_t size;  size_t copied;  union block *data_block;  char *to;  char *archive_dir;  size = stat_info->stat.st_size;  archive_dir = xmalloc (size);  to = archive_dir;  set_next_block_after (current_header);  mv_begin (stat_info);  for (; size > 0; size -= copied)    {      mv_size_left (size);      data_block = find_next_block ();      if (!data_block)	ERROR ((1, 0, _("Unexpected EOF in archive")));      copied = available_space_after (data_block);      if (copied > size)	copied = size;      memcpy (to, data_block->buffer, copied);      to += copied;      set_next_block_after ((union block *)			    (data_block->buffer + copied - 1));    }  mv_end ();  stat_info->dumpdir = archive_dir;  stat_info->skipped = true; /* For skip_member() and friends				to work correctly */}/* Return T if STAT_INFO represents a dumpdir archive member.   Note: can invalidate current_header. It happens if flush_archive()   gets called within get_gnu_dumpdir() */boolis_dumpdir (struct tar_stat_info *stat_info){  if (stat_info->is_dumpdir && !stat_info->dumpdir)    get_gnu_dumpdir (stat_info);  return stat_info->is_dumpdir;}static booldumpdir_ok (char *dumpdir){  char *p;  int has_tempdir = 0;  int expect = 0;  for (p = dumpdir; *p; p += strlen (p) + 1)    {      if (expect && *p != expect)	{	  ERROR ((0, 0,		  _("Malformed dumpdir: expected '%c' but found %#3o"),		  expect, *p));	  return false;	}      switch (*p)	{	case 'X':	  if (has_tempdir)	    {	      ERROR ((0, 0,		      _("Malformed dumpdir: 'X' duplicated")));	      return false;	    }	  else	    has_tempdir = 1;	  break;	case 'R':	  if (p[1] == 0)	    {	      if (!has_tempdir)		{		  ERROR ((0, 0,			  _("Malformed dumpdir: empty name in 'R'")));		  return false;		}	      else		has_tempdir = 0;	    }	  expect = 'T';	  break;	case 'T':	  if (expect != 'T')	    {	      ERROR ((0, 0,		      _("Malformed dumpdir: 'T' not preceeded by 'R'")));	      return false;	    }	  if (p[1] == 0 && !has_tempdir)	    {	      ERROR ((0, 0,		      _("Malformed dumpdir: empty name in 'T'")));	      return false;	    }	  expect = 0;	  break;	case 'N':	case 'Y':	case 'D':	  break;	default:	  /* FIXME: bail out? */	  break;	}    }  if (expect)    {      ERROR ((0, 0,	      _("Malformed dumpdir: expected '%c' but found end of data"),	      expect));      return false;    }  if (has_tempdir)    WARN ((0, 0, _("Malformed dumpdir: 'X' never used")));  return true;}/* Examine the directories under directory_name and delete any   files that were not there at the time of the back-up. */static booltry_purge_directory (char const *directory_name){  char *current_dir;  char *cur, *arc, *p;  char *temp_stub = NULL;  struct dumpdir *dump;  if (!is_dumpdir (&current_stat_info))    return false;  current_dir = savedir (directory_name);  if (!current_dir)    /* The directory doesn't exist now.  It'll be created.  In any       case, we don't have to delete any files out of it.  */    return false;  /* Verify if dump directory is sane */  if (!dumpdir_ok (current_stat_info.dumpdir))    return false;  /* Process renames */  for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)    {      if (*arc == 'X')	{#define TEMP_DIR_TEMPLATE "tar.XXXXXX"	  size_t len = strlen (arc + 1);	  temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);	  memcpy (temp_stub, arc + 1, len);	  temp_stub[len] = '/';	  memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE,		  sizeof TEMP_DIR_TEMPLATE);	  if (!mkdtemp (temp_stub))	    {	      ERROR ((0, errno,		      _("Cannot create temporary directory using template %s"),		      quote (temp_stub)));	      free (temp_stub);	      free (current_dir);	      return false;	    }	}      else if (*arc == 'R')	{	  char *src, *dst;	  src = arc + 1;	  arc += strlen (arc) + 1;	  dst = arc + 1;	  /* Ensure that neither source nor destination are absolute file	     names (unless permitted by -P option), and that they do not	     contain dubious parts (e.g. ../).	     This is an extra safety precaution. Besides, it might be	     necessary to extract from archives created with tar versions	     prior to 1.19. */	  if (*src)	    src = safer_name_suffix (src, false, absolute_names_option);	  if (*dst)	    dst = safer_name_suffix (dst, false, absolute_names_option);	  if (*src == 0)	    src = temp_stub;	  else if (*dst == 0)	    dst = temp_stub;	  if (!rename_directory (src, dst))	    {	      free (temp_stub);	      free (current_dir);	      /* FIXME: Make sure purge_directory(dst) will return		 immediately */	      return false;	    }	}    }  free (temp_stub);  /* Process deletes */  dump = dumpdir_create (current_stat_info.dumpdir);  p = NULL;  for (cur = current_dir; *cur; cur += strlen (cur) + 1)    {      const char *entry;      struct stat st;      if (p)	free (p);      p = new_name (directory_name, cur);      if (deref_stat (false, p, &st))	{	  if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed				  dirs and check it here? */	    {	      stat_diag (p);	      WARN ((0, 0, _("%s: Not purging directory: unable to stat"),		     quotearg_colon (p)));	    }	  continue;	}      if (!(entry = dumpdir_locate (dump, cur))	  || (*entry == 'D' && !S_ISDIR (st.st_mode))	  || (*entry == 'Y' && S_ISDIR (st.st_mode)))	{	  if (one_file_system_option && st.st_dev != root_device)	    {	      WARN ((0, 0,		     _("%s: directory is on a different device: not purging"),		     quotearg_colon (p)));	      continue;	    }	  if (! interactive_option || confirm ("delete", p))	    {	      if (verbose_option)		fprintf (stdlis, _("%s: Deleting %s\n"),			 program_name, quote (p));	      if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))		{		  int e = errno;		  ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));		}	    }	}    }  free (p);  dumpdir_free (dump);    free (current_dir);  return true;}voidpurge_directory (char const *directory_name){  if (!try_purge_directory (directory_name))    skip_member ();}voidlist_dumpdir (char *buffer, size_t size){  int state = 0;  while (size)    {      switch (*buffer)	{	case 'Y':	case 'N':	case 'D':	case 'R':	case 'T':	case 'X':	  fprintf (stdlis, "%c", *buffer);	  if (state == 0)	    {	      fprintf (stdlis, " ");	      state = 1;	    }	  buffer++;	  size--;	  break;	case 0:	  fputc ('\n', stdlis);	  buffer++;	  size--;	  state = 0;	  break;	default:	  fputc (*buffer, stdlis);	  buffer++;	  size--;	}    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -