سؤال

If you do use a simple fopen/fwrite() such as:

$ref = @fopen('/path/to/file', 'x+b'); // returns false if already exists
if ($ref) {
    fwrite($ref, 'A');
    sleep(5);
    fwrite($ref, 'B');
}

How can you check that the file pointer is still valid if some other process deletes the file during the sleep?

I have considered using a simple is_file() check, but that wouldn't say if another process did the unlink() then created a new file with the same path.

For reference, fwrite seems to still return true, even though the file has been unlink()'ed.

Edit: Just to clarify, the sleep(5) is just a random time, it could be just a couple of ms, in the case of a race condition.

هل كانت مفيدة؟

المحلول

I've just made a test, and it seems that fstat is the solution:

$fd = fopen("/path/to/file", "w");
var_dump(fstat($fd)); // shows ['nlink'] => int(1)
sleep(60);
// in a shell console, remove the file
var_dump(fstat($fd)); // shows ['nlink'] => int(0)

نصائح أخرى

You need to perform fopen() again. On linux system you can write into deleted file because you have still reference to it. When you close it the file will be finally deleted.

If process needs to wait I would close, then open file between sleeps

If you hold a handle to the file you do not need to bother that. Filesystem is taking care of that.

EDIT

Handle is valid unless you close it or script ends and deleting file is absolutely irrelevant to the validity of the handle and so is locking. One can easily check that by creating i.e. big file (1GB) and start i.e. fetching using browser and you can now "safely" delete it from other process. And this will NOT affect fetching even tools like ls will no longer list the file as existing. I wrote "safely" because if download fail, then httpd will close opened handle and then, if no other process hold a handle, it will phisicaly free diskspace. But it DOES as long as there's at least one reference to it, data remains on the disk (it can be easily checked by checking free disk space using tools like df - in sequence:

create 1GB file
df
start download
rm file
df

second df will indicate that discspace is the same as with 1st one (assuming no other file manipulation occured of course). Now stop downloading and do df again. Free space is now 1GB in plus.

Please note that Windows' FS won't let you delete opened file, but that's just a matter of implementation not technical limitations. Most (if not each) FS on *nix will handle this without any problem.

Just to add a lot of precisions: fopen() locking depends on the type you opened the file as. w and w+ will lock - r, a, r+ will not (by default). However, if you really want to be sure that your file cannot be used elsewhere, the function flock() might come in handy.

However, if you really need to lock the file and do nothing on it for 5 seconds, I would instead question your design/implementation rather than find a way around it.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top