#include "wimlib/security.h"
#include "wimlib/timestamp.h"
+#include <errno.h>
+
/* Allocate a new inode. Set the timestamps to the current time. */
struct wim_inode *
new_inode(void)
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))
*
* 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;
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;
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
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],
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.
*
* 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
*/
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;
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;
* 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;
}
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:
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. */
inode_first_full_path(inode), num_unnamed_streams);
}
- /* Files cannot have multiple DOS names, even if they have multiple
- * names in multiple directories (i.e. hard links).
- * Source: NTFS-3g authors. */
- struct wim_dentry *dentry_with_dos_name = NULL;
- inode_for_each_dentry(dentry, inode) {
- if (dentry_has_short_name(dentry)) {
- if (dentry_with_dos_name) {
- /* This was previously an error, but if we
- * capture a WIM from UDF on Windows, hard links
- * are supported but DOS names are automatically
- * generated for all names for an inode. */
- #if 0
- ERROR("Hard-linked file has a DOS name at "
- "both `%"TS"' and `%"TS"'",
- dentry_full_path(dentry_with_dos_name),
- dentry_full_path(dentry));
- return WIMLIB_ERR_INVALID_METADATA_RESOURCE;
- #else
- dentry->dos_name_invalid = 1;
- #endif
- }
- dentry_with_dos_name = dentry;
- }
- }
return 0;
}
}
}
+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)
{