home *** CD-ROM | disk | FTP | other *** search
- /* cp.c -- file copying (main routines)
- Copyright (C) 1989, 1990 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Written by Torbjorn Granlund, and David MacKenzie. */
-
- /*
- * MS-DOS port (c) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
- *
- * To this port, the same copying conditions apply as to the
- * original release.
- *
- * IMPORTANT:
- * This file is not identical to the original GNU release!
- * You should have received this code as patch to the official
- * GNU release.
- *
- * MORE IMPORTANT:
- * This port comes with ABSOLUTELY NO WARRANTY.
- *
- * $Header: e:/gnu/fileutil/RCS/cp.c'v 1.3.0.2 90/06/29 00:46:37 tho Stable $
- */
-
- /* Yet to be done:
-
- * Symlink translation. */
-
- #include <stdio.h>
- #include "cp.h"
- #include "getopt.h"
- #include "backupfile.h"
-
- #ifdef MSDOS
- extern enum backup_type get_version (char *version);
- extern char *savedir (char *dir, unsigned name_size);
- #endif /* MSDOS */
-
- #ifndef _POSIX_SOURCE
- /* This definition assumes that MODE has the S_IFIFO bit set. */
- #define mkfifo(path, mode) (mknod ((path), (mode), 0))
-
- int geteuid ();
- #endif
-
- enum backup_type get_version ();
-
- #define INITIAL_HASH_MODULE 100
-
- #define INITIAL_ENTRY_TAB_SIZE 70
-
- /* A pointer to either lstat or stat, depending on
- whether dereferencing of symlinks is done. */
- #ifdef MSDOS
- int (*xstat) (char *, struct stat *);
- #else
- int (*xstat) ();
- #endif /* MSDOS */
-
- /* The invocation name of this program. */
- char *program_name;
-
- /* If nonzero, dereference symbolic links (copy the files they point to). */
- int flag_dereference = 1;
-
- /* If nonzero, override protection for target files if possible. */
- int flag_force = 0;
-
- /* If nonzero, always query before removing existing targets. */
- int flag_interactive = 0;
-
- /* If nonzero, give the copies the original files' permissions. */
- int flag_preserve = 0;
-
- /* If nonzero, copy directories recursively and copy special files
- as themselves rather than copying their contents. */
- int flag_recursive = 0;
-
- /* If nonzero, when copying recursively, skip any subdirectories that are
- on different filesystems from the one we started on. */
- int flag_one_file_system = 0;
-
- /* If nonzero, display the names of the files before copying them. */
- int flag_verbose = 0;
-
- /* The error code to return to the system. */
- int exit_status = 0;
-
- /* If nonzero, effective uid is 0. */
- int root;
-
- /* The bits to preserve in created files' modes. */
- int umask_kill;
-
- /* If nonzero, skip unwritable files if not interactive. */
- int stdin_not_tty;
-
- struct option long_opts[] =
- {
- {"backup", 0, NULL, 'b'},
- {"force", 0, &flag_force, 1},
- {"interactive", 0, &flag_interactive, 1},
- {"no-dereference", 0, &flag_dereference, 0},
- {"one-file-system", 0, &flag_one_file_system, 1},
- {"preserve", 0, &flag_preserve, 1},
- {"recursive", 0, &flag_recursive, 1},
- {"suffix", 1, NULL, 'S'},
- {"verbose", 0, &flag_verbose, 1},
- {"version-control", 1, NULL, 'V'},
- {NULL, 0, NULL, 0}
- };
-
- void
- main (argc, argv)
- int argc;
- char *argv[];
- {
- int c;
- int ind;
- int make_backups = 0;
- char *version;
-
- program_name = argv[0];
- #ifdef MSDOS
- strlwr (program_name);
- #endif /* not MSDOS */
-
- version = getenv ("SIMPLE_BACKUP_SUFFIX");
- if (version)
- simple_backup_suffix = version;
- version = getenv ("VERSION_CONTROL");
-
- /* Find out the current file creation mask, to knock the right bits
- when using chmod. The creation mask is set to to be liberal, so
- that created directories can be written, even if it would not
- have been allowed with the mask this process was started with. */
-
- #ifdef MSDOS /* not 100%ly correct ... */
- umask_kill = 07777 ^ umask (0);
- #else /* not MSDOS */
- umask_kill = 0777777 ^ umask (0);
- #endif /* not MSDOS */
-
-
- while ((c = getopt_long (argc, argv, "bdfioprvRS:V:", long_opts, &ind))
- != EOF)
- {
- if (c == 0 && long_opts[ind].flag == NULL)
- c = long_opts[ind].val;
- switch (c)
- {
- case 0:
- break;
-
- case 'b':
- make_backups = 1;
- break;
-
- case 'd':
- flag_dereference = 0;
- break;
-
- case 'f':
- flag_force = 1;
- break;
-
- case 'i':
- flag_interactive = 1;
- break;
-
- case 'o':
- flag_one_file_system = 1;
- break;
-
- case 'p':
- flag_preserve = 1;
- break;
-
- case 'r':
- case 'R':
- flag_recursive = 1;
- break;
-
- case 'v':
- flag_verbose = 1;
- break;
-
- case 'S':
- simple_backup_suffix = optarg;
- break;
-
- case 'V':
- version = optarg;
- break;
-
- default:
- usage ((char *) 0);
- }
- }
-
- if (make_backups)
- backup_type = get_version (version);
-
- if (flag_interactive)
- flag_force = 0;
-
- if (flag_preserve == 1)
- #ifdef MSDOS /* not 100%ly correct ... */
- umask_kill = 07777;
- #else /* not MSDOS */
- umask_kill = 0777777;
- #endif /* not MSDOS */
-
- /* The key difference between -d (+no-dereference) and not is the version
- of `stat' to call. */
-
- if (flag_dereference)
- xstat = stat;
- else
- xstat = lstat;
-
- stdin_not_tty = !isatty (0);
- root = (geteuid () == 0);
-
- /* Allocate space for remembering copied and created files. */
-
- hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
-
- exit_status |= do_copy (argc, argv);
-
- exit (exit_status);
- }
-
- /* Scan the arguments, and copy each by calling `copy'.
- Return 0 if successful, 1 if any errors occur. */
-
- int
- do_copy (argc, argv)
- int argc;
- char *argv[];
- {
- char *target;
- struct stat sb;
- int new_dst = 0;
- int ret = 0;
-
- if (optind >= argc)
- usage ("missing file arguments");
- if (optind >= argc - 1)
- usage ("missing file argument");
-
- target = argv[argc - 1];
- #ifdef MSDOS
- strlwr (target);
- #endif /* MSDOS */
-
- strip_trailing_slashes (target);
-
- if (lstat (target, &sb))
- {
- if (errno != ENOENT)
- {
- error (0, errno, "%s", target);
- return 1;
- }
- else
- new_dst = 1;
- }
- else
- {
- struct stat sbx;
-
- /* If `target' is not a symlink to a nonexistent file, use
- the results of stat instead of lstat, so we can copy files
- into symlinks to directories. */
- if (stat (target, &sbx) == 0)
- sb = sbx;
- }
-
- if (!new_dst && (sb.st_mode & S_IFMT) == S_IFDIR)
- {
- /* cp e_file_1...e_file_n e_dir
- copy the files `e_file_1' through `e_file_n'
- to the existing directory `e_dir'. */
-
- for (;;)
- {
- char *arg;
- char *ap;
- char *dst_path;
-
- arg = argv[optind];
-
- strip_trailing_slashes (arg);
-
- /* Append the last component of `arg' to `target'. */
-
- ap = rindex (arg, '/');
- if (ap == 0)
- ap = arg;
- else
- ap++;
- dst_path = xmalloc (strlen (target) + strlen (ap) + 2);
- str_cpy (str_cpy (str_cpy (dst_path, target), "/"), ap);
-
- ret |= copy (arg, dst_path, new_dst, 0, (struct dir_list *) 0);
- forget_all ();
-
- ++optind;
- if (optind == argc - 1)
- break;
- }
- return ret;
- }
- else if (argc - optind == 2)
- return copy (argv[optind], target, new_dst, 0, (struct dir_list *) 0);
- else
- usage ("when copying multiple files, last argument must be a directory");
- }
-
- /* Copy the file `src_path' to the file `dst_path'. The files may be of
- any type. If the file `dst_path' cannot exist because its parent
- directory was just created, `new_dst' should be non-zero. If
- `dst_path' might already exist, `new_dst' should be zero.
- `device' is the device number of the parent directory, or 0 if
- this file has no known parent. `ancestors' points to a linked, null
- terminated list of parent directories of `src_path'.
- Return 0 if successful, 1 if an error occurs. */
-
- int
- copy (src_path, dst_path, new_dst, device, ancestors)
- char *src_path;
- char *dst_path;
- int new_dst;
- dev_t device;
- struct dir_list *ancestors;
- {
- struct stat src_sb;
- struct stat dst_sb;
- int mode;
- int type;
- char *earlier_file;
- int may_overwrite;
- char *dst_backup = NULL;
-
- #ifdef MSDOS
- strlwr(src_path);
- strlwr(dst_path);
- #endif /* MSDOS */
-
- if ((*xstat) (src_path, &src_sb))
- {
- error (0, errno, "%s", src_path);
- return 1;
- }
-
- /* Are we crossing a file system boundary? */
- if (flag_one_file_system && device != 0 && device != src_sb.st_dev)
- return 0;
-
- /* We wouldn't insert a node unless nlink > 1, except that we need to
- find created files so as to not copy infinitely if a directory is
- copied into itself. */
-
- earlier_file = remember_copied (dst_path, src_sb.st_ino, src_sb.st_dev);
-
- /* Have we encountered a file just created? */
-
- if (earlier_file == &new_file)
- return 0;
-
- if (flag_verbose)
- printf (" %s -> %s\n", src_path, dst_path);
-
- /* Did we copy this inode somewhere else (in this command line argument)
- and therefore this is a second hard link to the inode? */
-
- if (!flag_dereference && src_sb.st_nlink > 1 && earlier_file)
- {
- if (!new_dst)
- {
- if (backup_type != none)
- {
- dst_backup = find_backup_file_name (dst_path);
- if (dst_backup == NULL)
- error (1, 0, "virtual memory exhausted");
- if (rename (dst_path, dst_backup))
- {
- if (errno != ENOENT)
- {
- error (0, errno, "cannot backup `%s'", dst_path);
- free (dst_backup);
- return 1;
- }
- else
- {
- free (dst_backup);
- dst_backup = NULL;
- }
- }
- }
- else if (unlink (dst_path) && errno != ENOENT)
- {
- error (0, errno, "cannot remove old link `%s'", dst_path);
- return 1;
- }
- }
- if (link (earlier_file, dst_path))
- {
- error (0, errno, "cannot create link `%s'", dst_path);
- goto un_backup;
- }
- if (dst_backup)
- free (dst_backup);
- return 0;
- }
-
- mode = src_sb.st_mode;
- type = src_sb.st_mode & S_IFMT;
-
- if (type == S_IFDIR && !flag_recursive)
- {
- error (0, 0, "%s: omitting directory", src_path);
- return 1;
- }
-
- if (!new_dst)
- {
- if ((*xstat) (dst_path, &dst_sb))
- {
- if (errno != ENOENT)
- {
- error (0, errno, "%s", dst_path);
- return 1;
- }
- else
- new_dst = 1;
- }
- else
- {
- /* The file exists already. */
- #ifndef MSDOS
- if (src_sb.st_ino == dst_sb.st_ino && src_sb.st_dev == dst_sb.st_dev)
- {
- error (0, 0, "`%s' and `%s' are the same file (omitted)",
- src_path, dst_path);
- return 1;
- }
- #endif /* not MSDOS */
-
- if ((dst_sb.st_mode & S_IFMT) == S_IFDIR && type != S_IFDIR)
- {
- error (0, 0, "%s: cannot overwrite directory with non-directory",
- dst_path);
- return 1;
- }
-
- /* Treat the file as nonwritable if it lacks write permission bits,
- even if we are root. */
- #ifdef S_IFLNK
- if (type == S_IFLNK)
- may_overwrite = 1;
- else
- #endif
- may_overwrite =
- eaccess_stat (&dst_sb,
- #ifdef MSDOS
- W_OK) == 0
- #else /* not MSDOS */
- type == S_IFDIR ? (W_OK | X_OK) : W_OK) == 0
- #endif /* not MSDOS */
- && (dst_sb.st_mode & 0222)
- && (type != S_IFDIR
- || (dst_sb.st_mode & 0111));
-
- if (flag_interactive)
- {
- fprintf (stderr, "%s: replace `%s'? ", program_name, dst_path);
- if (!yesno ())
- return 0;
- }
- else if (!flag_force && !may_overwrite)
- {
- if (stdin_not_tty)
- {
- error (0, 0, "%s: no write permission", dst_path);
- return 1;
- }
- fprintf (stderr, "%s: override mode %04o for `%s'? ",
- program_name, dst_sb.st_mode & 0777, dst_path);
- if (!yesno ())
- return 0;
- }
-
- if (backup_type != none)
- {
- dst_backup = find_backup_file_name (dst_path);
- if (dst_backup == NULL)
- error (1, 0, "virtual memory exhausted");
- if (rename (dst_path, dst_backup))
- {
- if (errno != ENOENT)
- {
- error (0, errno, "cannot backup `%s'", dst_path);
- free (dst_backup);
- return 1;
- }
- else
- {
- free (dst_backup);
- dst_backup = NULL;
- }
- }
- new_dst = 1;
- }
- else if (!may_overwrite)
- {
- if (type == S_IFDIR)
- {
- /* Temporarily change mode to allow overwriting. */
- if (chmod (dst_path, dst_sb.st_mode | S_IEXEC | S_IWRITE))
- {
- error (0, errno, "%s", dst_path);
- return 1;
- }
- }
- else
- {
- if (unlink (dst_path) && errno != ENOENT)
- {
- error (0, errno, "cannot remove old link to `%s'",
- dst_path);
- return 1;
- }
- new_dst = 1;
- }
- }
- }
- }
-
- if (!flag_recursive)
- {
- if (copy_reg (src_path, dst_path))
- goto un_backup;
- }
- else
- switch (type)
- {
- #ifdef S_IFIFO
- case S_IFIFO:
- /* If a fifo already exists, we cannot do a better one. */
- if (new_dst)
- {
- if (mkfifo (dst_path, mode & umask_kill))
- {
- error (0, errno, "cannot make fifo `%s'", dst_path);
- goto un_backup;
- }
- }
- break;
- #endif
-
- #ifndef MSDOS
- case S_IFBLK:
- case S_IFCHR:
- #ifdef S_IFSOCK
- case S_IFSOCK:
- #endif
- if (!root)
- {
- error (0, 0, "%s: omitting special file", src_path);
- goto un_backup;
- }
- if (!new_dst && unlink (dst_path) && errno != ENOENT)
- {
- error (0, errno, "cannot remove old link to `%s'", dst_path);
- return 1;
- }
-
- if (mknod (dst_path, mode & umask_kill, src_sb.st_rdev))
- {
- error (0, errno, "cannot create special file `%s'", dst_path);
- goto un_backup;
- }
- break;
- #endif /* !MSDOS */
-
- case S_IFDIR:
- {
- struct dir_list *dir;
-
- /* If this directory has been copied before during the
- recursion, there's a symbolic link to an ancestor
- directory of the symbolic link. It's impossible to
- continue to copy this, unless we've got an infinite disk. */
-
- if (is_ancestor (&src_sb, ancestors))
- {
- error (0, 0, "%s: omitting cyclic symbolic link", src_path);
- goto un_backup;
- }
-
- /* Insert the current directory in the list of parents. */
-
- dir = (struct dir_list *) alloca (sizeof (struct dir_list));
- #ifdef MSDOS /* always short of stack space ... */
- if (!dir)
- error (1, 0, "%s: stack overflow", src_path);
- #endif /* MSDOS */
- dir->parent = ancestors;
- dir->ino = src_sb.st_ino;
- dir->dev = src_sb.st_dev;
-
- /* Create the directory. If a directory already exists, we
- cannot create a better one. */
-
- if (new_dst)
- {
- /* Create the new directory writable and searchable, so
- we can create new entries in it. */
-
- #ifdef MSDOS
- if (mkdir (dst_path))
- #else /* not MSDOS */
- if (mkdir (dst_path, 0700))
- #endif /* not MSDOS */
- {
- error (0, errno, "cannot create directory `%s'", dst_path);
- goto un_backup;
- }
-
- /* Insert the created directory's inode and device
- numbers into the search structure, so that we can
- avoid copying it again. */
-
- if (remember_created (dst_path))
- goto un_backup;
- }
-
- /* Now, copy the contents of the directory. */
-
- if (copy_dir (src_path, dst_path, new_dst, &src_sb, dir))
- goto err_return;
- }
- break;
-
- case S_IFREG:
- if (copy_reg (src_path, dst_path))
- goto un_backup;
- break;
-
- #ifdef S_IFLNK
- case S_IFLNK:
- {
- char *link_val = (char *) alloca (src_sb.st_size + 1);
-
- if (readlink (src_path, link_val, src_sb.st_size) < 0)
- {
- error (0, errno, "cannot read symbolic link `%s'", src_path);
- goto un_backup;
- }
- link_val[src_sb.st_size] = '\0';
-
- if (!new_dst && unlink (dst_path) && errno != ENOENT)
- {
- error (0, errno, "cannot remove old link to `%s'", dst_path);
- return 1;
- }
-
- if (symlink (link_val, dst_path))
- {
- error (0, errno, "cannot create symbolic link `%s'", dst_path);
- goto un_backup;
- }
- }
- return 0;
- #endif
-
- default:
- error (0, 0, "%s: unknown file type (omitted)", src_path);
- goto un_backup;
- }
-
- if ((flag_preserve || new_dst) && (type == S_IFREG || type == S_IFDIR))
- {
- if (chmod (dst_path, mode & umask_kill))
- {
- error (0, errno, "%s", dst_path);
- goto err_return;
- }
- }
- else if (type == S_IFDIR && !new_dst && !may_overwrite)
- {
- /* Reset the temporarily changed mode. */
- if (chmod (dst_path, dst_sb.st_mode))
- {
- error (0, errno, "%s", dst_path);
- goto err_return;
- }
- }
-
- /* Adjust the times (and if possible, ownership) for the copy. */
-
- if (flag_preserve)
- {
- struct utimbuf tv;
-
- tv.actime = src_sb.st_atime;
- tv.modtime = src_sb.st_mtime;
-
- if (utime (dst_path, &tv))
- {
- error (0, errno, "%s", dst_path);
- goto err_return;
- }
-
- #ifndef MSDOS
- if (chown (dst_path, src_sb.st_uid, src_sb.st_gid) && errno != EPERM)
- {
- error (0, errno, "%s", dst_path);
- goto err_return;
- }
- #endif /* not MSDOS */
- }
-
- if (dst_backup)
- free (dst_backup);
- return 0;
-
- err_return:
- if (dst_backup)
- free (dst_backup);
- return 1;
-
- un_backup:
- if (dst_backup)
- {
- if (rename (dst_backup, dst_path))
- error (0, errno, "cannot un-backup `%s'", dst_path);
- free (dst_backup);
- }
- return 1;
- }
-
- /* Read the contents of the directory `src_path_in', and recursively
- copy the contents to `dst_path_in'. `new_dst' is non-zero if
- `dst_path_in' is a directory that was created previously in the
- recursion. Return 0 if successful, -1 if an error occurs. */
-
- int
- copy_dir (src_path_in, dst_path_in, new_dst, src_sb, ancestors)
- char *src_path_in;
- char *dst_path_in;
- int new_dst;
- struct stat *src_sb;
- struct dir_list *ancestors;
- {
- char *name_space;
- char *namep;
- char *src_path;
- char *dst_path;
- int ret = 0;
-
- errno = 0;
- name_space = savedir (src_path_in, src_sb->st_size);
- if (name_space == 0)
- {
- if (errno)
- {
- error (0, errno, "%s", src_path_in);
- return -1;
- }
- else
- error (1, 0, "virtual memory exhausted");
- }
-
- namep = name_space;
- while (*namep != '\0')
- {
- int fn_length = strlen (namep) + 1;
-
- dst_path = xmalloc (strlen (dst_path_in) + fn_length + 1);
- src_path = xmalloc (strlen (src_path_in) + fn_length + 1);
-
- str_cpy (str_cpy (str_cpy (src_path, src_path_in), "/"), namep);
- str_cpy (str_cpy (str_cpy (dst_path, dst_path_in), "/"), namep);
-
- ret |= copy (src_path, dst_path, new_dst, src_sb->st_dev, ancestors);
-
- /* Free the memory for `src_path'. The memory for `dst_path'
- cannot be deallocated, since it is used to create multiple
- hard links. (Of course it is possible to optimize memory
- allocation, as most files have only one link.) */
-
- free (src_path);
-
- namep += fn_length;
- }
- free (name_space);
- return -ret;
- }
-
- /* Copy a regular file from `src_path' to `dst_path'. Large blocks of zeroes,
- as well as holes in the source file, are made into holes in the
- target file. (Holes are read as zero by the `read' system call.)
- Return 0 if successful, -1 if an error occurred. */
-
- int
- copy_reg (src_path, dst_path)
- char *src_path;
- char *dst_path;
- {
- char *buf;
- int buf_size;
- int target_desc;
- int source_desc;
- int n_read;
- int n_written;
- struct stat sb;
- int return_val = 0;
- long n_read_total = 0;
- char *cp;
- int *ip;
- int last_write_made_hole = 0;
-
- #ifdef MSDOS
- source_desc = open (src_path, O_BINARY | O_RDONLY);
- #else
- source_desc = open (src_path, O_RDONLY);
- #endif /* MSDOS */
- if (source_desc < 0)
- {
- error (0, errno, "%s", src_path);
- return -1;
- }
-
- /* Create the new regular file with small permissions initially,
- not to create a security hole. */
-
- #ifdef MSDOS
- target_desc = open (dst_path, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0600);
- #else
- target_desc = open (dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- #endif /* MSDOS */
- if (target_desc < 0)
- {
- error (0, errno, "cannot create regular file `%s'", dst_path);
- return_val = -1;
- goto ret2;
- }
-
- /* Find out the appropriate buffer length. */
-
- if (fstat (target_desc, &sb))
- {
- error (0, errno, "%s", dst_path);
- return_val = -1;
- goto ret;
- }
-
- buf_size = ST_BLKSIZE (sb);
-
- /* Make a buffer with space for a sentinel at the end. */
-
- buf = (char *) alloca (buf_size + sizeof (int));
- #ifdef MSDOS
- if (!buf)
- error (2, 0, "%s: stack overflow", src_path);
- #endif /* MSDOS */
-
- for (;;)
- {
- n_read = read (source_desc, buf, buf_size);
- if (n_read < 0)
- {
- error (0, errno, "%s", src_path);
- return_val = -1;
- goto ret;
- }
- if (n_read == 0)
- break;
-
- #ifdef MSDOS
- n_read_total += (long) n_read;
- #else /* not MSDOS */
- n_read_total += n_read;
- #endif /* not MSDOS */
-
- buf[n_read] = 1; /* Sentinel to stop loop. */
-
- /* Find first non-zero *word*, or the word with the sentinel. */
-
- ip = (int *) buf;
- while (*ip++ == 0)
- ;
-
- /* Find the first non-zero *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 (target_desc, (off_t) n_read, L_INCR) < 0L)
- {
- error (0, errno, "%s", dst_path);
- return_val = -1;
- goto ret;
- }
- last_write_made_hole = 1;
- }
- else
- {
- n_written = write (target_desc, buf, n_read);
- if (n_written < n_read)
- {
- error (0, errno, "%s", dst_path);
- return_val = -1;
- goto ret;
- }
- 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)
- {
- #ifndef FTRUNCATE_MISSING
- /* Write a null character and truncate it again. */
- if (write (target_desc, "", 1) != 1
- || ftruncate (target_desc, n_read_total) < 0)
- #else
- /* Seek backwards one character and write a null. */
- if (lseek (target_desc, (off_t) -1, L_INCR) < 0L
- || write (target_desc, "", 1) != 1)
- #endif
- {
- error (0, errno, "%s", dst_path);
- return_val = -1;
- }
- }
-
- ret:
- close (target_desc);
- ret2:
- close (source_desc);
-
- return return_val;
- }
-