*/
/*
- * 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
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;
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);
}
{
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++;
}
wimlib_assert(inode->i_nlink > 0);
- list_del(&dentry->d_alias);
+ hlist_del(&dentry->d_alias_node);
dentry->d_inode = NULL;
inode->i_nlink--;
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.
*
{
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;
}
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++;
}
/*
- * 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
* 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--;
}
*
* 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
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)) {
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)
{
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)
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,
{
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;
{
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;
/*
* 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;