2003-02-02 Piers Haken <piersh@friskit.com>
[mono.git] / mono / io-layer / io.c
1 /*
2  * io.c:  File, console and find handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <glob.h>
19 #include <stdio.h>
20 #include <utime.h>
21
22 #include <mono/io-layer/wapi.h>
23 #include <mono/io-layer/unicode.h>
24 #include <mono/io-layer/wapi-private.h>
25 #include <mono/io-layer/handles-private.h>
26 #include <mono/io-layer/io-private.h>
27 #include <mono/io-layer/timefuncs-private.h>
28
29 #undef DEBUG
30
31 static void file_close_shared (gpointer handle);
32 static void file_close_private (gpointer handle);
33 static WapiFileType file_getfiletype(void);
34 static gboolean file_read(gpointer handle, gpointer buffer,
35                           guint32 numbytes, guint32 *bytesread,
36                           WapiOverlapped *overlapped);
37 static gboolean file_write(gpointer handle, gconstpointer buffer,
38                            guint32 numbytes, guint32 *byteswritten,
39                            WapiOverlapped *overlapped);
40 static gboolean file_flush(gpointer handle);
41 static guint32 file_seek(gpointer handle, gint32 movedistance,
42                          gint32 *highmovedistance, WapiSeekMethod method);
43 static gboolean file_setendoffile(gpointer handle);
44 static guint32 file_getfilesize(gpointer handle, guint32 *highsize);
45 static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
46                                  WapiFileTime *last_access,
47                                  WapiFileTime *last_write);
48 static gboolean file_setfiletime(gpointer handle,
49                                  const WapiFileTime *create_time,
50                                  const WapiFileTime *last_access,
51                                  const WapiFileTime *last_write);
52
53 /* File handle is only signalled for overlapped IO */
54 struct _WapiHandleOps _wapi_file_ops = {
55         file_close_shared,      /* close_shared */
56         file_close_private,     /* close_private */
57         NULL,                   /* signal */
58         NULL,                   /* own */
59         NULL,                   /* is_owned */
60 };
61
62 static void console_close_shared (gpointer handle);
63 static void console_close_private (gpointer handle);
64 static WapiFileType console_getfiletype(void);
65 static gboolean console_read(gpointer handle, gpointer buffer,
66                              guint32 numbytes, guint32 *bytesread,
67                              WapiOverlapped *overlapped);
68 static gboolean console_write(gpointer handle, gconstpointer buffer,
69                               guint32 numbytes, guint32 *byteswritten,
70                               WapiOverlapped *overlapped);
71
72 /* Console is mostly the same as file, except it can block waiting for
73  * input or output
74  */
75 struct _WapiHandleOps _wapi_console_ops = {
76         console_close_shared,   /* close_shared */
77         console_close_private,  /* close_private */
78         NULL,                   /* signal */
79         NULL,                   /* own */
80         NULL,                   /* is_owned */
81 };
82
83 /* Find handle has no ops.
84  */
85 struct _WapiHandleOps _wapi_find_ops = {
86         NULL,                   /* close_shared */
87         NULL,                   /* close_private */
88         NULL,                   /* signal */
89         NULL,                   /* own */
90         NULL,                   /* is_owned */
91 };
92
93 static void pipe_close_shared (gpointer handle);
94 static void pipe_close_private (gpointer handle);
95 static WapiFileType pipe_getfiletype (void);
96 static gboolean pipe_read (gpointer handle, gpointer buffer, guint32 numbytes,
97                            guint32 *bytesread, WapiOverlapped *overlapped);
98 static gboolean pipe_write (gpointer handle, gconstpointer buffer,
99                             guint32 numbytes, guint32 *byteswritten,
100                             WapiOverlapped *overlapped);
101
102 /* Pipe handles
103  */
104 struct _WapiHandleOps _wapi_pipe_ops = {
105         pipe_close_shared,      /* close_shared */
106         pipe_close_private,     /* close_private */
107         NULL,                   /* signal */
108         NULL,                   /* own */
109         NULL,                   /* is_owned */
110 };
111
112 static struct {
113         /* File, console and pipe handles */
114         WapiFileType (*getfiletype)(void);
115         
116         /* File, console and pipe handles */
117         gboolean (*readfile)(gpointer handle, gpointer buffer,
118                              guint32 numbytes, guint32 *bytesread,
119                              WapiOverlapped *overlapped);
120         gboolean (*writefile)(gpointer handle, gconstpointer buffer,
121                               guint32 numbytes, guint32 *byteswritten,
122                               WapiOverlapped *overlapped);
123         gboolean (*flushfile)(gpointer handle);
124         
125         /* File handles */
126         guint32 (*seek)(gpointer handle, gint32 movedistance,
127                         gint32 *highmovedistance, WapiSeekMethod method);
128         gboolean (*setendoffile)(gpointer handle);
129         guint32 (*getfilesize)(gpointer handle, guint32 *highsize);
130         gboolean (*getfiletime)(gpointer handle, WapiFileTime *create_time,
131                                 WapiFileTime *last_access,
132                                 WapiFileTime *last_write);
133         gboolean (*setfiletime)(gpointer handle,
134                                 const WapiFileTime *create_time,
135                                 const WapiFileTime *last_access,
136                                 const WapiFileTime *last_write);
137 } io_ops[WAPI_HANDLE_COUNT]={
138         {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
139         /* file */
140         {file_getfiletype,
141          file_read, file_write,
142          file_flush, file_seek,
143          file_setendoffile,
144          file_getfilesize,
145          file_getfiletime,
146          file_setfiletime},
147         /* console */
148         {console_getfiletype,
149          console_read,
150          console_write,
151          NULL, NULL, NULL, NULL, NULL, NULL},
152         /* thread */
153         {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
154         /* sem */
155         {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
156         /* mutex */
157         {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
158         /* event */
159         {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
160         /* socket (will need at least read and write) */
161         {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
162         /* find */
163         {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
164         /* process */
165         {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
166         /* pipe */
167         {pipe_getfiletype,
168          pipe_read,
169          pipe_write,
170          NULL, NULL, NULL, NULL, NULL, NULL},
171 };
172
173
174 static mono_once_t io_ops_once=MONO_ONCE_INIT;
175
176 static void io_ops_init (void)
177 {
178 /*      _wapi_handle_register_capabilities (WAPI_HANDLE_FILE, */
179 /*                                          WAPI_HANDLE_CAP_WAIT); */
180 /*      _wapi_handle_register_capabilities (WAPI_HANDLE_CONSOLE, */
181 /*                                          WAPI_HANDLE_CAP_WAIT); */
182 }
183
184 /* Some utility functions.
185  */
186
187 static guint32 _wapi_stat_to_file_attributes (struct stat *buf)
188 {
189         guint32 attrs = 0;
190
191         /* FIXME: this could definitely be better */
192
193         if (S_ISDIR (buf->st_mode))
194                 attrs |= FILE_ATTRIBUTE_DIRECTORY;
195         else
196                 attrs |= FILE_ATTRIBUTE_ARCHIVE;
197         
198         if (!(buf->st_mode & S_IWUSR))
199                 attrs |= FILE_ATTRIBUTE_READONLY;
200         
201         return attrs;
202 }
203
204 static void _wapi_set_last_error_from_errno (void)
205 {
206         /* mapping ideas borrowed from wine. they may need some work */
207
208         switch (errno) {
209         case EACCES: case EPERM: case EROFS:
210                 SetLastError (ERROR_ACCESS_DENIED);
211                 break;
212         
213         case EAGAIN:
214                 SetLastError (ERROR_SHARING_VIOLATION);
215                 break;
216         
217         case EBUSY:
218                 SetLastError (ERROR_LOCK_VIOLATION);
219                 break;
220         
221         case EEXIST:
222                 SetLastError (ERROR_FILE_EXISTS);
223                 break;
224         
225         case EINVAL: case ESPIPE:
226                 SetLastError (ERROR_SEEK);
227                 break;
228         
229         case EISDIR:
230                 SetLastError (ERROR_CANNOT_MAKE);
231                 break;
232         
233         case ENFILE: case EMFILE:
234                 SetLastError (ERROR_NO_MORE_FILES);
235                 break;
236
237         case ENOENT: case ENOTDIR:
238                 SetLastError (ERROR_FILE_NOT_FOUND);
239                 break;
240         
241         case ENOSPC:
242                 SetLastError (ERROR_HANDLE_DISK_FULL);
243                 break;
244         
245         case ENOTEMPTY:
246                 SetLastError (ERROR_DIR_NOT_EMPTY);
247                 break;
248
249         case ENOEXEC:
250                 SetLastError (ERROR_BAD_FORMAT);
251                 break;
252
253         case ENAMETOOLONG:
254                 SetLastError (ERROR_FILENAME_EXCED_RANGE);
255                 break;
256         
257         default:
258                 g_message ("Unknown errno: %s\n", strerror (errno));
259                 SetLastError (ERROR_GEN_FAILURE);
260                 break;
261         }
262 }
263
264 /* Handle ops.
265  */
266 static void file_close_shared (gpointer handle)
267 {
268         struct _WapiHandle_file *file_handle;
269         gboolean ok;
270         
271         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
272                                 (gpointer *)&file_handle, NULL);
273         if(ok==FALSE) {
274                 g_warning (G_GNUC_PRETTY_FUNCTION
275                            ": error looking up file handle %p", handle);
276                 return;
277         }
278         
279 #ifdef DEBUG
280         g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p", handle);
281 #endif
282         
283         if(file_handle->filename!=0) {
284                 _wapi_handle_scratch_delete (file_handle->filename);
285                 file_handle->filename=0;
286         }
287         if(file_handle->security_attributes!=0) {
288                 _wapi_handle_scratch_delete (file_handle->security_attributes);
289                 file_handle->security_attributes=0;
290         }
291 }
292
293 static void file_close_private (gpointer handle)
294 {
295         struct _WapiHandlePrivate_file *file_private_handle;
296         gboolean ok;
297         
298         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE, NULL,
299                                 (gpointer *)&file_private_handle);
300         if(ok==FALSE) {
301                 g_warning (G_GNUC_PRETTY_FUNCTION
302                            ": error looking up file handle %p", handle);
303                 return;
304         }
305         
306 #ifdef DEBUG
307         g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p with fd %d",
308                   handle, file_private_handle->fd);
309 #endif
310         
311         close(file_private_handle->fd);
312 }
313
314 static WapiFileType file_getfiletype(void)
315 {
316         return(FILE_TYPE_DISK);
317 }
318
319 static gboolean file_read(gpointer handle, gpointer buffer,
320                           guint32 numbytes, guint32 *bytesread,
321                           WapiOverlapped *overlapped G_GNUC_UNUSED)
322 {
323         struct _WapiHandle_file *file_handle;
324         struct _WapiHandlePrivate_file *file_private_handle;
325         gboolean ok;
326         int ret;
327         
328         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
329                                 (gpointer *)&file_handle,
330                                 (gpointer *)&file_private_handle);
331         if(ok==FALSE) {
332                 g_warning (G_GNUC_PRETTY_FUNCTION
333                            ": error looking up file handle %p", handle);
334                 return(FALSE);
335         }
336         
337         if(bytesread!=NULL) {
338                 *bytesread=0;
339         }
340         
341         if(!(file_handle->fileaccess&GENERIC_READ) &&
342            !(file_handle->fileaccess&GENERIC_ALL)) {
343 #ifdef DEBUG
344                 g_message(G_GNUC_PRETTY_FUNCTION": handle %p fd %d doesn't have GENERIC_READ access: %u", handle, file_private_handle->fd, file_handle->fileaccess);
345 #endif
346
347                 return(FALSE);
348         }
349         
350         ret=read(file_private_handle->fd, buffer, numbytes);
351         if(ret==-1) {
352 #ifdef DEBUG
353                 g_message(G_GNUC_PRETTY_FUNCTION
354                           ": read of handle %p fd %d error: %s", handle,
355                           file_private_handle->fd, strerror(errno));
356 #endif
357
358                 return(FALSE);
359         }
360         
361         if(bytesread!=NULL) {
362                 *bytesread=ret;
363         }
364         
365         return(TRUE);
366 }
367
368 static gboolean file_write(gpointer handle, gconstpointer buffer,
369                            guint32 numbytes, guint32 *byteswritten,
370                            WapiOverlapped *overlapped G_GNUC_UNUSED)
371 {
372         struct _WapiHandle_file *file_handle;
373         struct _WapiHandlePrivate_file *file_private_handle;
374         gboolean ok;
375         int ret;
376         
377         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
378                                 (gpointer *)&file_handle,
379                                 (gpointer *)&file_private_handle);
380         if(ok==FALSE) {
381                 g_warning (G_GNUC_PRETTY_FUNCTION
382                            ": error looking up file handle %p", handle);
383                 return(FALSE);
384         }
385         
386         if(byteswritten!=NULL) {
387                 *byteswritten=0;
388         }
389         
390         if(!(file_handle->fileaccess&GENERIC_WRITE) &&
391            !(file_handle->fileaccess&GENERIC_ALL)) {
392 #ifdef DEBUG
393                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_private_handle->fd, file_handle->fileaccess);
394 #endif
395
396                 return(FALSE);
397         }
398         
399         ret=write(file_private_handle->fd, buffer, numbytes);
400         if(ret==-1) {
401 #ifdef DEBUG
402                 g_message(G_GNUC_PRETTY_FUNCTION
403                           ": write of handle %p fd %d error: %s", handle,
404                           file_private_handle->fd, strerror(errno));
405 #endif
406
407                 return(FALSE);
408         }
409         if(byteswritten!=NULL) {
410                 *byteswritten=ret;
411         }
412         
413         return(TRUE);
414 }
415
416 static gboolean file_flush(gpointer handle)
417 {
418         struct _WapiHandle_file *file_handle;
419         struct _WapiHandlePrivate_file *file_private_handle;
420         gboolean ok;
421         int ret;
422         
423         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
424                                 (gpointer *)&file_handle,
425                                 (gpointer *)&file_private_handle);
426         if(ok==FALSE) {
427                 g_warning (G_GNUC_PRETTY_FUNCTION
428                            ": error looking up file handle %p", handle);
429                 return(FALSE);
430         }
431
432         if(!(file_handle->fileaccess&GENERIC_WRITE) &&
433            !(file_handle->fileaccess&GENERIC_ALL)) {
434 #ifdef DEBUG
435                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_private_handle->fd, file_handle->fileaccess);
436 #endif
437
438                 return(FALSE);
439         }
440
441         ret=fsync(file_private_handle->fd);
442         if (ret==-1) {
443 #ifdef DEBUG
444                 g_message(G_GNUC_PRETTY_FUNCTION
445                           ": write of handle %p fd %d error: %s", handle,
446                           file_private_handle->fd, strerror(errno));
447 #endif
448
449                 return(FALSE);
450         }
451         
452         return(TRUE);
453 }
454
455 static guint32 file_seek(gpointer handle, gint32 movedistance,
456                          gint32 *highmovedistance, WapiSeekMethod method)
457 {
458         struct _WapiHandle_file *file_handle;
459         struct _WapiHandlePrivate_file *file_private_handle;
460         gboolean ok;
461         off_t offset, newpos;
462         int whence;
463         guint32 ret;
464         
465         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
466                                 (gpointer *)&file_handle,
467                                 (gpointer *)&file_private_handle);
468         if(ok==FALSE) {
469                 g_warning (G_GNUC_PRETTY_FUNCTION
470                            ": error looking up file handle %p", handle);
471                 return(INVALID_SET_FILE_POINTER);
472         }
473         
474         if(!(file_handle->fileaccess&GENERIC_READ) &&
475            !(file_handle->fileaccess&GENERIC_WRITE) &&
476            !(file_handle->fileaccess&GENERIC_ALL)) {
477 #ifdef DEBUG
478                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", handle, file_private_handle->fd, file_handle->fileaccess);
479 #endif
480
481                 return(INVALID_SET_FILE_POINTER);
482         }
483
484         switch(method) {
485         case FILE_BEGIN:
486                 whence=SEEK_SET;
487                 break;
488         case FILE_CURRENT:
489                 whence=SEEK_CUR;
490                 break;
491         case FILE_END:
492                 whence=SEEK_END;
493                 break;
494         default:
495 #ifdef DEBUG
496                 g_message(G_GNUC_PRETTY_FUNCTION ": invalid seek type %d",
497                           method);
498 #endif
499
500                 return(INVALID_SET_FILE_POINTER);
501         }
502
503 #ifdef HAVE_LARGE_FILE_SUPPORT
504         if(highmovedistance==NULL) {
505                 offset=movedistance;
506 #ifdef DEBUG
507                 g_message(G_GNUC_PRETTY_FUNCTION
508                           ": setting offset to %lld (low %d)", offset,
509                           movedistance);
510 #endif
511         } else {
512                 offset=((gint64) *highmovedistance << 32) | movedistance;
513                 
514 #ifdef DEBUG
515                 g_message(G_GNUC_PRETTY_FUNCTION ": setting offset to %lld 0x%llx (high %d 0x%x, low %d 0x%x)", offset, offset, *highmovedistance, *highmovedistance, movedistance, movedistance);
516 #endif
517         }
518 #else
519         offset=movedistance;
520 #endif
521
522 #ifdef DEBUG
523 #ifdef HAVE_LARGE_FILE_SUPPORT
524         g_message(G_GNUC_PRETTY_FUNCTION
525                   ": moving handle %p fd %d by %lld bytes from %d", handle,
526                   file_private_handle->fd, offset, whence);
527 #else
528         g_message(G_GNUC_PRETTY_FUNCTION
529                   ": moving handle %p fd %d by %ld bytes from %d", handle,
530                   file_private_handle->fd, offset, whence);
531 #endif
532 #endif
533
534         newpos=lseek(file_private_handle->fd, offset, whence);
535         if(newpos==-1) {
536 #ifdef DEBUG
537                 g_message(G_GNUC_PRETTY_FUNCTION
538                           ": lseek on handle %p fd %d returned error %s",
539                           handle, file_private_handle->fd, strerror(errno));
540 #endif
541
542                 return(INVALID_SET_FILE_POINTER);
543         }
544
545 #ifdef DEBUG
546 #ifdef HAVE_LARGE_FILE_SUPPORT
547         g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %lld", newpos);
548 #else
549         g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %ld", newpos);
550 #endif
551 #endif
552
553 #ifdef HAVE_LARGE_FILE_SUPPORT
554         ret=newpos & 0xFFFFFFFF;
555         if(highmovedistance!=NULL) {
556                 *highmovedistance=newpos>>32;
557         }
558 #else
559         ret=newpos;
560         if(highmovedistance!=NULL) {
561                 /* Accurate, but potentially dodgy :-) */
562                 *highmovedistance=0;
563         }
564 #endif
565
566 #ifdef DEBUG
567         g_message(G_GNUC_PRETTY_FUNCTION
568                   ": move of handle %p fd %d returning %d/%d", handle,
569                   file_private_handle->fd, ret,
570                   highmovedistance==NULL?0:*highmovedistance);
571 #endif
572
573         return(ret);
574 }
575
576 static gboolean file_setendoffile(gpointer handle)
577 {
578         struct _WapiHandle_file *file_handle;
579         struct _WapiHandlePrivate_file *file_private_handle;
580         gboolean ok;
581         struct stat statbuf;
582         off_t size, pos;
583         int ret;
584         
585         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
586                                 (gpointer *)&file_handle,
587                                 (gpointer *)&file_private_handle);
588         if(ok==FALSE) {
589                 g_warning (G_GNUC_PRETTY_FUNCTION
590                            ": error looking up file handle %p", handle);
591                 return(FALSE);
592         }
593         
594         if(!(file_handle->fileaccess&GENERIC_WRITE) &&
595            !(file_handle->fileaccess&GENERIC_ALL)) {
596 #ifdef DEBUG
597                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_private_handle->fd, file_handle->fileaccess);
598 #endif
599
600                 return(FALSE);
601         }
602
603         /* Find the current file position, and the file length.  If
604          * the file position is greater than the length, write to
605          * extend the file with a hole.  If the file position is less
606          * than the length, truncate the file.
607          */
608         
609         ret=fstat(file_private_handle->fd, &statbuf);
610         if(ret==-1) {
611 #ifdef DEBUG
612                 g_message(G_GNUC_PRETTY_FUNCTION
613                           ": handle %p fd %d fstat failed: %s", handle,
614                           file_private_handle->fd, strerror(errno));
615 #endif
616
617                 return(FALSE);
618         }
619         size=statbuf.st_size;
620
621         pos=lseek(file_private_handle->fd, (off_t)0, SEEK_CUR);
622         if(pos==-1) {
623 #ifdef DEBUG
624                 g_message(G_GNUC_PRETTY_FUNCTION
625                           ": handle %p fd %d lseek failed: %s", handle,
626                           file_private_handle->fd, strerror(errno));
627 #endif
628
629                 return(FALSE);
630         }
631         
632         if(pos>size) {
633                 /* extend */
634                 ret=write(file_private_handle->fd, "", 1);
635                 if(ret==-1) {
636 #ifdef DEBUG
637                         g_message(G_GNUC_PRETTY_FUNCTION
638                                   ": handle %p fd %d extend write failed: %s",
639                                   handle, file_private_handle->fd,
640                                   strerror(errno));
641 #endif
642
643                         return(FALSE);
644                 }
645         }
646
647         /* always truncate, because the extend write() adds an extra
648          * byte to the end of the file
649          */
650         ret=ftruncate(file_private_handle->fd, pos);
651         if(ret==-1) {
652 #ifdef DEBUG
653                 g_message(G_GNUC_PRETTY_FUNCTION
654                           ": handle %p fd %d ftruncate failed: %s", handle,
655                           file_private_handle->fd, strerror(errno));
656 #endif
657                 
658                 return(FALSE);
659         }
660                 
661         return(TRUE);
662 }
663
664 static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
665 {
666         struct _WapiHandle_file *file_handle;
667         struct _WapiHandlePrivate_file *file_private_handle;
668         gboolean ok;
669         struct stat statbuf;
670         guint32 size;
671         int ret;
672         
673         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
674                                 (gpointer *)&file_handle,
675                                 (gpointer *)&file_private_handle);
676         if(ok==FALSE) {
677                 g_warning (G_GNUC_PRETTY_FUNCTION
678                            ": error looking up file handle %p", handle);
679                 return(INVALID_FILE_SIZE);
680         }
681         
682         if(!(file_handle->fileaccess&GENERIC_READ) &&
683            !(file_handle->fileaccess&GENERIC_WRITE) &&
684            !(file_handle->fileaccess&GENERIC_ALL)) {
685 #ifdef DEBUG
686                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", handle, file_private_handle->fd, file_handle->fileaccess);
687 #endif
688
689                 return(INVALID_FILE_SIZE);
690         }
691
692         ret=fstat(file_private_handle->fd, &statbuf);
693         if(ret==-1) {
694 #ifdef DEBUG
695                 g_message(G_GNUC_PRETTY_FUNCTION
696                           ": handle %p fd %d fstat failed: %s", handle,
697                           file_private_handle->fd, strerror(errno));
698 #endif
699
700                 return(INVALID_FILE_SIZE);
701         }
702         
703 #ifdef HAVE_LARGE_FILE_SUPPORT
704         size=statbuf.st_size & 0xFFFFFFFF;
705         if(highsize!=NULL) {
706                 *highsize=statbuf.st_size>>32;
707         }
708 #else
709         if(highsize!=NULL) {
710                 /* Accurate, but potentially dodgy :-) */
711                 *highsize=0;
712         }
713         size=statbuf.st_size;
714 #endif
715
716 #ifdef DEBUG
717         g_message(G_GNUC_PRETTY_FUNCTION ": Returning size %d/%d", size,
718                   *highsize);
719 #endif
720         
721         return(size);
722 }
723
724 static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
725                                  WapiFileTime *last_access,
726                                  WapiFileTime *last_write)
727 {
728         struct _WapiHandle_file *file_handle;
729         struct _WapiHandlePrivate_file *file_private_handle;
730         gboolean ok;
731         struct stat statbuf;
732         guint64 create_ticks, access_ticks, write_ticks;
733         int ret;
734         
735         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
736                                 (gpointer *)&file_handle,
737                                 (gpointer *)&file_private_handle);
738         if(ok==FALSE) {
739                 g_warning (G_GNUC_PRETTY_FUNCTION
740                            ": error looking up file handle %p", handle);
741                 return(FALSE);
742         }
743         
744         if(!(file_handle->fileaccess&GENERIC_READ) &&
745            !(file_handle->fileaccess&GENERIC_ALL)) {
746 #ifdef DEBUG
747                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ access: %u", handle, file_private_handle->fd, file_handle->fileaccess);
748 #endif
749
750                 return(FALSE);
751         }
752         
753         ret=fstat(file_private_handle->fd, &statbuf);
754         if(ret==-1) {
755 #ifdef DEBUG
756                 g_message(G_GNUC_PRETTY_FUNCTION
757                           ": handle %p fd %d fstat failed: %s", handle,
758                           file_private_handle->fd, strerror(errno));
759 #endif
760
761                 return(FALSE);
762         }
763
764 #ifdef DEBUG
765         g_message(G_GNUC_PRETTY_FUNCTION
766                   ": atime: %ld ctime: %ld mtime: %ld",
767                   statbuf.st_atime, statbuf.st_ctime,
768                   statbuf.st_mtime);
769 #endif
770
771         /* Try and guess a meaningful create time by using the older
772          * of atime or ctime
773          */
774         /* The magic constant comes from msdn documentation
775          * "Converting a time_t Value to a File Time"
776          */
777         if(statbuf.st_atime < statbuf.st_ctime) {
778                 create_ticks=((guint64)statbuf.st_atime*10000000)
779                         + 116444736000000000UL;
780         } else {
781                 create_ticks=((guint64)statbuf.st_ctime*10000000)
782                         + 116444736000000000UL;
783         }
784         
785         access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000UL;
786         write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000UL;
787         
788 #ifdef DEBUG
789                 g_message(G_GNUC_PRETTY_FUNCTION
790                           ": aticks: %llu cticks: %llu wticks: %llu",
791                           access_ticks, create_ticks, write_ticks);
792 #endif
793
794         if(create_time!=NULL) {
795                 create_time->dwLowDateTime = create_ticks & 0xFFFFFFFF;
796                 create_time->dwHighDateTime = create_ticks >> 32;
797         }
798         
799         if(last_access!=NULL) {
800                 last_access->dwLowDateTime = access_ticks & 0xFFFFFFFF;
801                 last_access->dwHighDateTime = access_ticks >> 32;
802         }
803         
804         if(last_write!=NULL) {
805                 last_write->dwLowDateTime = write_ticks & 0xFFFFFFFF;
806                 last_write->dwHighDateTime = write_ticks >> 32;
807         }
808
809         return(TRUE);
810 }
811
812 static gboolean file_setfiletime(gpointer handle,
813                                  const WapiFileTime *create_time G_GNUC_UNUSED,
814                                  const WapiFileTime *last_access,
815                                  const WapiFileTime *last_write)
816 {
817         struct _WapiHandle_file *file_handle;
818         struct _WapiHandlePrivate_file *file_private_handle;
819         gboolean ok;
820         guchar *name;
821         struct utimbuf utbuf;
822         struct stat statbuf;
823         guint64 access_ticks, write_ticks;
824         int ret;
825         
826         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
827                                 (gpointer *)&file_handle,
828                                 (gpointer *)&file_private_handle);
829         if(ok==FALSE) {
830                 g_warning (G_GNUC_PRETTY_FUNCTION
831                            ": error looking up file handle %p", handle);
832                 return(FALSE);
833         }
834         
835         if(!(file_handle->fileaccess&GENERIC_WRITE) &&
836            !(file_handle->fileaccess&GENERIC_ALL)) {
837 #ifdef DEBUG
838                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_private_handle->fd, file_handle->fileaccess);
839 #endif
840
841                 return(FALSE);
842         }
843
844         if(file_handle->filename==0) {
845 #ifdef DEBUG
846                 g_message(G_GNUC_PRETTY_FUNCTION
847                           ": handle %p fd %d unknown filename", handle,
848                           file_private_handle->fd);
849 #endif
850
851                 return(FALSE);
852         }
853         
854         /* Get the current times, so we can put the same times back in
855          * the event that one of the FileTime structs is NULL
856          */
857         ret=fstat(file_private_handle->fd, &statbuf);
858         if(ret==-1) {
859 #ifdef DEBUG
860                 g_message(G_GNUC_PRETTY_FUNCTION
861                           ": handle %p fd %d fstat failed: %s", handle,
862                           file_private_handle->fd, strerror(errno));
863 #endif
864
865                 return(FALSE);
866         }
867
868         if(last_access!=NULL) {
869                 access_ticks=((guint64)last_access->dwHighDateTime << 32) +
870                         last_access->dwLowDateTime;
871                 utbuf.actime=(access_ticks - 116444736000000000) / 10000000;
872         } else {
873                 utbuf.actime=statbuf.st_atime;
874         }
875
876         if(last_write!=NULL) {
877                 write_ticks=((guint64)last_write->dwHighDateTime << 32) +
878                         last_write->dwLowDateTime;
879                 utbuf.modtime=(write_ticks - 116444736000000000) / 10000000;
880         } else {
881                 utbuf.modtime=statbuf.st_mtime;
882         }
883
884 #ifdef DEBUG
885         g_message(G_GNUC_PRETTY_FUNCTION
886                   ": setting handle %p access %ld write %ld", handle,
887                   utbuf.actime, utbuf.modtime);
888 #endif
889
890         name=_wapi_handle_scratch_lookup_as_string (file_handle->filename);
891
892         ret=utime(name, &utbuf);
893         if(ret==-1) {
894 #ifdef DEBUG
895                 g_message(G_GNUC_PRETTY_FUNCTION
896                           ": handle %p [%s] fd %d utime failed: %s", handle,
897                           name, file_private_handle->fd, strerror(errno));
898
899 #endif
900                 g_free (name);
901                 return(FALSE);
902         }
903
904         g_free (name);
905         
906         return(TRUE);
907 }
908
909 static void console_close_shared (gpointer handle)
910 {
911         struct _WapiHandle_file *console_handle;
912         gboolean ok;
913         
914         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
915                                 (gpointer *)&console_handle, NULL);
916         if(ok==FALSE) {
917                 g_warning (G_GNUC_PRETTY_FUNCTION
918                            ": error looking up console handle %p", handle);
919                 return;
920         }
921         
922 #ifdef DEBUG
923         g_message(G_GNUC_PRETTY_FUNCTION ": closing console handle %p", handle);
924 #endif
925         
926         if(console_handle->filename!=0) {
927                 _wapi_handle_scratch_delete (console_handle->filename);
928                 console_handle->filename=0;
929         }
930         if(console_handle->security_attributes!=0) {
931                 _wapi_handle_scratch_delete (console_handle->security_attributes);
932                 console_handle->security_attributes=0;
933         }
934 }
935
936 static void console_close_private (gpointer handle)
937 {
938         struct _WapiHandlePrivate_file *console_private_handle;
939         gboolean ok;
940         
941         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
942                                 (gpointer *)&console_private_handle);
943         if(ok==FALSE) {
944                 g_warning (G_GNUC_PRETTY_FUNCTION
945                            ": error looking up console handle %p", handle);
946                 return;
947         }
948         
949 #ifdef DEBUG
950         g_message(G_GNUC_PRETTY_FUNCTION
951                   ": closing console handle %p with fd %d", handle,
952                   console_private_handle->fd);
953 #endif
954         
955         close(console_private_handle->fd);
956 }
957
958 static WapiFileType console_getfiletype(void)
959 {
960         return(FILE_TYPE_CHAR);
961 }
962
963 static gboolean console_read(gpointer handle, gpointer buffer,
964                              guint32 numbytes, guint32 *bytesread,
965                              WapiOverlapped *overlapped G_GNUC_UNUSED)
966 {
967         struct _WapiHandle_file *console_handle;
968         struct _WapiHandlePrivate_file *console_private_handle;
969         gboolean ok;
970         int ret;
971         
972         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
973                                 (gpointer *)&console_handle,
974                                 (gpointer *)&console_private_handle);
975         if(ok==FALSE) {
976                 g_warning (G_GNUC_PRETTY_FUNCTION
977                            ": error looking up console handle %p", handle);
978                 return(FALSE);
979         }
980         
981         if(bytesread!=NULL) {
982                 *bytesread=0;
983         }
984         
985         if(!(console_handle->fileaccess&GENERIC_READ) &&
986            !(console_handle->fileaccess&GENERIC_ALL)) {
987 #ifdef DEBUG
988                 g_message(G_GNUC_PRETTY_FUNCTION": handle %p fd %d doesn't have GENERIC_READ access: %u", handle, console_private_handle->fd, console_handle->fileaccess);
989 #endif
990
991                 return(FALSE);
992         }
993         
994         ret=read(console_private_handle->fd, buffer, numbytes);
995         if(ret==-1) {
996 #ifdef DEBUG
997                 g_message(G_GNUC_PRETTY_FUNCTION
998                           ": read of handle %p fd %d error: %s", handle,
999                           console_private_handle->fd, strerror(errno));
1000 #endif
1001
1002                 return(FALSE);
1003         }
1004         
1005         if(bytesread!=NULL) {
1006                 *bytesread=ret;
1007         }
1008         
1009         return(TRUE);
1010 }
1011
1012 static gboolean console_write(gpointer handle, gconstpointer buffer,
1013                               guint32 numbytes, guint32 *byteswritten,
1014                               WapiOverlapped *overlapped G_GNUC_UNUSED)
1015 {
1016         struct _WapiHandle_file *console_handle;
1017         struct _WapiHandlePrivate_file *console_private_handle;
1018         gboolean ok;
1019         int ret;
1020         
1021         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1022                                 (gpointer *)&console_handle,
1023                                 (gpointer *)&console_private_handle);
1024         if(ok==FALSE) {
1025                 g_warning (G_GNUC_PRETTY_FUNCTION
1026                            ": error looking up console handle %p", handle);
1027                 return(FALSE);
1028         }
1029         
1030         if(byteswritten!=NULL) {
1031                 *byteswritten=0;
1032         }
1033         
1034         if(!(console_handle->fileaccess&GENERIC_WRITE) &&
1035            !(console_handle->fileaccess&GENERIC_ALL)) {
1036 #ifdef DEBUG
1037                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, console_private_handle->fd, console_handle->fileaccess);
1038 #endif
1039
1040                 return(FALSE);
1041         }
1042         
1043         ret=write(console_private_handle->fd, buffer, numbytes);
1044         if(ret==-1) {
1045 #ifdef DEBUG
1046                 g_message(G_GNUC_PRETTY_FUNCTION
1047                           ": write of handle %p fd %d error: %s", handle,
1048                           console_private_handle->fd, strerror(errno));
1049 #endif
1050
1051                 return(FALSE);
1052         }
1053         if(byteswritten!=NULL) {
1054                 *byteswritten=ret;
1055         }
1056         
1057         return(TRUE);
1058 }
1059
1060 static void pipe_close_shared (gpointer handle)
1061 {
1062         struct _WapiHandle_file *pipe_handle;
1063         gboolean ok;
1064         
1065         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1066                                 (gpointer *)&pipe_handle, NULL);
1067         if(ok==FALSE) {
1068                 g_warning (G_GNUC_PRETTY_FUNCTION
1069                            ": error looking up pipe handle %p", handle);
1070                 return;
1071         }
1072         
1073 #ifdef DEBUG
1074         g_message(G_GNUC_PRETTY_FUNCTION ": closing pipe handle %p", handle);
1075 #endif
1076         
1077         if(pipe_handle->filename!=0) {
1078                 _wapi_handle_scratch_delete (pipe_handle->filename);
1079                 pipe_handle->filename=0;
1080         }
1081         if(pipe_handle->security_attributes!=0) {
1082                 _wapi_handle_scratch_delete (pipe_handle->security_attributes);
1083                 pipe_handle->security_attributes=0;
1084         }
1085 }
1086
1087 static void pipe_close_private (gpointer handle)
1088 {
1089         struct _WapiHandlePrivate_file *pipe_private_handle;
1090         gboolean ok;
1091         
1092         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE, NULL,
1093                                 (gpointer *)&pipe_private_handle);
1094         if(ok==FALSE) {
1095                 g_warning (G_GNUC_PRETTY_FUNCTION
1096                            ": error looking up pipe handle %p", handle);
1097                 return;
1098         }
1099         
1100 #ifdef DEBUG
1101         g_message(G_GNUC_PRETTY_FUNCTION
1102                   ": closing pipe handle %p with fd %d", handle,
1103                   pipe_private_handle->fd);
1104 #endif
1105         
1106         close(pipe_private_handle->fd);
1107 }
1108
1109 static WapiFileType pipe_getfiletype(void)
1110 {
1111         return(FILE_TYPE_PIPE);
1112 }
1113
1114 static gboolean pipe_read (gpointer handle, gpointer buffer,
1115                            guint32 numbytes, guint32 *bytesread,
1116                            WapiOverlapped *overlapped G_GNUC_UNUSED)
1117 {
1118         struct _WapiHandle_file *pipe_handle;
1119         struct _WapiHandlePrivate_file *pipe_private_handle;
1120         gboolean ok;
1121         int ret;
1122         
1123         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1124                                 (gpointer *)&pipe_handle,
1125                                 (gpointer *)&pipe_private_handle);
1126         if(ok==FALSE) {
1127                 g_warning (G_GNUC_PRETTY_FUNCTION
1128                            ": error looking up pipe handle %p", handle);
1129                 return(FALSE);
1130         }
1131         
1132         if(bytesread!=NULL) {
1133                 *bytesread=0;
1134         }
1135         
1136         if(!(pipe_handle->fileaccess&GENERIC_READ) &&
1137            !(pipe_handle->fileaccess&GENERIC_ALL)) {
1138 #ifdef DEBUG
1139                 g_message(G_GNUC_PRETTY_FUNCTION": handle %p fd %d doesn't have GENERIC_READ access: %u", handle, pipe_private_handle->fd, pipe_handle->fileaccess);
1140 #endif
1141
1142                 return(FALSE);
1143         }
1144         
1145 #ifdef DEBUG
1146         g_message (G_GNUC_PRETTY_FUNCTION
1147                    ": reading up to %d bytes from pipe %p (fd %d)", numbytes,
1148                    handle, pipe_private_handle->fd);
1149 #endif
1150
1151         ret=read(pipe_private_handle->fd, buffer, numbytes);
1152         if(ret==-1) {
1153 #ifdef DEBUG
1154                 g_message(G_GNUC_PRETTY_FUNCTION
1155                           ": read of handle %p fd %d error: %s", handle,
1156                           pipe_private_handle->fd, strerror(errno));
1157 #endif
1158
1159                 return(FALSE);
1160         }
1161         
1162 #ifdef DEBUG
1163         g_message (G_GNUC_PRETTY_FUNCTION ": read %d bytes from pipe", ret);
1164 #endif
1165
1166         if(bytesread!=NULL) {
1167                 *bytesread=ret;
1168         }
1169         
1170         return(TRUE);
1171 }
1172
1173 static gboolean pipe_write(gpointer handle, gconstpointer buffer,
1174                            guint32 numbytes, guint32 *byteswritten,
1175                            WapiOverlapped *overlapped G_GNUC_UNUSED)
1176 {
1177         struct _WapiHandle_file *pipe_handle;
1178         struct _WapiHandlePrivate_file *pipe_private_handle;
1179         gboolean ok;
1180         int ret;
1181         
1182         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1183                                 (gpointer *)&pipe_handle,
1184                                 (gpointer *)&pipe_private_handle);
1185         if(ok==FALSE) {
1186                 g_warning (G_GNUC_PRETTY_FUNCTION
1187                            ": error looking up pipe handle %p", handle);
1188                 return(FALSE);
1189         }
1190         
1191         if(byteswritten!=NULL) {
1192                 *byteswritten=0;
1193         }
1194         
1195         if(!(pipe_handle->fileaccess&GENERIC_WRITE) &&
1196            !(pipe_handle->fileaccess&GENERIC_ALL)) {
1197 #ifdef DEBUG
1198                 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, pipe_private_handle->fd, pipe_handle->fileaccess);
1199 #endif
1200
1201                 return(FALSE);
1202         }
1203         
1204 #ifdef DEBUG
1205         g_message (G_GNUC_PRETTY_FUNCTION
1206                    ": writing up to %d bytes to pipe %p (fd %d)", numbytes,
1207                    handle, pipe_private_handle->fd);
1208 #endif
1209         
1210         ret=write(pipe_private_handle->fd, buffer, numbytes);
1211         if(ret==-1) {
1212 #ifdef DEBUG
1213                 g_message(G_GNUC_PRETTY_FUNCTION
1214                           ": write of handle %p fd %d error: %s", handle,
1215                           pipe_private_handle->fd, strerror(errno));
1216 #endif
1217
1218                 return(FALSE);
1219         }
1220         if(byteswritten!=NULL) {
1221                 *byteswritten=ret;
1222         }
1223         
1224         return(TRUE);
1225 }
1226
1227 static int convert_flags(guint32 fileaccess, guint32 createmode)
1228 {
1229         int flags=0;
1230         
1231         switch(fileaccess) {
1232         case GENERIC_READ:
1233                 flags=O_RDONLY;
1234                 break;
1235         case GENERIC_WRITE:
1236                 flags=O_WRONLY;
1237                 break;
1238         case GENERIC_READ|GENERIC_WRITE:
1239                 flags=O_RDWR;
1240                 break;
1241         default:
1242 #ifdef DEBUG
1243                 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown access type 0x%x",
1244                           fileaccess);
1245 #endif
1246                 break;
1247         }
1248
1249         switch(createmode) {
1250         case CREATE_NEW:
1251                 flags|=O_CREAT|O_EXCL;
1252                 break;
1253         case CREATE_ALWAYS:
1254                 flags|=O_CREAT|O_TRUNC;
1255                 break;
1256         case OPEN_EXISTING:
1257                 break;
1258         case OPEN_ALWAYS:
1259                 flags|=O_CREAT;
1260                 break;
1261         case TRUNCATE_EXISTING:
1262                 flags|=O_TRUNC;
1263                 break;
1264         default:
1265 #ifdef DEBUG
1266                 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown create mode 0x%x",
1267                           createmode);
1268 #endif
1269                 break;
1270         }
1271         
1272         return(flags);
1273 }
1274
1275 static guint32 convert_from_flags(int flags)
1276 {
1277         guint32 fileaccess=0;
1278         
1279 #ifndef O_ACCMODE
1280 #define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
1281 #endif
1282
1283         if((flags & O_ACCMODE) == O_RDONLY) {
1284                 fileaccess=GENERIC_READ;
1285         } else if ((flags & O_ACCMODE) == O_WRONLY) {
1286                 fileaccess=GENERIC_WRITE;
1287         } else if ((flags & O_ACCMODE) == O_RDWR) {
1288                 fileaccess=GENERIC_READ|GENERIC_WRITE;
1289         } else {
1290 #ifdef DEBUG
1291                 g_message(G_GNUC_PRETTY_FUNCTION
1292                           ": Can't figure out flags 0x%x", flags);
1293 #endif
1294         }
1295
1296         /* Maybe sort out create mode too */
1297
1298         return(fileaccess);
1299 }
1300
1301 static mode_t convert_perms(guint32 sharemode)
1302 {
1303         mode_t perms=0600;
1304         
1305         if(sharemode&FILE_SHARE_READ) {
1306                 perms|=044;
1307         }
1308         if(sharemode&FILE_SHARE_WRITE) {
1309                 perms|=022;
1310         }
1311
1312         return(perms);
1313 }
1314
1315
1316 /**
1317  * CreateFile:
1318  * @name: a pointer to a NULL-terminated unicode string, that names
1319  * the file or other object to create.
1320  * @fileaccess: specifies the file access mode
1321  * @sharemode: whether the file should be shared.  This parameter is
1322  * currently ignored.
1323  * @security: Ignored for now.
1324  * @createmode: specifies whether to create a new file, whether to
1325  * overwrite an existing file, whether to truncate the file, etc.
1326  * @attrs: specifies file attributes and flags.  On win32 attributes
1327  * are characteristics of the file, not the handle, and are ignored
1328  * when an existing file is opened.  Flags give the library hints on
1329  * how to process a file to optimise performance.
1330  * @template: the handle of an open %GENERIC_READ file that specifies
1331  * attributes to apply to a newly created file, ignoring @attrs.
1332  * Normally this parameter is NULL.  This parameter is ignored when an
1333  * existing file is opened.
1334  *
1335  * Creates a new file handle.  This only applies to normal files:
1336  * pipes are handled by CreatePipe(), and console handles are created
1337  * with GetStdHandle().
1338  *
1339  * Return value: the new handle, or %INVALID_HANDLE_VALUE on error.
1340  */
1341 gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
1342                     guint32 sharemode, WapiSecurityAttributes *security,
1343                     guint32 createmode, guint32 attrs,
1344                     gpointer template G_GNUC_UNUSED)
1345 {
1346         struct _WapiHandle_file *file_handle;
1347         struct _WapiHandlePrivate_file *file_private_handle;
1348         gpointer handle;
1349         gboolean ok;
1350         int flags=convert_flags(fileaccess, createmode);
1351         mode_t perms=convert_perms(sharemode);
1352         gchar *filename;
1353         int ret;
1354
1355         mono_once (&io_ops_once, io_ops_init);
1356         
1357         if(name==NULL) {
1358 #ifdef DEBUG
1359                 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1360 #endif
1361
1362                 return(INVALID_HANDLE_VALUE);
1363         }
1364
1365         filename=_wapi_unicode_to_utf8(name);
1366         if(filename==NULL) {
1367 #ifdef DEBUG
1368                 g_message(G_GNUC_PRETTY_FUNCTION
1369                           ": unicode conversion returned NULL");
1370 #endif
1371
1372                 return(INVALID_HANDLE_VALUE);
1373         }
1374         
1375         ret=open(filename, flags, perms);
1376         
1377         if(ret==-1) {
1378 #ifdef DEBUG
1379                 g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
1380                           filename, strerror(errno));
1381 #endif
1382                 _wapi_set_last_error_from_errno ();
1383                 g_free (filename);
1384
1385                 return(INVALID_HANDLE_VALUE);
1386         }
1387
1388         handle=_wapi_handle_new (WAPI_HANDLE_FILE);
1389         if(handle==_WAPI_HANDLE_INVALID) {
1390                 g_warning (G_GNUC_PRETTY_FUNCTION
1391                            ": error creating file handle");
1392                 g_free (filename);
1393
1394                 return(INVALID_HANDLE_VALUE);
1395         }
1396
1397         _wapi_handle_lock_handle (handle);
1398         
1399         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
1400                                 (gpointer *)&file_handle,
1401                                 (gpointer *)&file_private_handle);
1402         if(ok==FALSE) {
1403                 g_warning (G_GNUC_PRETTY_FUNCTION
1404                            ": error looking up file handle %p", handle);
1405                 _wapi_handle_unlock_handle (handle);
1406                 g_free (filename);
1407
1408                 return(INVALID_HANDLE_VALUE);
1409         }
1410
1411         file_private_handle->fd=ret;
1412         file_private_handle->assigned=TRUE;
1413         file_handle->filename=_wapi_handle_scratch_store (filename,
1414                                                           strlen (filename));
1415         if(security!=NULL) {
1416                 file_handle->security_attributes=_wapi_handle_scratch_store (
1417                         security, sizeof(WapiSecurityAttributes));
1418         }
1419         
1420         file_handle->fileaccess=fileaccess;
1421         file_handle->sharemode=sharemode;
1422         file_handle->attrs=attrs;
1423         
1424 #ifdef DEBUG
1425         g_message(G_GNUC_PRETTY_FUNCTION
1426                   ": returning handle %p with fd %d", handle,
1427                   file_private_handle->fd);
1428 #endif
1429
1430         _wapi_handle_unlock_handle (handle);
1431         g_free (filename);
1432         
1433         return(handle);
1434 }
1435
1436 /**
1437  * DeleteFile:
1438  * @name: a pointer to a NULL-terminated unicode string, that names
1439  * the file to be deleted.
1440  *
1441  * Deletes file @name.
1442  *
1443  * Return value: %TRUE on success, %FALSE otherwise.
1444  */
1445 gboolean DeleteFile(const gunichar2 *name)
1446 {
1447         gchar *filename;
1448         int ret;
1449         
1450         if(name==NULL) {
1451 #ifdef DEBUG
1452                 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1453 #endif
1454
1455                 return(FALSE);
1456         }
1457
1458         filename=_wapi_unicode_to_utf8(name);
1459         if(filename==NULL) {
1460 #ifdef DEBUG
1461                 g_message(G_GNUC_PRETTY_FUNCTION
1462                           ": unicode conversion returned NULL");
1463 #endif
1464
1465                 return(FALSE);
1466         }
1467         
1468         ret=unlink(filename);
1469         
1470         g_free(filename);
1471
1472         if(ret==0) {
1473                 return(TRUE);
1474         } else {
1475                 return(FALSE);
1476         }
1477 }
1478
1479 /**
1480  * MoveFile:
1481  * @name: a pointer to a NULL-terminated unicode string, that names
1482  * the file to be moved.
1483  * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1484  * new name for the file.
1485  *
1486  * Renames file @name to @dest_name
1487  *
1488  * Return value: %TRUE on success, %FALSE otherwise.
1489  */
1490 gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
1491 {
1492         gchar *utf8_name, *utf8_dest_name;
1493         int result;
1494
1495         utf8_name = _wapi_unicode_to_utf8 (name);
1496         if (utf8_name == NULL) {
1497 #ifdef DEBUG
1498                 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1499 #endif
1500                 
1501                 return FALSE;
1502         }
1503
1504         utf8_dest_name = _wapi_unicode_to_utf8 (dest_name);
1505         if (utf8_dest_name == NULL) {
1506 #ifdef DEBUG
1507                 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1508 #endif
1509
1510                 g_free (utf8_name);
1511                 return FALSE;
1512         }
1513
1514         result = rename (utf8_name, utf8_dest_name);
1515         g_free (utf8_name);
1516         g_free (utf8_dest_name);
1517
1518         if (result == 0)
1519                 return TRUE;
1520         
1521         switch (errno) {
1522         case EEXIST:
1523                 SetLastError (ERROR_ALREADY_EXISTS);
1524                 break;
1525         
1526         default:
1527                 _wapi_set_last_error_from_errno ();
1528                 break;
1529         }
1530
1531         return FALSE;
1532 }
1533
1534 /**
1535  * CopyFile:
1536  * @name: a pointer to a NULL-terminated unicode string, that names
1537  * the file to be copied.
1538  * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1539  * new name for the file.
1540  * @fail_if_exists: if TRUE and dest_name exists, the copy will fail.
1541  *
1542  * Copies file @name to @dest_name
1543  *
1544  * Return value: %TRUE on success, %FALSE otherwise.
1545  */
1546 gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
1547                    gboolean fail_if_exists)
1548 {
1549         gpointer src, dest;
1550         guint32 attrs;
1551         char *buffer;
1552         int remain, n;
1553
1554         attrs = GetFileAttributes (name);
1555         if (attrs == INVALID_FILE_ATTRIBUTES) {
1556                 SetLastError (ERROR_FILE_NOT_FOUND);
1557                 return  FALSE;
1558         }
1559         
1560         src = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1561                           NULL, OPEN_EXISTING, 0, NULL);
1562         if (src == INVALID_HANDLE_VALUE) {
1563                 _wapi_set_last_error_from_errno ();
1564                 return FALSE;
1565         }
1566         
1567         dest = CreateFile (dest_name, GENERIC_WRITE, 0, NULL,
1568                            fail_if_exists ? CREATE_NEW : CREATE_ALWAYS, attrs, NULL);
1569         if (dest == INVALID_HANDLE_VALUE) {
1570                 _wapi_set_last_error_from_errno ();
1571                 CloseHandle (src);
1572                 return FALSE;
1573         }
1574
1575         buffer = g_new (gchar, 2048);
1576
1577         for (;;) {
1578                 if (ReadFile (src, buffer,sizeof (buffer), &remain, NULL) == 0) {
1579                         _wapi_set_last_error_from_errno ();
1580 #ifdef DEBUG
1581                         g_message (G_GNUC_PRETTY_FUNCTION ": read failed.");
1582 #endif
1583                         
1584                         CloseHandle (dest);
1585                         CloseHandle (src);
1586                         return FALSE;
1587                 }
1588
1589                 if (remain == 0)
1590                         break;
1591
1592                 while (remain > 0) {
1593                         if (WriteFile (dest, buffer, remain, &n, NULL) == 0) {
1594                                 _wapi_set_last_error_from_errno ();
1595 #ifdef DEBUG
1596                                 g_message (G_GNUC_PRETTY_FUNCTION ": write failed.");
1597 #endif
1598                                 
1599                                 CloseHandle (dest);
1600                                 CloseHandle (src);
1601                                 return FALSE;
1602                         }
1603
1604                         remain -= n;
1605                 }
1606         }
1607
1608         g_free (buffer);
1609
1610         CloseHandle (dest);
1611         CloseHandle (src);
1612         return TRUE;
1613 }
1614
1615 static gboolean console_find_fd (gpointer handle, gpointer user_data)
1616 {
1617         struct _WapiHandlePrivate_file *file_private_handle;
1618         gboolean ok;
1619         guint32 fd;
1620
1621         fd=GPOINTER_TO_UINT (user_data);
1622         
1623 #ifdef DEBUG
1624         g_message (G_GNUC_PRETTY_FUNCTION
1625                    ": Looking up a console handle for fd %d", fd);
1626 #endif
1627
1628         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
1629                                 (gpointer *)&file_private_handle);
1630         if(ok==FALSE) {
1631                 g_warning (G_GNUC_PRETTY_FUNCTION
1632                            ": error looking up console handle %p", handle);
1633                 return(FALSE);
1634         }
1635         
1636         if(file_private_handle->fd==fd &&
1637            file_private_handle->assigned==TRUE) {
1638 #ifdef DEBUG
1639                 g_message (G_GNUC_PRETTY_FUNCTION
1640                            ": Returning console handle %p", handle);
1641 #endif
1642         
1643                 return(TRUE);
1644         } else {
1645                 return(FALSE);
1646         }
1647 }
1648
1649 /**
1650  * GetStdHandle:
1651  * @stdhandle: specifies the file descriptor
1652  *
1653  * Returns a handle for stdin, stdout, or stderr.  Always returns the
1654  * same handle for the same @stdhandle.
1655  *
1656  * Return value: the handle, or %INVALID_HANDLE_VALUE on error
1657  */
1658
1659 gpointer GetStdHandle(WapiStdHandle stdhandle)
1660 {
1661         struct _WapiHandle_file *file_handle;
1662         struct _WapiHandlePrivate_file *file_private_handle;
1663         gboolean ok;
1664         gpointer handle;
1665         const guchar *name;
1666         int flags, fd;
1667
1668         mono_once (&io_ops_once, io_ops_init);
1669         
1670         switch(stdhandle) {
1671         case STD_INPUT_HANDLE:
1672                 fd=0;
1673                 name="<stdin>";
1674                 break;
1675
1676         case STD_OUTPUT_HANDLE:
1677                 fd=1;
1678                 name="<stdout>";
1679                 break;
1680
1681         case STD_ERROR_HANDLE:
1682                 fd=2;
1683                 name="<stderr>";
1684                 break;
1685
1686         default:
1687 #ifdef DEBUG
1688                 g_message(G_GNUC_PRETTY_FUNCTION
1689                           ": unknown standard handle type");
1690 #endif
1691
1692                 return(INVALID_HANDLE_VALUE);
1693         }
1694
1695 #ifdef DEBUG
1696         g_message(G_GNUC_PRETTY_FUNCTION ": creating standard handle type %s",
1697                   name);
1698 #endif
1699         
1700         /* Check if fd is valid */
1701         flags=fcntl(fd, F_GETFL);
1702         if(flags==-1) {
1703                 /* Invalid fd.  Not really much point checking for EBADF
1704                  * specifically
1705                  */
1706 #ifdef DEBUG
1707                 g_message(G_GNUC_PRETTY_FUNCTION ": fcntl error on fd %d: %s",
1708                           fd, strerror(errno));
1709 #endif
1710
1711                 return(INVALID_HANDLE_VALUE);
1712         }
1713
1714         /* See if we already have a handle for this fd */
1715         handle=_wapi_search_handle (WAPI_HANDLE_CONSOLE, console_find_fd,
1716                                     GUINT_TO_POINTER (fd), NULL, NULL);
1717         if(handle==0) {
1718                 /* Create a new one */
1719                 handle=_wapi_handle_new (WAPI_HANDLE_CONSOLE);
1720                 if(handle==_WAPI_HANDLE_INVALID) {
1721                         g_warning (G_GNUC_PRETTY_FUNCTION
1722                                    ": error creating file handle");
1723                         return(NULL);
1724                 }
1725
1726                 _wapi_handle_lock_handle (handle);
1727         
1728                 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1729                                         (gpointer *)&file_handle,
1730                                         (gpointer *)&file_private_handle);
1731                 if(ok==FALSE) {
1732                         g_warning (G_GNUC_PRETTY_FUNCTION
1733                                    ": error looking up console handle %p",
1734                                    handle);
1735                         _wapi_handle_unlock_handle (handle);
1736                         return(NULL);
1737                 }
1738         
1739                 file_private_handle->fd=fd;
1740                 file_private_handle->assigned=TRUE;
1741                 file_handle->filename=_wapi_handle_scratch_store (name, strlen (name));
1742                 /* some default security attributes might be needed */
1743                 file_handle->security_attributes=0;
1744                 file_handle->fileaccess=convert_from_flags(flags);
1745                 file_handle->sharemode=0;
1746                 file_handle->attrs=0;
1747         
1748 #ifdef DEBUG
1749                 g_message(G_GNUC_PRETTY_FUNCTION
1750                           ": returning handle %p with fd %d", handle,
1751                           file_private_handle->fd);
1752 #endif
1753
1754                 _wapi_handle_unlock_handle (handle);
1755         } else {
1756 #ifdef DEBUG
1757                 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1758                                         (gpointer *)&file_handle,
1759                                         (gpointer *)&file_private_handle);
1760                 if(ok==FALSE) {
1761                         g_warning (G_GNUC_PRETTY_FUNCTION
1762                                    ": error looking up console handle %p",
1763                                    handle);
1764                         return(NULL);
1765                 }
1766
1767                 g_message(G_GNUC_PRETTY_FUNCTION
1768                           ": reusing handle %p with fd %d", handle,
1769                           file_private_handle->fd);
1770 #endif
1771
1772                 /* Add a reference to this reused handle */
1773                 _wapi_handle_ref (handle);
1774         }
1775         
1776         return(handle);
1777 }
1778
1779 /**
1780  * ReadFile:
1781  * @handle: The file handle to read from.  The handle must have
1782  * %GENERIC_READ access.
1783  * @buffer: The buffer to store read data in
1784  * @numbytes: The maximum number of bytes to read
1785  * @bytesread: The actual number of bytes read is stored here.  This
1786  * value can be zero if the handle is positioned at the end of the
1787  * file.
1788  * @overlapped: points to a required %WapiOverlapped structure if
1789  * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1790  * otherwise.
1791  *
1792  * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1793  * function reads up to @numbytes bytes from the file from the current
1794  * file position, and stores them in @buffer.  If there are not enough
1795  * bytes left in the file, just the amount available will be read.
1796  * The actual number of bytes read is stored in @bytesread.
1797
1798  * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1799  * file position is ignored and the read position is taken from data
1800  * in the @overlapped structure.
1801  *
1802  * Return value: %TRUE if the read succeeds (even if no bytes were
1803  * read due to an attempt to read past the end of the file), %FALSE on
1804  * error.
1805  */
1806 gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
1807                   guint32 *bytesread, WapiOverlapped *overlapped)
1808 {
1809         WapiHandleType type=_wapi_handle_type (handle);
1810         
1811         if(io_ops[type].readfile==NULL) {
1812                 return(FALSE);
1813         }
1814         
1815         return(io_ops[type].readfile (handle, buffer, numbytes, bytesread,
1816                                       overlapped));
1817 }
1818
1819 /**
1820  * WriteFile:
1821  * @handle: The file handle to write to.  The handle must have
1822  * %GENERIC_WRITE access.
1823  * @buffer: The buffer to read data from.
1824  * @numbytes: The maximum number of bytes to write.
1825  * @byteswritten: The actual number of bytes written is stored here.
1826  * If the handle is positioned at the file end, the length of the file
1827  * is extended.  This parameter may be %NULL.
1828  * @overlapped: points to a required %WapiOverlapped structure if
1829  * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1830  * otherwise.
1831  *
1832  * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1833  * function writes up to @numbytes bytes from @buffer to the file at
1834  * the current file position.  If @handle is positioned at the end of
1835  * the file, the file is extended.  The actual number of bytes written
1836  * is stored in @byteswritten.
1837  *
1838  * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1839  * file position is ignored and the write position is taken from data
1840  * in the @overlapped structure.
1841  *
1842  * Return value: %TRUE if the write succeeds, %FALSE on error.
1843  */
1844 gboolean WriteFile(gpointer handle, gconstpointer buffer, guint32 numbytes,
1845                    guint32 *byteswritten, WapiOverlapped *overlapped)
1846 {
1847         WapiHandleType type=_wapi_handle_type (handle);
1848         
1849         if(io_ops[type].writefile==NULL) {
1850                 return(FALSE);
1851         }
1852         
1853         return(io_ops[type].writefile (handle, buffer, numbytes, byteswritten,
1854                                        overlapped));
1855 }
1856
1857 /**
1858  * FlushFileBuffers:
1859  * @handle: Handle to open file.  The handle must have
1860  * %GENERIC_WRITE access.
1861  *
1862  * Flushes buffers of the file and causes all unwritten data to
1863  * be written.
1864  *
1865  * Return value: %TRUE on success, %FALSE otherwise.
1866  */
1867 gboolean FlushFileBuffers(gpointer handle)
1868 {
1869         WapiHandleType type=_wapi_handle_type (handle);
1870         
1871         if(io_ops[type].flushfile==NULL) {
1872                 return(FALSE);
1873         }
1874         
1875         return(io_ops[type].flushfile (handle));
1876 }
1877
1878 /**
1879  * SetEndOfFile:
1880  * @handle: The file handle to set.  The handle must have
1881  * %GENERIC_WRITE access.
1882  *
1883  * Moves the end-of-file position to the current position of the file
1884  * pointer.  This function is used to truncate or extend a file.
1885  *
1886  * Return value: %TRUE on success, %FALSE otherwise.
1887  */
1888 gboolean SetEndOfFile(gpointer handle)
1889 {
1890         WapiHandleType type=_wapi_handle_type (handle);
1891         
1892         if(io_ops[type].setendoffile==NULL) {
1893                 return(FALSE);
1894         }
1895         
1896         return(io_ops[type].setendoffile (handle));
1897 }
1898
1899 /**
1900  * SetFilePointer:
1901  * @handle: The file handle to set.  The handle must have
1902  * %GENERIC_READ or %GENERIC_WRITE access.
1903  * @movedistance: Low 32 bits of a signed value that specifies the
1904  * number of bytes to move the file pointer.
1905  * @highmovedistance: Pointer to the high 32 bits of a signed value
1906  * that specifies the number of bytes to move the file pointer, or
1907  * %NULL.
1908  * @method: The starting point for the file pointer move.
1909  *
1910  * Sets the file pointer of an open file.
1911  *
1912  * The distance to move the file pointer is calculated from
1913  * @movedistance and @highmovedistance: If @highmovedistance is %NULL,
1914  * @movedistance is the 32-bit signed value; otherwise, @movedistance
1915  * is the low 32 bits and @highmovedistance a pointer to the high 32
1916  * bits of a 64 bit signed value.  A positive distance moves the file
1917  * pointer forward from the position specified by @method; a negative
1918  * distance moves the file pointer backward.
1919  *
1920  * If the library is compiled without large file support,
1921  * @highmovedistance is ignored and its value is set to zero on a
1922  * successful return.
1923  *
1924  * Return value: On success, the low 32 bits of the new file pointer.
1925  * If @highmovedistance is not %NULL, the high 32 bits of the new file
1926  * pointer are stored there.  On failure, %INVALID_SET_FILE_POINTER.
1927  */
1928 guint32 SetFilePointer(gpointer handle, gint32 movedistance,
1929                        gint32 *highmovedistance, WapiSeekMethod method)
1930 {
1931         WapiHandleType type=_wapi_handle_type (handle);
1932         
1933         if(io_ops[type].seek==NULL) {
1934                 return(FALSE);
1935         }
1936         
1937         return(io_ops[type].seek (handle, movedistance, highmovedistance,
1938                                   method));
1939 }
1940
1941 /**
1942  * GetFileType:
1943  * @handle: The file handle to test.
1944  *
1945  * Finds the type of file @handle.
1946  *
1947  * Return value: %FILE_TYPE_UNKNOWN - the type of the file @handle is
1948  * unknown.  %FILE_TYPE_DISK - @handle is a disk file.
1949  * %FILE_TYPE_CHAR - @handle is a character device, such as a console.
1950  * %FILE_TYPE_PIPE - @handle is a named or anonymous pipe.
1951  */
1952 WapiFileType GetFileType(gpointer handle)
1953 {
1954         WapiHandleType type=_wapi_handle_type (handle);
1955         
1956         if(io_ops[type].getfiletype==NULL) {
1957                 return(FILE_TYPE_UNKNOWN);
1958         }
1959         
1960         return(io_ops[type].getfiletype ());
1961 }
1962
1963 /**
1964  * GetFileSize:
1965  * @handle: The file handle to query.  The handle must have
1966  * %GENERIC_READ or %GENERIC_WRITE access.
1967  * @highsize: If non-%NULL, the high 32 bits of the file size are
1968  * stored here.
1969  *
1970  * Retrieves the size of the file @handle.
1971  *
1972  * If the library is compiled without large file support, @highsize
1973  * has its value set to zero on a successful return.
1974  *
1975  * Return value: On success, the low 32 bits of the file size.  If
1976  * @highsize is non-%NULL then the high 32 bits of the file size are
1977  * stored here.  On failure %INVALID_FILE_SIZE is returned.
1978  */
1979 guint32 GetFileSize(gpointer handle, guint32 *highsize)
1980 {
1981         WapiHandleType type=_wapi_handle_type (handle);
1982         
1983         if(io_ops[type].getfilesize==NULL) {
1984                 return(FALSE);
1985         }
1986         
1987         return(io_ops[type].getfilesize (handle, highsize));
1988 }
1989
1990 /**
1991  * GetFileTime:
1992  * @handle: The file handle to query.  The handle must have
1993  * %GENERIC_READ access.
1994  * @create_time: Points to a %WapiFileTime structure to receive the
1995  * number of ticks since the epoch that file was created.  May be
1996  * %NULL.
1997  * @last_access: Points to a %WapiFileTime structure to receive the
1998  * number of ticks since the epoch when file was last accessed.  May be
1999  * %NULL.
2000  * @last_write: Points to a %WapiFileTime structure to receive the
2001  * number of ticks since the epoch when file was last written to.  May
2002  * be %NULL.
2003  *
2004  * Finds the number of ticks since the epoch that the file referenced
2005  * by @handle was created, last accessed and last modified.  A tick is
2006  * a 100 nanosecond interval.  The epoch is Midnight, January 1 1601
2007  * GMT.
2008  *
2009  * Create time isn't recorded on POSIX file systems or reported by
2010  * stat(2), so that time is guessed by returning the oldest of the
2011  * other times.
2012  *
2013  * Return value: %TRUE on success, %FALSE otherwise.
2014  */
2015 gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
2016                      WapiFileTime *last_access, WapiFileTime *last_write)
2017 {
2018         WapiHandleType type=_wapi_handle_type (handle);
2019         
2020         if(io_ops[type].getfiletime==NULL) {
2021                 return(FALSE);
2022         }
2023         
2024         return(io_ops[type].getfiletime (handle, create_time, last_access,
2025                                          last_write));
2026 }
2027
2028 /**
2029  * SetFileTime:
2030  * @handle: The file handle to set.  The handle must have
2031  * %GENERIC_WRITE access.
2032  * @create_time: Points to a %WapiFileTime structure that contains the
2033  * number of ticks since the epoch that the file was created.  May be
2034  * %NULL.
2035  * @last_access: Points to a %WapiFileTime structure that contains the
2036  * number of ticks since the epoch when the file was last accessed.
2037  * May be %NULL.
2038  * @last_write: Points to a %WapiFileTime structure that contains the
2039  * number of ticks since the epoch when the file was last written to.
2040  * May be %NULL.
2041  *
2042  * Sets the number of ticks since the epoch that the file referenced
2043  * by @handle was created, last accessed or last modified.  A tick is
2044  * a 100 nanosecond interval.  The epoch is Midnight, January 1 1601
2045  * GMT.
2046  *
2047  * Create time isn't recorded on POSIX file systems, and is ignored.
2048  *
2049  * Return value: %TRUE on success, %FALSE otherwise.
2050  */
2051 gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
2052                      const WapiFileTime *last_access,
2053                      const WapiFileTime *last_write)
2054 {
2055         WapiHandleType type=_wapi_handle_type (handle);
2056         
2057         if(io_ops[type].setfiletime==NULL) {
2058                 return(FALSE);
2059         }
2060         
2061         return(io_ops[type].setfiletime (handle, create_time, last_access,
2062                                          last_write));
2063 }
2064
2065 /* A tick is a 100-nanosecond interval.  File time epoch is Midnight,
2066  * January 1 1601 GMT
2067  */
2068
2069 #define TICKS_PER_MILLISECOND 10000L
2070 #define TICKS_PER_SECOND 10000000L
2071 #define TICKS_PER_MINUTE 600000000L
2072 #define TICKS_PER_HOUR 36000000000L
2073 #define TICKS_PER_DAY 864000000000L
2074
2075 #define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
2076
2077 static const guint16 mon_yday[2][13]={
2078         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
2079         {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
2080 };
2081
2082 /**
2083  * FileTimeToSystemTime:
2084  * @file_time: Points to a %WapiFileTime structure that contains the
2085  * number of ticks to convert.
2086  * @system_time: Points to a %WapiSystemTime structure to receive the
2087  * broken-out time.
2088  *
2089  * Converts a tick count into broken-out time values.
2090  *
2091  * Return value: %TRUE on success, %FALSE otherwise.
2092  */
2093 gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
2094                               WapiSystemTime *system_time)
2095 {
2096         gint64 file_ticks, totaldays, rem, y;
2097         const guint16 *ip;
2098         
2099         if(system_time==NULL) {
2100 #ifdef DEBUG
2101                 g_message(G_GNUC_PRETTY_FUNCTION ": system_time NULL");
2102 #endif
2103
2104                 return(FALSE);
2105         }
2106         
2107         file_ticks=((gint64)file_time->dwHighDateTime << 32) +
2108                 file_time->dwLowDateTime;
2109         
2110         /* Really compares if file_ticks>=0x8000000000000000
2111          * (LLONG_MAX+1) but we're working with a signed value for the
2112          * year and day calculation to work later
2113          */
2114         if(file_ticks<0) {
2115 #ifdef DEBUG
2116                 g_message(G_GNUC_PRETTY_FUNCTION ": file_time too big");
2117 #endif
2118
2119                 return(FALSE);
2120         }
2121
2122         totaldays=(file_ticks / TICKS_PER_DAY);
2123         rem = file_ticks % TICKS_PER_DAY;
2124 #ifdef DEBUG
2125         g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld rem: %lld",
2126                   totaldays, rem);
2127 #endif
2128
2129         system_time->wHour=rem/TICKS_PER_HOUR;
2130         rem %= TICKS_PER_HOUR;
2131 #ifdef DEBUG
2132         g_message(G_GNUC_PRETTY_FUNCTION ": Hour: %d rem: %lld",
2133                   system_time->wHour, rem);
2134 #endif
2135         
2136         system_time->wMinute = rem / TICKS_PER_MINUTE;
2137         rem %= TICKS_PER_MINUTE;
2138 #ifdef DEBUG
2139         g_message(G_GNUC_PRETTY_FUNCTION ": Minute: %d rem: %lld",
2140                   system_time->wMinute, rem);
2141 #endif
2142         
2143         system_time->wSecond = rem / TICKS_PER_SECOND;
2144         rem %= TICKS_PER_SECOND;
2145 #ifdef DEBUG
2146         g_message(G_GNUC_PRETTY_FUNCTION ": Second: %d rem: %lld",
2147                   system_time->wSecond, rem);
2148 #endif
2149         
2150         system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
2151 #ifdef DEBUG
2152         g_message(G_GNUC_PRETTY_FUNCTION ": Milliseconds: %d",
2153                   system_time->wMilliseconds);
2154 #endif
2155
2156         /* January 1, 1601 was a Monday, according to Emacs calendar */
2157         system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
2158 #ifdef DEBUG
2159         g_message(G_GNUC_PRETTY_FUNCTION ": Day of week: %d",
2160                   system_time->wDayOfWeek);
2161 #endif
2162         
2163         /* This algorithm to find year and month given days from epoch
2164          * from glibc
2165          */
2166         y=1601;
2167         
2168 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
2169 #define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400))
2170
2171         while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
2172                 /* Guess a corrected year, assuming 365 days per year */
2173                 gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
2174 #ifdef DEBUG
2175                 g_message(G_GNUC_PRETTY_FUNCTION
2176                           ": totaldays: %lld yg: %lld y: %lld", totaldays, yg,
2177                           y);
2178                 g_message(G_GNUC_PRETTY_FUNCTION
2179                           ": LEAPS(yg): %lld LEAPS(y): %lld",
2180                           LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
2181 #endif
2182                 
2183                 /* Adjust days and y to match the guessed year. */
2184                 totaldays -= ((yg - y) * 365
2185                               + LEAPS_THRU_END_OF (yg - 1)
2186                               - LEAPS_THRU_END_OF (y - 1));
2187 #ifdef DEBUG
2188                 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld",
2189                           totaldays);
2190 #endif
2191                 y = yg;
2192 #ifdef DEBUG
2193                 g_message(G_GNUC_PRETTY_FUNCTION ": y: %lld", y);
2194 #endif
2195         }
2196         
2197         system_time->wYear = y;
2198 #ifdef DEBUG
2199         g_message(G_GNUC_PRETTY_FUNCTION ": Year: %d", system_time->wYear);
2200 #endif
2201
2202         ip = mon_yday[isleap(y)];
2203         
2204         for(y=11; totaldays < ip[y]; --y) {
2205                 continue;
2206         }
2207         totaldays-=ip[y];
2208 #ifdef DEBUG
2209         g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld", totaldays);
2210 #endif
2211         
2212         system_time->wMonth = y + 1;
2213 #ifdef DEBUG
2214         g_message(G_GNUC_PRETTY_FUNCTION ": Month: %d", system_time->wMonth);
2215 #endif
2216
2217         system_time->wDay = totaldays + 1;
2218 #ifdef DEBUG
2219         g_message(G_GNUC_PRETTY_FUNCTION ": Day: %d", system_time->wDay);
2220 #endif
2221         
2222         return(TRUE);
2223 }
2224
2225 gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
2226 {
2227         struct _WapiHandle_find *find_handle;
2228         gpointer handle;
2229         gboolean ok;
2230         gchar *utf8_pattern = NULL;
2231         int result;
2232         
2233         if (pattern == NULL) {
2234 #ifdef DEBUG
2235                 g_message (G_GNUC_PRETTY_FUNCTION ": pattern is NULL");
2236 #endif
2237
2238                 return INVALID_HANDLE_VALUE;
2239         }
2240
2241         utf8_pattern = _wapi_unicode_to_utf8 (pattern);
2242         if (utf8_pattern == NULL) {
2243 #ifdef DEBUG
2244                 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2245 #endif
2246                 
2247                 return INVALID_HANDLE_VALUE;
2248         }
2249         
2250         handle=_wapi_handle_new (WAPI_HANDLE_FIND);
2251         if(handle==_WAPI_HANDLE_INVALID) {
2252                 g_warning (G_GNUC_PRETTY_FUNCTION
2253                            ": error creating find handle");
2254                 g_free (utf8_pattern);
2255                 
2256                 return(INVALID_HANDLE_VALUE);
2257         }
2258
2259         _wapi_handle_lock_handle (handle);
2260         
2261         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2262                                 (gpointer *)&find_handle, NULL);
2263         if(ok==FALSE) {
2264                 g_warning (G_GNUC_PRETTY_FUNCTION
2265                            ": error looking up find handle %p", handle);
2266                 _wapi_handle_unlock_handle (handle);
2267                 g_free (utf8_pattern);
2268                 
2269                 return(INVALID_HANDLE_VALUE);
2270         }
2271         
2272         result = glob (utf8_pattern, 0, NULL, &find_handle->glob);
2273         g_free (utf8_pattern);
2274
2275         if (result != 0) {
2276                 globfree (&find_handle->glob);
2277                 _wapi_handle_unlock_handle (handle);
2278                 _wapi_handle_unref (handle);
2279
2280                 switch (result) {
2281 #ifdef GLOB_NOMATCH
2282                 case GLOB_NOMATCH:
2283                         SetLastError (ERROR_NO_MORE_FILES);
2284                         break;
2285 #endif
2286
2287                 default:
2288 #ifdef DEBUG
2289                         g_message (G_GNUC_PRETTY_FUNCTION ": glob failed with code %d.", result);
2290 #endif
2291
2292                         break;
2293                 }
2294
2295                 return INVALID_HANDLE_VALUE;
2296         }
2297
2298         find_handle->count = 0;
2299         if (!FindNextFile (handle, find_data)) {
2300                 FindClose (handle);
2301                 SetLastError (ERROR_NO_MORE_FILES);
2302                 return INVALID_HANDLE_VALUE;
2303         }
2304
2305         _wapi_handle_unlock_handle (handle);
2306
2307         return (handle);
2308 }
2309
2310 gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
2311 {
2312         struct _WapiHandle_find *find_handle;
2313         gboolean ok;
2314         struct stat buf;
2315         const gchar *filename;
2316         
2317         gchar *base_filename;
2318         gunichar2 *utf16_basename;
2319         time_t create_time;
2320         int i;
2321         
2322         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2323                                 (gpointer *)&find_handle, NULL);
2324         if(ok==FALSE) {
2325                 g_warning (G_GNUC_PRETTY_FUNCTION
2326                            ": error looking up find handle %p", handle);
2327                 SetLastError (ERROR_INVALID_HANDLE);
2328                 return(FALSE);
2329         }
2330
2331         if (find_handle->count >= find_handle->glob.gl_pathc) {
2332                 SetLastError (ERROR_NO_MORE_FILES);
2333                 return FALSE;
2334         }
2335
2336         /* stat next glob match */
2337
2338         filename = find_handle->glob.gl_pathv [find_handle->count ++];
2339         if (stat (filename, &buf) != 0) {
2340 #ifdef DEBUG
2341                 g_message (G_GNUC_PRETTY_FUNCTION ": stat failed: %s", filename);
2342 #endif
2343
2344                 SetLastError (ERROR_NO_MORE_FILES);
2345                 return FALSE;
2346         }
2347
2348         /* fill data block */
2349
2350         if (buf.st_mtime < buf.st_ctime)
2351                 create_time = buf.st_mtime;
2352         else
2353                 create_time = buf.st_ctime;
2354         
2355         find_data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2356
2357         _wapi_time_t_to_filetime (create_time, &find_data->ftCreationTime);
2358         _wapi_time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
2359         _wapi_time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime);
2360
2361         if (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2362                 find_data->nFileSizeHigh = 0;
2363                 find_data->nFileSizeLow = 0;
2364         }
2365         else {
2366                 find_data->nFileSizeHigh = buf.st_size >> 32;
2367                 find_data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2368         }
2369
2370         find_data->dwReserved0 = 0;
2371         find_data->dwReserved1 = 0;
2372
2373         base_filename = g_path_get_basename (filename);
2374         utf16_basename = g_utf8_to_utf16 (base_filename, MAX_PATH, NULL, NULL, NULL);
2375
2376         i = 0;
2377         while (utf16_basename [i] != 0) {       /* copy basename */
2378                 find_data->cFileName [i] = utf16_basename [i];
2379                 ++ i;
2380         }
2381
2382         find_data->cFileName[i] = 0;            /* null terminate */
2383         find_data->cAlternateFileName [0] = 0;  /* not used */
2384
2385         g_free (base_filename);
2386         g_free (utf16_basename);
2387         return TRUE;
2388 }
2389
2390 /**
2391  * FindClose:
2392  * @wapi_handle: the find handle to close.
2393  *
2394  * Closes find handle @wapi_handle
2395  *
2396  * Return value: %TRUE on success, %FALSE otherwise.
2397  */
2398 gboolean FindClose (gpointer handle)
2399 {
2400         struct _WapiHandle_find *find_handle;
2401         gboolean ok;
2402         
2403         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2404                                 (gpointer *)&find_handle, NULL);
2405         if(ok==FALSE) {
2406                 g_warning (G_GNUC_PRETTY_FUNCTION
2407                            ": error looking up find handle %p", handle);
2408                 SetLastError (ERROR_INVALID_HANDLE);
2409                 return(FALSE);
2410         }
2411         
2412         globfree (&find_handle->glob);
2413         _wapi_handle_unref (handle);
2414
2415         return TRUE;
2416 }
2417
2418 /**
2419  * CreateDirectory:
2420  * @name: a pointer to a NULL-terminated unicode string, that names
2421  * the directory to be created.
2422  * @security: ignored for now
2423  *
2424  * Creates directory @name
2425  *
2426  * Return value: %TRUE on success, %FALSE otherwise.
2427  */
2428 gboolean CreateDirectory (const gunichar2 *name, WapiSecurityAttributes *security)
2429 {
2430         gchar *utf8_name;
2431         int result;
2432         
2433         utf8_name = _wapi_unicode_to_utf8 (name);
2434         if (utf8_name == NULL) {
2435 #ifdef DEBUG
2436                 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2437 #endif
2438         
2439                 return FALSE;
2440         }
2441
2442         result = mkdir (utf8_name, 0777);
2443         g_free (utf8_name);
2444
2445         if (result == 0)
2446                 return TRUE;
2447
2448         switch (errno) {
2449         case EEXIST:
2450                 return TRUE;
2451         default:
2452                 _wapi_set_last_error_from_errno ();
2453                 break;
2454         }
2455         
2456         return FALSE;
2457 }
2458
2459 /**
2460  * RemoveDirectory:
2461  * @name: a pointer to a NULL-terminated unicode string, that names
2462  * the directory to be removed.
2463  *
2464  * Removes directory @name
2465  *
2466  * Return value: %TRUE on success, %FALSE otherwise.
2467  */
2468 gboolean RemoveDirectory (const gunichar2 *name)
2469 {
2470         gchar *utf8_name;
2471         int result;
2472
2473         utf8_name = _wapi_unicode_to_utf8 (name);
2474         if (utf8_name == NULL) {
2475 #ifdef DEBUG
2476                 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2477 #endif
2478                 
2479                 return FALSE;
2480         }
2481
2482         result = rmdir (utf8_name);
2483         g_free (utf8_name);
2484
2485         if (result == 0)
2486                 return TRUE;
2487         
2488         _wapi_set_last_error_from_errno ();
2489         return FALSE;
2490 }
2491
2492 /**
2493  * GetFileAttributes:
2494  * @name: a pointer to a NULL-terminated unicode filename.
2495  *
2496  * Gets the attributes for @name;
2497  *
2498  * Return value: %INVALID_FILE_ATTRIBUTES on failure
2499  */
2500 guint32 GetFileAttributes (const gunichar2 *name)
2501 {
2502         gchar *utf8_name;
2503         struct stat buf;
2504         int result;
2505         
2506         utf8_name = _wapi_unicode_to_utf8 (name);
2507         if (utf8_name == NULL) {
2508 #ifdef DEBUG
2509                 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2510 #endif
2511
2512                 SetLastError (ERROR_INVALID_PARAMETER);
2513                 return (INVALID_FILE_ATTRIBUTES);
2514         }
2515
2516         result = stat (utf8_name, &buf);
2517         g_free (utf8_name);
2518
2519         if (result != 0) {
2520                 SetLastError (ERROR_FILE_NOT_FOUND);
2521                 return (INVALID_FILE_ATTRIBUTES);
2522         }
2523         
2524         return _wapi_stat_to_file_attributes (&buf);
2525 }
2526
2527 /**
2528  * GetFileAttributesEx:
2529  * @name: a pointer to a NULL-terminated unicode filename.
2530  * @level: must be GetFileExInfoStandard
2531  * @info: pointer to a WapiFileAttributesData structure
2532  *
2533  * Gets attributes, size and filetimes for @name;
2534  *
2535  * Return value: %TRUE on success, %FALSE on failure
2536  */
2537 gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels level, gpointer info)
2538 {
2539         gchar *utf8_name;
2540         WapiFileAttributesData *data;
2541
2542         struct stat buf;
2543         time_t create_time;
2544         int result;
2545         
2546         if (level != GetFileExInfoStandard) {
2547 #ifdef DEBUG
2548                 g_message (G_GNUC_PRETTY_FUNCTION ": info level %d not supported.", level);
2549 #endif
2550
2551                 return FALSE;
2552         }
2553
2554         utf8_name = _wapi_unicode_to_utf8 (name);
2555         if (utf8_name == NULL) {
2556 #ifdef DEBUG
2557                 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2558 #endif
2559
2560                 SetLastError (ERROR_INVALID_PARAMETER);
2561                 return FALSE;
2562         }
2563
2564         result = stat (utf8_name, &buf);
2565         g_free (utf8_name);
2566
2567         if (result != 0) {
2568                 SetLastError (ERROR_FILE_NOT_FOUND);
2569                 return FALSE;
2570         }
2571
2572         /* fill data block */
2573
2574         data = (WapiFileAttributesData *)info;
2575
2576         if (buf.st_mtime < buf.st_ctime)
2577                 create_time = buf.st_mtime;
2578         else
2579                 create_time = buf.st_ctime;
2580         
2581         data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2582
2583         _wapi_time_t_to_filetime (create_time, &data->ftCreationTime);
2584         _wapi_time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
2585         _wapi_time_t_to_filetime (buf.st_mtime, &data->ftLastWriteTime);
2586
2587         if (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2588                 data->nFileSizeHigh = 0;
2589                 data->nFileSizeLow = 0;
2590         }
2591         else {
2592                 data->nFileSizeHigh = buf.st_size >> 32;
2593                 data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2594         }
2595
2596         return TRUE;
2597 }
2598
2599 /**
2600  * SetFileAttributes
2601  * @name: name of file
2602  * @attrs: attributes to set
2603  *
2604  * Changes the attributes on a named file.
2605  *
2606  * Return value: %TRUE on success, %FALSE on failure.
2607  */
2608 extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
2609 {
2610         /* FIXME: think of something clever to do on unix */
2611         gchar *utf8_name;
2612         struct stat buf;
2613         int result;
2614
2615         /*
2616          * Currently we only handle one *internal* case, with a value that is
2617          * not standard: 0x80000000, which means `set executable bit'
2618          */
2619
2620         utf8_name = _wapi_unicode_to_utf8 (name);
2621         result = stat (utf8_name, &buf);
2622         if (result != 0) {
2623                 g_free (utf8_name);
2624                 SetLastError (ERROR_FILE_NOT_FOUND);
2625                 return FALSE;
2626         }
2627
2628         if (attrs == 0x80000000){
2629                 result = chmod (utf8_name, buf.st_mode | S_IEXEC | S_IXOTH | S_IXGRP);
2630                 g_free (utf8_name);
2631                 if (result != 0) {
2632                         g_free (utf8_name);
2633                         SetLastError (ERROR_FILE_NOT_FOUND);
2634                         return FALSE;
2635                 }
2636
2637                 return TRUE;
2638         }
2639
2640         SetLastError (ERROR_INVALID_FUNCTION);
2641         return FALSE;
2642 }
2643
2644 /**
2645  * GetCurrentDirectory
2646  * @length: size of the buffer
2647  * @buffer: pointer to buffer that recieves path
2648  *
2649  * Retrieves the current directory for the current process.
2650  *
2651  * Return value: number of characters in buffer on success, zero on failure
2652  */
2653 extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer)
2654 {
2655         gchar *path;
2656         gunichar2 *utf16_path, *ptr;
2657         glong count = 0;
2658         
2659         path = g_get_current_dir ();
2660         if (path == NULL)
2661                 return 0;
2662         
2663         /* if buffer too small, return number of characters required.
2664          * this is plain dumb.
2665          */
2666         
2667         count = strlen (path) + 1;
2668         if (count > length)
2669                 return count;
2670         
2671         utf16_path = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
2672         if (utf16_path == NULL)
2673                 return 0;
2674
2675         ptr = utf16_path;
2676         while (*ptr)
2677                 *buffer ++ = *ptr ++;
2678         
2679         *buffer = 0;
2680         
2681         g_free (utf16_path);
2682         g_free (path);
2683
2684         return count;
2685 }
2686
2687 /**
2688  * SetCurrentDirectory
2689  * @path: path to new directory
2690  *
2691  * Changes the directory path for the current process.
2692  *
2693  * Return value: %TRUE on success, %FALSE on failure.
2694  */
2695 extern gboolean SetCurrentDirectory (const gunichar2 *path)
2696 {
2697         gchar *utf8_path;
2698         gboolean result;
2699
2700         utf8_path = _wapi_unicode_to_utf8 (path);
2701         if (chdir (utf8_path) != 0) {
2702                 _wapi_set_last_error_from_errno ();
2703                 result = FALSE;
2704         }
2705         else
2706                 result = TRUE;
2707
2708         g_free (utf8_path);
2709         return result;
2710 }
2711
2712 int _wapi_file_handle_to_fd (gpointer handle)
2713 {
2714         struct _WapiHandlePrivate_file *file_private_handle;
2715         gboolean ok;
2716         
2717 #ifdef DEBUG
2718         g_message (G_GNUC_PRETTY_FUNCTION ": looking up fd for %p", handle);
2719 #endif
2720
2721         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
2722                                 (gpointer *)&file_private_handle);
2723         if(ok==FALSE) {
2724                 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE, NULL,
2725                                         (gpointer *)&file_private_handle);
2726                 if(ok==FALSE) {
2727                         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE, NULL,
2728                                                 (gpointer *)&file_private_handle);
2729                         if(ok==FALSE) {
2730 #ifdef DEBUG
2731                                 g_message (G_GNUC_PRETTY_FUNCTION
2732                                            ": returning -1");
2733 #endif
2734                                 return(-1);
2735                         }
2736                 }
2737         }
2738         
2739 #ifdef DEBUG
2740         g_message (G_GNUC_PRETTY_FUNCTION ": returning %d",
2741                    file_private_handle->fd);
2742 #endif
2743         
2744         return(file_private_handle->fd);
2745 }
2746
2747 gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
2748                      WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 size)
2749 {
2750         struct _WapiHandle_file *pipe_read_handle;
2751         struct _WapiHandle_file *pipe_write_handle;
2752         struct _WapiHandlePrivate_file *pipe_read_private_handle;
2753         struct _WapiHandlePrivate_file *pipe_write_private_handle;
2754         gpointer read_handle;
2755         gpointer write_handle;
2756         gboolean ok;
2757         int filedes[2];
2758         int ret;
2759         
2760         mono_once (&io_ops_once, io_ops_init);
2761         
2762 #ifdef DEBUG
2763         g_message (G_GNUC_PRETTY_FUNCTION ": Creating pipe");
2764 #endif
2765
2766         ret=pipe (filedes);
2767         if(ret==-1) {
2768 #ifdef DEBUG
2769                 g_message (G_GNUC_PRETTY_FUNCTION ": Error creating pipe: %s",
2770                            strerror (errno));
2771 #endif
2772                 
2773                 _wapi_set_last_error_from_errno ();
2774                 return(FALSE);
2775         }
2776         
2777         /* filedes[0] is open for reading, filedes[1] for writing */
2778
2779         read_handle=_wapi_handle_new (WAPI_HANDLE_PIPE);
2780         if(read_handle==_WAPI_HANDLE_INVALID) {
2781                 g_warning (G_GNUC_PRETTY_FUNCTION
2782                            ": error creating pipe read handle");
2783                 close (filedes[0]);
2784                 close (filedes[1]);
2785                 return(FALSE);
2786         }
2787         
2788         _wapi_handle_lock_handle (read_handle);
2789
2790         ok=_wapi_lookup_handle (read_handle, WAPI_HANDLE_PIPE,
2791                                 (gpointer *)&pipe_read_handle,
2792                                 (gpointer *)&pipe_read_private_handle);
2793         if(ok==FALSE) {
2794                 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2795                 _wapi_handle_unlock_handle (read_handle);
2796                 close (filedes[0]);
2797                 close (filedes[1]);
2798                 return(FALSE);
2799         }
2800         
2801         write_handle=_wapi_handle_new (WAPI_HANDLE_PIPE);
2802         if(write_handle==_WAPI_HANDLE_INVALID) {
2803                 g_warning (G_GNUC_PRETTY_FUNCTION
2804                            ": error creating pipe write handle");
2805                 _wapi_handle_unlock_handle (read_handle);
2806                 _wapi_handle_unref (read_handle);
2807                 
2808                 close (filedes[0]);
2809                 close (filedes[1]);
2810                 return(FALSE);
2811         }
2812         
2813         _wapi_handle_lock_handle (write_handle);
2814
2815         ok=_wapi_lookup_handle (write_handle, WAPI_HANDLE_PIPE,
2816                                 (gpointer *)&pipe_write_handle,
2817                                 (gpointer *)&pipe_write_private_handle);
2818         if(ok==FALSE) {
2819                 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2820                 _wapi_handle_unlock_handle (read_handle);
2821                 _wapi_handle_unref (read_handle);
2822                 _wapi_handle_unlock_handle (write_handle);
2823                 close (filedes[0]);
2824                 close (filedes[1]);
2825                 return(FALSE);
2826         }
2827         
2828         pipe_read_private_handle->fd=filedes[0];
2829         pipe_read_private_handle->assigned=TRUE;
2830         pipe_read_handle->fileaccess=GENERIC_READ;
2831         
2832         *readpipe=read_handle;
2833
2834         pipe_write_private_handle->fd=filedes[1];
2835         pipe_write_private_handle->assigned=TRUE;
2836         pipe_write_handle->fileaccess=GENERIC_WRITE;
2837         
2838         *writepipe=write_handle;
2839
2840         _wapi_handle_unlock_handle (read_handle);
2841         _wapi_handle_unlock_handle (write_handle);
2842
2843 #ifdef DEBUG
2844         g_message (G_GNUC_PRETTY_FUNCTION
2845                    ": Returning pipe: read handle %p, write handle %p",
2846                    read_handle, write_handle);
2847 #endif
2848
2849         return(TRUE);
2850 }