home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d9xx / d996 / ecopy.lha / ECopy / ECopy.c < prev    next >
C/C++ Source or Header  |  1994-04-05  |  30KB  |  861 lines

  1. /*
  2. ** ECopy V1.1 -- Economical File Copy Utility
  3. ** Copyright (c) 1994 by Sam Yee.
  4. ** Feb 20, 1994.
  5. **
  6. ** Permission is here granted for the distribution of ECopy, provided
  7. ** that files are intacted and in unmodified state.
  8. */
  9.  
  10. /*******************************************************************/
  11. /* includes */
  12. #include <clib/alib_protos.h>
  13. #include <clib/dos_protos.h>
  14. #include <clib/exec_protos.h>
  15. #include <ctype.h>
  16. #include <dos/dos.h>
  17. #include <dos/dosasl.h>
  18. #include <exec/memory.h>
  19. #include <math.h>
  20. #include <pragmas/dos_pragmas.h>
  21. #include <pragmas/exec_pragmas.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24.  
  25. /*******************************************************************/
  26. /* constants */
  27. /* for ReadArgs() */
  28. #define OPT_FROM    0
  29. #define OPT_TO      1
  30. #define OPT_QUIET   2
  31. #define OPT_BUF     3
  32. #define OPT_CLONE   4
  33. #define OPT_LISTNC  5   /* list files not copied */
  34. #define OPT_MOVE    6
  35. #define OPT_RESERVE 7
  36. #define OPT_SUFFIX  8
  37. #define OPT_BLOCKCAP 9  /* block capability; bytes usable in each block */
  38. #define OPT_FORCE   10  /* force move/copy */
  39. #define OPT_READFILE 11 /* read file names from file */
  40. #define OPT_NCTOFILE 12 /* file name to save files not copied to */
  41. #define OPT_COUNT   13
  42.  
  43. #define BUFFERS 8 /* 8K of buffers */
  44. #define MINBUFS 1 /* minimum 1K buffer */
  45.  
  46. #define TEMPLATE "FROM/M,TO/A,QUIET/S,BUF=BUFFER/K/N,CLONE/S,LISTNC/S,MOVE/S,\
  47. RES=RESERVE/K/N,SUF=SUFFIX/K,BLOCKCAP/K/N,FORCE/S,READFILE/K,NCTOFILE/K"
  48.  
  49. /*******************************************************************/
  50. /* structure definitions */
  51. struct FileLink
  52. {
  53.     struct Node             node;
  54.     struct FileInfoBlock    *fib;
  55. };
  56.  
  57. struct FileList
  58. {
  59.     struct List list;
  60.     long        count;  /* number of nodes in list */
  61. };
  62.  
  63. /*******************************************************************/
  64. /* prototypes */
  65.  
  66. /* need these for #pragmas */
  67. extern struct DOSBase  *DOSBase;
  68. extern struct SysBase  *SysBase;
  69.  
  70. /* disable SAS/C's ^C checking */
  71. void __regargs __chkabort(void);
  72. void __regargs __chkabort(){}
  73. void __regargs _CXBRK(void);
  74. void __regargs _CXBRK(){}
  75.  
  76. BOOL CollectFiles(struct FileList *fl, char *fname);
  77. void FreeFileList(struct FileList *flist, BOOL list_not_copied,
  78.                   BOOL is_copy, char *nctofname);
  79. void SortListDown(struct FileList *flist);
  80. struct FileLink *GetBestFitFile(struct List *list, long max_size);
  81. int GetDiskInfo(char *disk_name, struct InfoData *info);
  82. long CalcReserveBlocks(long size, long  block_size);
  83. BOOL CollectNamesFromFile(struct FileList *flist, char *fname);
  84.  
  85. /*******************************************************************/
  86. /* version info */
  87. char *version = "$VER: ECopy 1.10 (20.2.94)";
  88.  
  89. /*******************************************************************/
  90. /* main routine, what else? */
  91. int
  92. main(int    argc,       /* number of arguments from command invocation */
  93.      char   *argv[])    /* array of strings of command line options */
  94. {
  95.     struct InfoData *info = NULL;
  96.     struct FileList flist;
  97.     struct FileLink *flink;
  98.     struct RDArgs   *myrda = NULL;
  99.     char            **from_files,
  100.                     vol_name[256],  /* destination volume name */
  101.                     dst_name[256];  /* destination file name */
  102.     void            *io_buf;        /* copy buffer */
  103.     LONG            result[OPT_COUNT],
  104.                     rc = 10,
  105.                     i,
  106.                     block_cap,      /* # of usable bytes in a block */
  107.                     blocks_free,
  108.                     read_len,
  109.                     buffers = BUFFERS,
  110.                     buf_size,
  111.                     disk_used = 0L, /* total bytes used on disk(s) */
  112.                     disk_max = 0L;  /* maximum usable bytes on disk(s) */
  113.     BPTR            src_fh,     /* source file handle */
  114.                     dst_fh;     /* destination file handle */
  115.     BOOL            quit = FALSE,
  116.                     full,       /* disk full? */
  117.                     broke_scan = FALSE; /* user smashed ^C ? */
  118.  
  119.     NewList(&flist.list);
  120.     flist.count = 0;
  121.  
  122.     if (argc == 1)
  123.     {
  124.         Printf("\
  125. ECopy 1.10 -- Economical File Copy Utility\n\
  126. Copyright (c) 1992-1994 by Sam Yee.  All Rights Reserved.\n\
  127. Freely Distributable.  Bug reports to samy@sfu.ca or 1:153/765\n\
  128. Compiled on "__DATE__ " (" __TIME__").\n\n\
  129. For command usage type `%s ?'\n",argv[0]);
  130.         rc = 0;
  131.     }
  132.     else
  133.     {
  134.         myrda = (struct RDArgs *)AllocDosObject(DOS_RDARGS,NULL);
  135.         info = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_PUBLIC);
  136.     }
  137.  
  138.     if (myrda && info)
  139.     {
  140.             /* read from stdin instead */
  141.         myrda->RDA_Source.CS_Buffer = NULL;
  142.         myrda->RDA_Source.CS_Length = 0L;
  143.  
  144.             /* initialize result array */
  145.         for (i = 0; i < OPT_COUNT; i++)
  146.             result[i] = 0L;
  147.  
  148.             /* parse command line options */
  149.         if (ReadArgs(TEMPLATE,result,myrda))
  150.         {
  151.             if (result[OPT_BUF])
  152.                 buffers = max(*((long *)result[OPT_BUF]),MINBUFS);
  153.  
  154.             buf_size = buffers*1024L;
  155.  
  156.                 /* if copy buffer allocated */
  157.             if (io_buf = AllocVec(buf_size,MEMF_PUBLIC))
  158.             {
  159.                 from_files = (char **)result[OPT_FROM];
  160.  
  161.                     /* scan all files/directories to copy from */
  162.                 for (i = 0; from_files[i]; i++)
  163.                 {
  164.                     if (broke_scan = CollectFiles(&flist,from_files[i]))
  165.                         break;
  166.                 }
  167.  
  168.                 if (!broke_scan && result[OPT_READFILE])
  169.                     broke_scan = CollectNamesFromFile(&flist,
  170.                                     (char *)result[OPT_READFILE]);
  171.  
  172.                 if (!broke_scan) /* ^C not hit */
  173.                 {
  174.                     SortListDown(&flist);   /* sort in inverse order according
  175.                                                to size */
  176.                     strncpy(vol_name,(char *)result[OPT_TO],
  177.                             sizeof(vol_name)-1);
  178.                 }
  179.                 else
  180.                     quit = TRUE;
  181.  
  182.                 while (!quit)
  183.                 {
  184.                         /* get disk info data */
  185.                     if (!(block_cap = GetDiskInfo(vol_name,info)))
  186.                     {
  187.                         PrintFault(IoErr(),vol_name);
  188.                         break;
  189.                     }
  190.  
  191.                     if (result[OPT_BLOCKCAP])
  192.                         block_cap = max(*((long *)result[OPT_BLOCKCAP]),1L);
  193.  
  194.                     if (CheckSignal(SIGBREAKF_CTRL_C))
  195.                     {
  196.                         PrintFault(ERROR_BREAK,NULL);
  197.                         break;
  198.                     }
  199.  
  200.                     /* reserve 1 for file header and 1 for use by OS */
  201.                     blocks_free = (info->id_NumBlocks-info->id_NumBlocksUsed-
  202.                                    CalcReserveBlocks(result[OPT_RESERVE] ?
  203.                                                      (*((long *)result[OPT_RESERVE])*1024L) : 0L,
  204.                                                      block_cap))-2;
  205.  
  206.                     full = FALSE;
  207.                     flink = GetBestFitFile(&(flist.list),blocks_free*block_cap);
  208.  
  209.                     if (flink)
  210.                     {
  211.                             /* get destination file name */
  212.                         strncpy(dst_name,vol_name,sizeof(dst_name)-1);
  213.                         AddPart(dst_name,FilePart(flink->fib->fib_FileName),
  214.                                 sizeof(dst_name));
  215.  
  216.                             /* add suffix as required */
  217.                         if (result[OPT_SUFFIX])
  218.                             strncat(dst_name,(char *)result[OPT_SUFFIX],
  219.                                     sizeof(dst_name)-1);
  220.  
  221.                         if (src_fh = Open(flink->fib->fib_FileName,MODE_OLDFILE))
  222.                         {
  223.                             if (!(dst_fh = Open(dst_name,MODE_NEWFILE)))
  224.                             {
  225.                                 /* if delete/write protected and force then
  226.                                    delete file */
  227.                                 if (((IoErr() == ERROR_DELETE_PROTECTED) ||
  228.                                      (IoErr() == ERROR_WRITE_PROTECTED)) &&
  229.                                     result[OPT_FORCE])
  230.                                 {
  231.                                     SetProtection(dst_name,~(FIBF_READ|FIBF_WRITE|
  232.                                                            FIBF_EXECUTE|FIBF_DELETE));
  233.                                     DeleteFile(dst_name);
  234.                                 }
  235.  
  236.                                 dst_fh = Open(dst_name,MODE_NEWFILE);
  237.                             }
  238.  
  239.                             if (dst_fh)
  240.                             {
  241.                                 BOOL    bad = FALSE;
  242.  
  243.                                 if (!result[OPT_QUIET])
  244.                                 {
  245.                                     Printf("%s..",flink->fib->fib_FileName);
  246.                                     Flush(Output());
  247.                                 }
  248.  
  249.                                 while ((read_len = Read(src_fh,io_buf,buf_size)) > 0L)
  250.                                 {
  251.                                     if (CheckSignal(SIGBREAKF_CTRL_C))
  252.                                     {
  253.                                         PrintFault(ERROR_BREAK,NULL);
  254.                                         bad = quit = TRUE;
  255.                                         break;
  256.                                     }
  257.                                     else if (Write(dst_fh,io_buf,read_len) != read_len)
  258.                                     {
  259.                                         PrintFault(IoErr(),NULL);
  260.                                         full = bad = TRUE;
  261.                                         break;
  262.                                     }
  263.                                 }
  264.  
  265.                                 if (IoErr() && !read_len)
  266.                                 {
  267.                                     PrintFault(IoErr(),NULL);
  268.                                     bad = TRUE;
  269.                                     /* remove file node in the list to be copied */
  270.                                     Remove(&(flink->node));
  271.                                     flist.count--;
  272.                                 }
  273.  
  274.                                 Close(dst_fh);
  275.  
  276.                                 if (bad)    /* if copy was bad */
  277.                                 {
  278.                                     Printf("Incomplete file %s..",dst_name);
  279.                                     Flush(Output());
  280.                                     DeleteFile(dst_name);
  281.                                     Printf("deleted\n");
  282.                                 }
  283.                                 else
  284.                                 {
  285.                                     if (!result[OPT_QUIET])
  286.                                         Printf(result[OPT_MOVE] ? "moved\n" : "copied\n");
  287.  
  288.                                     /* if clone or move then clone file */
  289.                                     if (result[OPT_CLONE] || result[OPT_MOVE])
  290.                                     {
  291.                                         SetProtection(dst_name,flink->fib->fib_Protection);
  292.                                         SetFileDate(dst_name,&(flink->fib->fib_Date));
  293.  
  294.                                         /* if there is a comment, duplicate it */
  295.                                         if (flink->fib->fib_Comment[0])
  296.                                             SetComment(dst_name,flink->fib->fib_Comment);
  297.                                     }
  298.  
  299.                                     /* if moving files */
  300.                                     if (result[OPT_MOVE])
  301.                                     {
  302.                                         Close(src_fh);  /* close file first */
  303.                                         src_fh = NULL;
  304.  
  305.                                         /* attempt deletion */
  306.                                         if (!DeleteFile(flink->fib->fib_FileName))
  307.                                         {
  308.                                             /* if force deletion */
  309.                                             if (result[OPT_FORCE])
  310.                                             {
  311.                                                 SetProtection(flink->fib->fib_FileName,
  312.                                                               ~(FIBF_READ|FIBF_WRITE|
  313.                                                                 FIBF_EXECUTE|FIBF_DELETE));
  314.  
  315.                                                 if (!DeleteFile(flink->fib->fib_FileName))
  316.                                                     PrintFault(IoErr(),flink->fib->fib_FileName);
  317.                                             }
  318.                                             else
  319.                                                 PrintFault(IoErr(),flink->fib->fib_FileName);
  320.                                         }
  321.                                     }
  322.  
  323.                                     /* remove file node in the list to be copied */
  324.                                     Remove(&(flink->node));
  325.                                     flist.count--;
  326.                                 }
  327.                             }
  328.                             else
  329.                             {
  330.                                 PrintFault(IoErr(),dst_name);
  331.  
  332.                                 if ((IoErr() == ERROR_DELETE_PROTECTED) ||
  333.                                     (IoErr() == ERROR_WRITE_PROTECTED))
  334.                                 {
  335.                                     Remove(&(flink->node));
  336.                                     flist.count--;
  337.                                 }
  338.                             }
  339.  
  340.                             /* if file not already closed, close it */
  341.                             if (src_fh)
  342.                                 Close(src_fh);
  343.                         }
  344.                         else    /* fatal error opening file */
  345.                         {
  346.                             PrintFault(IoErr(),flink->fib->fib_FileName);
  347.                             Remove(&(flink->node));
  348.                             flist.count--;
  349.  
  350.                             if (!flist.count)
  351.                             {
  352.                                 rc = 0;
  353.                                 quit = TRUE;
  354.                             }
  355.                         }
  356.                     }
  357.                     else if (flist.count)   /* if more files to copy then
  358.                                                disk must be full */
  359.                         full = TRUE;
  360.                     else
  361.                     {
  362.                         quit = TRUE;
  363.                         rc = 0;
  364.                     }
  365.  
  366.                     if (full && !quit)
  367.                     {
  368.                         char    key = '\0';
  369.  
  370.                         GetDiskInfo(vol_name,info);
  371.                         disk_used += (info->id_NumBlocksUsed*info->id_BytesPerBlock);
  372.                         disk_max += (info->id_NumBlocks*info->id_BytesPerBlock);
  373.  
  374.                         PrintFault(ERROR_DISK_FULL,vol_name);
  375.  
  376.                         while (TRUE)
  377.                         {
  378.                             /* display status and get response */
  379.                             Printf("\n%ld more file%s to be copied.\n\n",
  380.                                    flist.count, (flist.count == 1L) ? "" : "s");
  381.                             Printf("[R]etry, [C]hange disk, or [A]bort? ");
  382.                             Flush(Output());
  383.                             SetMode(Output(),TRUE);
  384.                             Read(Input(),&key,1L);
  385.                             key = toupper(key);
  386.                             SetMode(Output(),FALSE);
  387.                             FPutC(Output(),key);
  388.                             Printf("\n");
  389.  
  390.                             if (key == 'R') /* retry copy */
  391.                             {
  392.                                 Printf("\n");
  393.                                 break;
  394.                             }
  395.                             else if (key == 'C')    /* change destination disk */
  396.                             {
  397.                                 char *s;
  398.  
  399.                                 /* get new disk name */
  400.                                 Printf("\nEnter new disk name [%s]: ",vol_name);
  401.                                 Flush(Output());
  402.                                 Read(Input(),dst_name,sizeof(dst_name)-1);
  403.                                 Printf("\n");
  404.                                 s = dst_name;
  405.  
  406.                                 while (*s && (*s != '\r') && (*s != '\n')) s++;
  407.  
  408.                                 *s = '\0';
  409.  
  410.                                 if (*dst_name)
  411.                                     strncpy(vol_name,dst_name,sizeof(vol_name)-1);
  412.  
  413.                                 if (GetDiskInfo(vol_name,info))
  414.                                     break;
  415.                                 else
  416.                                     PrintFault(IoErr(),vol_name);
  417.                             }
  418.                             else if (key == 'A')    /* abort copy */
  419.                             {
  420.                                 quit = TRUE;
  421.                                 break;
  422.                             }
  423.                         }
  424.                     }
  425.  
  426.                     if (!flist.count)   /* we are done */
  427.                     {
  428.                         rc = 0;
  429.                         quit = TRUE;
  430.                     }
  431.                 }
  432.  
  433.                 FreeFileList(&flist,!broke_scan && (result[OPT_LISTNC] ||
  434.                                                     result[OPT_NCTOFILE]),
  435.                              result[OPT_MOVE],(char *)result[OPT_NCTOFILE]);
  436.  
  437.                 if (!broke_scan && disk_used && disk_max)
  438.                 {
  439.                     ULONG x;
  440.  
  441.                     if (disk_used > 4000000)    /* check if * will overflow */
  442.                         x = ((disk_used*100)/disk_max)*10;
  443.                     else
  444.                         x = (disk_used*1000)/disk_max;
  445.  
  446.                     Printf("\nEfficiency: %ld.%ld%s!\n",x/10,x - ((x/10)*10),"%");
  447.                 }
  448.  
  449.                 FreeVec(io_buf);
  450.             }
  451.             else
  452.                 PrintFault(ERROR_NO_FREE_STORE,NULL);
  453.  
  454.             FreeArgs(myrda);
  455.         }
  456.         else
  457.             PrintFault(IoErr(),NULL);
  458.     }
  459.  
  460.     if (myrda)
  461.         FreeDosObject(DOS_RDARGS,myrda);
  462.  
  463.     if (info)
  464.         FreeVec(info);
  465.  
  466.     return(rc); /* return with error code, if any */
  467. }
  468.  
  469. /*******************************************************************/
  470. /* allocate a file information node that can be added to the list
  471.    of files to copy */
  472. struct FileLink *
  473. AllocFileLink(void)
  474. {
  475.     struct FileLink *flink;
  476.  
  477.     if (flink = AllocVec(sizeof(struct FileLink),MEMF_PUBLIC|MEMF_CLEAR))
  478.     {
  479.         if (!(flink->fib = AllocDosObject(DOS_FIB,NULL)))
  480.         {
  481.             FreeVec(flink);
  482.             flink = NULL;
  483.         }
  484.     }
  485.  
  486.     return(flink);
  487. }
  488.  
  489. /*******************************************************************/
  490. /* free the file information node allocated by AllocFileLink() */
  491. void
  492. FreeFileLink(struct FileLink *flink)
  493. {
  494.     FreeDosObject(DOS_FIB,flink->fib);
  495.     FreeVec(flink);
  496. }
  497.  
  498. /*******************************************************************/
  499. /* free the list if file information nodes, with file name listing */
  500. void
  501. FreeFileList(struct FileList    *flist,
  502.              BOOL               list_not_copied,    /* list those files not copied? */
  503.              BOOL               is_copy,            /* did we copy the files?
  504.                                                        if not, we moved them */
  505.              char               *nctofname)         /* file to save not copied file
  506.                                                        file names to */
  507. {
  508.     struct FileLink *flink;
  509.     BOOL            broke = FALSE;
  510.     LONG            not_copied_count = flist->count;
  511.     BPTR            outfh = NULL;
  512.  
  513.     if (nctofname)
  514.     {
  515.         if (!(outfh = Open(nctofname,MODE_NEWFILE)))
  516.             PrintFault(IoErr(),nctofname);
  517.     }
  518.  
  519.     while (flink = (struct FileLink *)RemHead(&flist->list))
  520.     {
  521.         if (!broke && (list_not_copied || outfh))
  522.         {
  523.             if (CheckSignal(SIGBREAKF_CTRL_C))
  524.             {
  525.                 PrintFault(ERROR_BREAK,NULL);
  526.                 broke = TRUE;
  527.             }
  528.             else
  529.             {
  530.                 if (outfh)
  531.                     FPrintf(outfh,"%s\n",flink->fib->fib_FileName);
  532.  
  533.                 if (list_not_copied)
  534.                     Printf("%s\n",flink->fib->fib_FileName);
  535.             }
  536.         }
  537.  
  538.         FreeFileLink(flink);
  539.     }
  540.  
  541.     if (!broke && list_not_copied && not_copied_count)
  542.     {
  543.         Printf("\n%ld file%s not %sd.\n",
  544.                not_copied_count,(not_copied_count == 1L) ? "" : "s",
  545.                is_copy ? "move" : "copie");
  546.     }
  547.  
  548.     if (outfh)
  549.         Close(outfh);
  550. }
  551.  
  552. /*******************************************************************/
  553. /* collect a list of file information nodes from a directory given
  554.    by 'lock'.  each file name is compared with 'pattern'. */
  555. BOOL /* broke? */
  556. CollectDirFiles(struct FileList *fl,    /* file link list */
  557.                 BPTR            lock,   /* lock of directory */
  558.                 char            *pattern, /* pattern buf from
  559.                                              ParsePatternNoCase() to match
  560.                                              each filename with */
  561.                 struct FileInfoBlock *fib)  /* fib from previous Examine () */
  562. {
  563.     struct FileLink *flink;
  564.     char            pathpart[256],
  565.                     pathname[256];
  566.     BOOL            broke = FALSE;
  567.  
  568.     NameFromLock(lock,pathpart,sizeof(pathpart));
  569.  
  570.     /* scan the whole directory */
  571.     while (ExNext(lock,fib))
  572.     {
  573.         /* user press ^C break? */
  574.         if (CheckSignal(SIGBREAKF_CTRL_C))
  575.         {
  576.             PrintFault(ERROR_BREAK,NULL);
  577.             broke = TRUE;
  578.             break;
  579.         }
  580.  
  581.         if (fib->fib_DirEntryType < 0) /* file? */
  582.         {
  583.             /* pattern matched? */
  584.             if (MatchPatternNoCase(pattern,FilePart(fib->fib_FileName)))
  585.             {
  586.                 if (flink = AllocFileLink())
  587.                 {
  588.                     /* add file information node to list */
  589.                     strcpy(pathname,pathpart);
  590.                     AddPart(pathname,fib->fib_FileName,sizeof(pathname));
  591.                     strncpy(fib->fib_FileName,pathname,sizeof(fib->fib_FileName)-1);
  592.                     CopyMem(fib,flink->fib,sizeof(struct FileInfoBlock));
  593.                     AddTail(&(fl->list),&(flink->node));
  594.                     fl->count++;
  595.                 }
  596.             }
  597.         }
  598.     }
  599.  
  600.     return(broke);
  601. }
  602.  
  603. /*******************************************************************/
  604. /* collect a list of file information nodes from a directory or
  605.    just one file information node if a file is specified. */
  606. BOOL /* broke? */
  607. CollectFiles(struct FileList    *fl,
  608.              char               *fname)
  609. {
  610.     struct FileLink *flink;
  611.     char            parse_buf[256],
  612.                     pathname[256],
  613.                     *path,
  614.                     c;
  615.     BPTR            dlock,
  616.                     flock;
  617.     BOOL            error = FALSE,
  618.                     broke = FALSE;
  619.  
  620.     if (flink = AllocFileLink())
  621.     {
  622.         strncpy(pathname,fname,sizeof(pathname)-1);
  623.  
  624.         /* Attempt to Lock() file or directory */
  625.         if (dlock = Lock(pathname,ACCESS_READ))
  626.         {
  627.             if (Examine(dlock,flink->fib))
  628.             {
  629.                 if (flink->fib->fib_DirEntryType > 0) /* a directory */
  630.                     AddPart(pathname,"#?",sizeof(pathname));
  631.             }
  632.             else
  633.             {
  634.                 PrintFault(IoErr(),pathname);
  635.                 error = TRUE;
  636.             }
  637.  
  638.             UnLock(dlock);
  639.         }
  640.  
  641.         if (!error) /* if file examinable */
  642.         {
  643.             path = PathPart(pathname);
  644.             c = *path;
  645.             *path = '\0';
  646.  
  647.             if (dlock = Lock(pathname,ACCESS_READ)) /* Lock() file or directory */
  648.             {
  649.                 if (Examine(dlock,flink->fib))  /* examine file or directory */
  650.                 {
  651.                     *path = c;
  652.  
  653.                     if (!(*path))
  654.                         path = "#?";
  655.  
  656.                     /* if patterned filename specified, scan the whole directory */
  657.                     if (ParsePatternNoCase(path,parse_buf,sizeof(parse_buf)))
  658.                         broke = CollectDirFiles(fl,dlock,parse_buf,flink->fib);
  659.                     else    /* file specified */
  660.                     {
  661.                         /* get relative file name */
  662.                         NameFromLock(dlock,parse_buf,sizeof(parse_buf));
  663.                         AddPart(parse_buf,path,sizeof(parse_buf));
  664.  
  665.                         if (flock = Lock(parse_buf,ACCESS_READ))    /* Lock() file */
  666.                         {
  667.                             if (Examine(flock,flink->fib))  /* examine file */
  668.                             {
  669.                                 /* get absolute file name and add to list */
  670.                                 NameFromLock(flock,flink->fib->fib_FileName,
  671.                                              sizeof(flink->fib->fib_FileName));
  672.                                 AddTail(&fl->list,&flink->node);
  673.                                 fl->count++;
  674.                                 flink = NULL;
  675.                             }
  676.                             else
  677.                                 PrintFault(IoErr(),parse_buf);
  678.  
  679.                             UnLock(flock);
  680.                         }
  681.                         else
  682.                             PrintFault(IoErr(),parse_buf);
  683.                     }
  684.                 }
  685.                 else
  686.                     PrintFault(IoErr(),pathname);
  687.  
  688.                 UnLock(dlock);
  689.             }
  690.             else
  691.                 PrintFault(IoErr(),pathname);
  692.         }
  693.  
  694.         /* if file information node not used then free it */
  695.         if (flink)
  696.             FreeFileLink(flink);
  697.     }
  698.  
  699.     return(broke);
  700. }
  701.  
  702. /*******************************************************************/
  703. /* callback routine for qsort() to sort file information nodes
  704.    by size */
  705. int
  706. sld_cmp(struct FileLink **f1,
  707.         struct FileLink **f2)
  708. {
  709.     return((*f1)->fib->fib_Size-(*f2)->fib->fib_Size);
  710. }
  711.  
  712. /*******************************************************************/
  713. /* sort list of file information nodes inversely by size */
  714. void
  715. SortListDown(struct FileList *flist)
  716. {
  717.     struct FileLink **flink_array;
  718.     long            i;
  719.  
  720.     if (flist->count)
  721.     {
  722.         if (flink_array = AllocVec(flist->count*sizeof(struct FileLink **),
  723.                                    MEMF_PUBLIC|MEMF_CLEAR))
  724.         {
  725.             /* create array to sort */
  726.             for (i = 0; i < flist->count; i++)
  727.                 flink_array[i] = (struct FileLink *)RemHead(&(flist->list));
  728.  
  729.             /* sort array in ascending order*/
  730.             qsort(flink_array,flist->count,sizeof(struct FileLink **),sld_cmp);
  731.  
  732.             /* rebuild file list in reverse order */
  733.             for (i = 0; i < flist->count; i++)
  734.                 AddHead(&(flist->list),(struct Node *)flink_array[i]);
  735.  
  736.             FreeVec(flink_array);
  737.         }
  738.     }
  739. }
  740.  
  741. /*******************************************************************/
  742. /* find the best file to fit into current disk */
  743. struct FileLink *
  744. GetBestFitFile(struct List  *list,
  745.                long         max_size)
  746. {
  747.     struct FileLink *flink;
  748.  
  749.     flink = (struct FileLink *)list->lh_Head;
  750.  
  751.     while (flink->node.ln_Succ)   /* not end of list? */
  752.     {
  753.         if (flink->fib->fib_Size <= max_size)
  754.             break;
  755.  
  756.         flink = (struct FileLink *)flink->node.ln_Succ;
  757.     }
  758.  
  759.     return(flink->node.ln_Succ ? flink : NULL);
  760. }
  761.  
  762. /*******************************************************************/
  763. /* get information about disk and also return the size of each block
  764.    that is usable */
  765. int /* block capability */
  766. GetDiskInfo(char            *disk_name,
  767.             struct InfoData *info)
  768. {
  769.     BPTR    lock;
  770.     int     block_cap = 0;
  771.  
  772.     if (lock = Lock(disk_name,ACCESS_READ))
  773.     {
  774.         if (Info(lock,info))
  775.         {
  776.             switch (info->id_DiskType)
  777.             {
  778.                 case ID_DOS_DISK:
  779.                 case ID_INTER_DOS_DISK:
  780.                 case ID_FASTDIR_DOS_DISK:
  781.                     block_cap = 488;
  782.                     break;
  783.  
  784.                 case ID_FFS_DISK:
  785.                 case ID_INTER_FFS_DISK:
  786.                 case ID_FASTDIR_FFS_DISK:
  787.                     block_cap = 504;
  788.                     break;
  789.  
  790.                 case ID_MSDOS_DISK:
  791.                     block_cap = 512;    /* this is a guess,
  792.                                            based on tests */
  793.                     break;
  794.  
  795.                 default:
  796.                     block_cap = info->id_BytesPerBlock;
  797.                     break;
  798.             }
  799.         }
  800.  
  801.         UnLock(lock);
  802.     }
  803.  
  804.     return(block_cap);
  805. }
  806.  
  807. /*******************************************************************/
  808. /* calculate how many blocks to reserve */
  809. long
  810. CalcReserveBlocks(long  size,   /* minimum size to reserve */
  811.                   long  block_size) /* usable bytes in each block */
  812. {
  813.     long reserve = 0L;
  814.  
  815.     if (size > 0L)
  816.     {
  817.         reserve = size/block_size;
  818.  
  819.         if (size%block_size)
  820.             reserve++;
  821.     }
  822.  
  823.     return(reserve);
  824. }
  825.  
  826. /*******************************************************************/
  827. /* get the list of files to copy from a file */
  828. BOOL /* broke? */
  829. CollectNamesFromFile(struct FileList *flist,
  830.                      char            *fname)    /* filename to
  831.                                                    read names from */
  832. {
  833.     BPTR    fh;
  834.     char    line[256],
  835.             *s;
  836.     BOOL    broke = FALSE;
  837.  
  838.     if (fh = Open(fname,MODE_OLDFILE))
  839.     {
  840.         while (FGets(fh,line,sizeof(line)))
  841.         {
  842.             /* remove CR and/or LF if any */
  843.             s = line;
  844.             while (*s && (*s != '\r') && (*s != '\n')) s++;
  845.             *s = '\0';
  846.  
  847.             if (broke = CollectFiles(flist,line))
  848.                 break;
  849.         }
  850.  
  851.         Close(fh);
  852.     }
  853.     else
  854.         PrintFault(IoErr(),fname);
  855.  
  856.     return(broke);
  857. }
  858.  
  859. /*******************************************************************/
  860. /* END */
  861.