]> wimlib.net Git - wimlib/blobdiff - src/dentry.c
Update progress functions
[wimlib] / src / dentry.c
index 3396d16972ee97a37875f038fb28fa8dd058a52a..42bc05ea58df5da6791fe5880f70633ea15b13fe 100644 (file)
@@ -81,9 +81,14 @@ struct wim_dentry_on_disk {
        le64 subdir_offset;
 
        /* Reserved fields */
-       le64 unused_1;
-       le64 unused_2;
-
+       /* As an extension, wimlib can store UNIX data here.  */
+       union {
+               struct {
+                       le64 unused_1;
+                       le64 unused_2;
+               };
+               struct wimlib_unix_data_disk unix_data;
+       };
 
        /* Creation time, last access time, and last write time, in
         * 100-nanosecond intervals since 12:00 a.m UTC January 1, 1601.  They
@@ -214,60 +219,59 @@ dentry_correct_length_aligned(const struct wim_dentry *dentry)
        return (len + 7) & ~7;
 }
 
-static int
-dentry_clear_short_name(struct wim_dentry *dentry)
+static void
+do_dentry_set_name(struct wim_dentry *dentry, utf16lechar *file_name,
+                  size_t file_name_nbytes)
 {
+       FREE(dentry->file_name);
+       dentry->file_name = file_name;
+       dentry->file_name_nbytes = file_name_nbytes;
+
        if (dentry_has_short_name(dentry)) {
                FREE(dentry->short_name);
                dentry->short_name = NULL;
                dentry->short_name_nbytes = 0;
        }
-       return 0;
 }
 
-/* Sets the name of a WIM dentry from a multibyte string.
+/* Sets the name of a WIM dentry from a UTF-16LE string.
  * Only use this on dentries not inserted into the tree.  Use rename_wim_path()
  * to do a real rename.  */
 int
-dentry_set_name(struct wim_dentry *dentry, const tchar *new_name)
+dentry_set_name_utf16le(struct wim_dentry *dentry, const utf16lechar *name,
+                       size_t name_nbytes)
 {
-       int ret;
-
-       ret = get_utf16le_string(new_name, &dentry->file_name,
-                                &dentry->file_name_nbytes);
-       if (ret)
-               return ret;
+       utf16lechar *dup = NULL;
 
-       return dentry_clear_short_name(dentry);
+       if (name_nbytes) {
+               dup = utf16le_dupz(name, name_nbytes);
+               if (!dup)
+                       return WIMLIB_ERR_NOMEM;
+       }
+       do_dentry_set_name(dentry, dup, name_nbytes);
+       return 0;
 }
 
-/* Sets the name of a WIM dentry from a UTF-16LE string.
+
+/* Sets the name of a WIM dentry from a multibyte string.
  * Only use this on dentries not inserted into the tree.  Use rename_wim_path()
  * to do a real rename.  */
 int
-dentry_set_name_utf16le(struct wim_dentry *dentry, const utf16lechar *new_name)
+dentry_set_name(struct wim_dentry *dentry, const tchar *name)
 {
-       utf16lechar *name = NULL;
-       size_t name_nbytes = 0;
-
-       if (new_name && *new_name) {
-               const utf16lechar *tmp;
-
-               tmp = new_name;
-               do {
-                       name_nbytes += sizeof(utf16lechar);
-               } while (*++tmp);
+       utf16lechar *name_utf16le = NULL;
+       size_t name_utf16le_nbytes = 0;
+       int ret;
 
-               name = memdup(new_name, name_nbytes + sizeof(utf16lechar));
-               if (!name)
-                       return WIMLIB_ERR_NOMEM;
+       if (name && *name) {
+               ret = tstr_to_utf16le(name, tstrlen(name) * sizeof(tchar),
+                                     &name_utf16le, &name_utf16le_nbytes);
+               if (ret)
+                       return ret;
        }
 
-       FREE(dentry->file_name);
-       dentry->file_name = name;
-       dentry->file_name_nbytes = name_nbytes;
-
-       return dentry_clear_short_name(dentry);
+       do_dentry_set_name(dentry, name_utf16le, name_utf16le_nbytes);
+       return 0;
 }
 
 /* Returns the total length of a WIM alternate data stream entry on-disk,
@@ -400,74 +404,36 @@ for_dentry_in_tree_depth(struct wim_dentry *root,
 int
 calculate_dentry_full_path(struct wim_dentry *dentry)
 {
-       tchar *full_path;
-       u32 full_path_nbytes;
-       int ret;
+       size_t ulen;
+       size_t dummy;
+       const struct wim_dentry *d;
 
        if (dentry->_full_path)
                return 0;
 
-       if (dentry_is_root(dentry)) {
-               static const tchar _root_path[] = {WIM_PATH_SEPARATOR, T('\0')};
-               full_path = TSTRDUP(_root_path);
-               if (full_path == NULL)
-                       return WIMLIB_ERR_NOMEM;
-               full_path_nbytes = 1 * sizeof(tchar);
-       } else {
-               struct wim_dentry *parent;
-               tchar *parent_full_path;
-               u32 parent_full_path_nbytes;
-               size_t filename_nbytes;
-
-               parent = dentry->parent;
-               if (dentry_is_root(parent)) {
-                       parent_full_path = T("");
-                       parent_full_path_nbytes = 0;
-               } else {
-                       if (parent->_full_path == NULL) {
-                               ret = calculate_dentry_full_path(parent);
-                               if (ret)
-                                       return ret;
-                       }
-                       parent_full_path = parent->_full_path;
-                       parent_full_path_nbytes = parent->full_path_nbytes;
-               }
+       ulen = 0;
+       d = dentry;
+       do {
+               ulen += d->file_name_nbytes / sizeof(utf16lechar);
+               ulen++;
+               d = d->parent;  /* assumes d == d->parent for root  */
+       } while (!dentry_is_root(d));
 
-               /* Append this dentry's name as a tchar string to the full path
-                * of the parent followed by the path separator */
-       #if TCHAR_IS_UTF16LE
-               filename_nbytes = dentry->file_name_nbytes;
-       #else
-               {
-                       int ret = utf16le_to_tstr_nbytes(dentry->file_name,
-                                                        dentry->file_name_nbytes,
-                                                        &filename_nbytes);
-                       if (ret)
-                               return ret;
-               }
-       #endif
+       utf16lechar ubuf[ulen];
+       utf16lechar *p = &ubuf[ulen];
 
-               full_path_nbytes = parent_full_path_nbytes + sizeof(tchar) +
-                                  filename_nbytes;
-               full_path = MALLOC(full_path_nbytes + sizeof(tchar));
-               if (full_path == NULL)
-                       return WIMLIB_ERR_NOMEM;
-               memcpy(full_path, parent_full_path, parent_full_path_nbytes);
-               full_path[parent_full_path_nbytes / sizeof(tchar)] = WIM_PATH_SEPARATOR;
-       #if TCHAR_IS_UTF16LE
-               memcpy(&full_path[parent_full_path_nbytes / sizeof(tchar) + 1],
-                      dentry->file_name,
-                      filename_nbytes + sizeof(tchar));
-       #else
-               utf16le_to_tstr_buf(dentry->file_name,
-                                   dentry->file_name_nbytes,
-                                   &full_path[parent_full_path_nbytes /
-                                              sizeof(tchar) + 1]);
-       #endif
-       }
-       dentry->_full_path = full_path;
-       dentry->full_path_nbytes= full_path_nbytes;
-       return 0;
+       d = dentry;
+       do {
+               p -= d->file_name_nbytes / sizeof(utf16lechar);
+               memcpy(p, d->file_name, d->file_name_nbytes);
+               *--p = cpu_to_le16(WIM_PATH_SEPARATOR);
+               d = d->parent;  /* assumes d == d->parent for root  */
+       } while (!dentry_is_root(d));
+
+       wimlib_assert(p == ubuf);
+
+       return utf16le_to_tstr(ubuf, ulen * sizeof(utf16lechar),
+                              &dentry->_full_path, &dummy);
 }
 
 tchar *
