(g2-UU+5B73): Add `=decomposition@hanyo-denshi'.
[chise/xemacs-chise.git.1] / src / fileio.c
index 1428ccd..64adf94 100644 (file)
@@ -57,7 +57,13 @@ Boston, MA 02111-1307, USA.  */
 #define WIN32_FILENAMES
 #ifdef WIN32_NATIVE
 #include "nt.h"
+#include <aclapi.h>
 #endif /* WIN32_NATIVE */
+#ifdef CYGWIN
+#include <w32api/aclapi.h>
+#endif
+
+
 #define IS_DRIVE(x) isalpha (x)
 /* Need to lower-case the drive letter, or else expanded
    filenames will sometimes compare inequal, because
@@ -364,6 +370,8 @@ If OPERATION equals `inhibit-file-name-operation', then we ignore
 any handlers that are members of `inhibit-file-name-handlers',
 but we still do run any other handlers.  This lets handlers
 use the standard functions without calling themselves recursively.
+
+Otherwise, OPERATION is the name of a funcall'able function.
 */
        (filename, operation))
 {
@@ -1333,7 +1341,23 @@ No component of the resulting pathname will be a symbolic link, as
     TO_EXTERNAL_FORMAT (LISP_STRING, expanded_name,
                        ALLOCA, (path, elen),
                        Qfile_name);
+
+#if defined(WIN32_FILENAMES) && defined(CYGWIN)
+    /* When using win32 filenames in cygwin we want file-truename to
+       detect that c:/windows == /windows for example. */
+    if ((IS_DIRECTORY_SEP (path[0]) 
+        && (elen == 1 || !IS_DIRECTORY_SEP (path[1])))
+       || (isalpha (path[0])
+           && (elen == 1 || !IS_DEVICE_SEP (path[1])))) {
+      int ltwff2 =
+       cygwin_posix_to_win32_path_list_buf_size (path);
+      p = (Bufbyte *) alloca (ltwff2);
+      cygwin_posix_to_win32_path_list (path, p);
+      path = p;
+    }
+#endif
     p = path;
+
     if (elen > MAXPATHLEN)
       goto toolong;
 
@@ -2249,11 +2273,86 @@ check_executable (char *filename)
 #endif /* not WIN32_NATIVE */
 }
 
+
+
 /* Return nonzero if file FILENAME exists and can be written.  */
 
 static int
 check_writable (const char *filename)
 {
+#if defined(WIN32_NATIVE) || defined(CYGWIN)
+#ifdef CYGWIN
+  char filename_buffer[PATH_MAX];
+#endif
+  // Since this has to work for a directory, we can't just call 'CreateFile'
+  PSECURITY_DESCRIPTOR pDesc; /* Must be freed with LocalFree */
+  /* these need not be freed, they point into pDesc */
+  PSID psidOwner;
+  PSID psidGroup;
+  PACL pDacl;
+  PACL pSacl;
+  /* end of insides of descriptor */
+  DWORD error;
+  DWORD attributes;
+  HANDLE tokenHandle;
+  GENERIC_MAPPING genericMapping;
+  DWORD accessMask;
+  PRIVILEGE_SET PrivilegeSet;
+  DWORD dwPrivSetSize = sizeof( PRIVILEGE_SET );
+  BOOL fAccessGranted = FALSE;
+  DWORD dwAccessAllowed;
+
+#ifdef CYGWIN
+  cygwin_conv_to_full_win32_path(filename, filename_buffer);
+  filename = filename_buffer;
+#endif
+
+  // First check for a normal file with the old-style readonly bit
+  attributes = GetFileAttributes(filename);
+  if (FILE_ATTRIBUTE_READONLY == (attributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_READONLY)))
+    return 0;
+
+  /* Win32 prototype lacks const. */
+  error = GetNamedSecurityInfo((LPTSTR)filename, SE_FILE_OBJECT, 
+                               DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION,
+                               &psidOwner, &psidGroup, &pDacl, &pSacl, &pDesc);
+  if (error != ERROR_SUCCESS) { // FAT?
+    attributes = GetFileAttributes(filename);
+    return (attributes & FILE_ATTRIBUTE_DIRECTORY) || (0 == (attributes & FILE_ATTRIBUTE_READONLY));
+  }
+
+  genericMapping.GenericRead = FILE_GENERIC_READ;
+  genericMapping.GenericWrite = FILE_GENERIC_WRITE;
+  genericMapping.GenericExecute = FILE_GENERIC_EXECUTE;
+  genericMapping.GenericAll = FILE_ALL_ACCESS;
+
+  if (!ImpersonateSelf(SecurityDelegation)) {
+    return 0;
+  }
+  if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &tokenHandle)) {
+      return 0;
+  }
+
+  accessMask = GENERIC_WRITE;
+  MapGenericMask(&accessMask, &genericMapping);
+
+  if (!AccessCheck(pDesc, tokenHandle, accessMask, &genericMapping,
+                   &PrivilegeSet,       // receives privileges used in check
+                   &dwPrivSetSize,      // size of PrivilegeSet buffer
+                   &dwAccessAllowed,    // receives mask of allowed access rights
+                   &fAccessGranted)) 
+  {
+    DWORD oops = GetLastError();
+    CloseHandle(tokenHandle);
+    RevertToSelf();
+    LocalFree(pDesc);
+    return 0;
+  }
+  CloseHandle(tokenHandle);
+  RevertToSelf();
+  LocalFree(pDesc);
+  return fAccessGranted == TRUE;
+#else
 #ifdef HAVE_EACCESS
   return (eaccess (filename, W_OK) >= 0);
 #else
@@ -2264,6 +2363,7 @@ check_writable (const char *filename)
      but would lose for directories.  */
   return (access (filename, W_OK) >= 0);
 #endif
+#endif
 }
 
 DEFUN ("file-exists-p", Ffile_exists_p, 1, 1, 0, /*
@@ -3181,6 +3281,11 @@ of the CODESYS argument under XEmacs/Mule. (When Mule support is not
 present, both functions are identical and ignore the CODESYS argument.)
 If support for Mule exists in this Emacs, the file is encoded according
 to the value of CODESYS.  If this is nil, no code conversion occurs.
+
+As a special kludge to support auto-saving, when START is nil START and
+END are set to the beginning and end, respectively, of the buffer,
+regardless of any restrictions.  Don't use this feature.  It is documented
+here because write-region handler writers need to be aware of it.
 */
        (start, end, filename, append, visit, lockname, codesys))
 {
@@ -3905,7 +4010,7 @@ do_auto_save_unwind_2 (Lisp_Object old_auto_saving)
    and if so, tries to avoid touching lisp objects.
 
    The only time that Fdo_auto_save() is called while GC is in progress
-   is if we're going down, as a result of an abort() or a kill signal.
+   is if we're going down, as a result of an ABORT() or a kill signal.
    It's fairly important that we generate autosave files in that case!
  */