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 void record_hardlink(struct cpio *cpio, struct archive_entry *entry) { struct links_entry *le; dev_t dev; ino_t ino; dev = archive_entry_dev(entry); ino = archive_entry_ino(entry); /* * First look in the list of multiply-linked files. If we've * already dumped it, convert this entry to a hard link entry. */ for (le = cpio->links_head; le; le = le->next) { if (le->dev == dev && le->ino == ino) { archive_entry_set_hardlink(entry, le->name); if (--le->links <= 0) { if (le->previous != NULL) le->previous->next = le->next; if (le->next != NULL) le->next->previous = le->previous; if (cpio->links_head == le) cpio->links_head = le->next; free(le); } return; } } le = (struct links_entry *)malloc(sizeof(struct links_entry)); if (le == NULL) __archive_errx(1, "Out of memory adding file to list"); if (cpio->links_head != NULL) cpio->links_head->previous = le; le->next = cpio->links_head; le->previous = NULL; cpio->links_head = le; le->dev = dev; le->ino = ino; le->links = archive_entry_nlink(entry) - 1; le->name = strdup(archive_entry_pathname(entry)); if (le->name == NULL) __archive_errx(1, "Out of memory adding file to list"); }
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_newc_header(struct archive_write *a, struct archive_entry *entry) { struct cpio *cpio; const char *p, *path; int pathlength, ret; struct cpio_header_newc h; int pad; 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_hex(0x070701, &h.c_magic, sizeof(h.c_magic)); format_hex(archive_entry_devmajor(entry), &h.c_devmajor, sizeof(h.c_devmajor)); format_hex(archive_entry_devminor(entry), &h.c_devminor, sizeof(h.c_devminor)); if (archive_entry_ino(entry) > 0xffffffff) { archive_set_error(&a->archive, ERANGE, "large inode number truncated"); ret = ARCHIVE_WARN; } format_hex(archive_entry_ino(entry) & 0xffffffff, &h.c_ino, sizeof(h.c_ino)); format_hex(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode)); format_hex(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid)); format_hex(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid)); format_hex(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_hex(archive_entry_rdevmajor(entry), &h.c_rdevmajor, sizeof(h.c_rdevmajor)); format_hex(archive_entry_rdevminor(entry), &h.c_rdevminor, sizeof(h.c_rdevminor)); } else { format_hex(0, &h.c_rdevmajor, sizeof(h.c_rdevmajor)); format_hex(0, &h.c_rdevminor, sizeof(h.c_rdevminor)); } format_hex(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime)); format_hex(pathlength, &h.c_namesize, sizeof(h.c_namesize)); format_hex(0, &h.c_checksum, sizeof(h.c_checksum)); /* 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_hex(strlen(p), &h.c_filesize, sizeof(h.c_filesize)); else format_hex(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); /* Pad pathname to even length. */ ret = (a->compressor.write)(a, path, pathlength); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); pad = 0x3 & - (pathlength + sizeof(struct cpio_header_newc)); if (pad) ret = (a->compressor.write)(a, "\0\0\0", pad); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); cpio->entry_bytes_remaining = archive_entry_size(entry); cpio->padding = 3 & (-cpio->entry_bytes_remaining); /* Write the symlink now. */ if (p != NULL && *p != '\0') ret = (a->compressor.write)(a, p, strlen(p)); return (ret); }
static struct links_entry * find_entry(struct archive_entry_linkresolver *res, struct archive_entry *entry) { struct links_entry *le; int hash, bucket; dev_t dev; #ifndef __minix int64_t ino; #else int32_t ino; #endif /* Free a held entry. */ if (res->spare != NULL) { archive_entry_free(res->spare->canonical); archive_entry_free(res->spare->entry); free(res->spare); res->spare = NULL; } /* If the links cache overflowed and got flushed, don't bother. */ if (res->buckets == NULL) return (NULL); dev = archive_entry_dev(entry); #ifndef __minix ino = archive_entry_ino64(entry); #else ino = archive_entry_ino(entry); #endif hash = (int)(dev ^ ino); /* Try to locate this entry in the links cache. */ bucket = hash % res->number_buckets; for (le = res->buckets[bucket]; le != NULL; le = le->next) { #ifndef __minix if (le->hash == hash && dev == archive_entry_dev(le->canonical) && ino == archive_entry_ino64(le->canonical)) { #else if (le->hash == hash && dev == archive_entry_dev(le->canonical) && ino == archive_entry_ino(le->canonical)) { #endif /* * Decrement link count each time and release * the entry if it hits zero. This saves * memory and is necessary for detecting * missed links. */ --le->links; if (le->links > 0) return (le); /* Remove it from this hash bucket. */ if (le->previous != NULL) le->previous->next = le->next; if (le->next != NULL) le->next->previous = le->previous; if (res->buckets[bucket] == le) res->buckets[bucket] = le->next; res->number_entries--; /* Defer freeing this entry. */ res->spare = le; return (le); } } return (NULL); } static struct links_entry * next_entry(struct archive_entry_linkresolver *res) { struct links_entry *le; size_t bucket; /* Free a held entry. */ if (res->spare != NULL) { archive_entry_free(res->spare->canonical); free(res->spare); res->spare = NULL; } /* If the links cache overflowed and got flushed, don't bother. */ if (res->buckets == NULL) return (NULL); /* Look for next non-empty bucket in the links cache. */ for (bucket = 0; bucket < res->number_buckets; bucket++) { le = res->buckets[bucket]; if (le != NULL) { /* Remove it from this hash bucket. */ if (le->next != NULL) le->next->previous = le->previous; res->buckets[bucket] = le->next; res->number_entries--; /* Defer freeing this entry. */ res->spare = le; return (le); } } return (NULL); } static struct links_entry * insert_entry(struct archive_entry_linkresolver *res, struct archive_entry *entry) { struct links_entry *le; int hash, bucket; /* Add this entry to the links cache. */ le = malloc(sizeof(struct links_entry)); if (le == NULL) return (NULL); memset(le, 0, sizeof(*le)); le->canonical = archive_entry_clone(entry); /* If the links cache is getting too full, enlarge the hash table. */ if (res->number_entries > res->number_buckets * 2) grow_hash(res); #ifndef __minix hash = archive_entry_dev(entry) ^ archive_entry_ino64(entry); #else hash = ((int)archive_entry_dev(entry)) ^ ((int)archive_entry_ino(entry)); #endif bucket = hash % res->number_buckets; /* If we could allocate the entry, record it. */ if (res->buckets[bucket] != NULL) res->buckets[bucket]->previous = le; res->number_entries++; le->next = res->buckets[bucket]; le->previous = NULL; res->buckets[bucket] = le; le->hash = hash; le->links = archive_entry_nlink(entry) - 1; return (le); } static void grow_hash(struct archive_entry_linkresolver *res) { struct links_entry *le, **new_buckets; size_t new_size; size_t i, bucket; /* Try to enlarge the bucket list. */ new_size = res->number_buckets * 2; new_buckets = malloc(new_size * sizeof(struct links_entry *)); if (new_buckets != NULL) { memset(new_buckets, 0, new_size * sizeof(struct links_entry *)); for (i = 0; i < res->number_buckets; i++) { while (res->buckets[i] != NULL) { /* Remove entry from old bucket. */ le = res->buckets[i]; res->buckets[i] = le->next; /* Add entry to new bucket. */ bucket = le->hash % new_size; if (new_buckets[bucket] != NULL) new_buckets[bucket]->previous = le; le->next = new_buckets[bucket]; le->previous = NULL; new_buckets[bucket] = le; } } free(res->buckets); res->buckets = new_buckets; res->number_buckets = new_size; } }
unsigned long Entry::ino() { return archive_entry_ino(_entry); }
const char * archive_entry_linkresolve(struct archive_entry_linkresolver *links_cache, struct archive_entry *entry) { struct links_entry *le, **new_buckets; int hash; size_t i, new_size; dev_t dev; ino_t ino; int nlinks; /* Free a held name. */ free(links_cache->last_name); links_cache->last_name = NULL; /* If the links cache overflowed and got flushed, don't bother. */ if (links_cache->buckets == NULL) return (NULL); dev = archive_entry_dev(entry); ino = archive_entry_ino(entry); nlinks = archive_entry_nlink(entry); /* An entry with one link can't be a hard link. */ if (nlinks == 1) return (NULL); /* If the links cache is getting too full, enlarge the hash table. */ if (links_cache->number_entries > links_cache->number_buckets * 2) { /* Try to enlarge the bucket list. */ new_size = links_cache->number_buckets * 2; new_buckets = malloc(new_size * sizeof(struct links_entry *)); if (new_buckets != NULL) { memset(new_buckets, 0, new_size * sizeof(struct links_entry *)); for (i = 0; i < links_cache->number_buckets; i++) { while (links_cache->buckets[i] != NULL) { /* Remove entry from old bucket. */ le = links_cache->buckets[i]; links_cache->buckets[i] = le->next; /* Add entry to new bucket. */ hash = (le->dev ^ le->ino) % new_size; if (new_buckets[hash] != NULL) new_buckets[hash]->previous = le; le->next = new_buckets[hash]; le->previous = NULL; new_buckets[hash] = le; } } free(links_cache->buckets); links_cache->buckets = new_buckets; links_cache->number_buckets = new_size; } } /* Try to locate this entry in the links cache. */ hash = ( dev ^ ino ) % links_cache->number_buckets; for (le = links_cache->buckets[hash]; le != NULL; le = le->next) { if (le->dev == dev && le->ino == ino) { /* * Decrement link count each time and release * the entry if it hits zero. This saves * memory and is necessary for detecting * missed links. */ --le->links; if (le->links > 0) return (le->name); /* * When we release the entry, save the name * until the next call. */ links_cache->last_name = le->name; /* * Release the entry. */ if (le->previous != NULL) le->previous->next = le->next; if (le->next != NULL) le->next->previous = le->previous; if (links_cache->buckets[hash] == le) links_cache->buckets[hash] = le->next; links_cache->number_entries--; free(le); return (links_cache->last_name); } } /* Add this entry to the links cache. */ le = malloc(sizeof(struct links_entry)); if (le == NULL) return (NULL); le->name = strdup(archive_entry_pathname(entry)); if (le->name == NULL) { free(le); return (NULL); } /* If we could allocate the entry, record it. */ if (links_cache->buckets[hash] != NULL) links_cache->buckets[hash]->previous = le; links_cache->number_entries++; le->next = links_cache->buckets[hash]; le->previous = NULL; links_cache->buckets[hash] = le; le->dev = dev; le->ino = ino; le->links = nlinks - 1; return (NULL); }