X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Finode.c;h=7699e9bf9d56dc94a82c4de6265b0a036101f2d4;hb=9ba9f3ee7bf1b0e6b211425a6c495f5dddf8c2d0;hp=e6da5095dcfc6ffb320d0aca5a349244b2077ca2;hpb=43a26b833482fc019c7aeee95656b8f2f3077db7;p=wimlib diff --git a/src/inode.c b/src/inode.c index e6da5095..7699e9bf 100644 --- a/src/inode.c +++ b/src/inode.c @@ -8,7 +8,7 @@ */ /* - * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers + * Copyright (C) 2012-2018 Eric Biggers * * This file is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -56,9 +56,9 @@ new_inode(struct wim_dentry *dentry, bool set_timestamps) inode->i_security_id = -1; /*inode->i_nlink = 0;*/ - inode->i_not_rpfixed = 1; - INIT_LIST_HEAD(&inode->i_list); - INIT_LIST_HEAD(&inode->i_dentry); + inode->i_rp_flags = WIM_RP_FLAG_NOT_FIXED; + INIT_HLIST_HEAD(&inode->i_alias_list); + inode->i_streams = inode->i_embedded_streams; if (set_timestamps) { u64 now = now_as_wim_timestamp(); inode->i_creation_time = now; @@ -85,10 +85,8 @@ free_inode(struct wim_inode *inode) FREE(inode->i_streams); 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)) - hlist_del(&inode->i_hlist); + if (!hlist_unhashed(&inode->i_hlist_node)) + hlist_del(&inode->i_hlist_node); FREE(inode); } @@ -110,7 +108,7 @@ d_associate(struct wim_dentry *dentry, struct wim_inode *inode) { wimlib_assert(!dentry->d_inode); - list_add_tail(&dentry->d_alias, &inode->i_dentry); + hlist_add_head(&dentry->d_alias_node, &inode->i_alias_list); dentry->d_inode = inode; inode->i_nlink++; } @@ -127,7 +125,7 @@ d_disassociate(struct wim_dentry *dentry) wimlib_assert(inode->i_nlink > 0); - list_del(&dentry->d_alias); + hlist_del(&dentry->d_alias_node); dentry->d_inode = NULL; inode->i_nlink--; @@ -201,6 +199,52 @@ inode_get_unnamed_stream(const struct wim_inode *inode, int stream_type) return NULL; } + +static void +inode_set_stream_blob(struct wim_inode *inode, struct wim_inode_stream *strm, + struct blob_descriptor *new_blob) +{ + strm->_stream_blob = new_blob; + strm->stream_resolved = 1; + if (new_blob) + new_blob->refcnt += inode->i_nlink; +} + +static void +inode_unset_stream_blob(struct wim_inode *inode, struct wim_inode_stream *strm, + struct blob_table *blob_table) +{ + struct blob_descriptor *old_blob; + + old_blob = stream_blob(strm, blob_table); + if (old_blob) + blob_subtract_refcnt(old_blob, blob_table, inode->i_nlink); + strm->_stream_blob = NULL; + strm->stream_resolved = 1; +} + +/* + * Replace the blob associated with the specified stream. + * + * @inode + * The inode containing @strm + * @strm + * The stream whose data needs to be replaced + * @new_blob + * The new blob descriptor to assign + * @blob_table + * Pointer to the blob table in which data blobs are being indexed + */ +void +inode_replace_stream_blob(struct wim_inode *inode, + struct wim_inode_stream *strm, + struct blob_descriptor *new_blob, + struct blob_table *blob_table) +{ + inode_unset_stream_blob(inode, strm, blob_table); + inode_set_stream_blob(inode, strm, new_blob); +} + /* * Add a new stream to the specified inode. * @@ -223,7 +267,7 @@ inode_add_stream(struct wim_inode *inode, int stream_type, { if (inode->i_num_streams >= 0xFFFF) { ERROR("Inode has too many streams! Path=\"%"TS"\"", - inode_first_full_path(inode)); + inode_any_full_path(inode)); errno = EFBIG; return NULL; } @@ -266,9 +310,10 @@ inode_add_stream(struct wim_inode *inode, int stream_type, if (!new_strm->stream_name) return NULL; } + new_strm->stream_id = inode->i_next_stream_id++; - stream_set_blob(new_strm, blob); + inode_set_stream_blob(inode, new_strm, blob); inode->i_num_streams++; @@ -276,10 +321,41 @@ inode_add_stream(struct wim_inode *inode, int stream_type, } /* - * Create a new blob descriptor for the specified data buffer or use an existing - * blob descriptor in @blob_table for an identical blob, then add a stream of - * the specified type and name to the specified inode and set it to initially - * reference the blob. + * Replace the data of the specified stream. + * + * @inode + * The inode containing @strm + * @strm + * The stream whose data needs to be replaced + * @data + * The buffer of data to assign to the stream + * @size + * Size of the @data buffer, in bytes + * @blob_table + * Pointer to the blob table in which data blobs are being indexed + * + * Returns true if successful; false with errno set if unsuccessful. + */ +bool +inode_replace_stream_data(struct wim_inode *inode, + struct wim_inode_stream *strm, + const void *data, size_t size, + struct blob_table *blob_table) +{ + struct blob_descriptor *new_blob = NULL; + + if (size) { + new_blob = new_blob_from_data_buffer(data, size, blob_table); + if (!new_blob) + return false; + } + + inode_replace_stream_blob(inode, strm, new_blob, blob_table); + return true; +} + +/* + * Add a new stream to the specified inode and assign it the specified data. * * @inode * The inode to which to add the stream @@ -289,54 +365,57 @@ inode_add_stream(struct wim_inode *inode, int stream_type, * The name of the stream being added as a null-terminated UTF-16LE string, * or NO_STREAM_NAME if the stream is unnamed * @data - * The uncompressed data of the blob + * The buffer of data to assign to the new stream * @size - * The size, in bytes, of the blob data + * Size of the @data buffer, in bytes * @blob_table - * Pointer to the blob table in which the blob needs to be indexed. + * Pointer to the blob table in which data blobs are being indexed * - * Returns a pointer to the new stream if successfully added, otherwise NULL - * with errno set. + * Returns true if successful; false with errno set if unsuccessful. */ -struct wim_inode_stream * +bool inode_add_stream_with_data(struct wim_inode *inode, int stream_type, const utf16lechar *stream_name, const void *data, size_t size, struct blob_table *blob_table) { - struct blob_descriptor *blob; struct wim_inode_stream *strm; + struct blob_descriptor *blob = NULL; - blob = new_blob_from_data_buffer(data, size, blob_table); - if (!blob) - return NULL; - strm = inode_add_stream(inode, stream_type, stream_name, blob); + strm = inode_add_stream(inode, stream_type, stream_name, NULL); if (!strm) - blob_decrement_refcnt(blob, blob_table); - return strm; + return false; + + if (size) { + blob = new_blob_from_data_buffer(data, size, blob_table); + if (unlikely(!blob)) { + inode_remove_stream(inode, strm, blob_table); + return false; + } + } + + inode_set_stream_blob(inode, strm, blob); + return true; } /* - * Remove a stream from the specified inode and release the reference to the - * blob descriptor, if any. + * Remove a stream from the specified inode. + * + * This handles releasing the references to the blob descriptor, if any. */ void inode_remove_stream(struct wim_inode *inode, struct wim_inode_stream *strm, struct blob_table *blob_table) { - struct blob_descriptor *blob; unsigned idx = strm - inode->i_streams; wimlib_assert(idx < inode->i_num_streams); - blob = stream_blob(strm, blob_table); - if (blob) - blob_decrement_refcnt(blob, blob_table); + inode_unset_stream_blob(inode, strm, blob_table); destroy_stream(strm); - memmove(&inode->i_streams[idx], - &inode->i_streams[idx + 1], + memmove(strm, strm + 1, (inode->i_num_streams - idx - 1) * sizeof(inode->i_streams[0])); inode->i_num_streams--; } @@ -360,7 +439,7 @@ inode_has_named_data_stream(const struct wim_inode *inode) * * If @force is %false: * If any of the needed blobs do not exist in @table, return - * WIMLIB_ERR_RESOURCE_NOT_FOUND and leave the inode unmodified. + * WIMLIB_ERR_RESOURCE_NOT_FOUND. * If @force is %true: * If any of the needed blobs do not exist in @table, allocate new blob * descriptors for them and insert them into @table. This does not, of @@ -375,14 +454,13 @@ int inode_resolve_streams(struct wim_inode *inode, struct blob_table *table, bool force) { - struct blob_descriptor *blobs[inode->i_num_streams]; - for (unsigned i = 0; i < inode->i_num_streams; i++) { + struct wim_inode_stream *strm = &inode->i_streams[i]; - if (inode->i_streams[i].stream_resolved) + if (strm->stream_resolved) continue; - const u8 *hash = stream_hash(&inode->i_streams[i]); + const u8 *hash = stream_hash(strm); struct blob_descriptor *blob = NULL; if (!is_zero_hash(hash)) { @@ -397,49 +475,31 @@ inode_resolve_streams(struct wim_inode *inode, struct blob_table *table, blob_table_insert(table, blob); } } - blobs[i] = blob; + strm->_stream_blob = blob; + strm->stream_resolved = 1; } - - for (unsigned i = 0; i < inode->i_num_streams; i++) - if (!inode->i_streams[i].stream_resolved) - stream_set_blob(&inode->i_streams[i], blobs[i]); return 0; } -/* Undo the effects of inode_resolve_streams(). */ -void -inode_unresolve_streams(struct wim_inode *inode) -{ - for (unsigned i = 0; i < inode->i_num_streams; i++) { - - if (!inode->i_streams[i].stream_resolved) - continue; - - copy_hash(inode->i_streams[i]._stream_hash, - stream_hash(&inode->i_streams[i])); - inode->i_streams[i].stream_resolved = 0; - } -} - int blob_not_found_error(const struct wim_inode *inode, const u8 *hash) { if (wimlib_print_errors) { - tchar hashstr[SHA1_HASH_SIZE * 2 + 1]; + tchar hashstr[SHA1_HASH_STRING_LEN]; sprint_hash(hash, hashstr); ERROR("\"%"TS"\": blob not found\n" " SHA-1 message digest of missing blob:\n" " %"TS"", - inode_first_full_path(inode), hashstr); + inode_any_full_path(inode), hashstr); } return WIMLIB_ERR_RESOURCE_NOT_FOUND; } /* - * Return the blob descriptor for the specified stream, or NULL if the blob for - * the stream is empty or not available. + * Return the blob descriptor for the specified stream, or NULL if the stream is + * empty or its blob is not available in @table. */ struct blob_descriptor * stream_blob(const struct wim_inode_stream *strm, const struct blob_table *table) @@ -450,22 +510,32 @@ stream_blob(const struct wim_inode_stream *strm, const struct blob_table *table) return lookup_blob(table, strm->_stream_hash); } -/* Return the SHA-1 message digest of the data of the specified stream, or a - * void SHA-1 of all zeroes if the specified stream is empty. */ +/* + * Return the SHA-1 message digest of the data of the specified stream, or a + * void SHA-1 of all zeroes if the specified stream is empty, or NULL if the + * specified stream is unhashed. (Most callers ensure the stream cannot be + * unhashed.) + */ const u8 * stream_hash(const struct wim_inode_stream *strm) { - if (strm->stream_resolved) - return strm->_stream_blob ? strm->_stream_blob->hash : zero_hash; - else + if (!strm->stream_resolved) return strm->_stream_hash; + + if (!strm->_stream_blob) + return zero_hash; + + if (strm->_stream_blob->unhashed) + return NULL; + + return strm->_stream_blob->hash; } /* * Return the blob descriptor for the unnamed data stream of the inode, or NULL - * if the inode does not have an unnamed data stream, the blob for the inode's - * unnamed data stream is empty, or the blob for the inode's unnamed data stream - * is not available in @blob_table. + * if the inode does not have an unnamed data stream, the inode's unnamed data + * stream is empty, or the blob for the inode's unnamed data stream is not + * available in @blob_table. */ struct blob_descriptor * inode_get_blob_for_unnamed_data_stream(const struct wim_inode *inode, @@ -473,7 +543,7 @@ inode_get_blob_for_unnamed_data_stream(const struct wim_inode *inode, { const struct wim_inode_stream *strm; - strm = inode_get_unnamed_stream(inode, STREAM_TYPE_DATA); + strm = inode_get_unnamed_data_stream(inode); if (!strm) return NULL; @@ -487,7 +557,7 @@ inode_get_blob_for_unnamed_data_stream_resolved(const struct wim_inode *inode) { const struct wim_inode_stream *strm; - strm = inode_get_unnamed_stream(inode, STREAM_TYPE_DATA); + strm = inode_get_unnamed_data_stream(inode); if (!strm) return NULL; @@ -497,14 +567,16 @@ inode_get_blob_for_unnamed_data_stream_resolved(const struct wim_inode *inode) /* * Return the SHA-1 message digest of the unnamed data stream of the inode, or a * void SHA-1 of all zeroes if the inode does not have an unnamed data stream or - * if the inode's unnamed data stream is empty. + * if the inode's unnamed data stream is empty, or NULL if the inode's unnamed + * data stream is unhashed. (Most callers ensure the stream cannot be + * unhashed.) */ const u8 * inode_get_hash_of_unnamed_data_stream(const struct wim_inode *inode) { const struct wim_inode_stream *strm; - strm = inode_get_unnamed_stream(inode, STREAM_TYPE_DATA); + strm = inode_get_unnamed_data_stream(inode); if (!strm) return zero_hash;