Skip to content

glib: map ERROR_LOCK_VIOLATION and ERROR_SHARING_VIOLATION to EBUSY.

Jehan requested to merge Jehan/glib:wip/Jehan/Windows-lock-file-on-rename into master

On Windows, these errors happen when a file is temporarily unavailable because another process has a lock on it. This is not necessarily a fatal error for g_rename(), as it means it may work after a retry. Yet we need to properly tell the proper error condition for calling developer to handle the situation.

Linux' rename() already use EBUSY errno for similar issue, though mostly when called on directories only, and warning such case is actually quite uncommon: "The rename fails because oldpath or newpath is a directory that is in use by some process" (cf. man 2 rename). So I figure this is the right counterpart for the sharing violation on Windows.

Additional context: this change was triggered by gimp#1370. Basically some people under Windows experience intermittent issues when saving on directories synced in their cloud system (reported for Dropbox and Google drive) on Windows.

Current code simply returns "Error renaming temporary file: Permission denied", because current implementation of g_rename() maps ACCESS_DENIED, LOCK_VIOLATION and SHARING_VIOLATION all to EACCESS, as though they were the same issue. Actually they aren't. Whereas ACCESS_DENIED can probably be considered as fatale (permissions or whatnot), the other could be just temporary stepbacks. Now this is up to the calling software probably to decide what to do when this happens (cancel, retry, and if so, for how long until abandoning, etc.) but for this, we need the information.

I chose to map these to EBUSY instead as it looks quite similar and is used in similar way by man 2 rename. POSIX defines this error as: "Resource busy. An attempt was made to make use of a system resource that is not currently available, as it is being used by another process in a manner that would have conflicted with the request being made by this process."

That sounds quite fitting! (note I hesitated with EAGAIN too, which is defined by: "Resource temporarily unavailable. This is a temporary condition and later calls to the same routine may complete normally." Yet I went with EBUSY as it was also a possible errno value in the rename() Linux call (unlike EAGAIN), so it seems like it could allow easier cross-platform handling.

Note: at first I actually added some handling code within g_rename(), to retry before abandoning. But afterwards I thought this may not be the wisest, especially since the caller cannot control any max retry delay (unless we create a new function with a delay parameter). Maybe it's better to just let the calling application decide what to do. Now if you would prefer to have handling code within glib, just tell me, and I'll push the alternative with a new function.

Edited by Philip Withnall

Merge request reports