#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
#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
+
+ /* 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
but would lose for directories. */
return (access (filename, W_OK) >= 0);
#endif
+#endif
}
DEFUN ("file-exists-p", Ffile_exists_p, 1, 1, 0, /*
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))
{
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!
*/