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

📄 sparse.c

📁 gnu tar 源码包。 tar 软件是 Unix 系统下的一个打包软件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Functions for dealing with sparse files   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.   This program is free software; you can redistribute it and/or modify it   under the terms of the GNU General Public License as published by the   Free Software Foundation; either version 3, or (at your option) any later   version.   This program is distributed in the hope that it will be useful, but   WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General   Public License for more details.   You should have received a copy of the GNU General Public License along   with this program; if not, write to the Free Software Foundation, Inc.,   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */#include <system.h>#include <inttostr.h>#include <quotearg.h>#include "common.h"struct tar_sparse_file;static bool sparse_select_optab (struct tar_sparse_file *file);enum sparse_scan_state  {    scan_begin,    scan_block,    scan_end  };struct tar_sparse_optab{  bool (*init) (struct tar_sparse_file *);  bool (*done) (struct tar_sparse_file *);  bool (*sparse_member_p) (struct tar_sparse_file *);  bool (*dump_header) (struct tar_sparse_file *);  bool (*fixup_header) (struct tar_sparse_file *);  bool (*decode_header) (struct tar_sparse_file *);  bool (*scan_block) (struct tar_sparse_file *, enum sparse_scan_state,		      void *);  bool (*dump_region) (struct tar_sparse_file *, size_t);  bool (*extract_region) (struct tar_sparse_file *, size_t);};struct tar_sparse_file{  int fd;                           /* File descriptor */  bool seekable;                    /* Is fd seekable? */  off_t offset;                     /* Current offset in fd if seekable==false.				       Otherwise unused */  off_t dumped_size;                /* Number of bytes actually written				       to the archive */  struct tar_stat_info *stat_info;  /* Information about the file */  struct tar_sparse_optab const *optab; /* Operation table */  void *closure;                    /* Any additional data optab calls might				       require */};/* Dump zeros to file->fd until offset is reached. It is used instead of   lseek if the output file is not seekable */static booldump_zeros (struct tar_sparse_file *file, off_t offset){  static char const zero_buf[BLOCKSIZE];  if (offset < file->offset)    {      errno = EINVAL;      return false;    }  while (file->offset < offset)    {      size_t size = (BLOCKSIZE < offset - file->offset		     ? BLOCKSIZE		     : offset - file->offset);      ssize_t wrbytes;      wrbytes = write (file->fd, zero_buf, size);      if (wrbytes <= 0)	{	  if (wrbytes == 0)	    errno = EINVAL;	  return false;	}      file->offset += wrbytes;    }  return true;}static booltar_sparse_member_p (struct tar_sparse_file *file){  if (file->optab->sparse_member_p)    return file->optab->sparse_member_p (file);  return false;}static booltar_sparse_init (struct tar_sparse_file *file){  memset (file, 0, sizeof *file);  if (!sparse_select_optab (file))    return false;  if (file->optab->init)    return file->optab->init (file);  return true;}static booltar_sparse_done (struct tar_sparse_file *file){  if (file->optab->done)    return file->optab->done (file);  return true;}static booltar_sparse_scan (struct tar_sparse_file *file, enum sparse_scan_state state,		 void *block){  if (file->optab->scan_block)    return file->optab->scan_block (file, state, block);  return true;}static booltar_sparse_dump_region (struct tar_sparse_file *file, size_t i){  if (file->optab->dump_region)    return file->optab->dump_region (file, i);  return false;}static booltar_sparse_extract_region (struct tar_sparse_file *file, size_t i){  if (file->optab->extract_region)    return file->optab->extract_region (file, i);  return false;}static booltar_sparse_dump_header (struct tar_sparse_file *file){  if (file->optab->dump_header)    return file->optab->dump_header (file);  return false;}static booltar_sparse_decode_header (struct tar_sparse_file *file){  if (file->optab->decode_header)    return file->optab->decode_header (file);  return true;}static booltar_sparse_fixup_header (struct tar_sparse_file *file){  if (file->optab->fixup_header)    return file->optab->fixup_header (file);  return true;}static boollseek_or_error (struct tar_sparse_file *file, off_t offset){  if (file->seekable      ? lseek (file->fd, offset, SEEK_SET) < 0      : ! dump_zeros (file, offset))    {      seek_diag_details (file->stat_info->orig_file_name, offset);      return false;    }  return true;}/* Takes a blockful of data and basically cruises through it to see if   it's made *entirely* of zeros, returning a 0 the instant it finds   something that is a nonzero, i.e., useful data.  */static boolzero_block_p (char const *buffer, size_t size){  while (size--)    if (*buffer++)      return false;  return true;}static voidsparse_add_map (struct tar_stat_info *st, struct sp_array const *sp){  struct sp_array *sparse_map = st->sparse_map;  size_t avail = st->sparse_map_avail;  if (avail == st->sparse_map_size)    st->sparse_map = sparse_map =      x2nrealloc (sparse_map, &st->sparse_map_size, sizeof *sparse_map);  sparse_map[avail] = *sp;  st->sparse_map_avail = avail + 1;}/* Scan the sparse file and create its map */static boolsparse_scan_file (struct tar_sparse_file *file){  struct tar_stat_info *st = file->stat_info;  int fd = file->fd;  char buffer[BLOCKSIZE];  size_t count;  off_t offset = 0;  struct sp_array sp = {0, 0};  if (!lseek_or_error (file, 0))    return false;  st->archive_file_size = 0;    if (!tar_sparse_scan (file, scan_begin, NULL))    return false;  while ((count = safe_read (fd, buffer, sizeof buffer)) != 0	 && count != SAFE_READ_ERROR)    {      /* Analyze the block.  */      if (zero_block_p (buffer, count))	{	  if (sp.numbytes)	    {	      sparse_add_map (st, &sp);	      sp.numbytes = 0;	      if (!tar_sparse_scan (file, scan_block, NULL))		return false;	    }	}      else	{	  if (sp.numbytes == 0)	    sp.offset = offset;	  sp.numbytes += count;	  st->archive_file_size += count;	  if (!tar_sparse_scan (file, scan_block, buffer))	    return false;	}      offset += count;    }  if (sp.numbytes == 0)    sp.offset = offset;  sparse_add_map (st, &sp);  st->archive_file_size += count;  return tar_sparse_scan (file, scan_end, NULL);}static struct tar_sparse_optab const oldgnu_optab;static struct tar_sparse_optab const star_optab;static struct tar_sparse_optab const pax_optab;static boolsparse_select_optab (struct tar_sparse_file *file){  switch (current_format == DEFAULT_FORMAT ? archive_format : current_format)    {    case V7_FORMAT:    case USTAR_FORMAT:      return false;    case OLDGNU_FORMAT:    case GNU_FORMAT: /*FIXME: This one should disappear? */      file->optab = &oldgnu_optab;      break;    case POSIX_FORMAT:      file->optab = &pax_optab;      break;    case STAR_FORMAT:      file->optab = &star_optab;      break;    default:      return false;    }  return true;}static boolsparse_dump_region (struct tar_sparse_file *file, size_t i){  union block *blk;  off_t bytes_left = file->stat_info->sparse_map[i].numbytes;  if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))    return false;  while (bytes_left > 0)    {      size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;      size_t bytes_read;      blk = find_next_block ();      bytes_read = safe_read (file->fd, blk->buffer, bufsize);      if (bytes_read == SAFE_READ_ERROR)	{          read_diag_details (file->stat_info->orig_file_name,	                     (file->stat_info->sparse_map[i].offset			      + file->stat_info->sparse_map[i].numbytes			      - bytes_left),			     bufsize);	  return false;	}      memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);      bytes_left -= bytes_read;      file->dumped_size += bytes_read;      mv_size_left (file->stat_info->archive_file_size - file->dumped_size);      set_next_block_after (blk);    }  return true;}static boolsparse_extract_region (struct tar_sparse_file *file, size_t i){  size_t write_size;  if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))    return false;  write_size = file->stat_info->sparse_map[i].numbytes;  if (write_size == 0)    {      /* Last block of the file is a hole */      if (file->seekable && sys_truncate (file->fd))	truncate_warn (file->stat_info->orig_file_name);    }  else while (write_size > 0)    {      size_t count;      size_t wrbytes = (write_size > BLOCKSIZE) ? BLOCKSIZE : write_size;      union block *blk = find_next_block ();      if (!blk)	{	  ERROR ((0, 0, _("Unexpected EOF in archive")));	  return false;	}      set_next_block_after (blk);      count = full_write (file->fd, blk->buffer, wrbytes);      write_size -= count;      file->dumped_size += count;      mv_size_left (file->stat_info->archive_file_size - file->dumped_size);      file->offset += count;      if (count != wrbytes)	{	  write_error_details (file->stat_info->orig_file_name,			       count, wrbytes);	  return false;	}    }  return true;}/* Interface functions */enum dump_statussparse_dump_file (int fd, struct tar_stat_info *st){  bool rc;  struct tar_sparse_file file;  if (!tar_sparse_init (&file))    return dump_status_not_implemented;  file.stat_info = st;  file.fd = fd;  file.seekable = true; /* File *must* be seekable for dump to work */  rc = sparse_scan_file (&file);

⌨️ 快捷键说明

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