-
Notifications
You must be signed in to change notification settings - Fork 290
Windows: add NSData writeToFile fallback for ERROR_NOT_SAME_DEVICE #564
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
Conversation
|
Copying is not atomic, so it seems to me that the proposed change is breaking the method rather than providing a fallback. If it turns out to be impossible to implement that method completely reliably on windows, I think failing is the correct behavior. In the specific case of NSUserDefaults, we probably already hold a cooperative filesystem level lock to prevent other processes accessing the defaults at the same time. If that's working reliably we don't really need an atomic lock there, and the NSZUserDefaults code could fall back to doing a non-atomic write if the atomic write fails. |
|
I suppose the other (possibly better) option would be to check what device the destination file is on, and make sure to create the auxilliary file is on that device, so this particular failure could not occur. |
|
We are actually seeing this error 17 (ERROR_NOT_SAME_DEVICE) for paths that both have the same drive letter, but somehow through filesystem redirection/virtualization they seem to end up on different file systems. Here is the full error we are seeing: You are of course right that the copy fallback is not atomic, but it’s unclear to me how to fix this in a better way. The auxiliary file is already being created on the same drive according to the path. I guess there might be a more involved fix where we would use additional Windows APIs to figure out the actual destination path after redirection, but that seems difficult to get right and test. And if we can’t guarantee that the files are actually on the same volume, as far as I know there is no Windows API for an atomic replace across volumes. Happy to try other approaches if you have more ideas how to improve this. |
|
I don't work on windows, but from what I can find searching online, your best approach might be to use LockFileEx() for atomic writes. So instead of using an auxilliary file, you open the original file, lock it, overwrite it, and release the lock. |
ba50501 to
9976fe0
Compare
|
If I understand it correctly locking wouldn’t protect against partial writes e.g. if the app crashes, and only works if readers lock too. I’ve implemented another approach based on your other suggestion:
I still kept the copy fallback, but with this change in theory it shouldn’t happen any more. How does that look to you? |
|
I think that looks good except ... I'm still not really happy about an explicitly atomic API doing a non-atomic copy. |
|
I can kind of see why you might want to put the fallback code in -writeToFile:atomically: rather than having higher level code deal with the issue (it's no great trouble to get NSUserDefaults to do it, but in practice most code expects methods to work and doesn't bother checking return values). I'm not completely set against that, but I feel it would need a lot of work as follows:
|
|
Thanks for your additional thoughts. It makes sense what you say about an explicitly atomic API doing a non-atomic copy. Since the original issue should hopefully be fixed even without the fallback, I’ll just remove it and we keep this change to just resolving the destination directory. |
9976fe0 to
8b58787
Compare
8b58787 to
450ba9c
Compare
# Conflicts: # ChangeLog
We have some users where writing the NSUserDefault settings fails on Windows with
ERROR_NOT_SAME_DEVICEwhen the settings plist gets renamed from the auxiliary file to the final filename. This can apparently happen due to Windows packaged app filesystem redirection/virtualization in some cases redirecting files via reparse points or even the same path string resolving to different backing locations depending on operation (e.g. create vs open existing).The change adds a fallback by copying the file instead of renaming, which works across volumes.