Skip to content

Skip ExtendedAttribute processing in Windows for volumes that do not support EA#4980

Merged
MichaelEischer merged 9 commits intorestic:masterfrom
zmanda:unsupported-ea-handling
Aug 10, 2024
Merged

Skip ExtendedAttribute processing in Windows for volumes that do not support EA#4980
MichaelEischer merged 9 commits intorestic:masterfrom
zmanda:unsupported-ea-handling

Conversation

@aneesh-n
Copy link
Copy Markdown
Contributor

@aneesh-n aneesh-n commented Aug 3, 2024

What does this PR change? What problem does it solve?

Some windows paths like network drives do not support ExtendedAttributes. Either they return error codes like windows.E_NOT_SET or windows.ERROR_INVALID_FUNCTION or it results in slower backups.
This PR aims to skip processing the ExtendedAttributes after detecting if the volume does not support them.
It completely skips the attempt to fetch Extended Attributes instead of trying to handle errors after trying to fetch EA for files on such volumes.

Was the change previously discussed in an issue or on the forum?

May resolve #4955 and #4950

Checklist

  • I have read the contribution guidelines.
  • I have enabled maintainer edits.
  • I have added tests for all code changes.
  • I have added documentation for relevant changes (in the manual).
  • There's a new file in changelog/unreleased/ that describes the changes for our users (see template).
  • I have run gofmt on the code in all commits.
  • All commit messages are formatted in the same style as the other commits in the repo.
  • I'm done! This pull request is ready for review.

Copy link
Copy Markdown
Member

@MichaelEischer MichaelEischer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can give this approach a try. I've found a few problems though, see below.


kernel32dll = syscall.NewLazyDLL("kernel32.dll")

procGetVolumeInformationW = kernel32dll.NewProc("GetVolumeInformationW")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use https://pkg.go.dev/golang.org/x/sys/windows#GetVolumeInformation instead of manually building a wrapper.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

const (
// fileSupportsExtendedAttributes is a bitmask that indicates whether the file system supports extended attributes.
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_fs_attribute_information
fileSupportsExtendedAttributes = 0x00800000
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that constant is also available in x/sys/windows with the name FILE_SUPPORTS_EXTENDED_ATTRIBUTES.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

}
ret, _, err := procGetVolumeInformationW.Call(
uintptr(unsafe.Pointer(utf16Path)),
uintptr(unsafe.Pointer(&volumeName[0])),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most output parameters are optional.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

return false, nil
}
if !strings.HasSuffix(filepath.Clean(path), `\`) {
if strings.HasSuffix(filepath.Clean(path), `\`) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach won't work for backups using relative paths.

cd /D Z:   # some network share
restic backup local/file

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I believe I've addressed this now.

procDecryptFile = modAdvapi32.NewProc("DecryptFileW")

// eaUnsupportedVolumesMap is a map of volumes that do not support extended attributes.
eaUnsupportedVolumesMap = map[string]bool{}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really no fan of introducing additional global state as it usually leads to problems sooner or later. However, until I've moved the NodeFromFileInfo and related code into the internal/fs package, I don't see a good way to avoid it. Either way this map MUST be synchronized.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. We can revisit later
Fixed using sync.Map

Copy link
Copy Markdown
Member

@MichaelEischer MichaelEischer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to almost work, see the comments for the remaining problems.

Copy link
Copy Markdown
Member

@MichaelEischer MichaelEischer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

@MichaelEischer MichaelEischer added this pull request to the merge queue Aug 10, 2024
Merged via the queue into restic:master with commit 86390b4 Aug 10, 2024
//Extended length path prefix needs to be trimmed to get the volume name correctly
path = path[len(extendedPathPrefix):]
} else if strings.HasPrefix(path, globalRootPrefix) {
// EAs are not supported for \\?\GLOBALROOT i.e. VSS snapshots
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a mistake here while fixing the test case errors.
Extended attributes are in fact supported for VSS snapshots.
Instead of returning false, we should be handling the volume names for VSS snapshots correctly. Apologies, I can add a separate PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning false, we should be handling the volume names for VSS snapshots correctly. Apologies, I can add a separate PR.

Does GetVolumeInformation support such paths or do we needs even more weird special case handling?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to get the 'volumeName' path like this -

// Extract the VSS snapshot volume name eg. `\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopyXX`
if parts := strings.SplitN(path, `\`, 7); len(parts) >= 6 {
	volumeName = strings.Join(parts[:6], `\`)
}

Rest of the code remains same-

fs.PathSupportsExtendedAttributes(volumeName + \) i.e. GetVolumeInformation works.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sigh, I'm not happy about all those Windows special case. But looks like we'd better add them. Can you open a PR for it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Regression] restic 0.17.0 on Windows: cannot backup using network drive

2 participants