• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/amule/wxWidgets-2.8.12/src/mac/classic/morefile/
1/*
2	File:		FileCopy.c
3
4	Contains:	A robust, general purpose file copy routine.
5
6	Version:	MoreFiles
7
8	Copyright:	� 1992-2001 by Apple Computer, Inc., all rights reserved.
9
10	You may incorporate this sample code into your applications without
11	restriction, though the sample code has been provided "AS IS" and the
12	responsibility for its operation is 100% yours.  However, what you are
13	not permitted to do is to redistribute the source as "DSC Sample Code"
14	after having made changes. If you're going to re-distribute the source,
15	we require that you make it clear in the source that the code was
16	descended from Apple Sample Code, but that you've made changes.
17
18	File Ownership:
19
20		DRI:				Apple Macintosh Developer Technical Support
21
22		Other Contact:		Apple Macintosh Developer Technical Support
23							<http://developer.apple.com/bugreporter/>
24
25		Technology:			DTS Sample Code
26
27	Writers:
28
29		(JL)	Jim Luther
30
31	Change History (most recent first):
32
33		 <2>	  2/7/01	JL		Added standard header. Updated names of includes. Updated
34									various routines to use new calling convention of the
35									MoreFilesExtras accessor functions.
36		<1>		12/06/99	JL		MoreFiles 1.5.
37*/
38
39#include <MacTypes.h>
40#include <MacErrors.h>
41#include <MacMemory.h>
42#include <Files.h>
43#include <Math64.h>
44
45#define	__COMPILINGMOREFILES
46
47#include "MoreFiles.h"
48#include "MoreFilesExtras.h"
49#include "MoreDesktopMgr.h"
50#include "FileCopy.h"
51
52/*****************************************************************************/
53
54/* local constants */
55
56/*	The deny-mode privileges to use when opening the source and destination files. */
57
58enum
59{
60	srcCopyMode = dmRdDenyWr,
61	dstCopyMode = dmWrDenyRdWr
62};
63
64/*	The largest (16K) and smallest (.5K) copy buffer to use if the caller doesn't supply
65**	their own copy buffer. */
66
67enum
68{
69	bigCopyBuffSize  = 0x00004000,
70	minCopyBuffSize  = 0x00000200
71};
72
73/*****************************************************************************/
74
75/* static prototypes */
76
77static	OSErr	GetDestinationDirInfo(short vRefNum,
78									  long dirID,
79									  ConstStr255Param name,
80									  long *theDirID,
81									  Boolean *isDirectory,
82									  Boolean *isDropBox);
83/*	GetDestinationDirInfo tells us if the destination is a directory, it's
84	directory ID, and if it's an AppleShare drop box (write privileges only --
85	no read or search privileges).
86	vRefNum		input:	Volume specification.
87	dirID		input:	Directory ID.
88	name		input:	Pointer to object name, or nil when dirID
89						specifies a directory that's the object.
90	theDirID	output:	If the object is a file, then its parent directory
91						ID. If the object is a directory, then its ID.
92	isDirectory	output:	True if object is a directory; false if
93						object is a file.
94	isDropBox	output:	True if directory is an AppleShare drop box.
95*/
96
97static	OSErr	CheckForForks(short vRefNum,
98							  long dirID,
99							  ConstStr255Param name,
100							  Boolean *hasDataFork,
101							  Boolean *hasResourceFork);
102/*	CheckForForks tells us if there is a data or resource fork to copy.
103	vRefNum		input:	Volume specification of the file's current
104							location.
105	dirID		input:	Directory ID of the file's current location.
106	name		input:	The name of the file.
107*/
108
109static	OSErr	PreflightFileCopySpace(short srcVRefNum,
110									   long srcDirID,
111									   ConstStr255Param srcName,
112									   ConstStr255Param dstVolName,
113									   short dstVRefNum,
114									   Boolean *spaceOK);
115/*	PreflightFileCopySpace determines if there's enough space on a
116	volume to copy the specified file to that volume.
117	Note: The results of this routine are not perfect. For example if the
118	volume's catalog or extents overflow file grows when the new file is
119	created, more allocation blocks may be needed beyond those needed for
120	the file's data and resource forks.
121
122	srcVRefNum		input:	Volume specification of the file's current
123							location.
124	srcDirID		input:	Directory ID of the file's current location.
125	srcName			input:	The name of the file.
126	dstVolName		input:	A pointer to the name of the volume where
127							the file will be copied or NULL.
128	dstVRefNum		input:	Volume specification indicating the volume
129							where the file will be copied.
130	spaceOK			output:	true if there's enough space on the volume for
131							the file's data and resource forks.
132*/
133
134/*****************************************************************************/
135
136static	OSErr	GetDestinationDirInfo(short vRefNum,
137									  long dirID,
138									  ConstStr255Param name,
139									  long *theDirID,
140									  Boolean *isDirectory,
141									  Boolean *isDropBox)
142{
143	CInfoPBRec pb;
144	OSErr error;
145
146	pb.dirInfo.ioACUser = 0;	/* ioACUser used to be filler2, clear it before calling GetCatInfo */
147	error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
148	*theDirID = pb.dirInfo.ioDrDirID;
149	*isDirectory = (pb.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0;
150	/* see if access priviledges are make changes, not see folder, and not see files (drop box) */
151	*isDropBox = userHasDropBoxAccess(pb.dirInfo.ioACUser);
152
153	return ( error );
154}
155
156/*****************************************************************************/
157
158static	OSErr	CheckForForks(short vRefNum,
159							  long dirID,
160							  ConstStr255Param name,
161							  Boolean *hasDataFork,
162							  Boolean *hasResourceFork)
163{
164	HParamBlockRec pb;
165	OSErr error;
166
167	pb.fileParam.ioNamePtr = (StringPtr)name;
168	pb.fileParam.ioVRefNum = vRefNum;
169	pb.fileParam.ioFVersNum = 0;
170	pb.fileParam.ioDirID = dirID;
171	pb.fileParam.ioFDirIndex = 0;
172	error = PBHGetFInfoSync(&pb);
173	*hasDataFork = (pb.fileParam.ioFlLgLen != 0);
174	*hasResourceFork = (pb.fileParam.ioFlRLgLen != 0);
175
176	return ( error );
177}
178
179/*****************************************************************************/
180
181static	OSErr	PreflightFileCopySpace(short srcVRefNum,
182									   long srcDirID,
183									   ConstStr255Param srcName,
184									   ConstStr255Param dstVolName,
185									   short dstVRefNum,
186									   Boolean *spaceOK)
187{
188	UniversalFMPB pb;
189	OSErr error;
190	unsigned long dstFreeBlocks;
191	unsigned long dstBlksPerAllocBlk;
192	unsigned long srcDataBlks;
193	unsigned long srcResourceBlks;
194
195	error = XGetVolumeInfoNoName(dstVolName, dstVRefNum, &pb.xPB);
196	if ( error == noErr )
197	{
198		/* get allocation block size (always multiple of 512) and divide by 512
199		  to get number of 512-byte blocks per allocation block */
200		dstBlksPerAllocBlk = ((unsigned long)pb.xPB.ioVAlBlkSiz >> 9);
201
202		/* Convert freeBytes to free disk blocks (512-byte blocks) */
203		dstFreeBlocks = U32SetU(U64ShiftRight(pb.xPB.ioVFreeBytes, 9));
204
205		/* Now, get the size of the file's data resource forks */
206		pb.hPB.fileParam.ioNamePtr = (StringPtr)srcName;
207		pb.hPB.fileParam.ioVRefNum = srcVRefNum;
208		pb.hPB.fileParam.ioFVersNum = 0;
209		pb.hPB.fileParam.ioDirID = srcDirID;
210		pb.hPB.fileParam.ioFDirIndex = 0;
211		error = PBHGetFInfoSync(&pb.hPB);
212		if ( error == noErr )
213		{
214			/* Since space on Mac OS disks is always allocated in allocation blocks, */
215			/* this code takes into account rounding up to the end of an allocation block. */
216
217			/* get number of 512-byte blocks needed for data fork */
218			if ( ((unsigned long)pb.hPB.fileParam.ioFlLgLen & 0x000001ff) != 0 )
219			{
220				srcDataBlks = ((unsigned long)pb.hPB.fileParam.ioFlLgLen >> 9) + 1;
221			}
222			else
223			{
224				srcDataBlks = (unsigned long)pb.hPB.fileParam.ioFlLgLen >> 9;
225			}
226
227			/* now, calculate number of new allocation blocks needed */
228			if ( srcDataBlks % dstBlksPerAllocBlk )
229			{
230				srcDataBlks = (srcDataBlks / dstBlksPerAllocBlk) + 1;
231			}
232			else
233			{
234				srcDataBlks /= dstBlksPerAllocBlk;
235			}
236
237			/* get number of 512-byte blocks needed for resource fork */
238			if ( ((unsigned long)pb.hPB.fileParam.ioFlRLgLen & 0x000001ff) != 0 )
239			{
240				srcResourceBlks = ((unsigned long)pb.hPB.fileParam.ioFlRLgLen >> 9) + 1;
241			}
242			else
243			{
244				srcResourceBlks = (unsigned long)pb.hPB.fileParam.ioFlRLgLen >> 9;
245			}
246
247			/* now, calculate number of new allocation blocks needed */
248			if ( srcResourceBlks % dstBlksPerAllocBlk )
249			{
250				srcResourceBlks = (srcResourceBlks / dstBlksPerAllocBlk) + 1;
251			}
252			else
253			{
254				srcResourceBlks /= dstBlksPerAllocBlk;
255			}
256
257			/* Is there enough room on the destination volume for the source file? */
258			*spaceOK = ( ((srcDataBlks + srcResourceBlks) * dstBlksPerAllocBlk) <= dstFreeBlocks );
259		}
260	}
261
262	return ( error );
263}
264
265/*****************************************************************************/
266
267pascal	OSErr	FileCopy(short srcVRefNum,
268						 long srcDirID,
269						 ConstStr255Param srcName,
270						 short dstVRefNum,
271						 long dstDirID,
272						 ConstStr255Param dstPathname,
273						 ConstStr255Param copyName,
274						 void *copyBufferPtr,
275						 long copyBufferSize,
276						 Boolean preflight)
277{
278	OSErr	err;
279
280	short	srcRefNum = 0,			/* 0 when source data and resource fork are closed  */
281			dstDataRefNum = 0,		/* 0 when destination data fork is closed */
282			dstRsrcRefNum = 0;		/* 0 when destination resource fork is closed */
283
284	Str63	dstName;				/* The filename of the destination. It might be the
285									** source filename, it might be a new name... */
286
287	GetVolParmsInfoBuffer infoBuffer; /* Where PBGetVolParms dumps its info */
288	long	srcServerAdr;			/* AppleTalk server address of source (if any) */
289
290	Boolean	dstCreated = false,		/* true when destination file has been created */
291			ourCopyBuffer = false,	/* true if we had to allocate the copy buffer */
292			isDirectory,			/* true if destination is really a directory */
293			isDropBox;				/* true if destination is an AppleShare drop box */
294
295	long	tempLong;
296	short	tempInt;
297
298	Boolean	spaceOK;				/* true if there's enough room to copy the file to the destination volume */
299
300	Boolean	hasDataFork;
301	Boolean	hasResourceFork;
302
303	/* Preflight for size */
304	if ( preflight )
305	{
306		err = PreflightFileCopySpace(srcVRefNum, srcDirID, srcName,
307									 dstPathname, dstVRefNum, &spaceOK);
308		if ( err != noErr )
309		{
310			return ( err );
311		}
312
313		if ( !spaceOK )
314		{
315			return ( dskFulErr );
316		}
317	}
318
319	/* get the destination's real dirID and make sure it really is a directory */
320	err = GetDestinationDirInfo(dstVRefNum, dstDirID, dstPathname,
321								&dstDirID, &isDirectory, &isDropBox);
322	if ( err != noErr )
323	{
324		goto ErrorExit;
325	}
326
327	if ( !isDirectory )
328	{
329		return ( dirNFErr );
330	}
331
332	/* get the destination's real vRefNum */
333	err = DetermineVRefNum(dstPathname, dstVRefNum, &dstVRefNum);
334	if ( err != noErr )
335	{
336		goto ErrorExit;
337	}
338
339	/* See if PBHCopyFile can be used.  Using PBHCopyFile saves time by letting the file server
340	** copy the file if the source and destination locations are on the same file server. */
341	tempLong = sizeof(infoBuffer);
342	err = HGetVolParms(srcName, srcVRefNum, &infoBuffer, &tempLong);
343	if ( (err != noErr) && (err != paramErr) )
344	{
345		return ( err );
346	}
347
348	if ( (err != paramErr) && hasCopyFile(&infoBuffer) )
349	{
350		/* The source volume supports PBHCopyFile. */
351		srcServerAdr = infoBuffer.vMServerAdr;
352
353		/* Now, see if the destination volume is on the same file server. */
354		tempLong = sizeof(infoBuffer);
355		err = HGetVolParms(NULL, dstVRefNum, &infoBuffer, &tempLong);
356		if ( (err != noErr) && (err != paramErr) )
357		{
358			return ( err );
359		}
360		if ( (err != paramErr) && (srcServerAdr == infoBuffer.vMServerAdr) )
361		{
362			/* Source and Dest are on same server and PBHCopyFile is supported. Copy with CopyFile. */
363			err = HCopyFile(srcVRefNum, srcDirID, srcName, dstVRefNum, dstDirID, NULL, copyName);
364			if ( err != noErr )
365			{
366				return ( err );
367			}
368
369			/* AppleShare's CopyFile clears the isAlias bit, so I still need to attempt to copy
370			   the File's attributes to attempt to get things right. */
371			if ( copyName != NULL )				/* Did caller supply copy file name? */
372			{
373				/* Yes, use the caller supplied copy file name. */
374				(void) CopyFileMgrAttributes(srcVRefNum, srcDirID, srcName,
375											 dstVRefNum, dstDirID, copyName, true);
376			}
377			else
378			{
379				/* They didn't, so get the source file name and use it. */
380				if ( GetFilenameFromPathname(srcName, dstName) == noErr )
381				{
382					/* */
383					(void) CopyFileMgrAttributes(srcVRefNum, srcDirID, srcName,
384												 dstVRefNum, dstDirID, dstName, true);
385				}
386			}
387			return ( err );
388		}
389	}
390
391	/* If we're here, then PBHCopyFile couldn't be used so we have to copy the file by hand. */
392
393	/* Make sure a copy buffer is allocated. */
394	if ( copyBufferPtr == NULL )
395	{
396		/* The caller didn't supply a copy buffer so grab one from the application heap.
397		** Try to get a big copy buffer, if we can't, try for a 512-byte buffer.
398		** If 512 bytes aren't available, we're in trouble. */
399		copyBufferSize = bigCopyBuffSize;
400		copyBufferPtr = NewPtr(copyBufferSize);
401		if ( copyBufferPtr == NULL )
402		{
403			copyBufferSize = minCopyBuffSize;
404			copyBufferPtr = NewPtr(copyBufferSize);
405			if ( copyBufferPtr == NULL )
406			{
407				return ( memFullErr );
408			}
409		}
410		ourCopyBuffer = true;
411	}
412
413	/* Open the source data fork. */
414	err = HOpenAware(srcVRefNum, srcDirID, srcName, srcCopyMode, &srcRefNum);
415	if ( err != noErr )
416		return ( err );
417
418	/* Once a file is opened, we have to exit via ErrorExit to make sure things are cleaned up */
419
420	/* See if the copy will be renamed. */
421	if ( copyName != NULL )				/* Did caller supply copy file name? */
422		BlockMoveData(copyName, dstName, copyName[0] + 1);	/* Yes, use the caller supplied copy file name. */
423	else
424	{	/* They didn't, so get the source file name and use it. */
425		err = GetFileLocation(srcRefNum, &tempInt, &tempLong, dstName);
426		if ( err != noErr )
427		{
428			goto ErrorExit;
429		}
430	}
431
432	/* Create the destination file. */
433	err = HCreateMinimum(dstVRefNum, dstDirID, dstName);
434	if ( err != noErr )
435	{
436		goto ErrorExit;
437	}
438	dstCreated = true;	/* After creating the destination file, any
439						** error conditions should delete the destination file */
440
441	/* An AppleShare dropbox folder is a folder for which the user has the Make Changes
442	** privilege (write access), but not See Files (read access) and See Folders (search access).
443	** Copying a file into an AppleShare dropbox presents some special problems. Here are the
444	** rules we have to follow to copy a file into a dropbox:
445	** � File attributes can be changed only when both forks of a file are empty.
446	** � DeskTop Manager comments can be added to a file only when both forks of a file
447	**   are empty.
448	** � A fork can be opened for write access only when both forks of a file are empty.
449	** So, with those rules to live with, we'll do those operations now while both forks
450	** are empty. */
451
452	if ( isDropBox )
453	{
454		/* We only set the file attributes now if the file is being copied into a
455		** drop box. In all other cases, it is better to set the attributes last
456		** so that if FileCopy is modified to give up time to other processes
457		** periodicly, the Finder won't try to read any bundle information (because
458		** the bundle-bit will still be clear) from a partially copied file. If the
459		** copy is into a drop box, we have to set the attributes now, but since the
460		** destination forks are opened with write/deny-read/deny-write permissions,
461		** any Finder that might see the file in the drop box won't be able to open
462		** its resource fork until the resource fork is closed.
463		**
464		** Note: if you do modify FileCopy to give up time to other processes, don't
465		** give up time between the time the destination file is created (above) and
466		** the time both forks are opened (below). That way, you stand the best chance
467		** of making sure the Finder doesn't read a partially copied resource fork.
468		*/
469		/* Copy attributes but don't lock the destination. */
470		err = CopyFileMgrAttributes(srcVRefNum, srcDirID, srcName,
471									dstVRefNum, dstDirID, dstName, false);
472		if ( err != noErr )
473		{
474			goto ErrorExit;
475		}
476	}
477
478	/* Attempt to copy the comments while both forks are empty.
479	** Ignore the result because we really don't care if it worked or not. */
480	(void) DTCopyComment(srcVRefNum, srcDirID, srcName, dstVRefNum, dstDirID, dstName);
481
482	/* See which forks we need to copy. By doing this, we won't create a data or resource fork
483	** for the destination unless it's really needed (some foreign file systems such as
484	** the ProDOS File System and Macintosh PC Exchange have to create additional disk
485	** structures to support resource forks). */
486	err = CheckForForks(srcVRefNum, srcDirID, srcName, &hasDataFork, &hasResourceFork);
487	if ( err != noErr )
488	{
489		goto ErrorExit;
490	}
491
492	if ( hasDataFork )
493	{
494		/* Open the destination data fork. */
495		err = HOpenAware(dstVRefNum, dstDirID, dstName, dstCopyMode, &dstDataRefNum);
496		if ( err != noErr )
497		{
498			goto ErrorExit;
499		}
500	}
501
502	if ( hasResourceFork )
503	{
504		/* Open the destination resource fork. */
505		err = HOpenRFAware(dstVRefNum, dstDirID, dstName, dstCopyMode, &dstRsrcRefNum);
506		if ( err != noErr )
507		{
508			goto ErrorExit;
509		}
510	}
511
512	if ( hasDataFork )
513	{
514		/* Copy the data fork. */
515		err = CopyFork(srcRefNum, dstDataRefNum, copyBufferPtr, copyBufferSize);
516		if ( err != noErr )
517		{
518			goto ErrorExit;
519		}
520
521		/* Close both data forks and clear reference numbers. */
522		(void) FSClose(srcRefNum);
523		(void) FSClose(dstDataRefNum);
524		srcRefNum = dstDataRefNum = 0;
525	}
526	else
527	{
528		/* Close the source data fork since it was opened earlier */
529		(void) FSClose(srcRefNum);
530		srcRefNum = 0;
531	}
532
533	if ( hasResourceFork )
534	{
535		/* Open the source resource fork. */
536		err = HOpenRFAware(srcVRefNum, srcDirID, srcName, srcCopyMode, &srcRefNum);
537		if ( err != noErr )
538		{
539			goto ErrorExit;
540		}
541
542		/* Copy the resource fork. */
543		err = CopyFork(srcRefNum, dstRsrcRefNum, copyBufferPtr, copyBufferSize);
544		if ( err != noErr )
545		{
546			goto ErrorExit;
547		}
548
549		/* Close both resource forks and clear reference numbers. */
550		(void) FSClose(srcRefNum);
551		(void) FSClose(dstRsrcRefNum);
552		srcRefNum = dstRsrcRefNum = 0;
553	}
554
555	/* Get rid of the copy buffer if we allocated it. */
556	if ( ourCopyBuffer )
557	{
558		DisposePtr((Ptr)copyBufferPtr);
559	}
560
561	/* Attempt to copy attributes again to set mod date.  Copy lock condition this time
562	** since we're done with the copy operation.  This operation will fail if we're copying
563	** into an AppleShare dropbox, so we don't check for error conditions. */
564	CopyFileMgrAttributes(srcVRefNum, srcDirID, srcName,
565							dstVRefNum, dstDirID, dstName, true);
566
567	/* Hey, we did it! */
568	return ( noErr );
569
570ErrorExit:
571	if ( srcRefNum != 0 )
572	{
573		(void) FSClose(srcRefNum);		/* Close the source file */
574	}
575	if ( dstDataRefNum != 0 )
576	{
577		(void) FSClose(dstDataRefNum);	/* Close the destination file data fork */
578	}
579	if ( dstRsrcRefNum != 0 )
580	{
581		(void) FSClose(dstRsrcRefNum);	/* Close the destination file resource fork */
582	}
583	if ( dstCreated )
584	{
585		(void) HDelete(dstVRefNum, dstDirID, dstName);	/* Delete dest file.  This may fail if the file
586												   is in a "drop folder" */
587	}
588	if ( ourCopyBuffer )	/* dispose of any memory we allocated */
589	{
590		DisposePtr((Ptr)copyBufferPtr);
591	}
592
593	return ( err );
594}
595
596/*****************************************************************************/
597
598pascal	OSErr	FSpFileCopy(const FSSpec *srcSpec,
599							const FSSpec *dstSpec,
600							ConstStr255Param copyName,
601							void *copyBufferPtr,
602							long copyBufferSize,
603							Boolean preflight)
604{
605	return ( FileCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
606					 dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
607					 copyName, copyBufferPtr, copyBufferSize, preflight) );
608}
609
610/*****************************************************************************/
611
612