I’m doing some folder watching to process files (in sub-folders), if present, in a given folder. What I’m finding, though, is when a folder is being copied from another volume (as opposed to just moved on the same volume), a test shows that the folder “exists”, although not all of the contents are there, thus triggering up my “ready to process” routine prematurely.
I’m wondering if there’s a way, via AS or Obj-C, to tell when such a copy is actually complete.
I did find that if the copy is being done in Finder, a look at the properties of the folder shows a creation date:date “Thursday, February 14, 1946 2:34:56 AM”, and then adjusts to the proper date when completed, but I need to cover bases if the copy/move is being done with shell’s cp/mv/ditto/etc…, or even another file managing app.
I’d like to avoid, if possible, having to test for filesize and contents changes to settle down. I’m afraid that if some other process ties up the machine for a while that I’ll get a false reading of no change, when actually it was just stalled. If I have to, I could resort to something like this, but I’d like to get more immediate results, rather than having to wait a few to several seconds to verify that the copy “really is done”.
Maybe there’s a way to tell if a file or folder is “busy” while being copied? I could, I guess, iterate through the list of the contents of a folder to see if anything is still copying, if that’s possible.
Well, so far while searching around in Google, I’ve found “fuser” (man fuser), which gets me close. It’s really slow, though. And it works on files, not folders, apparently. Also, it acts differently between a Finder copy and a ditto copy. During a Finder copy it will tell me if a file is busy during the copy, but it comes up as “no file” when using ditto to copy the folder.
If Finder would match a “no file”, then I’d be set.
And of course I found NSFileBusy in the docs for NSFileManager, but it’s not working. Guess it does in the deprecated fileAttributesAtPath:traverseLink:… Figures.
And it doesn’t help that the docs in Xcode for NSFileManager shows NSFileBusy in File Attribute Keys as part of the NSDictionary returned from attributesOfItemAtPath:error: and the entry for setAttributes:ofItemAtPath:error: says you can set NSFileBusy.
Thought I found another discussion that had the fix, but that dealt with deprecated methods as well.
I understand that UNIX file systems don’t really have a sense of a file being busy. Looks like something I’m going to have to fudge through.
I used to just do a finder copy, but that can hog up a network, depending.
I switched some scripts to use shell script “mv”, I thought I read somewhere that shell script will wait or reply when the command completes.
In one script I use a “System Event” to check for busy status, and it seems to generally work.
All that would be fine if my app were in charge of the copy/move operations, but I’m watching folders for changes, and the copy/move operation could be done by any means the user sees fit (via any of a number of command-line tools, Finder, PathFinder, any number of 3rd party apps).
There’s still plenty of the Obj-C/Cocoa docs for me to explore. I’ll take a look. I’ve already found that NSFileBusy won’t work, though.
There is busy property of System Events addition, although I have never used it.
However in the AppleScript Software Development kit version 1.3.4 which you may download through ADC (from around 98, I remember I saw a folder action script there. Although it may be even slower than the unix command line tool. That is unless you use the technique to write an applescript that constantly polls, but that may be a real resource hog.
The unix system knows very well which files are open like any platform, but you must over to C below Carbon and Cocoa and into the kernel. -lsof works – tells that a file is open at least. And you can regard a file as busy as long as it is open?
-Hope so.
If I were you I’d look into the source code of the utility “lsof” to see if there is something which can be compiled into your own specific tool.
I believe there must be some tables in the kernel which keeps tracks of open files, and if you inspect the source code of lsof - it runs in user mode! (bet’s its written in pure C), and manages to identify the system calls I guess you can manage to whip out a little utility in pure C which suits your needs with out too much effort.
But don’t blame me if I’m wrong.
The first way I would try solve this problem would have been to get in touch with some guys at the OpenDarwin site. They have the real knowledge.
I have the same question. Copying a file from a remote volume to local Hard Disk ONLY when file is really complete. In the same time the file is uploaded from other machines to the pathFolder dir.
I tested some solution but none of these works.
So I written a small routine based on bytes that seems works good:
property filesList : missing value
property filesListComplete : missing value
set filesList to {}
set filesListComplete to {}
set pathFolder to "/Volumes/Park/Test"
try
set shellTmp to do shell script "/usr/bin/find -E " & quoted form of pathFolder & " -type f -maxdepth 1 -regex '.*\\.(jpg|jpeg|tif|tiff|psd)'"
set filesList to paragraphs of shellTmp
checkCopy()
on error msg number errnum
--
end try
on checkCopy()
repeat with j from 1 to count filesList
set pathImage to (item j of filesList)
set fileSizeBefore to (do shell script "/usr/bin/stat -f %z " & quoted form of pathImage) as integer
set item j of filesList to {pathImage, fileSizeBefore}
end repeat
do shell script "sleep 10"
repeat with j from 1 to count filesList
set pathImage to (item 1 of item j of filesList)
set fileSizeBefore to (item 2 of item j of filesList)
if fileSizeBefore is not 0 then
set fileSizeAfter to (do shell script "/usr/bin/stat -f %z " & quoted form of pathImage) as integer
if fileSizeAfter = fileSizeBefore then
copy pathImage to end of filesListComplete
end if
end if
end repeat
end checkCopy
Ame