@@ -598,8 +564,8 @@ dir_lookup_ci(const struct wim_inode *dir, const struct wim_dentry *dummy)
 }
 
 /* Given a UTF-16LE filename and a directory, look up the dentry for the file.
- * Return it if found, otherwise NULL.  This is case-sensitive on UNIX and
- * case-insensitive on Windows. */
+ * Return it if found, otherwise NULL.  This has configurable case sensitivity,
+ * and @name need not be null-terminated.  */
 struct wim_dentry *
 get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry,
                                   const utf16lechar *name,
@@ -660,29 +626,22 @@ struct wim_dentry *
 get_dentry_child_with_name(const struct wim_dentry *dentry, const tchar *name,
                           CASE_SENSITIVITY_TYPE case_type)
 {
-#if TCHAR_IS_UTF16LE
-       return get_dentry_child_with_utf16le_name(dentry, name,
-                                                 tstrlen(name) * sizeof(tchar),
-                                                 case_type);
-#else
-       utf16lechar *utf16le_name;
-       size_t utf16le_name_nbytes;
        int ret;
+       const utf16lechar *name_utf16le;
+       size_t name_utf16le_nbytes;
        struct wim_dentry *child;
 
-       ret = tstr_to_utf16le(name, tstrlen(name) * sizeof(tchar),
-                             &utf16le_name, &utf16le_name_nbytes);
-       if (ret) {
-               child = NULL;
-       } else {
-               child = get_dentry_child_with_utf16le_name(dentry,
-                                                          utf16le_name,
-                                                          utf16le_name_nbytes,
-                                                          case_type);
-               FREE(utf16le_name);
-       }
+       ret = tstr_get_utf16le_and_len(name, &name_utf16le,
+                                      &name_utf16le_nbytes);
+       if (ret)
+               return NULL;
+
+       child = get_dentry_child_with_utf16le_name(dentry,
+                                                  name_utf16le,
+                                                  name_utf16le_nbytes,
+                                                  case_type);
+       tstr_put_utf16le(name_utf16le);
        return child;
-#endif
 }
 
 static struct wim_dentry *
