+ /* Generate the POSIX octal representation if the number fits. */
+ if (! negative && value <= MAX_VAL_WITH_DIGITS (size - 1, LG_8))
+ {
+ where[size - 1] = '\0';
+ to_octal (value, where, size - 1);
+ return true;
+ }
+ else if (gnu_format)
+ {
+ /* Try to cope with the number by using traditional GNU format
+ methods */
+
+ /* Generate the base-256 representation if the number fits. */
+ if (((negative ? -1 - value : value)
+ <= MAX_VAL_WITH_DIGITS (size - 1, LG_256)))
+ {
+ where[0] = negative ? -1 : 1 << (LG_256 - 1);
+ to_base256 (negative, value, where + 1, size - 1);
+ return true;
+ }
+
+ /* Otherwise, if the number is negative, and if it would not cause
+ ambiguity on this host by confusing positive with negative
+ values, then generate the POSIX octal representation of the value
+ modulo 2**(field bits). The resulting tar file is
+ machine-dependent, since it depends on the host word size. Yuck!
+ But this is the traditional behavior. */
+ else if (negative && valsize * CHAR_BIT <= (size - 1) * LG_8)
+ {
+ static int warned_once;
+ if (! warned_once)
+ {
+ warned_once = 1;
+ WARN ((0, 0, _("Generating negative octal headers")));
+ }
+ where[size - 1] = '\0';
+ to_octal (value & MAX_VAL_WITH_DIGITS (valsize * CHAR_BIT, 1),
+ where, size - 1);
+ return true;
+ }
+ /* Otherwise fall back to substitution, if possible: */
+ }
+ else
+ substitute = NULL; /* No substitution for formats, other than GNU */
+
+ return to_chars_subst (negative, gnu_format, value, valsize, substitute,
+ where, size, type);
+}
+
+static uintmax_t
+gid_substitute (int *negative)
+{
+ gid_t r;
+#ifdef GID_NOBODY
+ r = GID_NOBODY;
+#else
+ static gid_t gid_nobody;
+ if (!gid_nobody && !gname_to_gid ("nobody", &gid_nobody))
+ gid_nobody = -2;
+ r = gid_nobody;
+#endif
+ *negative = r < 0;
+ return r;
+}
+
+bool
+gid_to_chars (gid_t v, char *p, size_t s)
+{
+ return to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
+}
+
+bool
+major_to_chars (major_t v, char *p, size_t s)
+{
+ return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t");
+}
+
+bool
+minor_to_chars (minor_t v, char *p, size_t s)
+{
+ return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t");
+}
+
+bool
+mode_to_chars (mode_t v, char *p, size_t s)
+{
+ /* In the common case where the internal and external mode bits are the same,
+ and we are not using POSIX or GNU format,
+ propagate all unknown bits to the external mode.
+ This matches historical practice.
+ Otherwise, just copy the bits we know about. */
+ int negative;
+ uintmax_t u;
+ if (S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
+ && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC
+ && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC
+ && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
+ && archive_format != POSIX_FORMAT
+ && archive_format != USTAR_FORMAT
+ && archive_format != GNU_FORMAT
+ && archive_format != OLDGNU_FORMAT)
+ {
+ negative = v < 0;
+ u = v;
+ }
+ else
+ {
+ negative = 0;
+ u = ((v & S_ISUID ? TSUID : 0)
+ | (v & S_ISGID ? TSGID : 0)
+ | (v & S_ISVTX ? TSVTX : 0)
+ | (v & S_IRUSR ? TUREAD : 0)
+ | (v & S_IWUSR ? TUWRITE : 0)
+ | (v & S_IXUSR ? TUEXEC : 0)
+ | (v & S_IRGRP ? TGREAD : 0)
+ | (v & S_IWGRP ? TGWRITE : 0)
+ | (v & S_IXGRP ? TGEXEC : 0)
+ | (v & S_IROTH ? TOREAD : 0)
+ | (v & S_IWOTH ? TOWRITE : 0)
+ | (v & S_IXOTH ? TOEXEC : 0));
+ }
+ return to_chars (negative, u, sizeof v, 0, p, s, "mode_t");
+}
+
+bool
+off_to_chars (off_t v, char *p, size_t s)
+{
+ return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "off_t");
+}
+
+bool
+size_to_chars (size_t v, char *p, size_t s)
+{
+ return to_chars (0, (uintmax_t) v, sizeof v, 0, p, s, "size_t");
+}
+
+bool
+time_to_chars (time_t v, char *p, size_t s)
+{
+ return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "time_t");
+}
+
+static uintmax_t
+uid_substitute (int *negative)
+{
+ uid_t r;
+#ifdef UID_NOBODY
+ r = UID_NOBODY;
+#else
+ static uid_t uid_nobody;
+ if (!uid_nobody && !uname_to_uid ("nobody", &uid_nobody))
+ uid_nobody = -2;
+ r = uid_nobody;
+#endif
+ *negative = r < 0;
+ return r;
+}
+
+bool
+uid_to_chars (uid_t v, char *p, size_t s)
+{
+ return to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
+}
+
+bool
+uintmax_to_chars (uintmax_t v, char *p, size_t s)
+{
+ return to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
+}
+
+void
+string_to_chars (char const *str, char *p, size_t s)
+{
+ tar_copy_str (p, str, s);
+ p[s - 1] = '\0';
+}
+
+\f
+/* A file is considered dumpable if it is sparse and both --sparse and --totals
+ are specified.
+ Otherwise, it is dumpable unless any of the following conditions occur:
+
+ a) it is empty *and* world-readable, or
+ b) current archive is /dev/null */
+
+bool
+file_dumpable_p (struct tar_stat_info *st)
+{
+ if (dev_null_output)
+ return totals_option && sparse_option && ST_IS_SPARSE (st->stat);
+ return !(st->archive_file_size == 0
+ && (st->stat.st_mode & MODE_R) == MODE_R);
+}
+
+\f
+/* Writing routines. */
+
+/* Write the EOT block(s). Zero at least two blocks, through the end
+ of the record. Old tar, as previous versions of GNU tar, writes
+ garbage after two zeroed blocks. */