Release 960309
[wine] / win32 / file.c
1 /*
2  * Win32 kernel functions
3  *
4  * Copyright 1995 Martin von Loewis, Sven Verdoolaege, and Cameron Heide
5  */
6
7 #include <errno.h>
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/mman.h>
13 #include <fcntl.h>
14 #include <string.h>
15 #include <time.h>
16 #include "windows.h"
17 #include "winerror.h"
18 #include "kernel32.h"
19 #include "handle32.h"
20 #include "dos_fs.h"
21 #include "stddebug.h"
22 #define DEBUG_WIN32
23 #include "debug.h"
24
25
26 extern FILE_OBJECT *hstdin;
27 extern FILE_OBJECT *hstdout;
28 extern FILE_OBJECT *hstderr;
29
30 static void UnixTimeToFileTime(time_t unix_time, FILETIME *filetime);
31 static int TranslateCreationFlags(DWORD create_flags);
32 static int TranslateAccessFlags(DWORD access_flags);
33 #ifndef MAP_ANON
34 #define MAP_ANON 0
35 #endif
36
37 /***********************************************************************
38  *           OpenFileMappingA             (KERNEL32.397)
39  *
40  */
41 WINAPI HANDLE32 OpenFileMapping(DWORD access, BOOL inherit,const char *fname)
42 {
43         return 0;
44 }
45 /***********************************************************************
46  *           CreateFileMappingA         (KERNEL32.46)
47  *
48  */
49 int TranslateProtectionFlags(DWORD);
50 WINAPI HANDLE32 CreateFileMapping(HANDLE32 h,SECURITY_ATTRIBUTES *ats,
51   DWORD pot,  DWORD sh,  DWORD hlow,  const char * lpName )
52 {
53     FILE_OBJECT *file_obj;
54     FILEMAP_OBJECT *filemap_obj;
55     int fd;
56
57     if (sh)
58     {
59         SetLastError(ErrnoToLastError(errno));
60         return INVALID_HANDLE_VALUE;
61     }
62     fd = open(lpName, O_CREAT, 0666);
63     if(fd == -1)
64     {
65         SetLastError(ErrnoToLastError(errno));
66         return INVALID_HANDLE_VALUE;
67     }
68     file_obj = (FILE_OBJECT *)
69                          CreateKernelObject(sizeof(FILE_OBJECT));
70     if(file_obj == NULL)
71     {
72         SetLastError(ERROR_UNKNOWN);
73         return 0;
74     }
75     filemap_obj = (FILEMAP_OBJECT *)
76                          CreateKernelObject(sizeof(FILEMAP_OBJECT));
77     if(filemap_obj == NULL)
78     {
79         ReleaseKernelObject(file_obj);
80         SetLastError(ERROR_UNKNOWN);
81         return 0;
82     }
83     file_obj->common.magic = KERNEL_OBJECT_FILE;
84     file_obj->fd = fd;
85     file_obj->type = FILE_TYPE_DISK;
86     filemap_obj->common.magic = KERNEL_OBJECT_FILEMAP;
87     filemap_obj->file_obj = file_obj;
88     filemap_obj->prot = TranslateProtectionFlags(pot);
89     filemap_obj->size = hlow;
90     return (HANDLE32)filemap_obj;;
91 }
92
93 /***********************************************************************
94  *           MapViewOfFileEx                  (KERNEL32.386)
95  *
96  */
97 WINAPI void *MapViewOfFileEx(HANDLE32 handle, DWORD access, DWORD offhi,
98                              DWORD offlo, DWORD size, DWORD st)
99 {
100     if (!size) size = ((FILEMAP_OBJECT *)handle)->size;
101     return mmap ((caddr_t)st, size, ((FILEMAP_OBJECT *)handle)->prot, 
102                  MAP_ANON|MAP_PRIVATE, 
103                  ((FILEMAP_OBJECT *)handle)->file_obj->fd,
104                  offlo);
105 }
106
107 /***********************************************************************
108  *           GetFileInformationByHandle       (KERNEL32.219)
109  *
110  */
111 DWORD WINAPI GetFileInformationByHandle(FILE_OBJECT *hFile, 
112                                         BY_HANDLE_FILE_INFORMATION *lpfi)
113 {
114   struct stat file_stat;
115     int rc;
116
117     if(ValidateKernelObject((HANDLE32)hFile) != 0)
118     {
119         SetLastError(ERROR_INVALID_HANDLE);
120         return 0;
121     }
122     if(hFile->common.magic != KERNEL_OBJECT_FILE)
123     {
124         SetLastError(ERROR_INVALID_HANDLE);
125         return 0;
126     }
127
128     rc = fstat(hFile->fd, &file_stat);
129     if(rc == -1)
130     {
131         SetLastError(ErrnoToLastError(errno));
132         return 0;
133     }
134
135     /* Translate the file attributes.
136      */
137     lpfi->dwFileAttributes = 0;
138     if(file_stat.st_mode & S_IFREG)
139         lpfi->dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
140     if(file_stat.st_mode & S_IFDIR)
141         lpfi->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
142     if((file_stat.st_mode & S_IWRITE) == 0)
143         lpfi->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
144
145     /* Translate the file times.  Use the last modification time
146      * for both the creation time and write time.
147      */
148     UnixTimeToFileTime(file_stat.st_mtime, &(lpfi->ftCreationTime));
149     UnixTimeToFileTime(file_stat.st_mtime, &(lpfi->ftLastWriteTime));
150     UnixTimeToFileTime(file_stat.st_atime, &(lpfi->ftLastAccessTime));
151
152     lpfi->nFileSizeLow = file_stat.st_size;
153     lpfi->nNumberOfLinks = file_stat.st_nlink;
154     lpfi->nFileIndexLow = file_stat.st_ino;
155
156     /* Zero out currently unused fields.
157      */
158     lpfi->dwVolumeSerialNumber = 0;
159     lpfi->nFileSizeHigh = 0;
160     lpfi->nFileIndexHigh = 0;
161
162     return 1;
163 }
164
165
166 static void UnixTimeToFileTime(time_t unix_time, FILETIME *filetime)
167 {
168     /* This isn't anywhere close to being correct, but should
169      * work for now.
170      */
171     filetime->dwLowDateTime  = (unix_time & 0x0000FFFF) << 16;
172     filetime->dwHighDateTime = (unix_time & 0xFFFF0000) >> 16;
173 }
174
175
176 /***********************************************************************
177  *           GetFileType              (KERNEL32.222)
178  *
179  * GetFileType currently only supports stdin, stdout, and stderr, which
180  * are considered to be of type FILE_TYPE_CHAR.
181  */
182 DWORD GetFileType(FILE_OBJECT *hFile)
183 {
184     if(ValidateKernelObject((HANDLE32)hFile) != 0)
185     {
186         SetLastError(ERROR_UNKNOWN);
187         return FILE_TYPE_UNKNOWN;
188     }
189     if(hFile->common.magic != KERNEL_OBJECT_FILE)
190     {
191         SetLastError(ERROR_UNKNOWN);
192         return FILE_TYPE_UNKNOWN;
193     }
194
195     return hFile->type;
196 }
197
198 /***********************************************************************
199  *           GetStdHandle             (KERNEL32.276)
200  */
201 HANDLE32 GetStdHandle(DWORD nStdHandle)
202 {
203     HANDLE32 rc;
204
205     switch(nStdHandle)
206     {
207         case STD_INPUT_HANDLE:
208             rc = (HANDLE32)hstdin;
209             break;
210
211         case STD_OUTPUT_HANDLE:
212             rc = (HANDLE32)hstdout;
213             break;
214
215         case STD_ERROR_HANDLE:
216             rc = (HANDLE32)hstderr;
217             break;
218
219         default:
220             rc = INVALID_HANDLE_VALUE;
221             SetLastError(ERROR_INVALID_HANDLE);
222             break;
223     }
224
225     return rc;
226 }
227
228 /***********************************************************************
229  *              SetFilePointer          (KERNEL32.492)
230  *
231  * Luckily enough, this function maps almost directly into an lseek
232  * call, the exception being the use of 64-bit offsets.
233  */
234 DWORD SetFilePointer(FILE_OBJECT *hFile, LONG distance, LONG *highword,
235                      DWORD method)
236 {
237     int rc;
238
239     if(ValidateKernelObject((HANDLE32)hFile) != 0)
240     {
241         SetLastError(ERROR_INVALID_HANDLE);
242         return ((DWORD)0xFFFFFFFF);
243     }
244     if(hFile->common.magic != KERNEL_OBJECT_FILE)
245     {
246         SetLastError(ERROR_INVALID_HANDLE);
247         return ((DWORD)0xFFFFFFFF);
248     }
249
250     if(highword != NULL)
251     {
252         if(*highword != 0)
253         {
254             dprintf_win32(stddeb, "SetFilePointer: 64-bit offsets not yet supported.\n");
255             return -1;
256         }
257     }
258
259     rc = lseek(hFile->fd, distance, method);
260     if(rc == -1)
261         SetLastError(ErrnoToLastError(errno));
262     return rc;
263 }
264
265 /***********************************************************************
266  *             WriteFile               (KERNEL32.578)
267  */
268 BOOL WriteFile(FILE_OBJECT *hFile, LPVOID lpBuffer, DWORD numberOfBytesToWrite,
269                LPDWORD numberOfBytesWritten, LPOVERLAPPED lpOverlapped)
270 {
271     int written;
272
273     if(ValidateKernelObject((HANDLE32)hFile) != 0)
274     {
275         SetLastError(ERROR_INVALID_HANDLE);
276         return 0;
277     }
278     if(hFile->common.magic != KERNEL_OBJECT_FILE)
279     {
280         SetLastError(ERROR_INVALID_HANDLE);
281         return 0;
282     }
283
284     written = write(hFile->fd, lpBuffer, numberOfBytesToWrite);
285     if(numberOfBytesWritten)
286         *numberOfBytesWritten = written;
287
288     return 1;
289 }
290
291 /***********************************************************************
292  *              ReadFile                (KERNEL32.428)
293  */
294 BOOL ReadFile(FILE_OBJECT *hFile, LPVOID lpBuffer, DWORD numtoread,
295               LPDWORD numread, LPOVERLAPPED lpOverlapped)
296 {
297     int actual_read;
298
299     if(ValidateKernelObject((HANDLE32)hFile) != 0)
300     {
301         SetLastError(ERROR_INVALID_HANDLE);
302         return 0;
303     }
304     if(hFile->common.magic != KERNEL_OBJECT_FILE)
305     {
306         SetLastError(ERROR_INVALID_HANDLE);
307         return 0;
308     }
309
310     actual_read = read(hFile->fd, lpBuffer, numtoread);
311     if(actual_read == -1)
312     {
313         SetLastError(ErrnoToLastError(errno));
314         return 0;
315     }
316     if(numread)
317         *numread = actual_read;
318
319     return 1;
320 }
321
322 /*************************************************************************
323  *              CreateFile              (KERNEL32.45)
324  *
325  * Doesn't support character devices, pipes, template files, or a
326  * lot of the 'attributes' flags yet.
327  */
328 HANDLE32 CreateFileA(LPSTR filename, DWORD access, DWORD sharing,
329                      LPSECURITY_ATTRIBUTES security, DWORD creation,
330                      DWORD attributes, HANDLE32 template)
331 {
332     int access_flags, create_flags;
333     int fd;
334     FILE_OBJECT *file_obj;
335     int type;
336
337     /* Translate the various flags to Unix-style.
338      */
339     access_flags = TranslateAccessFlags(access);
340     create_flags = TranslateCreationFlags(creation);
341
342     if(template)
343         dprintf_win32(stddeb, "CreateFile: template handles not supported.\n");
344
345     /* If the name starts with '\\?' or '\\.', ignore the first 3 chars.
346      */
347     if(!strncmp(filename, "\\\\?", 3) || !strncmp(filename, "\\\\.", 3))
348         filename += 3;
349
350     /* If the name still starts with '\\', it's a UNC name.
351      */
352     if(!strncmp(filename, "\\\\", 2))
353     {
354         dprintf_win32(stddeb, "CreateFile: UNC names not supported.\n");
355         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
356         return INVALID_HANDLE_VALUE;
357     }
358
359     /* If the name is either CONIN$ or CONOUT$, give them stdin
360      * or stdout, respectively.
361      */
362     if(!strcmp(filename, "CONIN$"))
363     {
364         type = FILE_TYPE_CHAR;
365         fd = 0;
366     }
367     else if(!strcmp(filename, "CONOUT$"))
368     {
369         type = FILE_TYPE_CHAR;
370         fd = 1;
371     }
372     else
373     {
374         const char *unixName = DOSFS_GetUnixFileName( filename, FALSE );
375         type = FILE_TYPE_DISK;
376
377         /* Try to open the file.
378          */
379         if (!unixName ||
380             ((fd = open(unixName, access_flags | create_flags, 0666)) == -1))
381         {
382             SetLastError(ErrnoToLastError(errno));
383             return INVALID_HANDLE_VALUE;
384         }
385     }
386
387     /* We seem to have succeeded, so allocate a kernel object
388      * and set it up.
389      */
390     file_obj = (FILE_OBJECT *)CreateKernelObject(sizeof(FILE_OBJECT));
391     if(file_obj == NULL)
392     {
393         SetLastError(ERROR_INVALID_HANDLE);
394         return INVALID_HANDLE_VALUE;
395     }
396     file_obj->common.magic = KERNEL_OBJECT_FILE;
397     file_obj->fd = fd;
398     file_obj->type = type;
399     file_obj->misc_flags = attributes;
400     file_obj->access_flags = access_flags;
401     file_obj->create_flags = create_flags;
402
403     return (HANDLE32)file_obj;
404 }
405
406 /*************************************************************************
407  *              W32_SetHandleCount             (KERNEL32.??)
408  *
409  */
410 UINT W32_SetHandleCount(UINT cHandles)
411 {
412     return SetHandleCount(cHandles);
413 }
414
415 int CloseFileHandle(FILE_OBJECT *hFile)
416 {
417     /* If it's one of the 3 standard handles, don't really
418      * close it.
419      */
420     if(hFile->fd > 2)
421         close(hFile->fd);
422
423     return 1;
424 }
425
426 static int TranslateAccessFlags(DWORD access_flags)
427 {
428     int rc = 0;
429
430     switch(access_flags)
431     {
432         case GENERIC_READ:
433             rc = O_RDONLY;
434             break;
435
436         case GENERIC_WRITE:
437             rc = O_WRONLY;
438             break;
439
440         case (GENERIC_READ | GENERIC_WRITE):
441             rc = O_RDWR;
442             break;
443     }
444
445     return rc;
446 }
447
448 static int TranslateCreationFlags(DWORD create_flags)
449 {
450     int rc = 0;
451
452     switch(create_flags)
453     {
454         case CREATE_NEW:
455             rc = O_CREAT | O_EXCL;
456             break;
457
458         case CREATE_ALWAYS:
459             rc = O_CREAT | O_TRUNC;
460             break;
461
462         case OPEN_EXISTING:
463             rc = 0;
464             break;
465
466         case OPEN_ALWAYS:
467             rc = O_CREAT;
468             break;
469
470         case TRUNCATE_EXISTING:
471             rc = O_TRUNC;
472             break;
473     }
474
475     return rc;
476 }