forgotten commit. disabled until egl is adapted.
[AROS-Contrib.git] / Misc / SortCopy / SortCopy.c
blob4c72239219fc76e165339585d8fac4fb4d4c1abe
1 /*
2 Copyright © 2000, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: SortCopy from Thomas Richter
6 Lang: English
7 */
9 /*****************************************************************
10 ** SortCopy **
11 ** © 1996-2000 THOR-Software **
12 ** Version 1.34 **
13 ** sortiert kopieren **
14 ** (Hard)Links mitlinken **
15 *****************************************************************/
17 /* Converted to AROS by SDuvan 18.11.2000 (some bugs fixed too) */
19 /// Includes
20 #include <exec/types.h>
21 #include <exec/nodes.h>
22 #include <exec/lists.h>
23 #include <exec/memory.h>
24 #include <exec/alerts.h>
25 #define DOS_IO 1
26 #include <dos/dos.h>
27 #include <dos/dosextens.h>
28 #include <dos/dosasl.h>
30 #include <proto/alib.h>
31 #include <proto/exec.h>
32 #include <proto/dos.h>
33 #include <proto/utility.h>
35 #ifdef __AROS__
36 #define DEBUG 1
37 #include <aros/debug.h>
38 #include <exec/rawfmt.h>
39 #else
40 #define D(x)
41 #include <thor/tinyio.h>
42 #include <dos.h>
44 extern void __builtin__emit(int);
45 #define BreakPoint __builtin_emit(0x4afc)
46 #endif
48 #include <strings.h>
49 #include <stdarg.h>
51 ///
52 /// Defines
53 #define SIGMASK (1<<12)
54 #define MAXSOFTNEST 16
55 #define BUFFERSIZE 2048
57 ///
58 ///Strukturen
59 /* Verwaltung eines Eintrages in der Directory */
61 struct DirEntry
63 struct DirEntry *de_next;
64 struct DirEntry *de_pred;
65 ULONG de_flags; /* Siehe unten */
66 LONG de_protection;
67 struct DateStamp de_date;
68 ULONG de_length;
69 BPTR de_sourcelock; /* Nur in Sonderfällen: Lock auf
70 die Quelldirectory */
71 BPTR de_dirlock; /* Nur bei Links verwendet: BPTR
72 Directory, wo der Link hinsoll
73 (Ziel!) */
74 BPTR de_linklock; /* Bei Links: Directory, in dem
75 das Objekt liegt, zu dem der
76 Link besteht */
77 struct MinList de_sublist;
78 char de_name[MAXFILENAMELENGTH];
79 char de_comment[MAXCOMMENTLENGTH];
81 /* Name des Zielobjektes (Quellobject, d.h. Name des Links) in name */
82 char de_linkname[MAXFILENAMELENGTH];
86 /* Einträge in den Flags */
87 #define DEF_SOFTLINK (1 << 0) /* entry is a softlink */
88 #define DEF_HARDLINK (1 << 1) /* entry is a hardlink */
89 #define DEF_DIR (1 << 2) /* entry is a directory */
90 #define DEF_FORGET (1 << 3) /* failed to copy, ignore */
91 #define DEF_NORESOLVE (1 << 4) /* failed to read the link, do not resolve */
92 #define DEF_CREATED (1 << 5) /* directory has been created */
93 #define DEF_FLATDIR (1 << 6) /* directory wasn't created, contents
94 was copied */
95 #define DEF_REMOVED (1 << 7) /* directory has been removed */
98 /* Diese Node wird zum Kopieren von Files verwendet. */
100 struct CopyNode
102 struct Message cn_DosMessage; /* a message for the DOS process */
103 struct DosPacket cn_DosPacket; /* the message to be posted */
104 APTR cn_Buffer; /* Pointer to the buffer */
105 ULONG cn_BufSize; /* size of the buffer to allocate */
106 ULONG cn_WriteSize; /* number of bytes to be written out */
107 UWORD cn_Command; /* last command sent */
108 BOOL cn_release; /* release me? */
109 struct CopyNode *cn_BackTick; /* just to make sure that this is
110 our packet */
114 /// Statics
116 // These should be allocated by AllocDosObject()
117 struct FileInfoBlock fib;
118 struct FileInfoBlock dirfib;
119 struct AnchorPath ap;
121 struct DosLibrary *DOSBase;
122 struct UtilityBase *UtilityBase;
124 BOOL abortFlag;
125 BOOL failcondition;
126 IPTR tclower;
127 ULONG depth;
128 ULONG scount;
129 ULONG bufsize;
130 BPTR rootlock;
132 struct MinList resolvelist;
134 BOOL quiet, quieter, seta, onlya, overwrite, leaveempty, deletecopied,
135 force, update;
136 BOOL purge, nocopy, sourcewild;
138 UBYTE buffer[BUFFERSIZE];
139 char failbuffer[512];
141 struct CopyNode lastchancenode;
142 struct MsgPort ioport;
144 BOOL lastchancebusy;
146 char version[] = "$VER: SortCopy 41.1 (18.11.2000)";
150 /// Prototypes
152 void PostFailure(LONG error, char *failtext, ...);
153 BOOL ReadDir(BPTR lock, struct MinList *dirlist, char *name);
154 BOOL CopyFile(BPTR source, BPTR dest, char *name);
155 BOOL CopyDir(BPTR sourcelock, BPTR destlock, struct MinList *dirlist);
156 void Abort(void);
157 BOOL CheckAbort(void);
158 BOOL RecursiveCopy(BPTR source, BPTR dest, struct MinList *dirlist, char *name);
159 void FreeDirList(struct MinList *dirlist, BOOL links);
160 BOOL IsDir(BPTR lock, char *name);
161 BOOL FindSoftOrginal(struct DirEntry *de);
162 BOOL FindHardOrginal(struct DirEntry *de);
163 BOOL PathRelative(BPTR relpath, BPTR path, char *name, char *buffer,
164 ULONG bufsize);
165 BOOL ResolveLinks(struct MinList *list, BPTR dest);
166 BOOL CreateLink(char *name, BPTR melock, char *linkname, BPTR linklock,
167 ULONG soft);
168 void OFlush(void);
169 BOOL CloneFlags(struct DirEntry *de);
170 ULONG CopyMain(char *sourcename, char *destname);
171 BOOL SetAFlag(struct DirEntry *de);
172 void DoIndent(void);
173 BOOL DirEmpty(BPTR lock, char *name);
174 BOOL KillForce(char *name, BOOL force);
175 BOOL RecursiveDelete(BPTR lock, struct MinList *dirlist, BOOL all, char *name);
176 void DeleteEntry(struct DirEntry *de, BOOL all);
177 BOOL RecursiveSetA(BPTR source, struct MinList *dirlist, char *name);
178 LONG Fatal(void);
179 BOOL PurgeDir(BPTR sourcelock, BPTR destlock, struct MinList *dirlist,
180 char *name);
181 void FreeDirEntry(struct DirEntry *de, BOOL locks);
182 BOOL FindDirEntry(struct MinList *dirlist, struct DirEntry *de);
183 BOOL DeleteDirList(BPTR source, struct MinList *dirlist, BOOL all);
184 BOOL MustUpdate(BPTR destlock, struct DirEntry *de);
185 BOOL CopyFileEntry(struct DirEntry *de, BPTR sourcelock, BPTR destlock);
186 BOOL CopyDirEntry(struct DirEntry *de, BPTR sourcelock, BPTR destlock);
187 struct DirEntry *AllocDirEntry(struct FileInfoBlock *fib);
188 ULONG CopyBodyMatch(struct AnchorPath *ap, char *pattern, BPTR source,
189 BPTR dest);
190 BOOL FillDirEntry(struct DirEntry *de, struct FileInfoBlock *fib);
191 BOOL CopyEntry(struct DirEntry *de, BPTR sourcelock, BPTR destlock);
192 BOOL CopySubDirectory(struct DirEntry *de, BPTR source, BPTR dest);
193 BOOL PrepareLink(struct DirEntry *de, BPTR source, BPTR dest);
194 void EnqueueEntry(struct MinList *dirlist, struct DirEntry *de);
195 BOOL CopyEntryList(struct MinList *dirlist, BPTR dest);
196 BOOL AddMatch(struct AnchorPath *ap, struct MinList *dirlist);
197 struct DirEntry *DupDirEntry(struct DirEntry *se);
198 BOOL DupDirList(struct MinList *source, struct MinList *dest);
199 BOOL SetAList(BPTR source, struct MinList *dirlist);
200 ULONG FillDirList(char *pattern, struct MinList *dirlist);
201 ULONG MainCopyProcess(BPTR source, BPTR dest, struct MinList *dirlist,
202 struct MinList *copylist);
203 BOOL SetRootLock(struct DirEntry *de);
204 void FreeCopyNode(struct CopyNode *cn, ULONG *limit);
206 #ifdef USE_AROS_PACKETS
207 struct CopyNode *AllocCopyNode_AROS(BPTR from, ULONG size, ULONG *limit);
208 BOOL AsyncCopy_AROS(BPTR from, BPTR to, ULONG readsize, char *name);
209 #else
210 struct CopyNode *AllocCopyNode(BPTR from, ULONG size, ULONG *limit);
211 BOOL AsyncCopy(BPTR from, BPTR to, ULONG readsize, char *name);
212 #endif
216 #define ARG_TEMPLATE "FROM/A,TO/A,QT=QUIET/S,QTR=QUIETER/S,SETA=SETARCHIVE/S,NONA=NONAONLY/S,OVR=OVERWRITE/S,LVE=LEAVEEMPTY/S,DELC=DELETECOPIED/S,FORCE/S,UPD=UPDATE/S,PRB=PURGEBACKUP/S,PRO=PURGEONLY/S,BUFSIZE/K/N"
218 ///main
219 int main(void)
221 struct Process *this;
222 struct Message *msg;
223 struct RDArgs *ra;
225 IPTR args[14];
226 ULONG res = 0;
227 BPTR oldlock;
229 memset(args, 0, 14*sizeof(char *));
231 this = (struct Process *)FindTask(NULL);
233 if(this->pr_CLI == BNULL)
235 msg = WaitPort(&(this->pr_MsgPort));
236 msg = GetMsg(&(this->pr_MsgPort));
237 Forbid();
238 ReplyMsg(msg);
240 return 0;
243 /* Can't be started from WB */
245 tclower = (IPTR)(this->pr_Task.tc_SPLower);
247 DOSBase = (struct DosLibrary *)(OpenLibrary("dos.library", 37L));
249 if(DOSBase != NULL)
252 oldlock = CurrentDir(BNULL);
253 CurrentDir(oldlock);
255 UtilityBase = (struct UtilityBase *)OpenLibrary("utility.library", 37L);
257 if(UtilityBase != NULL)
259 ra = ReadArgs(ARG_TEMPLATE, args, NULL);
261 if(ra != NULL)
263 quiet = (BOOL)args[2];
264 quieter = (BOOL)args[3];
266 if(quieter)
267 quiet = TRUE;
269 seta = (BOOL)args[4];
270 onlya = (BOOL)args[5];
271 overwrite = (BOOL)args[6];
272 leaveempty = (BOOL)args[7];
273 deletecopied = (BOOL)args[8];
274 force = (BOOL)args[9];
275 update = (BOOL)args[10];
276 purge = (BOOL)args[11];
277 nocopy = (BOOL)args[12];
279 if(args[13])
281 bufsize = *((LONG *)args[13]);
283 else
285 bufsize = 0x7ffffff0;
288 if(bufsize < 256)
289 bufsize = 256;
291 if(nocopy)
292 purge = TRUE;
294 D(bug("Calling CopyMain()\n"));
296 res = CopyMain((STRPTR)args[0], (STRPTR)args[1]);
297 FreeArgs(ra);
299 else
300 { /* of ReadArgs */
301 PrintFault(IoErr(), "SortCopy failed");
302 res = 9;
305 CloseLibrary((struct Library *)UtilityBase);
307 else
309 Printf("SortCopy: Need utility.library V37!\n");
310 res = 32;
313 CurrentDir(oldlock);
314 CloseLibrary((struct Library *)DOSBase);
317 else
319 res = 32;
322 return res;
326 /// Fatal
327 /* Hole den I/O-Fehlercode, brich bei fatalem Fehler ab */
328 LONG Fatal(void)
330 LONG error;
332 error = IoErr();
334 if(error)
336 abortFlag = TRUE;
339 return error;
343 /// CopyMain
344 ULONG CopyMain(char *sourcename, char *destname)
346 BPTR dest, sourcelock;
347 ULONG res = 0;
349 struct MinList dirlist, copylist;
351 sourcelock = CurrentDir(BNULL);
352 SetSignal(0L, SIGMASK);
354 NewList((struct List *)&resolvelist);
355 NewList((struct List *)&dirlist);
356 NewList((struct List *)&copylist);
358 depth = 0;
359 CurrentDir(sourcelock);
361 switch(ParsePatternNoCase(destname, buffer, BUFFERSIZE))
363 case 0x01:
364 Printf("SortCopy: Wildcards not allowed in destination.\n");
365 res = RETURN_ERROR;
366 break;
368 case 0x00:
369 break;
371 default:
372 PostFailure(ERROR_BAD_TEMPLATE, "Wildcard parsing failed");
373 res = RETURN_FAIL;
374 break;
377 switch(ParsePatternNoCase(sourcename, buffer, BUFFERSIZE))
379 case 0x01:
380 sourcewild = TRUE;
381 break;
383 case 0x00:
384 sourcewild = FALSE;
385 break;
387 default:
388 PostFailure(ERROR_BAD_TEMPLATE, "Wildcard parsing failed");
389 res = RETURN_FAIL;
390 break;
393 D(bug("CopyMain part 2\n"));
395 if(!res)
397 res = MatchFirst(sourcename, &ap);
399 if(res)
401 if(res == ERROR_NO_MORE_ENTRIES)
402 res = ERROR_OBJECT_NOT_FOUND;
404 PostFailure(res, "Can't access \"%s\"", sourcename);
405 res = RETURN_ERROR;
408 MatchEnd(&ap);
411 D(bug("CopyMain part 3\n"));
413 if(!res)
415 dest = Lock(destname, SHARED_LOCK);
417 if(dest == BNULL)
419 D(bug("Destination not found\n"));
421 if(IoErr() == ERROR_OBJECT_NOT_FOUND)
423 if(!nocopy)
425 dest = CreateDir(destname);
427 if(dest == BNULL)
429 PostFailure(Fatal(),
430 "Can't create destination drawer \"%s\"",
431 destname);
432 res = RETURN_ERROR;
434 else
436 if(!(ChangeMode(CHANGE_LOCK, dest, SHARED_LOCK)))
438 PostFailure(Fatal(),
439 "Can't change the lock to \"%s\"",
440 destname);
441 UnLock(dest);
442 dest = BNULL; /* SDuvan: Was a bug here! */
443 DeleteFile(destname);
444 res = RETURN_ERROR;
449 else
451 PostFailure(Fatal(),
452 "Can't lock destination drawer \"%s\"",destname);
453 res = RETURN_ERROR;
458 D(bug("CopyMain part 3b\n"));
460 if(dest != BNULL)
462 D(bug("Checking IsDir() on %s\n", destname));
464 if(!IsDir(dest, destname))
466 D(bug("%s was no dir; calling Printf()\n", destname));
468 Printf("SortCopy: \"%s\" is not a directory.\n", destname);
469 res = RETURN_ERROR;
471 D(bug("Unlocking dest lock\n"));
473 UnLock(dest);
475 D(bug("Dest unlocked\n"));
477 dest = BNULL;
481 D(bug("CopyMain part 3c\n"));
483 if(dest)
485 CurrentDir(sourcelock);
486 res = FillDirList(sourcename, &dirlist);
488 if(res == 0)
490 D(bug("Calling MainCopyProcess()\n"));
491 res = MainCopyProcess(sourcelock, dest, &dirlist, &copylist);
494 UnLock(dest);
495 } /* of if dest */
498 FreeDirList(&dirlist, TRUE);
499 FreeDirList(&copylist, TRUE);
500 FreeDirList(&resolvelist, TRUE);
502 CurrentDir(sourcelock);
504 return res;
508 /// FillDirList
509 ULONG FillDirList(char *pattern, struct MinList *dirlist)
511 ULONG res = RETURN_OK;
512 LONG err;
513 BOOL found = FALSE;
515 ap.ap_BreakBits = 0;
516 ap.ap_Strlen = 0;
518 if(!(err = MatchFirst(pattern, &ap)))
520 do {
521 found = TRUE;
522 err = 0;
524 if(CheckAbort())
525 break;
527 if(!AddMatch(&ap, dirlist))
529 res = RETURN_WARN;
530 break;
533 ap.ap_Flags &= ~APF_DODIR;
534 err = MatchNext(&ap);
536 } while(!err);
538 if(err != ERROR_NO_MORE_ENTRIES && err)
540 PostFailure(err, "Can't resolve pattern \"%s\"", pattern);
541 res = RETURN_ERROR;
543 else if(!found)
545 PostFailure(ERROR_OBJECT_NOT_FOUND, "No information for \"%s\"",
546 pattern);
547 res = RETURN_WARN;
550 else
552 PostFailure(err, "Can't resolve pattern \"%s\"", pattern);
553 res = RETURN_ERROR;
556 MatchEnd(&ap);
558 return res;
562 /// MainCopyProcess
563 ULONG MainCopyProcess(BPTR source, BPTR dest, struct MinList *dirlist,
564 struct MinList *copylist)
566 ULONG res = RETURN_OK;
568 CurrentDir(source);
570 if(CheckAbort())
571 return res;
573 /* Create a copy of it */
574 DupDirList(dirlist, copylist);
576 /* And now for the heavy stuff */
577 if(CheckAbort())
578 return res;
580 /* Copy the list contents */
581 if(!(CopyEntryList(dirlist, dest)))
582 res = RETURN_WARN;
584 /* Move all the other stuff to the resolvelist */
585 FreeDirList(dirlist, FALSE);
587 if(CheckAbort())
588 return res;
590 /* create now all links */
591 if((!nocopy) && (resolvelist.mlh_Head->mln_Succ != NULL))
593 if(!quieter)
594 Printf("\nResolving outstanding links...\n\n");
596 if(!(ResolveLinks(&resolvelist,dest)))
597 res = 4;
599 if(!quieter)
600 Printf("\n");
603 FreeDirList(&resolvelist,TRUE);
605 if(CheckAbort())
606 return res;
608 /* Set now the archive bits in the source drawer */
609 if(seta && (failcondition == 0) && (!nocopy))
611 if(DupDirList(copylist, dirlist))
613 if(!quieter)
614 Printf("\n\nSetting the archive bits, please wait...\n");
616 if(!(SetAList(BNULL, dirlist)))
617 res = 3;
621 FreeDirList(dirlist, TRUE);
623 if(CheckAbort())
624 return res;
626 /* delete now the source files if the user selected this */
627 if(deletecopied && (res == 0) && (!nocopy))
629 if(failcondition)
631 Printf("\nA fail condition occured while copying. The deletion"
632 "of files is therefore disabled for security.\n");
634 else
636 if(!quieter)
637 Printf("\nRemoving old files...\n\n");
639 if(!(DeleteDirList(BNULL, copylist, FALSE)))
640 res = 2;
644 CurrentDir(source);
646 return res;
650 /// CopyEntryList
651 BOOL CopyEntryList(struct MinList *dirlist, BPTR dest)
653 struct DirEntry *de, *next;
655 BOOL fine = TRUE;
658 /* Copy all files, create directories and setup dummies for the
659 linked files and directories */
660 if(!nocopy)
662 if(!CopyDir(BNULL, dest, dirlist))
664 fine = FALSE;
668 /* Purge the destination: Not good if we gave a pattern... */
670 /* First free all the files and get the locks for the links */
671 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
673 next = de->de_next;
675 if(de->de_flags & (DEF_SOFTLINK | DEF_HARDLINK))
677 Remove((struct Node *)de);
678 PrepareLink(de, de->de_sourcelock, dest);
680 else
682 if(!(de->de_flags & DEF_DIR))
684 Remove((struct Node *)de);
685 FreeDirEntry(de, TRUE);
689 de = next;
692 /* Now copy the subdirectories recursively */
693 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
695 next = de->de_next;
697 if(CheckAbort())
698 break;
700 if(!(de->de_flags & DEF_FORGET))
702 if(de->de_flags & DEF_DIR)
704 if(!SetRootLock(de))
705 fine = FALSE;
707 if(!CopySubDirectory(de, de->de_sourcelock, dest))
708 fine = FALSE;
712 SetRootLock(NULL);
713 Remove((struct Node *)de);
714 FreeDirEntry(de, TRUE);
715 de = next;
718 FreeDirList(dirlist, FALSE);
720 return fine;
724 /// AddMatch
725 BOOL AddMatch(struct AnchorPath *ap, struct MinList *dirlist)
727 struct DirEntry *de;
729 BPTR oldlock;
730 LONG protection;
732 protection = ap->ap_Info.fib_Protection;
734 if(!(de = AllocDirEntry(&(ap->ap_Info))))
735 return FALSE;
737 oldlock = CurrentDir(ap->ap_Current->an_Lock);
739 de->de_sourcelock = DupLock(ap->ap_Current->an_Lock);
741 if(de->de_sourcelock != BNULL)
743 /* We need to call this first to find out if this
744 is a directory or not.... */
746 FillDirEntry(de, &(ap->ap_Info));
748 if((de->de_flags & DEF_DIR) == 0)
750 if(onlya && (protection & FIBF_ARCHIVE))
751 de->de_flags |= DEF_FORGET;
753 else if(!sourcewild)
755 de->de_flags |= DEF_FLATDIR;
758 EnqueueEntry(dirlist,de);
760 else
762 PostFailure(IoErr(), "Can't lock source directory \"%s\"",
763 ap->ap_Info.fib_FileName);
764 FreeDirEntry(de, TRUE);
765 de = NULL;
768 CurrentDir(oldlock);
770 if(de != NULL)
771 return TRUE;
772 else
773 return FALSE;
777 ///IsDir
778 BOOL IsDir(BPTR lock, char *name)
780 if(!Examine(lock, &fib))
782 PostFailure(Fatal(), "Can't examine object \"%s\"", name);
783 return FALSE;
786 /* No need to worry about links.... they are already resolved when we
787 Lock the object.. */
789 if(fib.fib_DirEntryType > 0)
790 return TRUE;
791 else
792 return FALSE;
796 ///OFlush
797 void OFlush(void)
799 Flush(Output());
803 /// Abort
804 void Abort(void)
806 abortFlag = TRUE;
807 PrintFault(ERROR_BREAK, NULL);
811 /// CheckAbort
812 BOOL CheckAbort(void)
814 if(abortFlag)
815 return TRUE;
817 // FIXME: Take care of stack check
818 #ifndef __AROS__
819 if((getreg(REG_A7) - tclower) < 1024)
821 PrintFault(ERROR_TOO_MANY_LEVELS, "SortCopy failed");
822 Printf("Increase the stack size with \"STACK\" and retry.\n");
824 abortFlag = TRUE;
826 return TRUE;
828 #endif
830 if(CheckSignal(SIGMASK))
832 Abort();
834 return TRUE;
837 return FALSE;
841 /// DoIndent
842 void DoIndent(void)
844 ULONG count = depth;
846 while(count-- > 0)
847 Printf(" ");
852 ///PostFailure
853 void PostFailure(LONG error, char *failtext, ...)
855 va_list args;
857 va_start(args, failtext);
859 if(error)
862 #ifdef __AROS__
863 VNewRawDoFmt(failtext, RAWFMTFUNC_STRING, failbuffer, args);
864 #else
865 tinyvsprintf(failbuffer, failtext, args);
866 #endif
868 Fault(error, failbuffer, buffer, BUFFERSIZE - 1);
869 Printf("\nSortCopy : %s \n", buffer);
870 failcondition = TRUE;
873 va_end(args);
877 ///FindSoftOrginal
878 BOOL FindSoftOrginal(struct DirEntry *de)
880 BPTR dirlock, objectlock = BNULL;
882 struct FileLock *flock;
884 BOOL fine = FALSE;
885 LONG err = 0;
887 de->de_flags |= DEF_NORESOLVE;
889 if(scount > MAXSOFTNEST)
891 SetIoErr(ERROR_TOO_MANY_LEVELS);
892 return FALSE;
895 dirlock = CurrentDir(BNULL);
896 CurrentDir(dirlock);
898 // NOTICE: Using lock internals here
900 flock = (struct FileLock *)(BADDR(dirlock));
902 if(flock->fl_Task == NULL)
903 { /* softlink at NIL:? Bizarre! */
904 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
905 return FALSE;
908 if(!ReadLink(flock->fl_Task, dirlock, de->de_name, buffer, BUFFERSIZE))
909 return FALSE;
912 /* Locate the object the link is going to */
913 if(!(dirlock = Lock(buffer, SHARED_LOCK)))
914 return FALSE;
916 if(Examine(dirlock, &fib))
918 objectlock = ParentDir(dirlock);
920 if(objectlock != BNULL)
922 strcpy(de->de_linkname, FilePart(buffer));
924 /* Fill in file name */
925 fine = TRUE;
929 err = IoErr();
930 UnLock(dirlock);
932 if(!fine)
934 SetIoErr(err);
935 return FALSE;
938 CurrentDir(objectlock);
939 switch(fib.fib_DirEntryType)
941 case ST_SOFTLINK:
942 scount++;
943 fine = FindSoftOrginal(de);
944 err = IoErr();
945 UnLock(objectlock);
946 scount--;
947 break;
949 case ST_LINKDIR:
950 de->de_flags |= DEF_DIR;
952 /* läuft hier hinein! */
954 case ST_LINKFILE:
955 fine = FindHardOrginal(de);
956 err = IoErr();
957 UnLock(objectlock);
958 break;
960 default:
961 if(fib.fib_DirEntryType > 0)
962 de->de_flags |= DEF_DIR;
964 de->de_linklock = objectlock;
965 err = 0;
966 fine = TRUE;
967 break;
970 CurrentDir(dirlock);
972 if(fine)
974 de->de_flags &= ~DEF_NORESOLVE;
977 SetIoErr(err);
978 return fine;
983 ///FindHardOrginal
984 BOOL FindHardOrginal(struct DirEntry *de)
986 BPTR lock; /* Resolve the link by getting the name */
987 LONG err;
989 if(!(lock = Lock(de->de_name, SHARED_LOCK)))
990 return FALSE;
992 if(Examine(lock, &fib))
994 de->de_linklock = ParentDir(lock);
996 if(de->de_linklock != BNULL)
998 strcpy(de->de_linkname, fib.fib_FileName);
999 UnLock(lock);
1001 return TRUE;
1005 err = IoErr();
1006 UnLock(lock);
1007 SetIoErr(err);
1009 return FALSE;
1011 /* old stuff, way too complicated...
1013 fine = NameFromLock(lock, buffer, BUFFERSIZE);
1014 err = IoErr();
1015 UnLock(lock);
1017 if(!fine)
1019 SetIoErr(err);
1020 return FALSE;
1023 strcpy(de->de_linkname, FilePart(buffer));
1024 *PathPart(buffer) = 0;
1025 de->de_linklock = Lock(buffer,SHARED_LOCK);
1027 if(!(de->de_linklock))
1028 return FALSE;
1029 else
1030 return TRUE;
1036 ///SetAFlag
1037 BOOL SetAFlag(struct DirEntry *de)
1039 BPTR lock;
1040 LONG err = 0;
1041 BPTR oldlock = BNULL;
1042 BPTR parent;
1044 if(CheckAbort())
1045 return FALSE;
1047 if(de->de_sourcelock != BNULL)
1048 oldlock = CurrentDir(de->de_sourcelock);
1050 lock = Lock(de->de_name, SHARED_LOCK);
1052 if(lock != BNULL)
1054 if(Examine(lock, &fib))
1056 parent = (BPTR)(-1);
1058 /* check if this the root directory. If so, don't set the A bit */
1059 if(fib.fib_DirEntryType > 0)
1061 parent = ParentDir(lock);
1063 if(parent != BNULL)
1065 UnLock(parent);
1067 else
1069 err = IoErr();
1073 if(parent != BNULL)
1075 if((!(fib.fib_Protection & FIBF_ARCHIVE)) ||
1076 (de->de_flags & (DEF_SOFTLINK | DEF_HARDLINK)))
1078 if(!SetProtection(de->de_name,
1079 fib.fib_Protection | FIBF_ARCHIVE))
1080 err = IoErr();
1084 else
1085 err = IoErr();
1087 UnLock(lock);
1089 else
1090 err = IoErr();
1092 if(de->de_sourcelock)
1093 CurrentDir(oldlock);
1095 if(err)
1097 PostFailure(err,"Can't set the archive bit of \"%s\"", de->de_name);
1098 return FALSE;
1101 return TRUE;
1105 ///CloneFlags
1106 BOOL CloneFlags(struct DirEntry *de)
1108 /* Die Directory wurde nicht angelegt, sondern der Inhalt
1109 hineinkopiert */
1110 if((de->de_flags & DEF_DIR) && (de->de_flags & (DEF_FLATDIR | DEF_REMOVED)))
1111 return TRUE;
1113 if(!SetComment(de->de_name, de->de_comment))
1115 PostFailure(IoErr(), "Can't set the file comment of \"%s\"",
1116 de->de_name);
1118 return FALSE;
1121 if(!SetFileDate(de->de_name, &(de->de_date)))
1123 PostFailure(IoErr(), "Can't set the file date of \"%s\"",
1124 de->de_name);
1126 return FALSE;
1129 if(!SetProtection(de->de_name,de->de_protection))
1131 PostFailure(IoErr(), "Can't set protection flags of \"%s\"",
1132 de->de_name);
1134 return FALSE;
1137 return TRUE;
1141 ///EnqueueEntry
1142 void EnqueueEntry(struct MinList *dirlist, struct DirEntry *de)
1144 struct DirEntry *cmp;
1146 /* Suche jetzt die richtige Einfügeposition für die neue Node */
1147 for(cmp = (struct DirEntry *)(dirlist->mlh_Head); cmp->de_next;
1148 cmp = cmp->de_next)
1150 if(Strnicmp(cmp->de_name, de->de_name, 108) > 0)
1151 break;
1154 if(cmp->de_next == NULL)
1156 AddTail((struct List *)dirlist, (struct Node *)de);
1158 else
1160 cmp = cmp->de_pred;
1162 if(cmp->de_pred == NULL)
1163 AddHead((struct List *)dirlist, (struct Node *)de);
1164 else
1165 Insert((struct List *)dirlist, (struct Node *)de,
1166 (struct Node *)cmp);
1171 ///ReadDir
1172 /* Eine komplette Directory zusammenbauen. Directory ist in BPTR lock */
1173 BOOL ReadDir(BPTR lock, struct MinList *dirlist, char *dirname)
1175 struct DirEntry *de = NULL;
1176 LONG protection;
1178 CurrentDir(lock);
1180 if(!Examine(lock, &dirfib))
1182 PostFailure(Fatal(), "Can't examine the directory \"%s\"", dirname);
1184 return FALSE;
1187 /* So, jetzt können wir den Rest der Directory lesen */
1188 for(;;)
1190 if(CheckAbort())
1191 return FALSE;
1193 if(!ExNext(lock, &dirfib))
1194 break;
1196 protection = dirfib.fib_Protection;
1198 if(!(de = AllocDirEntry(&dirfib)))
1199 return FALSE;
1201 FillDirEntry(de, &dirfib);
1203 /* selbst wenn es Probleme gibt, das Teil mit aufnehmen */
1205 if((de->de_flags & DEF_DIR) == 0)
1207 if(onlya && (protection & FIBF_ARCHIVE))
1208 de->de_flags |= DEF_FORGET;
1211 EnqueueEntry(dirlist, de);
1214 if(IoErr() == ERROR_NO_MORE_ENTRIES)
1216 return TRUE;
1218 else
1220 PostFailure(Fatal(), "Can't examine the directory \"%s\"", dirname);
1222 return FALSE;
1227 /// CopyFile
1228 BOOL CopyFile(BPTR source, BPTR dest, char *name)
1230 ULONG size;
1232 if(ExamineFH(source, &fib))
1234 size = fib.fib_Size;
1236 else
1238 /* Works like this, too, but takes *huge* amount of memoy */
1239 size = 0xffffffff;
1242 #ifdef USE_AROS_PACKETS
1243 return AsyncCopy_AROS(source, dest, size, name);
1244 #else
1245 return AsyncCopy(source, dest, size, name);
1246 #endif
1250 /// MustUpdate
1251 BOOL MustUpdate(BPTR destlock, struct DirEntry *de)
1253 BPTR dest;
1254 BOOL fine = TRUE;
1256 CurrentDir(destlock);
1257 dest = Lock(de->de_name, SHARED_LOCK);
1259 if(dest != BNULL)
1261 if(!Examine(dest, &fib))
1263 UnLock(dest);
1264 PostFailure(Fatal(), "Can't examine the destination file \"%s\"",
1265 de->de_name);
1266 de->de_flags |= DEF_FORGET;
1267 fine = FALSE;
1269 else
1271 if(fib.fib_Size == de->de_length)
1273 if(CompareDates(&(fib.fib_Date), &(de->de_date)) <= 0)
1274 fine = FALSE; /* no need to copy the file,
1275 we suppose they are identical */
1279 UnLock(dest);
1281 else
1283 if(IoErr() != ERROR_OBJECT_NOT_FOUND)
1285 PostFailure(Fatal(), "Can't lock the destination file \"%s\"",
1286 de->de_name);
1287 de->de_flags |= DEF_FORGET;
1288 fine = FALSE;
1292 return fine;
1296 /// CopyFileEntry
1297 /* Ein ganzes File kopieren. Achtung! Das muß auch wirklich ein File
1298 sein! */
1299 BOOL CopyFileEntry(struct DirEntry *de, BPTR sourcelock, BPTR destlock)
1301 BOOL fine = TRUE;
1302 BPTR source, dest, tmp;
1303 LONG err;
1304 struct MinList dirlist;
1306 if((!update) || MustUpdate(destlock, de))
1308 CurrentDir(sourcelock);
1309 source = Open(de->de_name, MODE_OLDFILE);
1311 if(source == BNULL)
1313 PostFailure(IoErr(), "Can't open the source file \"%s\"",
1314 de->de_name);
1315 de->de_flags |= DEF_FORGET;
1317 return FALSE;
1320 CurrentDir(destlock);
1322 /* Now check the destination object. Delete it if required */
1323 if(overwrite)
1325 tmp = Lock(de->de_name, EXCLUSIVE_LOCK);
1327 if(tmp != BNULL)
1329 if(ChangeMode(CHANGE_LOCK, tmp, SHARED_LOCK))
1331 /* Make it delete-able */
1332 if(SetProtection(de->de_name, 0))
1334 if(Examine(tmp, &fib))
1336 switch(fib.fib_DirEntryType)
1338 default:
1339 if(fib.fib_DirEntryType > 0)
1341 Printf("found obsolete directory, deleting.\n");
1342 depth++;
1343 NewList((struct List *)&dirlist);
1345 if(ReadDir(tmp, &dirlist, de->de_name))
1347 fine = DeleteDirList(tmp, &dirlist,
1348 TRUE);
1350 else
1351 fine = FALSE;
1353 CurrentDir(destlock);
1354 FreeDirList(&dirlist, TRUE);
1355 depth--;
1357 if(!fine)
1358 break;
1360 else
1361 break;
1363 case ST_SOFTLINK:
1364 case ST_LINKDIR:
1365 UnLock(tmp);
1366 tmp = BNULL;
1367 fine = DeleteFile(de->de_name);
1368 break;
1371 else
1372 fine = FALSE;
1374 else
1375 fine = FALSE;
1377 else
1378 fine = FALSE;
1380 if(tmp)
1382 err = IoErr();
1383 UnLock(tmp);
1384 SetIoErr(err);
1387 else
1389 if(IoErr() != ERROR_OBJECT_NOT_FOUND)
1390 fine = FALSE;
1393 if(!fine)
1395 err = IoErr();
1396 Close(source);
1397 PostFailure(err, "Can't delete the old entry \"%s\"",
1398 de->de_name);
1399 de->de_flags |= DEF_FORGET; /* nicht kopiert -> nicht löschen */
1401 return FALSE;
1405 dest = Open(de->de_name, MODE_NEWFILE);
1407 if (dest == BNULL)
1409 err = IoErr();
1410 Close(source);
1411 PostFailure(err, "Can't create the destination file \"%s\"",
1412 de->de_name);
1413 de->de_flags |= DEF_FORGET;
1415 return FALSE;
1418 fine = CopyFile(source, dest, de->de_name);
1419 Close(dest);
1420 Close(source);
1422 if(!fine)
1424 CurrentDir(destlock);
1425 DeleteFile(de->de_name);
1426 PostFailure(Fatal(), "Can't copy the file \"%s\"", de->de_name);
1427 de->de_flags |= DEF_FORGET; /* nicht kopiert -> nicht löschen */
1429 return FALSE;
1431 else
1433 de->de_flags |= DEF_CREATED;
1435 if(!quiet)
1436 Printf("\n");
1439 else
1441 if(!quiet)
1442 Printf("(up to date)\n");
1445 return TRUE;
1449 /// CopyDirEntry
1450 BOOL CopyDirEntry(struct DirEntry *de, BPTR sourcelock, BPTR destlock)
1452 BPTR newlock;
1453 BPTR dest;
1454 LONG err = 0;
1456 CurrentDir(destlock);
1458 newlock = Lock(de->de_name, SHARED_LOCK);
1460 if(newlock != BNULL)
1462 if(!IsDir(newlock, de->de_name))
1464 UnLock(newlock);
1466 if(overwrite)
1468 /* This is NOT a directory, erase it now */
1469 SetProtection(de->de_name, 0);
1471 if(!(DeleteFile(de->de_name)))
1473 PostFailure(IoErr(),
1474 "Can't remove \"%s\" to make room for a new directory",
1475 de->de_name);
1476 de->de_flags |= DEF_FORGET;
1478 return TRUE;
1481 else
1483 PostFailure(ERROR_OBJECT_WRONG_TYPE,
1484 "Destination \"%s\" is not a directory",
1485 de->de_name);
1486 de->de_flags |= DEF_FORGET;
1488 return TRUE;
1491 newlock = BNULL;
1494 else
1495 err = IoErr();
1497 if(newlock != BNULL)
1499 UnLock(newlock);
1501 /* This is not good in the case of a lock !*/
1502 if(de->de_flags & (DEF_SOFTLINK | DEF_HARDLINK))
1504 Printf("Warning: The name \"%s\" of the link is already in use.\n",
1505 de->de_name);
1506 de->de_flags |= DEF_NORESOLVE | DEF_FORGET; /* Diesen Link nicht erzeugen */
1508 return FALSE;
1510 else if(!quiet)
1512 Printf("\n");
1515 else
1517 if(err != ERROR_OBJECT_NOT_FOUND && err != 0)
1519 PostFailure(IoErr(), "Can't lock the directory \"%s\"",
1520 de->de_name);
1521 de->de_flags |= DEF_FORGET;
1523 return FALSE;
1525 else
1527 /* Don't create a directory in the case we replace it later
1528 by a link */
1529 if(de->de_flags & (DEF_SOFTLINK | DEF_HARDLINK))
1531 dest = Open(de->de_name, MODE_NEWFILE);
1533 if(dest == BNULL)
1535 PostFailure(Fatal(),
1536 "Can't create dummy link directory \"%s\"",
1537 de->de_name);
1538 de->de_flags |= DEF_FORGET; /* But try to resolve later */
1540 else
1542 de->de_flags |= DEF_CREATED;
1544 if(!quiet)
1545 Printf("(created)\n");
1547 Close(dest);
1550 else
1552 newlock = CreateDir(de->de_name);
1554 if(newlock == BNULL)
1556 PostFailure(Fatal(), "Can't create new directory \"%s\"",
1557 de->de_name);
1558 de->de_flags |= DEF_FORGET;
1560 return FALSE;
1562 else
1564 de->de_flags |= DEF_CREATED;
1566 if(!quiet)
1567 Printf("(created)\n");
1569 UnLock(newlock);
1575 return TRUE;
1579 /// CopyEntry
1580 BOOL CopyEntry(struct DirEntry *de, BPTR sourcelock, BPTR destlock)
1582 BPTR oldlock;
1584 if(de->de_flags & DEF_FORGET ||
1585 ((de->de_flags & DEF_DIR) && (de->de_flags & DEF_FLATDIR)))
1586 return TRUE;
1588 if(!quiet)
1590 DoIndent();
1591 Printf("%s...",de->de_name);
1592 OFlush();
1595 if(de->de_flags & DEF_DIR)
1597 if(!CopyDirEntry(de, sourcelock, destlock))
1598 return FALSE;
1600 else
1602 if(!CopyFileEntry(de, sourcelock, destlock))
1603 return FALSE;
1606 if(!(de->de_flags & DEF_FORGET))
1608 if((de->de_flags & (DEF_DIR | DEF_SOFTLINK | DEF_HARDLINK)) == 0)
1610 oldlock = CurrentDir(destlock);
1611 CloneFlags(de);
1612 CurrentDir(oldlock);
1616 return TRUE;
1620 /// SetRootLock
1621 BOOL SetRootLock(struct DirEntry *de)
1623 BOOL fine = TRUE;
1624 BPTR oldlock;
1626 if(rootlock)
1627 UnLock(rootlock);
1629 rootlock = BNULL;
1631 if(de != NULL)
1633 if(de->de_flags & DEF_DIR)
1635 /* Are we copying the root of a tree ? */
1636 UnLock(rootlock);
1637 oldlock = CurrentDir(de->de_sourcelock);
1638 rootlock = Lock(de->de_name, SHARED_LOCK);
1640 if(!rootlock)
1642 PostFailure(Fatal(), "Can't look the root directory \"%s\"\n",
1643 de->de_name);
1644 fine = FALSE;
1647 CurrentDir(oldlock);
1651 return fine;
1655 /// CopyDir
1656 /* Eine Directory nach Vorschrift kopieren */
1657 BOOL CopyDir(BPTR sourcelock, BPTR destlock, struct MinList *dirlist)
1659 struct DirEntry *de;
1660 BOOL fine = TRUE;
1662 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next;
1663 de = de->de_next)
1665 if(CheckAbort())
1667 return fine;
1670 if(sourcelock == BNULL)
1672 if(!SetRootLock(de))
1673 fine = FALSE;
1676 if(!(CopyEntry(de, (de->de_sourcelock) ? (de->de_sourcelock) :
1677 sourcelock, destlock)))
1678 fine = FALSE;
1681 if(sourcelock == BNULL)
1682 SetRootLock(BNULL);
1684 return fine;
1688 /// DupDirList
1689 BOOL DupDirList(struct MinList *source, struct MinList *dest)
1691 struct DirEntry *se, *de;
1693 NewList((struct List *)dest);
1695 for(se = (struct DirEntry *)(source->mlh_Head); se->de_next;
1696 se = se->de_next)
1698 if(!(de = DupDirEntry(se)))
1700 FreeDirList(dest, TRUE);
1702 return FALSE;
1705 AddTail((struct List *)dest, (struct Node *)de);
1708 return TRUE;
1712 /// DupDirEntry
1713 struct DirEntry *DupDirEntry(struct DirEntry *se)
1715 struct DirEntry *de;
1717 de = AllocMem(sizeof(struct DirEntry), MEMF_PUBLIC);
1719 if(!de)
1721 abortFlag = TRUE;
1722 PostFailure(Fatal(), "Can't allocate directory buffer");
1724 return NULL;
1725 /* Liste der bestehenden DirEntries wird von oben abgeräumt */
1728 /* Kopiere jetzt die Daten */
1729 memcpy(de, se, sizeof(struct DirEntry));
1730 de->de_sourcelock = BNULL;
1731 de->de_linklock = BNULL;
1732 de->de_dirlock = BNULL; /* Erstmal löschen */
1733 NewList((struct List *)(&(de->de_sublist))); /* Wird nicht geduppt */
1735 if(se->de_sourcelock == 0 ||
1736 (de->de_sourcelock = DupLock(se->de_sourcelock)))
1738 if(se->de_linklock == 0 || (de->de_linklock = DupLock(se->de_linklock)))
1740 if(se->de_dirlock == 0 || (de->de_dirlock=DupLock(se->de_dirlock)))
1742 return de;
1747 PostFailure(Fatal(), "Can't duplicate directory buffer");
1748 FreeDirEntry(de, TRUE);
1750 return NULL;
1754 /// AllocDirEntry
1755 struct DirEntry *AllocDirEntry(struct FileInfoBlock *fib)
1757 struct DirEntry *de;
1759 de = AllocMem(sizeof(struct DirEntry), MEMF_PUBLIC);
1761 if(!de)
1763 abortFlag = TRUE;
1764 PostFailure(Fatal(), "Can't allocate directory buffer");
1766 return NULL;
1767 /* Liste der bestehenden DirEntries wird von oben abgeräumt */
1770 /* Kopiere jetzt die Daten */
1771 strcpy(de->de_name, fib->fib_FileName);
1772 strcpy(de->de_comment, fib->fib_Comment);
1773 de->de_protection = fib->fib_Protection;
1774 de->de_date = fib->fib_Date;
1775 de->de_flags = 0L;
1776 de->de_sourcelock = BNULL;
1777 de->de_linklock = BNULL;
1778 de->de_dirlock = BNULL; /* Muß vom Caller ausgefüllt werden */
1779 de->de_linkname[0] = 0;
1780 de->de_length = fib->fib_Size;
1781 NewList((struct List *)(&(de->de_sublist)));
1783 return de;
1787 /// FillDirEntry
1788 BOOL FillDirEntry(struct DirEntry *de, struct FileInfoBlock *fib)
1790 BOOL fine = TRUE;
1792 switch(fib->fib_DirEntryType)
1794 case ST_SOFTLINK:
1795 de->de_flags |= DEF_SOFTLINK;
1797 /* We never set this up as a directory */
1798 fine = FindSoftOrginal(de);
1799 break;
1801 case ST_LINKDIR:
1802 de->de_flags |= DEF_DIR;
1804 /* Fall through */
1805 case ST_LINKFILE:
1806 de->de_flags |= DEF_HARDLINK;
1807 fine = FindHardOrginal(de);
1808 break;
1810 default:
1811 if(fib->fib_DirEntryType > 0)
1812 de->de_flags |= DEF_DIR;
1814 break;
1817 if(!fine)
1819 PostFailure(IoErr(), "Can't resolve link \"%s\"", de->de_name);
1820 de->de_flags |= DEF_NORESOLVE;
1823 return fine;
1827 ///FreeDirEntry
1828 void FreeDirEntry(struct DirEntry *de, BOOL locks)
1830 FreeDirList(&(de->de_sublist), locks);
1831 UnLock(de->de_sourcelock);
1832 UnLock(de->de_dirlock);
1833 UnLock(de->de_linklock);
1834 FreeMem(de, sizeof(struct DirEntry));
1838 ///FreeDirList
1839 void FreeDirList(struct MinList *dirlist, BOOL locks)
1841 struct DirEntry *de, *next;
1843 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
1845 next = de->de_next;
1846 Remove((struct Node *)de);
1848 if((de->de_flags & (DEF_SOFTLINK | DEF_HARDLINK)) && (locks == FALSE))
1850 AddTail((struct List *)&resolvelist, (struct Node *)(de));
1852 else
1854 FreeDirEntry(de, locks);
1857 de = next;
1862 /// DirEmpty
1863 BOOL DirEmpty(BPTR lock, char *name)
1865 if(Examine(lock, &fib))
1867 if(ExNext(lock, &fib))
1868 return FALSE;
1870 if(IoErr() == ERROR_NO_MORE_ENTRIES)
1871 return TRUE;
1873 PostFailure(IoErr(), "Can't inspect directory \"%s\"", name);
1875 return FALSE;
1878 PostFailure(IoErr(), "Can't inspect directory \"%s\"", name);
1880 return FALSE;
1884 /// KillForce
1885 BOOL KillForce(char *name, BOOL force)
1887 BPTR lock;
1889 lock = Lock(name, EXCLUSIVE_LOCK);
1891 if(lock != BNULL)
1893 UnLock(lock);
1895 if(force)
1896 SetProtection(name, 0);
1898 /* We'll see if this works... */
1900 if(DeleteFile(name))
1901 return TRUE;
1903 PostFailure(IoErr(), "Can't remove empty directory \"%s\"", name);
1905 return FALSE;
1908 if(IoErr() != ERROR_OBJECT_IN_USE)
1910 PostFailure(IoErr(), "Can't remove empty directory \"%s\"", name);
1913 return FALSE;
1917 /// CopySubDirectory
1918 BOOL CopySubDirectory(struct DirEntry *de, BPTR source, BPTR dest)
1920 BPTR newdest = BNULL;
1921 BPTR destlock;
1922 BPTR newsource;
1923 BOOL fine;
1925 /* find new destination lock of the directory */
1926 CurrentDir(dest);
1928 if(de->de_flags & DEF_FLATDIR)
1930 destlock = dest;
1932 else
1934 newdest = Lock(de->de_name, SHARED_LOCK);
1936 if(newdest == BNULL)
1938 if((IoErr() != ERROR_OBJECT_NOT_FOUND) || (!nocopy))
1939 PostFailure(Fatal(), "Can't lock the new directory \"%s\"",
1940 de->de_name);
1942 de->de_flags |= DEF_FORGET;
1944 return FALSE;
1946 else
1948 destlock = newdest;
1952 /* find the new source of the directory */
1953 CurrentDir((de->de_sourcelock) ? (de->de_sourcelock) : (source));
1954 newsource = Lock(de->de_name, SHARED_LOCK);
1956 if(newsource == BNULL)
1958 PostFailure(IoErr(), "Can't lock the source directory \"%s\"",
1959 de->de_name);
1960 de->de_flags |= DEF_FORGET;
1961 UnLock(newdest);
1963 return FALSE;
1966 if(!quieter)
1968 if(!quiet)
1969 Printf("\n");
1971 DoIndent();
1972 Printf("%sing the directory \"%s\":\n", (nocopy) ? ("Check") :("Copy"),
1973 de->de_name);
1976 depth++;
1978 fine = RecursiveCopy(newsource, destlock, &(de->de_sublist), de->de_name);
1979 UnLock(newsource);
1981 if((de->de_flags & DEF_CREATED) &&
1982 (de->de_protection & FIBF_ARCHIVE) && onlya)
1984 /* Falls erzeugt, überprüfe, ob leer. In diesem Falle löschen */
1985 if((!leaveempty) && (!nocopy) && DirEmpty(newdest, de->de_name))
1987 UnLock(newdest);
1988 newdest = BNULL;
1989 CurrentDir(dest);
1991 if(KillForce(de->de_name, TRUE))
1993 if(!quieter)
1995 DoIndent();
1996 Printf("\"%s\" is empty. Removed.\n", de->de_name);
1997 de->de_flags |= DEF_REMOVED;
2003 if(fine)
2005 CurrentDir(dest);
2006 if(!CloneFlags(de)) /* smart enough not to set the flags if REMOVED or FLATDIR */
2007 fine = FALSE;
2010 depth--;
2012 if(!quiet)
2014 DoIndent();
2015 Printf("...done with directory \"%s\".\n", de->de_name);
2018 UnLock(newdest);
2020 return fine;
2024 ///PrepareLink
2025 BOOL PrepareLink(struct DirEntry *de, BPTR source, BPTR dest)
2027 BOOL fine = TRUE;
2029 if(!(de->de_sourcelock))
2031 if(rootlock == BNULL)
2033 PostFailure(ERROR_OBJECT_NOT_FOUND,
2034 "The root lock of the link \"%s\" is not set.\n",
2035 de->de_name);
2036 fine = FALSE;
2038 else if(!(de->de_sourcelock = DupLock(rootlock)))
2040 fine = FALSE;
2041 PostFailure(IoErr(),
2042 "Can't duplock root dir of link \"%s\"",de->de_name);
2046 if(!(de->de_dirlock = DupLock(dest)))
2048 PostFailure(IoErr(), "Can't duplock destination dir of link \"%s\"",
2049 de->de_name);
2050 fine = FALSE;
2053 if(!fine)
2054 de->de_flags |= DEF_NORESOLVE;
2056 AddTail((struct List *)&resolvelist, (struct Node *)(de));
2058 return fine;
2062 ///RecursiveCopy
2063 BOOL RecursiveCopy(BPTR source, BPTR dest, struct MinList *dirlist,
2064 char *dirname)
2066 struct DirEntry *de, *next;
2067 BOOL fine = TRUE;
2069 CurrentDir(source);
2071 if(CheckAbort())
2072 return TRUE;
2074 if(!ReadDir(source, dirlist, dirname))
2076 FreeDirList(dirlist, FALSE);
2078 return FALSE;
2081 if(CheckAbort())
2083 FreeDirList(dirlist, FALSE);
2085 return TRUE;
2088 /* Copy all files, create directories and setup dummies for the
2089 linked files and directories */
2090 if(!nocopy)
2092 if(!CopyDir(source, dest, dirlist))
2094 fine = FALSE;
2098 if(CheckAbort())
2100 FreeDirList(dirlist, FALSE);
2102 return fine;
2105 /* Purge the destination */
2106 if(purge)
2108 if(!PurgeDir(source, dest, dirlist, dirname))
2110 fine = FALSE;
2114 if(CheckAbort())
2116 FreeDirList(dirlist, FALSE);
2118 return fine;
2121 /* First free all the files and get the locks for the links */
2122 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
2124 next = de->de_next;
2126 if(de->de_flags & (DEF_SOFTLINK | DEF_HARDLINK))
2128 Remove((struct Node *)de);
2129 PrepareLink(de, source, dest);
2131 else
2133 if(!(de->de_flags & DEF_DIR))
2135 Remove((struct Node *)de);
2136 FreeDirEntry(de, TRUE);
2140 de = next;
2143 /* Now copy the subdirectories recursively */
2144 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
2146 next = de->de_next;
2148 if(CheckAbort())
2149 break;
2151 if(!(de->de_flags & DEF_FORGET))
2153 if(de->de_flags & DEF_DIR)
2155 if(!(CopySubDirectory(de, source, dest)))
2156 fine = FALSE;
2160 Remove((struct Node *)(de));
2161 FreeDirEntry(de, TRUE);
2162 de = next;
2165 FreeDirList(dirlist, FALSE);
2167 return fine;
2171 ///PathRelative
2172 BOOL PathRelative(BPTR relpath, BPTR path, char *name, char *buffer,
2173 ULONG bufsize)
2175 char *bufend;
2176 char *slash;
2177 BPTR lock, newlock;
2179 bufend = buffer + bufsize - strlen(name) - 1;
2181 if(bufend < buffer)
2183 SetIoErr(ERROR_LINE_TOO_LONG);
2184 return FALSE;
2187 strcpy(bufend, name);
2188 slash = NULL;
2189 lock = DupLock(path);
2191 if(lock==BNULL)
2192 return FALSE;
2194 for(;;)
2196 if(SameLock(relpath, lock) == LOCK_SAME)
2197 break; /* If done */
2199 if(Examine(lock, &fib) == FALSE)
2201 UnLock(lock);
2203 return FALSE; /* Can't examine */
2206 bufend--;
2207 slash = bufend;
2208 bufend = bufend - strlen(fib.fib_FileName);
2210 if(bufend < buffer)
2212 SetIoErr(ERROR_LINE_TOO_LONG);
2213 UnLock(lock);
2215 return FALSE;
2218 strcpy(bufend, fib.fib_FileName);
2219 *slash = '/';
2220 newlock = ParentDir(lock);
2221 UnLock(lock);
2222 lock = newlock;
2224 if(newlock == BNULL)
2226 /* Either something got wrong or the object we are looking for is
2227 not related to the relative path */
2228 *slash = ':';
2230 if(IoErr() == 0)
2231 SetIoErr(ERROR_OBJECT_NOT_FOUND);
2233 return FALSE;
2238 if(slash)
2240 newlock = ParentDir(lock);
2241 UnLock(lock);
2243 if(newlock == BNULL)
2245 if(IoErr() == 0)
2246 *slash = ':';
2247 else
2248 return FALSE;
2250 else
2251 UnLock(newlock);
2255 strcpy(buffer, bufend);
2256 UnLock(lock);
2258 return TRUE;
2262 ///CreateLink
2263 BOOL CreateLink(char *name, BPTR melock, char *linkname, BPTR linklock,
2264 ULONG soft)
2266 BPTR lock;
2267 BOOL unlock;
2269 /* First, get a lock to the object we are linking to */
2270 /* linkname MIGHT be NULL. In this case, we already have a lock */
2271 if(linkname)
2273 CurrentDir(linklock);
2274 lock = Lock(linkname, SHARED_LOCK);
2276 if(lock == BNULL)
2278 PostFailure(IoErr(), "Can't lock the object \"%s\" the link is going to",
2279 linkname);
2281 return FALSE;
2284 unlock = TRUE;
2286 else
2288 lock = linklock;
2289 unlock = FALSE;
2292 /* if this is a softlink, get the full name of the object */
2293 if(soft)
2295 if(!NameFromLock(lock, buffer, BUFFERSIZE))
2297 PostFailure(IoErr(), "Can't find the full name of \"%s\"",
2298 linkname);
2300 if(unlock)
2301 UnLock(lock);
2303 return FALSE;
2307 /* Now find the place of the lock. Delete the placeholder */
2308 CurrentDir(melock);
2310 if(!DeleteFile(name))
2312 PostFailure(IoErr(), "Can't delete the placeholder \"%s\"", name);
2314 if(unlock)
2315 UnLock(lock);
2317 return FALSE;
2320 if(soft)
2322 if(!MakeLink(name, (SIPTR)buffer, TRUE))
2324 PostFailure(IoErr(), "Can't create the softlink \"%s\"", name);
2326 if (unlock)
2327 UnLock(lock);
2329 return FALSE;
2332 else
2334 if(!MakeLink(name, (SIPTR)lock, FALSE))
2336 PostFailure(IoErr(), "Can't create the hardlink \"%s\"", name);
2338 if(unlock)
2339 UnLock(lock);
2341 return FALSE;
2345 if(unlock)
2346 UnLock(lock);
2348 return TRUE;
2352 ///ResolveLinks
2353 BOOL ResolveLinks(struct MinList *list, BPTR dest)
2355 struct DirEntry *de;
2357 BOOL fine, resolved;
2358 BPTR destlock;
2359 BOOL rc = TRUE;
2361 for(de = (struct DirEntry *)(list->mlh_Head); de->de_next; de = de->de_next)
2363 if(CheckAbort())
2364 break;
2366 if(!quiet)
2368 DoIndent();
2369 Printf("%s...", de->de_name);
2370 OFlush();
2373 resolved = FALSE;
2375 if(de->de_flags & (DEF_FORGET | DEF_NORESOLVE))
2377 if(de->de_flags & DEF_NORESOLVE)
2378 Printf("\nDue to a former error, the link to \"%s\" can't be resolved.\n",
2379 de->de_name);
2381 else
2383 fine = PathRelative(de->de_sourcelock, de->de_linklock,
2384 de->de_linkname, buffer, BUFFERSIZE);
2386 if(!fine)
2388 if(IoErr() != ERROR_OBJECT_NOT_FOUND)
2390 PostFailure(IoErr(), "Can't find relative path of \"%s\"",
2391 de->de_name);
2392 rc = FALSE;
2394 else
2396 /* This might be O.K. */
2397 if(SameLock(de->de_sourcelock, dest) == LOCK_SAME_VOLUME)
2399 Printf("Warning: Link destination of \"%s\" not copied, using the original path.\n",
2400 de->de_name);
2401 OFlush();
2403 if(CreateLink(de->de_name, de->de_dirlock,
2404 de->de_linkname, de->de_linklock,
2405 de->de_flags & DEF_SOFTLINK))
2407 resolved = TRUE;
2411 if(!resolved)
2413 if(!(de->de_flags & DEF_DIR))
2415 Printf("Warning: Link destination of \"%s\" not present, using a copy instead.\n",
2416 de->de_name);
2417 OFlush();
2418 resolved = TRUE;
2423 else
2425 /* Found the relative path. Find a lock to the object
2426 the link goes to */
2427 CurrentDir(dest);
2428 destlock = Lock(buffer, SHARED_LOCK);
2430 /* If the destination can't be found... */
2431 if(destlock == BNULL)
2433 if(IoErr() == ERROR_OBJECT_NOT_FOUND)
2435 if(!(de->de_flags & DEF_DIR))
2437 Printf("Warning: Link destination of \"%s\" not present, using a copy instead.\n",
2438 de->de_name);
2439 OFlush();
2440 resolved = TRUE;
2443 else
2445 PostFailure(IoErr(), "Can't lock the object \"%s\" the link is relative to",
2446 buffer);
2447 rc = FALSE;
2450 else
2452 /* Found the destination */
2453 if(CreateLink(de->de_name, de->de_dirlock, NULL, destlock,
2454 de->de_flags & DEF_SOFTLINK))
2456 resolved = TRUE;
2458 if(!quiet)
2459 Printf("\n");
2462 UnLock(destlock);
2467 if(!resolved && (de->de_flags & DEF_CREATED))
2469 CurrentDir(de->de_dirlock);
2471 if(de->de_flags & DEF_DIR)
2473 /* Create an empty directory instead */
2474 if(DeleteFile(de->de_name))
2476 if((de->de_flags & DEF_CREATED) &&
2477 (de->de_protection & FIBF_ARCHIVE) && onlya)
2479 Printf("Warning: The archived directory link \"%s\" was left out.\n",
2480 de->de_name);
2481 rc = FALSE;
2482 resolved = FALSE;
2484 else if((destlock = CreateDir(de->de_name)) != BNULL)
2486 UnLock(destlock);
2487 resolved = TRUE;
2488 Printf("Warning: Created an empty directory for \"%s\" instead.\n",
2489 de->de_name);
2490 rc = FALSE;
2493 else
2494 PostFailure(IoErr(), "Can't delete the placeholder \"%s\"",
2495 de->de_name);
2497 else
2499 DeleteFile(de->de_name); /* Don't mind if this worked */
2500 Printf("Warning: The link to \"%s\" can't be resolved.\n",
2501 de->de_name);
2502 rc = FALSE;
2506 if(resolved)
2508 CurrentDir(de->de_dirlock);
2509 CloneFlags(de);
2513 return rc;
2517 /// DeleteEntry
2518 void DeleteEntry(struct DirEntry *de, BOOL all)
2520 BPTR oldlock = BNULL;
2522 if(all || (!(onlya && (de->de_protection & FIBF_ARCHIVE))))
2524 if(CheckAbort())
2525 return;
2527 if(!quiet)
2529 DoIndent();
2530 Printf("%s...", de->de_name);
2531 OFlush();
2534 if(de->de_sourcelock)
2535 oldlock = CurrentDir(de->de_sourcelock);
2537 if(force)
2538 SetProtection(de->de_name, 0);
2540 if(!DeleteFile(de->de_name))
2542 PostFailure(IoErr(), "Can't delete the file \"%s\"", de->de_name);
2544 else
2546 if(!quiet)
2547 Printf("(deleted)\n");
2551 if(de->de_sourcelock)
2552 CurrentDir(oldlock);
2554 Remove((struct Node *)(de));
2555 FreeDirEntry(de, TRUE);
2559 /// DeleteDirList
2560 BOOL DeleteDirList(BPTR source, struct MinList *dirlist, BOOL all)
2562 struct DirEntry *de, *next;
2564 BPTR newsource;
2565 BOOL fine = TRUE;
2567 if(CheckAbort())
2569 FreeDirList(dirlist, TRUE);
2571 return TRUE;
2574 /* Delete all files */
2575 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
2577 next = de->de_next;
2579 if((de->de_flags & DEF_DIR) == 0)
2580 DeleteEntry(de, all);
2582 de = next;
2585 /* Delete recursively all directories first ! */
2586 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
2588 next = de->de_next;
2590 if(CheckAbort())
2591 break;
2593 if(de->de_flags & DEF_DIR)
2595 CurrentDir((de->de_sourcelock) ? (de->de_sourcelock) : (source));
2596 newsource = Lock(de->de_name, SHARED_LOCK);
2598 if(newsource == BNULL)
2600 PostFailure(Fatal(), "Can't lock new directory \"%s\"",
2601 de->de_name);
2602 de->de_flags |= DEF_FORGET;
2604 else
2606 if(!quieter)
2608 DoIndent();
2609 Printf("Cleaning the directory \"%s\":\n", de->de_name);
2612 depth++;
2614 if(!RecursiveDelete(newsource, &(de->de_sublist), all,
2615 de->de_name))
2616 fine = FALSE;
2618 depth--;
2620 if(!quiet)
2622 DoIndent();
2623 Printf("...done with directory \"%s\".\n", de->de_name);
2626 CurrentDir((de->de_sourcelock) ? (de->de_sourcelock) :
2627 (source));
2629 if(DirEmpty(newsource, de->de_name))
2631 UnLock(newsource);
2633 if(force)
2634 SetProtection(de->de_name, 0);
2636 if(!DeleteFile(de->de_name))
2638 PostFailure(IoErr(),
2639 "Can't delete the directory \"%s\"",
2640 de->de_name);
2643 else
2644 UnLock(newsource);
2647 Remove((struct Node *)de);
2648 FreeDirEntry(de, TRUE);
2651 de = next;
2654 /* Delete now all (archived) files */
2655 CurrentDir(source);
2657 /* Free now all remaining stuff */
2658 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
2660 next = de->de_next;
2661 DeleteEntry(de, FALSE);
2662 de = next;
2665 FreeDirList(dirlist, TRUE);
2667 return fine;
2671 /// RecursiveDelete
2672 BOOL RecursiveDelete(BPTR source, struct MinList *dirlist, BOOL all,
2673 char *dirname)
2675 CurrentDir(source);
2677 if(CheckAbort())
2678 return TRUE;
2680 if(!ReadDir(source, dirlist, dirname))
2682 FreeDirList(dirlist, TRUE);
2684 return FALSE; /* Continue anyway */
2687 return DeleteDirList(source, dirlist, all);
2691 /// SetAList
2692 BOOL SetAList(BPTR source, struct MinList *dirlist)
2694 struct DirEntry *de, *next;
2696 BPTR newsource;
2697 BOOL fine = TRUE;
2699 CurrentDir(source);
2701 /* Set the archive bit of all files */
2702 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
2704 next = de->de_next;
2706 if((de->de_flags & DEF_DIR) == 0)
2708 SetAFlag(de);
2709 Remove((struct Node *)de);
2710 FreeDirEntry(de, TRUE);
2713 de = next;
2716 /* Set the archive bit of all directories */
2717 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
2719 next = de->de_next;
2721 if(CheckAbort())
2722 break;
2724 if(de->de_flags & DEF_DIR)
2726 CurrentDir((de->de_sourcelock) ? (de->de_sourcelock) : (source));
2727 newsource = Lock(de->de_name, SHARED_LOCK);
2729 if(newsource == BNULL)
2731 PostFailure(IoErr(), "Can't lock new directory \"%s\"",
2732 de->de_name);
2733 de->de_flags |= DEF_FORGET;
2735 else
2737 if(!quiet)
2739 DoIndent();
2740 Printf("Setting the archive bit of the directory \"%s\"...\n",
2741 de->de_name);
2744 depth++;
2746 if(!(RecursiveSetA(newsource, &(de->de_sublist), de->de_name)))
2747 fine = FALSE;
2749 depth--;
2751 CurrentDir(source);
2752 SetAFlag(de);
2753 UnLock(newsource);
2756 Remove((struct Node *)de);
2757 FreeDirEntry(de, TRUE);
2760 de = next;
2763 CurrentDir(source);
2765 /* Set now the A flag of all remaining stuff */
2766 for(de = (struct DirEntry *)(dirlist->mlh_Head); de->de_next; )
2768 next = de->de_next;
2770 SetAFlag(de);
2771 Remove((struct Node *)(de));
2772 FreeDirEntry(de, TRUE);
2773 de = next;
2776 FreeDirList(dirlist, TRUE);
2778 return fine;
2782 /// RecursiveSetA
2783 BOOL RecursiveSetA(BPTR source, struct MinList *dirlist, char *dirname)
2785 if(CheckAbort())
2786 return TRUE;
2788 CurrentDir(source);
2790 if(!ReadDir(source, dirlist, dirname))
2792 FreeDirList(dirlist, TRUE);
2794 return FALSE;
2798 if(CheckAbort())
2800 FreeDirList(dirlist, TRUE);
2802 return TRUE;
2805 return SetAList(source, dirlist);
2809 /// FindDirEntry
2810 BOOL FindDirEntry(struct MinList *dirlist, struct DirEntry *de)
2812 struct DirEntry *look;
2814 for(look = (struct DirEntry *)(dirlist->mlh_Head); look->de_next;
2815 look = look->de_next)
2817 if(!(Stricmp(de->de_name, look->de_name)))
2818 return TRUE;
2821 return FALSE;
2825 /// PurgeDir
2826 BOOL PurgeDir(BPTR sourcelock, BPTR destlock, struct MinList *dirlist,
2827 char *dirname)
2829 struct MinList destlist;
2830 struct DirEntry *de, *next;
2832 BOOL result;
2834 NewList((struct List *)&destlist);
2836 if(!quiet)
2838 DoIndent();
2839 Printf("Purging...");
2840 OFlush();
2843 depth++;
2845 /* Read destination directory */
2847 if(!ReadDir(destlock, &destlist, dirname))
2849 FreeDirList(&destlist, TRUE);
2850 Printf("\n");
2851 depth--;
2853 return FALSE;
2856 /* Remove all the stuff we already have in the source */
2857 for(de = (struct DirEntry *)(destlist.mlh_Head); de->de_next; )
2859 next = de->de_next;
2861 if(FindDirEntry(dirlist, de))
2863 Remove((struct Node *)de);
2864 FreeDirEntry(de, TRUE);
2867 de = next;
2870 Printf("\n");
2871 result = DeleteDirList(destlock, &destlist, TRUE);
2873 depth--;
2875 if(!quiet)
2877 DoIndent();
2878 Printf("...done\n");
2881 return result;
2886 /// AllocCopyNode
2887 struct CopyNode *AllocCopyNode(BPTR from, ULONG size, ULONG *limit)
2889 struct CopyNode *cn = NULL;
2891 if(size > *limit)
2893 size = *limit;
2896 if(size)
2898 cn = AllocVec(sizeof(struct CopyNode) + size,
2899 MEMF_PUBLIC | MEMF_NO_EXPUNGE);
2902 if(cn == NULL)
2904 if(lastchancebusy == FALSE)
2906 lastchancebusy = TRUE;
2907 cn = &lastchancenode;
2908 cn->cn_Buffer = buffer;
2909 cn->cn_release = FALSE;
2910 size = BUFFERSIZE;
2913 else
2915 *limit -= size;
2916 cn->cn_Buffer = (cn + 1);
2917 cn->cn_release = TRUE;
2920 if(cn != NULL)
2922 cn->cn_DosMessage.mn_Node.ln_Type = NT_MESSAGE;
2923 cn->cn_DosMessage.mn_Node.ln_Pri = 0;
2924 cn->cn_DosMessage.mn_Node.ln_Name = (APTR)(&(cn->cn_DosPacket));
2925 cn->cn_DosMessage.mn_ReplyPort = &ioport;
2926 cn->cn_DosPacket.dp_Port = &ioport;
2927 cn->cn_DosMessage.mn_Length = sizeof(struct StandardPacket);
2928 cn->cn_DosPacket.dp_Link = &(cn->cn_DosMessage);
2929 cn->cn_DosPacket.dp_Type = ACTION_READ; /* Read */
2930 cn->cn_Command = ACTION_READ;
2931 cn->cn_DosPacket.dp_Arg1 = ((struct FileHandle *)BADDR(from))->fh_Arg1;
2932 cn->cn_DosPacket.dp_Arg2 = (SIPTR)cn->cn_Buffer;
2933 cn->cn_DosPacket.dp_Arg3 = size;
2934 cn->cn_BufSize = size;
2935 cn->cn_BackTick = cn;
2938 return cn;
2943 /// FreeCopyNode
2944 void FreeCopyNode(struct CopyNode *cn, ULONG *limit)
2946 if(cn->cn_release)
2948 *limit += cn->cn_BufSize;
2949 FreeVec(cn);
2951 else
2952 lastchancebusy = FALSE;
2957 /// AsyncCopy
2958 BOOL AsyncCopy(BPTR from, BPTR to, ULONG readsize, char *name)
2960 struct MsgPort *readport, *writeport;
2961 struct CopyNode *cn;
2963 ULONG buffer;
2964 ULONG packetcount;
2965 ULONG limit;
2966 BOOL busy, stop, report;
2967 LONG readerror, writeerror;
2968 LONG arg1;
2969 LONG signals;
2971 ioport.mp_Node.ln_Type = NT_MSGPORT;
2972 ioport.mp_Node.ln_Pri = 0;
2973 ioport.mp_Node.ln_Name = NULL;
2974 ioport.mp_Flags = PA_SIGNAL;
2975 ioport.mp_SigBit = SIGB_DOS;
2976 ioport.mp_SigTask = FindTask(NULL);
2977 NewList(&(ioport.mp_MsgList));
2978 limit = AvailMem(MEMF_PUBLIC | MEMF_LARGEST);
2979 limit >>= 1;
2981 if(limit > 8192)
2983 limit -= 8192;
2985 else
2986 limit = 0;
2988 readport = ((struct FileHandle *)BADDR(from))->fh_Type;
2989 writeport = ((struct FileHandle *)BADDR(to))->fh_Type;
2990 arg1 = ((struct FileHandle *)BADDR(to))->fh_Arg1;
2992 /* if source or destination is NIL:, return no error
2993 but copy zero bytes anyhow */
2994 if((readport == NULL) || (writeport == NULL))
2995 return 0;
2997 /* if there's nothing to do, abort now */
2998 if(readsize == 0)
2999 return 0;
3001 readerror = 0;
3002 writeerror = 0;
3003 packetcount = 0;
3004 stop = FALSE;
3005 SetIoErr(0L);
3006 lastchancebusy = FALSE;
3007 report = TRUE;
3009 for(;;)
3011 /* Check whether we should still read bytes from the input */
3012 busy = FALSE;
3014 /* If user hit ^C, then abort reading */
3015 if(CheckAbort())
3016 stop = TRUE;
3018 if(stop)
3020 readsize = 0; /* Do not demand reading if halt required */
3023 if(readsize)
3025 /* Go for a reasonable buffer size */
3026 buffer = 4096;
3028 if(bufsize > buffer)
3029 buffer = bufsize;
3031 if(buffer > readsize)
3032 buffer = readsize;
3034 if(buffer > limit)
3036 if(limit > BUFFERSIZE)
3038 buffer = limit;
3042 cn = AllocCopyNode(from, buffer, &limit);
3044 if(cn != NULL)
3046 /* Might fill in another value if no memory */
3047 readsize -= cn->cn_BufSize;
3049 SendPkt(&(cn->cn_DosPacket), readport, &ioport);
3050 busy = TRUE;
3051 packetcount++;
3053 else
3055 /* Allocation of the packet failed. If at least one packet
3056 is busy, wait for its return as we may re-use it.
3057 else generate an error */
3058 if(packetcount == 0)
3060 readerror = ERROR_NO_FREE_STORE;
3061 SetIoErr(readerror);
3062 PostFailure(Fatal(), "Can't read from \"%s\"", name);
3063 stop = TRUE;
3064 /* Fatal sets also abortFlag */
3069 cn = (struct CopyNode *)GetMsg(&ioport);
3071 if(cn != NULL)
3073 busy = TRUE;
3075 /* A Queue packet failure ? */
3076 if(cn->cn_BackTick != cn)
3078 Alert(AN_QPktFail);
3080 else
3082 if(cn->cn_Command == ACTION_READ)
3084 if(cn->cn_DosPacket.dp_Res1 > 0)
3086 /* If this is an emergency stop, do not send a
3087 write request */
3088 if(CheckAbort())
3090 packetcount--;
3091 FreeCopyNode(cn, &limit);
3093 else
3095 /* Everything went fine, initialize this packet
3096 for writing and let it go */
3097 cn->cn_DosPacket.dp_Type = ACTION_WRITE;
3098 cn->cn_Command = ACTION_WRITE;
3099 cn->cn_DosPacket.dp_Arg1 = arg1;
3100 cn->cn_DosPacket.dp_Arg2 = (SIPTR)cn->cn_Buffer;
3101 readsize += cn->cn_BufSize;
3102 cn->cn_DosPacket.dp_Arg3 = cn->cn_DosPacket.dp_Res1;
3103 cn->cn_WriteSize = cn->cn_DosPacket.dp_Res1;
3104 readsize -= cn->cn_DosPacket.dp_Res1;
3105 SendPkt(&(cn->cn_DosPacket), writeport, &ioport);
3108 else
3110 /* Uhoh, something went wrong. An error? */
3111 if(cn->cn_DosPacket.dp_Res1 < 0)
3112 { /* An error! */
3114 /* If this is the first fault, print it */
3116 if(readerror == 0)
3118 if(report)
3120 if(ErrorReport(cn->cn_DosPacket.dp_Res2,
3121 REPORT_STREAM, (SIPTR)from,
3122 NULL))
3124 /* Cancled */
3125 report = FALSE;
3127 } /* continue with the next read-packet,
3128 release this */
3130 /* Abort and print error in case the user
3131 cancled */
3132 if(report == FALSE)
3134 readerror = cn->cn_DosPacket.dp_Res2;
3135 SetIoErr(readerror);
3136 PostFailure(readerror,
3137 "Can't read from \"%s\"", name);
3138 stop = TRUE;
3142 /* A read error is non-fatal */
3144 else
3145 stop = TRUE; /* EOF, Reading done */
3147 packetcount--;
3148 FreeCopyNode(cn, &limit);
3151 else if(cn->cn_Command == ACTION_WRITE)
3153 if(cn->cn_DosPacket.dp_Res1 != cn->cn_BufSize)
3155 if(cn->cn_DosPacket.dp_Res1 < 0)
3157 /* A real error? If so, report to the user
3158 if not aborted anyhow */
3159 if(report)
3161 if(ErrorReport(cn->cn_DosPacket.dp_Res2,
3162 REPORT_STREAM, (SIPTR)to, NULL))
3164 /* User canceled */
3165 report = FALSE;
3167 else
3169 /* Re-initialize the packet, and retry
3170 the write request */
3171 cn->cn_DosPacket.dp_Type = ACTION_WRITE;
3172 cn->cn_DosPacket.dp_Arg1 = arg1;
3173 cn->cn_DosPacket.dp_Arg2 = (SIPTR)cn->cn_Buffer;
3174 cn->cn_DosPacket.dp_Arg3 = cn->cn_WriteSize;
3175 SendPkt(&(cn->cn_DosPacket), writeport,
3176 &ioport);
3177 CheckAbort();
3178 continue;
3183 /* If this is the first write error, print it */
3184 if(report == FALSE && writeerror == 0)
3186 if(cn->cn_DosPacket.dp_Res1 < 0)
3188 writeerror = cn->cn_DosPacket.dp_Res2;
3190 else
3191 writeerror = ERROR_OBJECT_WRONG_TYPE;
3193 SetIoErr(writeerror);
3194 PostFailure(Fatal(), "Can't write to \"%s\"", name);
3196 /* Fatal() sets also abortFlag and therefore
3197 stops reading */
3201 packetcount--;
3202 FreeCopyNode(cn, &limit);
3204 else
3205 Alert(AN_QPktFail); /* Huh, an unkown command returned? */
3209 if(packetcount == 0 && readsize == 0)
3210 break;
3212 if(!busy)
3214 signals = Wait((ULONG)(SIGF_DOS | SIGBREAKF_CTRL_C));
3216 if(signals & SIGBREAKF_CTRL_C)
3217 Abort();
3219 else
3220 CheckAbort();
3223 if(readerror || writeerror)
3224 return FALSE;
3226 return TRUE;