-
Notifications
You must be signed in to change notification settings - Fork 342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(snapshots): Append path separator to Shadow Copy root directory on Windows #3891
base: master
Are you sure you want to change the base?
Conversation
Something additional to note, there is a similar check going on here in the NewEntry function: kopia/fs/localfs/local_fs_os.go Lines 112 to 128 in fcb8197
I wonder if it would be useful to change this to use the new |
I applied this PR on top of v0.17.0 tag which I confirmed to be showing the problem reported in #3842 using However, it's worth noting that appending a trailing backslash when detecting the |
Thanks for the extra info.
I wonder if there's any Windows API to detect or resolve links like this in the Object namespace? For normal symlinks / reparse points in the filesystem this can be done with os.Lstat, but as noted in the code in my second comment, Lstat seems to fail on these kinds of paths unless you "manually" resolve them with the trailing backslash. If there's a way to detect them directly, it might make sense to implement them like normal symlinks are now, and there wouldn't be any need to handle shadow volumes explicitly.
I considered doing something like this but I was worried about edge cases, which is why I went out of my way to make sure the workaround is only applied to the top-level root directory. Since "inside" the shadow volume device is just a normal filesystem, appending a backslash anywhere after the root might have different consequences, like resolving links. If we did something more generic, it would definitely need a lot more testing to make sure all the edge cases are handled correctly. |
I ended up reading a lot about Windows path handling, this article seems to contain a lot of the relevant information. I believe the fundamental issue here is that Windows treats opening the path Unfortunately, it seems non-triviable to handle this "correctly". It seems impossible to know whether a UNC path points to a device object without doing multiple Windows-specific syscalls for every path. That being said, I think there is a way to handle this a bit more cleanly. For one, rather than the current func (e *filesystemEntry) isWindowsVSSVolume() bool {
return runtime.GOOS == "windows" &&
e.prefix == `\\?\GLOBALROOT\Device\` &&
strings.HasPrefix(e.Name(), "HarddiskVolumeShadowCopy")
} then we can just do this in fullPath := fsd.fullPath()
appendPath := ""
if fsd.isWindowsVSSVolume() {
appendPath = string(os.PathSeparator)
}
f, direrr := os.Open(fullPath + appendPath) //nolint:gosec and that's all the logic needed. If we ever want to make it a bit more generic in the future. the If there's no objections to this revised patch, I think I'll push another commit with it in a little bit since it's pretty much the same logic as the previous commit, just cleaner. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3891 +/- ##
==========================================
+ Coverage 75.86% 77.13% +1.27%
==========================================
Files 470 479 +9
Lines 37301 28755 -8546
==========================================
- Hits 28299 22181 -6118
+ Misses 7071 4669 -2402
+ Partials 1931 1905 -26 ☔ View full report in Codecov by Sentry. |
Regarding the test coverage, should I add a test that covers this case? I think I could just mostly copy https://github.com/kopia/kopia/blob/master/tests/os_snapshot_test/os_snapshot_windows_test.go but enable |
This is a fix for #3842.
It's a slightly modified version of the patch in #3842 (comment), I separated the code out into a
maybe
function and added some tests.The root cause of this issue seems to be a regression in Go 1.22 (see #3842 (comment)), but as discussed with jkowalski in the issue, it seems better to just fix this up with a special case in Kopia.