wimlib incompatibility with dism when some reparse points are present?
Posted: Thu Feb 20, 2025 8:09 pm
Summary:
I think wimlib has a bug when capturing a symlink with a path starting with \\?\. These seem like valid paths that don't involve the edge cases listed in the wimlib documentation for limitations when capturing from a unix block device (dism doesn't appear to dereference or fix them up either). The wim files created by wimlib-imagex capture when these symlinks are present are unreadable by dism.
Background:
I have used wimlib in the past to capture sysprepped windows systems (win10 and win11) and then later use Dism in WinPE to apply those WIM images to new systems, but I noticed that if I have installed Office in the source system before capturing the WIM with wimlib, dism fails to apply the WIM with the error:
(Full DISM log attached)
I notice that is dying on this specific file:
C:\Program Files\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\C2R32.dll
That file looks like this when running dir /a against it in windows:
(There are several symlinks to this same file in various places within the Office install directory).
I decided to try to create a minimal reproduction:
New NTFS volume
Create X:\Temp
Create X:\Temp\test.txt with a little bit of text data
Create symlink X:\Templink -> X:\Temp (mklink X:\templink X:\temp)
Create symlink X:\temp\testlink.txt -> test.txt (pushd X:\temp; mklink testlink.txt test.txt)
Create symlink X:\temp\testlink2.txt -> X:\temp\test.txt (pushd X:\temp; mklink testlink2.txt X:\temp\test.txt)
Create symlink X:\temp\testlink3.txt -> \\?\X:\temp\test.txt (pushd X:\temp; mklink testlink3.txt \\?\X:\temp\test.txt)
I also tested that all these links 'work' (reading them reads the contents of the target file)
(no other files on this volume at all, other than system volume information)
And then booted to a linux environment, and captured these using "wimlib-imagex capture /dev/sda4 /mnt/share/file.wim". There are no warnings during the capture, but I get the same error 4392 when trying to apply this minimal WIM to a new empty NTFS partition with dism /apply-image.
I have read through the documentation on wimlib's limitations around reparse points, and found another thread regarding how reparse points are further limited when capturing from a block device using the ntfs-3g library, but it doesn't sound like any of those limitations apply to this case.
From the microsoft docs, it appears that the point of the \\?\ prefix is to disable string expansion and allow use of otherwise restricted characters, or to bypass path length restrictions, so I don't know why using it would be incompatible with the way wimlib stores reparse points/symlinks when doing a block device capture.
Also since I can replicate it with a very simple mklink command that only differs from a working one by the use of the \\?\ prefix, I don't think this is related to dedupe or other weirdness inherent to the Office 365 Click-to-Run app itself.
So, is this a wimlib bug, or an inherent limitation of ntfs-3g, or something else? I could provide a WIM file created from this minimal partition created with wimlib and with dism, if it would help. All my testing was done with wimlib 1.14.4 compiled locally on ubuntu 24.04.
I did a simple test of applying this minimal WIM to an empty NTFS partition (via block device) with wimlib-imagex apply, and while it reported success, the files do not appear to have been restored at all.
And yes, I have tested capturing these same systems with dism /capture-image, and they restore correctly with dism /apply-image. However, one thing I noticed when doing it with dism:
The link from "testlink2.txt -> C:\temp\test.txt" updates its drive letter to match the drive letter that the WIM was restored to*. However, the link from "testlink3.txt -> \\?\C:\temp\test.txt" kept the original drive letter from when the link was created.
*Caveats: When the link was resolveable at the time of the dism capture, dism apply fixed up the path. So in my case, it was targeting E:\temp\test.txt. If the volume was mounted to E when captured with dism, a restore to C would change this path to c:\temp\test.txt, UNLESS I passed /norpfix to the dism apply command. If the volume was mounted to another letter when captured with dism, this fixup was not done during the dism apply, and a restore to C would leave this link broken and pointing to E:\temp\test.txt.
I think retaining the exact path is fine behavior, and I understand that that would be the only option when using wimlib-imagex to capture from a block device.
wimlib-imagex output:
dism.log:
I think wimlib has a bug when capturing a symlink with a path starting with \\?\. These seem like valid paths that don't involve the edge cases listed in the wimlib documentation for limitations when capturing from a unix block device (dism doesn't appear to dereference or fix them up either). The wim files created by wimlib-imagex capture when these symlinks are present are unreadable by dism.
Background:
I have used wimlib in the past to capture sysprepped windows systems (win10 and win11) and then later use Dism in WinPE to apply those WIM images to new systems, but I noticed that if I have installed Office in the source system before capturing the WIM with wimlib, dism fails to apply the WIM with the error:
Code: Select all
Error: 4392
The data present in the reparse point buffer is invalid.I notice that is dying on this specific file:
C:\Program Files\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\C2R32.dll
That file looks like this when running dir /a against it in windows:
Code: Select all
Volume in drive C has no label.
Volume Serial Number is 68AB-E012
Directory of C:\Program Files\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16
02/19/2025 02:02 PM <SYMLINK> C2R32.dll [\\?\C:\Program Files\Common Files\Microsoft Shared\ClickToRun\C2R32.dll]
1 File(s) 0 bytes
0 Dir(s) 117,932,900,352 bytes free
I decided to try to create a minimal reproduction:
New NTFS volume
Create X:\Temp
Create X:\Temp\test.txt with a little bit of text data
Create symlink X:\Templink -> X:\Temp (mklink X:\templink X:\temp)
Create symlink X:\temp\testlink.txt -> test.txt (pushd X:\temp; mklink testlink.txt test.txt)
Create symlink X:\temp\testlink2.txt -> X:\temp\test.txt (pushd X:\temp; mklink testlink2.txt X:\temp\test.txt)
Create symlink X:\temp\testlink3.txt -> \\?\X:\temp\test.txt (pushd X:\temp; mklink testlink3.txt \\?\X:\temp\test.txt)
I also tested that all these links 'work' (reading them reads the contents of the target file)
(no other files on this volume at all, other than system volume information)
And then booted to a linux environment, and captured these using "wimlib-imagex capture /dev/sda4 /mnt/share/file.wim". There are no warnings during the capture, but I get the same error 4392 when trying to apply this minimal WIM to a new empty NTFS partition with dism /apply-image.
I have read through the documentation on wimlib's limitations around reparse points, and found another thread regarding how reparse points are further limited when capturing from a block device using the ntfs-3g library, but it doesn't sound like any of those limitations apply to this case.
From the microsoft docs, it appears that the point of the \\?\ prefix is to disable string expansion and allow use of otherwise restricted characters, or to bypass path length restrictions, so I don't know why using it would be incompatible with the way wimlib stores reparse points/symlinks when doing a block device capture.
Also since I can replicate it with a very simple mklink command that only differs from a working one by the use of the \\?\ prefix, I don't think this is related to dedupe or other weirdness inherent to the Office 365 Click-to-Run app itself.
So, is this a wimlib bug, or an inherent limitation of ntfs-3g, or something else? I could provide a WIM file created from this minimal partition created with wimlib and with dism, if it would help. All my testing was done with wimlib 1.14.4 compiled locally on ubuntu 24.04.
I did a simple test of applying this minimal WIM to an empty NTFS partition (via block device) with wimlib-imagex apply, and while it reported success, the files do not appear to have been restored at all.
And yes, I have tested capturing these same systems with dism /capture-image, and they restore correctly with dism /apply-image. However, one thing I noticed when doing it with dism:
The link from "testlink2.txt -> C:\temp\test.txt" updates its drive letter to match the drive letter that the WIM was restored to*. However, the link from "testlink3.txt -> \\?\C:\temp\test.txt" kept the original drive letter from when the link was created.
*Caveats: When the link was resolveable at the time of the dism capture, dism apply fixed up the path. So in my case, it was targeting E:\temp\test.txt. If the volume was mounted to E when captured with dism, a restore to C would change this path to c:\temp\test.txt, UNLESS I passed /norpfix to the dism apply command. If the volume was mounted to another letter when captured with dism, this fixup was not done during the dism apply, and a restore to C would leave this link broken and pointing to E:\temp\test.txt.
I think retaining the exact path is fine behavior, and I understand that that would be the only option when using wimlib-imagex to capture from a block device.
wimlib-imagex output:
Code: Select all
Capturing WIM image from NTFS filesystem on "/dev/sda4"
Scanning "/dev/sda4"
Excluding "/System Volume Information" from capture
4 bytes scanned (1 files, 0 directories)
272 bytes scanned (5 files, 2 directories)
Using LZX compression with 1 thread
Archiving file data: 0 bytes of 272 bytes (0%) done
Archiving file data: 92 bytes of 272 bytes (33%) done
Archiving file data: 176 bytes of 272 bytes (64%) done
Archiving file data: 220 bytes of 272 bytes (80%) done
Archiving file data: 224 bytes of 272 bytes (82%) done
Archiving file data: 272 bytes of 272 bytes (100%) done
dism.log:
Code: Select all
2025-02-20 19:18:26, Info DISM PID=1260 TID=876 Scratch directory set to 'X:\windows\SystemTemp\'. - CDISMManager::put_ScratchDir
2025-02-20 19:18:26, Info DISM PID=1260 TID=876 DismCore.dll version: 10.0.26100.1150 - CDISMManager::FinalConstruct
2025-02-20 19:18:26, Info DISM Initialized Panther logging at X:\windows\Logs\DISM\dism.log
2025-02-20 19:18:26, Info DISM PID=1260 TID=876 Successfully loaded the ImageSession at "X:\sources" - CDISMManager::LoadLocalImageSession
2025-02-20 19:18:26, Info DISM Initialized Panther logging at X:\windows\Logs\DISM\dism.log
2025-02-20 19:18:26, Info DISM DISM Provider Store: PID=1260 TID=876 Found and Initialized the DISM Logger. - CDISMProviderStore::Internal_InitializeLogger
2025-02-20 19:18:26, Info DISM Initialized Panther logging at X:\windows\Logs\DISM\dism.log
2025-02-20 19:18:26, Info DISM DISM Manager: PID=1260 TID=876 Successfully created the local image session and provider store. - CDISMManager::CreateLocalImageSession
2025-02-20 19:18:26, Info DISM DISM.EXE:
2025-02-20 19:18:26, Info DISM DISM.EXE: <----- Starting Dism.exe session ----->
2025-02-20 19:18:26, Info DISM DISM.EXE:
2025-02-20 19:18:26, Info DISM DISM.EXE: Host machine information: OS Version=10.0.26100, Running architecture=amd64, Number of processors=2
2025-02-20 19:18:26, Info DISM DISM.EXE: Instance information: Parent process=X:\Windows\System32\cmd.exe, Parent process PID=884
2025-02-20 19:18:26, Info DISM DISM.EXE: Dism.exe version: 10.0.26100.1150
2025-02-20 19:18:26, Info DISM DISM.EXE: Executing command line: dism /apply-image /index:1 /applydir:C:\ /imagefile:Z:\MinimalCaptureWithSymlink.wim
[1260.436] [0x80071128] RestoreReparsePoint:(1835): The data present in the reparse point buffer is invalid.
[1260.436] [0xc144012e]
2025-02-20 19:18:26, Error DISM DISM WIM Provider: PID=1260 [RestoreReparsePoint:(1836) -> ioctl: setting reparse point tag failed] C:\temp\testlink3.txt (HRESULT=0x80071128) - CWimManager::WimProviderMsgLogCallback
[1260.436] [0x80071128] RestoreFileData:(3186): The data present in the reparse point buffer is invalid.
[1260.436] [0x80071128] RestoreRefNode:(1870): The data present in the reparse point buffer is invalid.
[1260.436] [0xc144012e]
2025-02-20 19:18:26, Error DISM DISM WIM Provider: PID=1260 C:\temp\testlink3.txt (HRESULT=0x80071128) - CWimManager::WimProviderMsgLogCallback
[1260.436] [0x80071128] RestoreRefNodeCallback:(2098): The data present in the reparse point buffer is invalid.
[1260.436] [0x80071128] ProcessWimQueueNode:(98): The data present in the reparse point buffer is invalid.
[1260.436] [0x80071128] DequeueWimData:(304): The data present in the reparse point buffer is invalid.
[1260.436] [0x80071128] ImageWorkerThread:(250): The data present in the reparse point buffer is invalid.
[1260.576] [0x80071128] GetImageErrorCode:(8174): The data present in the reparse point buffer is invalid.
[1260.576] [0x80071128] ImageWorkerThread:(198): The data present in the reparse point buffer is invalid.
[1260.876] [0x80071128] GetImageErrorCode:(8174): The data present in the reparse point buffer is invalid.
[1260.876] [0x80071128] RestoreAllFiles:(4191): The data present in the reparse point buffer is invalid.
[1260.876] [0x80071128] RestoreAllData:(1303): The data present in the reparse point buffer is invalid.
[1260.876] [0x80071128] WIMApplyImageInternal:(954): The data present in the reparse point buffer is invalid.
2025-02-20 19:18:26, Error DISM DISM WIM Provider: PID=1260 TID=876 onecore\base\ntsetup\opktools\dism\providers\wimprovider\dll\wimmanager.cpp:998 - CWimManager::Apply(hr:0x80071128)
2025-02-20 19:18:26, Error DISM DISM Imaging Provider: PID=1260 TID=876 onecore\base\ntsetup\opktools\dism\providers\imagingprovider\dll\genericimagingmanager.cpp:2847 - CGenericImagingManager::InternalCmdWimApply(hr:0x80071128)
2025-02-20 19:18:26, Error DISM DISM Imaging Provider: PID=1260 TID=876 onecore\base\ntsetup\opktools\dism\providers\imagingprovider\dll\genericimagingmanager.cpp:538 - CGenericImagingManager::ExecuteCmdLine(hr:0x80071128)
2025-02-20 19:18:26, Info DISM DISM.EXE: Image session has been closed. Reboot required=no.
2025-02-20 19:18:26, Info DISM DISM.EXE:
2025-02-20 19:18:26, Info DISM DISM.EXE: <----- Ending Dism.exe session ----->
2025-02-20 19:18:26, Info DISM DISM.EXE: