PDA

View Full Version : Lock a file



euthymos
2nd June 2009, 09:35
Hi,

is there any way I can lock a file with Qt libraries?
For "lock" I mean that when my app opens the file for writing, no other process can write on it. This happens for many Windows applications working with files.
I've tried QtLockedFile, but it only works among processes using QtLockedFile to access the file.

I've tried to call the native Windows API LockFile but it does not work because I can't give it a valid HANDLE to the file (QFile::handle() returns rubbish).

How can I fix this?

Thank you
Giacomo

wysota
2nd June 2009, 11:21
I've tried to call the native Windows API LockFile but it does not work because I can't give it a valid HANDLE to the file (QFile::handle() returns rubbish).


Did you cast this rubbish to a proper type?

euthymos
2nd June 2009, 11:44
Did you cast this rubbish to a proper type?

Rubbish was not meant to be offensive, but ironic :)

However, I casted it to HANDLE, which is declared in windows.h ;)

wysota
2nd June 2009, 12:39
I didn't think it was offensive :-) Casting it to HANDLE should have worked. What exactly happens when you try to use the handle?

euthymos
2nd June 2009, 12:51
I didn't think it was offensive :-) Casting it to HANDLE should have worked. What exactly happens when you try to use the handle?

It could have been offensive towards the developers...

However, if I cast it to HANDLE and pass it to LockFile(HANDLE, DWORD, DWORD, DWORD, DWORD) Windows API, the function returns false. GetLastError() returns 6, which is "invalid handle" error code.
I think this leaves no room to other possibilities: the handle is not valid.

wysota
2nd June 2009, 13:10
Maybe you need to pass the result through some other function first?

nish
2nd June 2009, 14:03
newbie reply...
Win32 CreateFile() to open file in locked mode;
QFile open again
QFile close
CloseFile (or whatever win api).

i really dont think that will work but just had this tickling in my mid..
:o:o

euthymos
2nd June 2009, 17:15
MrDeath: I'm a novice, too. I've been programming with Windows' APIs for a short time, and then in Java. Now I'm learning C++/Qt.

That solution might work fine. I think I'll try it when I get back to development machine. :)
However, I just can't see why QFile::handle() returns an invalid handle.

wysota: I don't know if I have to pass it to another function, the docs say nothing about that.

EDIT: there was a function to call! _get_osfhandle(int fd)
I've learnt that thanks to Qxt guys. See http://doc.libqxt.org/0.5.0/classQxtFileLock.html

jonks
2nd June 2009, 17:31
1. Win32 CreateFile() to open file in locked mode;
2. QFile open again
3. QFile close
4. CloseFile (or whatever win api).



How can step 2 work? - it is trying to open a locked file.

euthymos
2nd June 2009, 22:51
How can step 2 work? - it is trying to open a locked file.

Actually I don't know... but maybe, because it's the same application and the same thread accessing the file, it can be opened after the lock. Just guessing.

However, I solved with a great "native" solution inspired by Qxt's "QxtFileLock" class (http://doc.libqxt.org/0.5.0/classQxtFileLock.html). You should check this Qxt thing out, it's really good.

nish
3rd June 2009, 03:21
Actually I don't know... but maybe, because it's the same application and the same thread accessing the file, it can be opened after the lock. Just guessing.


that was what i thought. Did it worked? i am on linux so cant test it.



However, I solved with a great "native" solution inspired by Qxt's "QxtFileLock" class (http://doc.libqxt.org/0.5.0/classQxtFileLock.html). You should check this Qxt thing out, it's really good.

this website is blocked at my office. can u please copy and paste the solution. thx..

euthymos
3rd June 2009, 15:10
that was what i thought. Did it worked? i am on linux so cant test it.
Actually, I didn't try it yet.




this website is blocked at my office. can u please copy and paste the solution. thx..
This is the actual piece of code performing the trick under Windows:

