comparison src/fileio.c @ 3728:6765f2581182

[xemacs-hg @ 2006-12-08 02:21:53 by vins] Added Benson Margulies's patch to avoid the dreaded: "File not found and directory write-protected" message under Windows.
author vins
date Fri, 08 Dec 2006 02:22:02 +0000
parents a0adf5f08c44
children a257e03c580e
comparison
equal deleted inserted replaced
3727:3246cf3e564d 3728:6765f2581182
2289 /* Return nonzero if file FILENAME exists and can be written. */ 2289 /* Return nonzero if file FILENAME exists and can be written. */
2290 2290
2291 static int 2291 static int
2292 check_writable (const Ibyte *filename) 2292 check_writable (const Ibyte *filename)
2293 { 2293 {
2294 #if defined(WIN32_NATIVE) || defined(CYGWIN)
2295 #ifdef CYGWIN
2296 char filename_buffer[PATH_MAX];
2297 #endif
2298 // Since this has to work for a directory, we can't just call 'CreateFile'
2299 PSECURITY_DESCRIPTOR pDesc; /* Must be freed with LocalFree */
2300 /* these need not be freed, they point into pDesc */
2301 PSID psidOwner;
2302 PSID psidGroup;
2303 PACL pDacl;
2304 PACL pSacl;
2305 /* end of insides of descriptor */
2306 DWORD error;
2307 DWORD attributes;
2308 HANDLE tokenHandle;
2309 GENERIC_MAPPING genericMapping;
2310 DWORD accessMask;
2311 PRIVILEGE_SET PrivilegeSet;
2312 DWORD dwPrivSetSize = sizeof( PRIVILEGE_SET );
2313 BOOL fAccessGranted = FALSE;
2314 DWORD dwAccessAllowed;
2315 Extbyte *fnameext;
2316
2317 #ifdef CYGWIN
2318 cygwin_conv_to_full_win32_path(filename, filename_buffer);
2319 filename = (Ibyte*)filename_buffer;
2320 #endif
2321
2322 C_STRING_TO_TSTR(filename, fnameext);
2323 /* Win32 prototype lacks const. */
2324 error = qxeGetNamedSecurityInfo(fnameext, SE_FILE_OBJECT,
2325 DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION,
2326 &psidOwner, &psidGroup, &pDacl, &pSacl, &pDesc);
2327 if(error != ERROR_SUCCESS) { // FAT?
2328 attributes = qxeGetFileAttributes((Extbyte *)filename);
2329 return (attributes & FILE_ATTRIBUTE_DIRECTORY) || (0 == (attributes & FILE_ATTRIBUTE_READONLY));
2330 }
2331
2332 genericMapping.GenericRead = FILE_GENERIC_READ;
2333 genericMapping.GenericWrite = FILE_GENERIC_WRITE;
2334 genericMapping.GenericExecute = FILE_GENERIC_EXECUTE;
2335 genericMapping.GenericAll = FILE_ALL_ACCESS;
2336
2337 if(!ImpersonateSelf(SecurityDelegation)) {
2338 return 0;
2339 }
2340 if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &tokenHandle)) {
2341 return 0;
2342 }
2343
2344 accessMask = GENERIC_WRITE;
2345 MapGenericMask(&accessMask, &genericMapping);
2346
2347 if(!AccessCheck(pDesc, tokenHandle, accessMask, &genericMapping,
2348 &PrivilegeSet, // receives privileges used in check
2349 &dwPrivSetSize, // size of PrivilegeSet buffer
2350 &dwAccessAllowed, // receives mask of allowed access rights
2351 &fAccessGranted))
2352 {
2353 CloseHandle(tokenHandle);
2354 RevertToSelf();
2355 LocalFree(pDesc);
2356 return 0;
2357 }
2358 CloseHandle(tokenHandle);
2359 RevertToSelf();
2360 LocalFree(pDesc);
2361 return fAccessGranted == TRUE;
2362 #else
2294 #ifdef HAVE_EACCESS 2363 #ifdef HAVE_EACCESS
2295 return (qxe_eaccess (filename, W_OK) >= 0); 2364 return (qxe_eaccess (filename, W_OK) >= 0);
2296 #else 2365 #else
2297 /* Access isn't quite right because it uses the real uid 2366 /* Access isn't quite right because it uses the real uid
2298 and we really want to test with the effective uid. 2367 and we really want to test with the effective uid.
2299 But Unix doesn't give us a right way to do it. 2368 But Unix doesn't give us a right way to do it.
2300 Opening with O_WRONLY could work for an ordinary file, 2369 Opening with O_WRONLY could work for an ordinary file,
2301 but would lose for directories. */ 2370 but would lose for directories. */
2302 return (qxe_access (filename, W_OK) >= 0); 2371 return (qxe_access (filename, W_OK) >= 0);
2372 #endif
2303 #endif 2373 #endif
2304 } 2374 }
2305 2375
2306 DEFUN ("file-exists-p", Ffile_exists_p, 1, 1, 0, /* 2376 DEFUN ("file-exists-p", Ffile_exists_p, 1, 1, 0, /*
2307 Return t if file FILENAME exists. (This does not mean you can read it.) 2377 Return t if file FILENAME exists. (This does not mean you can read it.)