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

📄 copy.c

📁 Linux下文件工具。
💻 C
📖 第 1 页 / 共 4 页
字号:
/* copy.c -- core functions for copying files and directories   Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation.   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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  *//* Extracted from cp.c and librarified by Jim Meyering.  */#ifdef _AIX #pragma alloca#endif#include <config.h>#include <stdio.h>#include <assert.h>#include <sys/types.h>#if HAVE_HURD_H# include <hurd.h>#endif#include "system.h"#include "error.h"#include "backupfile.h"#include "savedir.h"#include "copy.h"#include "cp-hash.h"#include "hash.h"#include "hash-pjw.h"#include "same.h"#include "dirname.h"#include "full-write.h"#include "path-concat.h"#include "quote.h"#include "same.h"#include "xreadlink.h"#define DO_CHOWN(Chown, File, New_uid, New_gid)				\  (Chown (File, New_uid, New_gid)					\   /* If non-root uses -p, it's ok if we can't preserve ownership.	\      But root probably wants to know, e.g. if NFS disallows it,	\      or if the target system doesn't support file ownership.  */	\   && ((errno != EPERM && errno != EINVAL) || x->myeuid == 0))#define SAME_OWNER(A, B) ((A).st_uid == (B).st_uid)#define SAME_GROUP(A, B) ((A).st_gid == (B).st_gid)#define SAME_OWNER_AND_GROUP(A, B) (SAME_OWNER (A, B) && SAME_GROUP (A, B))#define UNWRITABLE(File_name, File_mode)		\  ( /* euidaccess is not meaningful for symlinks */	\    ! S_ISLNK (File_mode)				\    && euidaccess (File_name, W_OK) != 0)struct dir_list{  struct dir_list *parent;  ino_t ino;  dev_t dev;};/* Describe a just-created or just-renamed destination file.  */struct F_triple{  char const* name;  ino_t st_ino;  dev_t st_dev;};/* Initial size of the above hash table.  */#define DEST_INFO_INITIAL_CAPACITY 61int euidaccess ();int yesno ();static int copy_internal PARAMS ((const char *src_path, const char *dst_path,				  int new_dst, dev_t device,				  struct dir_list *ancestors,				  const struct cp_options *x,				  int move_mode,				  int *copy_into_self,				  int *rename_succeeded));/* Pointers to the file names:  they're used in the diagnostic that is issued   when we detect the user is trying to copy a directory into itself.  */static char const *top_level_src_path;static char const *top_level_dst_path;/* The invocation name of this program.  */extern char *program_name;/* Encapsulate selection of the file mode to be applied to   new non-directories.  */static mode_tget_dest_mode (const struct cp_options *option, mode_t mode){  /* In some applications (e.g., install), use precisely the     specified mode.  */  if (option->set_mode)    return option->mode;  /* Honor the umask for `cp', but not for `mv' or `cp -p'.     In addition, `cp' without -p must clear the set-user-ID and set-group-ID     bits.  POSIX requires it do that when creating new files.  */  if (!option->move_mode && !option->preserve_mode)    mode &= (option->umask_kill & ~(S_ISUID | S_ISGID));  return mode;}/* FIXME: describe *//* FIXME: rewrite this to use a hash table so we avoid the quadratic   performance hit that's probably noticeable only on trees deeper   than a few hundred levels.  See use of active_dir_map in remove.c  */static intis_ancestor (const struct stat *sb, const struct dir_list *ancestors){  while (ancestors != 0)    {      if (ancestors->ino == sb->st_ino && ancestors->dev == sb->st_dev)	return 1;      ancestors = ancestors->parent;    }  return 0;}/* Read the contents of the directory SRC_PATH_IN, and recursively   copy the contents to DST_PATH_IN.  NEW_DST is nonzero if   DST_PATH_IN is a directory that was created previously in the   recursion.   SRC_SB and ANCESTORS describe SRC_PATH_IN.   Set *COPY_INTO_SELF to nonzero if SRC_PATH_IN is a parent of   (or the same as) DST_PATH_IN;  otherwise, set it to zero.   Return 0 if successful, -1 if an error occurs. */static intcopy_dir (const char *src_path_in, const char *dst_path_in, int new_dst,	  const struct stat *src_sb, struct dir_list *ancestors,	  const struct cp_options *x, int *copy_into_self){  char *name_space;  char *namep;  struct cp_options non_command_line_options = *x;  int ret = 0;  name_space = savedir (src_path_in);  if (name_space == NULL)    {      /* This diagnostic is a bit vague because savedir can fail in         several different ways.  */      error (0, errno, _("cannot access %s"), quote (src_path_in));      return -1;    }  /* For cp's -H option, dereference command line arguments, but do not     dereference symlinks that are found via recursive traversal.  */  if (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS)    non_command_line_options.xstat = lstat;  namep = name_space;  while (*namep != '\0')    {      int local_copy_into_self;      char *src_path = path_concat (src_path_in, namep, NULL);      char *dst_path = path_concat (dst_path_in, namep, NULL);      if (dst_path == NULL || src_path == NULL)	xalloc_die ();      ret |= copy_internal (src_path, dst_path, new_dst, src_sb->st_dev,			    ancestors, &non_command_line_options, 0,			    &local_copy_into_self, NULL);      *copy_into_self |= local_copy_into_self;      free (dst_path);      free (src_path);      namep += strlen (namep) + 1;    }  free (name_space);  return -ret;}/* Copy a regular file from SRC_PATH to DST_PATH.   If the source file contains holes, copies holes and blocks of zeros   in the source file as holes in the destination file.   (Holes are read as zeroes by the `read' system call.)   Use DST_MODE as the 3rd argument in the call to open.   X provides many option settings.   Return 0 if successful, -1 if an error occurred.   *NEW_DST is as in copy_internal.  SRC_SB is the result   of calling xstat (aka stat in this case) on SRC_PATH.  */static intcopy_reg (const char *src_path, const char *dst_path,	  const struct cp_options *x, mode_t dst_mode, int *new_dst,	  struct stat const *src_sb){  char *buf;  int buf_size;  int dest_desc;  int source_desc;  struct stat sb;  struct stat src_open_sb;  char *cp;  int *ip;  int return_val = 0;  off_t n_read_total = 0;  int last_write_made_hole = 0;  int make_holes = (x->sparse_mode == SPARSE_ALWAYS);  source_desc = open (src_path, O_RDONLY);  if (source_desc < 0)    {      error (0, errno, _("cannot open %s for reading"), quote (src_path));      return -1;    }  if (fstat (source_desc, &src_open_sb))    {      error (0, errno, _("cannot fstat %s"), quote (src_path));      return_val = -1;      goto close_src_desc;    }  /* Compare the source dev/ino from the open file to the incoming,     saved ones obtained via a previous call to stat.  */  if (! SAME_INODE (*src_sb, src_open_sb))    {      error (0, 0,	     _("skipping file %s, as it was replaced while being copied"),	     quote (src_path));      return_val = -1;      goto close_src_desc;    }  /* These semantics are required for cp.     The if-block will be taken in move_mode.  */  if (*new_dst)    {      dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode);    }  else    {      dest_desc = open (dst_path, O_WRONLY | O_TRUNC, dst_mode);      if (dest_desc < 0 && x->unlink_dest_after_failed_open)	{	  if (unlink (dst_path))	    {	      error (0, errno, _("cannot remove %s"), quote (dst_path));	      return_val = -1;	      goto close_src_desc;	    }	  /* Tell caller that the destination file was unlinked.  */	  *new_dst = 1;	  /* Try the open again, but this time with different flags.  */	  dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode);	}    }  if (dest_desc < 0)    {      error (0, errno, _("cannot create regular file %s"), quote (dst_path));      return_val = -1;      goto close_src_desc;    }  /* Determine the optimal buffer size.  */  if (fstat (dest_desc, &sb))    {      error (0, errno, _("cannot fstat %s"), quote (dst_path));      return_val = -1;      goto close_src_and_dst_desc;    }  buf_size = ST_BLKSIZE (sb);#if HAVE_STRUCT_STAT_ST_BLOCKS  if (x->sparse_mode == SPARSE_AUTO && S_ISREG (sb.st_mode))    {      /* Use a heuristic to determine whether SRC_PATH contains any	 sparse blocks. */      if (fstat (source_desc, &sb))	{	  error (0, errno, _("cannot fstat %s"), quote (src_path));	  return_val = -1;	  goto close_src_and_dst_desc;	}      /* If the file has fewer blocks than would normally	 be needed for a file of its size, then	 at least one of the blocks in the file is a hole. */      if (S_ISREG (sb.st_mode)	  && sb.st_size / ST_NBLOCKSIZE > ST_NBLOCKS (sb))	make_holes = 1;    }#endif  /* Make a buffer with space for a sentinel at the end.  */  buf = (char *) alloca (buf_size + sizeof (int));  for (;;)    {      ssize_t n_read = read (source_desc, buf, buf_size);      if (n_read < 0)	{#ifdef EINTR	  if (errno == EINTR)	    continue;#endif	  error (0, errno, _("reading %s"), quote (src_path));	  return_val = -1;	  goto close_src_and_dst_desc;	}      if (n_read == 0)	break;      n_read_total += n_read;      ip = 0;      if (make_holes)	{	  buf[n_read] = 1;	/* Sentinel to stop loop.  */	  /* Find first nonzero *word*, or the word with the sentinel.  */	  ip = (int *) buf;	  while (*ip++ == 0)	    ;	  /* Find the first nonzero *byte*, or the sentinel.  */	  cp = (char *) (ip - 1);	  while (*cp++ == 0)	    ;	  /* If we found the sentinel, the whole input block was zero,	     and we can make a hole.  */	  if (cp > buf + n_read)	    {	      /* Make a hole.  */	      if (lseek (dest_desc, (off_t) n_read, SEEK_CUR) < 0L)		{		  error (0, errno, _("cannot lseek %s"), quote (dst_path));		  return_val = -1;		  goto close_src_and_dst_desc;		}	      last_write_made_hole = 1;	    }	  else	    /* Clear to indicate that a normal write is needed. */	    ip = 0;	}      if (ip == 0)	{	  size_t n = n_read;	  if (full_write (dest_desc, buf, n) != n)	    {	      error (0, errno, _("writing %s"), quote (dst_path));	      return_val = -1;	      goto close_src_and_dst_desc;	    }	  last_write_made_hole = 0;	}    }  /* If the file ends with a `hole', something needs to be written at     the end.  Otherwise the kernel would truncate the file at the end     of the last write operation.  */  if (last_write_made_hole)    {#if HAVE_FTRUNCATE      /* Write a null character and truncate it again.  */      if (full_write (dest_desc, "", 1) != 1	  || ftruncate (dest_desc, n_read_total) < 0)#else      /* Seek backwards one character and write a null.  */      if (lseek (dest_desc, (off_t) -1, SEEK_CUR) < 0L	  || full_write (dest_desc, "", 1) != 1)#endif	{	  error (0, errno, _("writing %s"), quote (dst_path));	  return_val = -1;	}    }

⌨️ 快捷键说明

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