X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Finode.c;h=42faa194fba99165b18a1464b389255d3844a955;hp=34508659fa6724d56142552960a659df273a69ea;hb=af141a23c4d1540b8a64759bb68c7cd7ff054e72;hpb=a1d2684c03d066f103ae50485f48512613b84575 diff --git a/src/inode.c b/src/inode.c index 34508659..42faa194 100644 --- a/src/inode.c +++ b/src/inode.c @@ -39,6 +39,8 @@ #include "wimlib/security.h" #include "wimlib/timestamp.h" +#include + /* Allocate a new inode. Set the timestamps to the current time. */ struct wim_inode * new_inode(void) @@ -108,6 +110,8 @@ free_inode(struct wim_inode *inode) destroy_ads_entry(&inode->i_ads_entries[i]); FREE(inode->i_ads_entries); } + if (inode->i_extra) + FREE(inode->i_extra); /* HACK: This may instead delete the inode from i_list, but hlist_del() * behaves the same as list_del(). */ if (!hlist_unhashed(&inode->i_hlist)) @@ -136,96 +140,64 @@ ads_entry_has_name(const struct wim_ads_entry *entry, * * If @p stream_name is the empty string, NULL is returned --- that is, this * function will not return "unnamed" alternate data stream entries. + * + * If NULL is returned, errno is set. */ struct wim_ads_entry * -inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name, - u16 *idx_ret) +inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name) { + int ret; + const utf16lechar *stream_name_utf16le; + size_t stream_name_utf16le_nbytes; + u16 i; + struct wim_ads_entry *result; + if (inode->i_num_ads == 0) { + errno = ENOENT; return NULL; - } else { - size_t stream_name_utf16le_nbytes; - u16 i; - struct wim_ads_entry *result; - - if (stream_name[0] == T('\0')) - return NULL; + } - #if TCHAR_IS_UTF16LE - const utf16lechar *stream_name_utf16le; + if (stream_name[0] == T('\0')) { + errno = ENOENT; + return NULL; + } - stream_name_utf16le = stream_name; - stream_name_utf16le_nbytes = tstrlen(stream_name) * sizeof(tchar); - #else - utf16lechar *stream_name_utf16le; + ret = tstr_get_utf16le_and_len(stream_name, &stream_name_utf16le, + &stream_name_utf16le_nbytes); + if (ret) + return NULL; + i = 0; + result = NULL; + do { + if (ads_entry_has_name(&inode->i_ads_entries[i], + stream_name_utf16le, + stream_name_utf16le_nbytes, + default_ignore_case)) { - int ret = tstr_to_utf16le(stream_name, - tstrlen(stream_name) * - sizeof(tchar), - &stream_name_utf16le, - &stream_name_utf16le_nbytes); - if (ret) - return NULL; + result = &inode->i_ads_entries[i]; + break; } - #endif - i = 0; - result = NULL; - do { - if (ads_entry_has_name(&inode->i_ads_entries[i], - stream_name_utf16le, - stream_name_utf16le_nbytes, - default_ignore_case)) - { - if (idx_ret) - *idx_ret = i; - result = &inode->i_ads_entries[i]; - break; - } - } while (++i != inode->i_num_ads); - #if !TCHAR_IS_UTF16LE - FREE(stream_name_utf16le); - #endif - return result; - } -} + } while (++i != inode->i_num_ads); -static int -init_ads_entry(struct wim_ads_entry *ads_entry, const void *name, - size_t name_nbytes, bool is_utf16le) -{ - int ret = 0; - memset(ads_entry, 0, sizeof(*ads_entry)); + tstr_put_utf16le(stream_name_utf16le); - if (is_utf16le) { - utf16lechar *p = MALLOC(name_nbytes + sizeof(utf16lechar)); - if (p == NULL) - return WIMLIB_ERR_NOMEM; - memcpy(p, name, name_nbytes); - p[name_nbytes / 2] = cpu_to_le16(0); - ads_entry->stream_name = p; - ads_entry->stream_name_nbytes = name_nbytes; - } else { - if (name && *(const tchar*)name != T('\0')) { - ret = get_utf16le_string(name, &ads_entry->stream_name, - &ads_entry->stream_name_nbytes); - } - } - return ret; + if (!result) + errno = ENOENT; + return result; } static struct wim_ads_entry * -do_inode_add_ads(struct wim_inode *inode, const void *stream_name, - size_t stream_name_nbytes, bool is_utf16le) +do_inode_add_ads(struct wim_inode *inode, + utf16lechar *stream_name, size_t stream_name_nbytes) { u16 num_ads; struct wim_ads_entry *ads_entries; struct wim_ads_entry *new_entry; - wimlib_assert(stream_name_nbytes != 0); - if (inode->i_num_ads >= 0xfffe) { ERROR("Too many alternate data streams in one inode!"); + errno = EFBIG; return NULL; } num_ads = inode->i_num_ads + 1; @@ -238,8 +210,10 @@ do_inode_add_ads(struct wim_inode *inode, const void *stream_name, inode->i_ads_entries = ads_entries; new_entry = &inode->i_ads_entries[num_ads - 1]; - if (init_ads_entry(new_entry, stream_name, stream_name_nbytes, is_utf16le)) - return NULL; + + memset(new_entry, 0, sizeof(struct wim_ads_entry)); + new_entry->stream_name = stream_name; + new_entry->stream_name_nbytes = stream_name_nbytes; new_entry->stream_id = inode->i_next_stream_id++; inode->i_num_ads = num_ads; return new_entry; @@ -247,49 +221,67 @@ do_inode_add_ads(struct wim_inode *inode, const void *stream_name, struct wim_ads_entry * inode_add_ads_utf16le(struct wim_inode *inode, - const utf16lechar *stream_name, - size_t stream_name_nbytes) + const utf16lechar *stream_name, size_t stream_name_nbytes) { - DEBUG("Add alternate data stream \"%"WS"\"", stream_name); - return do_inode_add_ads(inode, stream_name, stream_name_nbytes, true); + utf16lechar *dup = NULL; + struct wim_ads_entry *result; + + if (stream_name_nbytes) { + dup = utf16le_dupz(stream_name, stream_name_nbytes); + if (!dup) + return NULL; + } + + result = do_inode_add_ads(inode, dup, stream_name_nbytes); + if (!result) + FREE(dup); + return result; } /* * Add an alternate stream entry to a WIM inode. On success, returns a pointer - * to the new entry; on failure, returns NULL. - * - * @stream_name must be a nonempty string. + * to the new entry; on failure, returns NULL and sets errno. */ struct wim_ads_entry * inode_add_ads(struct wim_inode *inode, const tchar *stream_name) { - DEBUG("Add alternate data stream \"%"TS"\"", stream_name); - return do_inode_add_ads(inode, stream_name, - tstrlen(stream_name) * sizeof(tchar), - TCHAR_IS_UTF16LE); + utf16lechar *stream_name_utf16le = NULL; + size_t stream_name_utf16le_nbytes = 0; + struct wim_ads_entry *result; + + if (stream_name && *stream_name) + if (tstr_to_utf16le(stream_name, + tstrlen(stream_name) * sizeof(tchar), + &stream_name_utf16le, + &stream_name_utf16le_nbytes)) + return NULL; + + result = do_inode_add_ads(inode, stream_name_utf16le, + stream_name_utf16le_nbytes); + if (!result) + FREE(stream_name_utf16le); + return result; } -int +struct wim_ads_entry * inode_add_ads_with_data(struct wim_inode *inode, const tchar *name, const void *value, size_t size, struct wim_lookup_table *lookup_table) { - struct wim_ads_entry *new_ads_entry; + struct wim_ads_entry *new_entry; wimlib_assert(inode->i_resolved); - new_ads_entry = inode_add_ads(inode, name); - if (new_ads_entry == NULL) - return WIMLIB_ERR_NOMEM; + new_entry = inode_add_ads(inode, name); + if (!new_entry) + return NULL; - new_ads_entry->lte = new_stream_from_data_buffer(value, size, - lookup_table); - if (new_ads_entry->lte == NULL) { - inode_remove_ads(inode, new_ads_entry - inode->i_ads_entries, - lookup_table); - return WIMLIB_ERR_NOMEM; + new_entry->lte = new_stream_from_data_buffer(value, size, lookup_table); + if (!new_entry->lte) { + inode_remove_ads(inode, new_entry, lookup_table); + return NULL; } - return 0; + return new_entry; } bool @@ -307,33 +299,29 @@ int inode_set_unnamed_stream(struct wim_inode *inode, const void *data, size_t len, struct wim_lookup_table *lookup_table) { + wimlib_assert(inode->i_resolved); inode->i_lte = new_stream_from_data_buffer(data, len, lookup_table); if (inode->i_lte == NULL) return WIMLIB_ERR_NOMEM; - inode->i_resolved = 1; return 0; } /* Remove an alternate data stream from a WIM inode */ void -inode_remove_ads(struct wim_inode *inode, u16 idx, +inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry, struct wim_lookup_table *lookup_table) { - struct wim_ads_entry *ads_entry; struct wim_lookup_table_entry *lte; + unsigned idx = entry - inode->i_ads_entries; wimlib_assert(idx < inode->i_num_ads); wimlib_assert(inode->i_resolved); - ads_entry = &inode->i_ads_entries[idx]; - - DEBUG("Remove alternate data stream \"%"WS"\"", ads_entry->stream_name); - - lte = ads_entry->lte; + lte = entry->lte; if (lte) lte_decrement_refcnt(lte, lookup_table); - destroy_ads_entry(ads_entry); + destroy_ads_entry(entry); memmove(&inode->i_ads_entries[idx], &inode->i_ads_entries[idx + 1], @@ -341,87 +329,6 @@ inode_remove_ads(struct wim_inode *inode, u16 idx, inode->i_num_ads--; } -bool -inode_has_unix_data(const struct wim_inode *inode) -{ - for (u16 i = 0; i < inode->i_num_ads; i++) - if (ads_entry_is_unix_data(&inode->i_ads_entries[i])) - return true; - return false; -} - -#ifndef __WIN32__ -int -inode_get_unix_data(const struct wim_inode *inode, - struct wimlib_unix_data *unix_data, - u16 *stream_idx_ret) -{ - const struct wim_ads_entry *ads_entry; - const struct wim_lookup_table_entry *lte; - size_t size; - int ret; - - wimlib_assert(inode->i_resolved); - - ads_entry = inode_get_ads_entry((struct wim_inode*)inode, - WIMLIB_UNIX_DATA_TAG, NULL); - if (ads_entry == NULL) - return NO_UNIX_DATA; - - if (stream_idx_ret) - *stream_idx_ret = ads_entry - inode->i_ads_entries; - - lte = ads_entry->lte; - if (lte == NULL) - return NO_UNIX_DATA; - - size = lte->size; - if (size != sizeof(struct wimlib_unix_data)) - return BAD_UNIX_DATA; - - ret = read_full_stream_into_buf(lte, unix_data); - if (ret) - return ret; - - if (unix_data->version != 0) - return BAD_UNIX_DATA; - return 0; -} - -int -inode_set_unix_data(struct wim_inode *inode, u16 uid, u16 gid, u16 mode, - struct wim_lookup_table *lookup_table, int which) -{ - struct wimlib_unix_data unix_data; - int ret; - bool have_good_unix_data = false; - bool have_unix_data = false; - u16 stream_idx; - - if (!(which & UNIX_DATA_CREATE)) { - ret = inode_get_unix_data(inode, &unix_data, &stream_idx); - if (ret == 0 || ret == BAD_UNIX_DATA || ret > 0) - have_unix_data = true; - if (ret == 0) - have_good_unix_data = true; - } - unix_data.version = 0; - if (which & UNIX_DATA_UID || !have_good_unix_data) - unix_data.uid = uid; - if (which & UNIX_DATA_GID || !have_good_unix_data) - unix_data.gid = gid; - if (which & UNIX_DATA_MODE || !have_good_unix_data) - unix_data.mode = mode; - ret = inode_add_ads_with_data(inode, WIMLIB_UNIX_DATA_TAG, - &unix_data, - sizeof(struct wimlib_unix_data), - lookup_table); - if (ret == 0 && have_unix_data) - inode_remove_ads(inode, stream_idx, lookup_table); - return ret; -} -#endif /* __WIN32__ */ - /* * Resolve an inode's lookup table entries. * @@ -657,8 +564,9 @@ stream_not_found_error(const struct wim_inode *inode, const u8 *hash) * Inode to load the alternate data streams into. @inode->i_num_ads must * have been set to the number of alternate data streams that are expected. * - * @remaining_size: + * @nbytes_remaining_p: * Number of bytes of data remaining in the buffer pointed to by @p. + * On success this will be updated to point just past the ADS entries. * * On success, inode->i_ads_entries is set to an array of `struct * wim_ads_entry's of length inode->i_num_ads. On failure, @inode is not @@ -671,8 +579,9 @@ stream_not_found_error(const struct wim_inode *inode, const u8 *hash) */ int read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, - size_t nbytes_remaining) + size_t *nbytes_remaining_p) { + size_t nbytes_remaining = *nbytes_remaining_p; u16 num_ads; struct wim_ads_entry *ads_entries; int ret; @@ -737,14 +646,10 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, cur_entry->stream_name_nbytes > length) goto out_invalid; - cur_entry->stream_name = MALLOC(cur_entry->stream_name_nbytes + 2); + cur_entry->stream_name = utf16le_dupz(disk_entry->stream_name, + cur_entry->stream_name_nbytes); if (cur_entry->stream_name == NULL) goto out_of_memory; - - memcpy(cur_entry->stream_name, - disk_entry->stream_name, - cur_entry->stream_name_nbytes); - cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = cpu_to_le16(0); } else { /* Mark inode as having weird stream entries. */ inode->i_canonical_streams = 0; @@ -758,7 +663,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, * that less than @length is actually remaining in the metadata * resource. We should set the remaining bytes to 0 if this * happens. */ - length = (length + 7) & ~(u64)7; + length = (length + 7) & ~7; p += length; if (nbytes_remaining < length) nbytes_remaining = 0; @@ -767,6 +672,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, } inode->i_ads_entries = ads_entries; inode->i_next_stream_id = inode->i_num_ads + 1; + *nbytes_remaining_p = nbytes_remaining; ret = 0; goto out; out_of_memory: @@ -798,8 +704,6 @@ out: int verify_inode(struct wim_inode *inode, const struct wim_security_data *sd) { - struct wim_dentry *dentry; - /* Check the security ID. -1 is valid and means "no security * descriptor". Anything else has to be a valid index into the WIM * image's security descriptors table. */ @@ -839,6 +743,20 @@ inode_ref_streams(struct wim_inode *inode) } } +void +inode_unref_streams(struct wim_inode *inode, + struct wim_lookup_table *lookup_table) +{ + struct wim_lookup_table_entry *lte; + unsigned i; + + for (i = 0; i <= inode->i_num_ads; i++) { + lte = inode_stream_lte(inode, i, lookup_table); + if (lte) + lte_decrement_refcnt(lte, lookup_table); + } +} + int init_inode_table(struct wim_inode_table *table, size_t capacity) {