Exemple #1
0
int
efile_delete_file(Efile_error* errInfo,		/* Where to return error codes. */
		  char* name)			/* Name of file to delete. */
{
    DWORD attr;
    WCHAR *wname = (WCHAR *) name;

    if (DeleteFileW(wname) != FALSE) {
	return 1;
    }

    errno = errno_map(GetLastError());
    if (errno == EACCES) {
        attr = GetFileAttributesW(wname);
	if (attr != (DWORD) -1) {
	    if (attr & FILE_ATTRIBUTE_DIRECTORY) {
		/*
		 * Windows NT reports removing a directory as EACCES instead
		 * of EPERM.
		 */

		errno = EPERM;
	    }
	}
    } else if (errno == ENOENT) {
        attr = GetFileAttributesW(wname);
	if (attr != (DWORD) -1) {
	    if (attr & FILE_ATTRIBUTE_DIRECTORY) {
	    	/*
		 * Windows 95 reports removing a directory as ENOENT instead 
		 * of EPERM.
		 */

		errno = EPERM;
	    }
	}
    } else if (errno == EINVAL) {
	/*
	 * Windows NT reports removing a char device as EINVAL instead of
	 * EACCES.
	 */
	
	errno = EACCES;
    }

    return check_error(-1, errInfo);
}
Exemple #2
0
static int
set_error(Efile_error* errInfo)
{
    errInfo->posix_errno = errno_map(errInfo->os_errno = GetLastError());
    return 0;
}
Exemple #3
0
int
efile_rename(Efile_error* errInfo,	/* Where to return error codes. */
	     char* src,			/* Original name. */
	     char* dst)			/* New name. */
{
    DWORD srcAttr, dstAttr;
    WCHAR *wsrc = (WCHAR *) src;
    WCHAR *wdst = (WCHAR *) dst;
    
    if (MoveFileW(wsrc, wdst) != FALSE) {
	return 1;
    }

    errno = errno_map(GetLastError());
    srcAttr = GetFileAttributesW(wsrc);
    dstAttr = GetFileAttributesW(wdst);
    if (srcAttr == (DWORD) -1) {
	srcAttr = 0;
    }
    if (dstAttr == (DWORD) -1) {
	dstAttr = 0;
    }

    if (errno == EBADF) {
	errno = EACCES;
	return check_error(-1, errInfo);
    }
    if (errno == EACCES) {
	decode:
	if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
	    WCHAR srcPath[MAX_PATH], dstPath[MAX_PATH];
	    WCHAR *srcRest, *dstRest;
	    int size;

	    size = GetFullPathNameW(wsrc, MAX_PATH, srcPath, &srcRest);
	    if ((size == 0) || (size > MAX_PATH)) {
		return check_error(-1, errInfo);
	    }
	    size = GetFullPathNameW(wdst, MAX_PATH, dstPath, &dstRest);
	    if ((size == 0) || (size > MAX_PATH)) {
		return check_error(-1, errInfo);
	    }
	    if (srcRest == NULL) {
		srcRest = srcPath + wcslen(srcPath);
	    }
	    if (_wcsnicmp(srcPath, dstPath, srcRest - srcPath) == 0) {
		/*
		 * Trying to move a directory into itself.
		 */

		errno = EINVAL;
	    }
	    if (extract_root(srcPath)) {
		/*
		 * Attempt to move a root directory.  Never allowed.
		 */
		errno = EINVAL;
	    }

	    (void) extract_root(dstPath);
	    if (dstPath[0] == L'\0') {
		/*
		 * The filename was invalid.  (Don't know why,
		 * but play it safe.)
		 */
		errno = EINVAL;
	    }
	    if (_wcsicmp(srcPath, dstPath) != 0) {
		/*
		 * If src is a directory and dst filesystem != src
		 * filesystem, errno should be EXDEV.  It is very
		 * important to get this behavior, so that the caller
		 * can respond to a cross filesystem rename by
		 * simulating it with copy and delete.  The MoveFile
		 * system call already handles the case of moving a
		 * *file* between filesystems.
		 */

		errno = EXDEV;
	    }
	}

	/*
	 * Other types of access failure is that dst is a read-only
	 * filesystem, that an open file referred to src or dest, or that
	 * src or dest specified the current working directory on the
	 * current filesystem.  EACCES is returned for those cases.
	 */

    } else if (errno == EEXIST) {
	/*
	 * Reports EEXIST any time the target already exists.  If it makes
	 * sense, remove the old file and try renaming again.
	 */

	if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
	    if (dstAttr & FILE_ATTRIBUTE_DIRECTORY) {
		/*
		 * Overwrite empty dst directory with src directory.  The
		 * following call will remove an empty directory.  If it
		 * fails, it's because it wasn't empty.
		 */

		if (RemoveDirectoryW(wdst)) {
		    /*
		     * Now that that empty directory is gone, we can try
		     * renaming again.  If that fails, we'll put this empty
		     * directory back, for completeness.
		     */

		    if (MoveFileW(wsrc, wdst) != FALSE) {
			return 1;
		    }

		    /*
		     * Some new error has occurred.  Don't know what it
		     * could be, but report this one.
		     */

		    errno = errno_map(GetLastError());
		    CreateDirectoryW(wdst, NULL);
		    SetFileAttributesW(wdst, dstAttr);
		    if (errno == EACCES) {
			/*
			 * Decode the EACCES to a more meaningful error.
			 */

			goto decode;
		    }
		}
	    } else {	/* (dstAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 */
		errno = ENOTDIR;
	    }
	} else {    /* (srcAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 */
	    if (dstAttr & FILE_ATTRIBUTE_DIRECTORY) {
		errno = EISDIR;
	    } else {
		/*
		 * Overwrite existing file by:
		 * 
		 * 1. Rename existing file to temp name.
		 * 2. Rename old file to new name.
		 * 3. If success, delete temp file.  If failure,
		 *    put temp file back to old name.
		 */

		WCHAR tempName[MAX_PATH];
		int result, size;
		WCHAR *rest;
		
		size = GetFullPathNameW(wdst, MAX_PATH, tempName, &rest);
		if ((size == 0) || (size > MAX_PATH) || (rest == NULL)) {
		    return check_error(-1, errInfo);
		}
		*rest = L'\0';
		result = -1;
		if (GetTempFileNameW(tempName, L"erlr", 0, tempName) != 0) {
		    /*
		     * Strictly speaking, need the following DeleteFile and
		     * MoveFile to be joined as an atomic operation so no
		     * other app comes along in the meantime and creates the
		     * same temp file.
		     */
		     
		    DeleteFileW(tempName);
		    if (MoveFileW(wdst, tempName) != FALSE) {
			if (MoveFileW(wsrc, wdst) != FALSE) {
			    SetFileAttributesW(tempName, FILE_ATTRIBUTE_NORMAL);
			    DeleteFileW(tempName);
			    return 1;
			} else {
			    DeleteFileW(wdst);
			    MoveFileW(tempName, wdst);
			}
		    } 

		    /*
		     * Can't backup dst file or move src file.  Return that
		     * error.  Could happen if an open file refers to dst.
		     */

		    errno = errno_map(GetLastError());
		    if (errno == EACCES) {
			/*
			 * Decode the EACCES to a more meaningful error.
			 */

			goto decode;
		    }
		}
		return result;
	    }
	}
    }
    return check_error(-1, errInfo);
}
Exemple #4
0
int
efile_rmdir(Efile_error* errInfo,	/* Where to return error codes. */
	    char* name)			/* Name of directory to delete. */
{
    OSVERSIONINFO os;
    DWORD attr;
    WCHAR *wname = (WCHAR *) name;

    if (RemoveDirectoryW(wname) != FALSE) {
	return 1;
    }
    errno = errno_map(GetLastError());
    if (errno == EACCES) {
	attr = GetFileAttributesW(wname);
	if (attr != (DWORD) -1) {
	    if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
		/* 
		 * Windows 95 reports calling RemoveDirectory on a file as an 
		 * EACCES, not an ENOTDIR.
		 */
		
		errno = ENOTDIR;
		goto end;
	    }

	    /* 
	     * Windows 95 reports removing a non-empty directory as
	     * an EACCES, not an EEXIST.  If the directory is not empty,
	     * change errno so caller knows what's going on.
	     */

	    os.dwOSVersionInfoSize = sizeof(os);
	    GetVersionEx(&os);
	    if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
		HANDLE handle;
		WIN32_FIND_DATAW data;
		WCHAR buffer[2*MAX_PATH];
		int len;

		len = wcslen(wname);
		wcscpy(buffer, wname);
		if (buffer[0] && buffer[len-1] != L'\\' && buffer[len-1] != L'/') {
		    wcscat(buffer, L"\\");
		}
		wcscat(buffer, L"*.*");
		handle = FindFirstFileW(buffer, &data);
		if (handle != INVALID_HANDLE_VALUE) {
		    while (1) {
			if ((wcscmp(data.cFileName, L".") != 0)
				&& (wcscmp(data.cFileName, L"..") != 0)) {
			    /*
			     * Found something in this directory.
			     */

			    errno = EEXIST;
			    break;
			}
			if (FindNextFileW(handle, &data) == FALSE) {
			    break;
			}
		    }
		    FindClose(handle);
		}
	    }
	}
    }

    if (errno == ENOTEMPTY) {
	/* 
	 * Posix allows both EEXIST or ENOTEMPTY, but we'll always
	 * return EEXIST to allow easy matching in Erlang code.
	 */

	errno = EEXIST;
    }

 end:
    return check_error(-1, errInfo);
}