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