/* * Format a number into a field, with some intelligence. */ static int format_number(int64_t v, char *p, int s, int maxsize, int strict) { int64_t limit; limit = ((int64_t)1 << (s*3)); /* "Strict" only permits octal values with proper termination. */ if (strict) return (format_octal(v, p, s)); /* * In non-strict mode, we allow the number to overwrite one or * more bytes of the field termination. Even old tar * implementations should be able to handle this with no * problem. */ if (v >= 0) { while (s <= maxsize) { if (v < limit) return (format_octal(v, p, s)); s++; limit <<= 3; } } /* Base-256 can handle any number, positive or negative. */ return (format_256(v, p, maxsize)); }
/* * Format a number into a field, falling back to base-256 if necessary. */ static int format_number(int64_t v, char *p, int s, int maxsize) { int64_t limit = ((int64_t)1 << (s*3)); if (v < limit) return (format_octal(v, p, s)); return (format_256(v, p, maxsize)); }
static int archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry) { struct cpio *cpio; const char *p, *path; int pathlength, ret; struct cpio_header h; cpio = (struct cpio *)a->format_data; ret = 0; path = archive_entry_pathname(entry); pathlength = strlen(path) + 1; /* Include trailing null. */ memset(&h, 0, sizeof(h)); format_octal(070707, &h.c_magic, sizeof(h.c_magic)); format_octal(archive_entry_dev(entry), &h.c_dev, sizeof(h.c_dev)); /* * TODO: Generate artificial inode numbers rather than just * re-using the ones off the disk. That way, the 18-bit c_ino * field only limits the number of files in the archive. */ if (archive_entry_ino(entry) > 0777777) { archive_set_error(&a->archive, ERANGE, "large inode number truncated"); ret = ARCHIVE_WARN; } format_octal(archive_entry_ino(entry) & 0777777, &h.c_ino, sizeof(h.c_ino)); format_octal(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode)); format_octal(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid)); format_octal(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid)); format_octal(archive_entry_nlink(entry), &h.c_nlink, sizeof(h.c_nlink)); if (archive_entry_filetype(entry) == AE_IFBLK || archive_entry_filetype(entry) == AE_IFCHR) format_octal(archive_entry_dev(entry), &h.c_rdev, sizeof(h.c_rdev)); else format_octal(0, &h.c_rdev, sizeof(h.c_rdev)); format_octal(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime)); format_octal(pathlength, &h.c_namesize, sizeof(h.c_namesize)); /* Non-regular files don't store bodies. */ if (archive_entry_filetype(entry) != AE_IFREG) archive_entry_set_size(entry, 0); /* Symlinks get the link written as the body of the entry. */ p = archive_entry_symlink(entry); if (p != NULL && *p != '\0') format_octal(strlen(p), &h.c_filesize, sizeof(h.c_filesize)); else format_octal(archive_entry_size(entry), &h.c_filesize, sizeof(h.c_filesize)); ret = (a->compressor.write)(a, &h, sizeof(h)); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); ret = (a->compressor.write)(a, path, pathlength); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); cpio->entry_bytes_remaining = archive_entry_size(entry); /* Write the symlink now. */ if (p != NULL && *p != '\0') ret = (a->compressor.write)(a, p, strlen(p)); return (ret); }
static int archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) { int ret, append_fn; char buff[60]; char *ss, *se; struct ar_w *ar; const char *pathname; const char *filename; int64_t size; append_fn = 0; ar = (struct ar_w *)a->format_data; ar->is_strtab = 0; filename = NULL; size = archive_entry_size(entry); /* * Reject files with empty name. */ pathname = archive_entry_pathname(entry); if (pathname == NULL || *pathname == '\0') { archive_set_error(&a->archive, EINVAL, "Invalid filename"); return (ARCHIVE_WARN); } /* * If we are now at the beginning of the archive, * we need first write the ar global header. */ if (!ar->wrote_global_header) { __archive_write_output(a, "!<arch>\n", 8); ar->wrote_global_header = 1; } memset(buff, ' ', 60); strncpy(&buff[AR_fmag_offset], "`\n", 2); if (strcmp(pathname, "/") == 0 ) { /* Entry is archive symbol table in GNU format */ buff[AR_name_offset] = '/'; goto stat; } if (strcmp(pathname, "__.SYMDEF") == 0) { /* Entry is archive symbol table in BSD format */ strncpy(buff + AR_name_offset, "__.SYMDEF", 9); goto stat; } if (strcmp(pathname, "//") == 0) { /* * Entry is archive filename table, inform that we should * collect strtab in next _data call. */ ar->is_strtab = 1; buff[AR_name_offset] = buff[AR_name_offset + 1] = '/'; /* * For archive string table, only ar_size field should * be set. */ goto size; } /* * Otherwise, entry is a normal archive member. * Strip leading paths from filenames, if any. */ if ((filename = ar_basename(pathname)) == NULL) { /* Reject filenames with trailing "/" */ archive_set_error(&a->archive, EINVAL, "Invalid filename"); return (ARCHIVE_WARN); } if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) { /* * SVR4/GNU variant use a "/" to mark then end of the filename, * make it possible to have embedded spaces in the filename. * So, the longest filename here (without extension) is * actually 15 bytes. */ if (strlen(filename) <= 15) { strncpy(&buff[AR_name_offset], filename, strlen(filename)); buff[AR_name_offset + strlen(filename)] = '/'; } else { /* * For filename longer than 15 bytes, GNU variant * makes use of a string table and instead stores the * offset of the real filename to in the ar_name field. * The string table should have been written before. */ if (ar->has_strtab <= 0) { archive_set_error(&a->archive, EINVAL, "Can't find string table"); return (ARCHIVE_WARN); } se = (char *)malloc(strlen(filename) + 3); if (se == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate filename buffer"); return (ARCHIVE_FATAL); } strncpy(se, filename, strlen(filename)); strcpy(se + strlen(filename), "/\n"); ss = strstr(ar->strtab, se); free(se); if (ss == NULL) { archive_set_error(&a->archive, EINVAL, "Invalid string table"); return (ARCHIVE_WARN); } /* * GNU variant puts "/" followed by digits into * ar_name field. These digits indicates the real * filename string's offset to the string table. */ buff[AR_name_offset] = '/'; if (format_decimal(ss - ar->strtab, buff + AR_name_offset + 1, AR_name_size - 1)) { archive_set_error(&a->archive, ERANGE, "string table offset too large"); return (ARCHIVE_WARN); } } } else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) { /* * BSD variant: for any file name which is more than * 16 chars or contains one or more embedded space(s), the * string "#1/" followed by the ASCII length of the name is * put into the ar_name field. The file size (stored in the * ar_size field) is incremented by the length of the name. * The name is then written immediately following the * archive header. */ if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) { strncpy(&buff[AR_name_offset], filename, strlen(filename)); buff[AR_name_offset + strlen(filename)] = ' '; } else { strncpy(buff + AR_name_offset, "#1/", 3); if (format_decimal(strlen(filename), buff + AR_name_offset + 3, AR_name_size - 3)) { archive_set_error(&a->archive, ERANGE, "File name too long"); return (ARCHIVE_WARN); } append_fn = 1; size += strlen(filename); } } stat: if (format_decimal(archive_entry_mtime(entry), buff + AR_date_offset, AR_date_size)) { archive_set_error(&a->archive, ERANGE, "File modification time too large"); return (ARCHIVE_WARN); } if (format_decimal(archive_entry_uid(entry), buff + AR_uid_offset, AR_uid_size)) { archive_set_error(&a->archive, ERANGE, "Numeric user ID too large"); return (ARCHIVE_WARN); } if (format_decimal(archive_entry_gid(entry), buff + AR_gid_offset, AR_gid_size)) { archive_set_error(&a->archive, ERANGE, "Numeric group ID too large"); return (ARCHIVE_WARN); } if (format_octal(archive_entry_mode(entry), buff + AR_mode_offset, AR_mode_size)) { archive_set_error(&a->archive, ERANGE, "Numeric mode too large"); return (ARCHIVE_WARN); } /* * Sanity Check: A non-pseudo archive member should always be * a regular file. */ if (filename != NULL && archive_entry_filetype(entry) != AE_IFREG) { archive_set_error(&a->archive, EINVAL, "Regular file required for non-pseudo member"); return (ARCHIVE_WARN); } size: if (format_decimal(size, buff + AR_size_offset, AR_size_size)) { archive_set_error(&a->archive, ERANGE, "File size out of range"); return (ARCHIVE_WARN); } ret = __archive_write_output(a, buff, 60); if (ret != ARCHIVE_OK) return (ret); ar->entry_bytes_remaining = size; ar->entry_padding = ar->entry_bytes_remaining % 2; if (append_fn > 0) { ret = __archive_write_output(a, filename, strlen(filename)); if (ret != ARCHIVE_OK) return (ret); ar->entry_bytes_remaining -= strlen(filename); } return (ARCHIVE_OK); }
/* * Format a basic 512-byte "ustar" header. * * Returns -1 if format failed (due to field overflow). * Note that this always formats as much of the header as possible. * If "strict" is set to zero, it will extend numeric fields as * necessary (overwriting terminators or using base-256 extensions). * * This is exported so that other 'tar' formats can use it. */ int __archive_write_format_header_ustar(struct archive_write *a, char h[512], struct archive_entry *entry, int tartype, int strict) { unsigned int checksum; int i, ret; size_t copy_length; const char *p, *pp; int mytartype; ret = 0; mytartype = -1; /* * The "template header" already includes the "ustar" * signature, various end-of-field markers and other required * elements. */ memcpy(h, &template_header, 512); /* * Because the block is already null-filled, and strings * are allowed to exactly fill their destination (without null), * I use memcpy(dest, src, strlen()) here a lot to copy strings. */ pp = tk_archive_entry_pathname(entry); if (strlen(pp) <= USTAR_name_size) memcpy(h + USTAR_name_offset, pp, strlen(pp)); else { /* Store in two pieces, splitting at a '/'. */ p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/'); /* * Look for the next '/' if we chose the first character * as the separator. (ustar format doesn't permit * an empty prefix.) */ if (p == pp) p = strchr(p + 1, '/'); /* Fail if the name won't fit. */ if (!p) { /* No separator. */ tk_archive_set_error(&a->archive, ENAMETOOLONG, "Pathname too long"); ret = ARCHIVE_FAILED; } else if (p[1] == '\0') { /* * The only feasible separator is a final '/'; * this would result in a non-empty prefix and * an empty name, which POSIX doesn't * explicity forbid, but it just feels wrong. */ tk_archive_set_error(&a->archive, ENAMETOOLONG, "Pathname too long"); ret = ARCHIVE_FAILED; } else if (p > pp + USTAR_prefix_size) { /* Prefix is too long. */ tk_archive_set_error(&a->archive, ENAMETOOLONG, "Pathname too long"); ret = ARCHIVE_FAILED; } else { /* Copy prefix and remainder to appropriate places */ memcpy(h + USTAR_prefix_offset, pp, p - pp); memcpy(h + USTAR_name_offset, p + 1, pp + strlen(pp) - p - 1); } } p = tk_archive_entry_hardlink(entry); if (p != NULL) mytartype = '1'; else p = tk_archive_entry_symlink(entry); if (p != NULL && p[0] != '\0') { copy_length = strlen(p); if (copy_length > USTAR_linkname_size) { tk_archive_set_error(&a->archive, ENAMETOOLONG, "Link contents too long"); ret = ARCHIVE_FAILED; copy_length = USTAR_linkname_size; } memcpy(h + USTAR_linkname_offset, p, copy_length); } p = tk_archive_entry_uname(entry); if (p != NULL && p[0] != '\0') { copy_length = strlen(p); if (copy_length > USTAR_uname_size) { tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Username too long"); ret = ARCHIVE_FAILED; copy_length = USTAR_uname_size; } memcpy(h + USTAR_uname_offset, p, copy_length); } p = tk_archive_entry_gname(entry); if (p != NULL && p[0] != '\0') { copy_length = strlen(p); if (strlen(p) > USTAR_gname_size) { tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Group name too long"); ret = ARCHIVE_FAILED; copy_length = USTAR_gname_size; } memcpy(h + USTAR_gname_offset, p, copy_length); } if (format_number(tk_archive_entry_mode(entry) & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) { tk_archive_set_error(&a->archive, ERANGE, "Numeric mode too large"); ret = ARCHIVE_FAILED; } if (format_number(tk_archive_entry_uid(entry), h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) { tk_archive_set_error(&a->archive, ERANGE, "Numeric user ID too large"); ret = ARCHIVE_FAILED; } if (format_number(tk_archive_entry_gid(entry), h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) { tk_archive_set_error(&a->archive, ERANGE, "Numeric group ID too large"); ret = ARCHIVE_FAILED; } if (format_number(tk_archive_entry_size(entry), h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) { tk_archive_set_error(&a->archive, ERANGE, "File size out of range"); ret = ARCHIVE_FAILED; } if (format_number(tk_archive_entry_mtime(entry), h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) { tk_archive_set_error(&a->archive, ERANGE, "File modification time too large"); ret = ARCHIVE_FAILED; } if (tk_archive_entry_filetype(entry) == AE_IFBLK || tk_archive_entry_filetype(entry) == AE_IFCHR) { if (format_number(tk_archive_entry_rdevmajor(entry), h + USTAR_rdevmajor_offset, USTAR_rdevmajor_size, USTAR_rdevmajor_max_size, strict)) { tk_archive_set_error(&a->archive, ERANGE, "Major device number too large"); ret = ARCHIVE_FAILED; } if (format_number(tk_archive_entry_rdevminor(entry), h + USTAR_rdevminor_offset, USTAR_rdevminor_size, USTAR_rdevminor_max_size, strict)) { tk_archive_set_error(&a->archive, ERANGE, "Minor device number too large"); ret = ARCHIVE_FAILED; } } if (tartype >= 0) { h[USTAR_typeflag_offset] = tartype; } else if (mytartype >= 0) { h[USTAR_typeflag_offset] = mytartype; } else { switch (tk_archive_entry_filetype(entry)) { case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break; case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break; case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break; case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break; case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break; case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break; case AE_IFSOCK: tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive socket"); return (ARCHIVE_FAILED); default: tk_archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive this (mode=0%lo)", (unsigned long)tk_archive_entry_mode(entry)); ret = ARCHIVE_FAILED; } } checksum = 0; for (i = 0; i < 512; i++) checksum += 255 & (unsigned int)h[i]; h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ /* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ format_octal(checksum, h + USTAR_checksum_offset, 6); return (ret); }
static int archive_format_gnutar_header(struct archive_write *a, char h[512], struct archive_entry *entry, int tartype) { unsigned int checksum; int i, ret; size_t copy_length; const char *p; struct gnutar *gnutar; gnutar = (struct gnutar *)a->format_data; ret = 0; /* * The "template header" already includes the signature, * various end-of-field markers, and other required elements. */ memcpy(h, &template_header, 512); /* * Because the block is already null-filled, and strings * are allowed to exactly fill their destination (without null), * I use memcpy(dest, src, strlen()) here a lot to copy strings. */ if (tartype == 'K' || tartype == 'L') { p = archive_entry_pathname(entry); copy_length = strlen(p); } else { p = gnutar->pathname; copy_length = gnutar->pathname_length; } if (copy_length > GNUTAR_name_size) copy_length = GNUTAR_name_size; memcpy(h + GNUTAR_name_offset, p, copy_length); if ((copy_length = gnutar->linkname_length) > 0) { if (copy_length > GNUTAR_linkname_size) copy_length = GNUTAR_linkname_size; memcpy(h + GNUTAR_linkname_offset, gnutar->linkname, copy_length); } /* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */ if (tartype == 'K' || tartype == 'L') { p = archive_entry_uname(entry); copy_length = strlen(p); } else { p = gnutar->uname; copy_length = gnutar->uname_length; } if (copy_length > 0) { if (copy_length > GNUTAR_uname_size) copy_length = GNUTAR_uname_size; memcpy(h + GNUTAR_uname_offset, p, copy_length); } /* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */ if (tartype == 'K' || tartype == 'L') { p = archive_entry_gname(entry); copy_length = strlen(p); } else { p = gnutar->gname; copy_length = gnutar->gname_length; } if (copy_length > 0) { if (strlen(p) > GNUTAR_gname_size) copy_length = GNUTAR_gname_size; memcpy(h + GNUTAR_gname_offset, p, copy_length); } /* By truncating the mode here, we ensure it always fits. */ format_octal(archive_entry_mode(entry) & 07777, h + GNUTAR_mode_offset, GNUTAR_mode_size); /* GNU tar supports base-256 here, so should never overflow. */ if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset, GNUTAR_uid_size, GNUTAR_uid_max_size)) { archive_set_error(&a->archive, ERANGE, "Numeric user ID %jd too large", (intmax_t)archive_entry_uid(entry)); ret = ARCHIVE_FAILED; } /* GNU tar supports base-256 here, so should never overflow. */ if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset, GNUTAR_gid_size, GNUTAR_gid_max_size)) { archive_set_error(&a->archive, ERANGE, "Numeric group ID %jd too large", (intmax_t)archive_entry_gid(entry)); ret = ARCHIVE_FAILED; } /* GNU tar supports base-256 here, so should never overflow. */ if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset, GNUTAR_size_size, GNUTAR_size_max_size)) { archive_set_error(&a->archive, ERANGE, "File size out of range"); ret = ARCHIVE_FAILED; } /* Shouldn't overflow before 2106, since mtime field is 33 bits. */ format_octal(archive_entry_mtime(entry), h + GNUTAR_mtime_offset, GNUTAR_mtime_size); if (archive_entry_filetype(entry) == AE_IFBLK || archive_entry_filetype(entry) == AE_IFCHR) { if (format_octal(archive_entry_rdevmajor(entry), h + GNUTAR_rdevmajor_offset, GNUTAR_rdevmajor_size)) { archive_set_error(&a->archive, ERANGE, "Major device number too large"); ret = ARCHIVE_FAILED; } if (format_octal(archive_entry_rdevminor(entry), h + GNUTAR_rdevminor_offset, GNUTAR_rdevminor_size)) { archive_set_error(&a->archive, ERANGE, "Minor device number too large"); ret = ARCHIVE_FAILED; } } h[GNUTAR_typeflag_offset] = tartype; checksum = 0; for (i = 0; i < 512; i++) checksum += 255 & (unsigned int)h[i]; h[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ /* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ format_octal(checksum, h + GNUTAR_checksum_offset, 6); return (ret); }
/* * Format a basic 512-byte "v7tar" header. * * Returns -1 if format failed (due to field overflow). * Note that this always formats as much of the header as possible. * If "strict" is set to zero, it will extend numeric fields as * necessary (overwriting terminators or using base-256 extensions). * */ static int format_header_v7tar(struct archive_write *a, char h[512], struct archive_entry *entry, int strict, struct archive_string_conv *sconv) { unsigned int checksum; int i, r, ret; size_t copy_length; const char *p, *pp; int mytartype; ret = 0; mytartype = -1; /* * The "template header" already includes the "v7tar" * signature, various end-of-field markers and other required * elements. */ memcpy(h, &template_header, 512); /* * Because the block is already null-filled, and strings * are allowed to exactly fill their destination (without null), * I use memcpy(dest, src, strlen()) here a lot to copy strings. */ r = archive_entry_pathname_l(entry, &pp, ©_length, sconv); if (r != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Pathname"); return (ARCHIVE_FATAL); } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate pathname '%s' to %s", pp, archive_string_conversion_charset_name(sconv)); ret = ARCHIVE_WARN; } if (strict && copy_length < V7TAR_name_size) memcpy(h + V7TAR_name_offset, pp, copy_length); else if (!strict && copy_length <= V7TAR_name_size) memcpy(h + V7TAR_name_offset, pp, copy_length); else { /* Prefix is too long. */ archive_set_error(&a->archive, ENAMETOOLONG, "Pathname too long"); ret = ARCHIVE_FAILED; } r = archive_entry_hardlink_l(entry, &p, ©_length, sconv); if (r != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Linkname"); return (ARCHIVE_FATAL); } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate linkname '%s' to %s", p, archive_string_conversion_charset_name(sconv)); ret = ARCHIVE_WARN; } if (copy_length > 0) mytartype = '1'; else { r = archive_entry_symlink_l(entry, &p, ©_length, sconv); if (r != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Linkname"); return (ARCHIVE_FATAL); } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate linkname '%s' to %s", p, archive_string_conversion_charset_name(sconv)); ret = ARCHIVE_WARN; } } if (copy_length > 0) { if (copy_length >= V7TAR_linkname_size) { archive_set_error(&a->archive, ENAMETOOLONG, "Link contents too long"); ret = ARCHIVE_FAILED; copy_length = V7TAR_linkname_size; } memcpy(h + V7TAR_linkname_offset, p, copy_length); } if (format_number(archive_entry_mode(entry) & 07777, h + V7TAR_mode_offset, V7TAR_mode_size, V7TAR_mode_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Numeric mode too large"); ret = ARCHIVE_FAILED; } if (format_number(archive_entry_uid(entry), h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Numeric user ID too large"); ret = ARCHIVE_FAILED; } if (format_number(archive_entry_gid(entry), h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Numeric group ID too large"); ret = ARCHIVE_FAILED; } if (format_number(archive_entry_size(entry), h + V7TAR_size_offset, V7TAR_size_size, V7TAR_size_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "File size out of range"); ret = ARCHIVE_FAILED; } if (format_number(archive_entry_mtime(entry), h + V7TAR_mtime_offset, V7TAR_mtime_size, V7TAR_mtime_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "File modification time too large"); ret = ARCHIVE_FAILED; } if (mytartype >= 0) { h[V7TAR_typeflag_offset] = mytartype; } else { switch (archive_entry_filetype(entry)) { case AE_IFREG: case AE_IFDIR: break; case AE_IFLNK: h[V7TAR_typeflag_offset] = '2'; break; case AE_IFCHR: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive character device"); return (ARCHIVE_FAILED); case AE_IFBLK: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive block device"); return (ARCHIVE_FAILED); case AE_IFIFO: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive fifo"); return (ARCHIVE_FAILED); case AE_IFSOCK: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive socket"); return (ARCHIVE_FAILED); default: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive this (mode=0%lo)", (unsigned long)archive_entry_mode(entry)); ret = ARCHIVE_FAILED; } } checksum = 0; for (i = 0; i < 512; i++) checksum += 255 & (unsigned int)h[i]; format_octal(checksum, h + V7TAR_checksum_offset, 6); /* Can't be pre-set in the template. */ h[V7TAR_checksum_offset + 6] = '\0'; return (ret); }