Release 960506
[wine.git] / win32 / file.c
blobab338534c5447d000755fb4c7bde3b911b45c2f5
1 /*
2 * Win32 kernel functions
4 * Copyright 1995 Martin von Loewis, Sven Verdoolaege, and Cameron Heide
5 */
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"
26 extern FILE_OBJECT *hstdin;
27 extern FILE_OBJECT *hstdout;
28 extern FILE_OBJECT *hstderr;
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
37 /***********************************************************************
38 * OpenFileMappingA (KERNEL32.397)
41 HANDLE32 OpenFileMapping(DWORD access, BOOL inherit,const char *fname)
43 return 0;
45 /***********************************************************************
46 * CreateFileMappingA (KERNEL32.46)
49 int TranslateProtectionFlags(DWORD);
50 HANDLE32 CreateFileMapping(HANDLE32 h,SECURITY_ATTRIBUTES *ats,
51 DWORD pot, DWORD sh, DWORD hlow, const char * lpName )
53 FILE_OBJECT *file_obj;
54 FILEMAP_OBJECT *filemap_obj;
55 int fd;
57 if (sh)
59 SetLastError(ErrnoToLastError(errno));
60 return INVALID_HANDLE_VALUE;
62 fd = open(lpName, O_CREAT, 0666);
63 if(fd == -1)
65 SetLastError(ErrnoToLastError(errno));
66 return INVALID_HANDLE_VALUE;
68 file_obj = (FILE_OBJECT *)
69 CreateKernelObject(sizeof(FILE_OBJECT));
70 if(file_obj == NULL)
72 SetLastError(ERROR_UNKNOWN);
73 return 0;
75 filemap_obj = (FILEMAP_OBJECT *)
76 CreateKernelObject(sizeof(FILEMAP_OBJECT));
77 if(filemap_obj == NULL)
79 ReleaseKernelObject(file_obj);
80 SetLastError(ERROR_UNKNOWN);
81 return 0;
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;;
93 /***********************************************************************
94 * MapViewOfFileEx (KERNEL32.386)
97 void *MapViewOfFileEx(HANDLE32 handle, DWORD access, DWORD offhi,
98 DWORD offlo, DWORD size, DWORD st)
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);
107 /***********************************************************************
108 * GetFileInformationByHandle (KERNEL32.219)
111 DWORD GetFileInformationByHandle(FILE_OBJECT *hFile,
112 BY_HANDLE_FILE_INFORMATION *lpfi)
114 struct stat file_stat;
115 int rc;
117 if(ValidateKernelObject((HANDLE32)hFile) != 0)
119 SetLastError(ERROR_INVALID_HANDLE);
120 return 0;
122 if(hFile->common.magic != KERNEL_OBJECT_FILE)
124 SetLastError(ERROR_INVALID_HANDLE);
125 return 0;
128 rc = fstat(hFile->fd, &file_stat);
129 if(rc == -1)
131 SetLastError(ErrnoToLastError(errno));
132 return 0;
135 /* Translate the file attributes.
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;
145 /* Translate the file times. Use the last modification time
146 * for both the creation time and write time.
148 UnixTimeToFileTime(file_stat.st_mtime, &(lpfi->ftCreationTime));
149 UnixTimeToFileTime(file_stat.st_mtime, &(lpfi->ftLastWriteTime));
150 UnixTimeToFileTime(file_stat.st_atime, &(lpfi->ftLastAccessTime));
152 lpfi->nFileSizeLow = file_stat.st_size;
153 lpfi->nNumberOfLinks = file_stat.st_nlink;
154 lpfi->nFileIndexLow = file_stat.st_ino;
156 /* Zero out currently unused fields.
158 lpfi->dwVolumeSerialNumber = 0;
159 lpfi->nFileSizeHigh = 0;
160 lpfi->nFileIndexHigh = 0;
162 return 1;
166 static void UnixTimeToFileTime(time_t unix_time, FILETIME *filetime)
168 /* This isn't anywhere close to being correct, but should
169 * work for now.
171 filetime->dwLowDateTime = (unix_time & 0x0000FFFF) << 16;
172 filetime->dwHighDateTime = (unix_time & 0xFFFF0000) >> 16;
176 /***********************************************************************
177 * GetFileType (KERNEL32.222)
179 * GetFileType currently only supports stdin, stdout, and stderr, which
180 * are considered to be of type FILE_TYPE_CHAR.
182 DWORD GetFileType(FILE_OBJECT *hFile)
184 if(ValidateKernelObject((HANDLE32)hFile) != 0)
186 SetLastError(ERROR_UNKNOWN);
187 return FILE_TYPE_UNKNOWN;
189 if(hFile->common.magic != KERNEL_OBJECT_FILE)
191 SetLastError(ERROR_UNKNOWN);
192 return FILE_TYPE_UNKNOWN;
195 return hFile->type;
198 /***********************************************************************
199 * GetStdHandle (KERNEL32.276)
201 HANDLE32 GetStdHandle(DWORD nStdHandle)
203 HANDLE32 rc;
205 switch(nStdHandle)
207 case STD_INPUT_HANDLE:
208 rc = (HANDLE32)hstdin;
209 break;
211 case STD_OUTPUT_HANDLE:
212 rc = (HANDLE32)hstdout;
213 break;
215 case STD_ERROR_HANDLE:
216 rc = (HANDLE32)hstderr;
217 break;
219 default:
220 rc = INVALID_HANDLE_VALUE;
221 SetLastError(ERROR_INVALID_HANDLE);
222 break;
225 return rc;
228 /***********************************************************************
229 * SetFilePointer (KERNEL32.492)
231 * Luckily enough, this function maps almost directly into an lseek
232 * call, the exception being the use of 64-bit offsets.
234 DWORD SetFilePointer(FILE_OBJECT *hFile, LONG distance, LONG *highword,
235 DWORD method)
237 int rc;
239 if(ValidateKernelObject((HANDLE32)hFile) != 0)
241 SetLastError(ERROR_INVALID_HANDLE);
242 return ((DWORD)0xFFFFFFFF);
244 if(hFile->common.magic != KERNEL_OBJECT_FILE)
246 SetLastError(ERROR_INVALID_HANDLE);
247 return ((DWORD)0xFFFFFFFF);
250 if(highword != NULL)
252 if(*highword != 0)
254 dprintf_win32(stddeb, "SetFilePointer: 64-bit offsets not yet supported.\n");
255 return -1;
259 rc = lseek(hFile->fd, distance, method);
260 if(rc == -1)
261 SetLastError(ErrnoToLastError(errno));
262 return rc;
265 /***********************************************************************
266 * WriteFile (KERNEL32.578)
268 BOOL WriteFile(FILE_OBJECT *hFile, LPVOID lpBuffer, DWORD numberOfBytesToWrite,
269 LPDWORD numberOfBytesWritten, LPOVERLAPPED lpOverlapped)
271 int written;
273 if(ValidateKernelObject((HANDLE32)hFile) != 0)
275 SetLastError(ERROR_INVALID_HANDLE);
276 return 0;
278 if(hFile->common.magic != KERNEL_OBJECT_FILE)
280 SetLastError(ERROR_INVALID_HANDLE);
281 return 0;
284 written = write(hFile->fd, lpBuffer, numberOfBytesToWrite);
285 if(numberOfBytesWritten)
286 *numberOfBytesWritten = written;
288 return 1;
291 /***********************************************************************
292 * ReadFile (KERNEL32.428)
294 BOOL ReadFile(FILE_OBJECT *hFile, LPVOID lpBuffer, DWORD numtoread,
295 LPDWORD numread, LPOVERLAPPED lpOverlapped)
297 int actual_read;
299 if(ValidateKernelObject((HANDLE32)hFile) != 0)
301 SetLastError(ERROR_INVALID_HANDLE);
302 return 0;
304 if(hFile->common.magic != KERNEL_OBJECT_FILE)
306 SetLastError(ERROR_INVALID_HANDLE);
307 return 0;
310 actual_read = read(hFile->fd, lpBuffer, numtoread);
311 if(actual_read == -1)
313 SetLastError(ErrnoToLastError(errno));
314 return 0;
316 if(numread)
317 *numread = actual_read;
319 return 1;
322 /*************************************************************************
323 * CreateFile (KERNEL32.45)
325 * Doesn't support character devices, pipes, template files, or a
326 * lot of the 'attributes' flags yet.
328 HANDLE32 CreateFileA(LPSTR filename, DWORD access, DWORD sharing,
329 LPSECURITY_ATTRIBUTES security, DWORD creation,
330 DWORD attributes, HANDLE32 template)
332 int access_flags, create_flags;
333 int fd;
334 FILE_OBJECT *file_obj;
335 int type;
337 /* Translate the various flags to Unix-style.
339 access_flags = TranslateAccessFlags(access);
340 create_flags = TranslateCreationFlags(creation);
342 if(template)
343 dprintf_win32(stddeb, "CreateFile: template handles not supported.\n");
345 /* If the name starts with '\\?' or '\\.', ignore the first 3 chars.
347 if(!strncmp(filename, "\\\\?", 3) || !strncmp(filename, "\\\\.", 3))
348 filename += 3;
350 /* If the name still starts with '\\', it's a UNC name.
352 if(!strncmp(filename, "\\\\", 2))
354 dprintf_win32(stddeb, "CreateFile: UNC names not supported.\n");
355 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
356 return INVALID_HANDLE_VALUE;
359 /* If the name is either CONIN$ or CONOUT$, give them stdin
360 * or stdout, respectively.
362 if(!strcmp(filename, "CONIN$"))
364 type = FILE_TYPE_CHAR;
365 fd = 0;
367 else if(!strcmp(filename, "CONOUT$"))
369 type = FILE_TYPE_CHAR;
370 fd = 1;
372 else
374 const char *unixName = DOSFS_GetUnixFileName( filename, FALSE );
375 type = FILE_TYPE_DISK;
377 /* Try to open the file.
379 if (!unixName ||
380 ((fd = open(unixName, access_flags | create_flags, 0666)) == -1))
382 SetLastError(ErrnoToLastError(errno));
383 return INVALID_HANDLE_VALUE;
387 /* We seem to have succeeded, so allocate a kernel object
388 * and set it up.
390 file_obj = (FILE_OBJECT *)CreateKernelObject(sizeof(FILE_OBJECT));
391 if(file_obj == NULL)
393 SetLastError(ERROR_INVALID_HANDLE);
394 return INVALID_HANDLE_VALUE;
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;
403 return (HANDLE32)file_obj;
406 /*************************************************************************
407 * W32_SetHandleCount (KERNEL32.??)
410 UINT W32_SetHandleCount(UINT cHandles)
412 return SetHandleCount(cHandles);
415 int CloseFileHandle(FILE_OBJECT *hFile)
417 /* If it's one of the 3 standard handles, don't really
418 * close it.
420 if(hFile->fd > 2)
421 close(hFile->fd);
423 return 1;
426 static int TranslateAccessFlags(DWORD access_flags)
428 int rc = 0;
430 switch(access_flags)
432 case GENERIC_READ:
433 rc = O_RDONLY;
434 break;
436 case GENERIC_WRITE:
437 rc = O_WRONLY;
438 break;
440 case (GENERIC_READ | GENERIC_WRITE):
441 rc = O_RDWR;
442 break;
445 return rc;
448 static int TranslateCreationFlags(DWORD create_flags)
450 int rc = 0;
452 switch(create_flags)
454 case CREATE_NEW:
455 rc = O_CREAT | O_EXCL;
456 break;
458 case CREATE_ALWAYS:
459 rc = O_CREAT | O_TRUNC;
460 break;
462 case OPEN_EXISTING:
463 rc = 0;
464 break;
466 case OPEN_ALWAYS:
467 rc = O_CREAT;
468 break;
470 case TRUNCATE_EXISTING:
471 rc = O_TRUNC;
472 break;
475 return rc;
478 /**************************************************************************
479 * GetFileAttributes
481 DWORD GetFileAttributesA(LPCSTR lpFileName)
483 struct stat buf;
484 DWORD res=0;
485 if(stat(lpFileName,&buf)==-1)
487 SetLastError(ErrnoToLastError(errno));
488 return 0;
490 if(buf.st_mode & S_IFREG)
491 res |= FILE_ATTRIBUTE_NORMAL;
492 if(buf.st_mode & S_IFDIR)
493 res |= FILE_ATTRIBUTE_DIRECTORY;
494 if((buf.st_mode & S_IWRITE) == 0)
495 res |= FILE_ATTRIBUTE_READONLY;
496 return res;