@@ -695,7 +654,7 @@ get_dentry_utf16le(WIMStruct *wim, const utf16lechar *path,
        /* Start with the root directory of the image.  Note: this will be NULL
         * if an image has been added directly with wimlib_add_empty_image() but
         * no files have been added yet; in that case we fail with ENOENT.  */
-       cur_dentry = wim_root_dentry(wim);
+       cur_dentry = wim_get_current_root_dentry(wim);
 
        name_start = path;
        for (;;) {
@@ -789,22 +748,16 @@ get_dentry_utf16le(WIMStruct *wim, const utf16lechar *path,
 struct wim_dentry *
 get_dentry(WIMStruct *wim, const tchar *path, CASE_SENSITIVITY_TYPE case_type)
 {
-#if TCHAR_IS_UTF16LE
-       return get_dentry_utf16le(wim, path, case_type);
-#else
-       utf16lechar *path_utf16le;
-       size_t path_utf16le_nbytes;
        int ret;
+       const utf16lechar *path_utf16le;
        struct wim_dentry *dentry;
 
-       ret = tstr_to_utf16le(path, tstrlen(path) * sizeof(tchar),
-                             &path_utf16le, &path_utf16le_nbytes);
+       ret = tstr_get_utf16le(path, &path_utf16le);
        if (ret)
                return NULL;
        dentry = get_dentry_utf16le(wim, path_utf16le, case_type);
-       FREE(path_utf16le);
+       tstr_put_utf16le(path_utf16le);
        return dentry;
-#endif
 }
 
 /* Takes in a path of length @len in @buf, and transforms it into a string for
@@ -1259,6 +1212,12 @@ read_dentry(const u8 * restrict buf, size_t buf_len,
        inode->i_attributes = le32_to_cpu(disk_dentry->attributes);
        inode->i_security_id = le32_to_cpu(disk_dentry->security_id);
        dentry->subdir_offset = le64_to_cpu(disk_dentry->subdir_offset);
+
+       inode->i_unix_data.uid = le32_to_cpu(disk_dentry->unix_data.uid);
+       inode->i_unix_data.gid = le32_to_cpu(disk_dentry->unix_data.gid);
+       inode->i_unix_data.mode = le32_to_cpu(disk_dentry->unix_data.mode);
+       inode->i_unix_data.reserved = le32_to_cpu(disk_dentry->unix_data.reserved);
+
        inode->i_creation_time = le64_to_cpu(disk_dentry->creation_time);
        inode->i_last_access_time = le64_to_cpu(disk_dentry->last_access_time);
        inode->i_last_write_time = le64_to_cpu(disk_dentry->last_write_time);
@@ -1318,29 +1277,27 @@ read_dentry(const u8 * restrict buf, size_t buf_len,
        /* Read the filename if present.  Note: if the filename is empty, there
         * is no null terminator following it.  */
        if (file_name_nbytes) {
-               dentry->file_name = MALLOC(file_name_nbytes + 2);
+               dentry->file_name = utf16le_dupz((const utf16lechar *)p,
+                                                file_name_nbytes);
                if (dentry->file_name == NULL) {
                        ret = WIMLIB_ERR_NOMEM;
                        goto err_free_dentry;
                }
                dentry->file_name_nbytes = file_name_nbytes;
-               memcpy(dentry->file_name, p, file_name_nbytes);
                p += file_name_nbytes + 2;
-               dentry->file_name[file_name_nbytes / 2] = cpu_to_le16(0);
        }
 
        /* Read the short filename if present.  Note: if there is no short
         * filename, there is no null terminator following it. */
        if (short_name_nbytes) {
-               dentry->short_name = MALLOC(short_name_nbytes + 2);
+               dentry->short_name = utf16le_dupz((const utf16lechar *)p,
+                                                 short_name_nbytes);
                if (dentry->short_name == NULL) {
                        ret = WIMLIB_ERR_NOMEM;
                        goto err_free_dentry;
                }
                dentry->short_name_nbytes = short_name_nbytes;
-               memcpy(dentry->short_name, p, short_name_nbytes);
                p += short_name_nbytes + 2;
-               dentry->short_name[short_name_nbytes / 2] = cpu_to_le16(0);
        }
 
        /* Align the dentry length.  */
@@ -1360,9 +1317,6 @@ read_dentry(const u8 * restrict buf, size_t buf_len,
                                            inode,
                                            buf_len - offset - dentry->length)))
                {
-                       ERROR("Failed to read alternate data stream "
-                             "entries of WIM dentry \"%"WS"\"",
-                             dentry->file_name);
                        goto err_free_dentry;
                }
        }
