appletfilecopy.c

Go to the documentation of this file.
00001 
00002 /*  $Id: appletfilecopy.c 355 2005-01-11 22:48:55Z andreradke $    */
00003 
00004 /* copyright 1991-96 UserLand Software, Inc. All Rights Reserved.*/
00005 
00006 
00007 #include <Script.h>
00008 #include "applet.h"
00009 #include "appletmain.h"
00010 #include "appletfilesinternal.h"
00011 #include "appletfolder.h"
00012 #include "appletfilealias.h"
00013 #include "appletfiledelete.h"
00014 #include "appletfiledesktop.h"
00015 #include "appletsyserror.h"
00016 #include "appletfilecopy.h"
00017 
00018 
00019 
00020 static boolean copyfork (short fsource, short fdest, Handle hbuffer) {
00021     
00022     /*
00023     copy either the data fork or resource fork of the indicated file.
00024     
00025     return true iff the file copy was successful.
00026     
00027     5/19/92 dmb: call langbackgroundtask when a script is running to make it more 
00028     likely that we'll yield the processor to another app.  also, only allow 
00029     background tasks if fork is larger than a single buffer.  note that if a script 
00030     is copying a bunch of files in a loop, the interpreter is already allowing 
00031     backgrounding between files.
00032     */
00033 
00034     register long buffersize = GetHandleSize (hbuffer);
00035     long ctbytes;
00036     register OSErr errcode;
00037     
00038     SetFPos (fsource, fsFromStart, 0L); 
00039     
00040     SetFPos (fdest, fsFromStart, 0L);
00041     
00042     while (true) { 
00043         
00044         ctbytes = buffersize;
00045         
00046         HLock (hbuffer);
00047         
00048         errcode = FSRead (fsource, &ctbytes, *hbuffer);
00049         
00050         HUnlock (hbuffer);
00051         
00052         if ((errcode != noErr) && (errcode != eofErr)) {
00053             
00054             fileerror (nil, errcode);
00055             
00056             return (false);
00057             }
00058             
00059         if (ctbytes == 0) /*last read got no bytes*/
00060             return (true);
00061         
00062         HLock (hbuffer);
00063         
00064         errcode = FSWrite (fdest, &ctbytes, *hbuffer);
00065         
00066         HUnlock (hbuffer);
00067         
00068         if (fileerror (nil, errcode)) 
00069             return (false);
00070         
00071         if (ctbytes < buffersize) /*copy of fork is finished*/
00072             return (true);
00073         
00074         appserviceeventqueue ();
00075         
00076         rollbeachball (); /*roll the beachball cursor if there is one*/
00077         } /*while*/
00078     } /*copyfork*/
00079 
00080 
00081 static boolean largefilebuffer (Handle *hbuffer) {
00082     
00083     /*
00084     allocate a "large" buffer for a file copy or some kind of transfer.
00085     
00086     we ask for a block the size of half of the current free space.  if we can't 
00087     get it, we'll ask for the largest free block.  in any case, we fail if 
00088     we can't get a block of at least a K
00089     
00090     3/16/92 dmb: total rewrite; old version _always_ compacted the heap, 
00091     resulting in poor performance.
00092     */
00093     
00094     register long ctbytes;
00095     register Handle h;
00096     
00097     *hbuffer = nil; /*default return*/
00098     
00099     ctbytes = memavail () / 2;
00100     
00101     if (ctbytes < 1024) { /*no enough memory to work with*/
00102         
00103         sysmemoryerror ();
00104         
00105         return (false);
00106         }
00107     
00108     ctbytes &= ~(1024 - 1); /*fast round down to nearest multiple of 1024*/
00109     
00110     h = appnewhandle (ctbytes);
00111     
00112     if (h != nil) {
00113         
00114         *hbuffer = h;
00115         
00116         return (true);
00117         }
00118     
00119     /*allocation failed; heap has been compacted; find largest block size*/
00120     
00121     ctbytes = CompactMem (maxSize); /*recompact the heap, finding out size of largest block*/
00122     
00123     if (ctbytes < 1024) { /*largest block is too small to use*/
00124         
00125         sysmemoryerror ();
00126         
00127         return (false);
00128         }
00129     
00130     ctbytes &= ~(1024 - 1); /*fast round down to nearest multiple of 1024*/
00131     
00132     *hbuffer = appnewhandle (ctbytes);
00133     
00134     return (*hbuffer != nil); /*shouldn't fail at this point, but let's be sure*/
00135     } /*largefilebuffer*/
00136 
00137 
00138 static boolean openforkforcopy (FSSpec *fs, boolean flresource, short *fnum) {
00139     
00140     /*
00141     we need a special entry-point to allow the userprogram to copy a file that's
00142     already open.  we checked this with the debugger -- FSOpen returns the right
00143     fnum for our file.
00144     
00145     3/2/92 dmb: rewrote using PBOpen asking for read-only permission.  removed 
00146     fldontclose parameter.  also, support either fork with this routine
00147     */
00148     
00149     OSErr errcode;
00150     HParamBlockRec pb;
00151     
00152     clearbytes (&pb, longsizeof (pb));
00153     
00154     pb.fileParam.ioDirID = (*fs).parID;
00155     
00156     pb.ioParam.ioNamePtr = (*fs).name;
00157     
00158     pb.ioParam.ioVRefNum = (*fs).vRefNum;
00159     
00160     pb.ioParam.ioPermssn = fsRdPerm;
00161     
00162     if (flresource)
00163         errcode = PBHOpenRFSync (&pb);
00164     else
00165         errcode = PBHOpenSync (&pb);
00166     
00167     *fnum = pb.ioParam.ioRefNum;
00168     
00169     if (fileerror (fs, errcode)) 
00170         return (false);
00171         
00172     return (true);
00173     } /*openforkforcopy*/
00174     
00175 
00176 static boolean copyonefile (FSSpec *fsource, FSSpec *fdest, boolean fldata, boolean flresources) {
00177 
00178     /*
00179     create a copy of the indicated file in the destination volume, with the indicated
00180     name.  
00181     
00182     we allocate a good-sized buffer in the heap, then open and copy the data fork then
00183     open and copy the resource fork of the source file.
00184     
00185     return true if the operation was successful, false otherwise.
00186     
00187     7/27/90 DW: add fldata, flresources -- allows selective copying of the two
00188     forks of each file.  we assume one of these two booleans is true.
00189     
00190     3/2/92 dmb: use new openforkforcopy to safely open in-use file forks for copying
00191     
00192     3/16/92 dmb: maintain all public Finder flags, not just creator/type & dates
00193     */
00194     
00195     Handle hbuffer;
00196     register OSErr errcode;
00197     short sourcerefnum = 0, destrefnum = 0;
00198     OSType filetype, filecreator;
00199     CInfoPBRec pb;
00200     CInfoPBRec pb2;
00201     unsigned short publicflags = 0xFCCE; /*non-reserved Finder flags as per IM-VI 9-37*/
00202     
00203     if (!largefilebuffer (&hbuffer)) 
00204         return (false);
00205     
00206     if (!getmacfileinfo (fsource, &pb)) 
00207         goto error;
00208     
00209     filecreator = pb.hFileInfo.ioFlFndrInfo.fdCreator;
00210     
00211     filetype = pb.hFileInfo.ioFlFndrInfo.fdType;
00212     
00213     setfileerrorfile (fsource);
00214         
00215     if (fldata) {
00216     
00217         if (!openforkforcopy (fsource, false, &sourcerefnum))
00218             goto error;
00219         
00220         if (!filenew (fdest, filecreator, filetype, &destrefnum)) 
00221             goto error;
00222         
00223         if (!copyfork (sourcerefnum, destrefnum, hbuffer)) /*copy data fork*/
00224             goto error;
00225         
00226         fileclose (sourcerefnum); 
00227             
00228         fileclose (destrefnum); 
00229         
00230         sourcerefnum = 0;
00231         
00232         destrefnum = 0;
00233         }
00234     
00235     if (flresources) {
00236         
00237         if (!openforkforcopy (fsource, true, &sourcerefnum))
00238             goto error;
00239         
00240         errcode = FSpOpenRF (fdest, fsWrPerm, &destrefnum);
00241         
00242         if (fileerror (fdest, errcode))
00243             goto error;
00244         
00245         if (!copyfork (sourcerefnum, destrefnum, hbuffer)) /*copy resource fork*/
00246             goto error;
00247         
00248         fileclose (sourcerefnum);
00249             
00250         fileclose (destrefnum); 
00251         
00252         sourcerefnum = 0;
00253         
00254         destrefnum = 0;
00255         }
00256     
00257     disposehandle (hbuffer);
00258     
00259     hbuffer = nil; /*if error don't dispose of it again*/
00260     
00261     if (!getmacfileinfo (fdest, &pb2)) 
00262         goto error;
00263      
00264     pb2.hFileInfo.ioFlCrDat = pb.hFileInfo.ioFlCrDat;
00265     
00266     pb2.hFileInfo.ioFlMdDat = pb.hFileInfo.ioFlMdDat;
00267     
00268     pb2.hFileInfo.ioFlFndrInfo.fdFlags = (pb.hFileInfo.ioFlFndrInfo.fdFlags & publicflags);
00269     
00270     if (!setmacfileinfo (fdest, &pb2))
00271         goto error;
00272     
00273     filecopycomment (fsource, fdest);
00274     
00275     return (true); /*the file copy was successful*/
00276     
00277     error: /*goto here to release the buffer, close files and return false*/
00278     
00279     if (hbuffer != nil)
00280         disposehandle (hbuffer);
00281     
00282     if (sourcerefnum != 0)
00283         fileclose (sourcerefnum);
00284     
00285     if (destrefnum != 0)
00286         fileclose (destrefnum);
00287     
00288     filedelete (fdest); /*no file created on error*/
00289     
00290     return (false);
00291     } /*copyonefile*/
00292 
00293 
00294 boolean foldercopy (ptrfilespec fssource, ptrfilespec fsdest, long *dirid) {
00295     
00296     OSErr ec;
00297     
00298     ec = FSpDirCreate (fsdest, smSystemScript, dirid);
00299     
00300     if (ec != noErr) {
00301         
00302         fileerror (fssource, ec);
00303         
00304         return (false);
00305         }
00306     
00307     /*copy folder attributes from source to dest*/ {
00308         
00309         CInfoPBRec pb;
00310         
00311         if (getmacfileinfo (fssource, &pb)) {
00312             
00313             assert (pb.dirInfo.ioFlAttrib == 16); /*just the folder bit set*/
00314             
00315             setmacfileinfo (fsdest, &pb);
00316             }   
00317         }
00318     
00319     filecopycomment (fssource, fsdest);
00320     
00321     return (true);
00322     } /*foldercopy*/
00323     
00324 
00325 boolean filteredcopy (FSSpec *, FSSpec *); /*prototype*/
00326 
00327 
00328 static boolean foldercopyvisit (bigstring bsitem, tyfileinfo *info, long refcon) {
00329     
00330     register FSSpec *fsfolder = (FSSpec *) refcon;
00331     FSSpec fssource, fsdest;
00332     
00333     filemakespec ((*info).vnum, (*info).dirid, bsitem, &fssource);
00334     
00335     filegetsubitemspec (fsfolder, bsitem, &fsdest);
00336     
00337     return (filteredcopy (&fssource, &fsdest));
00338     } /*foldercopyvisit*/
00339 
00340 
00341 static tyfilecopycallback copyfilter = nil;
00342 
00343 
00344 boolean filteredcopy (FSSpec *fssource, FSSpec *fsdest) {
00345     
00346     tyfileinfo info;
00347     
00348     /*call the copy filter callback*/ {
00349         
00350         if (copyfilter != nil) {
00351             
00352             boolean flskipfile, flcancel;
00353             
00354             flcancel = false; 
00355             
00356             flskipfile = false;
00357             
00358             (*copyfilter) (fssource, fsdest, &flskipfile, &flcancel);
00359             
00360             if (flcancel)
00361                 return (false);
00362             
00363             if (flskipfile) 
00364                 return (true);
00365             }
00366         }
00367         
00368     filegetinfo (fssource, &info);
00369     
00370     if (info.flfolder) {
00371         
00372         FSSpec fsfolder;
00373         long dirid;
00374         
00375         if (!foldercopy (fssource, fsdest, &dirid))
00376             return (false);
00377         
00378         getfolderfilespec ((*fsdest).vRefNum, dirid, &fsfolder);
00379         
00380         return (folderloop (fssource, false, &foldercopyvisit, (long) &fsfolder));
00381         }
00382         
00383     if (info.flalias) {
00384         
00385         if (!fileresolvealias (fssource, true))
00386             return (false);
00387             
00388         return (filemakealias (fssource, fsdest));
00389         }
00390         
00391     return (copyonefile (fssource, fsdest, true, true));
00392     } /*filteredcopy*/
00393 
00394 
00395 boolean filecopy (FSSpec *fssource, FSSpec *fsdest, tyfilecopycallback callback) {
00396     
00397     /*
00398     copies a file, folder or alias
00399     
00400     we callback to you on everything we copy. you can tell us to skip the file
00401     or folder, or you can cancel the copy.
00402     */
00403     
00404     copyfilter = callback;
00405     
00406     return (filteredcopy (fssource, fsdest));
00407     } /*filecopy*/
00408 
00409 
00410 
00411 
00412 

Generated on Wed May 31 18:19:41 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6