bool QxtFileLock::lock()
{
if (file() && file()->isOpen() && !isActive())
{
HANDLE w32FileHandle;
OVERLAPPED ov1;
DWORD dwflags;

w32FileHandle = (HANDLE)_get_osfhandle(file()->handle());
if (w32FileHandle == INVALID_HANDLE_VALUE)
return false;

switch (qxt_d().mode)
{
case ReadLock:
dwflags = LOCKFILE_FAIL_IMMEDIATELY;
break;

case ReadLockWait:
dwflags = 0;
break;

case WriteLock:
dwflags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY;
break;

case WriteLockWait:
dwflags = LOCKFILE_EXCLUSIVE_LOCK;
break;

default:
return (false);
}

memset(&ov1, 0, sizeof(ov1));
ov1.Offset = qxt_d().offset;

if (LockFileEx(w32FileHandle, dwflags, 0, qxt_d().length, 0, &ov1))
{
qxt_d().isLocked = true;
return true;
}
}
return false;
}

If you ignore the inner class stuff, you see it's just a call to LockFileEx. The HANDLE is get by w32FileHandle = (HANDLE)_get_osfhandle(file()->handle());

Nice, but still I'm not satisfied. I cannot understand why this lock allows other programs to TRUNCATE the file!!! They cannot change the bytes, but they can still truncate it.
Is there any effective solution to lock a file in Windows outside CreateFile call?

It's incredible how Qt programmers has been "lazy" not implementing in QFile some damn decent way to lock the files without performing those hacks. Is a QFile :: open(QString path, OpenMode mode, LockingMode lmode) so impossible?

lni
3rd June 2009, 15:58
This becomes platform dependence...

How about creating an empty file with named such as "myfile.txt.lock", and at any time when you want to write a file, check if myfile.txt.lock exists or not, if exists, then you can wait or bail out...

The program that creates "myfile.txt.lock" is responsible to delete it when done....

wysota
3rd June 2009, 19:22
It's incredible how Qt programmers has been "lazy" not implementing in QFile some damn decent way to lock the files without performing those hacks. Is a QFile :: open(QString path, OpenMode mode, LockingMode lmode) so impossible?

It's incredible how people think everyone is just like them - thinks like them, looks like them and in general agrees with them. Windows is the only platform supporting mandatory locks natively. And in general you should avoid mandatory locks, it's a great way to lock out your application.

auba
4th June 2009, 15:04
How would you avoid the reading of a file which currentely is written by another program? Let's say something like the iTunes database file, about 10MB plain text?
When you are working on win32, you can't simply create a tmp file, write it down, and then rename it. First, the file system of win32 seems to be too slow to realize, that a file is removed and you really fast get an "file exists" error when renaming the tmp file to the original name. Second, you'll get a small time span when the file does not exist as the old content is backuped and the new content is not yet renamed. Does that fact matter? :confused:

But I agree with you, both (wysota and euthmos). If I had mandatory locks, life would be much easier. But to say, that the Trolls are too lazy to implement them is the wrong way :rolleyes:

wysota
4th June 2009, 16:42
How would you avoid the reading of a file which currentely is written by another program?

I would use proper IPC mechanisms on local filesystems. On remote filesystems there is nothing you can do, even on Windows they don't support locking.

auba
4th June 2009, 19:46
Well... with qt3.x we patched qfile_win.cpp to allow locking by sopen - and it even works on network drives. But I don't want to do that in the future... :rolleyes:

Malek
27th December 2010, 22:47
What is the conclusion?
Can I lock the file until my thread finish writing on it? and how?

squidge
27th December 2010, 23:30
Sure, but the solution can be platform dependant depending on HOW you want to lock the file.

Malek
27th December 2010, 23:45
I work on Linux.
I need to lock the file until my thread finish writing on it. Then unlock it.

squidge
27th December 2010, 23:57
You still have not defined HOW you want to lock it.

For example, do you want to lock it to prevent your other threads from writing to the same file? Or writing and reading? Or prevent your other thread from even opening the file? Or prevent any application in the entire system from opening the file? Or perhaps allowing some apps to read the file but not write to it? etc...

Malek
28th December 2010, 00:02
do you want to lock it to prevent your other threads from writing to the same file?
Yes , this what I want to lock it for.
I am sorry if I was not clear.

wysota
28th December 2010, 00:29
On Unix systems there is no mandatory locking which means in a general case you cannot prevent someone else from writing to the same file while you have it open. It requires cooperation of all involved sides and use of advisory locking (e.g. using flock). Some filesystems may implement mandatory locking (through fcntl calls) but others will not and on some systems (like Linux) mandatory locks are unreliable (see the man page for fcntl).