How can I lock a file in Linux with a filestream?
Creating a filestream like in the example below works perfectly in Windows, the file is locked and cannot be deleted or written to in other sessions until the stream is freed. Under Linux I can delete the file or write to it in an other session without any problems.
var f: TFileStream; ... f := TFileStream.Create(TPath.Combine(FTemp, lowerCase(Name)), fmOpenReadWrite + fmCreate); ...
NEW FINDINGS 1.1.2020
Linux does not automatically apply an atomic lock on files like Windows does. So I tried applying a lock after creating the file:
function flock(handle, operation: integer): integer; cdecl; external libc name _PU + 'flock'; const LOCK_EX = 2; ... f := TFileStream.Create(fn, fmCreate, fmShareExclusive); flock(f.handle, LOCK_EX);
There is a small race condition as creating the file and locking it is not one single step but for my application this is not a problem. When looking at the created lock file on the linux console the difference is obvious:
Wihout flock():
mint@minti:/tmp/itclock$ lsof wirsing COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME _TestLibB 5417 mint 14u REG 8,1 8 2755101 wirsing
With flock():
mint@minti:/tmp/itclock$ lsof wirsing COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME _TestLibB 6365 mint 14uW REG 8,1 0 2755117 wirsing
The difference is the big W that indicates an exclusive lock.
Unfortunately this does not solve the problem as creating a second filestream just creates a second exclusive lock in the same process and deleting the file from an other process is still possible. If there was a way to read the extended attributes of lsof <file>
from within delphi …
An other finding (new year, new ideas)
As I run my tests as unit tests and create several objects in the same process to test the locks this might be the cause as Windows does not allow accessing the locked file even from within the same process. This seems to be different in Linux. I need something that behaves like in Windows – it should be no difference if it is locked in a different process or a thread of the same process. Perhaps Linux offers a totally different way to accomplish such a locking mechanism?
And still: Any help is very appreciated!
Advertisement
Answer
Finally I found a usable solution that at least serves my requirements:
In Windows I continue using the simple approach with fmShareExclusive. In Linux I apply a FileLock as described above in the question. For checking the exclusive lock I run a command line via popen and capture the result prior to deleting the lock file and then creating/locking it.
lsof -Fl <my flock file name>
This outputs three lines if a Lock exists:
p7590 f14 lW
I look for lW
in the result that indicates an exclusive lock on the file and I can react on that as required.
This solution still works if a process crashes as then the file lock will be gone too.
I am aware of the fact that this is not a very elegant solution but it seems to be rubust and reliable enough.
Comments and suggestions are very welcome!