usrFsLib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:53k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* usrFsLib.c - file system user interface subroutine library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01r,16jan02,chn  SPR#24332, add check to avoid copy() to a directory name dest
  8. 01q,12dec01,jkf  SPR#72133, add FIOMOVE to dosFsLib, use it in mv()
  9. 01p,17oct01,jkf  SPR#74904, function cleanup.
  10. 01o,20sep01,jkf  SPR#69031, common code for both AE & 5.x.
  11. 01n,15mar01,jkf  SPR#33973, copy not preserving time/date.
  12. 01m,15mar01,jkf  SPR#33557, ls returning error on first invocation
  13. 01l,29aug00,jgn  add const to function signatures (SPR #30492) +
  14.  clean up coding standard violations
  15. 01k,17mar00,dgp  modify attrib and xattrib synopsis comments for syngen
  16.                  processing
  17. 01j,16mar00,jkf  removed reference to dosFsVolFormat() from diskInit().
  18. 01i,26dec99,jkf  T3 KHEAP_ALLOC
  19. 01h,31jul99,jkf  T2 merge, tidiness & spelling.
  20. 01g,07dec98,lrn  fixed netDrv spurious error message (SPR#22554)
  21. 01f,23nov98,vld  print '/' after directory name in long output
  22. 01e,13jul98,lrn  fixed diskInit() to call dosFsVolFormat() if open() fails
  23. 01d,02jul98,lrn  corrected parameters for chkdsk()
  24. 01c,28jun98,lrn  added recursive xcopy, xdelete, added wildcards to
  25.                  cp(), mv(), added attrib and xattrib(), added help
  26. 01b,23jun98,lrn  rewrite ls, add more utils
  27. 01a,19feb98,vld  initial version, derived from usrLib.c
  28. */
  29. /*
  30. DESCRIPTION
  31. This library provides user-level utilities for managing file systems.
  32. These utilities may be used from Tornado Shell, the Target Shell or from
  33. an application.
  34. USAGE FROM TORNADO
  35. Some of the functions in this library have counterparts of the same
  36. names built into the Tornado Shell (aka Windsh). The built-in functions
  37. perform similar functions on the Tornado host computer's I/O systems.
  38. Hence if one of such functions needs to be executed in order to perform
  39. any operation on the Target's I/O system, it must be preceded with an
  40. '@' sign, e.g.:
  41. .CE
  42. -> @ls "/sd0"
  43. .CE
  44. will list the directory of a disk named "/sd0" on the target, wile
  45. .CS
  46. -> ls "/tmp"
  47. .CE
  48. will list the contents of the "/tmp" directory on the host.
  49. The target I/O system and the Tornado Shell running on the host, each
  50. have their own notion of current directory, which are not related,
  51. hence
  52. .CS
  53. -> pwd
  54. .CE
  55. will display the Tornado Shell current directory on the host file
  56. system, while
  57. .CS
  58. -> @pwd
  59. .CE
  60. will display the target's current directory on the target's console.
  61. WILDCARDS
  62. Some of the functions herein support wildcard characters in argument
  63. strings where file or directory names are expected. The wildcards are
  64. limited to "*" which matches zero or more characters and "?" which
  65. matches any single characters. Files or directories with names beginning
  66. with a "." are not normally matched with the "*" wildcard.
  67. DIRECTORY LISTING
  68. Directory listing is implemented in one function dirList(), which can be
  69. accessed using one of these four front-end functions:
  70. .iP ls()
  71. produces a short list of files
  72. .iP lsr()
  73. is like ls() but ascends into subdirectories
  74. .iP ll()
  75. produces a detailed list of files, with file size, modification date
  76. attributes etc.
  77. .iP llr()
  78. is like ll() but also ascends into subdirectories
  79. All of the directory listing functions accept a name of a directory or a
  80. single file to list, or a name which contain wildcards, which will
  81. result in listing of all objects that match the wildcard string
  82. provided.
  83. SEE ALSO
  84. ioLib, dosFsLib, netDrv, nfsLib,
  85. .pG "Target Shell"
  86. .pG "Tornado Users's Guide"
  87. */
  88. /* includes */
  89. #include <vxWorks.h>
  90. #include <fioLib.h>
  91. #include "ctype.h"
  92. #include "stdio.h"
  93. #include "ioLib.h"
  94. #include "memLib.h"
  95. #include "string.h"
  96. #include "ftpLib.h"
  97. #include "usrLib.h"
  98. #include "dirent.h"
  99. #include "sys/stat.h"
  100. #include "errnoLib.h"
  101. #include "iosLib.h"
  102. #include "taskLib.h"
  103. #include "logLib.h"
  104. #include "netDrv.h"
  105. #include "time.h"
  106. #include "nfsLib.h"
  107. #include "pathLib.h"
  108. #include "private/dosFsVerP.h"
  109. #include "dosFsLib.h"
  110. #include "stat.h"
  111. #include "utime.h"
  112. /* types */
  113. LOCAL int mvFile (const char *oldname, const char *newname);
  114. /* defines */
  115. /******************************************************************************
  116. *
  117. * usrPathCat - concatenate directory path to filename.
  118. *
  119. * This routine constructs a valid filename from a directory path
  120. * and a filename.
  121. * The resultant path name is put into <result>.
  122. * No arcane rules are used to derive the concatenated result.
  123. *
  124. * RETURNS: N/A.
  125. */
  126. LOCAL void usrPathCat
  127.     (
  128.     const char * dirName,
  129.     const char * fileName,
  130.     char * result
  131.     )
  132.     {
  133.     *result = EOS ;
  134.     if(dirName[0] != EOS && dirName != NULL && strcmp(dirName,".") != 0)
  135. {
  136. strcpy( result, dirName );
  137. strcat( result,  "/" );
  138. }
  139.     strcat( result, fileName );
  140.     } /* usrPathCat() */
  141. /*******************************************************************************
  142. *
  143. * cd - change the default directory
  144. *
  145. * .iP NOTE
  146. * This is a target resident function, which manipulates the target I/O
  147. * system. It must be preceded with the
  148. * '@' letter if executed from the Tornado Shell (windsh), which has a
  149. * built-in command of the same name that operates on the Host's I/O
  150. * system.
  151. *
  152. * This command sets the default directory to <name>.  The default directory
  153. * is a device name, optionally followed by a directory local to that
  154. * device.
  155. *
  156. * To change to a different directory, specify one of the following:
  157. * .iP "" 4
  158. * an entire path name with a device name, possibly followed by a directory
  159. * name.  The entire path name will be changed.
  160. * .iP
  161. * a directory name starting with a `~' or `/' or `$'.  The directory part
  162. * of the path, immediately after the device name, will be replaced with the new
  163. * directory name.
  164. * .iP
  165. * a directory name to be appended to the current default directory.
  166. * The directory name will be appended to the current default directory.
  167. * .LP
  168. *
  169. * An instance of ".." indicates one level up in the directory tree.
  170. *
  171. * Note that when accessing a remote file system via RSH or FTP, the
  172. * VxWorks network device must already have been created using
  173. * netDevCreate().
  174. *
  175. * WARNING
  176. * The cd() command does very little checking that <name> represents a valid
  177. * path.  If the path is invalid, cd() may return OK, but subsequent
  178. * calls that depend on the default path will fail.
  179. *
  180. * EXAMPLES
  181. * The following example changes the directory to device `/fd0/':
  182. * .CS
  183. *     -> cd "/fd0/"
  184. * .CE
  185. * This example changes the directory to device `wrs:' with the local
  186. * directory `~leslie/target':
  187. * .CS
  188. *     -> cd "wrs:~leslie/target"
  189. * .CE
  190. * After the previous command, the following changes the directory to
  191. * `wrs:~leslie/target/config':
  192. * .CS
  193. *     -> cd "config"
  194. * .CE
  195. * After the previous command, the following changes the directory to
  196. * `wrs:~leslie/target/demo':
  197. * .CS
  198. *     -> cd "../demo"
  199. * .CE
  200. * After the previous command, the following changes the directory to
  201. * `wrs:/etc'.
  202. * .CS
  203. *     -> cd "/etc"
  204. * .CE
  205. * Note that `~' can be used only on network devices (RSH or FTP).
  206. *
  207. * RETURNS: OK or ERROR.
  208. *
  209. * SEE ALSO: pwd(),
  210. * .pG "Target Shell"
  211. */
  212. STATUS cd
  213.     (
  214.     const char * name /* new directory name */
  215.     )
  216.     {
  217.     if (ioDefPathCat ((char *)name) != OK)
  218. {
  219. printf ("cd: error = %#x.n", errno);
  220. return (ERROR);
  221. }
  222.     return (OK);
  223.     }
  224. /******************************************************************************
  225. *
  226. * dirNameWildcard - check if file or dir name contains wildcards
  227. *
  228. * RETURNS: TRUE if "*" or "?" are contained in the <name> string
  229. */
  230. LOCAL BOOL dirNameWildcard
  231.     (
  232.     const char * name
  233.     )
  234.     {
  235.     if (index(name, '*') != NULL ||
  236. index(name, '?') != NULL)
  237. return TRUE ;
  238.     else
  239. return FALSE ;
  240.     }
  241. /******************************************************************************
  242. *
  243. * nameIsDir - check if name is a directory
  244. *
  245. * RETURNS: TRUE if the name is an existing directory
  246. */
  247. LOCAL BOOL nameIsDir
  248.     (
  249.     const char * name
  250.     )
  251.     {
  252.     struct stat fStat ;
  253.     if ((name == NULL) || (*name == EOS))
  254. return FALSE ;
  255.     /* if it does not exist, it ain't a directory */
  256.     if (stat ((char *) name, &fStat) == ERROR)
  257.         {
  258. errno = OK ;
  259.      return FALSE;
  260.         }
  261.     if (S_ISDIR (fStat.st_mode))
  262.         {
  263.         return TRUE;
  264.         }
  265.     return FALSE ;
  266.     }
  267. /*******************************************************************************
  268. *
  269. * pwd - print the current default directory
  270. *
  271. * This command displays the current working device/directory.
  272. *
  273. * .iP NOTE
  274. * This is a target resident function, which manipulates the target I/O
  275. * system. It must be preceded with the
  276. * '@' letter if executed from the Tornado Shell (windsh), which has a
  277. * built-in command of the same name that operates on the Host's I/O
  278. * system.
  279. *
  280. * RETURNS: N/A
  281. *
  282. * SEE ALSO: cd(),
  283. * .pG "Target Shell,"
  284. * windsh,
  285. * .tG "Shell"
  286. */
  287. void pwd (void)
  288.     {
  289.     char name [MAX_FILENAME_LENGTH];
  290.     ioDefPathGet (name);
  291.     printf ("%sn", name);
  292.     }
  293. /*******************************************************************************
  294. *
  295. * mkdir - make a directory
  296. *
  297. * This command creates a new directory in a hierarchical file system.
  298. * The <dirName> string specifies the name to be used for the
  299. * new directory, and can be either a full or relative pathname.
  300. *
  301. * This call is supported by the VxWorks NFS and dosFs file systems.
  302. *
  303. * RETURNS: OK, or ERROR if the directory cannot be created.
  304. *
  305. * SEE ALSO: rmdir(),
  306. * .pG "Target Shell"
  307. */
  308. STATUS mkdir
  309.     (
  310.     const char * dirName /* directory name */
  311.     )
  312.     {
  313.     int fd;
  314.     if ((fd = open (dirName, O_RDWR | O_CREAT, FSTAT_DIR | DEFAULT_DIR_PERM))
  315.  == ERROR)
  316. {
  317. return (ERROR);
  318. }
  319.     return (close (fd));
  320.     }
  321. /*******************************************************************************
  322. *
  323. * rmdir - remove a directory
  324. *
  325. * This command removes an existing directory from a hierarchical file
  326. * system.  The <dirName> string specifies the name of the directory to
  327. * be removed, and may be either a full or relative pathname.
  328. *
  329. * This call is supported by the VxWorks NFS and dosFs file systems.
  330. *
  331. * RETURNS: OK, or ERROR if the directory cannot be removed.
  332. *
  333. * SEE ALSO: mkdir(),
  334. * .pG "Target Shell"
  335. */
  336. STATUS rmdir
  337.     (
  338.     const char * dirName /* name of directory to remove */
  339.     )
  340.     {
  341.     return (remove (dirName));
  342.     }
  343. /*******************************************************************************
  344. *
  345. * rm - remove a file
  346. *
  347. * This command is provided for UNIX similarity.  It simply calls remove().
  348. *
  349. * RETURNS: OK, or ERROR if the file cannot be removed.
  350. *
  351. * SEE ALSO: remove(),
  352. * .pG "Target Shell"
  353. */
  354. STATUS rm
  355.     (
  356.     const char * fileName /* name of file to remove */
  357.     )
  358.     {
  359.     return (remove (fileName));
  360.     }
  361. /*******************************************************************************
  362. *
  363. * copyStreams - copy from/to specified streams
  364. *
  365. * This command copies from the stream identified by <inFd> to the stream
  366. * identified by <outFd> until an end of file is reached in <inFd>.
  367. * This command is used by copy().
  368. *
  369. * INTERNAL
  370. * The size of an array buffer can have a dramatic impact on the throughput
  371. * achieved by the copyStreams() routine.  The default is 1 Kbyte, but this
  372. * can be increased as long as the calling task (usually the VxWorks shell)
  373. * has ample stack space.  Alternately, copyStreams() can be modified to use a
  374. * static buffer, as long as the routine is guaranteed not to be called in
  375. * the context of more than one task simultaneously.
  376. *
  377. * RETURNS: OK, or ERROR if there is an error reading from <inFd> or writing
  378. * to <outFd>.
  379. *
  380. * SEE ALSO: copy(),
  381. * .pG "Target Shell"
  382. *
  383. * INTERNAL
  384. * Note use of printErr since printf's would probably go to the output stream
  385. * outFd!
  386. */
  387. STATUS copyStreams
  388.     (
  389.     int inFd, /* file descriptor of stream to copy from */
  390.     int outFd  /* file descriptor of stream to copy to */
  391.     )
  392.     {
  393.     char * buffer;
  394.     int totalBytes = 0;
  395.     int nbytes;
  396.     size_t dSize;
  397.     /* update file size */
  398.     if (ioctl( inFd, FIONREAD, (int)&dSize ) == ERROR)
  399.      dSize = 1024;
  400.     /* transferring buffer */
  401.     dSize = min( 0x10000, dSize );
  402.     buffer = KHEAP_ALLOC( dSize );
  403.     if (buffer == NULL)
  404.      return ERROR;
  405.     while ((nbytes = fioRead (inFd, buffer, dSize)) > 0)
  406. {
  407. if (write (outFd, buffer, nbytes) != nbytes)
  408.     {
  409.     printErr ("copy: error writing file. errno %pn", (void *)errno);
  410.           KHEAP_FREE( buffer );
  411.     return (ERROR);
  412.     }
  413. totalBytes += nbytes;
  414.      }
  415.     KHEAP_FREE( buffer );
  416.     if (nbytes < 0)
  417. {
  418. printErr ("copy: error reading file after copying %d bytes.n",
  419.  totalBytes);
  420. return (ERROR);
  421. }
  422.     printf("Copy OK: %u bytes copiedn", totalBytes );
  423.     return (OK);
  424.     }
  425. /*******************************************************************************
  426. *
  427. * copy - copy <in> (or stdin) to <out> (or stdout)
  428. *
  429. * This command copies from the input file to the output file, until an
  430. * end-of-file is reached.
  431. *
  432. * EXAMPLES:
  433. * The following example displays the file `dog', found on the default file
  434. * device:
  435. * .CS
  436. *     -> copy <dog
  437. * .CE
  438. * This example copies from the console to the file `dog', on device `/ct0/',
  439. * until an EOF (default ^D) is typed:
  440. * .CS
  441. *     -> copy >/ct0/dog
  442. * .CE
  443. * This example copies the file `dog', found on the default file device, to
  444. * device `/ct0/':
  445. * .CS
  446. *     -> copy <dog >/ct0/dog
  447. * .CE
  448. * This example makes a conventional copy from the file named `file1' to the file
  449. * named `file2':
  450. * .CS
  451. *     -> copy "file1", "file2"
  452. * .CE
  453. * Remember that standard input and output are global; therefore, spawning
  454. * the first three constructs will not work as expected.
  455. *
  456. * RETURNS:
  457. * OK, or
  458. * ERROR if <in> or <out> cannot be opened/created, or if there is an
  459. * error copying from <in> to <out>.
  460. *
  461. * SEE ALSO: copyStreams(), tyEOFSet(), cp(), xcopy()
  462. * .pG "Target Shell"
  463. */
  464. STATUS copy
  465.     (
  466.     const char *in, /* name of file to read  (if NULL assume stdin)  */
  467.     const char *out  /* name of file to write (if NULL assume stdout) */
  468.     )
  469.     {
  470.     int inFd = ERROR;
  471.     int outFd = ERROR;
  472.     int status;
  473.     struct stat    fileStat; /* structure to fill with data */
  474.     struct utimbuf fileTime;
  475.     /* open input file */
  476.     inFd = in ? open (in, O_RDONLY, 0) : STD_IN;
  477.     if (inFd == ERROR)
  478. {
  479. printErr ("Can't open input file "%s" errno = %pn",
  480.   in, (void *)errno );
  481. return (ERROR);
  482. }
  483.    
  484.     /* Is this a directory or a file, can't write to a directory! */
  485.     if (nameIsDir(out)) 
  486.         {
  487.         errnoSet(S_ioLib_CANT_OVERWRITE_DIR);
  488.         close(inFd);
  489.         return(ERROR);
  490.         }
  491.     /* creat output file */
  492.     outFd = out ? creat (out, O_WRONLY) : STD_OUT;
  493.     if (outFd  == ERROR)
  494. {
  495. printErr ("Can't write to "%s", errno %pn", out, (void *)errno);
  496.      if (in)
  497.          close( inFd );
  498. return (ERROR);
  499. }
  500.     /* copy data */
  501.     status = copyStreams (inFd, outFd);
  502.     ioctl (inFd, FIOFSTATGET, (int) &fileStat);
  503.     fileTime.actime = fileStat.st_atime;
  504.     fileTime.modtime = fileStat.st_mtime;
  505.     ioctl (outFd, FIOTIMESET, (int) &fileTime);
  506.     if (in)
  507. close (inFd);
  508.     /* close could cause buffers flushing */
  509.     if (out && close (outFd) == ERROR)
  510. status = ERROR;
  511.     return (status);
  512.     }
  513. /********************************************************************************
  514. * chkdsk - perform consistency checking on a MS-DOS file system
  515. *
  516. * This function invokes the integral consistency checking built
  517. * into the dosFsLib file system, via FIOCHKDSK ioctl.
  518. * During the test, the file system will be blocked from application code
  519. * access, and will emit messages describing any inconsistencies found on
  520. * the disk, as well as some statistics, depending on the value of the
  521. * <verbose> argument.
  522. * Depending the value of <repairLevel>, the inconsistencies will be
  523. * repaired, and changes written to disk.
  524. *
  525. * These are the values for <repairLevel>:
  526. * .iP 0
  527. * Same as DOS_CHK_ONLY (1)
  528. * .IP "DOS_CHK_ONLY (1)"
  529. * Only report errors, do not modify disk.
  530. * .IP "DOS_CHK_REPAIR (2)"
  531. * Repair any errors found.
  532. *
  533. * These are the values for <verbose>:
  534. * .iP 0
  535. * similar to DOS_CHK_VERB_1
  536. * .iP "DOS_CHK_VERB_SILENT (0xff00)"
  537. * Do not emit any messages, except errors encountered.
  538. * .iP "DOS_CHK_VERB_1 (0x0100)"
  539. * Display some volume statistics when done testing, as well
  540. * as errors encountered during the test.
  541. * .iP "DOS_CHK_VERB_2 (0x0200)"
  542. * In addition to the above option, display path of every file, while it
  543. * is being checked. This option may significantly slow down
  544. * the test process.
  545. *
  546. * Note that the consistency check procedure will
  547. * .I unmount
  548. * the file system, meaning the all currently open file descriptors will
  549. * be deemed unusable.
  550. *
  551. * RETURNS: OK or ERROR if device can not be checked or could not be repaired.
  552. *
  553. */
  554. STATUS chkdsk
  555.     (
  556.     const char * pDevName, /* device name */
  557.     u_int repairLevel, /* how to fix errors */
  558.     u_int verbose /* verbosity level */
  559.     )
  560.     {
  561.     int fd = open (pDevName, O_RDONLY, 0);
  562.     STATUS retStat;
  563.     if (fd == ERROR)
  564.      {
  565.      perror (pDevName);
  566.      return ERROR;
  567.      }
  568.     repairLevel &= 0x0f;
  569.     if ((verbose & 0xff00) != 0)
  570.      verbose  &= 0xff00;
  571.     else if ((verbose & 0xff) != 0)
  572.      verbose  <<= 8;
  573.     else /* default is 1 */
  574.      verbose  = 0x0100;
  575.   
  576.     retStat = ioctl (fd, FIOCHKDSK, repairLevel | verbose);
  577.     close (fd);
  578.     return retStat;
  579.     } /* chkDsk() */
  580. /*******************************************************************************
  581. *
  582. * dirListPattern - match file name pattern with an actual file name
  583. *
  584. * <pat> is a pattern consisting with '?' and '*' wildcard characters,
  585. * which is matched against the <name> filename, and TRUE is returned
  586. * if they match, or FALSE if do not match. Both arguments must be
  587. * null terminated strings.
  588. * The pattern matching is case insensitive.
  589. *
  590. * NOTE: we're using EOS as integral part of the pattern and name.
  591. */
  592. LOCAL BOOL dirListPattern
  593.     (
  594.     char * pat,
  595.     char * name
  596.     )
  597.     {
  598.     FAST char * pPat;
  599.     FAST char * pNext;
  600.     const char anyOne = '?';
  601.     const char anyMany = '*';
  602.     pPat = pat ;
  603.     for (pNext = name ; * pNext != EOS ; pNext ++)
  604. {
  605. /* DEBUG-  logMsg("pattern %s, name %sn", pPat, pNext, 0,0,0,0);*/
  606. if (*pPat == anyOne)
  607.     {
  608.     pPat ++ ;
  609.     }
  610. else if (*pPat == anyMany)
  611.     {
  612.     if (pNext[0] == '.') /* '*' dont match . .. and .xxx */
  613. return FALSE ;
  614.     if (toupper(pPat[1]) == toupper(pNext[1]))
  615. pPat ++ ;
  616.     else if (toupper(pPat[1]) == toupper(pNext[0]))
  617. pPat += 2 ;
  618.     else
  619. continue ;
  620.     }
  621. else if (toupper(*pPat) != toupper(*pNext))
  622.     {
  623.     return FALSE ;
  624.     }
  625. else
  626.     {
  627.     pPat ++ ;
  628.     }
  629. }
  630.     /* loop is done, let's see if there is anything left */
  631.     if ((*pPat == EOS) || (pPat[0] == anyMany && pPat[1] == EOS))
  632. return TRUE ;
  633.     else
  634. return FALSE ;
  635.     }
  636. /*******************************************************************************
  637. *
  638. * dirListEnt - list one file or directory
  639. *
  640. * List one particular file or directory entry.
  641. *
  642. * NOMANUAL
  643. */
  644. LOCAL STATUS dirListEnt
  645.     (
  646.     int fd, /* file descriptor for output */
  647.     char * fileName, /* file name */
  648.     struct stat * fileStat, /* stat() structure */
  649.     char * prefix, /* prefix for short output */
  650.     BOOL doLong /* do Long listing format */
  651.     )
  652.     {
  653.     time_t now; /* current clock */
  654.     struct tm nowDate; /* current date & time */
  655.     struct tm fileDate; /* file date/time      (long listing) */
  656.     const  char  *monthNames[] = {"???", "Jan", "Feb", "Mar", "Apr",
  657.       "May", "Jun", "Jul", "Aug", "Sep",
  658.       "Oct", "Nov", "Dec"};
  659.     char fType, modbits[10] ;
  660.     char suffix = ' '; /* print '/' after directory name */
  661.     if(doLong)
  662. {
  663. /* Break down file modified time */
  664. time( &now );
  665. localtime_r (&now, &nowDate);
  666. localtime_r (&fileStat->st_mtime, &fileDate);
  667. if (fileStat->st_attrib & DOS_ATTR_RDONLY)
  668.     fileStat->st_mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
  669. if (S_ISDIR (fileStat->st_mode))
  670.          {
  671.     fType = 'd' ;
  672.          suffix = '/';
  673.          }
  674. else if (S_ISREG (fileStat->st_mode))
  675.     fType = '-' ;
  676. else
  677.     fType = '?' ;
  678. strcpy( modbits, "---------" );
  679. modbits[0] = (fileStat->st_mode & S_IRUSR)? 'r':'-';
  680. modbits[1] = (fileStat->st_mode & S_IWUSR)? 'w':'-';
  681. modbits[2] = (fileStat->st_mode & S_IXUSR)? 'x':'-';
  682. modbits[3] = (fileStat->st_mode & S_IRGRP)? 'r':'-';
  683. modbits[4] = (fileStat->st_mode & S_IWGRP)? 'w':'-';
  684. modbits[5] = (fileStat->st_mode & S_IXGRP)? 'x':'-';
  685. modbits[6] = (fileStat->st_mode & S_IROTH)? 'r':'-';
  686. modbits[7] = (fileStat->st_mode & S_IWOTH)? 'w':'-';
  687. modbits[8] = (fileStat->st_mode & S_IXOTH)? 'x':'-';
  688. if (fileStat->st_attrib & DOS_ATTR_ARCHIVE)
  689.     modbits[6] = 'A';
  690. if(fileStat->st_attrib & DOS_ATTR_SYSTEM)
  691.     modbits[7] = 'S';
  692. if(fileStat->st_attrib & DOS_ATTR_HIDDEN)
  693.     modbits[8] = 'H';
  694. modbits[9] = EOS ;
  695. /* print file mode */
  696. fdprintf(fd, "%c%9s", fType, modbits);
  697. /* fake links, user and group fields */
  698. fdprintf(fd, " %2d %-7d %-7d ", fileStat->st_nlink,
  699. fileStat->st_uid, fileStat->st_gid );
  700. /* print file size - XXX: add 64 bit file size support */
  701. fdprintf(fd, " %9lu ", fileStat->st_size );
  702. /* print date */
  703. if (fileDate.tm_year == nowDate.tm_year)
  704.     {
  705.     fdprintf(fd, "%s %2d %02d:%02d ",
  706.     monthNames [fileDate.tm_mon + 1],/* month */
  707.     fileDate.tm_mday,               /* day of month */
  708.     fileDate.tm_hour, /* hour */
  709.     fileDate.tm_min /* minute */
  710.     );
  711.     }
  712. else
  713.     {
  714.     fdprintf(fd, "%s %2d  %04d ",
  715.     monthNames [fileDate.tm_mon + 1],/* month */
  716.     fileDate.tm_mday, /* day of month */
  717.     fileDate.tm_year+1900 /* year */
  718.     );
  719.     }
  720. } /* if doLong */
  721.     else
  722. { /* short listing */
  723. if (strcmp(prefix , ".") == 0 || prefix[0] == EOS)
  724.     /* dint print "." prefix */ ;
  725. else if (prefix != NULL &&  prefix [ strlen(prefix) -1 ] != '/')
  726.     fdprintf(fd, "%s/", prefix);
  727. else if (prefix != NULL)
  728.     fdprintf(fd, prefix);
  729. }
  730.     /* last, print file name */
  731.     if (fdprintf(fd, "%s%cn", fileName, suffix ) == ERROR)
  732. return ERROR;
  733.     return OK ;
  734.     }
  735. /*******************************************************************************
  736. *
  737. * dirList - list contents of a directory (multi-purpose)
  738. *
  739. * This command is similar to UNIX ls.  It lists the contents of a directory
  740. * in one of two formats.  If <doLong> is FALSE, only the names of the files
  741. * (or subdirectories) in the specified directory are displayed.  If <doLong>
  742. * is TRUE, then the file name, size, date, and time are displayed.
  743. * If <doTree> flag is TRUE, then each subdirectory encountered
  744. * will be listed as well (i.e. the listing will be recursive).
  745. *
  746. * The <dirName> parameter specifies the directory to be listed.
  747. * If <dirName> is omitted or NULL, the current working directory will be
  748. * listed. <dirName> may contain wildcard characters to list some
  749. * of the directory's contents.
  750. *
  751. * LIMITATIONS
  752. * .iP -
  753. * With dosFsLib file systems, MS-DOS volume label entries are not reported.
  754. * .iP -
  755. * Although an output format very similar to UNIX "ls" is employed,
  756. * some information items have no particular meaning on some
  757. * file systems.
  758. * .iP -
  759. * Some file systems which do not support the POSIX compliant dirLib()
  760. * interface, can not support the <doLong> and <doTree> options.
  761. *
  762. * RETURNS:  OK or ERROR.
  763. *
  764. * SEE ALSO: dirLib, dosFsLib, ls(), ll(), lsr(), llr()
  765. */
  766. STATUS dirList
  767.     (
  768.     int         fd,             /* file descriptor to write on */
  769.     char *      dirName,        /* name of the directory to be listed */
  770.     BOOL        doLong,         /* if TRUE, do long listing */
  771.     BOOL doTree /* if TRUE, recurse into subdirs */
  772.     )
  773.     {
  774.     FAST STATUS status; /* return status */
  775.     FAST DIR *pDir; /* ptr to directory descriptor */
  776.     FAST struct dirent *pDirEnt; /* ptr to dirent */
  777.     struct stat fileStat; /* file status info    (long listing) */
  778.     char *pPattern; /* wildcard pattern */
  779.     char  fileName [MAX_FILENAME_LENGTH];
  780. /* buffer for building file name */
  781.     /* If no directory name specified, use "." */
  782.     if (dirName == NULL)
  783. dirName = ".";
  784.     /* try to do a netDrv listing first, hacky way to know its a local FS */
  785.     if (_func_netLsByName != NULL)
  786. {
  787. if ((*_func_netLsByName) (dirName) == OK)
  788.     return (OK);
  789. else if (errno != S_netDrv_UNKNOWN_REQUEST)
  790.     return (ERROR);
  791. }
  792.     pDir = NULL ; pPattern = NULL ;
  793.     /* Open dir */
  794.     pDir = opendir (dirName) ;
  795.     /* could not opendir: last component may be a wildcard  pattern */
  796.     if (pDir == NULL)
  797. {
  798. pPattern = rindex(dirName, '/');
  799. if ( pPattern != NULL && pPattern != dirName &&
  800. dirNameWildcard(pPattern))
  801.     {
  802.     /* dir and pattern e.g. dir1/a*.c */
  803.     *pPattern++ = EOS ;
  804.     pDir = opendir (dirName) ;
  805.     }
  806. else if (dirNameWildcard( dirName ))
  807.     {
  808.     /* just pattern e.g. *.c or abc.? */
  809.     pPattern = dirName ;
  810.     dirName = "." ;
  811.     pDir = opendir (dirName) ;
  812.     }
  813.   }
  814.      /* count not opendir: no can do ! */
  815.      if (pDir == NULL)
  816. goto _nodir ;
  817.     status = OK;
  818.     /* print directory name as header */
  819.     if (dirName == ".")
  820. dirName = "" ;
  821.     else if (doLong)
  822. fdprintf(fd,"nListing Directory %s:n", dirName);
  823.     do
  824. {
  825. errno = OK;
  826.      pDirEnt = readdir (pDir);
  827. if (pDirEnt != NULL)
  828.     {
  829.     if (pPattern != NULL &&
  830. dirListPattern( pPattern, pDirEnt->d_name) == FALSE)
  831. continue ;
  832.     if (doLong) /* if doing long listing */
  833. {
  834. /* Construct path/filename for stat */
  835. usrPathCat( dirName, pDirEnt->d_name, fileName );
  836. /* Get and print file status info */
  837. if (stat (fileName, &fileStat) != OK)
  838.     {
  839.     /* stat() error, mark the file questionable and continue */
  840.     bzero( (caddr_t) &fileStat, sizeof(fileStat));
  841.     }
  842. }
  843.     if (dirListEnt(fd, pDirEnt->d_name,
  844. &fileStat, dirName, doLong ) == ERROR)
  845. status = ERROR;
  846.     }
  847. else /* readdir returned NULL */
  848.     {
  849.     if (errno != OK) /* if real error, not dir end */
  850. {
  851. fdprintf (fd, "error reading dir %s, errno: %xn",
  852. dirName, errno) ;
  853. status = ERROR;
  854. }
  855.     }
  856. } while (pDirEnt != NULL); /* until end of dir */
  857.     /* Close dir */
  858.     status |= closedir (pDir);
  859.     if (! doTree)
  860. return (status);
  861.     /* do recursion into each subdir AFTER all files and subdir are listed */
  862.     if (dirName[0] == EOS)
  863. pDir = opendir (".") ;
  864.     else
  865. pDir = opendir (dirName) ;
  866.     if (pDir == NULL)
  867. goto _nodir ;
  868.     do
  869. {
  870. errno = OK;
  871.      pDirEnt = readdir (pDir);
  872. if (pDirEnt != NULL)
  873.     {
  874.     if (pPattern != NULL &&
  875. dirListPattern( pPattern, pDirEnt->d_name) == FALSE)
  876. continue ;
  877.    
  878.     /* Construct path/filename for stat */
  879.     usrPathCat( dirName, pDirEnt->d_name, fileName );
  880.     /* Get and print file status info */
  881.     if (stat (fileName, &fileStat) != OK)
  882. {
  883. /* stat() error, mark the file questionable and continue */
  884. bzero( (caddr_t) &fileStat, sizeof(fileStat));
  885. }
  886.     /* recurse into subdir, but not "." or ".." */
  887.     if (S_ISDIR (fileStat.st_mode) &&
  888. strcmp(pDirEnt->d_name,"." ) &&
  889. strcmp(pDirEnt->d_name,".." ))
  890. {
  891. status = dirList( fd, fileName, doLong, doTree );
  892. /* maybe count files ?? */
  893. }
  894.     }
  895. else /* readdir returned NULL */
  896.     {
  897.     if (errno != OK) /* if real error, not dir end */
  898. {
  899. fdprintf (fd, "error reading dir %s, errno: %xn",
  900. dirName, errno) ;
  901. status = ERROR;
  902. }
  903.     }
  904. } while (pDirEnt != NULL); /* until end of dir */
  905.     /* Close dir */
  906.     status |= closedir (pDir);
  907.     return (status);
  908. _nodir:
  909.     fdprintf (fd, "Can't open "%s".n", dirName);
  910.     return (ERROR);
  911.     }
  912. /*******************************************************************************
  913. *
  914. * ls - generate a brief listing of a directory
  915. *
  916. * This function is simply a front-end for dirList(), intended for
  917. * brevity and backward compatibility. It produces a list of files
  918. * and directories, without details such as file size and date,
  919. * and without recursion into subdirectories.
  920. *
  921. * <dirName> is a name of a directory or file, and may contain wildcards.
  922. * <doLong> is provided for backward compatibility.
  923. *
  924. * .iP NOTE
  925. * This is a target resident function, which manipulates the target I/O
  926. * system. It must be preceded with the
  927. * '@' letter if executed from the Tornado Shell (windsh), which has a
  928. * built-in command of the same name that operates on the Host's I/O
  929. * system.
  930. *
  931. * RETURNS: OK or ERROR.
  932. *
  933. * SEE ALSO: dirList()
  934. */
  935. STATUS ls
  936.     (
  937.     char *dirName, /* name of dir to list */
  938.     BOOL doLong /* switch on details */
  939.     )
  940.     {
  941.     return (dirList (STD_OUT, dirName, doLong, FALSE));
  942.     }
  943. /******************************************************************************
  944. *
  945. * ll - generate a long listing of directory contents
  946. *
  947. * This command causes a long listing of a directory's contents to be
  948. * displayed.  It is equivalent to:
  949. * .CS
  950. *     -> dirList 1, dirName, TRUE, FALSE
  951. * .CE
  952. *
  953. * <dirName> is a name of a directory or file, and may contain wildcards.
  954. *
  955. * .iP "NOTE 1:"
  956. * This is a target resident function, which manipulates the target I/O
  957. * system. It must be preceded with the
  958. * '@' letter if executed from the Tornado Shell (windsh), which has a
  959. * built-in command of the same name that operates on the Host's I/O
  960. * system.
  961. *
  962. * .iP "NOTE 2:"
  963. * When used with netDrv devices (FTP or RSH), ll() does not give
  964. * directory information.  It is equivalent to an ls() call with no
  965. * long-listing option.
  966. *
  967. * RETURNS: OK or ERROR.
  968. *
  969. * SEE ALSO: dirList()
  970. */
  971. STATUS ll
  972.     (   
  973.     char *dirName               /* name of directory to list */
  974.     )
  975.     {
  976.     return (dirList (STD_OUT, dirName, TRUE, FALSE));
  977.     }
  978. /*******************************************************************************
  979. *
  980. * lsr - list the contents of a directory and any of its subdirectories
  981. *
  982. * This function is simply a front-end for dirList(), intended for
  983. * brevity and backward compatibility. It produces a list of files
  984. * and directories, without details such as file size and date,
  985. * with recursion into subdirectories.
  986. *
  987. * <dirName> is a name of a directory or file, and may contain wildcards.
  988. *
  989. * RETURNS: OK or ERROR.
  990. *
  991. * SEE ALSO: dirList()
  992. */
  993. STATUS lsr
  994.     (
  995.     char *dirName /* name of dir to list */
  996.     )
  997.     {
  998.     return (dirList( STD_OUT, dirName, FALSE, TRUE));
  999.     }
  1000. /******************************************************************************
  1001. *
  1002. * llr - do a long listing of directory and all its subdirectories contents
  1003. *
  1004. * This command causes a long listing of a directory's contents to be
  1005. * displayed.  It is equivalent to:
  1006. * .CS
  1007. *     -> dirList 1, dirName, TRUE, TRUE
  1008. * .CE
  1009.  *
  1010. * <dirName> is a name of a directory or file, and may contain wildcards.
  1011. *
  1012. * NOTE: When used with netDrv devices (FTP or RSH), ll() does not give
  1013. * directory information.  It is equivalent to an ls() call with no
  1014. * long-listing option.
  1015. *
  1016. * RETURNS: OK or ERROR.
  1017. *
  1018. * SEE ALSO: dirList()
  1019. */
  1020. STATUS llr
  1021.     (   
  1022.     char *dirName               /* name of directory to list */
  1023.     )
  1024.     {
  1025.     return (dirList (STD_OUT, dirName, TRUE, TRUE));
  1026.     }
  1027. /********************************************************************************
  1028. * cp - copy file into other file/directory.
  1029. *
  1030. * This command copies from the input file to the output file.
  1031. * If destination name is directory, a source file is copied into
  1032. * this directory, using the last element of the source file name
  1033. * to be the name of the destination file.
  1034. *
  1035. * This function is very similar to copy(), except it is somewhat
  1036. * more similar to the UNIX "cp" program in its handling of the
  1037. * destination.
  1038. *
  1039. * <src> may contain a wildcard pattern, in which case all files
  1040. * matching the pattern will be copied to the directory specified in
  1041. * <dest>.
  1042. * This function does not copy directories, and is not recursive.
  1043. * To copy entire subdirectories recursively, use xcopy().
  1044. *
  1045. * EXAMPLES
  1046. * .CS
  1047. * -> cp( "/sd0/FILE1.DAT","/sd0/dir2/f001.dat")
  1048. * -> cp( "/sd0/dir1/file88","/sd0/dir2")
  1049. * -> cp( "/sd0/@.tmp","/sd0/junkdir")
  1050. * .CE
  1051. *
  1052. * RETURNS: OK or ERROR if destination is not a directory while <src> is
  1053. * a wildcard pattern, or if any of the files could not be copied.
  1054. *
  1055. * SEE ALSO; xcopy()
  1056. *
  1057. */
  1058. STATUS cp
  1059.     (
  1060.     const char *src,   /* source file or wildcard pattern */
  1061.     const char *dest   /* destination file name or directory */
  1062.     )
  1063.     {
  1064.     FAST DIR *pDir; /* ptr to directory descriptor */
  1065.     FAST struct dirent *pDirEnt; /* ptr to dirent */
  1066.     STATUS status = OK ;
  1067.     char * pattern = NULL ;
  1068.     char * dirName = NULL ;
  1069.     char  dir[MAX_FILENAME_LENGTH] ;
  1070.     char  fileName[MAX_FILENAME_LENGTH] ;
  1071.     char  destName[MAX_FILENAME_LENGTH] ;
  1072.     if (src == NULL)
  1073.      {
  1074. errno = EINVAL ;
  1075.         return ERROR;
  1076.      }
  1077.     if (dest == NULL)
  1078. dest = "." ;
  1079.     /* dest does not exist or regular file */
  1080.     if (!nameIsDir (dest))
  1081. {
  1082. if (dirNameWildcard (src))
  1083.     {
  1084.     printErr("mv: destination "%s" not a directoryn", dest );
  1085.     errno = ENOTDIR ;
  1086.     return ERROR;
  1087.     }
  1088. printf("copying file %s -> %sn", src, dest );
  1089.         return copy( src, dest );
  1090. }
  1091.     strncpy( dir, src, MAX_FILENAME_LENGTH-1 );
  1092.     pattern = rindex(dir, '/');
  1093.     if ( pattern != NULL && pattern != dir && dirNameWildcard(pattern))
  1094. {
  1095. /* dir and pattern e.g. dir1/a*.c */
  1096. *pattern++ = EOS ;
  1097. dirName = dir ;
  1098. }
  1099.     else if (dirNameWildcard (dir))
  1100. {
  1101. /* just pattern e.g. *.c or abc.? */
  1102. pattern = dir;
  1103. dirName = "." ;
  1104. }
  1105.     else
  1106. {
  1107. pattern = NULL ;
  1108. dirName = dir ;
  1109. }
  1110.     if (pattern == NULL)
  1111. {
  1112. printf("copying file %s -> %sn", src, dest );
  1113. return copy(src, dest ) ;
  1114. }
  1115.     pDir = opendir (dirName) ;
  1116.     if (pDir == NULL)
  1117. {
  1118. perror(dirName);
  1119. return ERROR;
  1120. }
  1121.     errno = OK;
  1122.     do
  1123. {
  1124.      pDirEnt = readdir (pDir);
  1125. if (pDirEnt != NULL)
  1126.     {
  1127.     if (pattern != NULL &&
  1128. dirListPattern( pattern, pDirEnt->d_name) == FALSE)
  1129. continue ;
  1130.     if (strcmp(pDirEnt->d_name,"." )  == 0 &&
  1131. strcmp(pDirEnt->d_name,".." ) == 0)
  1132. continue ;
  1133.     /* Construct path/filename for stat */
  1134.     usrPathCat( dirName, pDirEnt->d_name, fileName );
  1135.     usrPathCat( dest, pDirEnt->d_name, destName );
  1136.     if (nameIsDir( fileName ))
  1137. {
  1138. printf("skipping directory %sn", fileName );
  1139. continue;
  1140. }
  1141.     printf("copying file %s -> %sn", fileName, destName );
  1142.     status |= copy( fileName, destName );
  1143.     }
  1144. } while (pDirEnt != NULL); /* until end of dir */
  1145.     status |= closedir (pDir);
  1146.     return status ;
  1147.     }/* cp() */
  1148. /********************************************************************************
  1149. * mv - mv file into other directory.
  1150. *
  1151. * This function is similar to rename() but behaves somewhat more
  1152. * like the UNIX program "mv", it will overwrite files.
  1153. *
  1154. * This command moves the <src> file or directory into
  1155. * a file which name is passed in the <dest> argument, if <dest> is
  1156. * a regular file or does not exist.
  1157. * If <dest> name is a directory, the source object is moved into
  1158. * this directory as with the same name,
  1159. * if <dest> is NULL, the current directory is assumed as the destination
  1160. * directory.
  1161. * <src> may be a single file name or a path containing a wildcard
  1162. * pattern, in which case all files or directories matching the pattern
  1163. * will be moved to <dest> which must be a directory in this case.
  1164. *
  1165. * EXAMPLES
  1166. * .CS
  1167. * -> mv( "/sd0/dir1","/sd0/dir2")
  1168. * -> mv( "/sd0/@.tmp","/sd0/junkdir")
  1169. * -> mv( "/sd0/FILE1.DAT","/sd0/dir2/f001.dat")
  1170. * .CE
  1171. *
  1172. * RETURNS: OK or error if any of the files or directories could not be
  1173. * moved, or if <src> is a pattern but the destination is not a
  1174. * directory.
  1175. */
  1176. STATUS mv
  1177.     (   
  1178.     const char *src,   /* source file name or wildcard */
  1179.     const char *dest   /* destination name or directory */
  1180.     )
  1181.     {
  1182.     FAST DIR *pDir; /* ptr to directory descriptor */
  1183.     FAST struct dirent *pDirEnt; /* ptr to dirent */
  1184.     STATUS status = OK ;
  1185.     char * pattern = NULL ;
  1186.     char * dirName = NULL ;
  1187.     char  dir[MAX_FILENAME_LENGTH] ;
  1188.     char  fileName[MAX_FILENAME_LENGTH] ;
  1189.     char  destName[MAX_FILENAME_LENGTH] ;
  1190.     if (src == NULL)
  1191.      {
  1192. errno = EINVAL ;
  1193.         return ERROR;
  1194.      }
  1195.     if (dest == NULL)
  1196. dest = "." ;
  1197.     /* dest does not exist or regular file */
  1198.     if (nameIsDir( dest ) == nameIsDir( src ))
  1199. {
  1200. if (dirNameWildcard( src))
  1201.     {
  1202.     printErr("mv: destination "%s" not a directoryn", dest );
  1203.     errno = ENOTDIR ;
  1204.     return ERROR;
  1205.     }
  1206. printf("moving file %s -> %sn", src, dest );
  1207.         return mvFile ( src, dest );
  1208. }
  1209.     strncpy( dir, src, MAX_FILENAME_LENGTH-1 );
  1210.     pattern = rindex(dir, '/');
  1211.     if ( pattern != NULL && pattern != dir && dirNameWildcard(pattern))
  1212. {
  1213. /* dir and pattern e.g. dir1/a*.c */
  1214. *pattern++ = EOS ;
  1215. dirName = dir ;
  1216. }
  1217.     else if (dirNameWildcard( dir))
  1218. {
  1219. /* just pattern e.g. *.c or abc.? */
  1220. pattern = dir;
  1221. dirName = "." ;
  1222. }
  1223.     else
  1224. {
  1225. pattern = NULL ;
  1226. dirName = dir ;
  1227. }
  1228.     if (pattern == NULL)
  1229. {
  1230. printf("moving file %s -> %sn", src, dest );
  1231. return (mvFile (src, dest ));
  1232. }
  1233.     pDir = opendir (dirName) ;
  1234.     if (pDir == NULL)
  1235. {
  1236. perror(dirName);
  1237. return ERROR;
  1238. }
  1239.     errno = OK;
  1240.     do
  1241. {
  1242.      pDirEnt = readdir (pDir);
  1243. if (pDirEnt != NULL)
  1244.     {
  1245.     if (pattern != NULL &&
  1246. dirListPattern( pattern, pDirEnt->d_name) == FALSE)
  1247. continue ;
  1248.     if (strcmp(pDirEnt->d_name,"." )  == 0 &&
  1249. strcmp(pDirEnt->d_name,".." ) == 0)
  1250. continue ;
  1251.     /* Construct path/filename for stat */
  1252.     usrPathCat( dirName, pDirEnt->d_name, fileName );
  1253.     usrPathCat( dest, pDirEnt->d_name, destName );
  1254.     printf("moving file %s -> %sn", fileName, destName );
  1255.     status |= mvFile( fileName, destName );
  1256.     }
  1257. } while (pDirEnt != NULL); /* until end of dir */
  1258.     status |= closedir (pDir);
  1259.     return status ;
  1260.     }  /* mv() */
  1261. /*******************************************************************************
  1262. *
  1263. * mvFile - move a file from one place to another.  
  1264. *
  1265. * This routine does some of the work of the mv() function.
  1266. *
  1267. * RETURNS: OK, or ERROR if the file could not be opened or moved.
  1268. */
  1269. LOCAL int mvFile
  1270.     (
  1271.     const char *oldname,        /* name of file to move */
  1272.     const char *newname         /* name with which to move file */
  1273.     )
  1274.     {
  1275.     int fd;
  1276.     int status;
  1277.     if ((oldname == NULL) || (newname == NULL) || (newname[0] == EOS))
  1278.         {
  1279.         errnoSet (ENOENT);
  1280.         return (ERROR);
  1281.         }
  1282.     /* try to open file */
  1283.     if (ERROR == (fd = open ((char *) oldname, O_RDONLY, 0)))
  1284.         return (ERROR);
  1285.     /* move it */
  1286.     status = ioctl (fd, FIOMOVE, (int) newname);
  1287.     close (fd);
  1288.     return (status);
  1289.     }
  1290. /******************************************************************************
  1291. *
  1292. * xcopy - copy a hierarchy of files with wildcards
  1293. *
  1294. * <source> is a string containing a name of a directory, or a wildcard
  1295. * or both which will cause this function to make a recursive copy of all
  1296. * files residing in that directory and matching the wildcard pattern into
  1297. * the <dest> directory, preserving the file names and subdirectories.
  1298. *
  1299. * CAVEAT
  1300. * This function may call itself in accordance with the depth of the
  1301. * source directory, and occupies approximately 800 bytes per stack
  1302. * frame, meaning that to accommodate the maximum depth of subdirectories
  1303. * which is 20, at least 16 Kbytes of stack space should be available to
  1304. * avoid stack overflow.
  1305. *
  1306. * RETURNS: OK or ERROR if any operation has failed.
  1307. *
  1308. * SEE ALSO: tarLib, checkStack(), cp()
  1309. */
  1310. STATUS xcopy
  1311.     (
  1312.     const char *source, /* source directory or wildcard name */
  1313.     const char *dest /* destination directory */
  1314.     )
  1315.     {
  1316.     FAST DIR *pDir; /* ptr to directory descriptor */
  1317.     FAST struct dirent *pDirEnt; /* ptr to dirent */
  1318.     STATUS status = OK ;
  1319.     char * pattern = NULL ;
  1320.     char * dirName = NULL ;
  1321.     char  dir[MAX_FILENAME_LENGTH] ;
  1322.     char  fileName[MAX_FILENAME_LENGTH] ;
  1323.     char  destName[MAX_FILENAME_LENGTH] ;
  1324.     if (!nameIsDir( dest ))
  1325. {
  1326. printErr("xcopy: error: destination "%s" is not a directoryn",
  1327. dest );
  1328. errno = ENOTDIR ;
  1329. return ERROR ;
  1330. }
  1331.     strncpy( dir, source, MAX_FILENAME_LENGTH-1 );
  1332.     pattern = rindex(dir, '/');
  1333.     if ( pattern != NULL && pattern != dir && dirNameWildcard(pattern))
  1334. {
  1335. /* dir and pattern e.g. dir1/a*.c */
  1336. *pattern++ = EOS ;
  1337. dirName = dir ;
  1338. }
  1339.     else if (dirNameWildcard( dir))
  1340. {
  1341. /* just pattern e.g. *.c or abc.? */
  1342. pattern = dir;
  1343. dirName = "." ;
  1344. }
  1345.     else
  1346. {
  1347. pattern = NULL ;
  1348. dirName = dir ;
  1349. }
  1350.     if (!nameIsDir (dirName))
  1351. {
  1352. printf("copying file %s -> %sn", source, dest );
  1353. return copy(source, dest ) ;
  1354. }
  1355.     pDir = opendir (dirName) ;
  1356.     if (pDir == NULL)
  1357. {
  1358. perror(dirName);
  1359. return ERROR;
  1360. }
  1361.     errno = OK;
  1362.     do
  1363. {
  1364.      pDirEnt = readdir (pDir);
  1365. if (pDirEnt != NULL)
  1366.     {
  1367.     if (pattern != NULL &&
  1368. dirListPattern( pattern, pDirEnt->d_name) == FALSE)
  1369. continue ;
  1370.     /* Construct path/filename for stat */
  1371.     usrPathCat( dirName, pDirEnt->d_name, fileName );
  1372.     usrPathCat( dest, pDirEnt->d_name, destName );
  1373.     if (!nameIsDir( fileName ))
  1374. {
  1375. printf("copying file %s -> %sn", fileName, destName );
  1376. status |= copy( fileName, destName );
  1377. }
  1378.     else if (strcmp(pDirEnt->d_name,"." ) &&
  1379. strcmp(pDirEnt->d_name,".." ))
  1380. {
  1381. printf("copying dir %s -> %sn", fileName, destName );
  1382. mkdir(destName);
  1383. status |= xcopy( fileName, destName );
  1384. }
  1385.     }
  1386. } while (pDirEnt != NULL); /* until end of dir */
  1387.     status |= closedir (pDir);
  1388.     return status ;
  1389.     }
  1390. /******************************************************************************
  1391. *
  1392. * xdelete - delete a hierarchy of files with wildcards
  1393. *
  1394. * <source> is a string containing a name of a directory, or a wildcard
  1395. * or both which will cause this function to recursively remove all
  1396. * files and subdirectories residing in that directory
  1397. * and matching the wildcard pattern.
  1398. * When a directory is encountered, all its contents are removed,
  1399. * and then the directory itself is deleted.
  1400. *
  1401. * CAVEAT
  1402. * This function may call itself in accordance with the depth of the
  1403. * source directory, and occupies approximately 520 bytes per stack
  1404. * frame, meaning that to accommodate the maximum depth of subdirectories
  1405. * which is 20, at least 10 Kbytes of stack space should be available to
  1406. * avoid stack overflow.
  1407. *
  1408. * RETURNS: OK or ERROR if any operation has failed.
  1409. *
  1410. * SEE ALSO: checkStack(), cp(), copy(), xcopy(), tarLib
  1411. */
  1412. STATUS xdelete
  1413.     (
  1414.     const char *source /* source directory or wildcard name */
  1415.     )
  1416.     {
  1417.     FAST DIR *pDir; /* ptr to directory descriptor */
  1418.     FAST struct dirent *pDirEnt; /* ptr to dirent */
  1419.     STATUS status = OK ;
  1420.     char * pattern = NULL ;
  1421.     char * dirName = NULL ;
  1422.     char  dir[MAX_FILENAME_LENGTH] ;
  1423.     char  fileName[MAX_FILENAME_LENGTH] ;
  1424.     strncpy( dir, source, MAX_FILENAME_LENGTH-1 );
  1425.     pattern = rindex(dir, '/');
  1426.     if ( pattern != NULL && pattern != dir && dirNameWildcard(pattern))
  1427. {
  1428. /* dir and pattern e.g. dir1/a*.c */
  1429. *pattern++ = EOS ;
  1430. dirName = dir ;
  1431. }
  1432.     else if (dirNameWildcard( dir))
  1433. {
  1434. /* just pattern e.g. *.c or abc.? */
  1435. pattern = dir;
  1436. dirName = "." ;
  1437. }
  1438.     else
  1439. {
  1440. pattern = NULL ;
  1441. dirName = dir ;
  1442. }
  1443.     if (! nameIsDir( dirName ))
  1444. {
  1445. printf("deleting file %sn", source);
  1446. return unlink((char *)source);
  1447. }
  1448.     pDir = opendir (dirName) ;
  1449.     if (pDir == NULL)
  1450. {
  1451. perror(dirName);
  1452. return ERROR;
  1453. }
  1454.     errno = OK;
  1455.     do
  1456. {
  1457.      pDirEnt = readdir (pDir);
  1458. if (pDirEnt != NULL)
  1459.     {
  1460.     if (pattern != NULL &&
  1461. dirListPattern( pattern, pDirEnt->d_name) == FALSE)
  1462. continue ;
  1463.     /* Construct path/filename for stat */
  1464.     usrPathCat( dirName, pDirEnt->d_name, fileName );
  1465.     if (!nameIsDir( fileName ))
  1466. {
  1467. printf("deleting file %sn", fileName);
  1468. status |= unlink( fileName);
  1469. }
  1470.     else if (strcmp(pDirEnt->d_name,"." ) &&
  1471. strcmp(pDirEnt->d_name,".." ))
  1472. {
  1473. printf("deleting directory %s n", fileName);
  1474. status |= xdelete( fileName);
  1475. status |= rmdir(fileName);
  1476. }
  1477.     }
  1478. } while (pDirEnt != NULL); /* until end of dir */
  1479.     status |= closedir (pDir);
  1480.     return status ;
  1481.     }
  1482. /******************************************************************************
  1483. *
  1484. * attrib - modify MS-DOS file attributes on a file or directory
  1485. *
  1486. * This function provides means for the user to modify the attributes
  1487. * of a single file or directory. There are four attribute flags which
  1488. * may be modified: "Archive", "System", "Hidden" and "Read-only".
  1489. * Among these flags, only "Read-only" has a meaning in VxWorks,
  1490. * namely, read-only files can not be modified deleted or renamed.
  1491. *
  1492. * The <attr> argument string may contain must start with either "+" or
  1493. * "-", meaning the attribute flags which will follow should be either set
  1494. * or cleared. After "+" or "-" any of these four letter will signify their
  1495. * respective attribute flags - "A", "S", "H" and "R".
  1496. *
  1497. * For example, to write-protect a particular file and flag that it is a
  1498. * system file:
  1499. *
  1500. * .CS
  1501. * -> attrib( "bootrom.sys", "+RS")
  1502. * .CE
  1503. *
  1504. * RETURNS: OK, or ERROR if the file can not be opened.
  1505. */
  1506. STATUS attrib
  1507.     (
  1508.     const char * fileName, /* file or dir name on which to change flags */
  1509.     const char * attr /* flag settings to change */
  1510.     )
  1511.     {
  1512.     BOOL set = TRUE ;
  1513.     STATUS status ;
  1514.     u_char bit = 0 ;
  1515.     struct stat fileStat;
  1516.     int fd ;
  1517.     if (attr == NULL)
  1518. {
  1519. errno = EINVAL ;
  1520. return ERROR;
  1521. }
  1522.     fd = open (fileName, O_RDONLY, 0);
  1523.     if (fd == ERROR)
  1524. {
  1525. perror(fileName);
  1526. return ERROR ;
  1527. }
  1528.     if (fstat (fd, &fileStat) == ERROR)          /* get file status    */
  1529. {
  1530. printErr("Can't get stat on %sn", fileName );
  1531. return ERROR;
  1532. }
  1533.     for ( ; *attr != EOS ; attr ++)
  1534. {
  1535. switch( *attr)
  1536.     {
  1537.     case '+' :
  1538. set = TRUE ;
  1539. break ;
  1540.     case '-' :
  1541. set = FALSE ;
  1542. break ;
  1543.     case 'A' : case 'a' :
  1544. bit = DOS_ATTR_ARCHIVE ;
  1545. break ;
  1546.     case 'S' : case 's' :
  1547. bit = DOS_ATTR_SYSTEM ;
  1548. break ;
  1549.     case 'H' : case 'h' :
  1550. bit = DOS_ATTR_HIDDEN ;
  1551. break ;
  1552.     case 'R' : case 'r' :
  1553. bit = DOS_ATTR_RDONLY ;
  1554. break ;
  1555.     default:
  1556. printErr("Illegal attribute flag "%c", ignoredn", *attr );
  1557.     } /* end of switch */
  1558. if (set)
  1559.     fileStat.st_attrib |= bit ;
  1560. else
  1561.     fileStat.st_attrib &= ~bit ;
  1562. }
  1563.     status = ioctl (fd, FIOATTRIBSET, fileStat.st_attrib);
  1564.     close(fd);
  1565.     return status ;
  1566.     }
  1567. /******************************************************************************
  1568. *
  1569. * xattrib - modify MS-DOS file attributes of many files
  1570. *
  1571. * This function is essentially the same as attrib(), but it accepts
  1572. * wildcards in <fileName>, and traverses subdirectories in order
  1573. * to modify attributes of entire file hierarchies.
  1574. *
  1575. * The <attr> argument string may contain must start with either "+" or
  1576. * "-", meaning the attribute flags which will follow should be either set
  1577. * or cleared. After "+" or "-" any of these four letter will signify their
  1578. * respective attribute flags - "A", "S", "H" and "R".
  1579. *
  1580. * EXAMPLE
  1581. * .CS
  1582. * -> xattrib( "/sd0/sysfiles", "+RS") /@ write protect "sysfiles" @/
  1583. * -> xattrib( "/sd0/logfiles", "-R") /@ unprotect logfiles before deletion @/
  1584. * -> xdelete( "/sd0/logfiles")
  1585. * .CE
  1586. *
  1587. * CAVEAT
  1588. * This function may call itself in accordance with the depth of the
  1589. * source directory, and occupies approximately 520 bytes per stack
  1590. * frame, meaning that to accommodate the maximum depth of subdirectories
  1591. * which is 20, at least 10 Kbytes of stack space should be available to
  1592. * avoid stack overflow.
  1593. *
  1594. * RETURNS: OK, or ERROR if the file can not be opened.
  1595. */
  1596. STATUS xattrib
  1597.     (
  1598.     const char *source, /* file or directory name on which to change flags */
  1599.     const char *attr /* flag settings to change */
  1600.     )
  1601.     {
  1602.     FAST DIR *pDir; /* ptr to directory descriptor */
  1603.     FAST struct dirent *pDirEnt; /* ptr to dirent */
  1604.     STATUS status = OK ;
  1605.     char * pattern = NULL ;
  1606.     char * dirName = NULL ;
  1607.     char  dir[MAX_FILENAME_LENGTH] ;
  1608.     char  fileName[MAX_FILENAME_LENGTH] ;
  1609.     strncpy (dir, source, MAX_FILENAME_LENGTH-1 );
  1610.     pattern = rindex(dir, '/');
  1611.     if ( pattern != NULL && pattern != dir && dirNameWildcard(pattern))
  1612. {
  1613. /* dir and pattern e.g. dir1/a*.c */
  1614. *pattern++ = EOS ;
  1615. dirName = dir ;
  1616. }
  1617.     else if (dirNameWildcard( dir))
  1618. {
  1619. /* just pattern e.g. *.c or abc.? */
  1620. pattern = dir;
  1621. dirName = "." ;
  1622. }
  1623.     else
  1624. {
  1625. pattern = NULL ;
  1626. dirName = dir ;
  1627. }
  1628.     if (!nameIsDir (dirName))
  1629. {
  1630. printf("changing attributes on %sn", source);
  1631. return attrib(source, attr);
  1632. }
  1633.     pDir = opendir (dirName);
  1634.     if (pDir == NULL)
  1635. {
  1636. perror(dirName);
  1637. return ERROR;
  1638. }
  1639.     errno = OK;
  1640.     do
  1641. {
  1642.      pDirEnt = readdir (pDir);
  1643. if (pDirEnt != NULL)
  1644.     {
  1645.     if (pattern != NULL &&
  1646. dirListPattern( pattern, pDirEnt->d_name) == FALSE)
  1647. continue ;
  1648.     /* Construct path/filename for stat */
  1649.     usrPathCat( dirName, pDirEnt->d_name, fileName );
  1650.     if (!nameIsDir( fileName ))
  1651. {
  1652. printf("changing attributes on %sn", fileName);
  1653. status |= attrib( fileName, attr);
  1654. }
  1655.     else if (strcmp(pDirEnt->d_name,"." ) &&
  1656. strcmp(pDirEnt->d_name,".." ))
  1657. {
  1658. printf("traversing directory %s to change attributes n",
  1659. fileName);
  1660. status |= xattrib( fileName, attr);
  1661. status |= attrib( fileName, attr);
  1662. }
  1663.     }
  1664. } while (pDirEnt != NULL); /* until end of dir */
  1665.     status |= closedir (pDir);
  1666.     return status ;
  1667.     }
  1668. /*******************************************************************************
  1669. *
  1670. * diskFormat - format a disk
  1671. *
  1672. * This command formats a disk and creates a file system on it.  The
  1673. * device must already have been created by the device driver and
  1674. * initialized for use with a particular file system, via dosFsDevInit().
  1675. *
  1676. * This command calls ioctl() to perform the FIODISKFORMAT function.
  1677. *
  1678. * EXAMPLE
  1679. * .CS
  1680. *     -> diskFormat "/fd0/"
  1681. * .CE
  1682. *
  1683. * RETURNS:
  1684. * OK, or ERROR if the device cannot be opened or formatted.
  1685. *
  1686. * SEE ALSO: dosFsLib
  1687. * .pG "Target Shell"
  1688. */
  1689. STATUS diskFormat
  1690.     (
  1691.     const char *pDevName  /* name of the device to initialize */
  1692.     )
  1693.     {
  1694.     FAST int fd;
  1695.     FAST const char *name;
  1696.     /* If no directory name specified, use current working directory (".") */
  1697.     name = (pDevName == NULL) ? "." : pDevName;
  1698.     /* Open the device, format it, and initialize it. */
  1699.     if ((fd = open (name, O_WRONLY, 0)) == ERROR)
  1700. {
  1701. printErr ("Couldn't open "%s".n", name);
  1702. return (ERROR);
  1703. }
  1704.     printf (""%s" formatting... ", name);
  1705.     if (ioctl (fd, FIODISKFORMAT, 0) != OK)
  1706. {
  1707. printErr ("Couldn't format "%s".n", name);
  1708. close (fd);
  1709. return (ERROR);
  1710. }
  1711.     printf (""%s" formatted... ", name);
  1712.     if (ioctl (fd, FIODISKINIT, 0) < OK)
  1713. {
  1714. printErr ("Couldn't initialize file system on "%s".n", name);
  1715. close (fd);
  1716. return (ERROR);
  1717. }
  1718.     close (fd);
  1719.     printf (""%s" initialized.n", name);
  1720.     return (OK);
  1721.     }
  1722. /*******************************************************************************
  1723. *
  1724. * diskInit - initialize a file system on a block device
  1725. *
  1726. * This function is now obsolete, use of dosFsVolFormat() is recommended.
  1727. *
  1728. * This command creates a new, blank file system on a block device.  The
  1729. * device must already have been created by the device driver and
  1730. * initialized for use with a particular file system, via dosFsDevCreate().
  1731. *
  1732. * EXAMPLE
  1733. * .CS
  1734. *     -> diskInit "/fd0/"
  1735. * .CE
  1736. *
  1737. * Note that if the disk is unformatted, it can not be mounted,
  1738. * thus open() will return error, in which case use the dosFsVolFormat
  1739. * routine manually.
  1740. *
  1741. * This routine performs the FIODISKINIT ioctl operation.
  1742. *
  1743. * RETURNS:
  1744. * OK, or
  1745. * ERROR if the device cannot be opened or initialized.
  1746. *
  1747. * SEE ALSO: dosFsLib
  1748. * .pG "Target Shell"
  1749. */
  1750. STATUS diskInit
  1751.     (
  1752.     const char *pDevName /* name of the device to initialize */
  1753.     )
  1754.     {
  1755.     FAST int fd;
  1756.     char name[MAX_FILENAME_LENGTH+1];
  1757.     /* If no directory name specified, use current working directory (".") */
  1758.     if (pDevName == NULL)
  1759. ioDefPathGet (name);
  1760.     else
  1761. strncpy (name, pDevName, MAX_FILENAME_LENGTH);
  1762.     /* Open the device, format it, and initialize it. */
  1763.     fd = open (name, O_WRONLY, 0) ;
  1764.     if (ERROR == fd)
  1765. {
  1766. printErr ("Couldn't open file system on "%s".n", name);
  1767. printErr ("Perhaps a dosFsVolFormat on the file system is needed.n");
  1768. return (ERROR);
  1769. }
  1770.     if (ioctl (fd, FIODISKINIT, 0) < OK)
  1771. {
  1772. printErr ("Couldn't initialize file system on "%s".n", name);
  1773. close (fd);
  1774. return (ERROR);
  1775. }
  1776.     printf (""%s" initialized.n", name);
  1777.     close (fd);
  1778.     return (OK);
  1779.     }
  1780. /*******************************************************************************
  1781. *
  1782. * ioHelp - print a synopsis of I/O utility functions
  1783. *
  1784. * This function prints out synopsis for the I/O and File System
  1785. * utility functions.
  1786. *
  1787. * RETURNS: N/A
  1788. *
  1789. * SEE ALSO:
  1790. * .pG "Target Shell"
  1791. */
  1792. void ioHelp (void)
  1793.     {
  1794.     static char *help_msg [] = {
  1795.     "cd        "path"             Set current working path",
  1796.     "pwd                            Print working path",
  1797.     "ls        ["wpat"[,long]]    List contents of directory",
  1798.     "ll        ["wpat"]           List contents of directory - long format",
  1799.     "lsr       ["wpat"[,long]]    Recursive list of directory contents",
  1800.     "llr       ["wpat"]           Recursive detailed list of directory",
  1801.     "rename    "old","new"      Change name of file",
  1802.     "copy      ["in"][,"out"]   Copy in file to out file (0 = std in/out)",
  1803.     "cp        "wpat","dst"      Copy many files to another dir",
  1804.     "xcopy     "wpat","dst"      Recursively copy files",
  1805.     "mv        "wpat","dst"      Move files into another directory",
  1806.     "xdelete   "wpat"             Delete a file, wildcard list or tree",
  1807.     "attrib    "path","attr"    Modify file attributes",
  1808.     "xattrib   "wpat","attr"    Recursively modify file attributes",
  1809.     "chkdsk    "device", L, V     Consistency check of file system",
  1810.     "diskInit  "device"           Initialize file system on disk",
  1811.     "diskFormat "device"          Low level and file system disk format",
  1812.     "",
  1813.     ""attr" contains one or more of: " + - A H S R" characters",
  1814.     ""wpat" may be name of a file, directory or wildcard pattern",
  1815.     " in which case "dst" must be a directory name",
  1816.     "chkdsk() params: L=0, check only, L=2, check and fix, V=0x200 verbose",
  1817.     NULL
  1818.     };
  1819.     FAST int ix;
  1820.     char ch;
  1821.     printf ("n");
  1822.     for (ix = 0; help_msg [ix] != NULL; ix++)
  1823. {
  1824. if ((ix+1) % 20 == 0)
  1825.     {
  1826.     printf ("nType <CR> to continue, Q<CR> to stop: ");
  1827.     fioRdString (STD_IN, &ch, 1);
  1828.     if (ch == 'q' || ch == 'Q')
  1829. break;
  1830.     else
  1831. printf ("n");
  1832.     }
  1833. printf ("%sn", help_msg [ix]);
  1834. }
  1835.     printf ("n");
  1836.     }
  1837. /* End of file */