home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / microcode / os2fs.c < prev    next >
C/C++ Source or Header  |  2001-07-18  |  15KB  |  562 lines

  1. /* -*-C-*-
  2.  
  3. $Id: os2fs.c,v 1.14 2001/07/19 01:45:02 cph Exp $
  4.  
  5. Copyright (c) 1994-2001 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  20. USA.
  21. */
  22.  
  23. #include "os2.h"
  24. #include "osfs.h"
  25.  
  26. #ifdef __GCC2__
  27. #  define stricmp strcasecmp
  28. #  define strnicmp strncasecmp
  29. #endif
  30.  
  31. #ifndef FILE_TOUCH_OPEN_TRIES
  32. #  define FILE_TOUCH_OPEN_TRIES 5
  33. #endif
  34.  
  35. static const char * make_pathname (const char *, const char *);
  36. static const char * filename_extension (const char *);
  37. extern char * OS2_drive_type (char);
  38. extern char * OS2_remove_trailing_backslash (const char *);
  39.  
  40. FILESTATUS3 *
  41. OS2_read_file_status (const char * filename)
  42. {
  43.   char name [CCHMAXPATH];
  44.   static FILESTATUS3 info;
  45.   unsigned int flen = (strlen (filename));
  46.   FASTCOPY (filename, name, flen);
  47.   /* Strip trailing backslash.  */
  48.   if ((flen > 0) && ((name [flen - 1]) == '\\'))
  49.     flen -= 1;
  50.   (name [flen]) = '\0';
  51.   /* Canonicalize various forms of reference to root directory.  */
  52.   if ((flen == 5)
  53.       && (isalpha (name [0]))
  54.       && ((name [1]) == ':')
  55.       && ((name [2]) == '\\')
  56.       && ((name [3]) == '.')
  57.       && ((name [4]) == '.'))
  58.     (name [4]) = '\0';
  59.   else if ((flen == 2)
  60.        && (isalpha (name [0]))
  61.        && ((name [1]) == ':'))
  62.     {
  63.       (name [2]) = '\\';
  64.       (name [3]) = '.';
  65.       (name [4]) = '\0';
  66.     }
  67.   else if (flen == 0)
  68.     {
  69.       (name [0]) = '\\';
  70.       (name [1]) = '.';
  71.       (name [2]) = '\0';
  72.     }
  73.   {
  74.     APIRET rc
  75.       = (dos_query_path_info (name, FIL_STANDARD, (&info), (sizeof (info))));
  76.     /* So many different things can go wrong here that it is a bad
  77.        idea to attempt to enumerate them.  Several times I have
  78.        thought I had all the possible conditions and later discovered
  79.        that I was wrong.  */
  80.     if (rc != NO_ERROR)
  81.       return (0);
  82.   }
  83.   return (&info);
  84. }
  85.  
  86. void
  87. OS2_write_file_status (const char * filename, FILESTATUS3 * info)
  88. {
  89.   STD_API_CALL
  90.     (dos_set_path_info,
  91.      ((OS2_remove_trailing_backslash (filename)),
  92.       FIL_STANDARD, info, (sizeof (FILESTATUS3)), 0));
  93. }
  94.  
  95. enum file_existence
  96. OS_file_existence_test (const char * filename)
  97. {
  98.   return
  99.     ((OS2_read_file_status (filename))
  100.      ? file_does_exist
  101.      : file_doesnt_exist);
  102. }
  103.  
  104. enum file_existence
  105. OS_file_existence_test_direct (const char * filename)
  106. {
  107.   return (OS_file_existence_test (filename));
  108. }
  109.  
  110. enum file_type
  111. OS_file_type_direct (const char * filename)
  112. {
  113.   FILESTATUS3 * info = (OS2_read_file_status (filename));
  114.   return
  115.     ((info == 0)
  116.      ? file_type_nonexistent
  117.      : (((info -> attrFile) & FILE_DIRECTORY) == 0)
  118.      ? file_type_regular
  119.      : file_type_directory);
  120. }
  121.  
  122. enum file_type
  123. OS_file_type_indirect (const char * filename)
  124. {
  125.   return (OS_file_type_direct (filename));
  126. }
  127.  
  128. #define R_OK 4
  129. #define W_OK 2
  130. #define X_OK 1
  131.  
  132. int
  133. OS_file_access (const char * filename, unsigned int mode)
  134. {
  135.   FILESTATUS3 * info = (OS2_read_file_status (filename));
  136.   if (!info)
  137.     return (0);
  138.   if (((mode & W_OK) != 0) && (((info -> attrFile) & FILE_READONLY) != 0))
  139.     return (0);
  140.   if (((mode & X_OK) != 0) && (((info -> attrFile) & FILE_DIRECTORY) == 0))
  141.     {
  142.       const char * extension = (filename_extension (filename));
  143.       if (! (((stricmp (extension, ".exe")) == 0)
  144.          || ((stricmp (extension, ".com")) == 0)
  145.          || ((stricmp (extension, ".cmd")) == 0)
  146.          || ((stricmp (extension, ".bat")) == 0)))
  147.     return (0);
  148.     }
  149.   return (1);
  150. }
  151.  
  152. int
  153. OS_file_directory_p (const char * filename)
  154. {
  155.   if (((strlen (filename)) == 3)
  156.       && (isalpha (filename [0]))
  157.       && ((filename [1]) == ':')
  158.       && ((filename [2]) == '\\'))
  159.     return ((OS2_drive_type (filename [0])) != 0);
  160.   else
  161.     {
  162.       FILESTATUS3 * info = (OS2_read_file_status (filename));
  163.       return ((info == 0) ? 0 : (((info -> attrFile) & FILE_DIRECTORY) != 0));
  164.     }
  165. }
  166.  
  167. char *
  168. OS2_drive_type (char drive_letter)
  169. {
  170.   char name [3];
  171.   static char cbuf [(sizeof (FSQBUFFER2)) + (3 * CCHMAXPATH)];
  172.   FSQBUFFER2 * buffer = ((FSQBUFFER2 *) cbuf);
  173.   ULONG size = (sizeof (cbuf));
  174.   (name [0]) = drive_letter;
  175.   (name [1]) = ':';
  176.   (name [2]) = '\0';
  177.   STD_API_CALL
  178.     (dos_query_fs_attach, (name, 0, FSAIL_QUERYNAME, buffer, (& size)));
  179.   if (((buffer -> iType) == FSAT_LOCALDRV)
  180.       || ((buffer -> iType) == FSAT_REMOTEDRV))
  181.     {
  182.       char * fsdname = ((buffer -> szName) + (buffer -> cbName) + 1);
  183.       if ((buffer -> iType) == FSAT_REMOTEDRV)
  184.     /* This bit of magic causes the "attach data" to be appended
  185.        to the driver name, with a colon separator.  In the case of
  186.        an NFS drive, the "attach data" is the mount information,
  187.        e.g. "martigny:/zu".  This information is valuable, because
  188.        it can be used to make crude inferences about the file
  189.        system on the remote machine.  */
  190.     (fsdname [buffer -> cbFSDName]) = ':';
  191.       return (fsdname);
  192.     }
  193.   else
  194.     return (0);
  195. }
  196.  
  197. const char *
  198. OS_file_soft_link_p (const char * filename)
  199. {
  200.   return (0);
  201. }
  202.  
  203. void
  204. OS_file_remove (const char * filename)
  205. {
  206.   {
  207.     FILESTATUS3 * info = (OS2_read_file_status (filename));
  208.     if (info == 0)
  209.       return;
  210.     if (((info -> attrFile) & FILE_READONLY) != 0)
  211.       {
  212.     (info -> attrFile) &=~ FILE_READONLY;
  213.     STD_API_CALL
  214.       (dos_set_path_info,
  215.        (((char *) filename), FIL_STANDARD, info, (sizeof (*info)), 0));
  216.       }
  217.   }
  218.   STD_API_CALL (dos_delete, ((char *) filename));
  219. }
  220.  
  221. void
  222. OS_file_remove_link (const char * filename)
  223. {
  224.   OS_file_remove (filename);
  225. }
  226.  
  227. void
  228. OS_file_rename (const char * from_name, const char * to_name)
  229. {
  230.   STD_API_CALL (dos_move, (((char *) from_name), ((char *) to_name)));
  231. }
  232.  
  233. void
  234. OS_file_link_hard (const char * from_name, const char * to_name)
  235. {
  236.   OS2_error_unimplemented_primitive ();
  237. }
  238.  
  239. void
  240. OS_file_link_soft (const char * from_name, const char * to_name)
  241. {
  242.   OS2_error_unimplemented_primitive ();
  243. }
  244.  
  245. void
  246. OS_file_copy (const char * from, const char * to)
  247. {
  248.   FILESTATUS3 * info = (OS2_read_file_status (to));
  249.   if ((info != 0) && (((info -> attrFile) & FILE_READONLY) != 0))
  250.     {
  251.       (info -> attrFile) &=~ FILE_READONLY;
  252.       OS2_write_file_status (to, info);
  253.     }
  254.   STD_API_CALL (dos_copy, (((PSZ) from), ((PSZ) to), DCPY_EXISTING));
  255. }
  256.  
  257. void
  258. OS_directory_make (const char * directory_name)
  259. {
  260.   STD_API_CALL
  261.     (dos_create_dir, ((OS2_remove_trailing_backslash (directory_name)), 0));
  262. }
  263.  
  264. void
  265. OS_directory_delete (const char * directory_name)
  266. {
  267.   STD_API_CALL
  268.     (dos_delete_dir, (OS2_remove_trailing_backslash (directory_name)));
  269. }
  270.  
  271. static void protect_handle (LHANDLE);
  272.  
  273. int
  274. OS_file_touch (const char * filename)
  275. {
  276.   HFILE handle;
  277.   ULONG action;
  278.   APIRET rc;
  279.   unsigned int count = 0;
  280.  
  281.   transaction_begin ();
  282.   while (1)
  283.     {
  284.       APIRET rc
  285.     = (dos_open (((char *) filename),
  286.              (&handle),
  287.              (&action),
  288.              0,
  289.              FILE_NORMAL,
  290.              (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW),
  291.              (OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE),
  292.              0));
  293.       if (rc == NO_ERROR)
  294.     break;
  295.       if ((rc != NO_ERROR)
  296.       && (rc != ERROR_FILE_NOT_FOUND)
  297.       && (rc != ERROR_PATH_NOT_FOUND)
  298.       && ((++ count) >= FILE_TOUCH_OPEN_TRIES))
  299.     OS2_error_system_call (rc, syscall_dos_open);
  300.     }
  301.   protect_handle (handle);
  302.   if (action == FILE_CREATED)
  303.     {
  304.       transaction_commit ();
  305.       return (1);
  306.     }
  307.   /* Existing file -- we'll write something to it to make sure that it
  308.      has its times updated properly upon close.  This was needed for
  309.      unix implementation, but it is not known whether it is needed in
  310.      OS/2.  In any case, it does no harm to do this.  */
  311.   {
  312.     FILESTATUS3 info;
  313.     char buffer [1];
  314.     ULONG n;
  315.     STD_API_CALL (dos_query_file_info,
  316.           (handle, FIL_STANDARD, (& info), (sizeof (info))));
  317.     if ((info . cbFile) == 0)
  318.       {
  319.     /* Zero-length file: write a byte, then reset the length.  */
  320.     (buffer[0]) = '\0';
  321.     STD_API_CALL (dos_write, (handle, buffer, 1, (& n)));
  322.     STD_API_CALL (dos_set_file_size, (handle, 0));
  323.       }
  324.     else
  325.       {
  326.     /* Read the first byte, then write it back in place.  */
  327.     STD_API_CALL (dos_read, (handle, buffer, 1, (&n)));
  328.     STD_API_CALL (dos_set_file_ptr, (handle, 0, FILE_BEGIN, (& n)));
  329.     STD_API_CALL (dos_write, (handle, buffer, 1, (& n)));
  330.       }
  331.   }
  332.   transaction_commit ();
  333.   return (0);
  334. }
  335.  
  336. static void
  337. protect_handle_1 (void * hp)
  338. {
  339.   (void) dos_close (* ((LHANDLE *) hp));
  340. }
  341.  
  342. static void
  343. protect_handle (LHANDLE h)
  344. {
  345.   LHANDLE * hp = (dstack_alloc (sizeof (LHANDLE)));
  346.   (*hp) = h;
  347.   transaction_record_action (tat_always, protect_handle_1, hp);
  348. }
  349.  
  350. typedef struct
  351. {
  352.   char allocatedp;
  353.   HDIR handle;
  354.   FILEFINDBUF3 info;
  355.   ULONG count;
  356. } dir_search_state;
  357.  
  358. static dir_search_state * dir_search_states;
  359. static unsigned int n_dir_search_states;
  360.  
  361. void
  362. OS2_initialize_directory_reader (void)
  363. {
  364.   dir_search_states = 0;
  365.   n_dir_search_states = 0;
  366. }
  367.  
  368. static unsigned int
  369. allocate_dir_search_state (void)
  370. {
  371.   if (n_dir_search_states == 0)
  372.     {
  373.       dir_search_state * states =
  374.     ((dir_search_state *) (OS_malloc ((sizeof (dir_search_state)) * 4)));
  375.       dir_search_states = states;
  376.       n_dir_search_states = 4;
  377.       {
  378.     dir_search_state * scan = dir_search_states;
  379.     dir_search_state * end = (scan + n_dir_search_states);
  380.     ((scan++) -> allocatedp) = 1;
  381.     while (scan < end)
  382.       ((scan++) -> allocatedp) = 0;
  383.       }
  384.       return (0);
  385.     }
  386.   {
  387.     dir_search_state * scan = dir_search_states;
  388.     dir_search_state * end = (scan + n_dir_search_states);
  389.     while (scan < end)
  390.       if (! ((scan++) -> allocatedp))
  391.     {
  392.       ((--scan) -> allocatedp) = 1;
  393.       return (scan - dir_search_states);
  394.     }
  395.   }
  396.   {
  397.     unsigned int result = n_dir_search_states;
  398.     unsigned int n_states = (2 * n_dir_search_states);
  399.     dir_search_state * states =
  400.       ((dir_search_state *)
  401.        (OS_realloc (((void *) dir_search_states),
  402.             ((sizeof (dir_search_state)) * n_states))));
  403.     {
  404.       dir_search_state * scan = (states + result);
  405.       dir_search_state * end = (states + n_states);
  406.       ((scan++) -> allocatedp) = 1;
  407.       while (scan < end)
  408.     ((scan++) -> allocatedp) = 0;
  409.     }
  410.     dir_search_states = states;
  411.     n_dir_search_states = n_states;
  412.     return (result);
  413.   }
  414. }
  415.  
  416. #define REFERENCE_DIR_SEARCH_STATE(index) (& (dir_search_states[(index)]))
  417. #define DEALLOCATE_DIR_SEARCH_STATE(state) ((state) -> allocatedp) = 0
  418.  
  419. int
  420. OS_directory_valid_p (long index)
  421. {
  422.   return
  423.     ((0 <= index)
  424.      && (index < n_dir_search_states)
  425.      && ((REFERENCE_DIR_SEARCH_STATE (index)) -> allocatedp));
  426. }
  427.  
  428. static void
  429. dir_open_deallocate (void * arg)
  430. {
  431.   DEALLOCATE_DIR_SEARCH_STATE ((dir_search_state *) arg);
  432. }
  433.  
  434. unsigned int
  435. OS_directory_open (const char * search_pattern)
  436. {
  437.   static char pattern [CCHMAXPATH];
  438.   unsigned int index = (allocate_dir_search_state ());
  439.   dir_search_state * s = (REFERENCE_DIR_SEARCH_STATE (index));
  440.   transaction_begin ();
  441.   transaction_record_action (tat_abort, dir_open_deallocate, s);
  442.   strcpy (pattern, search_pattern);
  443.   {
  444.     unsigned int len = (strlen (pattern));
  445.     if ((len > 0) && ((pattern [len - 1]) == '\\'))
  446.       strcat (pattern, "*");
  447.   }
  448.   (s -> handle) = HDIR_CREATE;
  449.   (s -> count) = 1;
  450.   while (1)
  451.     {
  452.       APIRET rc
  453.     = (dos_find_first
  454.        (pattern, (& (s -> handle)), FILE_ANY, (& (s -> info)),
  455.         (sizeof (s -> info)), (& (s -> count)), FIL_STANDARD));
  456.       if (rc == NO_ERROR)
  457.     break;
  458.       if (rc == ERROR_NO_MORE_FILES)
  459.     {
  460.       (s -> handle) = HDIR_CREATE;
  461.       (s -> count) = 0;
  462.       break;
  463.     }
  464.       if (rc != ERROR_INTERRUPT)
  465.     OS2_error_system_call (rc, syscall_dos_find_first);
  466.     }
  467.   transaction_commit ();
  468.   return (index);
  469. }
  470.  
  471. static void
  472. dir_find_next (dir_search_state * s)
  473. {
  474.   (s -> count) = 1;
  475.   XTD_API_CALL
  476.     (dos_find_next,
  477.      ((s -> handle), (& (s -> info)), (sizeof (s -> info)), (& (s -> count))),
  478.      {
  479.        if (rc == ERROR_NO_MORE_FILES)
  480.      {
  481.        (s -> count) = 0;
  482.        return;
  483.      }
  484.      });
  485. }
  486.  
  487. static const char *
  488. dir_current_name (dir_search_state * s)
  489. {
  490.   static char result [CCHMAXPATH];
  491.   strcpy (result, ((s -> info) . achName));
  492.   dir_find_next (s);
  493.   return (result);
  494. }
  495.  
  496. const char *
  497. OS_directory_read (unsigned int index)
  498. {
  499.   dir_search_state * s = (REFERENCE_DIR_SEARCH_STATE (index));
  500.   return (((s -> count) == 0) ? 0 : (dir_current_name (s)));
  501. }
  502.  
  503. const char *
  504. OS_directory_read_matching (unsigned int index, const char * prefix)
  505. {
  506.   dir_search_state * s = (REFERENCE_DIR_SEARCH_STATE (index));
  507.   unsigned int n = (strlen (prefix));
  508.   while (1)
  509.     {
  510.       if ((s -> count) == 0)
  511.     return (0);
  512.       if ((strnicmp (((s -> info) . achName), prefix, n)) == 0)
  513.     return (dir_current_name (s));
  514.       dir_find_next (s);
  515.     }
  516. }
  517.  
  518. void
  519. OS_directory_close (unsigned int index)
  520. {
  521.   dir_search_state * s = (REFERENCE_DIR_SEARCH_STATE (index));
  522.   if ((s -> handle) != HDIR_CREATE)
  523.     STD_API_CALL (dos_find_close, (s -> handle));
  524.   DEALLOCATE_DIR_SEARCH_STATE (s);
  525. }
  526.  
  527. static const char *
  528. filename_extension (const char * filename)
  529. {
  530.   const char * start;
  531.   const char * period;
  532.   start = (strrchr (filename, '\\'));
  533.   start = ((start == 0) ? filename : (start + 1));
  534.   period = (strrchr (start, '.'));
  535.   return ((period == 0) ? (filename + (strlen (filename))) : period);
  536. }
  537.  
  538. static const char *
  539. make_pathname (const char * directory, const char * name)
  540. {
  541.   unsigned int dirlen = (strlen (directory));
  542.   unsigned int namlen = (strlen (name));
  543.   char * result = (OS_malloc (dirlen + namlen + 2));
  544.   strcpy (result, directory);
  545.   if ((dirlen > 0) && ((result [dirlen - 1]) != '\\'))
  546.     strcat (result, "\\");
  547.   strcat (result, name);
  548.   return (result);
  549. }
  550.  
  551. char *
  552. OS2_remove_trailing_backslash (const char * filename)
  553. {
  554.   static char result [CCHMAXPATH];
  555.   unsigned int len = (strlen (filename));
  556.   if ((len == 0) || ((filename [len - 1]) != '\\'))
  557.     return ((char *) filename);
  558.   FASTCOPY (filename, result, (len - 1));
  559.   (result [len - 1]) = '\0';
  560.   return (result);
  561. }
  562.