/* Miscellaneous functions, not really specific to GNU tar.
Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
- 2003 Free Software Foundation, Inc.
+ 2003, 2004 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
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#include "system.h"
-#include "rmt.h"
+#include <system.h>
+#include <rmt.h>
#include "common.h"
#include <quotearg.h>
#include <save-cwd.h>
source++;
break;
- case 'n':
- *destination++ = '\n';
+ case 'a':
+ *destination++ = '\a';
source++;
break;
-
- case 't':
- *destination++ = '\t';
+
+ case 'b':
+ *destination++ = '\b';
source++;
break;
source++;
break;
- case 'b':
- *destination++ = '\b';
+ case 'n':
+ *destination++ = '\n';
source++;
break;
source++;
break;
+ case 't':
+ *destination++ = '\t';
+ source++;
+ break;
+
+ case 'v':
+ *destination++ = '\v';
+ source++;
+ break;
+
case '?':
*destination++ = 0177;
source++;
static char *before_backup_name;
static char *after_backup_name;
-/* Return 1 if PATH is obviously "." or "/". */
+/* Return 1 if FILE_NAME is obviously "." or "/". */
static bool
-must_be_dot_or_slash (char const *path)
+must_be_dot_or_slash (char const *file_name)
{
- path += FILESYSTEM_PREFIX_LEN (path);
+ file_name += FILE_SYSTEM_PREFIX_LEN (file_name);
- if (ISSLASH (path[0]))
+ if (ISSLASH (file_name[0]))
{
for (;;)
- if (ISSLASH (path[1]))
- path++;
- else if (path[1] == '.' && ISSLASH (path[2 + (path[2] == '.')]))
- path += 2 + (path[2] == '.');
+ if (ISSLASH (file_name[1]))
+ file_name++;
+ else if (file_name[1] == '.'
+ && ISSLASH (file_name[2 + (file_name[2] == '.')]))
+ file_name += 2 + (file_name[2] == '.');
else
- return ! path[1];
+ return ! file_name[1];
}
else
{
- while (path[0] == '.' && ISSLASH (path[1]))
+ while (file_name[0] == '.' && ISSLASH (file_name[1]))
{
- path += 2;
- while (ISSLASH (*path))
- path++;
+ file_name += 2;
+ while (ISSLASH (*file_name))
+ file_name++;
}
- return ! path[0] || (path[0] == '.' && ! path[1]);
+ return ! file_name[0] || (file_name[0] == '.' && ! file_name[1]);
}
}
Report an error with errno set to zero for obvious cases of this;
otherwise call rmdir. */
static int
-safer_rmdir (const char *path)
+safer_rmdir (const char *file_name)
{
- if (must_be_dot_or_slash (path))
+ if (must_be_dot_or_slash (file_name))
{
errno = 0;
return -1;
}
- return rmdir (path);
+ return rmdir (file_name);
}
-/* Remove PATH, returning 1 on success. If PATH is a directory, then
- if OPTION is RECURSIVE_REMOVE_OPTION is set remove PATH
- recursively; otherwise, remove it only if it is empty. If PATH is
+/* Remove FILE_NAME, returning 1 on success. If FILE_NAME is a directory,
+ then if OPTION is RECURSIVE_REMOVE_OPTION is set remove FILE_NAME
+ recursively; otherwise, remove it only if it is empty. If FILE_NAME is
a directory that cannot be removed (e.g., because it is nonempty)
and if OPTION is WANT_DIRECTORY_REMOVE_OPTION, then return -1.
- Return 0 on error, with errno set; if PATH is obviously the working
+ Return 0 on error, with errno set; if FILE_NAME is obviously the working
directory return zero with errno set to zero. */
int
-remove_any_file (const char *path, enum remove_option option)
+remove_any_file (const char *file_name, enum remove_option option)
{
/* Try unlink first if we are not root, as this saves us a system
call in the common case where we're removing a non-directory. */
if (! we_are_root)
{
- if (unlink (path) == 0)
+ if (unlink (file_name) == 0)
return 1;
/* POSIX 1003.1-2001 requires EPERM when attempting to unlink a
return 0;
}
- if (safer_rmdir (path) == 0)
+ if (safer_rmdir (file_name) == 0)
return 1;
switch (errno)
{
case ENOTDIR:
- return we_are_root && unlink (path) == 0;
+ return we_are_root && unlink (file_name) == 0;
case 0:
case EEXIST:
case RECURSIVE_REMOVE_OPTION:
{
- char *directory = savedir (path);
+ char *directory = savedir (file_name);
char const *entry;
size_t entrylen;
(entrylen = strlen (entry)) != 0;
entry += entrylen + 1)
{
- char *path_buffer = new_name (path, entry);
- int r = remove_any_file (path_buffer, 1);
+ char *file_name_buffer = new_name (file_name, entry);
+ int r = remove_any_file (file_name_buffer,
+ RECURSIVE_REMOVE_OPTION);
int e = errno;
- free (path_buffer);
+ free (file_name_buffer);
if (! r)
{
}
free (directory);
- return safer_rmdir (path) == 0;
+ return safer_rmdir (file_name) == 0;
}
}
break;
return 0;
}
-/* Check if PATH already exists and make a backup of it right now.
- Return success (nonzero) only if the backup in either unneeded, or
+/* Check if FILE_NAME already exists and make a backup of it right now.
+ Return success (nonzero) only if the backup is either unneeded, or
successful. For now, directories are considered to never need
- backup. If ARCHIVE is nonzero, this is the archive and so, we do
- not have to backup block or character devices, nor remote entities. */
-int
-maybe_backup_file (const char *path, int archive)
+ backup. If THIS_IS_THE_ARCHIVE is nonzero, this is the archive and
+ so, we do not have to backup block or character devices, nor remote
+ entities. */
+bool
+maybe_backup_file (const char *file_name, int this_is_the_archive)
{
struct stat file_stat;
/* Check if we really need to backup the file. */
- if (archive && _remdev (path))
- return 1;
+ if (this_is_the_archive && _remdev (file_name))
+ return true;
- if (stat (path, &file_stat))
+ if (stat (file_name, &file_stat))
{
if (errno == ENOENT)
- return 1;
+ return true;
- stat_error (path);
- return 0;
+ stat_error (file_name);
+ return false;
}
if (S_ISDIR (file_stat.st_mode))
- return 1;
+ return true;
- if (archive && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
- return 1;
+ if (this_is_the_archive
+ && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
+ return true;
- assign_string (&before_backup_name, path);
+ assign_string (&before_backup_name, file_name);
/* A run situation may exist between Emacs or other GNU programs trying to
make a backup for the same file simultaneously. If theoretically
convention, GNU-wide, for all programs doing backups. */
assign_string (&after_backup_name, 0);
- after_backup_name = find_backup_file_name (path, backup_type);
+ after_backup_name = find_backup_file_name (file_name, backup_type);
if (! after_backup_name)
xalloc_die ();
fprintf (stdlis, _("Renaming %s to %s\n"),
quote_n (0, before_backup_name),
quote_n (1, after_backup_name));
- return 1;
+ return true;
}
else
{
quotearg_colon (before_backup_name),
quote_n (1, after_backup_name)));
assign_string (&after_backup_name, 0);
- return 0;
+ return false;
}
}
}
void
-close_fatal (char const *name)
+close_warn (char const *name)
{
- call_arg_fatal ("close", name);
+ call_arg_warn ("close", name);
}
void
-close_warn (char const *name)
+close_diag (char const *name)
{
- call_arg_warn ("close", name);
+ if (ignore_failed_read_option)
+ close_warn (name);
+ else
+ close_error (name);
}
void
call_arg_warn ("open", name);
}
+void
+open_diag (char const *name)
+{
+ if (ignore_failed_read_option)
+ open_warn (name);
+ else
+ open_error (name);
+}
+
void
read_error (char const *name)
{
(unsigned long) size));
}
+void
+read_diag_details (char const *name, off_t offset, size_t size)
+{
+ if (ignore_failed_read_option)
+ read_warn_details (name, offset, size);
+ else
+ read_error_details (name, offset, size);
+}
+
void
read_fatal (char const *name)
{
call_arg_warn ("readlink", name);
}
+void
+readlink_diag (char const *name)
+{
+ if (ignore_failed_read_option)
+ readlink_warn (name);
+ else
+ readlink_error (name);
+}
+
void
savedir_error (char const *name)
{
call_arg_warn ("savedir", name);
}
+void
+savedir_diag (char const *name)
+{
+ if (ignore_failed_read_option)
+ savedir_warn (name);
+ else
+ savedir_error (name);
+}
+
void
seek_error (char const *name)
{
STRINGIFY_BIGINT (offset, buf)));
}
+void
+seek_diag_details (char const *name, off_t offset)
+{
+ if (ignore_failed_read_option)
+ seek_warn_details (name, offset);
+ else
+ seek_error_details (name, offset);
+}
+
void
symlink_error (char const *contents, char const *name)
{
call_arg_warn ("stat", name);
}
+void
+stat_diag (char const *name)
+{
+ if (ignore_failed_read_option)
+ stat_warn (name);
+ else
+ stat_error (name);
+}
+
void
truncate_error (char const *name)
{
}
void
-write_error_details (char const *name, ssize_t status, size_t size)
+write_error_details (char const *name, size_t status, size_t size)
{
- if (status < 0)
+ if (status == 0)
write_error (name);
else
ERROR ((0, 0,
ngettext ("%s: Wrote only %lu of %lu byte",
"%s: Wrote only %lu of %lu bytes",
- record_size),
- name, (unsigned long) status, (unsigned long) record_size));
+ size),
+ name, (unsigned long int) status, (unsigned long int) size));
}
void
call_arg_fatal ("pipe", _("interprocess channel"));
}
-/* Return an unambiguous printable representation, allocated in slot N,
- for NAME, suitable for diagnostics. */
-char const *
-quote_n (int n, char const *name)
+/* Return PTR, aligned upward to the next multiple of ALIGNMENT.
+ ALIGNMENT must be nonzero. The caller must arrange for ((char *)
+ PTR) through ((char *) PTR + ALIGNMENT - 1) to be addressable
+ locations. */
+
+static inline void *
+ptr_align (void *ptr, size_t alignment)
{
- return quotearg_n_style (n, locale_quoting_style, name);
+ char *p0 = ptr;
+ char *p1 = p0 + alignment - 1;
+ return p1 - (size_t) p1 % alignment;
}
-/* Return an unambiguous printable representation of NAME, suitable
- for diagnostics. */
-char const *
-quote (char const *name)
+/* Return the address of a page-aligned buffer of at least SIZE bytes.
+ The caller should free *PTR when done with the buffer. */
+
+void *
+page_aligned_alloc (void **ptr, size_t size)
{
- return quote_n (0, name);
+ size_t alignment = getpagesize ();
+ size_t size1 = size + alignment;
+ if (size1 < size)
+ xalloc_die ();
+ *ptr = xmalloc (size1);
+ return ptr_align (*ptr, alignment);
}