static void test_linkify_old_cpio(void) { struct archive_entry *entry, *e2; struct archive_entry_linkresolver *resolver; /* Initialize the resolver. */ assert(NULL != (resolver = archive_entry_linkresolver_new())); archive_entry_linkresolver_set_strategy(resolver, ARCHIVE_FORMAT_CPIO_POSIX); /* Create an entry with 2 link and try to linkify it. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test1"); archive_entry_set_ino(entry, 1); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 2); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't have been changed. */ assert(e2 == NULL); assertEqualInt(10, archive_entry_size(entry)); assertEqualString("test1", archive_entry_pathname(entry)); /* Still shouldn't be matched. */ archive_entry_linkify(resolver, &entry, &e2); assert(e2 == NULL); assertEqualString("test1", archive_entry_pathname(entry)); assertEqualString(NULL, archive_entry_hardlink(entry)); assertEqualInt(10, archive_entry_size(entry)); archive_entry_free(entry); archive_entry_linkresolver_free(resolver); }
static int header_bin_be(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const struct cpio_bin_header *header; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE; a->archive.archive_format_name = "cpio (big-endian binary)"; /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, sizeof(struct cpio_bin_header), NULL); if (h == NULL) return (ARCHIVE_FATAL); __archive_read_consume(a, sizeof(struct cpio_bin_header)); /* Parse out binary fields. */ header = (const struct cpio_bin_header *)h; archive_entry_set_dev(entry, header->c_dev[0] * 256 + header->c_dev[1]); archive_entry_set_ino(entry, header->c_ino[0] * 256 + header->c_ino[1]); archive_entry_set_mode(entry, header->c_mode[0] * 256 + header->c_mode[1]); archive_entry_set_uid(entry, header->c_uid[0] * 256 + header->c_uid[1]); archive_entry_set_gid(entry, header->c_gid[0] * 256 + header->c_gid[1]); archive_entry_set_nlink(entry, header->c_nlink[0] * 256 + header->c_nlink[1]); archive_entry_set_rdev(entry, header->c_rdev[0] * 256 + header->c_rdev[1]); archive_entry_set_mtime(entry, be4(header->c_mtime), 0); *namelength = header->c_namesize[0] * 256 + header->c_namesize[1]; *name_pad = *namelength & 1; /* Pad to even. */ cpio->entry_bytes_remaining = be4(header->c_filesize); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */ return (ARCHIVE_OK); }
static int header_bin_be(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const unsigned char *header; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE; a->archive.archive_format_name = "cpio (big-endian binary)"; /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, bin_header_size, NULL); if (h == NULL) return (ARCHIVE_FATAL); /* Parse out binary fields. */ header = (const unsigned char *)h; archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]); archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]); archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]); archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]); archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]); archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]); archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]); archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0); *namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1]; *name_pad = *namelength & 1; /* Pad to even. */ cpio->entry_bytes_remaining = be4(header + bin_filesize_offset); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */ __archive_read_consume(a, bin_header_size); return (ARCHIVE_OK); }
static int header_odc(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; int r; const char *header; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; a->archive.archive_format_name = "POSIX octet-oriented cpio"; /* Find the start of the next header. */ r = find_odc_header(a); if (r < ARCHIVE_WARN) return (r); if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_AFIO_LARGE) { int r2 = (header_afiol(a, cpio, entry, namelength, name_pad)); if (r2 == ARCHIVE_OK) return (r); else return (r2); } /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, odc_header_size, NULL); if (h == NULL) return (ARCHIVE_FATAL); /* Parse out octal fields. */ header = (const char *)h; archive_entry_set_dev(entry, (dev_t)atol8(header + odc_dev_offset, odc_dev_size)); archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size)); archive_entry_set_mode(entry, (mode_t)atol8(header + odc_mode_offset, odc_mode_size)); archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size)); archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size)); archive_entry_set_nlink(entry, (unsigned int)atol8(header + odc_nlink_offset, odc_nlink_size)); archive_entry_set_rdev(entry, (dev_t)atol8(header + odc_rdev_offset, odc_rdev_size)); archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0); *namelength = (size_t)atol8(header + odc_namesize_offset, odc_namesize_size); *name_pad = 0; /* No padding of filename. */ /* * Note: entry_bytes_remaining is at least 64 bits and * therefore guaranteed to be big enough for a 33-bit file * size. */ cpio->entry_bytes_remaining = atol8(header + odc_filesize_offset, odc_filesize_size); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = 0; __archive_read_consume(a, odc_header_size); return (r); }
static int header_newc(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const struct cpio_newc_header *header; size_t bytes; int r; r = find_newc_header(a); if (r < ARCHIVE_WARN) return (r); /* Read fixed-size portion of header. */ bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_newc_header)); if (bytes < sizeof(struct cpio_newc_header)) return (ARCHIVE_FATAL); (a->decompressor->consume)(a, sizeof(struct cpio_newc_header)); /* Parse out hex fields. */ header = (const struct cpio_newc_header *)h; if (memcmp(header->c_magic, "070701", 6) == 0) { a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)"; } else if (memcmp(header->c_magic, "070702", 6) == 0) { a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC; a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)"; } else { /* TODO: Abort here? */ } archive_entry_set_devmajor(entry, atol16(header->c_devmajor, sizeof(header->c_devmajor))); archive_entry_set_devminor(entry, atol16(header->c_devminor, sizeof(header->c_devminor))); archive_entry_set_ino(entry, atol16(header->c_ino, sizeof(header->c_ino))); archive_entry_set_mode(entry, atol16(header->c_mode, sizeof(header->c_mode))); archive_entry_set_uid(entry, atol16(header->c_uid, sizeof(header->c_uid))); archive_entry_set_gid(entry, atol16(header->c_gid, sizeof(header->c_gid))); archive_entry_set_nlink(entry, atol16(header->c_nlink, sizeof(header->c_nlink))); archive_entry_set_rdevmajor(entry, atol16(header->c_rdevmajor, sizeof(header->c_rdevmajor))); archive_entry_set_rdevminor(entry, atol16(header->c_rdevminor, sizeof(header->c_rdevminor))); archive_entry_set_mtime(entry, atol16(header->c_mtime, sizeof(header->c_mtime)), 0); *namelength = atol16(header->c_namesize, sizeof(header->c_namesize)); /* Pad name to 2 more than a multiple of 4. */ *name_pad = (2 - *namelength) & 3; /* * Note: entry_bytes_remaining is at least 64 bits and * therefore guaranteed to be big enough for a 33-bit file * size. */ cpio->entry_bytes_remaining = atol16(header->c_filesize, sizeof(header->c_filesize)); archive_entry_set_size(entry, cpio->entry_bytes_remaining); /* Pad file contents to a multiple of 4. */ cpio->entry_padding = 3 & -cpio->entry_bytes_remaining; return (r); }
static int ar_entry_ino(lua_State *L) { struct archive_entry* self = *ar_entry_check(L, 1); int is_set; if ( NULL == self ) return 0; is_set = ( lua_gettop(L) == 2 ); lua_pushnumber(L, archive_entry_ino(self)); if ( is_set ) { archive_entry_set_ino(self, lua_tonumber(L, 2)); } return 1; }
static int header_odc(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; int r; const struct cpio_odc_header *header; size_t bytes; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; a->archive.archive_format_name = "POSIX octet-oriented cpio"; /* Find the start of the next header. */ r = find_odc_header(a); if (r < ARCHIVE_WARN) return (r); /* Read fixed-size portion of header. */ bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_odc_header)); if (bytes < sizeof(struct cpio_odc_header)) return (ARCHIVE_FATAL); (a->decompressor->consume)(a, sizeof(struct cpio_odc_header)); /* Parse out octal fields. */ header = (const struct cpio_odc_header *)h; archive_entry_set_dev(entry, atol8(header->c_dev, sizeof(header->c_dev))); archive_entry_set_ino(entry, atol8(header->c_ino, sizeof(header->c_ino))); archive_entry_set_mode(entry, atol8(header->c_mode, sizeof(header->c_mode))); archive_entry_set_uid(entry, atol8(header->c_uid, sizeof(header->c_uid))); archive_entry_set_gid(entry, atol8(header->c_gid, sizeof(header->c_gid))); archive_entry_set_nlink(entry, atol8(header->c_nlink, sizeof(header->c_nlink))); archive_entry_set_rdev(entry, atol8(header->c_rdev, sizeof(header->c_rdev))); archive_entry_set_mtime(entry, atol8(header->c_mtime, sizeof(header->c_mtime)), 0); *namelength = atol8(header->c_namesize, sizeof(header->c_namesize)); *name_pad = 0; /* No padding of filename. */ /* * Note: entry_bytes_remaining is at least 64 bits and * therefore guaranteed to be big enough for a 33-bit file * size. */ cpio->entry_bytes_remaining = atol8(header->c_filesize, sizeof(header->c_filesize)); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = 0; return (r); }
void archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st) { #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC archive_entry_set_atime(entry, st->st_atime, st->st_atimespec.tv_nsec); archive_entry_set_ctime(entry, st->st_ctime, st->st_ctimespec.tv_nsec); archive_entry_set_mtime(entry, st->st_mtime, st->st_mtimespec.tv_nsec); #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC archive_entry_set_atime(entry, st->st_atime, st->st_atim.tv_nsec); archive_entry_set_ctime(entry, st->st_ctime, st->st_ctim.tv_nsec); archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec); #elif HAVE_STRUCT_STAT_ST_MTIME_N archive_entry_set_atime(entry, st->st_atime, st->st_atime_n); archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_n); archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_n); #elif HAVE_STRUCT_STAT_ST_UMTIME archive_entry_set_atime(entry, st->st_atime, st->st_uatime * 1000); archive_entry_set_ctime(entry, st->st_ctime, st->st_uctime * 1000); archive_entry_set_mtime(entry, st->st_mtime, st->st_umtime * 1000); #elif HAVE_STRUCT_STAT_ST_MTIME_USEC archive_entry_set_atime(entry, st->st_atime, st->st_atime_usec * 1000); archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_usec * 1000); archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_usec * 1000); #else archive_entry_set_atime(entry, st->st_atime, 0); archive_entry_set_ctime(entry, st->st_ctime, 0); archive_entry_set_mtime(entry, st->st_mtime, 0); #endif #if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC archive_entry_set_birthtime(entry, st->st_birthtime, st->st_birthtimespec.tv_nsec); #elif HAVE_STRUCT_STAT_ST_BIRTHTIME archive_entry_set_birthtime(entry, st->st_birthtime, 0); #else archive_entry_unset_birthtime(entry); #endif archive_entry_set_dev(entry, st->st_dev); archive_entry_set_gid(entry, st->st_gid); archive_entry_set_uid(entry, st->st_uid); archive_entry_set_ino(entry, st->st_ino); archive_entry_set_nlink(entry, st->st_nlink); archive_entry_set_rdev(entry, st->st_rdev); archive_entry_set_size(entry, st->st_size); archive_entry_set_mode(entry, st->st_mode); }
/* * NOTE: if a filename suffix is ".z", it is the file gziped by afio. * it would be nice that we can show uncompressed file size and we can * uncompressed file contents automatically, unfortunately we have nothing * to get a uncompressed file size while reading each header. It means * we also cannot uncompress file contents under our framework. */ static int header_afiol(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const char *header; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE; a->archive.archive_format_name = "afio large ASCII"; /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, afiol_header_size, NULL); if (h == NULL) return (ARCHIVE_FATAL); /* Parse out octal fields. */ header = (const char *)h; archive_entry_set_dev(entry, (dev_t)atol16(header + afiol_dev_offset, afiol_dev_size)); archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size)); archive_entry_set_mode(entry, (mode_t)atol8(header + afiol_mode_offset, afiol_mode_size)); archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size)); archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size)); archive_entry_set_nlink(entry, (unsigned int)atol16(header + afiol_nlink_offset, afiol_nlink_size)); archive_entry_set_rdev(entry, (dev_t)atol16(header + afiol_rdev_offset, afiol_rdev_size)); archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0); *namelength = (size_t)atol16(header + afiol_namesize_offset, afiol_namesize_size); *name_pad = 0; /* No padding of filename. */ cpio->entry_bytes_remaining = atol16(header + afiol_filesize_offset, afiol_filesize_size); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = 0; __archive_read_consume(a, afiol_header_size); return (ARCHIVE_OK); }
static int header_bin_le(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const struct cpio_bin_header *header; size_t bytes; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE; a->archive.archive_format_name = "cpio (little-endian binary)"; /* Read fixed-size portion of header. */ bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_bin_header)); if (bytes < sizeof(struct cpio_bin_header)) return (ARCHIVE_FATAL); (a->decompressor->consume)(a, sizeof(struct cpio_bin_header)); /* Parse out binary fields. */ header = (const struct cpio_bin_header *)h; archive_entry_set_dev(entry, header->c_dev[0] + header->c_dev[1] * 256); archive_entry_set_ino(entry, header->c_ino[0] + header->c_ino[1] * 256); archive_entry_set_mode(entry, header->c_mode[0] + header->c_mode[1] * 256); archive_entry_set_uid(entry, header->c_uid[0] + header->c_uid[1] * 256); archive_entry_set_gid(entry, header->c_gid[0] + header->c_gid[1] * 256); archive_entry_set_nlink(entry, header->c_nlink[0] + header->c_nlink[1] * 256); archive_entry_set_rdev(entry, header->c_rdev[0] + header->c_rdev[1] * 256); archive_entry_set_mtime(entry, le4(header->c_mtime), 0); *namelength = header->c_namesize[0] + header->c_namesize[1] * 256; *name_pad = *namelength & 1; /* Pad to even. */ cpio->entry_bytes_remaining = le4(header->c_filesize); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */ return (ARCHIVE_OK); }
/* * A single file can have multiple lines contribute specifications. * Parse as many lines as necessary, then pull additional information * from a backing file on disk as necessary. */ static int parse_file(struct archive_read *a, struct archive_entry *entry, struct mtree *mtree, struct mtree_entry *mentry, int *use_next) { const char *path; struct stat st_storage, *st; struct mtree_entry *mp; struct archive_entry *sparse_entry; int r = ARCHIVE_OK, r1, parsed_kws; mentry->used = 1; /* Initialize reasonable defaults. */ archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_size(entry, 0); archive_string_empty(&mtree->contents_name); /* Parse options from this line. */ parsed_kws = 0; r = parse_line(a, entry, mtree, mentry, &parsed_kws); if (mentry->full) { archive_entry_copy_pathname(entry, mentry->name); /* * "Full" entries are allowed to have multiple lines * and those lines aren't required to be adjacent. We * don't support multiple lines for "relative" entries * nor do we make any attempt to merge data from * separate "relative" and "full" entries. (Merging * "relative" and "full" entries would require dealing * with pathname canonicalization, which is a very * tricky subject.) */ for (mp = mentry->next; mp != NULL; mp = mp->next) { if (mp->full && !mp->used && strcmp(mentry->name, mp->name) == 0) { /* Later lines override earlier ones. */ mp->used = 1; r1 = parse_line(a, entry, mtree, mp, &parsed_kws); if (r1 < r) r = r1; } } } else { /* * Relative entries require us to construct * the full path and possibly update the * current directory. */ size_t n = archive_strlen(&mtree->current_dir); if (n > 0) archive_strcat(&mtree->current_dir, "/"); archive_strcat(&mtree->current_dir, mentry->name); archive_entry_copy_pathname(entry, mtree->current_dir.s); if (archive_entry_filetype(entry) != AE_IFDIR) mtree->current_dir.length = n; } /* * Try to open and stat the file to get the real size * and other file info. It would be nice to avoid * this here so that getting a listing of an mtree * wouldn't require opening every referenced contents * file. But then we wouldn't know the actual * contents size, so I don't see a really viable way * around this. (Also, we may want to someday pull * other unspecified info from the contents file on * disk.) */ mtree->fd = -1; if (archive_strlen(&mtree->contents_name) > 0) path = mtree->contents_name.s; else path = archive_entry_pathname(entry); if (archive_entry_filetype(entry) == AE_IFREG || archive_entry_filetype(entry) == AE_IFDIR) { mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC); __archive_ensure_cloexec_flag(mtree->fd); if (mtree->fd == -1 && (errno != ENOENT || archive_strlen(&mtree->contents_name) > 0)) { archive_set_error(&a->archive, errno, "Can't open %s", path); r = ARCHIVE_WARN; } } st = &st_storage; if (mtree->fd >= 0) { if (fstat(mtree->fd, st) == -1) { archive_set_error(&a->archive, errno, "Could not fstat %s", path); r = ARCHIVE_WARN; /* If we can't stat it, don't keep it open. */ close(mtree->fd); mtree->fd = -1; st = NULL; } } else if (lstat(path, st) == -1) { st = NULL; } /* * Check for a mismatch between the type in the specification and * the type of the contents object on disk. */ if (st != NULL) { if ( ((st->st_mode & S_IFMT) == S_IFREG && archive_entry_filetype(entry) == AE_IFREG) #ifdef S_IFLNK || ((st->st_mode & S_IFMT) == S_IFLNK && archive_entry_filetype(entry) == AE_IFLNK) #endif #ifdef S_IFSOCK || ((st->st_mode & S_IFSOCK) == S_IFSOCK && archive_entry_filetype(entry) == AE_IFSOCK) #endif #ifdef S_IFCHR || ((st->st_mode & S_IFMT) == S_IFCHR && archive_entry_filetype(entry) == AE_IFCHR) #endif #ifdef S_IFBLK || ((st->st_mode & S_IFMT) == S_IFBLK && archive_entry_filetype(entry) == AE_IFBLK) #endif || ((st->st_mode & S_IFMT) == S_IFDIR && archive_entry_filetype(entry) == AE_IFDIR) #ifdef S_IFIFO || ((st->st_mode & S_IFMT) == S_IFIFO && archive_entry_filetype(entry) == AE_IFIFO) #endif ) { /* Types match. */ } else { /* Types don't match; bail out gracefully. */ if (mtree->fd >= 0) close(mtree->fd); mtree->fd = -1; if (parsed_kws & MTREE_HAS_OPTIONAL) { /* It's not an error for an optional entry to not match disk. */ *use_next = 1; } else if (r == ARCHIVE_OK) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "mtree specification has different type for %s", archive_entry_pathname(entry)); r = ARCHIVE_WARN; } return r; } } /* * If there is a contents file on disk, pick some of the metadata * from that file. For most of these, we only set it from the contents * if it wasn't already parsed from the specification. */ if (st != NULL) { if (((parsed_kws & MTREE_HAS_DEVICE) == 0 || (parsed_kws & MTREE_HAS_NOCHANGE) != 0) && (archive_entry_filetype(entry) == AE_IFCHR || archive_entry_filetype(entry) == AE_IFBLK)) archive_entry_set_rdev(entry, st->st_rdev); if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 || (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_gid(entry, st->st_gid); if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 || (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_uid(entry, st->st_uid); if ((parsed_kws & MTREE_HAS_MTIME) == 0 || (parsed_kws & MTREE_HAS_NOCHANGE) != 0) { #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC archive_entry_set_mtime(entry, st->st_mtime, st->st_mtimespec.tv_nsec); #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec); #elif HAVE_STRUCT_STAT_ST_MTIME_N archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_n); #elif HAVE_STRUCT_STAT_ST_UMTIME archive_entry_set_mtime(entry, st->st_mtime, st->st_umtime*1000); #elif HAVE_STRUCT_STAT_ST_MTIME_USEC archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_usec*1000); #else archive_entry_set_mtime(entry, st->st_mtime, 0); #endif } if ((parsed_kws & MTREE_HAS_NLINK) == 0 || (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_nlink(entry, st->st_nlink); if ((parsed_kws & MTREE_HAS_PERM) == 0 || (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_perm(entry, st->st_mode); if ((parsed_kws & MTREE_HAS_SIZE) == 0 || (parsed_kws & MTREE_HAS_NOCHANGE) != 0) archive_entry_set_size(entry, st->st_size); archive_entry_set_ino(entry, st->st_ino); archive_entry_set_dev(entry, st->st_dev); archive_entry_linkify(mtree->resolver, &entry, &sparse_entry); } else if (parsed_kws & MTREE_HAS_OPTIONAL) { /* * Couldn't open the entry, stat it or the on-disk type * didn't match. If this entry is optional, just ignore it * and read the next header entry. */ *use_next = 1; return ARCHIVE_OK; } mtree->cur_size = archive_entry_size(entry); mtree->offset = 0; return r; }
static int archive_read_format_iso9660_read_header(struct archive_read *a, struct archive_entry *entry) { struct iso9660 *iso9660; struct file_info *file; ssize_t bytes_read; int r; iso9660 = (struct iso9660 *)(a->format->data); if (!a->archive.archive_format) { a->archive.archive_format = ARCHIVE_FORMAT_ISO9660; a->archive.archive_format_name = "ISO9660"; } /* Get the next entry that appears after the current offset. */ r = next_entry_seek(a, iso9660, &file); if (r != ARCHIVE_OK) return (r); iso9660->entry_bytes_remaining = file->size; iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */ /* Set up the entry structure with information about this entry. */ archive_entry_set_mode(entry, file->mode); archive_entry_set_uid(entry, file->uid); archive_entry_set_gid(entry, file->gid); archive_entry_set_nlink(entry, file->nlinks); archive_entry_set_ino(entry, file->inode); archive_entry_set_mtime(entry, file->mtime, 0); archive_entry_set_ctime(entry, file->ctime, 0); archive_entry_set_atime(entry, file->atime, 0); archive_entry_set_size(entry, iso9660->entry_bytes_remaining); archive_string_empty(&iso9660->pathname); archive_entry_set_pathname(entry, build_pathname(&iso9660->pathname, file)); if (file->symlink.s != NULL) archive_entry_copy_symlink(entry, file->symlink.s); /* If this entry points to the same data as the previous * entry, convert this into a hardlink to that entry. * But don't bother for zero-length files. */ if (file->offset == iso9660->previous_offset && file->size == iso9660->previous_size && file->size > 0) { archive_entry_set_hardlink(entry, iso9660->previous_pathname.s); iso9660->entry_bytes_remaining = 0; iso9660->entry_sparse_offset = 0; release_file(iso9660, file); return (ARCHIVE_OK); } /* If the offset is before our current position, we can't * seek backwards to extract it, so issue a warning. */ if (file->offset < iso9660->current_position) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Ignoring out-of-order file"); iso9660->entry_bytes_remaining = 0; iso9660->entry_sparse_offset = 0; release_file(iso9660, file); return (ARCHIVE_WARN); } iso9660->previous_size = file->size; iso9660->previous_offset = file->offset; archive_strcpy(&iso9660->previous_pathname, iso9660->pathname.s); /* If this is a directory, read in all of the entries right now. */ if (archive_entry_filetype(entry) == AE_IFDIR) { while (iso9660->entry_bytes_remaining > 0) { const void *block; const unsigned char *p; ssize_t step = iso9660->logical_block_size; if (step > iso9660->entry_bytes_remaining) step = iso9660->entry_bytes_remaining; bytes_read = (a->decompressor->read_ahead)(a, &block, step); if (bytes_read < step) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Failed to read full block when scanning ISO9660 directory list"); release_file(iso9660, file); return (ARCHIVE_FATAL); } if (bytes_read > step) bytes_read = step; (a->decompressor->consume)(a, bytes_read); iso9660->current_position += bytes_read; iso9660->entry_bytes_remaining -= bytes_read; for (p = (const unsigned char *)block; *p != 0 && p < (const unsigned char *)block + bytes_read; p += *p) { struct file_info *child; /* Skip '.' entry. */ if (*(p + DR_name_len_offset) == 1 && *(p + DR_name_offset) == '\0') continue; /* Skip '..' entry. */ if (*(p + DR_name_len_offset) == 1 && *(p + DR_name_offset) == '\001') continue; child = parse_file_info(iso9660, file, p); add_entry(iso9660, child); if (iso9660->seenRockridge) { a->archive.archive_format = ARCHIVE_FORMAT_ISO9660_ROCKRIDGE; a->archive.archive_format_name = "ISO9660 with Rockridge extensions"; } } } } release_file(iso9660, file); return (ARCHIVE_OK); }
static int header_newc(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const char *header; int r; r = find_newc_header(a); if (r < ARCHIVE_WARN) return (r); /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, newc_header_size, NULL); if (h == NULL) return (ARCHIVE_FATAL); /* Parse out hex fields. */ header = (const char *)h; if (memcmp(header + newc_magic_offset, "070701", 6) == 0) { a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)"; } else if (memcmp(header + newc_magic_offset, "070702", 6) == 0) { a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC; a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)"; } else { /* TODO: Abort here? */ } archive_entry_set_devmajor(entry, (dev_t)atol16(header + newc_devmajor_offset, newc_devmajor_size)); archive_entry_set_devminor(entry, (dev_t)atol16(header + newc_devminor_offset, newc_devminor_size)); archive_entry_set_ino(entry, atol16(header + newc_ino_offset, newc_ino_size)); archive_entry_set_mode(entry, (mode_t)atol16(header + newc_mode_offset, newc_mode_size)); archive_entry_set_uid(entry, atol16(header + newc_uid_offset, newc_uid_size)); archive_entry_set_gid(entry, atol16(header + newc_gid_offset, newc_gid_size)); archive_entry_set_nlink(entry, (unsigned int)atol16(header + newc_nlink_offset, newc_nlink_size)); archive_entry_set_rdevmajor(entry, (dev_t)atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size)); archive_entry_set_rdevminor(entry, (dev_t)atol16(header + newc_rdevminor_offset, newc_rdevminor_size)); archive_entry_set_mtime(entry, atol16(header + newc_mtime_offset, newc_mtime_size), 0); *namelength = (size_t)atol16(header + newc_namesize_offset, newc_namesize_size); /* Pad name to 2 more than a multiple of 4. */ *name_pad = (2 - *namelength) & 3; /* * Note: entry_bytes_remaining is at least 64 bits and * therefore guaranteed to be big enough for a 33-bit file * size. */ cpio->entry_bytes_remaining = atol16(header + newc_filesize_offset, newc_filesize_size); archive_entry_set_size(entry, cpio->entry_bytes_remaining); /* Pad file contents to a multiple of 4. */ cpio->entry_padding = 3 & -cpio->entry_bytes_remaining; __archive_read_consume(a, newc_header_size); return (r); }
static void test_linkify_tar(void) { struct archive_entry *entry, *e2; struct archive_entry_linkresolver *resolver; /* Initialize the resolver. */ assert(NULL != (resolver = archive_entry_linkresolver_new())); archive_entry_linkresolver_set_strategy(resolver, ARCHIVE_FORMAT_TAR_USTAR); /* Create an entry with only 1 link and try to linkify it. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test1"); archive_entry_set_ino(entry, 1); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 1); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't have been changed. */ assert(e2 == NULL); assertEqualInt(10, archive_entry_size(entry)); assertEqualString("test1", archive_entry_pathname(entry)); /* Now, try again with an entry that has 2 links. */ archive_entry_set_pathname(entry, "test2"); archive_entry_set_nlink(entry, 2); archive_entry_set_ino(entry, 2); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't be altered, since it wasn't seen before. */ assert(e2 == NULL); assertEqualString("test2", archive_entry_pathname(entry)); assertEqualString(NULL, archive_entry_hardlink(entry)); assertEqualInt(10, archive_entry_size(entry)); /* Match again and make sure it does get altered. */ archive_entry_linkify(resolver, &entry, &e2); assert(e2 == NULL); assertEqualString("test2", archive_entry_pathname(entry)); assertEqualString("test2", archive_entry_hardlink(entry)); assertEqualInt(0, archive_entry_size(entry)); /* Dirs should never be matched as hardlinks, regardless. */ archive_entry_set_pathname(entry, "test3"); archive_entry_set_nlink(entry, 2); archive_entry_set_filetype(entry, AE_IFDIR); archive_entry_set_ino(entry, 3); archive_entry_set_hardlink(entry, NULL); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't be altered, since it wasn't seen before. */ assert(e2 == NULL); assertEqualString("test3", archive_entry_pathname(entry)); assertEqualString(NULL, archive_entry_hardlink(entry)); /* Dir, so it shouldn't get matched. */ archive_entry_linkify(resolver, &entry, &e2); assert(e2 == NULL); assertEqualString("test3", archive_entry_pathname(entry)); assertEqualString(NULL, archive_entry_hardlink(entry)); archive_entry_free(entry); archive_entry_linkresolver_free(resolver); }
static void test_linkify_new_cpio(void) { struct archive_entry *entry, *e2; struct archive_entry_linkresolver *resolver; /* Initialize the resolver. */ assert(NULL != (resolver = archive_entry_linkresolver_new())); archive_entry_linkresolver_set_strategy(resolver, ARCHIVE_FORMAT_CPIO_SVR4_NOCRC); /* Create an entry with only 1 link and try to linkify it. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test1"); archive_entry_set_ino(entry, 1); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 1); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't have been changed. */ assert(e2 == NULL); assertEqualInt(10, archive_entry_size(entry)); assertEqualString("test1", archive_entry_pathname(entry)); /* Now, try again with an entry that has 3 links. */ archive_entry_set_pathname(entry, "test2"); archive_entry_set_nlink(entry, 3); archive_entry_set_ino(entry, 2); archive_entry_linkify(resolver, &entry, &e2); /* First time, it just gets swallowed. */ assert(entry == NULL); assert(e2 == NULL); /* Match again. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test3"); archive_entry_set_ino(entry, 2); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 2); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Should get back "test2" and nothing else. */ assertEqualString("test2", archive_entry_pathname(entry)); assertEqualInt(0, archive_entry_size(entry)); archive_entry_free(entry); assert(NULL == e2); archive_entry_free(e2); /* This should be a no-op. */ /* Match a third time. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test4"); archive_entry_set_ino(entry, 2); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 3); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Should get back "test3". */ assertEqualString("test3", archive_entry_pathname(entry)); assertEqualInt(0, archive_entry_size(entry)); /* Since "test4" was the last link, should get it back also. */ assertEqualString("test4", archive_entry_pathname(e2)); assertEqualInt(10, archive_entry_size(e2)); archive_entry_free(entry); archive_entry_free(e2); archive_entry_linkresolver_free(resolver); }
/* * Parse a single keyword and its value. */ static int parse_keyword(struct archive_read *a, struct mtree *mtree, struct archive_entry *entry, struct mtree_option *opt, int *parsed_kws) { char *val, *key; key = opt->value; if (*key == '\0') return (ARCHIVE_OK); if (strcmp(key, "nochange") == 0) { *parsed_kws |= MTREE_HAS_NOCHANGE; return (ARCHIVE_OK); } if (strcmp(key, "optional") == 0) { *parsed_kws |= MTREE_HAS_OPTIONAL; return (ARCHIVE_OK); } if (strcmp(key, "ignore") == 0) { /* * The mtree processing is not recursive, so * recursion will only happen for explicitly listed * entries. */ return (ARCHIVE_OK); } val = strchr(key, '='); if (val == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Malformed attribute \"%s\" (%d)", key, key[0]); return (ARCHIVE_WARN); } *val = '\0'; ++val; switch (key[0]) { case 'c': if (strcmp(key, "content") == 0 || strcmp(key, "contents") == 0) { parse_escapes(val, NULL); archive_strcpy(&mtree->contents_name, val); break; } if (strcmp(key, "cksum") == 0) break; case 'd': if (strcmp(key, "device") == 0) { /* stat(2) st_rdev field, e.g. the major/minor IDs * of a char/block special file */ int r; dev_t dev; *parsed_kws |= MTREE_HAS_DEVICE; r = parse_device(&dev, &a->archive, val); if (r == ARCHIVE_OK) archive_entry_set_rdev(entry, dev); return r; } case 'f': if (strcmp(key, "flags") == 0) { *parsed_kws |= MTREE_HAS_FFLAGS; archive_entry_copy_fflags_text(entry, val); break; } case 'g': if (strcmp(key, "gid") == 0) { *parsed_kws |= MTREE_HAS_GID; archive_entry_set_gid(entry, mtree_atol10(&val)); break; } if (strcmp(key, "gname") == 0) { *parsed_kws |= MTREE_HAS_GNAME; archive_entry_copy_gname(entry, val); break; } case 'i': if (strcmp(key, "inode") == 0) { archive_entry_set_ino(entry, mtree_atol10(&val)); break; } case 'l': if (strcmp(key, "link") == 0) { archive_entry_copy_symlink(entry, val); break; } case 'm': if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) break; if (strcmp(key, "mode") == 0) { if (val[0] >= '0' && val[0] <= '9') { *parsed_kws |= MTREE_HAS_PERM; archive_entry_set_perm(entry, (mode_t)mtree_atol8(&val)); } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Symbolic mode \"%s\" unsupported", val); return ARCHIVE_WARN; } break; } case 'n': if (strcmp(key, "nlink") == 0) { *parsed_kws |= MTREE_HAS_NLINK; archive_entry_set_nlink(entry, (unsigned int)mtree_atol10(&val)); break; } case 'r': if (strcmp(key, "resdevice") == 0) { /* stat(2) st_dev field, e.g. the device ID where the * inode resides */ int r; dev_t dev; r = parse_device(&dev, &a->archive, val); if (r == ARCHIVE_OK) archive_entry_set_dev(entry, dev); return r; } if (strcmp(key, "rmd160") == 0 || strcmp(key, "rmd160digest") == 0) break; case 's': if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0) break; if (strcmp(key, "sha256") == 0 || strcmp(key, "sha256digest") == 0) break; if (strcmp(key, "sha384") == 0 || strcmp(key, "sha384digest") == 0) break; if (strcmp(key, "sha512") == 0 || strcmp(key, "sha512digest") == 0) break; if (strcmp(key, "size") == 0) { archive_entry_set_size(entry, mtree_atol10(&val)); break; } case 't': if (strcmp(key, "tags") == 0) { /* * Comma delimited list of tags. * Ignore the tags for now, but the interface * should be extended to allow inclusion/exclusion. */ break; } if (strcmp(key, "time") == 0) { int64_t m; int64_t my_time_t_max = get_time_t_max(); int64_t my_time_t_min = get_time_t_min(); long ns = 0; *parsed_kws |= MTREE_HAS_MTIME; m = mtree_atol10(&val); /* Replicate an old mtree bug: * 123456789.1 represents 123456789 * seconds and 1 nanosecond. */ if (*val == '.') { ++val; ns = (long)mtree_atol10(&val); } else ns = 0; if (m > my_time_t_max) m = my_time_t_max; else if (m < my_time_t_min) m = my_time_t_min; archive_entry_set_mtime(entry, (time_t)m, ns); break; } if (strcmp(key, "type") == 0) { switch (val[0]) { case 'b': if (strcmp(val, "block") == 0) { archive_entry_set_filetype(entry, AE_IFBLK); break; } case 'c': if (strcmp(val, "char") == 0) { archive_entry_set_filetype(entry, AE_IFCHR); break; } case 'd': if (strcmp(val, "dir") == 0) { archive_entry_set_filetype(entry, AE_IFDIR); break; } case 'f': if (strcmp(val, "fifo") == 0) { archive_entry_set_filetype(entry, AE_IFIFO); break; } if (strcmp(val, "file") == 0) { archive_entry_set_filetype(entry, AE_IFREG); break; } case 'l': if (strcmp(val, "link") == 0) { archive_entry_set_filetype(entry, AE_IFLNK); break; } default: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Unrecognized file type \"%s\"; " "assuming \"file\"", val); archive_entry_set_filetype(entry, AE_IFREG); return (ARCHIVE_WARN); } *parsed_kws |= MTREE_HAS_TYPE; break; } case 'u': if (strcmp(key, "uid") == 0) { *parsed_kws |= MTREE_HAS_UID; archive_entry_set_uid(entry, mtree_atol10(&val)); break; } if (strcmp(key, "uname") == 0) { *parsed_kws |= MTREE_HAS_UNAME; archive_entry_copy_uname(entry, val); break; } default: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Unrecognized key %s=%s", key, val); return (ARCHIVE_WARN); } return (ARCHIVE_OK); }
void Entry::set_ino(unsigned long ino) { archive_entry_set_ino(_entry, ino); }