summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c202
1 files changed, 111 insertions, 91 deletions
diff --git a/src/util.c b/src/util.c
index b60ef3a..1cc1a68 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,4 +1,4 @@
-/* utility functions for `patch' */
+/* utility functions for 'patch' */
/* Copyright (C) 1986 Larry Wall
@@ -57,6 +57,8 @@ typedef struct
{
dev_t dev;
ino_t ino;
+ enum file_id_type type;
+ bool queued_output;
} file_id;
/* Return an index for ENTRY into a hash table of size TABLE_SIZE. */
@@ -92,10 +94,8 @@ init_backup_hash_table (void)
xalloc_die ();
}
-/* Insert a file with status ST into the hash table. */
-
-static void
-insert_file (struct stat const *st)
+static file_id *
+__insert_file_id (struct stat const *st, enum file_id_type type)
{
file_id *p;
static file_id *next_slot;
@@ -104,23 +104,62 @@ insert_file (struct stat const *st)
next_slot = xmalloc (sizeof *next_slot);
next_slot->dev = st->st_dev;
next_slot->ino = st->st_ino;
+ next_slot->queued_output = false;
p = hash_insert (file_id_table, next_slot);
if (!p)
xalloc_die ();
if (p == next_slot)
next_slot = NULL;
+ p->type = type;
+ return p;
}
-/* Has the file identified by ST already been inserted into the hash
- table? */
-
-bool
-file_already_seen (struct stat const *st)
+static file_id *
+__lookup_file_id (struct stat const *st)
{
file_id f;
+
f.dev = st->st_dev;
f.ino = st->st_ino;
- return hash_lookup (file_id_table, &f) != 0;
+ return hash_lookup (file_id_table, &f);
+}
+
+/* Insert a file with status ST and type TYPE into the hash table.
+ The type of an existing entry can be changed by re-inserting it. */
+
+void
+insert_file_id (struct stat const *st, enum file_id_type type)
+{
+ __insert_file_id (st, type);
+}
+
+/* Has the file identified by ST already been inserted into the hash
+ table, and what type does it have? */
+
+enum file_id_type
+lookup_file_id (struct stat const *st)
+{
+ file_id *p = __lookup_file_id (st);
+
+ return p ? p->type : UNKNOWN;
+}
+
+void
+set_queued_output (struct stat const *st, bool queued_output)
+{
+ file_id *p = __lookup_file_id (st);
+
+ if (! p)
+ p = __insert_file_id (st, UNKNOWN);
+ p->queued_output = queued_output;
+}
+
+bool
+has_queued_output (struct stat const *st)
+{
+ file_id *p = __lookup_file_id (st);
+
+ return p && p->queued_output;
}
static bool _GL_ATTRIBUTE_PURE
@@ -140,10 +179,13 @@ copy_attr_error (struct error_context *ctx, char const *fmt, ...)
int err = errno;
va_list ap;
- /* use verror module to print error message */
- va_start (ap, fmt);
- verror (0, err, fmt, ap);
- va_end (ap);
+ if (err != ENOSYS && err != ENOTSUP && err != EPERM)
+ {
+ /* use verror module to print error message */
+ va_start (ap, fmt);
+ verror (0, err, fmt, ap);
+ va_end (ap);
+ }
}
static char const *
@@ -188,7 +230,7 @@ copy_attr (char const *src_path, char const *dst_path)
void
set_file_attributes (char const *to, enum file_attributes attr,
- char const *from, struct stat *st, mode_t mode,
+ char const *from, const struct stat *st, mode_t mode,
struct timespec *new_time)
{
if (attr & FA_TIMES)
@@ -235,9 +277,9 @@ set_file_attributes (char const *to, enum file_attributes attr,
quotearg (to));
}
if (attr & FA_XATTRS)
- if (copy_attr (from, to))
+ if (copy_attr (from, to) != 0
+ && errno != ENOSYS && errno != ENOTSUP && errno != EPERM)
fatal_exit (0);
- /* FIXME: There may be other attributes to preserve. */
if (attr & FA_MODE)
{
#if 0 && defined HAVE_LCHMOD
@@ -255,24 +297,16 @@ set_file_attributes (char const *to, enum file_attributes attr,
}
static void
-create_backup_copy (char const *from, char const *to, struct stat *st,
- bool to_dir_known_to_exist, bool remember_backup)
+create_backup_copy (char const *from, char const *to, const struct stat *st,
+ bool to_dir_known_to_exist)
{
- struct stat backup_st;
- copy_file (from, to, remember_backup ? &backup_st : NULL, 0, st->st_mode,
- to_dir_known_to_exist);
- if (remember_backup)
- insert_file (&backup_st);
+ copy_file (from, to, NULL, 0, st->st_mode, to_dir_known_to_exist);
set_file_attributes (to, FA_TIMES | FA_IDS | FA_MODE, from, st, st->st_mode, NULL);
}
void
-create_backup (char const *to, struct stat *to_st, int *to_errno,
- bool leave_original, bool remember_backup)
+create_backup (char const *to, const struct stat *to_st, bool leave_original)
{
- struct stat tmp_st;
- int tmp_errno;
-
/* When the input to patch modifies the same file more than once, patch only
backs up the initial version of each file.
@@ -281,26 +315,16 @@ create_backup (char const *to, struct stat *to_st, int *to_errno,
up; files already known have already been backed up before, and are
skipped.
- When a patch deletes a file, this leaves patch without such a "sentinel"
- file. In that case, patch remembers the *backup file* instead; when a
- patch creates a file, patch checks if the *backup file* is already known.
-
- This strategy is not fully compatible with numbered backups: when a patch
- deletes and later recreates a file with numbered backups, two numbered
- backups will be created. */
+ When a patch tries to delete a file, in order to not break the above
+ logic, we merely remember which file to delete. After the entire patch
+ file has been read, we delete all files marked for deletion which have not
+ been recreated in the meantime. */
- if (! to_st || ! to_errno)
- {
- to_st = &tmp_st;
- to_errno = &tmp_errno;
- }
- *to_errno = lstat (to, to_st) == 0 ? 0 : errno;
-
- if (! to_errno && ! (S_ISREG (to_st->st_mode) || S_ISLNK (to_st->st_mode)))
+ if (to_st && ! (S_ISREG (to_st->st_mode) || S_ISLNK (to_st->st_mode)))
fatal ("File %s is not a %s -- refusing to create backup",
to, S_ISLNK (to_st->st_mode) ? "symbolic link" : "regular file");
- if (! *to_errno && file_already_seen (to_st))
+ if (to_st && lookup_file_id (to_st) == CREATED)
{
if (debug & 4)
say ("File %s already seen\n", quotearg (to));
@@ -349,40 +373,27 @@ create_backup (char const *to, struct stat *to_st, int *to_errno,
xalloc_die ();
}
- if (*to_errno)
+ if (! to_st)
{
- struct stat backup_st;
int fd;
- if (lstat (bakname, &backup_st) == 0
- && file_already_seen (&backup_st))
- {
- if (debug & 4)
- say ("File %s already seen\n", quotearg (to));
- }
- else
- {
- if (debug & 4)
- say ("Creating empty file %s\n", quotearg (bakname));
+ if (debug & 4)
+ say ("Creating empty file %s\n", quotearg (bakname));
- try_makedirs_errno = ENOENT;
- unlink (bakname);
- while ((fd = creat (bakname, 0666)) < 0)
- {
- if (errno != try_makedirs_errno)
- pfatal ("Can't create file %s", quotearg (bakname));
- makedirs (bakname);
- try_makedirs_errno = 0;
- }
- if (remember_backup && fstat (fd, &backup_st) == 0)
- insert_file (&backup_st);
- if (close (fd) != 0)
- pfatal ("Can't close file %s", quotearg (bakname));
+ try_makedirs_errno = ENOENT;
+ unlink (bakname);
+ while ((fd = creat (bakname, 0666)) < 0)
+ {
+ if (errno != try_makedirs_errno)
+ pfatal ("Can't create file %s", quotearg (bakname));
+ makedirs (bakname);
+ try_makedirs_errno = 0;
}
+ if (close (fd) != 0)
+ pfatal ("Can't close file %s", quotearg (bakname));
}
else if (leave_original)
- create_backup_copy (to, bakname, to_st, try_makedirs_errno == 0,
- remember_backup);
+ create_backup_copy (to, bakname, to_st, try_makedirs_errno == 0);
else
{
if (debug & 4)
@@ -398,8 +409,7 @@ create_backup (char const *to, struct stat *to_st, int *to_errno,
else if (errno == EXDEV)
{
create_backup_copy (to, bakname, to_st,
- try_makedirs_errno == 0,
- remember_backup);
+ try_makedirs_errno == 0);
unlink (to);
break;
}
@@ -407,8 +417,6 @@ create_backup (char const *to, struct stat *to_st, int *to_errno,
pfatal ("Can't rename file %s to %s",
quotearg_n (0, to), quotearg_n (1, bakname));
}
- if (remember_backup)
- insert_file (to_st);
}
free (bakname);
}
@@ -425,15 +433,18 @@ create_backup (char const *to, struct stat *to_st, int *to_errno,
Back up TO if BACKUP is true. */
void
-move_file (char const *from, int *from_needs_removal,
+move_file (char const *from, bool *from_needs_removal,
struct stat const *fromst,
char const *to, mode_t mode, bool backup)
{
struct stat to_st;
- int to_errno = -1;
+ int to_errno;
+ to_errno = stat_file (to, &to_st);
if (backup)
- create_backup (to, &to_st, &to_errno, false, from == NULL);
+ create_backup (to, to_errno ? NULL : &to_st, false);
+ if (! to_errno)
+ insert_file_id (&to_st, OVERWRITTEN);
if (from)
{
@@ -469,7 +480,7 @@ move_file (char const *from, int *from_needs_removal,
free (buffer);
if (lstat (to, &to_st) != 0)
pfatal ("Can't get file attributes of %s %s", "symbolic link", to);
- insert_file (&to_st);
+ insert_file_id (&to_st, CREATED);
}
else
{
@@ -501,7 +512,7 @@ move_file (char const *from, int *from_needs_removal,
pfatal ("Can't remove file %s", quotearg (to));
}
copy_file (from, to, &tost, 0, mode, to_dir_known_to_exist);
- insert_file (&tost);
+ insert_file_id (&tost, CREATED);
return;
}
@@ -510,13 +521,14 @@ move_file (char const *from, int *from_needs_removal,
}
rename_succeeded:
- insert_file (fromst);
+ insert_file_id (fromst, CREATED);
/* Do not clear *FROM_NEEDS_REMOVAL if it's possible that the
rename returned zero because FROM and TO are hard links to
the same file. */
- if (0 < to_errno
- || (to_errno == 0 && to_st.st_nlink <= 1))
- *from_needs_removal = 0;
+ if ((0 < to_errno
+ || (to_errno == 0 && to_st.st_nlink <= 1))
+ && from_needs_removal)
+ *from_needs_removal = false;
}
}
else if (! backup)
@@ -811,7 +823,7 @@ version_get (char const *filename, char const *cs, bool exists, bool readonly,
if (dry_run)
{
if (! exists)
- fatal ("can't do dry run on nonexistent version-controlled file %s; invoke `%s' and try again",
+ fatal ("can't do dry run on nonexistent version-controlled file %s; invoke '%s' and try again",
quotearg (filename), getbuf);
}
else
@@ -977,7 +989,7 @@ ask (char const *format, ...)
/* If standard output is not a tty, don't bother opening /dev/tty,
since it's unlikely that stdout will be seen by the tty user.
The isatty test also works around a bug in GNU Emacs 19.34 under Linux
- which makes a call-process `patch' hang when it reads from /dev/tty.
+ which makes a call-process 'patch' hang when it reads from /dev/tty.
POSIX.1-2001 XCU line 26599 requires that we read /dev/tty,
though. */
ttyfd = (posixly_correct || isatty (STDOUT_FILENO)
@@ -1251,7 +1263,7 @@ replace_slashes (char *filename)
}
/* Make sure we'll have the directories to create a file.
- Ignore the last element of `filename'. */
+ Ignore the last element of 'filename'. */
static void
makedirs (char const *name)
@@ -1422,7 +1434,7 @@ strip_leading_slashes (char *name, int strip_leading)
/* Make filenames more reasonable. */
void
-fetchname (char const *at, int strip_leading, bool maybe_quoted, char **pname,
+fetchname (char const *at, int strip_leading, char **pname,
char **ptimestr, struct timespec *pstamp)
{
char *name;
@@ -1438,7 +1450,7 @@ fetchname (char const *at, int strip_leading, bool maybe_quoted, char **pname,
if (debug & 128)
say ("fetchname %s %d\n", at, strip_leading);
- if (maybe_quoted && *at == '"')
+ if (*at == '"')
{
name = parse_c_string (at, &t);
if (! name)
@@ -1640,3 +1652,11 @@ make_tempfile (char const **name, char letter, char const *real_name,
return fd;
}
}
+
+int stat_file (char const *filename, struct stat *st)
+{
+ int (*xstat)(char const *, struct stat *) =
+ follow_symlinks ? stat : lstat;
+
+ return xstat (filename, st) == 0 ? 0 : errno;
+}