blob: ef6dc52fa05d6a90d5905975f6adfe68c33f6219 [file] [log] [blame]
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001/*
2 * File handling functions
3 *
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00006 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +000021 * TODO:
Andreas Mohr20cd9352000-09-12 23:40:40 +000022 * Fix the CopyFileEx methods to implement the "extended" functionality.
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +000023 * Right now, they simply call the CopyFile method.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000024 */
25
Howard Abrams13277481999-07-10 13:16:29 +000026#include "config.h"
Marcus Meissner3f1ed522001-05-14 20:09:37 +000027#include "wine/port.h"
Howard Abrams13277481999-07-10 13:16:29 +000028
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000029#include <assert.h>
Alexandre Julliardd90840e1996-06-11 16:02:08 +000030#include <ctype.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000031#include <errno.h>
32#include <fcntl.h>
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +000033#include <stdlib.h>
Alexandre Julliard383da682000-02-10 22:15:21 +000034#include <stdio.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000035#include <string.h>
Howard Abrams13277481999-07-10 13:16:29 +000036#ifdef HAVE_SYS_ERRNO_H
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000037#include <sys/errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000038#endif
Alexandre Julliard01d63461997-01-20 19:43:45 +000039#include <sys/types.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000040#include <sys/stat.h>
Howard Abrams13277481999-07-10 13:16:29 +000041#ifdef HAVE_SYS_MMAN_H
Alexandre Julliard21979011997-03-05 08:22:35 +000042#include <sys/mman.h>
Howard Abrams13277481999-07-10 13:16:29 +000043#endif
Marcus Meissner7d123bf1998-12-11 09:13:29 +000044#include <sys/time.h>
Michael McCormack1c32a462001-03-22 20:09:34 +000045#include <sys/poll.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000046#include <time.h>
47#include <unistd.h>
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +000048#include <utime.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000049
Alexandre Julliard8bbf8181996-09-13 16:50:47 +000050#include "winerror.h"
Marcus Meissner317af321999-02-17 13:51:06 +000051#include "windef.h"
52#include "winbase.h"
53#include "wine/winbase16.h"
Martin Wilck2b47fb32002-04-05 22:53:57 +000054#include "wine/server.h"
55
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000056#include "drive.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000057#include "file.h"
Martin Wilck2b47fb32002-04-05 22:53:57 +000058#include "async.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000059#include "heap.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000060#include "msdos.h"
Marcus Meissner6b5a8111999-01-30 13:06:00 +000061#include "wincon.h"
Mike McCormackfc932612002-03-12 19:24:04 +000062
63#include "smb.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000064#include "wine/debug.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000065
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000066WINE_DEFAULT_DEBUG_CHANNEL(file);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000067
Alexandre Julliard21979011997-03-05 08:22:35 +000068#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
69#define MAP_ANON MAP_ANONYMOUS
70#endif
Alexandre Julliard0c126c71996-02-18 18:44:41 +000071
Alexandre Julliard8da12c41999-01-17 16:55:11 +000072/* Size of per-process table of DOS handles */
73#define DOS_TABLE_SIZE 256
Alexandre Julliard0c126c71996-02-18 18:44:41 +000074
Martin Wilck718b1b72002-01-07 21:02:15 +000075/* Macro to derive file offset from OVERLAPPED struct */
76#define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
77
Alexandre Julliard231674d2000-08-09 22:30:18 +000078static HANDLE dos_handles[DOS_TABLE_SIZE];
79
Francois Gouget34372dc2002-03-29 18:17:35 +000080mode_t FILE_umask;
81
Stefan Leichterf25efa02002-04-11 17:34:46 +000082extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
Alexandre Julliarda11d7b11998-03-01 20:05:02 +000083
Alexandre Julliard0c126c71996-02-18 18:44:41 +000084/***********************************************************************
Martin Wilck2b47fb32002-04-05 22:53:57 +000085 * Asynchronous file I/O *
86 */
87static DWORD fileio_get_async_status (const async_private *ovp);
88static DWORD fileio_get_async_count (const async_private *ovp);
89static void fileio_set_async_status (async_private *ovp, const DWORD status);
90static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
Martin Wilck08867f72002-04-14 19:34:57 +000091static void fileio_async_cleanup (async_private *ovp);
Martin Wilck2b47fb32002-04-05 22:53:57 +000092
93static async_ops fileio_async_ops =
94{
95 fileio_get_async_status, /* get_status */
96 fileio_set_async_status, /* set_status */
97 fileio_get_async_count, /* get_count */
Martin Wilck08867f72002-04-14 19:34:57 +000098 fileio_call_completion_func, /* call_completion */
99 fileio_async_cleanup /* cleanup */
100};
101
102static async_ops fileio_nocomp_async_ops =
103{
104 fileio_get_async_status, /* get_status */
105 fileio_set_async_status, /* set_status */
106 fileio_get_async_count, /* get_count */
107 NULL, /* call_completion */
108 fileio_async_cleanup /* cleanup */
Martin Wilck2b47fb32002-04-05 22:53:57 +0000109};
110
111typedef struct async_fileio
112{
113 struct async_private async;
114 LPOVERLAPPED lpOverlapped;
115 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
116 char *buffer;
117 int count;
Martin Wilck9ca42852002-04-25 22:58:59 +0000118 enum fd_type fd_type;
Martin Wilck2b47fb32002-04-05 22:53:57 +0000119} async_fileio;
120
121static DWORD fileio_get_async_status (const struct async_private *ovp)
122{
123 return ((async_fileio*) ovp)->lpOverlapped->Internal;
124}
125
126static void fileio_set_async_status (async_private *ovp, const DWORD status)
127{
128 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
129}
130
131static DWORD fileio_get_async_count (const struct async_private *ovp)
132{
133 async_fileio *fileio = (async_fileio*) ovp;
134 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
135 return (ret < 0 ? 0 : ret);
136}
137
138static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
139{
140 async_fileio *ovp = (async_fileio*) data;
141 TRACE ("data: %p\n", ovp);
142
Martin Wilck08867f72002-04-14 19:34:57 +0000143 ovp->completion_func( ovp->lpOverlapped->Internal,
144 ovp->lpOverlapped->InternalHigh,
145 ovp->lpOverlapped );
Martin Wilck2b47fb32002-04-05 22:53:57 +0000146
Martin Wilck08867f72002-04-14 19:34:57 +0000147 fileio_async_cleanup ( &ovp->async );
148}
149
150static void fileio_async_cleanup ( struct async_private *ovp )
151{
152 HeapFree ( GetProcessHeap(), 0, ovp );
Martin Wilck2b47fb32002-04-05 22:53:57 +0000153}
154
155/***********************************************************************
Alexandre Julliard05625391999-01-03 11:55:56 +0000156 * FILE_ConvertOFMode
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000157 *
Alexandre Julliard05625391999-01-03 11:55:56 +0000158 * Convert OF_* mode into flags for CreateFile.
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000159 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000160static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000161{
Alexandre Julliard05625391999-01-03 11:55:56 +0000162 switch(mode & 0x03)
163 {
164 case OF_READ: *access = GENERIC_READ; break;
165 case OF_WRITE: *access = GENERIC_WRITE; break;
166 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
167 default: *access = 0; break;
168 }
169 switch(mode & 0x70)
170 {
171 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
172 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
173 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
174 case OF_SHARE_DENY_NONE:
175 case OF_SHARE_COMPAT:
176 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
177 }
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000178}
179
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000180
181/***********************************************************************
Aric Stewarte4d09322000-12-03 03:14:29 +0000182 * FILE_strcasecmp
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000183 *
Aric Stewarte4d09322000-12-03 03:14:29 +0000184 * locale-independent case conversion for file I/O
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000185 */
Aric Stewarte4d09322000-12-03 03:14:29 +0000186int FILE_strcasecmp( const char *str1, const char *str2 )
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000187{
Aric Stewarte4d09322000-12-03 03:14:29 +0000188 for (;;)
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000189 {
Aric Stewarte4d09322000-12-03 03:14:29 +0000190 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
191 if (ret || !*str1) return ret;
192 str1++;
193 str2++;
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000194 }
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000195}
Aric Stewarte4d09322000-12-03 03:14:29 +0000196
197
198/***********************************************************************
199 * FILE_strncasecmp
200 *
201 * locale-independent case conversion for file I/O
202 */
203int FILE_strncasecmp( const char *str1, const char *str2, int len )
204{
205 int ret = 0;
206 for ( ; len > 0; len--, str1++, str2++)
207 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
208 return ret;
209}
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000210
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000211
212/***********************************************************************
Martin Wilck9ca42852002-04-25 22:58:59 +0000213 * FILE_GetNtStatus(void)
214 *
215 * Retrieve the Nt Status code from errno.
216 * Try to be consistent with FILE_SetDosError().
217 */
218DWORD FILE_GetNtStatus(void)
219{
220 int err = errno;
221 DWORD nt;
222 TRACE ( "errno = %d\n", errno );
223 switch ( err )
224 {
225 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
226 case EBADF: nt = STATUS_INVALID_HANDLE; break;
227 case ENOSPC: nt = STATUS_DISK_FULL; break;
228 case EPERM:
229 case EROFS:
230 case EACCES: nt = STATUS_ACCESS_DENIED; break;
231 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
232 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
233 case EMFILE:
234 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
235 case EINVAL:
236 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
237 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
238 case ENOEXEC: /* ?? */
239 case ESPIPE: /* ?? */
240 case EEXIST: /* ?? */
241 default:
242 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
243 nt = STATUS_UNSUCCESSFUL;
244 }
245 return nt;
246}
247
248/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000249 * FILE_SetDosError
250 *
251 * Set the DOS error code from errno.
252 */
253void FILE_SetDosError(void)
254{
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000255 int save_errno = errno; /* errno gets overwritten by printf */
256
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000257 TRACE("errno = %d %s\n", errno, strerror(errno));
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000258 switch (save_errno)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000259 {
260 case EAGAIN:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000261 SetLastError( ERROR_SHARING_VIOLATION );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000262 break;
263 case EBADF:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000264 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000265 break;
266 case ENOSPC:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000267 SetLastError( ERROR_HANDLE_DISK_FULL );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000268 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000269 case EACCES:
270 case EPERM:
271 case EROFS:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000272 SetLastError( ERROR_ACCESS_DENIED );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000273 break;
274 case EBUSY:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000275 SetLastError( ERROR_LOCK_VIOLATION );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000276 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000277 case ENOENT:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000278 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000279 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000280 case EISDIR:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000281 SetLastError( ERROR_CANNOT_MAKE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000282 break;
283 case ENFILE:
284 case EMFILE:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000285 SetLastError( ERROR_NO_MORE_FILES );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000286 break;
287 case EEXIST:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000288 SetLastError( ERROR_FILE_EXISTS );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000289 break;
Alexandre Julliarde658d821997-11-30 17:45:40 +0000290 case EINVAL:
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000291 case ESPIPE:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000292 SetLastError( ERROR_SEEK );
Alexandre Julliarde658d821997-11-30 17:45:40 +0000293 break;
294 case ENOTEMPTY:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000295 SetLastError( ERROR_DIR_NOT_EMPTY );
Alexandre Julliarde658d821997-11-30 17:45:40 +0000296 break;
Alexandre Julliard045d81f2000-05-01 16:20:23 +0000297 case ENOEXEC:
298 SetLastError( ERROR_BAD_FORMAT );
299 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000300 default:
Andreas Mohrc9cf70d2001-01-26 20:40:50 +0000301 WARN("unknown file error: %s\n", strerror(save_errno) );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000302 SetLastError( ERROR_GEN_FAILURE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000303 break;
304 }
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000305 errno = save_errno;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000306}
307
308
309/***********************************************************************
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000310 * FILE_DupUnixHandle
311 *
312 * Duplicate a Unix handle into a task handle.
François Gouget4b4f69a2001-01-09 20:51:19 +0000313 * Returns 0 on failure.
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000314 */
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000315HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000316{
Mike McCormackeb3e38e2001-01-12 19:57:38 +0000317 HANDLE ret;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000318
319 wine_server_send_fd( fd );
320
Alexandre Julliard67a74992001-02-27 02:09:16 +0000321 SERVER_START_REQ( alloc_file_handle )
Mike McCormackeb3e38e2001-01-12 19:57:38 +0000322 {
Mike McCormackeb3e38e2001-01-12 19:57:38 +0000323 req->access = access;
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000324 req->inherit = inherit;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000325 req->fd = fd;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000326 wine_server_call( req );
327 ret = reply->handle;
Mike McCormackeb3e38e2001-01-12 19:57:38 +0000328 }
329 SERVER_END_REQ;
330 return ret;
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000331}
332
333
334/***********************************************************************
Mike McCormackff58be52001-10-04 16:18:15 +0000335 * FILE_GetUnixHandleType
Alexandre Julliard92643002000-08-31 01:59:51 +0000336 *
337 * Retrieve the Unix handle corresponding to a file handle.
François Gouget4b4f69a2001-01-09 20:51:19 +0000338 * Returns -1 on failure.
Alexandre Julliard92643002000-08-31 01:59:51 +0000339 */
Martin Wilckaf16c982002-04-25 21:34:24 +0000340static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
Alexandre Julliard92643002000-08-31 01:59:51 +0000341{
Martin Wilckaf16c982002-04-25 21:34:24 +0000342 int ret, flags, fd = -1;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000343
Martin Wilckaf16c982002-04-25 21:34:24 +0000344 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
345 if (flags_ptr) *flags_ptr = flags;
Alexandre Julliard8d1550d2002-03-23 18:48:12 +0000346 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
Martin Wilckaf16c982002-04-25 21:34:24 +0000347 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
348 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
349 {
350 close (fd);
351 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
352 return -1;
353 }
Alexandre Julliardd549f692000-12-22 02:04:15 +0000354 return fd;
Alexandre Julliard92643002000-08-31 01:59:51 +0000355}
356
Mike McCormackff58be52001-10-04 16:18:15 +0000357/***********************************************************************
358 * FILE_GetUnixHandle
359 *
360 * Retrieve the Unix handle corresponding to a file handle.
361 * Returns -1 on failure.
362 */
363int FILE_GetUnixHandle( HANDLE handle, DWORD access )
364{
Martin Wilck88cd32b2002-01-09 20:30:51 +0000365 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
Mike McCormackff58be52001-10-04 16:18:15 +0000366}
Alexandre Julliard92643002000-08-31 01:59:51 +0000367
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000368/*************************************************************************
369 * FILE_OpenConsole
370 *
371 * Open a handle to the current process console.
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000372 * Returns 0 on failure.
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000373 */
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000374static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000375{
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000376 HANDLE ret;
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000377
Alexandre Julliard67a74992001-02-27 02:09:16 +0000378 SERVER_START_REQ( open_console )
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000379 {
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000380 req->from = output;
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000381 req->access = access;
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000382 req->share = sharing;
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000383 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
384 SetLastError(0);
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000385 wine_server_call_err( req );
386 ret = reply->handle;
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000387 }
388 SERVER_END_REQ;
389 return ret;
390}
391
392
Alexandre Julliard92643002000-08-31 01:59:51 +0000393/***********************************************************************
Alexandre Julliard05625391999-01-03 11:55:56 +0000394 * FILE_CreateFile
395 *
396 * Implementation of CreateFile. Takes a Unix path name.
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000397 * Returns 0 on failure.
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000398 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000399HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000400 LPSECURITY_ATTRIBUTES sa, DWORD creation,
Ove Kaaven708a8462001-10-24 00:23:25 +0000401 DWORD attributes, HANDLE template, BOOL fail_read_only,
402 UINT drive_type )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000403{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000404 unsigned int err;
Alexandre Julliard92643002000-08-31 01:59:51 +0000405 HANDLE ret;
Alexandre Julliard92643002000-08-31 01:59:51 +0000406
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000407 for (;;)
Alexandre Julliard92643002000-08-31 01:59:51 +0000408 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000409 SERVER_START_REQ( create_file )
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000410 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000411 req->access = access;
412 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
413 req->sharing = sharing;
414 req->create = creation;
415 req->attrs = attributes;
416 req->drive_type = drive_type;
417 wine_server_add_data( req, filename, strlen(filename) );
418 SetLastError(0);
419 err = wine_server_call( req );
420 ret = reply->handle;
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000421 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000422 SERVER_END_REQ;
423
424 /* If write access failed, retry without GENERIC_WRITE */
425
426 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
427 {
428 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
429 {
430 TRACE("Write access failed for file '%s', trying without "
431 "write access\n", filename);
432 access &= ~GENERIC_WRITE;
433 continue;
434 }
435 }
436
437 if (err) SetLastError( RtlNtStatusToDosError(err) );
438
439 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
440 return ret;
Matthew Cline8bfd8252000-02-18 19:05:11 +0000441 }
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000442}
443
444
445/***********************************************************************
446 * FILE_CreateDevice
447 *
448 * Same as FILE_CreateFile but for a device
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000449 * Returns 0 on failure.
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000450 */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000451HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000452{
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000453 HANDLE ret;
Alexandre Julliard67a74992001-02-27 02:09:16 +0000454 SERVER_START_REQ( create_device )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000455 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000456 req->access = access;
457 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
458 req->id = client_id;
459 SetLastError(0);
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000460 wine_server_call_err( req );
461 ret = reply->handle;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000462 }
463 SERVER_END_REQ;
464 return ret;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000465}
466
Mike McCormackde7c3002001-07-10 19:16:49 +0000467static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
468{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000469 WCHAR buffer[MAX_PATH];
Mike McCormackde7c3002001-07-10 19:16:49 +0000470 HANDLE ret;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000471 DWORD len = 0;
Mike McCormackde7c3002001-07-10 19:16:49 +0000472
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000473 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
Mike McCormackde7c3002001-07-10 19:16:49 +0000474 {
475 SetLastError( ERROR_FILENAME_EXCED_RANGE );
476 return 0;
477 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000478 SERVER_START_REQ( open_named_pipe )
Mike McCormackde7c3002001-07-10 19:16:49 +0000479 {
480 req->access = access;
Mike McCormackde7c3002001-07-10 19:16:49 +0000481 SetLastError(0);
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000482 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
483 wine_server_call_err( req );
484 ret = reply->handle;
Mike McCormackde7c3002001-07-10 19:16:49 +0000485 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000486 SERVER_END_REQ;
Mike McCormackde7c3002001-07-10 19:16:49 +0000487 TRACE("Returned %d\n",ret);
488 return ret;
489}
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000490
Alexandre Julliard05625391999-01-03 11:55:56 +0000491/*************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000492 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
Uwe Bonnesa370ab41998-10-24 09:16:44 +0000493 *
Alexandre Julliard05625391999-01-03 11:55:56 +0000494 * Creates or opens an object, and returns a handle that can be used to
495 * access that object.
Uwe Bonnesa370ab41998-10-24 09:16:44 +0000496 *
Alexandre Julliard05625391999-01-03 11:55:56 +0000497 * PARAMS
498 *
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +0000499 * filename [in] pointer to filename to be accessed
500 * access [in] access mode requested
501 * sharing [in] share mode
502 * sa [in] pointer to security attributes
503 * creation [in] how to create the file
504 * attributes [in] attributes for newly created file
505 * template [in] handle to file with extended attributes to copy
Alexandre Julliard05625391999-01-03 11:55:56 +0000506 *
507 * RETURNS
508 * Success: Open handle to specified file
509 * Failure: INVALID_HANDLE_VALUE
510 *
511 * NOTES
512 * Should call SetLastError() on failure.
513 *
514 * BUGS
515 *
Mike McCormackde7c3002001-07-10 19:16:49 +0000516 * Doesn't support character devices, template files, or a
Alexandre Julliard05625391999-01-03 11:55:56 +0000517 * lot of the 'attributes' flags yet.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000518 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000519HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
Alexandre Julliard05625391999-01-03 11:55:56 +0000520 LPSECURITY_ATTRIBUTES sa, DWORD creation,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000521 DWORD attributes, HANDLE template )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000522{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000523 DOS_FULL_NAME full_name;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000524 HANDLE ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000525
Alexandre Julliard05625391999-01-03 11:55:56 +0000526 if (!filename)
527 {
528 SetLastError( ERROR_INVALID_PARAMETER );
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000529 return INVALID_HANDLE_VALUE;
Alexandre Julliard05625391999-01-03 11:55:56 +0000530 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000531 TRACE("%s %s%s%s%s%s%s%s\n",filename,
Uwe Bonnese4f46dc1999-06-06 17:08:13 +0000532 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
533 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
534 (!access)?"QUERY_ACCESS ":"",
535 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
536 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
537 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
538 (creation ==CREATE_NEW)?"CREATE_NEW":
539 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
540 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
541 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
542 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000543
Alexandre Julliard05625391999-01-03 11:55:56 +0000544 /* If the name starts with '\\?\', ignore the first 4 chars. */
545 if (!strncmp(filename, "\\\\?\\", 4))
546 {
547 filename += 4;
548 if (!strncmp(filename, "UNC\\", 4))
549 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000550 FIXME("UNC name (%s) not supported.\n", filename );
Alexandre Julliard05625391999-01-03 11:55:56 +0000551 SetLastError( ERROR_PATH_NOT_FOUND );
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000552 return INVALID_HANDLE_VALUE;
Alexandre Julliard05625391999-01-03 11:55:56 +0000553 }
554 }
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000555
Marcus Meissnerdd7523d2000-01-23 02:18:27 +0000556 if (!strncmp(filename, "\\\\.\\", 4)) {
Mike McCormackde7c3002001-07-10 19:16:49 +0000557 if(!strncasecmp(&filename[4],"pipe\\",5))
558 {
559 TRACE("Opening a pipe: %s\n",filename);
Ove Kaaven7efa8e22001-09-25 22:37:32 +0000560 ret = FILE_OpenPipe(filename,access);
561 goto done;
Mike McCormackde7c3002001-07-10 19:16:49 +0000562 }
Eric Pouech5cc61052002-01-13 01:44:00 +0000563 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
564 {
565 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
566 goto done;
567 }
Mike McCormackde7c3002001-07-10 19:16:49 +0000568 else if (!DOSFS_GetDevice( filename ))
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000569 {
570 ret = DEVICE_Open( filename+4, access, sa );
571 goto done;
572 }
Marcus Meissnerdd7523d2000-01-23 02:18:27 +0000573 else
574 filename+=4; /* fall into DOSFS_Device case below */
575 }
Alexandre Julliard05625391999-01-03 11:55:56 +0000576
577 /* If the name still starts with '\\', it's a UNC name. */
578 if (!strncmp(filename, "\\\\", 2))
579 {
Mike McCormackfc932612002-03-12 19:24:04 +0000580 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
581 goto done;
Alexandre Julliard05625391999-01-03 11:55:56 +0000582 }
583
Francois Boisvert567bcf11999-09-20 18:31:21 +0000584 /* If the name contains a DOS wild card (* or ?), do no create a file */
585 if(strchr(filename,'*') || strchr(filename,'?'))
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000586 return INVALID_HANDLE_VALUE;
Francois Boisvert567bcf11999-09-20 18:31:21 +0000587
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000588 /* Open a console for CONIN$ or CONOUT$ */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000589 if (!strcasecmp(filename, "CONIN$"))
590 {
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000591 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000592 goto done;
593 }
594 if (!strcasecmp(filename, "CONOUT$"))
595 {
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000596 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000597 goto done;
598 }
Alexandre Julliard05625391999-01-03 11:55:56 +0000599
600 if (DOSFS_GetDevice( filename ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000601 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000602 TRACE("opening device '%s'\n", filename );
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000603
Eric Pouech3bbeb722001-10-14 16:08:45 +0000604 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000605 {
606 /* Do not silence this please. It is a critical error. -MM */
607 ERR("Couldn't open device '%s'!\n",filename);
608 SetLastError( ERROR_FILE_NOT_FOUND );
609 }
610 goto done;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000611 }
Alexandre Julliard05625391999-01-03 11:55:56 +0000612
613 /* check for filename, don't check for last entry if creating */
614 if (!DOSFS_GetFullName( filename,
Matthew Cline8bfd8252000-02-18 19:05:11 +0000615 (creation == OPEN_EXISTING) ||
616 (creation == TRUNCATE_EXISTING),
617 &full_name )) {
618 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
619 filename, GetLastError());
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000620 return INVALID_HANDLE_VALUE;
Matthew Cline8bfd8252000-02-18 19:05:11 +0000621 }
Alexandre Julliard05625391999-01-03 11:55:56 +0000622
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000623 ret = FILE_CreateFile( full_name.long_name, access, sharing,
624 sa, creation, attributes, template,
Ove Kaaven708a8462001-10-24 00:23:25 +0000625 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
626 GetDriveTypeA( full_name.short_name ) );
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000627 done:
628 if (!ret) ret = INVALID_HANDLE_VALUE;
629 return ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000630}
631
632
Alexandre Julliard05625391999-01-03 11:55:56 +0000633
634/*************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000635 * CreateFileW (KERNEL32.@)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000636 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000637HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
Alexandre Julliard05625391999-01-03 11:55:56 +0000638 LPSECURITY_ATTRIBUTES sa, DWORD creation,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000639 DWORD attributes, HANDLE template)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000640{
Alexandre Julliard05625391999-01-03 11:55:56 +0000641 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Jim Aston031f4fa1999-10-23 19:00:02 +0000642 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
Alexandre Julliard05625391999-01-03 11:55:56 +0000643 HeapFree( GetProcessHeap(), 0, afn );
644 return res;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000645}
646
647
648/***********************************************************************
649 * FILE_FillInfo
650 *
651 * Fill a file information from a struct stat.
652 */
Marcus Meissner6bb990f2001-05-29 20:55:21 +0000653static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000654{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000655 if (S_ISDIR(st->st_mode))
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000656 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
657 else
658 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
Alexandre Julliard01d63461997-01-20 19:43:45 +0000659 if (!(st->st_mode & S_IWUSR))
660 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000661
Alexandre Julliarde101f6d2000-08-14 14:42:41 +0000662 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
663 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
664 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000665
666 info->dwVolumeSerialNumber = 0; /* FIXME */
667 info->nFileSizeHigh = 0;
Marcus Meissner3f1ed522001-05-14 20:09:37 +0000668 info->nFileSizeLow = 0;
669 if (!S_ISDIR(st->st_mode)) {
670 info->nFileSizeHigh = st->st_size >> 32;
671 info->nFileSizeLow = st->st_size & 0xffffffff;
672 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000673 info->nNumberOfLinks = st->st_nlink;
674 info->nFileIndexHigh = 0;
675 info->nFileIndexLow = st->st_ino;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000676}
677
678
679/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000680 * FILE_Stat
681 *
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000682 * Stat a Unix path name. Return TRUE if OK.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000683 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000684BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000685{
Marcus Meissner6bb990f2001-05-29 20:55:21 +0000686 struct stat st;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000687
Marcus Meissner6bb990f2001-05-29 20:55:21 +0000688 if (lstat( unixName, &st ) == -1)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000689 {
690 FILE_SetDosError();
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000691 return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000692 }
Andreas Mohr220312e2000-10-19 20:38:38 +0000693 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
694 else
695 {
696 /* do a "real" stat to find out
697 about the type of the symlink destination */
Marcus Meissner6bb990f2001-05-29 20:55:21 +0000698 if (stat( unixName, &st ) == -1)
Andreas Mohr220312e2000-10-19 20:38:38 +0000699 {
700 FILE_SetDosError();
701 return FALSE;
702 }
703 FILE_FillInfo( &st, info );
704 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
705 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000706 return TRUE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000707}
708
709
710/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000711 * GetFileInformationByHandle (KERNEL32.@)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000712 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000713DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000714 BY_HANDLE_FILE_INFORMATION *info )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000715{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000716 DWORD ret;
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000717 if (!info) return 0;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000718
Alexandre Julliard67a74992001-02-27 02:09:16 +0000719 SERVER_START_REQ( get_file_info )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000720 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000721 req->handle = hFile;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000722 if ((ret = !wine_server_call_err( req )))
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000723 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000724 /* FIXME: which file types are supported ?
725 * Serial ports (FILE_TYPE_CHAR) are not,
726 * and MSDN also says that pipes are not supported.
727 * FILE_TYPE_REMOTE seems to be supported according to
728 * MSDN q234741.txt */
729 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
730 {
731 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
732 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
733 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
734 info->dwFileAttributes = reply->attr;
735 info->dwVolumeSerialNumber = reply->serial;
736 info->nFileSizeHigh = reply->size_high;
737 info->nFileSizeLow = reply->size_low;
738 info->nNumberOfLinks = reply->links;
739 info->nFileIndexHigh = reply->index_high;
740 info->nFileIndexLow = reply->index_low;
741 }
742 else
743 {
744 SetLastError(ERROR_NOT_SUPPORTED);
745 ret = 0;
746 }
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000747 }
748 }
749 SERVER_END_REQ;
750 return ret;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000751}
752
753
754/**************************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000755 * GetFileAttributes (KERNEL.420)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000756 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000757DWORD WINAPI GetFileAttributes16( LPCSTR name )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000758{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000759 return GetFileAttributesA( name );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000760}
761
762
763/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000764 * GetFileAttributesA (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000765 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000766DWORD WINAPI GetFileAttributesA( LPCSTR name )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000767{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000768 DOS_FULL_NAME full_name;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000769 BY_HANDLE_FILE_INFORMATION info;
770
Jon Griffiths0cfa2782001-02-14 00:26:46 +0000771 if (name == NULL)
772 {
773 SetLastError( ERROR_INVALID_PARAMETER );
774 return -1;
775 }
Gerard Pateld52e1c42001-02-16 19:05:42 +0000776 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
Jon Griffiths0cfa2782001-02-14 00:26:46 +0000777 return -1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000778 if (!FILE_Stat( full_name.long_name, &info )) return -1;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000779 return info.dwFileAttributes;
780}
781
782
783/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000784 * GetFileAttributesW (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000785 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000786DWORD WINAPI GetFileAttributesW( LPCWSTR name )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000787{
788 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000789 DWORD res = GetFileAttributesA( nameA );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000790 HeapFree( GetProcessHeap(), 0, nameA );
791 return res;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000792}
793
794
Francois Gouget34372dc2002-03-29 18:17:35 +0000795/**************************************************************************
796 * SetFileAttributes (KERNEL.421)
797 */
798BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
799{
800 return SetFileAttributesA( lpFileName, attributes );
801}
802
803
804/**************************************************************************
805 * SetFileAttributesA (KERNEL32.@)
806 */
807BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
808{
809 struct stat buf;
810 DOS_FULL_NAME full_name;
811
812 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
813 return FALSE;
814
815 TRACE("(%s,%lx)\n",lpFileName,attributes);
816 if (attributes & FILE_ATTRIBUTE_NORMAL) {
817 attributes &= ~FILE_ATTRIBUTE_NORMAL;
818 if (attributes)
819 FIXME("(%s):%lx illegal combination with FILE_ATTRIBUTE_NORMAL.\n", lpFileName,attributes);
820 }
821 if(stat(full_name.long_name,&buf)==-1)
822 {
823 FILE_SetDosError();
824 return FALSE;
825 }
826 if (attributes & FILE_ATTRIBUTE_READONLY)
827 {
828 if(S_ISDIR(buf.st_mode))
829 /* FIXME */
830 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
831 else
832 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
833 attributes &= ~FILE_ATTRIBUTE_READONLY;
834 }
835 else
836 {
837 /* add write permission */
838 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
839 }
840 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
841 {
842 if (!S_ISDIR(buf.st_mode))
843 FIXME("SetFileAttributes expected the file '%s' to be a directory",
844 lpFileName);
845 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
846 }
847 attributes &= ~(FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
848 if (attributes)
849 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
850 if (-1==chmod(full_name.long_name,buf.st_mode))
851 {
852 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
853 SetLastError( ERROR_ACCESS_DENIED );
854 return FALSE;
855 }
856
857 /*
858 * FIXME: We don't return FALSE here because of differences between
859 * Linux and Windows privileges. Under Linux only the owner of
860 * the file is allowed to change file attributes. Under Windows,
861 * applications expect that if you can write to a file, you can also
862 * change its attributes (see GENERIC_WRITE). We could try to be
863 * clever here but that would break multi-user installations where
864 * users share read-only DLLs. This is because some installers like
865 * to change attributes of already installed DLLs.
866 */
867 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
868 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
869 }
870 return TRUE;
871}
872
873
874/**************************************************************************
875 * SetFileAttributesW (KERNEL32.@)
876 */
877BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
878{
879 BOOL res;
880 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
881 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
882
883 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
884 res = SetFileAttributesA( afn, attributes );
885 HeapFree( GetProcessHeap(), 0, afn );
886 return res;
887}
888
889
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000890/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000891 * GetFileSize (KERNEL32.@)
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000892 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000893DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000894{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000895 BY_HANDLE_FILE_INFORMATION info;
Andreas Mohr12bf7f12001-03-05 19:30:52 +0000896 if (!GetFileInformationByHandle( hFile, &info )) return -1;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000897 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
898 return info.nFileSizeLow;
899}
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000900
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000901
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000902/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000903 * GetFileTime (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000904 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000905BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000906 FILETIME *lpLastAccessTime,
907 FILETIME *lpLastWriteTime )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000908{
909 BY_HANDLE_FILE_INFORMATION info;
910 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
911 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
912 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
913 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
914 return TRUE;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000915}
916
Alexandre Julliard349a9531997-02-02 19:01:52 +0000917/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000918 * CompareFileTime (KERNEL32.@)
Alexandre Julliard349a9531997-02-02 19:01:52 +0000919 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000920INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
Alexandre Julliard349a9531997-02-02 19:01:52 +0000921{
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000922 if (!x || !y) return -1;
923
Alexandre Julliard349a9531997-02-02 19:01:52 +0000924 if (x->dwHighDateTime > y->dwHighDateTime)
925 return 1;
926 if (x->dwHighDateTime < y->dwHighDateTime)
927 return -1;
928 if (x->dwLowDateTime > y->dwLowDateTime)
929 return 1;
930 if (x->dwLowDateTime < y->dwLowDateTime)
931 return -1;
932 return 0;
933}
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000934
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000935/***********************************************************************
Gerard Patelc465e191999-10-24 20:48:54 +0000936 * FILE_GetTempFileName : utility for GetTempFileName
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000937 */
Gerard Patelc465e191999-10-24 20:48:54 +0000938static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
939 LPSTR buffer, BOOL isWin16 )
Alexandre Julliardca22b331996-07-12 19:02:39 +0000940{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000941 static UINT unique_temp;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000942 DOS_FULL_NAME full_name;
Alexandre Julliardca22b331996-07-12 19:02:39 +0000943 int i;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000944 LPSTR p;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000945 UINT num;
Alexandre Julliardca22b331996-07-12 19:02:39 +0000946
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000947 if ( !path || !prefix || !buffer ) return 0;
948
Uwe Bonnes2e525891998-11-01 15:04:52 +0000949 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
950 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
951
Alexandre Julliardca22b331996-07-12 19:02:39 +0000952 strcpy( buffer, path );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000953 p = buffer + strlen(buffer);
Alexandre Julliard02e90081998-01-04 17:49:09 +0000954
955 /* add a \, if there isn't one and path is more than just the drive letter ... */
956 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
957 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
958
Gerard Patelc465e191999-10-24 20:48:54 +0000959 if (isWin16) *p++ = '~';
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000960 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
961 sprintf( p, "%04x.tmp", num );
962
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000963 /* Now try to create it */
964
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000965 if (!unique)
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000966 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000967 do
968 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000969 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
François Gouget4b4f69a2001-01-09 20:51:19 +0000970 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000971 if (handle != INVALID_HANDLE_VALUE)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000972 { /* We created it */
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000973 TRACE("created %s\n",
Alexandre Julliard21979011997-03-05 08:22:35 +0000974 buffer);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000975 CloseHandle( handle );
976 break;
977 }
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000978 if (GetLastError() != ERROR_FILE_EXISTS)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000979 break; /* No need to go on */
980 num++;
981 sprintf( p, "%04x.tmp", num );
982 } while (num != (unique & 0xffff));
983 }
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000984
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000985 /* Get the full path name */
986
987 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
988 {
Alexandre Julliard01d63461997-01-20 19:43:45 +0000989 /* Check if we have write access in the directory */
990 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000991 if (access( full_name.long_name, W_OK ) == -1)
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000992 WARN("returns '%s', which doesn't seem to be writeable.\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000993 buffer);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000994 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000995 TRACE("returning %s\n", buffer );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000996 return unique ? unique : num;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000997}
998
999
1000/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001001 * GetTempFileNameA (KERNEL32.@)
Gerard Patelc465e191999-10-24 20:48:54 +00001002 */
1003UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1004 LPSTR buffer)
1005{
1006 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
1007}
1008
1009/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001010 * GetTempFileNameW (KERNEL32.@)
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001011 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001012UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001013 LPWSTR buffer )
Alexandre Julliardca22b331996-07-12 19:02:39 +00001014{
1015 LPSTR patha,prefixa;
1016 char buffera[144];
Alexandre Julliarda3960291999-02-26 11:11:13 +00001017 UINT ret;
Alexandre Julliardca22b331996-07-12 19:02:39 +00001018
1019 if (!path) return 0;
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001020 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1021 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
Gerard Patelc465e191999-10-24 20:48:54 +00001022 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001023 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001024 HeapFree( GetProcessHeap(), 0, patha );
1025 HeapFree( GetProcessHeap(), 0, prefixa );
Alexandre Julliardca22b331996-07-12 19:02:39 +00001026 return ret;
1027}
1028
1029
1030/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001031 * GetTempFileName (KERNEL.97)
Gerard Patelc465e191999-10-24 20:48:54 +00001032 */
1033UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1034 LPSTR buffer )
1035{
1036 char temppath[144];
1037
1038 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1039 drive |= DRIVE_GetCurrentDrive() + 'A';
1040
1041 if ((drive & TF_FORCEDRIVE) &&
1042 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1043 {
1044 drive &= ~TF_FORCEDRIVE;
1045 WARN("invalid drive %d specified\n", drive );
1046 }
1047
1048 if (drive & TF_FORCEDRIVE)
1049 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1050 else
1051 GetTempPathA( 132, temppath );
1052 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1053}
1054
1055/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001056 * FILE_DoOpenFile
1057 *
1058 * Implementation of OpenFile16() and OpenFile32().
Alexandre Julliardca22b331996-07-12 19:02:39 +00001059 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001060static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1061 BOOL win32 )
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001062{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001063 HFILE hFileRet;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001064 FILETIME filetime;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001065 WORD filedatetime[2];
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001066 DOS_FULL_NAME full_name;
Alexandre Julliard05625391999-01-03 11:55:56 +00001067 DWORD access, sharing;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001068 char *p;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001069
Alexandre Julliarda3960291999-02-26 11:11:13 +00001070 if (!ofs) return HFILE_ERROR;
Uwe Bonnese4f46dc1999-06-06 17:08:13 +00001071
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001072 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
Uwe Bonnese4f46dc1999-06-06 17:08:13 +00001073 ((mode & 0x3 )==OF_READ)?"OF_READ":
1074 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1075 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1076 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1077 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1078 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1079 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1080 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1081 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1082 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1083 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1084 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1085 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1086 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1087 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1088 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1089 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1090 );
1091
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001092
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001093 ofs->cBytes = sizeof(OFSTRUCT);
1094 ofs->nErrCode = 0;
1095 if (mode & OF_REOPEN) name = ofs->szPathName;
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001096
1097 if (!name) {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001098 ERR("called with `name' set to NULL ! Please debug.\n");
Alexandre Julliarda3960291999-02-26 11:11:13 +00001099 return HFILE_ERROR;
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001100 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001101
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001102 TRACE("%s %04x\n", name, mode );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001103
Alexandre Julliard889f7421997-04-15 17:19:52 +00001104 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1105 Are there any cases where getting the path here is wrong?
1106 Uwe Bonnes 1997 Apr 2 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001107 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
Alexandre Julliard889f7421997-04-15 17:19:52 +00001108 ofs->szPathName, NULL )) goto error;
Alexandre Julliard05625391999-01-03 11:55:56 +00001109 FILE_ConvertOFMode( mode, &access, &sharing );
Alexandre Julliard889f7421997-04-15 17:19:52 +00001110
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001111 /* OF_PARSE simply fills the structure */
1112
1113 if (mode & OF_PARSE)
1114 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001115 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1116 != DRIVE_REMOVABLE);
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001117 TRACE("(%s): OF_PARSE, res = '%s'\n",
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001118 name, ofs->szPathName );
1119 return 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001120 }
1121
1122 /* OF_CREATE is completely different from all other options, so
1123 handle it first */
1124
1125 if (mode & OF_CREATE)
1126 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001127 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
Alexandre Julliard638f1691999-01-17 16:32:32 +00001128 sharing, NULL, CREATE_ALWAYS,
François Gouget4b4f69a2001-01-09 20:51:19 +00001129 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001130 goto error;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001131 goto success;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001132 }
1133
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001134 /* If OF_SEARCH is set, ignore the given path */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001135
1136 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1137 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001138 /* First try the file name as is */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001139 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001140 /* Now remove the path */
1141 if (name[0] && (name[1] == ':')) name += 2;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001142 if ((p = strrchr( name, '\\' ))) name = p + 1;
1143 if ((p = strrchr( name, '/' ))) name = p + 1;
1144 if (!name[0]) goto not_found;
1145 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001146
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001147 /* Now look for the file */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001148
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001149 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001150
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001151found:
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001152 TRACE("found %s = %s\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001153 full_name.long_name, full_name.short_name );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001154 lstrcpynA( ofs->szPathName, full_name.short_name,
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001155 sizeof(ofs->szPathName) );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001156
Alexandre Julliard767e6f61998-08-09 12:47:43 +00001157 if (mode & OF_SHARE_EXCLUSIVE)
Uwe Bonnese6b5e381998-10-18 14:48:31 +00001158 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1159 on the file <tempdir>/_ins0432._mp to determine how
1160 far installation has proceeded.
1161 _ins0432._mp is an executable and while running the
1162 application expects the open with OF_SHARE_ to fail*/
1163 /* Probable FIXME:
1164 As our loader closes the files after loading the executable,
1165 we can't find the running executable with FILE_InUse.
Andreas Mohrc9cf70d2001-01-26 20:40:50 +00001166 The loader should keep the file open, as Windows does that, too.
1167 */
Alexandre Julliard767e6f61998-08-09 12:47:43 +00001168 {
1169 char *last = strrchr(full_name.long_name,'/');
1170 if (!last)
1171 last = full_name.long_name - 1;
Alexandre Julliard767e6f61998-08-09 12:47:43 +00001172 if (GetModuleHandle16(last+1))
1173 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001174 TRACE("Denying shared open for %s\n",full_name.long_name);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001175 return HFILE_ERROR;
Alexandre Julliard767e6f61998-08-09 12:47:43 +00001176 }
Alexandre Julliard767e6f61998-08-09 12:47:43 +00001177 }
1178
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001179 if (mode & OF_DELETE)
1180 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001181 if (unlink( full_name.long_name ) == -1) goto not_found;
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001182 TRACE("(%s): OF_DELETE return = OK\n", name);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001183 return 1;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001184 }
1185
Alexandre Julliard05625391999-01-03 11:55:56 +00001186 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
Alexandre Julliard8081e5a2001-01-05 04:08:07 +00001187 NULL, OPEN_EXISTING, 0, 0,
Ove Kaaven708a8462001-10-24 00:23:25 +00001188 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1189 GetDriveTypeA( full_name.short_name ) );
Alexandre Julliard8081e5a2001-01-05 04:08:07 +00001190 if (!hFileRet) goto not_found;
Uwe Bonnese6b5e381998-10-18 14:48:31 +00001191
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001192 GetFileTime( hFileRet, NULL, NULL, &filetime );
1193 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001194 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001195 {
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001196 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001197 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001198 CloseHandle( hFileRet );
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001199 WARN("(%s): OF_VERIFY failed\n", name );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001200 /* FIXME: what error here? */
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001201 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001202 goto error;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001203 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001204 }
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001205 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001206
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001207success: /* We get here if the open was successful */
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001208 TRACE("(%s): OK, return = %d\n", name, hFileRet );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001209 if (win32)
1210 {
1211 if (mode & OF_EXIST) /* Return the handle, but close it first */
1212 CloseHandle( hFileRet );
1213 }
1214 else
1215 {
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001216 hFileRet = Win32HandleToDosFileHandle( hFileRet );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001217 if (hFileRet == HFILE_ERROR16) goto error;
1218 if (mode & OF_EXIST) /* Return the handle, but close it first */
1219 _lclose16( hFileRet );
1220 }
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001221 return hFileRet;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001222
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001223not_found: /* We get here if the file does not exist */
Andreas Mohr20cd9352000-09-12 23:40:40 +00001224 WARN("'%s' not found or sharing violation\n", name );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001225 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001226 /* fall through */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001227
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001228error: /* We get here if there was an error opening the file */
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001229 ofs->nErrCode = GetLastError();
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001230 WARN("(%s): return = HFILE_ERROR error= %d\n",
Alexandre Julliard889f7421997-04-15 17:19:52 +00001231 name,ofs->nErrCode );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001232 return HFILE_ERROR;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001233}
1234
Alexandre Julliardac9c9b01996-07-28 18:50:11 +00001235
1236/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001237 * OpenFile (KERNEL.74)
1238 * OpenFileEx (KERNEL.360)
Alexandre Julliardac9c9b01996-07-28 18:50:11 +00001239 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001240HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001241{
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001242 return FILE_DoOpenFile( name, ofs, mode, FALSE );
Alexandre Julliardac9c9b01996-07-28 18:50:11 +00001243}
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001244
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001245
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001246/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001247 * OpenFile (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001248 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001249HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001250{
1251 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1252}
1253
1254
1255/***********************************************************************
Marcus Meissnerb12e72d1999-01-23 14:01:08 +00001256 * FILE_InitProcessDosHandles
1257 *
1258 * Allocates the default DOS handles for a process. Called either by
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001259 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
Marcus Meissnerb12e72d1999-01-23 14:01:08 +00001260 */
Alexandre Julliard231674d2000-08-09 22:30:18 +00001261static void FILE_InitProcessDosHandles( void )
1262{
1263 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1264 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1265 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1266 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1267 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
Marcus Meissnerb12e72d1999-01-23 14:01:08 +00001268}
1269
1270/***********************************************************************
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001271 * Win32HandleToDosFileHandle (KERNEL32.21)
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001272 *
1273 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1274 * longer valid after this function (even on failure).
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001275 *
1276 * Note: this is not exactly right, since on Win95 the Win32 handles
1277 * are on top of DOS handles and we do it the other way
1278 * around. Should be good enough though.
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001279 */
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001280HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001281{
1282 int i;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001283
Alexandre Julliarda3960291999-02-26 11:11:13 +00001284 if (!handle || (handle == INVALID_HANDLE_VALUE))
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001285 return HFILE_ERROR;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001286
Alexandre Julliard231674d2000-08-09 22:30:18 +00001287 for (i = 5; i < DOS_TABLE_SIZE; i++)
1288 if (!dos_handles[i])
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001289 {
Alexandre Julliard231674d2000-08-09 22:30:18 +00001290 dos_handles[i] = handle;
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001291 TRACE("Got %d for h32 %d\n", i, handle );
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001292 return (HFILE)i;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001293 }
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001294 CloseHandle( handle );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001295 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001296 return HFILE_ERROR;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001297}
1298
1299
1300/***********************************************************************
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001301 * DosFileHandleToWin32Handle (KERNEL32.20)
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001302 *
1303 * Return the Win32 handle for a DOS handle.
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001304 *
1305 * Note: this is not exactly right, since on Win95 the Win32 handles
1306 * are on top of DOS handles and we do it the other way
1307 * around. Should be good enough though.
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001308 */
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001309HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001310{
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001311 HFILE16 hfile = (HFILE16)handle;
Alexandre Julliard231674d2000-08-09 22:30:18 +00001312 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1313 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001314 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001315 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001316 return INVALID_HANDLE_VALUE;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001317 }
Alexandre Julliard231674d2000-08-09 22:30:18 +00001318 return dos_handles[hfile];
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001319}
1320
1321
1322/***********************************************************************
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001323 * DisposeLZ32Handle (KERNEL32.22)
1324 *
1325 * Note: this is not entirely correct, we should only close the
1326 * 32-bit handle and not the 16-bit one, but we cannot do
1327 * this because of the way our DOS handles are implemented.
1328 * It shouldn't break anything though.
1329 */
1330void WINAPI DisposeLZ32Handle( HANDLE handle )
1331{
1332 int i;
1333
1334 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1335
1336 for (i = 5; i < DOS_TABLE_SIZE; i++)
1337 if (dos_handles[i] == handle)
1338 {
1339 dos_handles[i] = 0;
1340 CloseHandle( handle );
1341 break;
1342 }
1343}
1344
1345
1346/***********************************************************************
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001347 * FILE_Dup2
1348 *
1349 * dup2() function for DOS handles.
1350 */
1351HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1352{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001353 HANDLE new_handle;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001354
Alexandre Julliard231674d2000-08-09 22:30:18 +00001355 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1356
1357 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001358 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001359 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001360 return HFILE_ERROR16;
1361 }
1362 if (hFile2 < 5)
1363 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001364 FIXME("stdio handle closed, need proper conversion\n" );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001365 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001366 return HFILE_ERROR16;
1367 }
Alexandre Julliard231674d2000-08-09 22:30:18 +00001368 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001369 GetCurrentProcess(), &new_handle,
1370 0, FALSE, DUPLICATE_SAME_ACCESS ))
1371 return HFILE_ERROR16;
Alexandre Julliard231674d2000-08-09 22:30:18 +00001372 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1373 dos_handles[hFile2] = new_handle;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001374 return hFile2;
1375}
1376
1377
1378/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001379 * _lclose (KERNEL.81)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001380 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001381HFILE16 WINAPI _lclose16( HFILE16 hFile )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001382{
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001383 if (hFile < 5)
1384 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001385 FIXME("stdio handle closed, need proper conversion\n" );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001386 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001387 return HFILE_ERROR16;
1388 }
Alexandre Julliard231674d2000-08-09 22:30:18 +00001389 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001390 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001391 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001392 return HFILE_ERROR16;
1393 }
Alexandre Julliard231674d2000-08-09 22:30:18 +00001394 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1395 CloseHandle( dos_handles[hFile] );
1396 dos_handles[hFile] = 0;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001397 return 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001398}
1399
1400
1401/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001402 * _lclose (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001403 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001404HFILE WINAPI _lclose( HFILE hFile )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001405{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001406 TRACE("handle %d\n", hFile );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001407 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001408}
1409
Moshe Vainer0ea089b1999-11-10 19:51:01 +00001410/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001411 * GetOverlappedResult (KERNEL32.@)
Mike McCormackad72e712000-12-29 19:44:18 +00001412 *
1413 * Check the result of an Asynchronous data transfer from a file.
1414 *
1415 * RETURNS
1416 * TRUE on success
1417 * FALSE on failure
1418 *
Francois Gouget3bb9a362001-10-22 19:04:32 +00001419 * If successful (and relevant) lpTransferred will hold the number of
1420 * bytes transferred during the async operation.
Mike McCormackad72e712000-12-29 19:44:18 +00001421 *
1422 * BUGS
1423 *
1424 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1425 * with communications ports.
1426 *
Moshe Vainer0ea089b1999-11-10 19:51:01 +00001427 */
Mike McCormackad72e712000-12-29 19:44:18 +00001428BOOL WINAPI GetOverlappedResult(
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +00001429 HANDLE hFile, /* [in] handle of file to check on */
1430 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
Francois Gouget3bb9a362001-10-22 19:04:32 +00001431 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +00001432 BOOL bWait /* [in] wait for the transfer to complete ? */
Mike McCormackad72e712000-12-29 19:44:18 +00001433) {
1434 DWORD r;
1435
1436 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1437
1438 if(lpOverlapped==NULL)
1439 {
1440 ERR("lpOverlapped was null\n");
1441 return FALSE;
1442 }
1443 if(!lpOverlapped->hEvent)
1444 {
1445 ERR("lpOverlapped->hEvent was null\n");
1446 return FALSE;
1447 }
1448
1449 do {
1450 TRACE("waiting on %p\n",lpOverlapped);
1451 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1452 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1453 } while (r==STATUS_USER_APC);
1454
1455 if(lpTransferred)
Mike McCormackeb3e38e2001-01-12 19:57:38 +00001456 *lpTransferred = lpOverlapped->InternalHigh;
Mike McCormackad72e712000-12-29 19:44:18 +00001457
Martin Wilcke0587d42002-04-17 16:46:06 +00001458 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
Martin Wilckaf16c982002-04-25 21:34:24 +00001459 ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
Michael McCormack1c32a462001-03-22 20:09:34 +00001460
Mike McCormackad72e712000-12-29 19:44:18 +00001461 return (r==WAIT_OBJECT_0);
Moshe Vainer0ea089b1999-11-10 19:51:01 +00001462}
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001463
Mike McCormack6f011c02001-12-20 00:07:05 +00001464/***********************************************************************
Mike McCormackb473a0f2001-08-22 18:02:39 +00001465 * CancelIo (KERNEL32.@)
1466 */
1467BOOL WINAPI CancelIo(HANDLE handle)
1468{
Mike McCormackde339f32002-01-07 18:06:59 +00001469 async_private *ovp,*t;
1470
1471 TRACE("handle = %x\n",handle);
1472
Martin Wilck2b47fb32002-04-05 22:53:57 +00001473 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
Mike McCormackde339f32002-01-07 18:06:59 +00001474 {
1475 t = ovp->next;
Martin Wilck2b47fb32002-04-05 22:53:57 +00001476 if ( ovp->handle == handle )
1477 cancel_async ( ovp );
Mike McCormackde339f32002-01-07 18:06:59 +00001478 }
1479 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1480 return TRUE;
Mike McCormackb473a0f2001-08-22 18:02:39 +00001481}
1482
1483/***********************************************************************
Mike McCormackf21aac02001-01-10 22:45:03 +00001484 * FILE_AsyncReadService (INTERNAL)
Michael McCormack1c32a462001-03-22 20:09:34 +00001485 *
1486 * This function is called while the client is waiting on the
1487 * server, so we can't make any server calls here.
Mike McCormackf21aac02001-01-10 22:45:03 +00001488 */
Mike McCormack6f011c02001-12-20 00:07:05 +00001489static void FILE_AsyncReadService(async_private *ovp)
Mike McCormackf21aac02001-01-10 22:45:03 +00001490{
Martin Wilck2b47fb32002-04-05 22:53:57 +00001491 async_fileio *fileio = (async_fileio*) ovp;
1492 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
Michael McCormack1c32a462001-03-22 20:09:34 +00001493 int result, r;
Martin Wilck718b1b72002-01-07 21:02:15 +00001494 int already = lpOverlapped->InternalHigh;
Mike McCormackf21aac02001-01-10 22:45:03 +00001495
Martin Wilck2b47fb32002-04-05 22:53:57 +00001496 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
Mike McCormackf21aac02001-01-10 22:45:03 +00001497
1498 /* check to see if the data is ready (non-blocking) */
Martin Wilck718b1b72002-01-07 21:02:15 +00001499
Martin Wilck9ca42852002-04-25 22:58:59 +00001500 if ( fileio->fd_type == FD_TYPE_SOCKET )
Martin Wilck2b47fb32002-04-05 22:53:57 +00001501 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
Martin Wilck9ca42852002-04-25 22:58:59 +00001502 else
1503 {
1504 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1505 OVERLAPPED_OFFSET (lpOverlapped) + already);
1506 if ((result < 0) && (errno == ESPIPE))
1507 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1508 }
Mike McCormackf21aac02001-01-10 22:45:03 +00001509
1510 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1511 {
1512 TRACE("Deferred read %d\n",errno);
1513 r = STATUS_PENDING;
1514 goto async_end;
1515 }
1516
1517 /* check to see if the transfer is complete */
1518 if(result<0)
1519 {
Martin Wilck9ca42852002-04-25 22:58:59 +00001520 r = FILE_GetNtStatus ();
Mike McCormackf21aac02001-01-10 22:45:03 +00001521 goto async_end;
1522 }
1523
Mike McCormackeb3e38e2001-01-12 19:57:38 +00001524 lpOverlapped->InternalHigh += result;
Martin Wilck2b47fb32002-04-05 22:53:57 +00001525 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
Mike McCormackf21aac02001-01-10 22:45:03 +00001526
Martin Wilck9ca42852002-04-25 22:58:59 +00001527 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
Mike McCormackf21aac02001-01-10 22:45:03 +00001528 r = STATUS_SUCCESS;
Martin Wilck9ca42852002-04-25 22:58:59 +00001529 else
1530 r = STATUS_PENDING;
Mike McCormackf21aac02001-01-10 22:45:03 +00001531
1532async_end:
1533 lpOverlapped->Internal = r;
Michael McCormack1c32a462001-03-22 20:09:34 +00001534}
Mike McCormackf21aac02001-01-10 22:45:03 +00001535
Mike McCormackea4f32c2001-10-17 17:45:11 +00001536/***********************************************************************
Mike McCormack6f030e82001-08-20 18:01:17 +00001537 * FILE_ReadFileEx (INTERNAL)
Mike McCormackf21aac02001-01-10 22:45:03 +00001538 */
Mike McCormack6f030e82001-08-20 18:01:17 +00001539static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
Mike McCormacka38e5e52001-07-08 20:29:26 +00001540 LPOVERLAPPED overlapped,
Mike McCormack4a6b9902002-03-11 01:19:29 +00001541 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1542 HANDLE hEvent)
Mike McCormackf21aac02001-01-10 22:45:03 +00001543{
Martin Wilck2b47fb32002-04-05 22:53:57 +00001544 async_fileio *ovp;
Mike McCormack6f011c02001-12-20 00:07:05 +00001545 int fd;
Martin Wilck08867f72002-04-14 19:34:57 +00001546 int flags;
1547 enum fd_type type;
Mike McCormackf21aac02001-01-10 22:45:03 +00001548
Mike McCormacka38e5e52001-07-08 20:29:26 +00001549 TRACE("file %d to buf %p num %ld %p func %p\n",
1550 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1551
Mike McCormack91195432002-01-01 01:11:32 +00001552 /* check that there is an overlapped struct */
1553 if (overlapped==NULL)
Mike McCormacka38e5e52001-07-08 20:29:26 +00001554 {
Mike McCormacka38e5e52001-07-08 20:29:26 +00001555 SetLastError(ERROR_INVALID_PARAMETER);
1556 return FALSE;
1557 }
1558
Martin Wilck08867f72002-04-14 19:34:57 +00001559 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1560 if ( fd < 0 )
Michael McCormack1c32a462001-03-22 20:09:34 +00001561 {
Martin Wilck08867f72002-04-14 19:34:57 +00001562 WARN ( "Couldn't get FD\n" );
Michael McCormack1c32a462001-03-22 20:09:34 +00001563 return FALSE;
1564 }
1565
Martin Wilck2b47fb32002-04-05 22:53:57 +00001566 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
Michael McCormack1c32a462001-03-22 20:09:34 +00001567 if(!ovp)
1568 {
1569 TRACE("HeapAlloc Failed\n");
Mike McCormacka38e5e52001-07-08 20:29:26 +00001570 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
Martin Wilck08867f72002-04-14 19:34:57 +00001571 goto error;
Michael McCormack1c32a462001-03-22 20:09:34 +00001572 }
Martin Wilck2b47fb32002-04-05 22:53:57 +00001573
Martin Wilck08867f72002-04-14 19:34:57 +00001574 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
Martin Wilck2b47fb32002-04-05 22:53:57 +00001575 ovp->async.handle = hFile;
1576 ovp->async.fd = fd;
1577 ovp->async.type = ASYNC_TYPE_READ;
1578 ovp->async.func = FILE_AsyncReadService;
1579 ovp->async.event = hEvent;
Michael McCormack1c32a462001-03-22 20:09:34 +00001580 ovp->lpOverlapped = overlapped;
Mike McCormacke61ad3a2001-07-12 22:29:41 +00001581 ovp->count = bytesToRead;
1582 ovp->completion_func = lpCompletionRoutine;
Michael McCormack1c32a462001-03-22 20:09:34 +00001583 ovp->buffer = buffer;
Martin Wilck9ca42852002-04-25 22:58:59 +00001584 ovp->fd_type = type;
Michael McCormack1c32a462001-03-22 20:09:34 +00001585
Martin Wilck2b47fb32002-04-05 22:53:57 +00001586 return !register_new_async (&ovp->async);
Martin Wilck08867f72002-04-14 19:34:57 +00001587
1588error:
1589 close (fd);
1590 return FALSE;
1591
Mike McCormack6f030e82001-08-20 18:01:17 +00001592}
Michael McCormack1c32a462001-03-22 20:09:34 +00001593
Mike McCormack6f030e82001-08-20 18:01:17 +00001594/***********************************************************************
1595 * ReadFileEx (KERNEL32.@)
1596 */
1597BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1598 LPOVERLAPPED overlapped,
1599 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1600{
Mike McCormack6f030e82001-08-20 18:01:17 +00001601 overlapped->InternalHigh = 0;
Mike McCormack4a6b9902002-03-11 01:19:29 +00001602 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
Mike McCormack27cf4a42001-12-19 18:48:29 +00001603}
1604
1605static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1606{
1607 OVERLAPPED ov;
1608 BOOL r = FALSE;
1609
1610 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1611
1612 ZeroMemory(&ov, sizeof (OVERLAPPED));
1613 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1614 {
Mike McCormack4a6b9902002-03-11 01:19:29 +00001615 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
Mike McCormack27cf4a42001-12-19 18:48:29 +00001616 {
1617 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1618 }
1619 }
1620 CloseHandle(ov.hEvent);
1621 return r;
1622}
1623
Mike McCormackf21aac02001-01-10 22:45:03 +00001624/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001625 * ReadFile (KERNEL32.@)
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001626 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001627BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001628 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1629{
Alexandre Julliard8d1550d2002-03-23 18:48:12 +00001630 int unix_handle, result, flags;
Martin Wilck88cd32b2002-01-09 20:30:51 +00001631 enum fd_type type;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001632
Mike McCormackf21aac02001-01-10 22:45:03 +00001633 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1634 bytesRead, overlapped );
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001635
1636 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1637 if (!bytesToRead) return TRUE;
1638
Martin Wilck88cd32b2002-01-09 20:30:51 +00001639 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
Mike McCormack9e1fc622001-10-10 20:26:58 +00001640
Martin Wilck88cd32b2002-01-09 20:30:51 +00001641 if (flags & FD_FLAG_OVERLAPPED)
Mike McCormack6f030e82001-08-20 18:01:17 +00001642 {
Eric Pouech0b83d4c2001-11-23 23:04:58 +00001643 if (unix_handle == -1) return FALSE;
Mike McCormack91195432002-01-01 01:11:32 +00001644 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
Mike McCormack9e1fc622001-10-10 20:26:58 +00001645 {
Mike McCormack91195432002-01-01 01:11:32 +00001646 TRACE("Overlapped not specified or invalid event flag\n");
Eric Pouech0b83d4c2001-11-23 23:04:58 +00001647 close(unix_handle);
Mike McCormack9e1fc622001-10-10 20:26:58 +00001648 SetLastError(ERROR_INVALID_PARAMETER);
Mike McCormack6f030e82001-08-20 18:01:17 +00001649 return FALSE;
Mike McCormack9e1fc622001-10-10 20:26:58 +00001650 }
Mike McCormack6f030e82001-08-20 18:01:17 +00001651
Martin Wilcke0587d42002-04-17 16:46:06 +00001652 close(unix_handle);
1653 overlapped->InternalHigh = 0;
Mike McCormack6f030e82001-08-20 18:01:17 +00001654
Mike McCormack4a6b9902002-03-11 01:19:29 +00001655 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
Mike McCormack6f030e82001-08-20 18:01:17 +00001656 return FALSE;
1657
Martin Wilcke0587d42002-04-17 16:46:06 +00001658 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1659 {
1660 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1661 SetLastError ( ERROR_IO_PENDING );
1662 return FALSE;
1663 }
1664
1665 return TRUE;
Martin Wilck88cd32b2002-01-09 20:30:51 +00001666 }
1667 if (flags & FD_FLAG_TIMEOUT)
1668 {
Mike McCormack27cf4a42001-12-19 18:48:29 +00001669 close(unix_handle);
1670 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
Martin Wilck88cd32b2002-01-09 20:30:51 +00001671 }
1672 switch(type)
1673 {
Mike McCormackfc932612002-03-12 19:24:04 +00001674 case FD_TYPE_SMB:
1675 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
Martin Wilck88cd32b2002-01-09 20:30:51 +00001676 case FD_TYPE_CONSOLE:
1677 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
Mike McCormack27cf4a42001-12-19 18:48:29 +00001678
Mike McCormack9e1fc622001-10-10 20:26:58 +00001679 default:
Eric Pouech0b83d4c2001-11-23 23:04:58 +00001680 /* normal unix files */
1681 if (unix_handle == -1)
1682 return FALSE;
1683 if (overlapped)
1684 {
1685 close(unix_handle);
1686 SetLastError(ERROR_INVALID_PARAMETER);
1687 return FALSE;
1688 }
1689 break;
Mike McCormack9e1fc622001-10-10 20:26:58 +00001690 }
Mike McCormackf21aac02001-01-10 22:45:03 +00001691
1692 /* code for synchronous reads */
Alexandre Julliard55443871998-12-31 15:52:06 +00001693 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001694 {
Eric Pouech0b83d4c2001-11-23 23:04:58 +00001695 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1696 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1697 FILE_SetDosError();
1698 break;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001699 }
Alexandre Julliard55443871998-12-31 15:52:06 +00001700 close( unix_handle );
1701 if (result == -1) return FALSE;
1702 if (bytesRead) *bytesRead = result;
1703 return TRUE;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001704}
1705
Michael McCormack1c32a462001-03-22 20:09:34 +00001706
Mike McCormackf21aac02001-01-10 22:45:03 +00001707/***********************************************************************
1708 * FILE_AsyncWriteService (INTERNAL)
Michael McCormack1c32a462001-03-22 20:09:34 +00001709 *
1710 * This function is called while the client is waiting on the
1711 * server, so we can't make any server calls here.
Mike McCormackf21aac02001-01-10 22:45:03 +00001712 */
Mike McCormack6f011c02001-12-20 00:07:05 +00001713static void FILE_AsyncWriteService(struct async_private *ovp)
Mike McCormackf21aac02001-01-10 22:45:03 +00001714{
Martin Wilck2b47fb32002-04-05 22:53:57 +00001715 async_fileio *fileio = (async_fileio *) ovp;
1716 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
Michael McCormack1c32a462001-03-22 20:09:34 +00001717 int result, r;
Martin Wilck718b1b72002-01-07 21:02:15 +00001718 int already = lpOverlapped->InternalHigh;
Mike McCormackf21aac02001-01-10 22:45:03 +00001719
Martin Wilck2b47fb32002-04-05 22:53:57 +00001720 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
Mike McCormackf21aac02001-01-10 22:45:03 +00001721
Mike McCormackf21aac02001-01-10 22:45:03 +00001722 /* write some data (non-blocking) */
Martin Wilck718b1b72002-01-07 21:02:15 +00001723
Martin Wilck9ca42852002-04-25 22:58:59 +00001724 if ( fileio->fd_type == FD_TYPE_SOCKET )
Martin Wilck2b47fb32002-04-05 22:53:57 +00001725 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
Martin Wilck9ca42852002-04-25 22:58:59 +00001726 else
1727 {
1728 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1729 OVERLAPPED_OFFSET (lpOverlapped) + already);
1730 if ((result < 0) && (errno == ESPIPE))
1731 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1732 }
Mike McCormackf21aac02001-01-10 22:45:03 +00001733
1734 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1735 {
1736 r = STATUS_PENDING;
1737 goto async_end;
1738 }
1739
1740 /* check to see if the transfer is complete */
1741 if(result<0)
1742 {
Martin Wilck9ca42852002-04-25 22:58:59 +00001743 r = FILE_GetNtStatus ();
Mike McCormackf21aac02001-01-10 22:45:03 +00001744 goto async_end;
1745 }
1746
Mike McCormackeb3e38e2001-01-12 19:57:38 +00001747 lpOverlapped->InternalHigh += result;
Mike McCormackf21aac02001-01-10 22:45:03 +00001748
Martin Wilck2b47fb32002-04-05 22:53:57 +00001749 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
Michael McCormack1c32a462001-03-22 20:09:34 +00001750
Martin Wilck2b47fb32002-04-05 22:53:57 +00001751 if(lpOverlapped->InternalHigh < fileio->count)
Mike McCormackf21aac02001-01-10 22:45:03 +00001752 r = STATUS_PENDING;
1753 else
1754 r = STATUS_SUCCESS;
1755
1756async_end:
1757 lpOverlapped->Internal = r;
Mike McCormackf21aac02001-01-10 22:45:03 +00001758}
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001759
1760/***********************************************************************
Alexandre Julliard45342a32002-01-21 17:37:24 +00001761 * FILE_WriteFileEx
Mike McCormackf21aac02001-01-10 22:45:03 +00001762 */
Alexandre Julliard45342a32002-01-21 17:37:24 +00001763static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1764 LPOVERLAPPED overlapped,
Mike McCormack4a6b9902002-03-11 01:19:29 +00001765 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1766 HANDLE hEvent)
Mike McCormackf21aac02001-01-10 22:45:03 +00001767{
Martin Wilck2b47fb32002-04-05 22:53:57 +00001768 async_fileio *ovp;
1769 int fd;
Martin Wilck08867f72002-04-14 19:34:57 +00001770 int flags;
1771 enum fd_type type;
Mike McCormackf21aac02001-01-10 22:45:03 +00001772
Martin Wilck9ca42852002-04-25 22:58:59 +00001773 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1774 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
Mike McCormacka38e5e52001-07-08 20:29:26 +00001775
Mike McCormack91195432002-01-01 01:11:32 +00001776 if (overlapped == NULL)
Mike McCormacka38e5e52001-07-08 20:29:26 +00001777 {
1778 SetLastError(ERROR_INVALID_PARAMETER);
1779 return FALSE;
1780 }
1781
Martin Wilck08867f72002-04-14 19:34:57 +00001782 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
Martin Wilck2b47fb32002-04-05 22:53:57 +00001783 if ( fd < 0 )
Mike McCormackf21aac02001-01-10 22:45:03 +00001784 {
Martin Wilck2b47fb32002-04-05 22:53:57 +00001785 TRACE( "Couldn't get FD\n" );
Michael McCormack1c32a462001-03-22 20:09:34 +00001786 return FALSE;
Mike McCormacka38e5e52001-07-08 20:29:26 +00001787 }
Mike McCormackf21aac02001-01-10 22:45:03 +00001788
Martin Wilck2b47fb32002-04-05 22:53:57 +00001789 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
Mike McCormacka38e5e52001-07-08 20:29:26 +00001790 if(!ovp)
1791 {
1792 TRACE("HeapAlloc Failed\n");
1793 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
Martin Wilck08867f72002-04-14 19:34:57 +00001794 goto error;
Mike McCormacka38e5e52001-07-08 20:29:26 +00001795 }
Martin Wilck2b47fb32002-04-05 22:53:57 +00001796
Martin Wilckef79c38e2002-04-23 19:27:51 +00001797 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
Martin Wilck2b47fb32002-04-05 22:53:57 +00001798 ovp->async.handle = hFile;
Martin Wilckef79c38e2002-04-23 19:27:51 +00001799 ovp->async.fd = fd;
Martin Wilck2b47fb32002-04-05 22:53:57 +00001800 ovp->async.type = ASYNC_TYPE_WRITE;
1801 ovp->async.func = FILE_AsyncWriteService;
Michael McCormack1c32a462001-03-22 20:09:34 +00001802 ovp->lpOverlapped = overlapped;
Martin Wilck2b47fb32002-04-05 22:53:57 +00001803 ovp->async.event = hEvent;
Michael McCormack1c32a462001-03-22 20:09:34 +00001804 ovp->buffer = (LPVOID) buffer;
Mike McCormacke61ad3a2001-07-12 22:29:41 +00001805 ovp->count = bytesToWrite;
1806 ovp->completion_func = lpCompletionRoutine;
Martin Wilck9ca42852002-04-25 22:58:59 +00001807 ovp->fd_type = type;
Mike McCormack6f011c02001-12-20 00:07:05 +00001808
Martin Wilck2b47fb32002-04-05 22:53:57 +00001809 return !register_new_async (&ovp->async);
Martin Wilck08867f72002-04-14 19:34:57 +00001810
1811error:
1812 close (fd);
1813 return FALSE;
Mike McCormack99a5cfe2002-01-07 18:11:28 +00001814}
Michael McCormack1c32a462001-03-22 20:09:34 +00001815
Mike McCormack99a5cfe2002-01-07 18:11:28 +00001816/***********************************************************************
1817 * WriteFileEx (KERNEL32.@)
1818 */
1819BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1820 LPOVERLAPPED overlapped,
1821 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1822{
Mike McCormack99a5cfe2002-01-07 18:11:28 +00001823 overlapped->InternalHigh = 0;
1824
Mike McCormack4a6b9902002-03-11 01:19:29 +00001825 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
Mike McCormack838a3612001-07-02 18:56:01 +00001826}
Michael McCormack1c32a462001-03-22 20:09:34 +00001827
Mike McCormackf21aac02001-01-10 22:45:03 +00001828/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001829 * WriteFile (KERNEL32.@)
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001830 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001831BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001832 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1833{
Alexandre Julliard8d1550d2002-03-23 18:48:12 +00001834 int unix_handle, result, flags;
Martin Wilck88cd32b2002-01-09 20:30:51 +00001835 enum fd_type type;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001836
Mike McCormackf21aac02001-01-10 22:45:03 +00001837 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1838 bytesWritten, overlapped );
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001839
1840 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1841 if (!bytesToWrite) return TRUE;
1842
Martin Wilck88cd32b2002-01-09 20:30:51 +00001843 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
Eric Pouech0b83d4c2001-11-23 23:04:58 +00001844
Martin Wilck88cd32b2002-01-09 20:30:51 +00001845 if (flags & FD_FLAG_OVERLAPPED)
Eric Pouech0b83d4c2001-11-23 23:04:58 +00001846 {
Mike McCormack91195432002-01-01 01:11:32 +00001847 if (unix_handle == -1) return FALSE;
1848 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1849 {
1850 TRACE("Overlapped not specified or invalid event flag\n");
1851 close(unix_handle);
1852 SetLastError(ERROR_INVALID_PARAMETER);
1853 return FALSE;
1854 }
Mike McCormack99a5cfe2002-01-07 18:11:28 +00001855
Mike McCormack99a5cfe2002-01-07 18:11:28 +00001856 close(unix_handle);
Martin Wilcke0587d42002-04-17 16:46:06 +00001857 overlapped->InternalHigh = 0;
Mike McCormack99a5cfe2002-01-07 18:11:28 +00001858
Mike McCormack4a6b9902002-03-11 01:19:29 +00001859 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
Mike McCormack99a5cfe2002-01-07 18:11:28 +00001860 return FALSE;
1861
Martin Wilcke0587d42002-04-17 16:46:06 +00001862 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1863 {
1864 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1865 SetLastError ( ERROR_IO_PENDING );
1866 return FALSE;
1867 }
1868
1869 return TRUE;
Martin Wilck88cd32b2002-01-09 20:30:51 +00001870 }
Mike McCormack91195432002-01-01 01:11:32 +00001871
Martin Wilck88cd32b2002-01-09 20:30:51 +00001872 switch(type)
1873 {
Eric Pouech0b83d4c2001-11-23 23:04:58 +00001874 case FD_TYPE_CONSOLE:
1875 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1876 bytesWritten, overlapped );
1877 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1878 default:
1879 if (unix_handle == -1)
1880 return FALSE;
1881 }
Mike McCormackf21aac02001-01-10 22:45:03 +00001882
1883 /* synchronous file write */
Alexandre Julliard55443871998-12-31 15:52:06 +00001884 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001885 {
Alexandre Julliard55443871998-12-31 15:52:06 +00001886 if ((errno == EAGAIN) || (errno == EINTR)) continue;
Alexandre Julliard982a2232000-12-13 20:20:09 +00001887 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
Gerard Patel8f3c0a31999-06-27 15:26:37 +00001888 if (errno == ENOSPC)
1889 SetLastError( ERROR_DISK_FULL );
1890 else
Alexandre Julliard55443871998-12-31 15:52:06 +00001891 FILE_SetDosError();
1892 break;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001893 }
Alexandre Julliard55443871998-12-31 15:52:06 +00001894 close( unix_handle );
1895 if (result == -1) return FALSE;
1896 if (bytesWritten) *bytesWritten = result;
1897 return TRUE;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001898}
1899
Michael McCormack1c32a462001-03-22 20:09:34 +00001900
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001901/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001902 * _hread (KERNEL.349)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001903 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001904LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001905{
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001906 LONG maxlen;
1907
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001908 TRACE("%d %08lx %ld\n",
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001909 hFile, (DWORD)buffer, count );
1910
1911 /* Some programs pass a count larger than the allocated buffer */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001912 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001913 if (count > maxlen) count = maxlen;
Alexandre Julliard982a2232000-12-13 20:20:09 +00001914 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001915}
1916
1917
1918/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001919 * _lread (KERNEL.82)
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001920 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001921UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001922{
1923 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1924}
1925
1926
1927/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001928 * _lread (KERNEL32.@)
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001929 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001930UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001931{
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001932 DWORD result;
1933 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1934 return result;
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001935}
1936
1937
1938/***********************************************************************
1939 * _lread16 (KERNEL.82)
1940 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001941UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001942{
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001943 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001944}
1945
1946
1947/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001948 * _lcreat (KERNEL.83)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001949 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001950HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001951{
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00001952 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001953}
1954
1955
1956/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001957 * _lcreat (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001958 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001959HFILE WINAPI _lcreat( LPCSTR path, INT attr )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001960{
Alexandre Julliardd5240f11999-04-03 13:54:51 +00001961 /* Mask off all flags not explicitly allowed by the doc */
1962 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001963 TRACE("%s %02x\n", path, attr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001964 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
Alexandre Julliardd5240f11999-04-03 13:54:51 +00001965 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
François Gouget4b4f69a2001-01-09 20:51:19 +00001966 CREATE_ALWAYS, attr, 0 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001967}
1968
1969
1970/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001971 * SetFilePointer (KERNEL32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001972 */
Jim Aston031f4fa1999-10-23 19:00:02 +00001973DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001974 DWORD method )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001975{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001976 DWORD ret = 0xffffffff;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001977
Marcus Meissner3f1ed522001-05-14 20:09:37 +00001978 TRACE("handle %d offset %ld high %ld origin %ld\n",
1979 hFile, distance, highword?*highword:0, method );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001980
Alexandre Julliard67a74992001-02-27 02:09:16 +00001981 SERVER_START_REQ( set_file_pointer )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001982 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001983 req->handle = hFile;
1984 req->low = distance;
1985 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1986 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1987 req->whence = method;
1988 SetLastError( 0 );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001989 if (!wine_server_call_err( req ))
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001990 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001991 ret = reply->new_low;
1992 if (highword) *highword = reply->new_high;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001993 }
1994 }
1995 SERVER_END_REQ;
1996 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001997}
1998
1999
2000/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002001 * _llseek (KERNEL.84)
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00002002 *
2003 * FIXME:
2004 * Seeking before the start of the file should be allowed for _llseek16,
2005 * but cause subsequent I/O operations to fail (cf. interrupt list)
2006 *
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002007 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002008LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002009{
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00002010 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002011}
2012
2013
2014/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002015 * _llseek (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002016 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002017LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002018{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002019 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002020}
2021
2022
2023/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002024 * _lopen (KERNEL.85)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002025 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002026HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002027{
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00002028 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002029}
2030
2031
2032/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002033 * _lopen (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002034 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002035HFILE WINAPI _lopen( LPCSTR path, INT mode )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002036{
Alexandre Julliard05625391999-01-03 11:55:56 +00002037 DWORD access, sharing;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002038
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002039 TRACE("('%s',%04x)\n", path, mode );
Alexandre Julliard05625391999-01-03 11:55:56 +00002040 FILE_ConvertOFMode( mode, &access, &sharing );
François Gouget4b4f69a2001-01-09 20:51:19 +00002041 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002042}
2043
2044
2045/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002046 * _lwrite (KERNEL.86)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002047 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002048UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002049{
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00002050 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00002051}
2052
2053/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002054 * _lwrite (KERNEL32.@)
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00002055 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002056UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00002057{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002058 return (UINT)_hwrite( hFile, buffer, (LONG)count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002059}
2060
2061
2062/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002063 * _hread16 (KERNEL.349)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002064 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002065LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002066{
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00002067 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002068}
2069
2070
2071/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002072 * _hread (KERNEL32.@)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002073 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002074LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002075{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002076 return _lread( hFile, buffer, count );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002077}
2078
2079
2080/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002081 * _hwrite (KERNEL.350)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002082 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002083LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002084{
Alexandre Julliard5ce902b2000-11-27 21:59:08 +00002085 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002086}
2087
2088
2089/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002090 * _hwrite (KERNEL32.@)
Alexandre Julliarda11d7b11998-03-01 20:05:02 +00002091 *
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00002092 * experimentation yields that _lwrite:
Alexandre Julliarda11d7b11998-03-01 20:05:02 +00002093 * o truncates the file at the current position with
2094 * a 0 len write
2095 * o returns 0 on a 0 length write
2096 * o works with console handles
2097 *
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002098 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002099LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002100{
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00002101 DWORD result;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002102
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002103 TRACE("%d %p %ld\n", handle, buffer, count );
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00002104
2105 if (!count)
2106 {
2107 /* Expand or truncate at current position */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002108 if (!SetEndOfFile( handle )) return HFILE_ERROR;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00002109 return 0;
2110 }
2111 if (!WriteFile( handle, buffer, count, &result, NULL ))
Alexandre Julliarda3960291999-02-26 11:11:13 +00002112 return HFILE_ERROR;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00002113 return result;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002114}
2115
2116
2117/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002118 * SetHandleCount (KERNEL.199)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002119 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002120UINT16 WINAPI SetHandleCount16( UINT16 count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002121{
Alexandre Julliard7d5bc5c2001-01-15 20:09:09 +00002122 return SetHandleCount( count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00002123}
Alexandre Julliard339eefc1996-06-23 14:56:20 +00002124
2125
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002126/*************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002127 * SetHandleCount (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002128 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002129UINT WINAPI SetHandleCount( UINT count )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002130{
Francois Gouget6d77d3a2000-03-25 21:44:35 +00002131 return min( 256, count );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002132}
2133
2134
Alexandre Julliard339eefc1996-06-23 14:56:20 +00002135/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002136 * FlushFileBuffers (KERNEL32.@)
Alexandre Julliard339eefc1996-06-23 14:56:20 +00002137 */
Jim Aston031f4fa1999-10-23 19:00:02 +00002138BOOL WINAPI FlushFileBuffers( HANDLE hFile )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00002139{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002140 BOOL ret;
Alexandre Julliard67a74992001-02-27 02:09:16 +00002141 SERVER_START_REQ( flush_file )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002142 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002143 req->handle = hFile;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00002144 ret = !wine_server_call_err( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002145 }
2146 SERVER_END_REQ;
2147 return ret;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002148}
2149
2150
2151/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002152 * SetEndOfFile (KERNEL32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002153 */
Jim Aston031f4fa1999-10-23 19:00:02 +00002154BOOL WINAPI SetEndOfFile( HANDLE hFile )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002155{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002156 BOOL ret;
Alexandre Julliard67a74992001-02-27 02:09:16 +00002157 SERVER_START_REQ( truncate_file )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002158 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002159 req->handle = hFile;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00002160 ret = !wine_server_call_err( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002161 }
2162 SERVER_END_REQ;
2163 return ret;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00002164}
2165
2166
2167/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002168 * DeleteFile (KERNEL.146)
Alexandre Julliard3051b641996-07-05 17:14:13 +00002169 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002170BOOL16 WINAPI DeleteFile16( LPCSTR path )
Alexandre Julliard3051b641996-07-05 17:14:13 +00002171{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002172 return DeleteFileA( path );
Alexandre Julliard3051b641996-07-05 17:14:13 +00002173}
2174
2175
2176/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002177 * DeleteFileA (KERNEL32.@)
Alexandre Julliard3051b641996-07-05 17:14:13 +00002178 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002179BOOL WINAPI DeleteFileA( LPCSTR path )
Alexandre Julliard3051b641996-07-05 17:14:13 +00002180{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002181 DOS_FULL_NAME full_name;
Alexandre Julliard3051b641996-07-05 17:14:13 +00002182
Uwe Bonnesef3d0222001-10-02 17:40:33 +00002183 if (!path)
2184 {
2185 SetLastError(ERROR_INVALID_PARAMETER);
2186 return FALSE;
2187 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002188 TRACE("'%s'\n", path );
Alexandre Julliard3051b641996-07-05 17:14:13 +00002189
Alexandre Julliard638f1691999-01-17 16:32:32 +00002190 if (!*path)
2191 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002192 ERR("Empty path passed\n");
Alexandre Julliard638f1691999-01-17 16:32:32 +00002193 return FALSE;
2194 }
Alexandre Julliard829fe321998-07-26 14:27:39 +00002195 if (DOSFS_GetDevice( path ))
Alexandre Julliard3051b641996-07-05 17:14:13 +00002196 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002197 WARN("cannot remove DOS device '%s'!\n", path);
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00002198 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliard3051b641996-07-05 17:14:13 +00002199 return FALSE;
2200 }
2201
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002202 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2203 if (unlink( full_name.long_name ) == -1)
Alexandre Julliard3051b641996-07-05 17:14:13 +00002204 {
2205 FILE_SetDosError();
2206 return FALSE;
2207 }
2208 return TRUE;
2209}
2210
2211
2212/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002213 * DeleteFileW (KERNEL32.@)
Alexandre Julliard3051b641996-07-05 17:14:13 +00002214 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002215BOOL WINAPI DeleteFileW( LPCWSTR path )
Alexandre Julliard3051b641996-07-05 17:14:13 +00002216{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00002217 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002218 BOOL ret = DeleteFileA( xpath );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00002219 HeapFree( GetProcessHeap(), 0, xpath );
Alexandre Julliard3051b641996-07-05 17:14:13 +00002220 return ret;
2221}
2222
2223
2224/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002225 * GetFileType (KERNEL32.@)
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00002226 */
Jim Aston031f4fa1999-10-23 19:00:02 +00002227DWORD WINAPI GetFileType( HANDLE hFile )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00002228{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002229 DWORD ret = FILE_TYPE_UNKNOWN;
Alexandre Julliard67a74992001-02-27 02:09:16 +00002230 SERVER_START_REQ( get_file_info )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002231 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002232 req->handle = hFile;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00002233 if (!wine_server_call_err( req )) ret = reply->type;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002234 }
2235 SERVER_END_REQ;
2236 return ret;
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00002237}
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002238
2239
Bernhard Rosenkraenzer5dda1f72001-07-23 18:09:41 +00002240/* check if a file name is for an executable file (.exe or .com) */
2241inline static BOOL is_executable( const char *name )
2242{
2243 int len = strlen(name);
2244
2245 if (len < 4) return FALSE;
2246 return (!strcasecmp( name + len - 4, ".exe" ) ||
2247 !strcasecmp( name + len - 4, ".com" ));
2248}
2249
2250
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002251/***********************************************************************
2252 * FILE_AddBootRenameEntry
2253 *
2254 * Adds an entry to the registry that is loaded when windows boots and
2255 * checks if there are some files to be removed or renamed/moved.
2256 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2257 * non-NULL then the file is moved, otherwise it is deleted. The
2258 * entry of the registrykey is always appended with two zero
2259 * terminated strings. If <fn2> is NULL then the second entry is
2260 * simply a single 0-byte. Otherwise the second filename goes
2261 * there. The entries are prepended with \??\ before the path and the
2262 * second filename gets also a '!' as the first character if
2263 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2264 * 0-byte follows to indicate the end of the strings.
2265 * i.e.:
2266 * \??\D:\test\file1[0]
2267 * !\??\D:\test\file1_renamed[0]
2268 * \??\D:\Test|delete[0]
2269 * [0] <- file is to be deleted, second string empty
2270 * \??\D:\test\file2[0]
2271 * !\??\D:\test\file2_renamed[0]
2272 * [0] <- indicates end of strings
2273 *
2274 * or:
2275 * \??\D:\test\file1[0]
2276 * !\??\D:\test\file1_renamed[0]
2277 * \??\D:\Test|delete[0]
2278 * [0] <- file is to be deleted, second string empty
2279 * [0] <- indicates end of strings
2280 *
2281 */
2282static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2283{
2284 static const char PreString[] = "\\??\\";
2285 static const char ValueName[] = "PendingFileRenameOperations";
2286
2287 BOOL rc = FALSE;
2288 HKEY Reboot = 0;
2289 DWORD Type, len1, len2, l;
2290 DWORD DataSize = 0;
2291 BYTE *Buffer = NULL;
2292
2293 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2294 &Reboot) != ERROR_SUCCESS)
2295 {
2296 WARN("Error creating key for reboot managment [%s]\n",
2297 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2298 return FALSE;
2299 }
2300
2301 l = strlen(PreString);
2302 len1 = strlen(fn1) + l + 1;
2303 if (fn2)
2304 {
2305 len2 = strlen(fn2) + l + 1;
2306 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2307 }
2308 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2309
2310 /* First we check if the key exists and if so how many bytes it already contains. */
2311 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2312 {
2313 if (Type != REG_MULTI_SZ) goto Quit;
2314 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2315 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2316 goto Quit;
2317 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2318 }
2319 else
2320 {
2321 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2322 DataSize = 0;
2323 }
2324 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2325 DataSize += len1;
2326 if (fn2)
2327 {
2328 sprintf( Buffer + DataSize, "%s%s%s",
2329 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2330 DataSize += len2;
2331 }
2332 else Buffer[DataSize++] = 0;
2333
2334 Buffer[DataSize++] = 0; /* add final null */
2335 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2336
2337 Quit:
2338 if (Reboot) RegCloseKey(Reboot);
2339 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2340 return(rc);
2341}
2342
2343
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002344/**************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00002345 * MoveFileExA (KERNEL32.@)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002346 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002347BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002348{
2349 DOS_FULL_NAME full_name1, full_name2;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002350
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002351 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002352
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002353 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2354 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2355 to be really compatible. Most programs wont have any problems though. In case
2356 you encounter one, this is what you should return here. I don't know what's up
2357 with NT 3.5. Is this function available there or not?
2358 Does anybody really care about 3.5? :)
2359 */
2360
2361 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2362 if the source file has to be deleted.
2363 */
Ove Kaaven72f40442001-10-01 20:52:00 +00002364 if (!fn1) {
2365 SetLastError(ERROR_INVALID_PARAMETER);
2366 return FALSE;
2367 }
2368
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002369 /* This function has to be run through in order to process the name properly.
2370 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2371 that is the behaviour on NT 4.0. The operation accepts the filenames as
2372 they are given but it can't reply with a reasonable returncode. Success
2373 means in that case success for entering the values into the registry.
2374 */
2375 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2376 {
2377 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2378 return FALSE;
2379 }
Alexandre Julliard86a75531999-11-21 02:11:48 +00002380
2381 if (fn2) /* !fn2 means delete fn1 */
2382 {
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002383 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
Alexandre Julliard86a75531999-11-21 02:11:48 +00002384 {
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002385 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
Alexandre Julliard86a75531999-11-21 02:11:48 +00002386 {
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002387 /* target exists, check if we may overwrite */
2388 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2389 {
2390 /* FIXME: Use right error code */
2391 SetLastError( ERROR_ACCESS_DENIED );
2392 return FALSE;
2393 }
Alexandre Julliard86a75531999-11-21 02:11:48 +00002394 }
2395 }
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002396 else
2397 {
2398 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2399 {
2400 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2401 return FALSE;
2402 }
2403 }
Alexandre Julliard86a75531999-11-21 02:11:48 +00002404
2405 /* Source name and target path are valid */
2406
2407 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2408 {
2409 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2410 Perhaps we should queue these command and execute it
2411 when exiting... What about using on_exit(2)
2412 */
2413 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002414 fn1, fn2);
2415 return FILE_AddBootRenameEntry( fn1, fn2, flag );
Alexandre Julliard86a75531999-11-21 02:11:48 +00002416 }
2417
2418 if (full_name1.drive != full_name2.drive)
2419 {
2420 /* use copy, if allowed */
2421 if (!(flag & MOVEFILE_COPY_ALLOWED))
2422 {
2423 /* FIXME: Use right error code */
2424 SetLastError( ERROR_FILE_EXISTS );
2425 return FALSE;
2426 }
2427 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2428 }
2429 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2430 {
2431 FILE_SetDosError();
2432 return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002433 }
Bernhard Rosenkraenzer5dda1f72001-07-23 18:09:41 +00002434 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2435 {
2436 struct stat fstat;
2437 if (stat( full_name2.long_name, &fstat ) != -1)
2438 {
2439 if (is_executable( full_name2.long_name ))
2440 /* set executable bit where read bit is set */
2441 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2442 else
2443 fstat.st_mode &= ~0111;
2444 chmod( full_name2.long_name, fstat.st_mode );
2445 }
2446 }
Alexandre Julliard86a75531999-11-21 02:11:48 +00002447 return TRUE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002448 }
2449 else /* fn2 == NULL means delete source */
Alexandre Julliard86a75531999-11-21 02:11:48 +00002450 {
2451 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2452 {
2453 if (flag & MOVEFILE_COPY_ALLOWED) {
2454 WARN("Illegal flag\n");
2455 SetLastError( ERROR_GEN_FAILURE );
2456 return FALSE;
2457 }
2458 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2459 Perhaps we should queue these command and execute it
2460 when exiting... What about using on_exit(2)
2461 */
Gerhard W. Gruber814a3fa2002-02-22 21:30:22 +00002462 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2463 return FILE_AddBootRenameEntry( fn1, NULL, flag );
Alexandre Julliard86a75531999-11-21 02:11:48 +00002464 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002465
Alexandre Julliard86a75531999-11-21 02:11:48 +00002466 if (unlink( full_name1.long_name ) == -1)
2467 {
2468 FILE_SetDosError();
2469 return FALSE;
2470 }
2471 return TRUE; /* successfully deleted */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002472 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002473}
2474
2475/**************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00002476 * MoveFileExW (KERNEL32.@)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002477 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002478BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002479{
2480 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2481 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002482 BOOL res = MoveFileExA( afn1, afn2, flag );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002483 HeapFree( GetProcessHeap(), 0, afn1 );
2484 HeapFree( GetProcessHeap(), 0, afn2 );
2485 return res;
2486}
2487
2488
2489/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002490 * MoveFileA (KERNEL32.@)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002491 *
2492 * Move file or directory
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002493 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002494BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002495{
2496 DOS_FULL_NAME full_name1, full_name2;
Marcus Meissner6bb990f2001-05-29 20:55:21 +00002497 struct stat fstat;
Marcus Meissner3f1ed522001-05-14 20:09:37 +00002498
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002499 TRACE("(%s,%s)\n", fn1, fn2 );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002500
2501 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
Marcus Meissner242d23e2000-08-21 03:18:32 +00002502 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
Bernhard Rosenkraenzer5dda1f72001-07-23 18:09:41 +00002503 /* The new name must not already exist */
Marcus Meissner242d23e2000-08-21 03:18:32 +00002504 SetLastError(ERROR_ALREADY_EXISTS);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002505 return FALSE;
Marcus Meissner242d23e2000-08-21 03:18:32 +00002506 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002507 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002508
2509 if (full_name1.drive == full_name2.drive) /* move */
Bernhard Rosenkraenzer5dda1f72001-07-23 18:09:41 +00002510 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2511
2512 /* copy */
2513 if (stat( full_name1.long_name, &fstat ))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002514 {
Bernhard Rosenkraenzer5dda1f72001-07-23 18:09:41 +00002515 WARN("Invalid source file %s\n",
2516 full_name1.long_name);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002517 FILE_SetDosError();
2518 return FALSE;
2519 }
Bernhard Rosenkraenzer5dda1f72001-07-23 18:09:41 +00002520 if (S_ISDIR(fstat.st_mode)) {
2521 /* No Move for directories across file systems */
2522 /* FIXME: Use right error code */
2523 SetLastError( ERROR_GEN_FAILURE );
2524 return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002525 }
Bernhard Rosenkraenzer5dda1f72001-07-23 18:09:41 +00002526 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002527}
2528
2529
2530/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002531 * MoveFileW (KERNEL32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002532 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002533BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002534{
2535 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2536 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002537 BOOL res = MoveFileA( afn1, afn2 );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002538 HeapFree( GetProcessHeap(), 0, afn1 );
2539 HeapFree( GetProcessHeap(), 0, afn2 );
2540 return res;
2541}
2542
2543
2544/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002545 * CopyFileA (KERNEL32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002546 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002547BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002548{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002549 HFILE h1, h2;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002550 BY_HANDLE_FILE_INFORMATION info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002551 UINT count;
2552 BOOL ret = FALSE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002553 int mode;
2554 char buffer[2048];
2555
Alexandre Julliarda3960291999-02-26 11:11:13 +00002556 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002557 if (!GetFileInformationByHandle( h1, &info ))
2558 {
2559 CloseHandle( h1 );
2560 return FALSE;
2561 }
2562 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002563 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
Alexandre Julliard05625391999-01-03 11:55:56 +00002564 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
François Gouget4b4f69a2001-01-09 20:51:19 +00002565 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002566 {
2567 CloseHandle( h1 );
2568 return FALSE;
2569 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00002570 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002571 {
2572 char *p = buffer;
2573 while (count > 0)
2574 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002575 INT res = _lwrite( h2, p, count );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002576 if (res <= 0) goto done;
2577 p += res;
2578 count -= res;
2579 }
2580 }
2581 ret = TRUE;
2582done:
2583 CloseHandle( h1 );
2584 CloseHandle( h2 );
2585 return ret;
2586}
2587
2588
2589/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002590 * CopyFileW (KERNEL32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002591 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002592BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002593{
2594 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2595 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002596 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002597 HeapFree( GetProcessHeap(), 0, sourceA );
2598 HeapFree( GetProcessHeap(), 0, destA );
2599 return ret;
2600}
2601
2602
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002603/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002604 * CopyFileExA (KERNEL32.@)
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002605 *
2606 * This implementation ignores most of the extra parameters passed-in into
2607 * the "ex" version of the method and calls the CopyFile method.
2608 * It will have to be fixed eventually.
2609 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002610BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002611 LPCSTR destFilename,
2612 LPPROGRESS_ROUTINE progressRoutine,
2613 LPVOID appData,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002614 LPBOOL cancelFlagPointer,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002615 DWORD copyFlags)
2616{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002617 BOOL failIfExists = FALSE;
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002618
2619 /*
2620 * Interpret the only flag that CopyFile can interpret.
2621 */
2622 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2623 {
2624 failIfExists = TRUE;
2625 }
2626
Alexandre Julliarda3960291999-02-26 11:11:13 +00002627 return CopyFileA(sourceFilename, destFilename, failIfExists);
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002628}
2629
2630/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002631 * CopyFileExW (KERNEL32.@)
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002632 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002633BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002634 LPCWSTR destFilename,
2635 LPPROGRESS_ROUTINE progressRoutine,
2636 LPVOID appData,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002637 LPBOOL cancelFlagPointer,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002638 DWORD copyFlags)
2639{
2640 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2641 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2642
Alexandre Julliarda3960291999-02-26 11:11:13 +00002643 BOOL ret = CopyFileExA(sourceA,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00002644 destA,
2645 progressRoutine,
2646 appData,
2647 cancelFlagPointer,
2648 copyFlags);
2649
2650 HeapFree( GetProcessHeap(), 0, sourceA );
2651 HeapFree( GetProcessHeap(), 0, destA );
2652
2653 return ret;
2654}
2655
2656
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002657/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002658 * SetFileTime (KERNEL32.@)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002659 */
Jim Aston031f4fa1999-10-23 19:00:02 +00002660BOOL WINAPI SetFileTime( HANDLE hFile,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002661 const FILETIME *lpCreationTime,
2662 const FILETIME *lpLastAccessTime,
2663 const FILETIME *lpLastWriteTime )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002664{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002665 BOOL ret;
Alexandre Julliard67a74992001-02-27 02:09:16 +00002666 SERVER_START_REQ( set_file_time )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002667 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002668 req->handle = hFile;
2669 if (lpLastAccessTime)
Alexandre Julliard27952ef2000-10-13 20:26:03 +00002670 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002671 else
2672 req->access_time = 0; /* FIXME */
2673 if (lpLastWriteTime)
Alexandre Julliard27952ef2000-10-13 20:26:03 +00002674 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002675 else
2676 req->write_time = 0; /* FIXME */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00002677 ret = !wine_server_call_err( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002678 }
2679 SERVER_END_REQ;
2680 return ret;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00002681}
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002682
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002683
2684/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002685 * LockFile (KERNEL32.@)
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002686 */
Jim Aston031f4fa1999-10-23 19:00:02 +00002687BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002688 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2689{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002690 BOOL ret;
Alexandre Julliard67a74992001-02-27 02:09:16 +00002691 SERVER_START_REQ( lock_file )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002692 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002693 req->handle = hFile;
2694 req->offset_low = dwFileOffsetLow;
2695 req->offset_high = dwFileOffsetHigh;
2696 req->count_low = nNumberOfBytesToLockLow;
2697 req->count_high = nNumberOfBytesToLockHigh;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00002698 ret = !wine_server_call_err( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002699 }
2700 SERVER_END_REQ;
2701 return ret;
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002702}
2703
James Jurane8df90b1999-06-05 08:57:37 +00002704/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002705 * LockFileEx [KERNEL32.@]
James Jurane8df90b1999-06-05 08:57:37 +00002706 *
2707 * Locks a byte range within an open file for shared or exclusive access.
2708 *
2709 * RETURNS
2710 * success: TRUE
2711 * failure: FALSE
James Jurane8df90b1999-06-05 08:57:37 +00002712 *
Andreas Mohrc9cf70d2001-01-26 20:40:50 +00002713 * NOTES
James Jurane8df90b1999-06-05 08:57:37 +00002714 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2715 */
2716BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2717 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2718 LPOVERLAPPED pOverlapped )
2719{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002720 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
James Jurane8df90b1999-06-05 08:57:37 +00002721 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2722 pOverlapped);
2723 if (reserved == 0)
2724 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2725 else
2726 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002727 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
James Jurane8df90b1999-06-05 08:57:37 +00002728 SetLastError(ERROR_INVALID_PARAMETER);
2729 }
2730
2731 return FALSE;
2732}
2733
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002734
2735/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002736 * UnlockFile (KERNEL32.@)
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002737 */
Jim Aston031f4fa1999-10-23 19:00:02 +00002738BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002739 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2740{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002741 BOOL ret;
Alexandre Julliard67a74992001-02-27 02:09:16 +00002742 SERVER_START_REQ( unlock_file )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002743 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002744 req->handle = hFile;
2745 req->offset_low = dwFileOffsetLow;
2746 req->offset_high = dwFileOffsetHigh;
2747 req->count_low = nNumberOfBytesToUnlockLow;
2748 req->count_high = nNumberOfBytesToUnlockHigh;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00002749 ret = !wine_server_call_err( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002750 }
2751 SERVER_END_REQ;
2752 return ret;
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002753}
2754
2755
Andreas Mohre00114c1999-07-03 11:56:07 +00002756/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002757 * UnlockFileEx (KERNEL32.@)
Andreas Mohre00114c1999-07-03 11:56:07 +00002758 */
2759BOOL WINAPI UnlockFileEx(
2760 HFILE hFile,
2761 DWORD dwReserved,
2762 DWORD nNumberOfBytesToUnlockLow,
2763 DWORD nNumberOfBytesToUnlockHigh,
2764 LPOVERLAPPED lpOverlapped
2765)
2766{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002767 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
Andreas Mohre00114c1999-07-03 11:56:07 +00002768 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2769 lpOverlapped);
2770 if (dwReserved == 0)
2771 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2772 else
2773 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002774 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
Andreas Mohre00114c1999-07-03 11:56:07 +00002775 SetLastError(ERROR_INVALID_PARAMETER);
2776 }
2777
2778 return FALSE;
2779}
2780
2781
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002782#if 0
2783
2784struct DOS_FILE_LOCK {
2785 struct DOS_FILE_LOCK * next;
2786 DWORD base;
2787 DWORD len;
2788 DWORD processId;
2789 FILE_OBJECT * dos_file;
2790/* char * unix_name;*/
2791};
2792
2793typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2794
2795static DOS_FILE_LOCK *locks = NULL;
2796static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2797
2798
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002799/* Locks need to be mirrored because unix file locking is based
2800 * on the pid. Inside of wine there can be multiple WINE processes
2801 * that share the same unix pid.
2802 * Read's and writes should check these locks also - not sure
2803 * how critical that is at this point (FIXME).
2804 */
2805
Alexandre Julliarda3960291999-02-26 11:11:13 +00002806static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002807{
2808 DOS_FILE_LOCK *curr;
2809 DWORD processId;
2810
2811 processId = GetCurrentProcessId();
2812
2813 /* check if lock overlaps a current lock for the same file */
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002814#if 0
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002815 for (curr = locks; curr; curr = curr->next) {
2816 if (strcmp(curr->unix_name, file->unix_name) == 0) {
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00002817 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2818 return TRUE;/* region is identic */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002819 if ((f->l_start < (curr->base + curr->len)) &&
2820 ((f->l_start + f->l_len) > curr->base)) {
2821 /* region overlaps */
2822 return FALSE;
2823 }
2824 }
2825 }
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002826#endif
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002827
Alexandre Julliard90476d62000-02-16 22:47:24 +00002828 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002829 curr->processId = GetCurrentProcessId();
2830 curr->base = f->l_start;
2831 curr->len = f->l_len;
Alexandre Julliard90476d62000-02-16 22:47:24 +00002832/* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002833 curr->next = locks;
2834 curr->dos_file = file;
2835 locks = curr;
2836 return TRUE;
2837}
2838
2839static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2840{
2841 DWORD processId;
2842 DOS_FILE_LOCK **curr;
2843 DOS_FILE_LOCK *rem;
2844
2845 processId = GetCurrentProcessId();
2846 curr = &locks;
2847 while (*curr) {
2848 if ((*curr)->dos_file == file) {
2849 rem = *curr;
2850 *curr = (*curr)->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +00002851/* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2852 HeapFree( GetProcessHeap(), 0, rem );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002853 }
2854 else
2855 curr = &(*curr)->next;
2856 }
2857}
2858
Alexandre Julliarda3960291999-02-26 11:11:13 +00002859static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002860{
2861 DWORD processId;
2862 DOS_FILE_LOCK **curr;
2863 DOS_FILE_LOCK *rem;
2864
2865 processId = GetCurrentProcessId();
2866 for (curr = &locks; *curr; curr = &(*curr)->next) {
2867 if ((*curr)->processId == processId &&
2868 (*curr)->dos_file == file &&
2869 (*curr)->base == f->l_start &&
2870 (*curr)->len == f->l_len) {
2871 /* this is the same lock */
2872 rem = *curr;
2873 *curr = (*curr)->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +00002874/* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2875 HeapFree( GetProcessHeap(), 0, rem );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002876 return TRUE;
2877 }
2878 }
2879 /* no matching lock found */
2880 return FALSE;
2881}
2882
2883
2884/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002885 * LockFile (KERNEL32.@)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002886 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002887BOOL WINAPI LockFile(
2888 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002889 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2890{
2891 struct flock f;
2892 FILE_OBJECT *file;
2893
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002894 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002895 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2896 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2897
2898 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002899 FIXME("Unimplemented bytes > 32bits\n");
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002900 return FALSE;
2901 }
2902
2903 f.l_start = dwFileOffsetLow;
2904 f.l_len = nNumberOfBytesToLockLow;
2905 f.l_whence = SEEK_SET;
2906 f.l_pid = 0;
2907 f.l_type = F_WRLCK;
2908
Alexandre Julliard338e7571998-12-27 15:28:54 +00002909 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002910
2911 /* shadow locks internally */
2912 if (!DOS_AddLock(file, &f)) {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00002913 SetLastError( ERROR_LOCK_VIOLATION );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002914 return FALSE;
2915 }
2916
2917 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2918#ifdef USE_UNIX_LOCKS
2919 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2920 if (errno == EACCES || errno == EAGAIN) {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00002921 SetLastError( ERROR_LOCK_VIOLATION );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002922 }
2923 else {
2924 FILE_SetDosError();
2925 }
2926 /* remove our internal copy of the lock */
2927 DOS_RemoveLock(file, &f);
2928 return FALSE;
2929 }
2930#endif
2931 return TRUE;
2932}
2933
2934
2935/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002936 * UnlockFile (KERNEL32.@)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002937 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002938BOOL WINAPI UnlockFile(
2939 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002940 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2941{
2942 FILE_OBJECT *file;
2943 struct flock f;
2944
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002945 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002946 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2947 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2948
2949 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002950 WARN("Unimplemented bytes > 32bits\n");
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002951 return FALSE;
2952 }
2953
2954 f.l_start = dwFileOffsetLow;
2955 f.l_len = nNumberOfBytesToUnlockLow;
2956 f.l_whence = SEEK_SET;
2957 f.l_pid = 0;
2958 f.l_type = F_UNLCK;
2959
Alexandre Julliard338e7571998-12-27 15:28:54 +00002960 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002961
2962 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2963
2964 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2965#ifdef USE_UNIX_LOCKS
2966 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2967 FILE_SetDosError();
2968 return FALSE;
2969 }
2970#endif
2971 return TRUE;
2972}
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002973#endif
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002974
Alexandre Julliarda845b881998-06-01 10:44:35 +00002975/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002976 * GetFileAttributesExA [KERNEL32.@]
Alexandre Julliarda845b881998-06-01 10:44:35 +00002977 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002978BOOL WINAPI GetFileAttributesExA(
Alexandre Julliarda845b881998-06-01 10:44:35 +00002979 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2980 LPVOID lpFileInformation)
2981{
2982 DOS_FULL_NAME full_name;
2983 BY_HANDLE_FILE_INFORMATION info;
2984
2985 if (lpFileName == NULL) return FALSE;
2986 if (lpFileInformation == NULL) return FALSE;
2987
2988 if (fInfoLevelId == GetFileExInfoStandard) {
2989 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2990 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2991 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2992 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2993
2994 lpFad->dwFileAttributes = info.dwFileAttributes;
2995 lpFad->ftCreationTime = info.ftCreationTime;
2996 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2997 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2998 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2999 lpFad->nFileSizeLow = info.nFileSizeLow;
3000 }
3001 else {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00003002 FIXME("invalid info level %d!\n", fInfoLevelId);
Alexandre Julliarda845b881998-06-01 10:44:35 +00003003 return FALSE;
3004 }
3005
3006 return TRUE;
3007}
3008
3009
3010/**************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003011 * GetFileAttributesExW [KERNEL32.@]
Alexandre Julliarda845b881998-06-01 10:44:35 +00003012 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003013BOOL WINAPI GetFileAttributesExW(
Alexandre Julliarda845b881998-06-01 10:44:35 +00003014 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3015 LPVOID lpFileInformation)
3016{
3017 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003018 BOOL res =
3019 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
Alexandre Julliarda845b881998-06-01 10:44:35 +00003020 HeapFree( GetProcessHeap(), 0, nameA );
3021 return res;
3022}