winapi - ReplaceFile alternative when application keeps file locked -
editor fooedit (let's call it) uses replacefile() when saving ensure save operation atomic, , if goes wrong original file on disc preserved. (the other important benefit of replacefile() continuity of file identity - creation date , other metadata.)
fooedit keeps open handle file sharing mode of file_share_read, other processes can open file can't write while while fooedit has open writing.
"obviously", handle has closed briefly while replacefile operation takes place, , allows race in process can potentially open file write access before fooedit re-establishes it's file_share_read lock handle.
(if fooedit doesn't close file_share_read handle before calling replacefile(), replacefile() fails sharing violation.)
i'd know simplest way resolve race. options seem either find way lock file compatible replacefile() (i don't see how possible) or replicate behaviour of replacefile(), using existing file handle access destination file rather path. i'm bit stuck on how of operations of replacefile() carried out atomically user code (and reimplementing replacefile() seems bad idea anyway).
this must common problem, there's obvious solution i've missed.
(this question seems related has no answer: transactionally write file change on windows.)
here's minimal verifiable example showing trying achieve (updated 13:18 30/9/2015 utc). must supply 3 file names command line arguments, on same volume. first must exist.
i sharing violation replacefile().
#include <windows.h> #include <stdio.h> #include <assert.h> int main(int argc, char *argv[]) { handle lock; handle temp; dword bytes; if (argc != 4) { puts("first argument project file. second argument temporary file."); puts("the third argument backup file."); } /* open , lock project file make sure no 1 else can modify */ lock = createfile(argv[1], generic_read | generic_write, file_share_read | file_share_delete, null, open_existing, 0, 0); assert(lock != invalid_handle_value); /* save temporary file. */ temp = createfile(argv[2], generic_read | generic_write, file_share_read | file_share_delete, null, create_always, 0, 0); assert(temp != invalid_handle_value); writefile(temp, "test", 4, &bytes, null); /* keep temp open process can't modify file. */ if (!replacefile(argv[1], argv[2], argv[3], 0, null, null)) { if (getlasterror() == error_sharing_violation) puts("sharing violation expected"); else puts("something went wrong"); } else puts("replacefile worked - not expected"); /* if worked file referenced temp called argv[1]. */ closehandle(lock); lock = temp; return exit_success; }
thanks hans passant, provided valuable clarifying thoughts in answer deleted. here's discovered while following suggestions:
it seems replacefile() allows lpreplacedfilename open file_share_read | file_share_delete, lpreplacementfilename can't be. (and behaviour doesn't seem depend on whether lpbackupfilename supplied.) it's possible replace file process has open if other process doesn't allow file_share_write, hans' point.
but fooedit trying ensure no other process can open file generic_write in first place. ensure in fooedit there's no race process can open replacement file generic_write, seems fooedit has keep hold continuously of file_share_read | file_share_delete handle lpreplacementfilename, precludes use of replacefile().
i'd know simplest way resolve race.
there no simple way resolve race. it's inherent part of file system not transactional. ms had transactional file api while, has been removed. if want transactions, need implement them yourself.
i have had experience replacefile
think caused more trouble worth. recollection whilst meta data preserved, new file created. consequence of annoying behaviour files saved on desktop. because such files have position preserved, creating new file resulted in default position being used. you'd save file, you'd drag place on desktop wanted keep it, , when saved file again, moved default position.
Comments
Post a Comment