]> wimlib.net Git - wimlib/blobdiff - src/inode.c
Update mount implementation
[wimlib] / src / inode.c
index e2f291631a043048273daf47fd1a958dc4209a2e..ae971d8343da5bc239aec20cbf9401546b27efc2 100644 (file)
@@ -39,6 +39,8 @@
 #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)
@@ -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.
  *
@@ -737,14 +644,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;