dd.c

来自「Linux下文件工具。」· C语言 代码 · 共 1,229 行 · 第 1/3 页

C
1,229
字号
  cleanup ();  kill (getpid (), sig);}static RETSIGTYPEsiginfo_handler (int sig ATTRIBUTE_UNUSED){  print_stats ();}/* Encapsulate portability mess of establishing signal handlers.  */static voidinstall_handler (int sig_num, RETSIGTYPE (*sig_handler) (int sig)){#ifdef SA_NOCLDSTOP  struct sigaction sigact;  sigaction (sig_num, NULL, &sigact);  if (sigact.sa_handler != SIG_IGN)    {      sigact.sa_handler = sig_handler;      sigemptyset (&sigact.sa_mask);      sigact.sa_flags = 0;      sigaction (sig_num, &sigact, NULL);    }#else  if (signal (sig_num, SIG_IGN) != SIG_IGN)    signal (sig_num, sig_handler);#endif}/* Open a file to a particular file descriptor.  This is like standard   `open', except it always returns DESIRED_FD if successful.  */static intopen_fd (int desired_fd, char const *filename, int options, mode_t mode){  int fd;  close (desired_fd);  fd = open (filename, options, mode);  if (fd < 0)    return -1;  if (fd != desired_fd)    {      if (dup2 (fd, desired_fd) != desired_fd)	desired_fd = -1;      if (close (fd) != 0)	return -1;    }  return desired_fd;}/* Write, then empty, the output buffer `obuf'. */static voidwrite_output (void){  size_t nwritten = full_write (STDOUT_FILENO, obuf, output_blocksize);  if (nwritten != output_blocksize)    {      error (0, errno, _("writing to %s"), quote (output_file));      if (nwritten != 0)	w_partial++;      quit (1);    }  else    w_full++;  oc = 0;}/* Interpret one "conv=..." option.   As a by product, this function replaces each `,' in STR with a NUL byte.  */static voidparse_conversion (char *str){  char *new;  int i;  do    {      new = strchr (str, ',');      if (new != NULL)	*new++ = '\0';      for (i = 0; conversions[i].convname != NULL; i++)	if (STREQ (conversions[i].convname, str))	  {	    conversions_mask |= conversions[i].conversion;	    break;	  }      if (conversions[i].convname == NULL)	{	  error (0, 0, _("invalid conversion: %s"), quote (str));	  usage (1);	}      str = new;  } while (new != NULL);}/* Return the value of STR, interpreted as a non-negative decimal integer,   optionally multiplied by various values.   Assign nonzero to *INVALID if STR does not represent a number in   this format. */static uintmax_tparse_integer (const char *str, int *invalid){  uintmax_t n;  char *suffix;  enum strtol_error e = xstrtoumax (str, &suffix, 10, &n, "bcEGkKMPTwYZ0");  if (e == LONGINT_INVALID_SUFFIX_CHAR && *suffix == 'x')    {      uintmax_t multiplier = parse_integer (suffix + 1, invalid);      if (multiplier != 0 && n * multiplier / multiplier != n)	{	  *invalid = 1;	  return 0;	}      n *= multiplier;    }  else if (e != LONGINT_OK)    {      *invalid = 1;      return 0;    }  return n;}static voidscanargs (int argc, char **argv){  int i;  --argc;  ++argv;  for (i = optind; i < argc; i++)    {      char *name, *val;      name = argv[i];      val = strchr (name, '=');      if (val == NULL)	{	  error (0, 0, _("unrecognized option %s"), quote (name));	  usage (1);	}      *val++ = '\0';      if (STREQ (name, "if"))	input_file = val;      else if (STREQ (name, "of"))	output_file = val;      else if (STREQ (name, "conv"))	parse_conversion (val);      else	{	  int invalid = 0;	  uintmax_t n = parse_integer (val, &invalid);	  if (STREQ (name, "ibs"))	    {	      input_blocksize = n;	      invalid |= input_blocksize != n || input_blocksize == 0;	      conversions_mask |= C_TWOBUFS;	    }	  else if (STREQ (name, "obs"))	    {	      output_blocksize = n;	      invalid |= output_blocksize != n || output_blocksize == 0;	      conversions_mask |= C_TWOBUFS;	    }	  else if (STREQ (name, "bs"))	    {	      output_blocksize = input_blocksize = n;	      invalid |= output_blocksize != n || output_blocksize == 0;	    }	  else if (STREQ (name, "cbs"))	    {	      conversion_blocksize = n;	      invalid |= (conversion_blocksize != n			  || conversion_blocksize == 0);	    }	  else if (STREQ (name, "skip"))	    skip_records = n;	  else if (STREQ (name, "seek"))	    seek_records = n;	  else if (STREQ (name, "count"))	    max_records = n;	  else	    {	      error (0, 0, _("unrecognized option %s=%s"),		     quote_n (0, name), quote_n (1, val));	      usage (1);	    }	  if (invalid)	    error (1, 0, _("invalid number %s"), quote (val));	}    }  /* If bs= was given, both `input_blocksize' and `output_blocksize' will     have been set to positive values.  If either has not been set,     bs= was not given, so make sure two buffers are used. */  if (input_blocksize == 0 || output_blocksize == 0)    conversions_mask |= C_TWOBUFS;  if (input_blocksize == 0)    input_blocksize = DEFAULT_BLOCKSIZE;  if (output_blocksize == 0)    output_blocksize = DEFAULT_BLOCKSIZE;  if (conversion_blocksize == 0)    conversions_mask &= ~(C_BLOCK | C_UNBLOCK);}/* Fix up translation table. */static voidapply_translations (void){  int i;#define MX(a) (bit_count (conversions_mask & (a)))  if ((MX (C_ASCII | C_EBCDIC | C_IBM) > 1)      || (MX (C_BLOCK | C_UNBLOCK) > 1)      || (MX (C_LCASE | C_UCASE) > 1)      || (MX (C_UNBLOCK | C_SYNC) > 1))    {      error (1, 0, _("\only one conv in {ascii,ebcdic,ibm}, {lcase,ucase}, {block,unblock}, {unblock,sync}"));    }#undef MX  if (conversions_mask & C_ASCII)    translate_charset (ebcdic_to_ascii);  if (conversions_mask & C_UCASE)    {      for (i = 0; i < 256; i++)	if (ISLOWER (trans_table[i]))	  trans_table[i] = TOUPPER (trans_table[i]);      translation_needed = 1;    }  else if (conversions_mask & C_LCASE)    {      for (i = 0; i < 256; i++)	if (ISUPPER (trans_table[i]))	  trans_table[i] = TOLOWER (trans_table[i]);      translation_needed = 1;    }  if (conversions_mask & C_EBCDIC)    {      translate_charset (ascii_to_ebcdic);      newline_character = ascii_to_ebcdic['\n'];      space_character = ascii_to_ebcdic[' '];    }  else if (conversions_mask & C_IBM)    {      translate_charset (ascii_to_ibm);      newline_character = ascii_to_ibm['\n'];      space_character = ascii_to_ibm[' '];    }}/* Apply the character-set translations specified by the user   to the NREAD bytes in BUF.  */static voidtranslate_buffer (char *buf, size_t nread){  char *cp;  size_t i;  for (i = nread, cp = buf; i; i--, cp++)    *cp = trans_table[(unsigned char) *cp];}/* If nonnzero, the last char from the previous call to `swab_buffer'   is saved in `saved_char'.  */static int char_is_saved = 0;/* Odd char from previous call.  */static char saved_char;/* Swap NREAD bytes in BUF, plus possibly an initial char from the   previous call.  If NREAD is odd, save the last char for the   next call.   Return the new start of the BUF buffer.  */static char *swab_buffer (char *buf, size_t *nread){  char *bufstart = buf;  register char *cp;  register int i;  /* Is a char left from last time?  */  if (char_is_saved)    {      *--bufstart = saved_char;      (*nread)++;      char_is_saved = 0;    }  if (*nread & 1)    {      /* An odd number of chars are in the buffer.  */      saved_char = bufstart[--*nread];      char_is_saved = 1;    }  /* Do the byte-swapping by moving every second character two     positions toward the end, working from the end of the buffer     toward the beginning.  This way we only move half of the data.  */  cp = bufstart + *nread;	/* Start one char past the last.  */  for (i = *nread / 2; i; i--, cp -= 2)    *cp = *(cp - 2);  return ++bufstart;}/* This is a wrapper for lseek.  It detects and warns about a kernel   bug that makes lseek a no-op for tape devices, even though the kernel   lseek return value suggests that the function succeeded.   The parameters are the same as those of the lseek function, but   with the addition of FILENAME, the name of the file associated with   descriptor FDESC.  The file name is used solely in the warning that's   printed when the bug is detected.  Return the same value that lseek   would have returned, but when the lseek bug is detected, return -1   to indicate that lseek failed.   The offending behavior has been confirmed with an Exabyte SCSI tape   drive accessed via /dev/nst0 on both Linux-2.2.17 and Linux-2.4.16.  */#ifdef __linux__# include <sys/mtio.h># define MT_SAME_POSITION(P, Q) \   ((P).mt_resid == (Q).mt_resid \    && (P).mt_fileno == (Q).mt_fileno \    && (P).mt_blkno == (Q).mt_blkno)static off_tskip_via_lseek (char const *filename, int fdesc, off_t offset, int whence){  struct mtget s1;  struct mtget s2;  off_t new_position;  int got_original_tape_position;  got_original_tape_position = (ioctl (fdesc, MTIOCGET, &s1) == 0);  /* known bad device type */  /* && s.mt_type == MT_ISSCSI2 */  new_position = lseek (fdesc, offset, whence);  if (0 <= new_position      && got_original_tape_position      && ioctl (fdesc, MTIOCGET, &s2) == 0      && MT_SAME_POSITION (s1, s2))    {      error (0, 0, _("warning: working around lseek kernel bug for file (%s)\n\  of mt_type=0x%0lx -- see <sys/mtio.h> for the list of types"),	     filename, s2.mt_type);      new_position = -1;    }  return new_position;}#else# define skip_via_lseek(Filename, Fd, Offset, Whence) lseek (Fd, Offset, Whence)#endif/* Throw away RECORDS blocks of BLOCKSIZE bytes on file descriptor FDESC,   which is open with read permission for FILE.  Store up to BLOCKSIZE   bytes of the data at a time in BUF, if necessary.  RECORDS must be   nonzero.  */static voidskip (int fdesc, char const *file, uintmax_t records, size_t blocksize,      char *buf){  off_t offset = records * blocksize;  /* Try lseek and if an error indicates it was an inappropriate     operation, fall back on using read.  */  if (offset / blocksize != records      || skip_via_lseek (file, fdesc, offset, SEEK_CUR) < 0)    {      while (records--)	{	  ssize_t nread = safe_read (fdesc, buf, blocksize);	  if (nread < 0)	    {	      error (0, errno, _("reading %s"), quote (file));	      quit (1);	    }	  /* POSIX doesn't say what to do when dd detects it has been	     asked to skip past EOF, so I assume it's non-fatal.	     FIXME: maybe give a warning.  */	  if (nread == 0)	    break;	}

⌨️ 快捷键说明

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