Exemple #1
0
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);
}