]> wimlib.net Git - wimlib/blobdiff - src/win32.c
Win32: Do not hard link files with nNumberOfLinks = 1
[wimlib] / src / win32.c
index 10f28b3d91280106d4955526f30bc8b10ddf0203..0db8c3bf72583dcbe6e9c4091996dd5eac7745ce 100644 (file)
@@ -394,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
@@ -876,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
@@ -1058,6 +1073,7 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
        DWORD err;
        u64 file_size;
        int ret = 0;
+       const wchar_t *basename;
 
        if (exclude_path(path, path_num_chars, params->config, true)) {
                if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
@@ -1105,15 +1121,31 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                goto out_close_handle;
        }
 
-       /* Create a WIM dentry with an associated inode, which may be shared */
-       ret = inode_table_new_dentry(params->inode_table,
-                                    path_basename_with_len(path, path_num_chars),
-                                    ((u64)file_info.nFileIndexHigh << 32) |
-                                        (u64)file_info.nFileIndexLow,
-                                    file_info.dwVolumeSerialNumber,
-                                    &root);
-       if (ret)
-               goto out_close_handle;
+       /* Create a WIM dentry with an associated inode, which may be shared.
+        *
+        * However, we need to explicitly check for directories and files with
+        * only 1 link and refuse to hard link them.  This is because Windows
+        * has a bug where it can return duplicate File IDs for files and
+        * directories on the FAT filesystem. */
+       basename = path_basename_with_len(path, path_num_chars);
+       if (!(file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+           && file_info.nNumberOfLinks > 1)
+       {
+               ret = inode_table_new_dentry(params->inode_table,
+                                            basename,
+                                            ((u64)file_info.nFileIndexHigh << 32) |
+                                                (u64)file_info.nFileIndexLow,
+                                            file_info.dwVolumeSerialNumber,
+                                            &root);
+               if (ret)
+                       goto out_close_handle;
+       } else {
+               ret = new_dentry_with_inode(basename, &root);
+               if (ret)
+                       goto out_close_handle;
+               list_add_tail(&root->d_inode->i_list, &params->inode_table->extra_inodes);
+       }
+
 
        ret = win32_get_short_name(root, path);
        if (ret)