]> wimlib.net Git - wimlib/blobdiff - src/win32.c
win32_get_short_name(): Add missing FindClose
[wimlib] / src / win32.c
index b10a4058ab05d2fb654bcbdff72260590d6f52a8..c36b13ae8593d106080d34915ed8b712c4b9764a 100644 (file)
@@ -46,6 +46,7 @@
 
 #define MAX_GET_SD_ACCESS_DENIED_WARNINGS 1
 #define MAX_GET_SACL_PRIV_NOTHELD_WARNINGS 1
+#define MAX_CREATE_HARD_LINK_WARNINGS 5
 struct win32_capture_state {
        unsigned long num_get_sd_access_denied;
        unsigned long num_get_sacl_priv_notheld;
@@ -393,22 +394,31 @@ static int
 win32_get_short_name(struct wim_dentry *dentry, const wchar_t *path)
 {
        WIN32_FIND_DATAW dat;
-       if (FindFirstFileW(path, &dat) && dat.cAlternateFileName[0] != L'\0') {
-               DEBUG("\"%ls\": short name \"%ls\"", path, dat.cAlternateFileName);
-               size_t short_name_nbytes = wcslen(dat.cAlternateFileName) *
-                                          sizeof(wchar_t);
-               size_t n = short_name_nbytes + sizeof(wchar_t);
-               dentry->short_name = MALLOC(n);
-               if (!dentry->short_name)
-                       return WIMLIB_ERR_NOMEM;
-               memcpy(dentry->short_name, dat.cAlternateFileName, n);
-               dentry->short_name_nbytes = short_name_nbytes;
-       }
+       HANDLE hFind;
+       int ret = 0;
+
        /* If we can't read the short filename for some reason, we just ignore
         * the error and assume the file has no short name.  I don't think this
         * should be an issue, since the short names are essentially obsolete
         * anyway. */
-       return 0;
+       hFind = FindFirstFileW(path, &dat);
+       if (hFind != INVALID_HANDLE_VALUE) {
+               if (dat.cAlternateFileName[0] != L'\0') {
+                       DEBUG("\"%ls\": short name \"%ls\"", path, dat.cAlternateFileName);
+                       size_t short_name_nbytes = wcslen(dat.cAlternateFileName) *
+                                                  sizeof(wchar_t);
+                       size_t n = short_name_nbytes + sizeof(wchar_t);
+                       dentry->short_name = MALLOC(n);
+                       if (dentry->short_name) {
+                               memcpy(dentry->short_name, dat.cAlternateFileName, n);
+                               dentry->short_name_nbytes = short_name_nbytes;
+                       } else {
+                               ret = WIMLIB_ERR_NOMEM;
+                       }
+               }
+               FindClose(hFind);
+       }
+       return ret;
 }
 
 static int
@@ -743,18 +753,11 @@ win32_do_capture_rpfix(char *rpbuf, DWORD *rpbuflen_p,
 
 /* Load a reparse point into a WIM inode.  It is just stored in memory.
  *
- * @hFile:  Open handle to a reparse point, with permission to read the reparse
- *          data.
- *
- * @inode:  WIM inode for the reparse point.
+ * @hFile is the open handle to a reparse point, with permission to read the
+ * reparse data.
  *
- * @lookup_table:  Stream lookup table for the WIM; an entry will be added to it
- *                 for the reparse point unless an entry already exists for
- *                 the exact same data stream.
- *
- * @path:  External path to the reparse point.  Used for error messages only.
- *
- * Returns 0 on success; nonzero on failure. */
+ * @inode is the WIM inode for the reparse point.
+ */
 static int
 win32_capture_reparse_point(struct wim_dentry **root_p,
                            HANDLE hFile,
@@ -809,8 +812,8 @@ win32_capture_reparse_point(struct wim_dentry **root_p,
                        inode->i_not_rpfixed = 0;
                }
        }
-       return inode_add_ads_with_data(inode, L"", reparse_point_buf + 8,
-                                      bytesReturned - 8, params->lookup_table);
+       return inode_set_unnamed_stream(inode, reparse_point_buf + 8,
+                                       bytesReturned - 8, params->lookup_table);
 }
 
 /* Scans an unnamed or named stream of a Win32 file (not a reparse point
@@ -882,6 +885,12 @@ win32_capture_stream(const wchar_t *path,
                }
        }
 
+       /* If zero length stream, no lookup table entry needed. */
+       if ((u64)dat->StreamSize.QuadPart == 0) {
+               ret = 0;
+               goto out;
+       }
+
        /* Create a UTF-16LE string @spath that gives the filename, then a
         * colon, then the stream name.  Or, if it's an unnamed stream, just the
         * filename.  It is MALLOC()'ed so that it can be saved in the
@@ -1768,7 +1777,7 @@ win32_extract_streams(const struct wim_inode *inode,
                                   vol_flags);
        if (ret)
                goto out;
-       if (unnamed_lte)
+       if (unnamed_lte && inode->i_extracted_file == NULL)
                *completed_bytes_p += wim_resource_size(unnamed_lte);
 
        if (!(vol_flags & FILE_NAMED_STREAMS))
@@ -1790,7 +1799,7 @@ win32_extract_streams(const struct wim_inode *inode,
                                                   vol_flags);
                        if (ret)
                                break;
-                       if (ads_entry->lte)
+                       if (ads_entry->lte && inode->i_extracted_file == NULL)
                                *completed_bytes_p += wim_resource_size(ads_entry->lte);
                }
        }
@@ -1865,11 +1874,31 @@ win32_do_apply_dentry(const wchar_t *output_path,
                        win32_error(err);
                        return WIMLIB_ERR_LINK;
                } else {
-                       WARNING("Can't create hard link \"%ls => %ls\":\n"
-                               "          Volume does not support hard links!\n"
-                               "          Falling back to extracting a copy of the file.");
+                       args->num_hard_links_failed++;
+                       if (args->num_hard_links_failed < MAX_CREATE_HARD_LINK_WARNINGS) {
+                               WARNING("Can't create hard link \"%ls => %ls\":\n"
+                                       "          Volume does not support hard links!\n"
+                                       "          Falling back to extracting a copy of the file.",
+                                       output_path, inode->i_extracted_file);
+                       } else if (args->num_hard_links_failed == MAX_CREATE_HARD_LINK_WARNINGS) {
+                               WARNING("Suppressing further hard linking warnings...");
+                       }
                }
        }
+
+       if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT &&
+           !(args->vol_flags & FILE_SUPPORTS_REPARSE_POINTS))
+       {
+               WARNING("Skipping extraction of reparse point \"%ls\":\n"
+                       "          Not supported by destination filesystem",
+                       output_path);
+               struct wim_lookup_table_entry *lte;
+               lte = inode_unnamed_lte_resolved(inode);
+               if (lte)
+                       args->progress.extract.completed_bytes += wim_resource_size(lte);
+               return 0;
+       }
+
        /* Create the file, directory, or reparse point, and extract the
         * data streams. */
        ret = win32_extract_streams(inode, output_path,
@@ -1908,6 +1937,19 @@ win32_do_apply_dentry_timestamps(const wchar_t *path,
        HANDLE h;
        const struct wim_inode *inode = dentry->d_inode;
 
+       if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT &&
+           !(args->vol_flags & FILE_SUPPORTS_REPARSE_POINTS))
+       {
+               /* Skip reparse points not extracted */
+               return 0;
+       }
+
+       /* Windows doesn't let you change the timestamps of the root directory
+        * (at least on FAT, which is dumb but expected since FAT doesn't store
+        * any metadata about the root directory...) */
+       if (path_is_root_of_drive(path))
+               return 0;
+
        DEBUG("Opening \"%ls\" to set timestamps", path);
        h = win32_open_existing_file(path, FILE_WRITE_ATTRIBUTES);
        if (h == INVALID_HANDLE_VALUE) {