blob: 2f9bc307f9ed25cae971451d7e04032140968641 [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 *
7 * TODO:
Andreas Mohr20cd9352000-09-12 23:40:40 +00008 * Fix the CopyFileEx methods to implement the "extended" functionality.
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00009 * Right now, they simply call the CopyFile method.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000010 */
11
Howard Abrams13277481999-07-10 13:16:29 +000012#include "config.h"
13
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000014#include <assert.h>
Alexandre Julliardd90840e1996-06-11 16:02:08 +000015#include <ctype.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000016#include <errno.h>
17#include <fcntl.h>
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +000018#include <stdlib.h>
Alexandre Julliard383da682000-02-10 22:15:21 +000019#include <stdio.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000020#include <string.h>
Howard Abrams13277481999-07-10 13:16:29 +000021#ifdef HAVE_SYS_ERRNO_H
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000022#include <sys/errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000023#endif
Alexandre Julliard01d63461997-01-20 19:43:45 +000024#include <sys/types.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000025#include <sys/stat.h>
Howard Abrams13277481999-07-10 13:16:29 +000026#ifdef HAVE_SYS_MMAN_H
Alexandre Julliard21979011997-03-05 08:22:35 +000027#include <sys/mman.h>
Howard Abrams13277481999-07-10 13:16:29 +000028#endif
Marcus Meissner7d123bf1998-12-11 09:13:29 +000029#include <sys/time.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000030#include <time.h>
31#include <unistd.h>
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +000032#include <utime.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000033
Alexandre Julliard8bbf8181996-09-13 16:50:47 +000034#include "winerror.h"
Marcus Meissner317af321999-02-17 13:51:06 +000035#include "windef.h"
36#include "winbase.h"
37#include "wine/winbase16.h"
38#include "wine/winestring.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000039#include "drive.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000040#include "file.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000041#include "global.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000042#include "heap.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000043#include "msdos.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000044#include "ldt.h"
45#include "task.h"
Marcus Meissner6b5a8111999-01-30 13:06:00 +000046#include "wincon.h"
Alexandre Julliard359f497e1999-07-04 16:02:24 +000047#include "debugtools.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000048
Alexandre Julliard338e7571998-12-27 15:28:54 +000049#include "server.h"
50
Alexandre Julliard383da682000-02-10 22:15:21 +000051DEFAULT_DEBUG_CHANNEL(file);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000052
Alexandre Julliard21979011997-03-05 08:22:35 +000053#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
54#define MAP_ANON MAP_ANONYMOUS
55#endif
Alexandre Julliard0c126c71996-02-18 18:44:41 +000056
Alexandre Julliard8da12c41999-01-17 16:55:11 +000057/* Size of per-process table of DOS handles */
58#define DOS_TABLE_SIZE 256
Alexandre Julliard0c126c71996-02-18 18:44:41 +000059
Alexandre Julliard231674d2000-08-09 22:30:18 +000060static HANDLE dos_handles[DOS_TABLE_SIZE];
61
Alexandre Julliarda11d7b11998-03-01 20:05:02 +000062
Alexandre Julliard0c126c71996-02-18 18:44:41 +000063/***********************************************************************
Alexandre Julliard05625391999-01-03 11:55:56 +000064 * FILE_ConvertOFMode
Uwe Bonnese6b5e381998-10-18 14:48:31 +000065 *
Alexandre Julliard05625391999-01-03 11:55:56 +000066 * Convert OF_* mode into flags for CreateFile.
Uwe Bonnese6b5e381998-10-18 14:48:31 +000067 */
Alexandre Julliarda3960291999-02-26 11:11:13 +000068static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
Uwe Bonnese6b5e381998-10-18 14:48:31 +000069{
Alexandre Julliard05625391999-01-03 11:55:56 +000070 switch(mode & 0x03)
71 {
72 case OF_READ: *access = GENERIC_READ; break;
73 case OF_WRITE: *access = GENERIC_WRITE; break;
74 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
75 default: *access = 0; break;
76 }
77 switch(mode & 0x70)
78 {
79 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
80 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
81 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
82 case OF_SHARE_DENY_NONE:
83 case OF_SHARE_COMPAT:
84 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
85 }
Uwe Bonnese6b5e381998-10-18 14:48:31 +000086}
87
Uwe Bonnese6b5e381998-10-18 14:48:31 +000088
Alexandre Julliard05625391999-01-03 11:55:56 +000089#if 0
Uwe Bonnese6b5e381998-10-18 14:48:31 +000090/***********************************************************************
91 * FILE_ShareDeny
92 *
93 * PARAMS
94 * oldmode[I] mode how file was first opened
95 * mode[I] mode how the file should get opened
96 * RETURNS
97 * TRUE: deny open
98 * FALSE: allow open
99 *
100 * Look what we have to do with the given SHARE modes
101 *
102 * Ralph Brown's interrupt list gives following explication, I guess
103 * the same holds for Windows, DENY ALL should be OF_SHARE_COMPAT
104 *
105 * FIXME: Validate this function
106========from Ralph Brown's list =========
107(Table 0750)
108Values of DOS file sharing behavior:
109 | Second and subsequent Opens
110 First |Compat Deny Deny Deny Deny
111 Open | All Write Read None
112 |R W RW R W RW R W RW R W RW R W RW
113 - - - - -| - - - - - - - - - - - - - - - - -
114 Compat R |Y Y Y N N N 1 N N N N N 1 N N
115 W |Y Y Y N N N N N N N N N N N N
116 RW|Y Y Y N N N N N N N N N N N N
117 - - - - -|
118 Deny R |C C C N N N N N N N N N N N N
119 All W |C C C N N N N N N N N N N N N
120 RW|C C C N N N N N N N N N N N N
121 - - - - -|
122 Deny R |2 C C N N N Y N N N N N Y N N
123 Write W |C C C N N N N N N Y N N Y N N
124 RW|C C C N N N N N N N N N Y N N
125 - - - - -|
126 Deny R |C C C N N N N Y N N N N N Y N
127 Read W |C C C N N N N N N N Y N N Y N
128 RW|C C C N N N N N N N N N N Y N
129 - - - - -|
130 Deny R |2 C C N N N Y Y Y N N N Y Y Y
131 None W |C C C N N N N N N Y Y Y Y Y Y
132 RW|C C C N N N N N N N N N Y Y Y
133Legend: Y = open succeeds, N = open fails with error code 05h
134 C = open fails, INT 24 generated
135 1 = open succeeds if file read-only, else fails with error code
136 2 = open succeeds if file read-only, else fails with INT 24
137========end of description from Ralph Brown's List =====
138 For every "Y" in the table we return FALSE
139 For every "N" we set the DOS_ERROR and return TRUE
140 For all other cases we barf,set the DOS_ERROR and return TRUE
141
142 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000143static BOOL FILE_ShareDeny( int mode, int oldmode)
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000144{
145 int oldsharemode = oldmode & 0x70;
146 int sharemode = mode & 0x70;
147 int oldopenmode = oldmode & 3;
148 int openmode = mode & 3;
149
150 switch (oldsharemode)
151 {
152 case OF_SHARE_COMPAT:
153 if (sharemode == OF_SHARE_COMPAT) return FALSE;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000154 if (openmode == OF_READ) goto test_ro_err05;
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000155 goto fail_error05;
156 case OF_SHARE_EXCLUSIVE:
157 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
158 goto fail_error05;
159 case OF_SHARE_DENY_WRITE:
160 if (openmode != OF_READ)
161 {
162 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
163 goto fail_error05;
164 }
165 switch (sharemode)
166 {
167 case OF_SHARE_COMPAT:
Andreas Mohr20cd9352000-09-12 23:40:40 +0000168 if (oldopenmode == OF_READ) goto test_ro_int24;
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000169 goto fail_int24;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000170 case OF_SHARE_DENY_NONE:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000171 return FALSE;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000172 case OF_SHARE_DENY_WRITE:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000173 if (oldopenmode == OF_READ) return FALSE;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000174 case OF_SHARE_DENY_READ:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000175 if (oldopenmode == OF_WRITE) return FALSE;
176 case OF_SHARE_EXCLUSIVE:
177 default:
178 goto fail_error05;
179 }
180 break;
181 case OF_SHARE_DENY_READ:
182 if (openmode != OF_WRITE)
183 {
184 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
185 goto fail_error05;
186 }
187 switch (sharemode)
188 {
189 case OF_SHARE_COMPAT:
190 goto fail_int24;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000191 case OF_SHARE_DENY_NONE:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000192 return FALSE;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000193 case OF_SHARE_DENY_WRITE:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000194 if (oldopenmode == OF_READ) return FALSE;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000195 case OF_SHARE_DENY_READ:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000196 if (oldopenmode == OF_WRITE) return FALSE;
197 case OF_SHARE_EXCLUSIVE:
198 default:
199 goto fail_error05;
200 }
201 break;
202 case OF_SHARE_DENY_NONE:
203 switch (sharemode)
204 {
205 case OF_SHARE_COMPAT:
206 goto fail_int24;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000207 case OF_SHARE_DENY_NONE:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000208 return FALSE;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000209 case OF_SHARE_DENY_WRITE:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000210 if (oldopenmode == OF_READ) return FALSE;
Andreas Mohr20cd9352000-09-12 23:40:40 +0000211 case OF_SHARE_DENY_READ:
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000212 if (oldopenmode == OF_WRITE) return FALSE;
213 case OF_SHARE_EXCLUSIVE:
214 default:
215 goto fail_error05;
216 }
217 default:
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000218 ERR("unknown mode\n");
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000219 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000220 ERR("shouldn't happen\n");
221 ERR("Please report to bon@elektron.ikp.physik.tu-darmstadt.de\n");
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000222 return TRUE;
223
224test_ro_int24:
Uwe Bonnes99f1d371998-11-06 16:39:57 +0000225 if (oldmode == OF_READ)
Uwe Bonnes2e525891998-11-01 15:04:52 +0000226 return FALSE;
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000227 /* Fall through */
228fail_int24:
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000229 FIXME("generate INT24 missing\n");
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000230 /* Is this the right error? */
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000231 SetLastError( ERROR_ACCESS_DENIED );
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000232 return TRUE;
233
234test_ro_err05:
Uwe Bonnes99f1d371998-11-06 16:39:57 +0000235 if (oldmode == OF_READ)
Uwe Bonnes2e525891998-11-01 15:04:52 +0000236 return FALSE;
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000237 /* fall through */
238fail_error05:
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000239 TRACE("Access Denied, oldmode 0x%02x mode 0x%02x\n",oldmode,mode);
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000240 SetLastError( ERROR_ACCESS_DENIED );
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000241 return TRUE;
242}
Alexandre Julliard05625391999-01-03 11:55:56 +0000243#endif
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000244
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000245
246/***********************************************************************
247 * FILE_SetDosError
248 *
249 * Set the DOS error code from errno.
250 */
251void FILE_SetDosError(void)
252{
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000253 int save_errno = errno; /* errno gets overwritten by printf */
254
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000255 TRACE("errno = %d %s\n", errno, strerror(errno));
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000256 switch (save_errno)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000257 {
258 case EAGAIN:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000259 SetLastError( ERROR_SHARING_VIOLATION );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000260 break;
261 case EBADF:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000262 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000263 break;
264 case ENOSPC:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000265 SetLastError( ERROR_HANDLE_DISK_FULL );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000266 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000267 case EACCES:
268 case EPERM:
269 case EROFS:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000270 SetLastError( ERROR_ACCESS_DENIED );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000271 break;
272 case EBUSY:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000273 SetLastError( ERROR_LOCK_VIOLATION );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000274 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000275 case ENOENT:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000276 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000277 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000278 case EISDIR:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000279 SetLastError( ERROR_CANNOT_MAKE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000280 break;
281 case ENFILE:
282 case EMFILE:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000283 SetLastError( ERROR_NO_MORE_FILES );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000284 break;
285 case EEXIST:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000286 SetLastError( ERROR_FILE_EXISTS );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000287 break;
Alexandre Julliarde658d821997-11-30 17:45:40 +0000288 case EINVAL:
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000289 case ESPIPE:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000290 SetLastError( ERROR_SEEK );
Alexandre Julliarde658d821997-11-30 17:45:40 +0000291 break;
292 case ENOTEMPTY:
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000293 SetLastError( ERROR_DIR_NOT_EMPTY );
Alexandre Julliarde658d821997-11-30 17:45:40 +0000294 break;
Alexandre Julliard045d81f2000-05-01 16:20:23 +0000295 case ENOEXEC:
296 SetLastError( ERROR_BAD_FORMAT );
297 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000298 default:
Alexandre Julliard045d81f2000-05-01 16:20:23 +0000299 perror( "FILE_SetDosError: unknown errno" );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000300 SetLastError( ERROR_GEN_FAILURE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000301 break;
302 }
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000303 errno = save_errno;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000304}
305
306
307/***********************************************************************
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000308 * FILE_DupUnixHandle
309 *
310 * Duplicate a Unix handle into a task handle.
311 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000312HFILE FILE_DupUnixHandle( int fd, DWORD access )
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000313{
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000314 struct alloc_file_handle_request *req = get_req_buffer();
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000315 req->access = access;
Alexandre Julliard8a971bf2000-04-04 19:57:23 +0000316 server_call_fd( REQ_ALLOC_FILE_HANDLE, fd, NULL );
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000317 return req->handle;
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000318}
319
320
321/***********************************************************************
Alexandre Julliard92643002000-08-31 01:59:51 +0000322 * FILE_GetUnixHandle
323 *
324 * Retrieve the Unix handle corresponding to a file handle.
325 */
326int FILE_GetUnixHandle( HANDLE handle, DWORD access )
327{
328 int unix_handle = -1;
329 if (access == GENERIC_READ)
330 {
331 struct get_read_fd_request *req = get_req_buffer();
332 req->handle = handle;
333 server_call_fd( REQ_GET_READ_FD, -1, &unix_handle );
334 }
335 else if (access == GENERIC_WRITE)
336 {
337 struct get_write_fd_request *req = get_req_buffer();
338 req->handle = handle;
339 server_call_fd( REQ_GET_WRITE_FD, -1, &unix_handle );
340 }
341 else ERR( "bad access %08lx\n", access );
342 return unix_handle;
343}
344
345
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000346/*************************************************************************
347 * FILE_OpenConsole
348 *
349 * Open a handle to the current process console.
350 */
351static HANDLE FILE_OpenConsole( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
352{
353 int ret = -1;
354
355 SERVER_START_REQ
356 {
357 struct open_console_request *req = server_alloc_req( sizeof(*req), 0 );
358
359 req->output = output;
360 req->access = access;
361 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
362 SetLastError(0);
363 if (!server_call( REQ_OPEN_CONSOLE )) ret = req->handle;
364 }
365 SERVER_END_REQ;
366 return ret;
367}
368
369
Alexandre Julliard92643002000-08-31 01:59:51 +0000370/***********************************************************************
Alexandre Julliard05625391999-01-03 11:55:56 +0000371 * FILE_CreateFile
372 *
373 * Implementation of CreateFile. Takes a Unix path name.
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000374 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000375HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000376 LPSECURITY_ATTRIBUTES sa, DWORD creation,
377 DWORD attributes, HANDLE template, BOOL fail_read_only )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000378{
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000379 DWORD err;
Alexandre Julliard92643002000-08-31 01:59:51 +0000380 HANDLE ret;
381 size_t len = strlen(filename);
382
383 if (len > REQUEST_MAX_VAR_SIZE)
384 {
385 FIXME("filename '%s' too long\n", filename );
386 SetLastError( ERROR_INVALID_PARAMETER );
387 return -1;
388 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000389
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000390 restart:
Alexandre Julliard92643002000-08-31 01:59:51 +0000391 SERVER_START_REQ
392 {
393 struct create_file_request *req = server_alloc_req( sizeof(*req), len );
394 req->access = access;
395 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
396 req->sharing = sharing;
397 req->create = creation;
398 req->attrs = attributes;
399 memcpy( server_data_ptr(req), filename, len );
400 SetLastError(0);
401 err = server_call( REQ_CREATE_FILE );
402 ret = req->handle;
403 }
404 SERVER_END_REQ;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000405
Alexandre Julliard05625391999-01-03 11:55:56 +0000406 /* If write access failed, retry without GENERIC_WRITE */
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000407
Alexandre Julliard92643002000-08-31 01:59:51 +0000408 if ((ret == -1) && !fail_read_only && (access & GENERIC_WRITE))
Alexandre Julliard05625391999-01-03 11:55:56 +0000409 {
Andreas Mohraf7e1ae2000-04-13 15:58:30 +0000410 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000411 {
Matthew Cline8bfd8252000-02-18 19:05:11 +0000412 TRACE("Write access failed for file '%s', trying without "
Andreas Mohr2caee712000-07-16 15:44:22 +0000413 "write access\n", filename);
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000414 access &= ~GENERIC_WRITE;
415 goto restart;
416 }
Matthew Cline8bfd8252000-02-18 19:05:11 +0000417 }
418
Alexandre Julliard92643002000-08-31 01:59:51 +0000419 if (ret == -1)
Andreas Mohr2caee712000-07-16 15:44:22 +0000420 WARN("Unable to create file '%s' (GLE %ld)\n", filename,
Matthew Cline8bfd8252000-02-18 19:05:11 +0000421 GetLastError());
422
Alexandre Julliard92643002000-08-31 01:59:51 +0000423 return ret;
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000424}
425
426
427/***********************************************************************
428 * FILE_CreateDevice
429 *
430 * Same as FILE_CreateFile but for a device
431 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000432HFILE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000433{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000434 HFILE ret;
435 SERVER_START_REQ
436 {
437 struct create_device_request *req = server_alloc_req( sizeof(*req), 0 );
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000438
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000439 req->access = access;
440 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
441 req->id = client_id;
442 SetLastError(0);
443 server_call( REQ_CREATE_DEVICE );
444 ret = req->handle;
445 }
446 SERVER_END_REQ;
447 return ret;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000448}
449
450
Alexandre Julliard05625391999-01-03 11:55:56 +0000451/*************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000452 * CreateFileA [KERNEL32.45] Creates or opens a file or other object
Uwe Bonnesa370ab41998-10-24 09:16:44 +0000453 *
Alexandre Julliard05625391999-01-03 11:55:56 +0000454 * Creates or opens an object, and returns a handle that can be used to
455 * access that object.
Uwe Bonnesa370ab41998-10-24 09:16:44 +0000456 *
Alexandre Julliard05625391999-01-03 11:55:56 +0000457 * PARAMS
458 *
459 * filename [I] pointer to filename to be accessed
460 * access [I] access mode requested
461 * sharing [I] share mode
462 * sa [I] pointer to security attributes
463 * creation [I] how to create the file
464 * attributes [I] attributes for newly created file
465 * template [I] handle to file with extended attributes to copy
466 *
467 * RETURNS
468 * Success: Open handle to specified file
469 * Failure: INVALID_HANDLE_VALUE
470 *
471 * NOTES
472 * Should call SetLastError() on failure.
473 *
474 * BUGS
475 *
476 * Doesn't support character devices, pipes, template files, or a
477 * lot of the 'attributes' flags yet.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000478 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000479HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
Alexandre Julliard05625391999-01-03 11:55:56 +0000480 LPSECURITY_ATTRIBUTES sa, DWORD creation,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000481 DWORD attributes, HANDLE template )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000482{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000483 DOS_FULL_NAME full_name;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000484
Alexandre Julliard05625391999-01-03 11:55:56 +0000485 if (!filename)
486 {
487 SetLastError( ERROR_INVALID_PARAMETER );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000488 return HFILE_ERROR;
Alexandre Julliard05625391999-01-03 11:55:56 +0000489 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000490 TRACE("%s %s%s%s%s%s%s%s\n",filename,
Uwe Bonnese4f46dc1999-06-06 17:08:13 +0000491 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
492 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
493 (!access)?"QUERY_ACCESS ":"",
494 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
495 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
496 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
497 (creation ==CREATE_NEW)?"CREATE_NEW":
498 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
499 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
500 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
501 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000502
Alexandre Julliard05625391999-01-03 11:55:56 +0000503 /* If the name starts with '\\?\', ignore the first 4 chars. */
504 if (!strncmp(filename, "\\\\?\\", 4))
505 {
506 filename += 4;
507 if (!strncmp(filename, "UNC\\", 4))
508 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000509 FIXME("UNC name (%s) not supported.\n", filename );
Alexandre Julliard05625391999-01-03 11:55:56 +0000510 SetLastError( ERROR_PATH_NOT_FOUND );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000511 return HFILE_ERROR;
Alexandre Julliard05625391999-01-03 11:55:56 +0000512 }
513 }
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000514
Marcus Meissnerdd7523d2000-01-23 02:18:27 +0000515 if (!strncmp(filename, "\\\\.\\", 4)) {
516 if (!DOSFS_GetDevice( filename ))
517 return DEVICE_Open( filename+4, access, sa );
518 else
519 filename+=4; /* fall into DOSFS_Device case below */
520 }
Alexandre Julliard05625391999-01-03 11:55:56 +0000521
522 /* If the name still starts with '\\', it's a UNC name. */
523 if (!strncmp(filename, "\\\\", 2))
524 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000525 FIXME("UNC name (%s) not supported.\n", filename );
Alexandre Julliard05625391999-01-03 11:55:56 +0000526 SetLastError( ERROR_PATH_NOT_FOUND );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000527 return HFILE_ERROR;
Alexandre Julliard05625391999-01-03 11:55:56 +0000528 }
529
Francois Boisvert567bcf11999-09-20 18:31:21 +0000530 /* If the name contains a DOS wild card (* or ?), do no create a file */
531 if(strchr(filename,'*') || strchr(filename,'?'))
532 return HFILE_ERROR;
533
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000534 /* Open a console for CONIN$ or CONOUT$ */
Alexandre Julliard83f52d12000-09-26 22:20:14 +0000535 if (!strcasecmp(filename, "CONIN$")) return FILE_OpenConsole( FALSE, access, sa );
536 if (!strcasecmp(filename, "CONOUT$")) return FILE_OpenConsole( TRUE, access, sa );
Alexandre Julliard05625391999-01-03 11:55:56 +0000537
538 if (DOSFS_GetDevice( filename ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000539 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000540 HFILE ret;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000541
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000542 TRACE("opening device '%s'\n", filename );
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000543
Alexandre Julliarda3960291999-02-26 11:11:13 +0000544 if (HFILE_ERROR!=(ret=DOSFS_OpenDevice( filename, access )))
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000545 return ret;
546
547 /* Do not silence this please. It is a critical error. -MM */
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000548 ERR("Couldn't open device '%s'!\n",filename);
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000549 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000550 return HFILE_ERROR;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000551 }
Alexandre Julliard05625391999-01-03 11:55:56 +0000552
553 /* check for filename, don't check for last entry if creating */
554 if (!DOSFS_GetFullName( filename,
Matthew Cline8bfd8252000-02-18 19:05:11 +0000555 (creation == OPEN_EXISTING) ||
556 (creation == TRUNCATE_EXISTING),
557 &full_name )) {
558 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
559 filename, GetLastError());
Alexandre Julliarda3960291999-02-26 11:11:13 +0000560 return HFILE_ERROR;
Matthew Cline8bfd8252000-02-18 19:05:11 +0000561 }
Alexandre Julliard05625391999-01-03 11:55:56 +0000562
563 return FILE_CreateFile( full_name.long_name, access, sharing,
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000564 sa, creation, attributes, template,
565 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000566}
567
568
Alexandre Julliard05625391999-01-03 11:55:56 +0000569
570/*************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000571 * CreateFileW (KERNEL32.48)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000572 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000573HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
Alexandre Julliard05625391999-01-03 11:55:56 +0000574 LPSECURITY_ATTRIBUTES sa, DWORD creation,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000575 DWORD attributes, HANDLE template)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000576{
Alexandre Julliard05625391999-01-03 11:55:56 +0000577 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Jim Aston031f4fa1999-10-23 19:00:02 +0000578 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
Alexandre Julliard05625391999-01-03 11:55:56 +0000579 HeapFree( GetProcessHeap(), 0, afn );
580 return res;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000581}
582
583
584/***********************************************************************
585 * FILE_FillInfo
586 *
587 * Fill a file information from a struct stat.
588 */
589static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
590{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000591 if (S_ISDIR(st->st_mode))
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000592 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
593 else
594 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
Alexandre Julliard01d63461997-01-20 19:43:45 +0000595 if (!(st->st_mode & S_IWUSR))
596 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000597
Alexandre Julliarde101f6d2000-08-14 14:42:41 +0000598 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
599 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
600 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000601
602 info->dwVolumeSerialNumber = 0; /* FIXME */
603 info->nFileSizeHigh = 0;
604 info->nFileSizeLow = S_ISDIR(st->st_mode) ? 0 : st->st_size;
605 info->nNumberOfLinks = st->st_nlink;
606 info->nFileIndexHigh = 0;
607 info->nFileIndexLow = st->st_ino;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000608}
609
610
611/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000612 * FILE_Stat
613 *
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000614 * Stat a Unix path name. Return TRUE if OK.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000615 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000616BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000617{
618 struct stat st;
619
Andreas Mohr220312e2000-10-19 20:38:38 +0000620 if (lstat( unixName, &st ) == -1)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000621 {
622 FILE_SetDosError();
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000623 return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000624 }
Andreas Mohr220312e2000-10-19 20:38:38 +0000625 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
626 else
627 {
628 /* do a "real" stat to find out
629 about the type of the symlink destination */
630 if (stat( unixName, &st ) == -1)
631 {
632 FILE_SetDosError();
633 return FALSE;
634 }
635 FILE_FillInfo( &st, info );
636 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
637 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000638 return TRUE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000639}
640
641
642/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000643 * GetFileInformationByHandle (KERNEL32.219)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000644 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000645DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000646 BY_HANDLE_FILE_INFORMATION *info )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000647{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000648 DWORD ret;
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000649 if (!info) return 0;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000650
651 SERVER_START_REQ
652 {
653 struct get_file_info_request *req = server_alloc_req( sizeof(*req), 0 );
654 req->handle = hFile;
655 if ((ret = !server_call( REQ_GET_FILE_INFO )))
656 {
657 RtlSecondsSince1970ToTime( req->write_time, &info->ftCreationTime );
658 RtlSecondsSince1970ToTime( req->write_time, &info->ftLastWriteTime );
659 RtlSecondsSince1970ToTime( req->access_time, &info->ftLastAccessTime );
660 info->dwFileAttributes = req->attr;
661 info->dwVolumeSerialNumber = req->serial;
662 info->nFileSizeHigh = req->size_high;
663 info->nFileSizeLow = req->size_low;
664 info->nNumberOfLinks = req->links;
665 info->nFileIndexHigh = req->index_high;
666 info->nFileIndexLow = req->index_low;
667 }
668 }
669 SERVER_END_REQ;
670 return ret;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000671}
672
673
674/**************************************************************************
675 * GetFileAttributes16 (KERNEL.420)
676 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000677DWORD WINAPI GetFileAttributes16( LPCSTR name )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000678{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000679 return GetFileAttributesA( name );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000680}
681
682
683/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000684 * GetFileAttributesA (KERNEL32.217)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000685 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000686DWORD WINAPI GetFileAttributesA( LPCSTR name )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000687{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000688 DOS_FULL_NAME full_name;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000689 BY_HANDLE_FILE_INFORMATION info;
690
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000691 if (name == NULL || *name=='\0') return -1;
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000692
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000693 if (!DOSFS_GetFullName( name, TRUE, &full_name )) return -1;
694 if (!FILE_Stat( full_name.long_name, &info )) return -1;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000695 return info.dwFileAttributes;
696}
697
698
699/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000700 * GetFileAttributesW (KERNEL32.218)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000701 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000702DWORD WINAPI GetFileAttributesW( LPCWSTR name )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000703{
704 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000705 DWORD res = GetFileAttributesA( nameA );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000706 HeapFree( GetProcessHeap(), 0, nameA );
707 return res;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000708}
709
710
711/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000712 * GetFileSize (KERNEL32.220)
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000713 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000714DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000715{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000716 BY_HANDLE_FILE_INFORMATION info;
717 if (!GetFileInformationByHandle( hFile, &info )) return 0;
718 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
719 return info.nFileSizeLow;
720}
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000721
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000722
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000723/***********************************************************************
724 * GetFileTime (KERNEL32.221)
725 */
Jim Aston031f4fa1999-10-23 19:00:02 +0000726BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000727 FILETIME *lpLastAccessTime,
728 FILETIME *lpLastWriteTime )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000729{
730 BY_HANDLE_FILE_INFORMATION info;
731 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
732 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
733 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
734 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
735 return TRUE;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000736}
737
Alexandre Julliard349a9531997-02-02 19:01:52 +0000738/***********************************************************************
739 * CompareFileTime (KERNEL32.28)
740 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000741INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
Alexandre Julliard349a9531997-02-02 19:01:52 +0000742{
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000743 if (!x || !y) return -1;
744
Alexandre Julliard349a9531997-02-02 19:01:52 +0000745 if (x->dwHighDateTime > y->dwHighDateTime)
746 return 1;
747 if (x->dwHighDateTime < y->dwHighDateTime)
748 return -1;
749 if (x->dwLowDateTime > y->dwLowDateTime)
750 return 1;
751 if (x->dwLowDateTime < y->dwLowDateTime)
752 return -1;
753 return 0;
754}
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000755
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000756/***********************************************************************
Gerard Patelc465e191999-10-24 20:48:54 +0000757 * FILE_GetTempFileName : utility for GetTempFileName
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000758 */
Gerard Patelc465e191999-10-24 20:48:54 +0000759static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
760 LPSTR buffer, BOOL isWin16 )
Alexandre Julliardca22b331996-07-12 19:02:39 +0000761{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000762 static UINT unique_temp;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000763 DOS_FULL_NAME full_name;
Alexandre Julliardca22b331996-07-12 19:02:39 +0000764 int i;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000765 LPSTR p;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000766 UINT num;
Alexandre Julliardca22b331996-07-12 19:02:39 +0000767
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000768 if ( !path || !prefix || !buffer ) return 0;
769
Uwe Bonnes2e525891998-11-01 15:04:52 +0000770 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
771 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
772
Alexandre Julliardca22b331996-07-12 19:02:39 +0000773 strcpy( buffer, path );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000774 p = buffer + strlen(buffer);
Alexandre Julliard02e90081998-01-04 17:49:09 +0000775
776 /* add a \, if there isn't one and path is more than just the drive letter ... */
777 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
778 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
779
Gerard Patelc465e191999-10-24 20:48:54 +0000780 if (isWin16) *p++ = '~';
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000781 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
782 sprintf( p, "%04x.tmp", num );
783
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000784 /* Now try to create it */
785
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000786 if (!unique)
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000787 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000788 do
789 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000790 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
Alexandre Julliard05625391999-01-03 11:55:56 +0000791 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000792 if (handle != INVALID_HANDLE_VALUE)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000793 { /* We created it */
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000794 TRACE("created %s\n",
Alexandre Julliard21979011997-03-05 08:22:35 +0000795 buffer);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000796 CloseHandle( handle );
797 break;
798 }
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000799 if (GetLastError() != ERROR_FILE_EXISTS)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000800 break; /* No need to go on */
801 num++;
802 sprintf( p, "%04x.tmp", num );
803 } while (num != (unique & 0xffff));
804 }
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000805
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000806 /* Get the full path name */
807
808 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
809 {
Alexandre Julliard01d63461997-01-20 19:43:45 +0000810 /* Check if we have write access in the directory */
811 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000812 if (access( full_name.long_name, W_OK ) == -1)
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000813 WARN("returns '%s', which doesn't seem to be writeable.\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000814 buffer);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000815 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000816 TRACE("returning %s\n", buffer );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000817 return unique ? unique : num;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000818}
819
820
821/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000822 * GetTempFileNameA (KERNEL32.290)
Gerard Patelc465e191999-10-24 20:48:54 +0000823 */
824UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
825 LPSTR buffer)
826{
827 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
828}
829
830/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000831 * GetTempFileNameW (KERNEL32.291)
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000832 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000833UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000834 LPWSTR buffer )
Alexandre Julliardca22b331996-07-12 19:02:39 +0000835{
836 LPSTR patha,prefixa;
837 char buffera[144];
Alexandre Julliarda3960291999-02-26 11:11:13 +0000838 UINT ret;
Alexandre Julliardca22b331996-07-12 19:02:39 +0000839
840 if (!path) return 0;
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +0000841 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
842 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
Gerard Patelc465e191999-10-24 20:48:54 +0000843 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +0000844 lstrcpyAtoW( buffer, buffera );
845 HeapFree( GetProcessHeap(), 0, patha );
846 HeapFree( GetProcessHeap(), 0, prefixa );
Alexandre Julliardca22b331996-07-12 19:02:39 +0000847 return ret;
848}
849
850
851/***********************************************************************
Gerard Patelc465e191999-10-24 20:48:54 +0000852 * GetTempFileName16 (KERNEL.97)
853 */
854UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
855 LPSTR buffer )
856{
857 char temppath[144];
858
859 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
860 drive |= DRIVE_GetCurrentDrive() + 'A';
861
862 if ((drive & TF_FORCEDRIVE) &&
863 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
864 {
865 drive &= ~TF_FORCEDRIVE;
866 WARN("invalid drive %d specified\n", drive );
867 }
868
869 if (drive & TF_FORCEDRIVE)
870 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
871 else
872 GetTempPathA( 132, temppath );
873 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
874}
875
876/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000877 * FILE_DoOpenFile
878 *
879 * Implementation of OpenFile16() and OpenFile32().
Alexandre Julliardca22b331996-07-12 19:02:39 +0000880 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000881static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
882 BOOL win32 )
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000883{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000884 HFILE hFileRet;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000885 FILETIME filetime;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000886 WORD filedatetime[2];
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000887 DOS_FULL_NAME full_name;
Alexandre Julliard05625391999-01-03 11:55:56 +0000888 DWORD access, sharing;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000889 char *p;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000890
Alexandre Julliarda3960291999-02-26 11:11:13 +0000891 if (!ofs) return HFILE_ERROR;
Uwe Bonnese4f46dc1999-06-06 17:08:13 +0000892
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000893 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
Uwe Bonnese4f46dc1999-06-06 17:08:13 +0000894 ((mode & 0x3 )==OF_READ)?"OF_READ":
895 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
896 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
897 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
898 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
899 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
900 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
901 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
902 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
903 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
904 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
905 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
906 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
907 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
908 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
909 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
910 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
911 );
912
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000913
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000914 ofs->cBytes = sizeof(OFSTRUCT);
915 ofs->nErrCode = 0;
916 if (mode & OF_REOPEN) name = ofs->szPathName;
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000917
918 if (!name) {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000919 ERR("called with `name' set to NULL ! Please debug.\n");
Alexandre Julliarda3960291999-02-26 11:11:13 +0000920 return HFILE_ERROR;
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000921 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000922
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000923 TRACE("%s %04x\n", name, mode );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000924
Alexandre Julliard889f7421997-04-15 17:19:52 +0000925 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
926 Are there any cases where getting the path here is wrong?
927 Uwe Bonnes 1997 Apr 2 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000928 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
Alexandre Julliard889f7421997-04-15 17:19:52 +0000929 ofs->szPathName, NULL )) goto error;
Alexandre Julliard05625391999-01-03 11:55:56 +0000930 FILE_ConvertOFMode( mode, &access, &sharing );
Alexandre Julliard889f7421997-04-15 17:19:52 +0000931
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000932 /* OF_PARSE simply fills the structure */
933
934 if (mode & OF_PARSE)
935 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000936 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
937 != DRIVE_REMOVABLE);
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000938 TRACE("(%s): OF_PARSE, res = '%s'\n",
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000939 name, ofs->szPathName );
940 return 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000941 }
942
943 /* OF_CREATE is completely different from all other options, so
944 handle it first */
945
946 if (mode & OF_CREATE)
947 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000948 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
Alexandre Julliard638f1691999-01-17 16:32:32 +0000949 sharing, NULL, CREATE_ALWAYS,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000950 FILE_ATTRIBUTE_NORMAL, -1 ))== INVALID_HANDLE_VALUE)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000951 goto error;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +0000952 goto success;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000953 }
954
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000955 /* If OF_SEARCH is set, ignore the given path */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000956
957 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
958 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000959 /* First try the file name as is */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000960 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000961 /* Now remove the path */
962 if (name[0] && (name[1] == ':')) name += 2;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000963 if ((p = strrchr( name, '\\' ))) name = p + 1;
964 if ((p = strrchr( name, '/' ))) name = p + 1;
965 if (!name[0]) goto not_found;
966 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000967
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000968 /* Now look for the file */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000969
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000970 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000971
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000972found:
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000973 TRACE("found %s = %s\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000974 full_name.long_name, full_name.short_name );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000975 lstrcpynA( ofs->szPathName, full_name.short_name,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000976 sizeof(ofs->szPathName) );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000977
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000978 if (mode & OF_SHARE_EXCLUSIVE)
Uwe Bonnese6b5e381998-10-18 14:48:31 +0000979 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
980 on the file <tempdir>/_ins0432._mp to determine how
981 far installation has proceeded.
982 _ins0432._mp is an executable and while running the
983 application expects the open with OF_SHARE_ to fail*/
984 /* Probable FIXME:
985 As our loader closes the files after loading the executable,
986 we can't find the running executable with FILE_InUse.
987 Perhaps the loader should keep the file open.
988 Recheck against how Win handles that case */
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000989 {
990 char *last = strrchr(full_name.long_name,'/');
991 if (!last)
992 last = full_name.long_name - 1;
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000993 if (GetModuleHandle16(last+1))
994 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000995 TRACE("Denying shared open for %s\n",full_name.long_name);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000996 return HFILE_ERROR;
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000997 }
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000998 }
999
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001000 if (mode & OF_DELETE)
1001 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001002 if (unlink( full_name.long_name ) == -1) goto not_found;
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001003 TRACE("(%s): OF_DELETE return = OK\n", name);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001004 return 1;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001005 }
1006
Alexandre Julliard05625391999-01-03 11:55:56 +00001007 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
Alexandre Julliardfbace6e2000-04-04 20:35:45 +00001008 NULL, OPEN_EXISTING, 0, -1,
1009 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001010 if (hFileRet == HFILE_ERROR) goto not_found;
Uwe Bonnese6b5e381998-10-18 14:48:31 +00001011
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001012 GetFileTime( hFileRet, NULL, NULL, &filetime );
1013 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001014 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001015 {
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001016 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001017 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001018 CloseHandle( hFileRet );
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001019 WARN("(%s): OF_VERIFY failed\n", name );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001020 /* FIXME: what error here? */
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001021 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001022 goto error;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001023 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001024 }
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001025 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001026
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001027success: /* We get here if the open was successful */
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001028 TRACE("(%s): OK, return = %d\n", name, hFileRet );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001029 if (win32)
1030 {
1031 if (mode & OF_EXIST) /* Return the handle, but close it first */
1032 CloseHandle( hFileRet );
1033 }
1034 else
1035 {
1036 hFileRet = FILE_AllocDosHandle( hFileRet );
1037 if (hFileRet == HFILE_ERROR16) goto error;
1038 if (mode & OF_EXIST) /* Return the handle, but close it first */
1039 _lclose16( hFileRet );
1040 }
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001041 return hFileRet;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001042
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001043not_found: /* We get here if the file does not exist */
Andreas Mohr20cd9352000-09-12 23:40:40 +00001044 WARN("'%s' not found or sharing violation\n", name );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001045 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001046 /* fall through */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001047
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00001048error: /* We get here if there was an error opening the file */
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001049 ofs->nErrCode = GetLastError();
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001050 WARN("(%s): return = HFILE_ERROR error= %d\n",
Alexandre Julliard889f7421997-04-15 17:19:52 +00001051 name,ofs->nErrCode );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001052 return HFILE_ERROR;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001053}
1054
Alexandre Julliardac9c9b01996-07-28 18:50:11 +00001055
1056/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001057 * OpenFile16 (KERNEL.74)
Alexandre Julliardac9c9b01996-07-28 18:50:11 +00001058 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001059HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001060{
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001061 return FILE_DoOpenFile( name, ofs, mode, FALSE );
Alexandre Julliardac9c9b01996-07-28 18:50:11 +00001062}
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001063
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001064
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001065/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001066 * OpenFile (KERNEL32.396)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001067 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001068HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001069{
1070 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1071}
1072
1073
1074/***********************************************************************
Marcus Meissnerb12e72d1999-01-23 14:01:08 +00001075 * FILE_InitProcessDosHandles
1076 *
1077 * Allocates the default DOS handles for a process. Called either by
1078 * AllocDosHandle below or by the DOSVM stuff.
1079 */
Alexandre Julliard231674d2000-08-09 22:30:18 +00001080static void FILE_InitProcessDosHandles( void )
1081{
1082 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1083 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1084 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1085 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1086 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
Marcus Meissnerb12e72d1999-01-23 14:01:08 +00001087}
1088
1089/***********************************************************************
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001090 * FILE_AllocDosHandle
1091 *
1092 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1093 * longer valid after this function (even on failure).
1094 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001095HFILE16 FILE_AllocDosHandle( HANDLE handle )
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001096{
1097 int i;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001098
Alexandre Julliarda3960291999-02-26 11:11:13 +00001099 if (!handle || (handle == INVALID_HANDLE_VALUE))
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001100 return INVALID_HANDLE_VALUE16;
1101
Alexandre Julliard231674d2000-08-09 22:30:18 +00001102 for (i = 5; i < DOS_TABLE_SIZE; i++)
1103 if (!dos_handles[i])
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001104 {
Alexandre Julliard231674d2000-08-09 22:30:18 +00001105 dos_handles[i] = handle;
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001106 TRACE("Got %d for h32 %d\n", i, handle );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001107 return i;
1108 }
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001109 CloseHandle( handle );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001110 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001111 return INVALID_HANDLE_VALUE16;
1112}
1113
1114
1115/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001116 * FILE_GetHandle
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001117 *
1118 * Return the Win32 handle for a DOS handle.
1119 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001120HANDLE FILE_GetHandle( HFILE16 hfile )
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001121{
Alexandre Julliard231674d2000-08-09 22:30:18 +00001122 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1123 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001124 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001125 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001126 return INVALID_HANDLE_VALUE;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001127 }
Alexandre Julliard231674d2000-08-09 22:30:18 +00001128 return dos_handles[hfile];
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001129}
1130
1131
1132/***********************************************************************
1133 * FILE_Dup2
1134 *
1135 * dup2() function for DOS handles.
1136 */
1137HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1138{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001139 HANDLE new_handle;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001140
Alexandre Julliard231674d2000-08-09 22:30:18 +00001141 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1142
1143 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001144 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001145 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001146 return HFILE_ERROR16;
1147 }
1148 if (hFile2 < 5)
1149 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001150 FIXME("stdio handle closed, need proper conversion\n" );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001151 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001152 return HFILE_ERROR16;
1153 }
Alexandre Julliard231674d2000-08-09 22:30:18 +00001154 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001155 GetCurrentProcess(), &new_handle,
1156 0, FALSE, DUPLICATE_SAME_ACCESS ))
1157 return HFILE_ERROR16;
Alexandre Julliard231674d2000-08-09 22:30:18 +00001158 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1159 dos_handles[hFile2] = new_handle;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001160 return hFile2;
1161}
1162
1163
1164/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001165 * _lclose16 (KERNEL.81)
1166 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001167HFILE16 WINAPI _lclose16( HFILE16 hFile )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001168{
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001169 if (hFile < 5)
1170 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001171 FIXME("stdio handle closed, need proper conversion\n" );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001172 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001173 return HFILE_ERROR16;
1174 }
Alexandre Julliard231674d2000-08-09 22:30:18 +00001175 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001176 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001177 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001178 return HFILE_ERROR16;
1179 }
Alexandre Julliard231674d2000-08-09 22:30:18 +00001180 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1181 CloseHandle( dos_handles[hFile] );
1182 dos_handles[hFile] = 0;
Alexandre Julliard8da12c41999-01-17 16:55:11 +00001183 return 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001184}
1185
1186
1187/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001188 * _lclose (KERNEL32.592)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001189 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001190HFILE WINAPI _lclose( HFILE hFile )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001191{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001192 TRACE("handle %d\n", hFile );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001193 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001194}
1195
Moshe Vainer0ea089b1999-11-10 19:51:01 +00001196/***********************************************************************
1197 * GetOverlappedResult (KERNEL32.360)
1198 */
1199BOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,
1200 LPDWORD lpNumberOfBytesTransferred,
1201 BOOL bWait)
1202{
Andreas Mohr2caee712000-07-16 15:44:22 +00001203 /* Since all i/o is currently synchronous,
Moshe Vainer0ea089b1999-11-10 19:51:01 +00001204 * return true, assuming ReadFile/WriteFile
1205 * have completed the operation */
1206 FIXME("NO Asynch I/O, assuming Read/Write succeeded\n" );
1207 return TRUE;
1208}
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001209
1210/***********************************************************************
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001211 * ReadFile (KERNEL32.428)
1212 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001213BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001214 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1215{
Alexandre Julliard55443871998-12-31 15:52:06 +00001216 int unix_handle, result;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001217
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001218 TRACE("%d %p %ld\n", hFile, buffer, bytesToRead );
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001219
1220 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1221 if (!bytesToRead) return TRUE;
1222
Peter Gantenf6c43881999-12-11 23:08:00 +00001223 if ( overlapped ) {
1224 SetLastError ( ERROR_INVALID_PARAMETER );
1225 return FALSE;
1226 }
1227
Alexandre Julliard92643002000-08-31 01:59:51 +00001228 unix_handle = FILE_GetUnixHandle( hFile, GENERIC_READ );
Alexandre Julliard55443871998-12-31 15:52:06 +00001229 if (unix_handle == -1) return FALSE;
1230 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001231 {
Alexandre Julliard55443871998-12-31 15:52:06 +00001232 if ((errno == EAGAIN) || (errno == EINTR)) continue;
Gerard Patelf69c1502000-05-07 18:26:19 +00001233 if ((errno == EFAULT) && !VIRTUAL_HandleFault( buffer )) continue;
Alexandre Julliard55443871998-12-31 15:52:06 +00001234 FILE_SetDosError();
1235 break;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001236 }
Alexandre Julliard55443871998-12-31 15:52:06 +00001237 close( unix_handle );
1238 if (result == -1) return FALSE;
1239 if (bytesRead) *bytesRead = result;
1240 return TRUE;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001241}
1242
1243
1244/***********************************************************************
1245 * WriteFile (KERNEL32.578)
1246 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001247BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001248 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1249{
Alexandre Julliard55443871998-12-31 15:52:06 +00001250 int unix_handle, result;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001251
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001252 TRACE("%d %p %ld\n", hFile, buffer, bytesToWrite );
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001253
1254 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1255 if (!bytesToWrite) return TRUE;
1256
Peter Gantenf6c43881999-12-11 23:08:00 +00001257 if ( overlapped ) {
1258 SetLastError ( ERROR_INVALID_PARAMETER );
1259 return FALSE;
1260 }
1261
Alexandre Julliard92643002000-08-31 01:59:51 +00001262 unix_handle = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
Alexandre Julliard55443871998-12-31 15:52:06 +00001263 if (unix_handle == -1) return FALSE;
1264 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001265 {
Alexandre Julliard55443871998-12-31 15:52:06 +00001266 if ((errno == EAGAIN) || (errno == EINTR)) continue;
Gerard Patelf69c1502000-05-07 18:26:19 +00001267 if ((errno == EFAULT) && !VIRTUAL_HandleFault( buffer )) continue;
Gerard Patel8f3c0a31999-06-27 15:26:37 +00001268 if (errno == ENOSPC)
1269 SetLastError( ERROR_DISK_FULL );
1270 else
Alexandre Julliard55443871998-12-31 15:52:06 +00001271 FILE_SetDosError();
1272 break;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001273 }
Alexandre Julliard55443871998-12-31 15:52:06 +00001274 close( unix_handle );
1275 if (result == -1) return FALSE;
1276 if (bytesWritten) *bytesWritten = result;
1277 return TRUE;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001278}
1279
1280
1281/***********************************************************************
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001282 * WIN16_hread
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001283 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001284LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001285{
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001286 LONG maxlen;
1287
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001288 TRACE("%d %08lx %ld\n",
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001289 hFile, (DWORD)buffer, count );
1290
1291 /* Some programs pass a count larger than the allocated buffer */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001292 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001293 if (count > maxlen) count = maxlen;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001294 return _lread(FILE_GetHandle(hFile), PTR_SEG_TO_LIN(buffer), count );
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001295}
1296
1297
1298/***********************************************************************
1299 * WIN16_lread
1300 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001301UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001302{
1303 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1304}
1305
1306
1307/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001308 * _lread (KERNEL32.596)
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001309 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001310UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001311{
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001312 DWORD result;
1313 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1314 return result;
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001315}
1316
1317
1318/***********************************************************************
1319 * _lread16 (KERNEL.82)
1320 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001321UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001322{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001323 return (UINT16)_lread(FILE_GetHandle(hFile), buffer, (LONG)count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001324}
1325
1326
1327/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001328 * _lcreat16 (KERNEL.83)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001329 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001330HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001331{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001332 return FILE_AllocDosHandle( _lcreat( path, attr ) );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001333}
1334
1335
1336/***********************************************************************
Alexandre Julliardd5240f11999-04-03 13:54:51 +00001337 * _lcreat (KERNEL32.593)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001338 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001339HFILE WINAPI _lcreat( LPCSTR path, INT attr )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001340{
Alexandre Julliardd5240f11999-04-03 13:54:51 +00001341 /* Mask off all flags not explicitly allowed by the doc */
1342 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001343 TRACE("%s %02x\n", path, attr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001344 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
Alexandre Julliardd5240f11999-04-03 13:54:51 +00001345 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1346 CREATE_ALWAYS, attr, -1 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001347}
1348
1349
1350/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001351 * SetFilePointer (KERNEL32.492)
1352 */
Jim Aston031f4fa1999-10-23 19:00:02 +00001353DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001354 DWORD method )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001355{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001356 DWORD ret = 0xffffffff;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001357
Hidenori Takeshima66791af2000-07-31 23:26:50 +00001358 if (highword &&
1359 ((distance >= 0 && *highword != 0) || (distance < 0 && *highword != -1)))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001360 {
Hidenori Takeshima66791af2000-07-31 23:26:50 +00001361 FIXME("64-bit offsets not supported yet\n"
1362 "SetFilePointer(%08x,%08lx,%08lx,%08lx)\n",
1363 hFile,distance,*highword,method);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001364 SetLastError( ERROR_INVALID_PARAMETER );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001365 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001366 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001367 TRACE("handle %d offset %ld origin %ld\n",
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001368 hFile, distance, method );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001369
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001370 SERVER_START_REQ
1371 {
1372 struct set_file_pointer_request *req = server_alloc_req( sizeof(*req), 0 );
1373 req->handle = hFile;
1374 req->low = distance;
1375 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1376 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1377 req->whence = method;
1378 SetLastError( 0 );
1379 if (!server_call( REQ_SET_FILE_POINTER ))
1380 {
1381 ret = req->new_low;
1382 if (highword) *highword = req->new_high;
1383 }
1384 }
1385 SERVER_END_REQ;
1386 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001387}
1388
1389
1390/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001391 * _llseek16 (KERNEL.84)
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001392 *
1393 * FIXME:
1394 * Seeking before the start of the file should be allowed for _llseek16,
1395 * but cause subsequent I/O operations to fail (cf. interrupt list)
1396 *
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001397 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001398LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001399{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001400 return SetFilePointer( FILE_GetHandle(hFile), lOffset, NULL, nOrigin );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001401}
1402
1403
1404/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001405 * _llseek (KERNEL32.594)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001406 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001407LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001408{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001409 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001410}
1411
1412
1413/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001414 * _lopen16 (KERNEL.85)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001415 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001416HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001417{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001418 return FILE_AllocDosHandle( _lopen( path, mode ) );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001419}
1420
1421
1422/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001423 * _lopen (KERNEL32.595)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001424 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001425HFILE WINAPI _lopen( LPCSTR path, INT mode )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001426{
Alexandre Julliard05625391999-01-03 11:55:56 +00001427 DWORD access, sharing;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001428
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001429 TRACE("('%s',%04x)\n", path, mode );
Alexandre Julliard05625391999-01-03 11:55:56 +00001430 FILE_ConvertOFMode( mode, &access, &sharing );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001431 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, -1 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001432}
1433
1434
1435/***********************************************************************
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001436 * _lwrite16 (KERNEL.86)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001437 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001438UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001439{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001440 return (UINT16)_hwrite( FILE_GetHandle(hFile), buffer, (LONG)count );
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001441}
1442
1443/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001444 * _lwrite (KERNEL32.761)
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001445 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001446UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001447{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001448 return (UINT)_hwrite( hFile, buffer, (LONG)count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001449}
1450
1451
1452/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001453 * _hread16 (KERNEL.349)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001454 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001455LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001456{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001457 return _lread( FILE_GetHandle(hFile), buffer, count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001458}
1459
1460
1461/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001462 * _hread (KERNEL32.590)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001463 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001464LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001465{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001466 return _lread( hFile, buffer, count );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001467}
1468
1469
1470/***********************************************************************
1471 * _hwrite16 (KERNEL.350)
1472 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001473LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001474{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001475 return _hwrite( FILE_GetHandle(hFile), buffer, count );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001476}
1477
1478
1479/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001480 * _hwrite (KERNEL32.591)
Alexandre Julliarda11d7b11998-03-01 20:05:02 +00001481 *
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001482 * experimentation yields that _lwrite:
Alexandre Julliarda11d7b11998-03-01 20:05:02 +00001483 * o truncates the file at the current position with
1484 * a 0 len write
1485 * o returns 0 on a 0 length write
1486 * o works with console handles
1487 *
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001488 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001489LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001490{
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001491 DWORD result;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001492
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001493 TRACE("%d %p %ld\n", handle, buffer, count );
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001494
1495 if (!count)
1496 {
1497 /* Expand or truncate at current position */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001498 if (!SetEndOfFile( handle )) return HFILE_ERROR;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001499 return 0;
1500 }
1501 if (!WriteFile( handle, buffer, count, &result, NULL ))
Alexandre Julliarda3960291999-02-26 11:11:13 +00001502 return HFILE_ERROR;
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +00001503 return result;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001504}
1505
1506
1507/***********************************************************************
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001508 * SetHandleCount16 (KERNEL.199)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001509 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001510UINT16 WINAPI SetHandleCount16( UINT16 count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001511{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001512 HGLOBAL16 hPDB = GetCurrentPDB16();
1513 PDB16 *pdb = (PDB16 *)GlobalLock16( hPDB );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001514 BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001515
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001516 TRACE("(%d)\n", count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001517
1518 if (count < 20) count = 20; /* No point in going below 20 */
1519 else if (count > 254) count = 254;
1520
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001521 if (count == 20)
1522 {
1523 if (pdb->nbFiles > 20)
1524 {
1525 memcpy( pdb->fileHandles, files, 20 );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001526 GlobalFree16( pdb->hFileHandles );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001527 pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001528 GlobalHandleToSel16( hPDB ) );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001529 pdb->hFileHandles = 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001530 pdb->nbFiles = 20;
1531 }
1532 }
1533 else /* More than 20, need a new file handles table */
1534 {
1535 BYTE *newfiles;
Alexandre Julliardbf9130a1996-10-13 17:45:47 +00001536 HGLOBAL16 newhandle = GlobalAlloc16( GMEM_MOVEABLE, count );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001537 if (!newhandle)
1538 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001539 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001540 return pdb->nbFiles;
1541 }
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00001542 newfiles = (BYTE *)GlobalLock16( newhandle );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001543
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001544 if (count > pdb->nbFiles)
1545 {
1546 memcpy( newfiles, files, pdb->nbFiles );
1547 memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1548 }
1549 else memcpy( newfiles, files, count );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001550 if (pdb->nbFiles > 20) GlobalFree16( pdb->hFileHandles );
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00001551 pdb->fileHandlesPtr = WIN16_GlobalLock16( newhandle );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001552 pdb->hFileHandles = newhandle;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001553 pdb->nbFiles = count;
1554 }
1555 return pdb->nbFiles;
1556}
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001557
1558
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001559/*************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001560 * SetHandleCount (KERNEL32.494)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001561 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001562UINT WINAPI SetHandleCount( UINT count )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001563{
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001564 return min( 256, count );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001565}
1566
1567
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001568/***********************************************************************
1569 * FlushFileBuffers (KERNEL32.133)
1570 */
Jim Aston031f4fa1999-10-23 19:00:02 +00001571BOOL WINAPI FlushFileBuffers( HANDLE hFile )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001572{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001573 BOOL ret;
1574 SERVER_START_REQ
1575 {
1576 struct flush_file_request *req = server_alloc_req( sizeof(*req), 0 );
1577 req->handle = hFile;
1578 ret = !server_call( REQ_FLUSH_FILE );
1579 }
1580 SERVER_END_REQ;
1581 return ret;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001582}
1583
1584
1585/**************************************************************************
1586 * SetEndOfFile (KERNEL32.483)
1587 */
Jim Aston031f4fa1999-10-23 19:00:02 +00001588BOOL WINAPI SetEndOfFile( HANDLE hFile )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001589{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001590 BOOL ret;
1591 SERVER_START_REQ
1592 {
1593 struct truncate_file_request *req = server_alloc_req( sizeof(*req), 0 );
1594 req->handle = hFile;
1595 ret = !server_call( REQ_TRUNCATE_FILE );
1596 }
1597 SERVER_END_REQ;
1598 return ret;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001599}
1600
1601
1602/***********************************************************************
Alexandre Julliard3051b641996-07-05 17:14:13 +00001603 * DeleteFile16 (KERNEL.146)
1604 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001605BOOL16 WINAPI DeleteFile16( LPCSTR path )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001606{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001607 return DeleteFileA( path );
Alexandre Julliard3051b641996-07-05 17:14:13 +00001608}
1609
1610
1611/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001612 * DeleteFileA (KERNEL32.71)
Alexandre Julliard3051b641996-07-05 17:14:13 +00001613 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001614BOOL WINAPI DeleteFileA( LPCSTR path )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001615{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001616 DOS_FULL_NAME full_name;
Alexandre Julliard3051b641996-07-05 17:14:13 +00001617
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001618 TRACE("'%s'\n", path );
Alexandre Julliard3051b641996-07-05 17:14:13 +00001619
Alexandre Julliard638f1691999-01-17 16:32:32 +00001620 if (!*path)
1621 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001622 ERR("Empty path passed\n");
Alexandre Julliard638f1691999-01-17 16:32:32 +00001623 return FALSE;
1624 }
Alexandre Julliard829fe321998-07-26 14:27:39 +00001625 if (DOSFS_GetDevice( path ))
Alexandre Julliard3051b641996-07-05 17:14:13 +00001626 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001627 WARN("cannot remove DOS device '%s'!\n", path);
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001628 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliard3051b641996-07-05 17:14:13 +00001629 return FALSE;
1630 }
1631
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001632 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1633 if (unlink( full_name.long_name ) == -1)
Alexandre Julliard3051b641996-07-05 17:14:13 +00001634 {
1635 FILE_SetDosError();
1636 return FALSE;
1637 }
1638 return TRUE;
1639}
1640
1641
1642/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001643 * DeleteFileW (KERNEL32.72)
Alexandre Julliard3051b641996-07-05 17:14:13 +00001644 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001645BOOL WINAPI DeleteFileW( LPCWSTR path )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001646{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001647 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001648 BOOL ret = DeleteFileA( xpath );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001649 HeapFree( GetProcessHeap(), 0, xpath );
Alexandre Julliard3051b641996-07-05 17:14:13 +00001650 return ret;
1651}
1652
1653
1654/***********************************************************************
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001655 * GetFileType (KERNEL32.222)
1656 */
Jim Aston031f4fa1999-10-23 19:00:02 +00001657DWORD WINAPI GetFileType( HANDLE hFile )
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001658{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001659 DWORD ret = FILE_TYPE_UNKNOWN;
1660 SERVER_START_REQ
1661 {
1662 struct get_file_info_request *req = server_alloc_req( sizeof(*req), 0 );
1663 req->handle = hFile;
1664 if (!server_call( REQ_GET_FILE_INFO )) ret = req->type;
1665 }
1666 SERVER_END_REQ;
1667 return ret;
Alexandre Julliard8bbf8181996-09-13 16:50:47 +00001668}
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001669
1670
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001671/**************************************************************************
Alexandre Julliard86a75531999-11-21 02:11:48 +00001672 * MoveFileExA (KERNEL32.???)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001673 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001674BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001675{
1676 DOS_FULL_NAME full_name1, full_name2;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001677
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001678 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001679
1680 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
Alexandre Julliard86a75531999-11-21 02:11:48 +00001681
1682 if (fn2) /* !fn2 means delete fn1 */
1683 {
1684 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1685 {
1686 /* target exists, check if we may overwrite */
1687 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1688 {
1689 /* FIXME: Use right error code */
1690 SetLastError( ERROR_ACCESS_DENIED );
1691 return FALSE;
1692 }
1693 }
1694 else if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1695
1696 /* Source name and target path are valid */
1697
1698 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1699 {
1700 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1701 Perhaps we should queue these command and execute it
1702 when exiting... What about using on_exit(2)
1703 */
1704 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
1705 full_name1.long_name, full_name2.long_name);
1706 return TRUE;
1707 }
1708
1709 if (full_name1.drive != full_name2.drive)
1710 {
1711 /* use copy, if allowed */
1712 if (!(flag & MOVEFILE_COPY_ALLOWED))
1713 {
1714 /* FIXME: Use right error code */
1715 SetLastError( ERROR_FILE_EXISTS );
1716 return FALSE;
1717 }
1718 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
1719 }
1720 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1721 {
1722 FILE_SetDosError();
1723 return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001724 }
Alexandre Julliard86a75531999-11-21 02:11:48 +00001725 return TRUE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001726 }
1727 else /* fn2 == NULL means delete source */
Alexandre Julliard86a75531999-11-21 02:11:48 +00001728 {
1729 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1730 {
1731 if (flag & MOVEFILE_COPY_ALLOWED) {
1732 WARN("Illegal flag\n");
1733 SetLastError( ERROR_GEN_FAILURE );
1734 return FALSE;
1735 }
1736 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1737 Perhaps we should queue these command and execute it
1738 when exiting... What about using on_exit(2)
1739 */
1740 FIXME("Please delete file '%s' when Wine has finished\n",
1741 full_name1.long_name);
1742 return TRUE;
1743 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001744
Alexandre Julliard86a75531999-11-21 02:11:48 +00001745 if (unlink( full_name1.long_name ) == -1)
1746 {
1747 FILE_SetDosError();
1748 return FALSE;
1749 }
1750 return TRUE; /* successfully deleted */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001751 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001752}
1753
1754/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001755 * MoveFileExW (KERNEL32.???)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001756 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001757BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001758{
1759 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1760 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001761 BOOL res = MoveFileExA( afn1, afn2, flag );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001762 HeapFree( GetProcessHeap(), 0, afn1 );
1763 HeapFree( GetProcessHeap(), 0, afn2 );
1764 return res;
1765}
1766
1767
1768/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001769 * MoveFileA (KERNEL32.387)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001770 *
1771 * Move file or directory
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001772 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001773BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001774{
1775 DOS_FULL_NAME full_name1, full_name2;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001776 struct stat fstat;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001777
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001778 TRACE("(%s,%s)\n", fn1, fn2 );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001779
1780 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
Marcus Meissner242d23e2000-08-21 03:18:32 +00001781 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001782 /* The new name must not already exist */
Marcus Meissner242d23e2000-08-21 03:18:32 +00001783 SetLastError(ERROR_ALREADY_EXISTS);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001784 return FALSE;
Marcus Meissner242d23e2000-08-21 03:18:32 +00001785 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001786 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001787
1788 if (full_name1.drive == full_name2.drive) /* move */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001789 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1790 {
1791 FILE_SetDosError();
1792 return FALSE;
1793 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001794 else return TRUE;
1795 else /*copy */ {
1796 if (stat( full_name1.long_name, &fstat ))
1797 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001798 WARN("Invalid source file %s\n",
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001799 full_name1.long_name);
1800 FILE_SetDosError();
1801 return FALSE;
1802 }
1803 if (S_ISDIR(fstat.st_mode)) {
1804 /* No Move for directories across file systems */
1805 /* FIXME: Use right error code */
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001806 SetLastError( ERROR_GEN_FAILURE );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001807 return FALSE;
1808 }
1809 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001810 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001811 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001812}
1813
1814
1815/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001816 * MoveFileW (KERNEL32.390)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001817 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001818BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001819{
1820 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1821 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001822 BOOL res = MoveFileA( afn1, afn2 );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001823 HeapFree( GetProcessHeap(), 0, afn1 );
1824 HeapFree( GetProcessHeap(), 0, afn2 );
1825 return res;
1826}
1827
1828
1829/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001830 * CopyFileA (KERNEL32.36)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001831 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001832BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001833{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001834 HFILE h1, h2;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001835 BY_HANDLE_FILE_INFORMATION info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001836 UINT count;
1837 BOOL ret = FALSE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001838 int mode;
1839 char buffer[2048];
1840
Alexandre Julliarda3960291999-02-26 11:11:13 +00001841 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001842 if (!GetFileInformationByHandle( h1, &info ))
1843 {
1844 CloseHandle( h1 );
1845 return FALSE;
1846 }
1847 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001848 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
Alexandre Julliard05625391999-01-03 11:55:56 +00001849 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001850 info.dwFileAttributes, h1 )) == HFILE_ERROR)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001851 {
1852 CloseHandle( h1 );
1853 return FALSE;
1854 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001855 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001856 {
1857 char *p = buffer;
1858 while (count > 0)
1859 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001860 INT res = _lwrite( h2, p, count );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001861 if (res <= 0) goto done;
1862 p += res;
1863 count -= res;
1864 }
1865 }
1866 ret = TRUE;
1867done:
1868 CloseHandle( h1 );
1869 CloseHandle( h2 );
1870 return ret;
1871}
1872
1873
1874/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001875 * CopyFileW (KERNEL32.37)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001876 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001877BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001878{
1879 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
1880 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001881 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001882 HeapFree( GetProcessHeap(), 0, sourceA );
1883 HeapFree( GetProcessHeap(), 0, destA );
1884 return ret;
1885}
1886
1887
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001888/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001889 * CopyFileExA (KERNEL32.858)
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001890 *
1891 * This implementation ignores most of the extra parameters passed-in into
1892 * the "ex" version of the method and calls the CopyFile method.
1893 * It will have to be fixed eventually.
1894 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001895BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001896 LPCSTR destFilename,
1897 LPPROGRESS_ROUTINE progressRoutine,
1898 LPVOID appData,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001899 LPBOOL cancelFlagPointer,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001900 DWORD copyFlags)
1901{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001902 BOOL failIfExists = FALSE;
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001903
1904 /*
1905 * Interpret the only flag that CopyFile can interpret.
1906 */
1907 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
1908 {
1909 failIfExists = TRUE;
1910 }
1911
Alexandre Julliarda3960291999-02-26 11:11:13 +00001912 return CopyFileA(sourceFilename, destFilename, failIfExists);
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001913}
1914
1915/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001916 * CopyFileExW (KERNEL32.859)
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001917 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001918BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001919 LPCWSTR destFilename,
1920 LPPROGRESS_ROUTINE progressRoutine,
1921 LPVOID appData,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001922 LPBOOL cancelFlagPointer,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001923 DWORD copyFlags)
1924{
1925 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
1926 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
1927
Alexandre Julliarda3960291999-02-26 11:11:13 +00001928 BOOL ret = CopyFileExA(sourceA,
Alexandre Julliard0c0e3be1998-12-10 15:49:22 +00001929 destA,
1930 progressRoutine,
1931 appData,
1932 cancelFlagPointer,
1933 copyFlags);
1934
1935 HeapFree( GetProcessHeap(), 0, sourceA );
1936 HeapFree( GetProcessHeap(), 0, destA );
1937
1938 return ret;
1939}
1940
1941
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001942/***********************************************************************
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001943 * SetFileTime (KERNEL32.650)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001944 */
Jim Aston031f4fa1999-10-23 19:00:02 +00001945BOOL WINAPI SetFileTime( HANDLE hFile,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001946 const FILETIME *lpCreationTime,
1947 const FILETIME *lpLastAccessTime,
1948 const FILETIME *lpLastWriteTime )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001949{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001950 BOOL ret;
1951 SERVER_START_REQ
1952 {
1953 struct set_file_time_request *req = server_alloc_req( sizeof(*req), 0 );
1954 req->handle = hFile;
1955 if (lpLastAccessTime)
Alexandre Julliard27952ef2000-10-13 20:26:03 +00001956 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001957 else
1958 req->access_time = 0; /* FIXME */
1959 if (lpLastWriteTime)
Alexandre Julliard27952ef2000-10-13 20:26:03 +00001960 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001961 else
1962 req->write_time = 0; /* FIXME */
1963 ret = !server_call( REQ_SET_FILE_TIME );
1964 }
1965 SERVER_END_REQ;
1966 return ret;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001967}
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001968
Alexandre Julliard62a8b431999-01-19 17:48:23 +00001969
1970/**************************************************************************
1971 * LockFile (KERNEL32.511)
1972 */
Jim Aston031f4fa1999-10-23 19:00:02 +00001973BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
Alexandre Julliard62a8b431999-01-19 17:48:23 +00001974 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
1975{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001976 BOOL ret;
1977 SERVER_START_REQ
1978 {
1979 struct lock_file_request *req = server_alloc_req( sizeof(*req), 0 );
Alexandre Julliard62a8b431999-01-19 17:48:23 +00001980
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001981 req->handle = hFile;
1982 req->offset_low = dwFileOffsetLow;
1983 req->offset_high = dwFileOffsetHigh;
1984 req->count_low = nNumberOfBytesToLockLow;
1985 req->count_high = nNumberOfBytesToLockHigh;
1986 ret = !server_call( REQ_LOCK_FILE );
1987 }
1988 SERVER_END_REQ;
1989 return ret;
Alexandre Julliard62a8b431999-01-19 17:48:23 +00001990}
1991
James Jurane8df90b1999-06-05 08:57:37 +00001992/**************************************************************************
1993 * LockFileEx [KERNEL32.512]
1994 *
1995 * Locks a byte range within an open file for shared or exclusive access.
1996 *
1997 * RETURNS
1998 * success: TRUE
1999 * failure: FALSE
2000 * NOTES
2001 *
2002 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2003 */
2004BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2005 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2006 LPOVERLAPPED pOverlapped )
2007{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002008 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
James Jurane8df90b1999-06-05 08:57:37 +00002009 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2010 pOverlapped);
2011 if (reserved == 0)
2012 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2013 else
2014 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002015 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
James Jurane8df90b1999-06-05 08:57:37 +00002016 SetLastError(ERROR_INVALID_PARAMETER);
2017 }
2018
2019 return FALSE;
2020}
2021
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002022
2023/**************************************************************************
2024 * UnlockFile (KERNEL32.703)
2025 */
Jim Aston031f4fa1999-10-23 19:00:02 +00002026BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002027 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2028{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002029 BOOL ret;
2030 SERVER_START_REQ
2031 {
2032 struct unlock_file_request *req = server_alloc_req( sizeof(*req), 0 );
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002033
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00002034 req->handle = hFile;
2035 req->offset_low = dwFileOffsetLow;
2036 req->offset_high = dwFileOffsetHigh;
2037 req->count_low = nNumberOfBytesToUnlockLow;
2038 req->count_high = nNumberOfBytesToUnlockHigh;
2039 ret = !server_call( REQ_UNLOCK_FILE );
2040 }
2041 SERVER_END_REQ;
2042 return ret;
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002043}
2044
2045
Andreas Mohre00114c1999-07-03 11:56:07 +00002046/**************************************************************************
2047 * UnlockFileEx (KERNEL32.705)
2048 */
2049BOOL WINAPI UnlockFileEx(
2050 HFILE hFile,
2051 DWORD dwReserved,
2052 DWORD nNumberOfBytesToUnlockLow,
2053 DWORD nNumberOfBytesToUnlockHigh,
2054 LPOVERLAPPED lpOverlapped
2055)
2056{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002057 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
Andreas Mohre00114c1999-07-03 11:56:07 +00002058 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2059 lpOverlapped);
2060 if (dwReserved == 0)
2061 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2062 else
2063 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002064 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
Andreas Mohre00114c1999-07-03 11:56:07 +00002065 SetLastError(ERROR_INVALID_PARAMETER);
2066 }
2067
2068 return FALSE;
2069}
2070
2071
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002072#if 0
2073
2074struct DOS_FILE_LOCK {
2075 struct DOS_FILE_LOCK * next;
2076 DWORD base;
2077 DWORD len;
2078 DWORD processId;
2079 FILE_OBJECT * dos_file;
2080/* char * unix_name;*/
2081};
2082
2083typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2084
2085static DOS_FILE_LOCK *locks = NULL;
2086static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2087
2088
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002089/* Locks need to be mirrored because unix file locking is based
2090 * on the pid. Inside of wine there can be multiple WINE processes
2091 * that share the same unix pid.
2092 * Read's and writes should check these locks also - not sure
2093 * how critical that is at this point (FIXME).
2094 */
2095
Alexandre Julliarda3960291999-02-26 11:11:13 +00002096static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002097{
2098 DOS_FILE_LOCK *curr;
2099 DWORD processId;
2100
2101 processId = GetCurrentProcessId();
2102
2103 /* check if lock overlaps a current lock for the same file */
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002104#if 0
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002105 for (curr = locks; curr; curr = curr->next) {
2106 if (strcmp(curr->unix_name, file->unix_name) == 0) {
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00002107 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2108 return TRUE;/* region is identic */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002109 if ((f->l_start < (curr->base + curr->len)) &&
2110 ((f->l_start + f->l_len) > curr->base)) {
2111 /* region overlaps */
2112 return FALSE;
2113 }
2114 }
2115 }
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002116#endif
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002117
Alexandre Julliard90476d62000-02-16 22:47:24 +00002118 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002119 curr->processId = GetCurrentProcessId();
2120 curr->base = f->l_start;
2121 curr->len = f->l_len;
Alexandre Julliard90476d62000-02-16 22:47:24 +00002122/* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002123 curr->next = locks;
2124 curr->dos_file = file;
2125 locks = curr;
2126 return TRUE;
2127}
2128
2129static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2130{
2131 DWORD processId;
2132 DOS_FILE_LOCK **curr;
2133 DOS_FILE_LOCK *rem;
2134
2135 processId = GetCurrentProcessId();
2136 curr = &locks;
2137 while (*curr) {
2138 if ((*curr)->dos_file == file) {
2139 rem = *curr;
2140 *curr = (*curr)->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +00002141/* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2142 HeapFree( GetProcessHeap(), 0, rem );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002143 }
2144 else
2145 curr = &(*curr)->next;
2146 }
2147}
2148
Alexandre Julliarda3960291999-02-26 11:11:13 +00002149static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002150{
2151 DWORD processId;
2152 DOS_FILE_LOCK **curr;
2153 DOS_FILE_LOCK *rem;
2154
2155 processId = GetCurrentProcessId();
2156 for (curr = &locks; *curr; curr = &(*curr)->next) {
2157 if ((*curr)->processId == processId &&
2158 (*curr)->dos_file == file &&
2159 (*curr)->base == f->l_start &&
2160 (*curr)->len == f->l_len) {
2161 /* this is the same lock */
2162 rem = *curr;
2163 *curr = (*curr)->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +00002164/* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2165 HeapFree( GetProcessHeap(), 0, rem );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002166 return TRUE;
2167 }
2168 }
2169 /* no matching lock found */
2170 return FALSE;
2171}
2172
2173
2174/**************************************************************************
2175 * LockFile (KERNEL32.511)
2176 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002177BOOL WINAPI LockFile(
2178 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002179 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2180{
2181 struct flock f;
2182 FILE_OBJECT *file;
2183
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002184 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002185 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2186 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2187
2188 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002189 FIXME("Unimplemented bytes > 32bits\n");
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002190 return FALSE;
2191 }
2192
2193 f.l_start = dwFileOffsetLow;
2194 f.l_len = nNumberOfBytesToLockLow;
2195 f.l_whence = SEEK_SET;
2196 f.l_pid = 0;
2197 f.l_type = F_WRLCK;
2198
Alexandre Julliard338e7571998-12-27 15:28:54 +00002199 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002200
2201 /* shadow locks internally */
2202 if (!DOS_AddLock(file, &f)) {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00002203 SetLastError( ERROR_LOCK_VIOLATION );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002204 return FALSE;
2205 }
2206
2207 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2208#ifdef USE_UNIX_LOCKS
2209 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2210 if (errno == EACCES || errno == EAGAIN) {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00002211 SetLastError( ERROR_LOCK_VIOLATION );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002212 }
2213 else {
2214 FILE_SetDosError();
2215 }
2216 /* remove our internal copy of the lock */
2217 DOS_RemoveLock(file, &f);
2218 return FALSE;
2219 }
2220#endif
2221 return TRUE;
2222}
2223
2224
2225/**************************************************************************
2226 * UnlockFile (KERNEL32.703)
2227 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002228BOOL WINAPI UnlockFile(
2229 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002230 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2231{
2232 FILE_OBJECT *file;
2233 struct flock f;
2234
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002235 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002236 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2237 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2238
2239 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002240 WARN("Unimplemented bytes > 32bits\n");
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002241 return FALSE;
2242 }
2243
2244 f.l_start = dwFileOffsetLow;
2245 f.l_len = nNumberOfBytesToUnlockLow;
2246 f.l_whence = SEEK_SET;
2247 f.l_pid = 0;
2248 f.l_type = F_UNLCK;
2249
Alexandre Julliard338e7571998-12-27 15:28:54 +00002250 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002251
2252 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2253
2254 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2255#ifdef USE_UNIX_LOCKS
2256 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2257 FILE_SetDosError();
2258 return FALSE;
2259 }
2260#endif
2261 return TRUE;
2262}
Alexandre Julliard62a8b431999-01-19 17:48:23 +00002263#endif
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002264
Alexandre Julliarda845b881998-06-01 10:44:35 +00002265/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00002266 * GetFileAttributesExA [KERNEL32.874]
Alexandre Julliarda845b881998-06-01 10:44:35 +00002267 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002268BOOL WINAPI GetFileAttributesExA(
Alexandre Julliarda845b881998-06-01 10:44:35 +00002269 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2270 LPVOID lpFileInformation)
2271{
2272 DOS_FULL_NAME full_name;
2273 BY_HANDLE_FILE_INFORMATION info;
2274
2275 if (lpFileName == NULL) return FALSE;
2276 if (lpFileInformation == NULL) return FALSE;
2277
2278 if (fInfoLevelId == GetFileExInfoStandard) {
2279 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2280 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2281 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2282 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2283
2284 lpFad->dwFileAttributes = info.dwFileAttributes;
2285 lpFad->ftCreationTime = info.ftCreationTime;
2286 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2287 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2288 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2289 lpFad->nFileSizeLow = info.nFileSizeLow;
2290 }
2291 else {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00002292 FIXME("invalid info level %d!\n", fInfoLevelId);
Alexandre Julliarda845b881998-06-01 10:44:35 +00002293 return FALSE;
2294 }
2295
2296 return TRUE;
2297}
2298
2299
2300/**************************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00002301 * GetFileAttributesExW [KERNEL32.875]
Alexandre Julliarda845b881998-06-01 10:44:35 +00002302 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002303BOOL WINAPI GetFileAttributesExW(
Alexandre Julliarda845b881998-06-01 10:44:35 +00002304 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2305 LPVOID lpFileInformation)
2306{
2307 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002308 BOOL res =
2309 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
Alexandre Julliarda845b881998-06-01 10:44:35 +00002310 HeapFree( GetProcessHeap(), 0, nameA );
2311 return res;
2312}