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
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) {
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, ¶ms->inode_table->extra_inodes);
+ }
+
ret = win32_get_short_name(root, path);
if (ret)