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 / ntfs.c < prev    next >
C/C++ Source or Header  |  2001-05-21  |  15KB  |  559 lines

  1. /* -*-C-*-
  2.  
  3. $Id: ntfs.c,v 1.28 2001/05/22 02:21:10 cph Exp $
  4.  
  5. Copyright (c) 1992-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 "nt.h"
  24. #include "ntfs.h"
  25. #include <string.h>
  26. #include "outf.h"
  27.  
  28. #ifndef FILE_TOUCH_OPEN_TRIES
  29. #  define FILE_TOUCH_OPEN_TRIES 5
  30. #endif
  31.  
  32. static enum get_file_info_result get_file_info_from_dir
  33.   (const char *, BY_HANDLE_FILE_INFORMATION *, int);
  34. static int valid_drive_p (const char *);
  35. static HANDLE create_file_for_info (const char *);
  36.  
  37. enum get_file_info_result
  38. NT_get_file_info (const char * namestring, BY_HANDLE_FILE_INFORMATION * info,
  39.           int inaccessible_ok)
  40. {
  41.   char nscopy [MAX_PATH];
  42.   HANDLE hfile;
  43.  
  44.   strcpy (nscopy, namestring);
  45.   {
  46.     unsigned int len = (strlen (nscopy));
  47.     if ((len > 3) && ((nscopy [len - 1]) == '\\'))
  48.       (nscopy [len - 1]) = '\0';
  49.   }
  50.   hfile = (create_file_for_info (nscopy));
  51.   if (hfile == INVALID_HANDLE_VALUE)
  52.     {
  53.       DWORD code = (GetLastError ());
  54.       if (STAT_NOT_FOUND_P (code))
  55.     return (gfi_not_found);
  56.       if (STAT_NOT_ACCESSIBLE_P (code))
  57.     return (get_file_info_from_dir (nscopy, info, inaccessible_ok));
  58.       NT_error_api_call (code, apicall_CreateFile);
  59.     }
  60.   if (!GetFileInformationByHandle (hfile, info))
  61.     {
  62.       DWORD code = (GetLastError ());
  63.       (void) CloseHandle (hfile);
  64.       if (STAT_NOT_FOUND_P (code))
  65.     return (gfi_not_found);
  66.       if (inaccessible_ok && (STAT_NOT_ACCESSIBLE_P (code)))
  67.     return (gfi_not_accessible);
  68.       NT_error_api_call (code, apicall_GetFileInformationByHandle);
  69.     }
  70.   STD_BOOL_API_CALL (CloseHandle, (hfile));
  71.   return (gfi_ok);
  72. }
  73.  
  74. /* Incredible kludge.  Some files (e.g. \pagefile.sys) cannot be
  75.    accessed by the usual technique, but much of the same information
  76.    is available by reading the directory.  More M$ bullshit.  */
  77. static enum get_file_info_result
  78. get_file_info_from_dir (const char * namestring,
  79.             BY_HANDLE_FILE_INFORMATION * info,
  80.             int inaccessible_ok)
  81. {
  82.   WIN32_FIND_DATA fi;
  83.   HANDLE handle = (FindFirstFile (namestring, (&fi)));
  84.   if (handle == INVALID_HANDLE_VALUE)
  85.     {
  86.       DWORD code = (GetLastError ());
  87.       if (STAT_NOT_FOUND_P (code))
  88.     {
  89.       /* On Windows 95, the root directory of a drive cannot be
  90.          interrogated using either method.  Test to see if it is a
  91.          valid drive name, and if so, dummy it.  */
  92.       if (((strlen (namestring)) == 3)
  93.           && ((namestring[1]) == ':')
  94.           && ((namestring[2]) == '\\')
  95.           && (valid_drive_p (namestring)))
  96.         {
  97.           (info -> dwFileAttributes) = FILE_ATTRIBUTE_DIRECTORY;
  98.           ((info -> ftCreationTime) . dwHighDateTime) = 0;
  99.           ((info -> ftCreationTime) . dwLowDateTime) = 0;
  100.           ((info -> ftLastAccessTime) . dwHighDateTime) = 0;
  101.           ((info -> ftLastAccessTime) . dwLowDateTime) = 0;
  102.           ((info -> ftLastWriteTime) . dwHighDateTime) = 0;
  103.           ((info -> ftLastWriteTime) . dwLowDateTime) = 0;
  104.           (info -> dwVolumeSerialNumber) = 0;
  105.           (info -> nFileSizeHigh) = 0;
  106.           (info -> nFileSizeLow) = 0;
  107.           (info -> nNumberOfLinks) = 1;
  108.           (info -> nFileIndexHigh) = 0;
  109.           (info -> nFileIndexLow) = 0;
  110.           return (gfi_ok);
  111.         }
  112.       else
  113.         return (gfi_not_found);
  114.     }
  115.       if (inaccessible_ok && (STAT_NOT_ACCESSIBLE_P (code)))
  116.     return (gfi_not_accessible);
  117.       NT_error_api_call (code, apicall_FindFirstFile);
  118.     }
  119.   FindClose (handle);
  120.   (info -> dwFileAttributes) = (fi . dwFileAttributes);
  121.   (info -> ftCreationTime) = (fi . ftCreationTime);
  122.   (info -> ftLastAccessTime) = (fi . ftLastAccessTime);
  123.   (info -> ftLastWriteTime) = (fi . ftLastWriteTime);
  124.   (info -> dwVolumeSerialNumber) = 0;
  125.   (info -> nFileSizeHigh) = (fi . nFileSizeHigh);
  126.   (info -> nFileSizeLow) = (fi . nFileSizeLow);
  127.   (info -> nNumberOfLinks) = 1;
  128.   (info -> nFileIndexHigh) = 0;
  129.   (info -> nFileIndexLow) = 0;
  130.   return (gfi_ok);
  131. }
  132.  
  133. static int
  134. valid_drive_p (const char * namestring)
  135. {
  136.   DWORD sectors_per_cluster;
  137.   DWORD bytes_per_sector;
  138.   DWORD number_of_free_clusters;
  139.   DWORD total_number_of_clusters;
  140.   return
  141.     (GetDiskFreeSpace (namestring,
  142.                (§ors_per_cluster),
  143.                (&bytes_per_sector),
  144.                (&number_of_free_clusters),
  145.                (&total_number_of_clusters)));
  146. }
  147.  
  148. static HANDLE
  149. create_file_for_info (const char * namestring)
  150. {
  151.   return
  152.     (CreateFile (namestring,
  153.          0,
  154.          (FILE_SHARE_READ | FILE_SHARE_WRITE),
  155.          0,
  156.          OPEN_EXISTING,
  157.          FILE_FLAG_BACKUP_SEMANTICS,
  158.          NULL));
  159. }
  160.  
  161. enum file_existence
  162. OS_file_existence_test (const char * name)
  163. {
  164.   BY_HANDLE_FILE_INFORMATION info;
  165.   return
  166.     (((NT_get_file_info (name, (&info), 1)) == gfi_ok)
  167.      ? file_does_exist
  168.      : file_doesnt_exist);
  169. }
  170.  
  171. enum file_existence
  172. OS_file_existence_test_direct (const char * name)
  173. {
  174.   return (OS_file_existence_test (name));
  175. }
  176.  
  177. enum file_type
  178. OS_file_type_direct (const char * name)
  179. {
  180.   BY_HANDLE_FILE_INFORMATION info;
  181.   return
  182.     (((NT_get_file_info (name, (&info), 0)) == gfi_not_found)
  183.      ? file_type_nonexistent
  184.      : (((info . dwFileAttributes) & FILE_ATTRIBUTE_DIRECTORY) == 0)
  185.      ? file_type_regular
  186.      : file_type_directory);
  187. }
  188.  
  189. enum file_type
  190. OS_file_type_indirect (const char * name)
  191. {
  192.   return (OS_file_type_direct (name));
  193. }
  194.  
  195. #define R_OK 4
  196. #define W_OK 2
  197. #define X_OK 1
  198.  
  199. int
  200. DEFUN (OS_file_access, (name, mode), CONST char * name AND unsigned int mode)
  201. {
  202.   BY_HANDLE_FILE_INFORMATION info;
  203.   if ((NT_get_file_info (name, (&info), 1)) != gfi_ok)
  204.     return (0);
  205.   if (((mode & W_OK) != 0)
  206.       && (((info . dwFileAttributes) & FILE_ATTRIBUTE_READONLY) != 0))
  207.     return (0);
  208.   if (((mode & X_OK) != 0)
  209.       && (((info . dwFileAttributes) & FILE_ATTRIBUTE_DIRECTORY) == 0))
  210.     {
  211.       const char * extension = (strrchr (name, '.'));
  212.       if (! (((stricmp (extension, ".exe")) == 0)
  213.          || ((stricmp (extension, ".com")) == 0)
  214.          || ((stricmp (extension, ".bat")) == 0)))
  215.     return (0);
  216.     }
  217.   return (1);
  218. }
  219.  
  220. int
  221. DEFUN (OS_file_directory_p, (name), CONST char * name)
  222. {
  223.   BY_HANDLE_FILE_INFORMATION info;
  224.   return
  225.     (((NT_get_file_info (name, (&info), 0)) == gfi_ok)
  226.      && (((info . dwFileAttributes) & FILE_ATTRIBUTE_DIRECTORY) != 0));
  227. }
  228.  
  229. CONST char *
  230. DEFUN (OS_file_soft_link_p, (name), CONST char * name)
  231. {
  232.   return (0);
  233. }
  234.  
  235. static void
  236. DEFUN (guarantee_writable, (name, errorp),
  237.        CONST char * name AND
  238.        int errorp)
  239. {
  240.   DWORD attributes = (GetFileAttributes (name));
  241.   if (attributes == 0xFFFFFFFF)
  242.     {
  243.       DWORD error_code = (GetLastError ());
  244.       if ((! ((error_code == ERROR_FILE_NOT_FOUND)
  245.           || (error_code == ERROR_PATH_NOT_FOUND)))
  246.       && errorp)
  247.     NT_error_api_call (error_code, apicall_GetFileAttributes);
  248.     }
  249.   else if ((attributes & FILE_ATTRIBUTE_READONLY) != 0)
  250.     {
  251.       if ((! (SetFileAttributes (name,
  252.                  (attributes &~ FILE_ATTRIBUTE_READONLY))))
  253.       && errorp)
  254.     NT_error_api_call ((GetLastError ()), apicall_SetFileAttributes);
  255.     }
  256. }
  257.  
  258. void
  259. DEFUN (OS_file_remove, (name), CONST char * name)
  260. {
  261.   guarantee_writable (name, 1);
  262.   STD_BOOL_API_CALL (DeleteFile, (name));
  263. }
  264.  
  265. void
  266. DEFUN (OS_file_remove_link, (name), CONST char * name)
  267. {
  268.   struct stat s;
  269.   if ((stat (name, (&s)) == 0)
  270.       && (((s . st_mode) & S_IFMT) == S_IFREG))
  271.     {
  272.       guarantee_writable (name, 0);
  273.       unlink (name);
  274.     }
  275. }
  276.  
  277. void
  278. DEFUN (OS_file_rename, (from, to),
  279.        CONST char * from AND
  280.        CONST char * to)
  281. {
  282.   guarantee_writable (to, 1);
  283.   STD_BOOL_API_CALL (MoveFile, (from, to));
  284. }
  285.  
  286. void
  287. DEFUN (OS_file_copy, (from, to),
  288.        CONST char * from AND
  289.        CONST char * to)
  290. {
  291.   guarantee_writable (to, 1);
  292.   STD_BOOL_API_CALL (CopyFile, (from, to, FALSE));
  293. }
  294.  
  295. void
  296. DEFUN (OS_file_link_hard, (from_name, to_name),
  297.        CONST char * from_name AND
  298.        CONST char * to_name)
  299. {
  300.   error_unimplemented_primitive ();
  301. }
  302.  
  303. void
  304. DEFUN (OS_file_link_soft, (from_name, to_name),
  305.        CONST char * from_name AND
  306.        CONST char * to_name)
  307. {
  308.   error_unimplemented_primitive ();
  309. }
  310.  
  311. void
  312. DEFUN (OS_directory_make, (name), CONST char * name)
  313. {
  314.   STD_BOOL_API_CALL (CreateDirectory, (name, 0));
  315. }
  316.  
  317. void
  318. DEFUN (OS_directory_delete, (name), CONST char * name)
  319. {
  320.   STD_BOOL_API_CALL (RemoveDirectory, (name));
  321. }
  322.  
  323. static void EXFUN (protect_fd, (int fd));
  324.  
  325. int
  326. OS_file_touch (const char * filename)
  327. {
  328.   int fd;
  329.   transaction_begin ();
  330.   {
  331.     unsigned int count = 0;
  332.     while (1)
  333.       {
  334.     count += 1;
  335.     /* Use O_EXCL to prevent overwriting existing file. */
  336.     fd = (open (filename, (O_RDWR | O_CREAT | O_EXCL), MODE_REG));
  337.     if (fd >= 0)
  338.       {
  339.         protect_fd (fd);
  340.         transaction_commit ();
  341.         return (1);
  342.       }
  343.     if (errno == EEXIST)
  344.       {
  345.         fd = (open (filename, O_RDWR, MODE_REG));
  346.         if (fd >= 0)
  347.           {
  348.         protect_fd (fd);
  349.         break;
  350.           }
  351.         else if (errno == ENOENT)
  352.           continue;
  353.       }
  354.     if (count >= FILE_TOUCH_OPEN_TRIES)
  355.       NT_error_unix_call (errno, syscall_open);
  356.       }
  357.   }
  358.   {
  359.     struct stat file_status;
  360.     STD_VOID_UNIX_CALL (fstat, (fd, (&file_status)));
  361.     if (((file_status . st_mode) & S_IFMT) != S_IFREG)
  362.       error_bad_range_arg (1);
  363.     /* CASE 3: file length of 0 needs special treatment. */
  364.     if ((file_status . st_size) == 0)
  365.      {
  366.     char buf [1];
  367.     (buf[0]) = '\0';
  368.     STD_VOID_UNIX_CALL (write, (fd, buf, 1));
  369.     transaction_commit ();
  370.     fd = (open (filename, (O_WRONLY | O_TRUNC), MODE_REG));
  371.     if (fd >= 0)
  372.       STD_VOID_UNIX_CALL (close, (fd));
  373.     return (0);
  374.       }
  375.   }
  376.   /* CASE 4: read, then write back the first byte in the file. */
  377.   {
  378.     char buf [1];
  379.     int scr;
  380.     STD_UINT_UNIX_CALL (scr, read, (fd, buf, 1));
  381.     if (scr > 0)
  382.       {
  383.     STD_VOID_UNIX_CALL (lseek, (fd, 0, SEEK_SET));
  384.     STD_VOID_UNIX_CALL (write, (fd, buf, 1));
  385.       }
  386.   }
  387.   transaction_commit ();
  388.   return (0);
  389. }
  390.  
  391. static void
  392. DEFUN (protect_fd_close, (ap), PTR ap)
  393. {
  394.   close (* ((int *) ap));
  395. }
  396.  
  397. static void
  398. DEFUN (protect_fd, (fd), int fd)
  399. {
  400.   int * p = (dstack_alloc (sizeof (int)));
  401.   (*p) = fd;
  402.   transaction_record_action (tat_always, protect_fd_close, p);
  403. }
  404.  
  405. typedef struct nt_dir_struct
  406. {
  407.   WIN32_FIND_DATA entry;
  408.   HANDLE handle;         /* may be DIR_UNALLOCATED */
  409.   BOOL more;
  410. } nt_dir;
  411.  
  412. static nt_dir ** directory_pointers;
  413. static unsigned int n_directory_pointers;
  414.  
  415. void
  416. DEFUN_VOID (NT_initialize_directory_reader)
  417. {
  418.   directory_pointers = 0;
  419.   n_directory_pointers = 0;
  420. }
  421.  
  422. static unsigned int
  423. DEFUN (allocate_directory_pointer, (pointer), nt_dir * pointer)
  424. {
  425.   if (n_directory_pointers == 0)
  426.     {
  427.       nt_dir ** pointers = (OS_malloc ((sizeof (nt_dir *)) * 4));
  428.       directory_pointers = pointers;
  429.       n_directory_pointers = 4;
  430.       {
  431.     nt_dir ** scan = directory_pointers;
  432.     nt_dir ** end = (scan + n_directory_pointers);
  433.     (*scan++) = pointer;
  434.     while (scan < end)
  435.       (*scan++) = 0;
  436.       }
  437.       return (0);
  438.     }
  439.   {
  440.     nt_dir ** scan = directory_pointers;
  441.     nt_dir ** end = (scan + n_directory_pointers);
  442.     while (scan < end)
  443.       if ((*scan++) == 0)
  444.     {
  445.       (*--scan) = pointer;
  446.       return (scan - directory_pointers);
  447.     }
  448.   }
  449.   {
  450.     unsigned int result = n_directory_pointers;
  451.     unsigned int n_pointers = (2 * n_directory_pointers);
  452.     nt_dir ** pointers
  453.       = (OS_realloc (((PTR) directory_pointers),
  454.              ((sizeof (nt_dir *)) * n_pointers)));
  455.     {
  456.       nt_dir ** scan = (pointers + result);
  457.       nt_dir ** end = (pointers + n_pointers);
  458.       (*scan++) = pointer;
  459.       while (scan < end)
  460.     (*scan++) = 0;
  461.     }
  462.     directory_pointers = pointers;
  463.     n_directory_pointers = n_pointers;
  464.     return (result);
  465.   }
  466. }
  467.  
  468. #define REFERENCE_DIRECTORY(index) (directory_pointers[(index)])
  469. #define DEALLOCATE_DIRECTORY(index) ((directory_pointers[(index)]) = 0)
  470.  
  471. int
  472. DEFUN (OS_directory_valid_p, (index), long index)
  473. {
  474.   return
  475.     ((0 <= index)
  476.      && (index < (long) n_directory_pointers)
  477.      && ((REFERENCE_DIRECTORY (index)) != 0));
  478. }
  479.  
  480. unsigned int
  481. DEFUN (OS_directory_open, (name), CONST char * search_pattern)
  482. {
  483.   char pattern [MAX_PATH];
  484.   nt_dir * dir = (OS_malloc (sizeof (nt_dir)));
  485.   strcpy (pattern, search_pattern);
  486.   {
  487.     unsigned int len = (strlen (pattern));
  488.     if ((len > 0) && ((pattern [len - 1]) == '\\'))
  489.       strcat (pattern, "*.*");
  490.   }
  491.   (dir -> handle) = (FindFirstFile (pattern, (& (dir -> entry))));
  492.   if ((dir -> handle) == INVALID_HANDLE_VALUE)
  493.     {
  494.       DWORD code = (GetLastError ());
  495.       if (code != ERROR_FILE_NOT_FOUND)
  496.     {
  497.       free (dir);
  498.       NT_error_api_call (code, apicall_FindFirstFile);
  499.     }
  500.       (dir -> more) = FALSE;
  501.     }
  502.   else
  503.     (dir -> more) = TRUE;
  504.   return (allocate_directory_pointer (dir));
  505. }
  506.  
  507. int
  508. win32_directory_read (unsigned int index, WIN32_FIND_DATA * info)
  509. {
  510.   nt_dir * dir = (REFERENCE_DIRECTORY (index));
  511.   if ((dir == 0) || (! (dir -> more)))
  512.     return (0);
  513.   (*info) = (dir -> entry);
  514.   if ((dir -> handle) == INVALID_HANDLE_VALUE)
  515.     (dir -> more) = FALSE;
  516.   else
  517.     (dir -> more) = (FindNextFile ((dir -> handle), (& (dir -> entry))));
  518.   return (1);
  519. }
  520.  
  521. CONST char *
  522. DEFUN (OS_directory_read, (index), unsigned int index)
  523. {
  524.   static WIN32_FIND_DATA info;
  525.   return
  526.     ((win32_directory_read (index, (&info)))
  527.      ? (info . cFileName)
  528.      : 0);
  529. }
  530.  
  531. CONST char *
  532. DEFUN (OS_directory_read_matching, (index, prefix),
  533.        unsigned int index AND
  534.        CONST char * prefix)
  535. {
  536.   unsigned int n = (strlen (prefix));
  537.   while (1)
  538.     {
  539.       CONST char * pathname = (OS_directory_read (index));
  540.       if (pathname == 0)
  541.     return (0);
  542.       if ((strnicmp (pathname, prefix, n)) == 0)
  543.     return (pathname);
  544.     }
  545. }
  546.  
  547. void
  548. DEFUN (OS_directory_close, (index), unsigned int index)
  549. {
  550.   nt_dir * dir = (REFERENCE_DIRECTORY (index));
  551.   if (dir)
  552.     {
  553.       if ((dir -> handle) != INVALID_HANDLE_VALUE)
  554.     FindClose (dir -> handle);
  555.       free (dir);
  556.     }
  557.   DEALLOCATE_DIRECTORY (index);
  558. }
  559.