+ *negative = r < 0;
+ return r;
+}
+
+void
+uid_to_chars (uid_t v, char *p, size_t s)
+{
+ to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
+}
+
+void
+uintmax_to_chars (uintmax_t v, char *p, size_t s)
+{
+ to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
+}
+
+void
+string_to_chars (char *str, char *p, size_t s)
+{
+ strncpy (p, str, s);
+ p[s-1] = 0;
+}
+
+\f
+/* Writing routines. */
+
+/* Zero out the buffer so we don't confuse ourselves with leftover
+ data. */
+static void
+clear_buffer (char *buffer)
+{
+ memset (buffer, 0, BLOCKSIZE);
+}
+
+/* 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. */
+void
+write_eot (void)
+{
+ union block *pointer = find_next_block ();
+ memset (pointer->buffer, 0, BLOCKSIZE);
+ set_next_block_after (pointer);
+ pointer = find_next_block ();
+ memset (pointer->buffer, 0, available_space_after (pointer));
+ set_next_block_after (pointer);
+}
+
+/* Copy at most LEN bytes from SRC to DST. Terminate with NUL unless
+ SRC is LEN characters long */
+static void
+tar_copy_str (char *dst, const char *src, size_t len)
+{
+ dst[len-1] = 0;
+ strncpy (dst, src, len);
+}
+
+/* Write a "private" header */
+static union block *
+start_private_header (const char *name, size_t size)
+{
+ time_t t;
+ union block *header = find_next_block ();
+
+ memset (header->buffer, 0, sizeof (union block));
+
+ tar_copy_str (header->header.name, name, NAME_FIELD_SIZE);
+ OFF_TO_CHARS (size, header->header.size);
+
+ time (&t);
+ TIME_TO_CHARS (t, header->header.mtime);
+ MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode);
+ UID_TO_CHARS (getuid (), header->header.uid);
+ GID_TO_CHARS (getgid (), header->header.gid);
+ MAJOR_TO_CHARS (0, header->header.devmajor);
+ MAJOR_TO_CHARS (0, header->header.devminor);
+ strncpy (header->header.magic, TMAGIC, TMAGLEN);
+ strncpy (header->header.version, TVERSION, TVERSLEN);
+ return header;
+}
+
+/* Create a new header and store there at most NAME_FIELD_SIZE bytes of
+ the file name */
+
+static union block *
+write_short_name (struct tar_stat_info *st)
+{
+ union block *header = find_next_block ();
+ memset (header->buffer, 0, sizeof (union block));
+ tar_copy_str (header->header.name, st->file_name, NAME_FIELD_SIZE);
+ return header;
+}
+
+/* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */
+static void
+write_gnu_long_link (const char *p, char type)
+{
+ size_t size = strlen (p) + 1;
+ size_t bufsize;
+ union block *header;
+
+ header = start_private_header ("././@LongLink", size);
+ header->header.typeflag = type;
+ finish_header (header, -1);
+
+ header = find_next_block ();
+
+ bufsize = available_space_after (header);
+
+ while (bufsize < size)