@@ -1375,18 +1329,6 @@ err_free_dentry:
        return ret;
 }
 
-static const tchar *
-dentry_get_file_type_string(const struct wim_dentry *dentry)
-{
-       const struct wim_inode *inode = dentry->d_inode;
-       if (inode_is_directory(inode))
-               return T("directory");
-       else if (inode_is_symlink(inode))
-               return T("symbolic link");
-       else
-               return T("file");
-}
-
 static bool
 dentry_is_dot_or_dotdot(const struct wim_dentry *dentry)
 {
@@ -1465,14 +1407,10 @@ read_dentry_tree_recursive(const u8 * restrict buf, size_t buf_len,
                        /* We already found a dentry with this same
                         * case-sensitive long name.  Only keep the first one.
                         */
-                       const tchar *child_type, *duplicate_type;
-                       child_type = dentry_get_file_type_string(child);
-                       duplicate_type = dentry_get_file_type_string(duplicate);
-                       WARNING("Ignoring duplicate %"TS" \"%"TS"\" "
-                               "(the WIM image already contains a %"TS" "
+                       WARNING("Ignoring duplicate file \"%"TS"\" "
+                               "(the WIM image already contains a file "
                                "at that path with the exact same name)",
-                               child_type, dentry_full_path(duplicate),
-                               duplicate_type);
+                               dentry_full_path(duplicate));
                        free_dentry(child);
                        continue;
                }
@@ -1628,8 +1566,14 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
        disk_dentry->attributes = cpu_to_le32(inode->i_attributes);
        disk_dentry->security_id = cpu_to_le32(inode->i_security_id);
        disk_dentry->subdir_offset = cpu_to_le64(dentry->subdir_offset);
-       disk_dentry->unused_1 = cpu_to_le64(0);
-       disk_dentry->unused_2 = cpu_to_le64(0);
+
+       /* UNIX data uses the two 8-byte reserved fields.  So if no UNIX data
+        * exists, they get set to 0, just as we would do anyway.  */
+       disk_dentry->unix_data.uid = cpu_to_le32(inode->i_unix_data.uid);
+       disk_dentry->unix_data.gid = cpu_to_le32(inode->i_unix_data.gid);
+       disk_dentry->unix_data.mode = cpu_to_le32(inode->i_unix_data.mode);
+       disk_dentry->unix_data.reserved = cpu_to_le32(inode->i_unix_data.reserved);
+
        disk_dentry->creation_time = cpu_to_le64(inode->i_creation_time);
        disk_dentry->last_access_time = cpu_to_le64(inode->i_last_access_time);
        disk_dentry->last_write_time = cpu_to_le64(inode->i_last_write_time);
@@ -1668,11 +1612,6 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
        while ((uintptr_t)p & 7)
                *p++ = 0;
 
-       /* We calculate the correct length of the dentry ourselves because the
-        * dentry->length field may been set to an unexpected value from when we
-        * read the dentry in (for example, there may have been unknown data
-        * appended to the end of the dentry...).  Furthermore, the dentry may
-        * have been renamed, thus changing its needed length. */
        disk_dentry->length = cpu_to_le64(p - orig_p);
 
        if (use_dummy_stream) {