Export the FILE_GetUnixHandle functionality from ntdll.
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index a36457a..2914d24 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -1041,6 +1041,7 @@
# Server interface
@ cdecl -norelay wine_server_call(ptr) wine_server_call
+@ cdecl wine_server_handle_to_fd(long long ptr ptr ptr) wine_server_handle_to_fd
# Codepages
@ cdecl __wine_init_codepages(ptr ptr) __wine_init_codepages
diff --git a/files/file.c b/files/file.c
index 0bc85ac..87953dc 100644
--- a/files/file.c
+++ b/files/file.c
@@ -227,36 +227,12 @@
* Retrieve the Unix handle corresponding to a file handle.
* Returns -1 on failure.
*/
-static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, DWORD *flags )
+static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags )
{
int ret, fd = -1;
- do
- {
- SERVER_START_REQ( get_handle_fd )
- {
- req->handle = handle;
- req->access = access;
- if (!(ret = wine_server_call_err( req )))
- {
- fd = reply->fd;
- }
- if (type) *type = reply->type;
- if (flags) *flags = reply->flags;
- }
- SERVER_END_REQ;
- if (ret) return -1;
-
- if (fd == -1) /* it wasn't in the cache, get it from the server */
- fd = wine_server_recv_fd( handle );
-
- } while (fd == -2); /* -2 means race condition, so restart from scratch */
-
- if (fd != -1)
- {
- if ((fd = dup(fd)) == -1)
- SetLastError( ERROR_TOO_MANY_OPEN_FILES );
- }
+ ret = wine_server_handle_to_fd( handle, access, &fd, type, flags );
+ if (ret) SetLastError( RtlNtStatusToDosError(ret) );
return fd;
}
@@ -1467,9 +1443,8 @@
BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
LPDWORD bytesRead, LPOVERLAPPED overlapped )
{
- int unix_handle, result;
+ int unix_handle, result, flags;
enum fd_type type;
- DWORD flags;
TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
bytesRead, overlapped );
@@ -1693,9 +1668,8 @@
BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
LPDWORD bytesWritten, LPOVERLAPPED overlapped )
{
- int unix_handle, result;
+ int unix_handle, result, flags;
enum fd_type type;
- DWORD flags;
TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
bytesWritten, overlapped );
diff --git a/include/wine/server.h b/include/wine/server.h
index 1280a62..c8fc370 100644
--- a/include/wine/server.h
+++ b/include/wine/server.h
@@ -51,7 +51,8 @@
extern unsigned int wine_server_call( void *req_ptr );
extern void wine_server_send_fd( int fd );
-extern int wine_server_recv_fd( handle_t handle );
+extern int wine_server_handle_to_fd( handle_t handle, unsigned int access, int *unix_fd,
+ enum fd_type *type, int *flags );
/* do a server call and set the last error code */
inline static unsigned int wine_server_call_err( void *req_ptr )
diff --git a/scheduler/client.c b/scheduler/client.c
index 0da699a..c8523ee 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -330,23 +330,17 @@
/***********************************************************************
- * wine_server_recv_fd
+ * store_cached_fd
*
- * Receive a file descriptor passed from the server.
- * The file descriptor must not be closed.
- * Return -2 if a race condition stole our file descriptor.
+ * Store the cached fd value for a given handle back into the server.
+ * Returns the new fd, which can be different if there was already an
+ * fd in the cache for that handle.
*/
-int wine_server_recv_fd( handle_t handle )
+inline static int store_cached_fd( int fd, handle_t handle )
{
- handle_t fd_handle;
-
- int fd = receive_fd( &fd_handle );
-
- /* now store it in the server fd cache for this handle */
-
SERVER_START_REQ( set_handle_info )
{
- req->handle = fd_handle;
+ req->handle = handle;
req->flags = 0;
req->mask = 0;
req->fd = fd;
@@ -366,13 +360,56 @@
}
}
SERVER_END_REQ;
-
- if (handle != fd_handle) fd = -2; /* not the one we expected */
return fd;
}
/***********************************************************************
+ * wine_server_handle_to_fd (NTDLL.@)
+ *
+ * Retrieve the Unix fd corresponding to a file handle.
+ */
+int wine_server_handle_to_fd( handle_t handle, unsigned int access, int *unix_fd,
+ enum fd_type *type, int *flags )
+{
+ handle_t fd_handle;
+ int ret, fd = -1;
+
+ *unix_fd = -1;
+ for (;;)
+ {
+ SERVER_START_REQ( get_handle_fd )
+ {
+ req->handle = handle;
+ req->access = access;
+ if (!(ret = wine_server_call( req ))) fd = reply->fd;
+ if (type) *type = reply->type;
+ if (flags) *flags = reply->flags;
+ }
+ SERVER_END_REQ;
+ if (ret) return ret;
+
+ if (fd != -1) break;
+
+ /* it wasn't in the cache, get it from the server */
+ fd = receive_fd( &fd_handle );
+ /* and store it back into the cache */
+ fd = store_cached_fd( fd, fd_handle );
+
+ if (fd_handle == handle) break;
+ /* if we received a different handle this means there was
+ * a race with another thread; we restart everything from
+ * scratch in this case.
+ */
+ }
+
+ if ((fd != -1) && ((fd = dup(fd)) == -1)) return STATUS_TOO_MANY_OPENED_FILES;
+ *unix_fd = fd;
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
* get_config_dir
*
* Return the configuration directory ($WINEPREFIX or $HOME/.wine)