2 * io.c: File, console and find handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
17 #include <sys/types.h>
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>
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);
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 */
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);
72 /* Console is mostly the same as file, except it can block waiting for
75 struct _WapiHandleOps _wapi_console_ops = {
76 console_close_shared, /* close_shared */
77 console_close_private, /* close_private */
83 /* Find handle has no ops.
85 struct _WapiHandleOps _wapi_find_ops = {
86 NULL, /* close_shared */
87 NULL, /* close_private */
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);
104 struct _WapiHandleOps _wapi_pipe_ops = {
105 pipe_close_shared, /* close_shared */
106 pipe_close_private, /* close_private */
113 /* File, console and pipe handles */
114 WapiFileType (*getfiletype)(void);
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);
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},
141 file_read, file_write,
142 file_flush, file_seek,
148 {console_getfiletype,
151 NULL, NULL, NULL, NULL, NULL, NULL},
153 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
155 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
157 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
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},
163 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
165 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
170 NULL, NULL, NULL, NULL, NULL, NULL},
174 static mono_once_t io_ops_once=MONO_ONCE_INIT;
176 static void io_ops_init (void)
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); */
184 /* Some utility functions.
187 static guint32 _wapi_stat_to_file_attributes (struct stat *buf)
191 /* FIXME: this could definitely be better */
193 if (S_ISDIR (buf->st_mode))
194 attrs |= FILE_ATTRIBUTE_DIRECTORY;
196 attrs |= FILE_ATTRIBUTE_ARCHIVE;
198 if (!(buf->st_mode & S_IWUSR))
199 attrs |= FILE_ATTRIBUTE_READONLY;
204 static void _wapi_set_last_error_from_errno (void)
206 /* mapping ideas borrowed from wine. they may need some work */
209 case EACCES: case EPERM: case EROFS:
210 SetLastError (ERROR_ACCESS_DENIED);
214 SetLastError (ERROR_SHARING_VIOLATION);
218 SetLastError (ERROR_LOCK_VIOLATION);
222 SetLastError (ERROR_FILE_EXISTS);
225 case EINVAL: case ESPIPE:
226 SetLastError (ERROR_SEEK);
230 SetLastError (ERROR_CANNOT_MAKE);
233 case ENFILE: case EMFILE:
234 SetLastError (ERROR_NO_MORE_FILES);
237 case ENOENT: case ENOTDIR:
238 SetLastError (ERROR_FILE_NOT_FOUND);
242 SetLastError (ERROR_HANDLE_DISK_FULL);
246 SetLastError (ERROR_DIR_NOT_EMPTY);
250 SetLastError (ERROR_BAD_FORMAT);
254 SetLastError (ERROR_FILENAME_EXCED_RANGE);
258 g_message ("Unknown errno: %s\n", strerror (errno));
259 SetLastError (ERROR_GEN_FAILURE);
266 static void file_close_shared (gpointer handle)
268 struct _WapiHandle_file *file_handle;
271 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
272 (gpointer *)&file_handle, NULL);
274 g_warning (G_GNUC_PRETTY_FUNCTION
275 ": error looking up file handle %p", handle);
280 g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p", handle);
283 if(file_handle->filename!=0) {
284 _wapi_handle_scratch_delete (file_handle->filename);
285 file_handle->filename=0;
287 if(file_handle->security_attributes!=0) {
288 _wapi_handle_scratch_delete (file_handle->security_attributes);
289 file_handle->security_attributes=0;
293 static void file_close_private (gpointer handle)
295 struct _WapiHandlePrivate_file *file_private_handle;
298 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE, NULL,
299 (gpointer *)&file_private_handle);
301 g_warning (G_GNUC_PRETTY_FUNCTION
302 ": error looking up file handle %p", handle);
307 g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p with fd %d",
308 handle, file_private_handle->fd);
311 close(file_private_handle->fd);
314 static WapiFileType file_getfiletype(void)
316 return(FILE_TYPE_DISK);
319 static gboolean file_read(gpointer handle, gpointer buffer,
320 guint32 numbytes, guint32 *bytesread,
321 WapiOverlapped *overlapped G_GNUC_UNUSED)
323 struct _WapiHandle_file *file_handle;
324 struct _WapiHandlePrivate_file *file_private_handle;
328 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
329 (gpointer *)&file_handle,
330 (gpointer *)&file_private_handle);
332 g_warning (G_GNUC_PRETTY_FUNCTION
333 ": error looking up file handle %p", handle);
337 if(bytesread!=NULL) {
341 if(!(file_handle->fileaccess&GENERIC_READ) &&
342 !(file_handle->fileaccess&GENERIC_ALL)) {
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);
350 ret=read(file_private_handle->fd, buffer, numbytes);
353 g_message(G_GNUC_PRETTY_FUNCTION
354 ": read of handle %p fd %d error: %s", handle,
355 file_private_handle->fd, strerror(errno));
361 if(bytesread!=NULL) {
368 static gboolean file_write(gpointer handle, gconstpointer buffer,
369 guint32 numbytes, guint32 *byteswritten,
370 WapiOverlapped *overlapped G_GNUC_UNUSED)
372 struct _WapiHandle_file *file_handle;
373 struct _WapiHandlePrivate_file *file_private_handle;
377 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
378 (gpointer *)&file_handle,
379 (gpointer *)&file_private_handle);
381 g_warning (G_GNUC_PRETTY_FUNCTION
382 ": error looking up file handle %p", handle);
386 if(byteswritten!=NULL) {
390 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
391 !(file_handle->fileaccess&GENERIC_ALL)) {
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);
399 ret=write(file_private_handle->fd, buffer, numbytes);
402 g_message(G_GNUC_PRETTY_FUNCTION
403 ": write of handle %p fd %d error: %s", handle,
404 file_private_handle->fd, strerror(errno));
409 if(byteswritten!=NULL) {
416 static gboolean file_flush(gpointer handle)
418 struct _WapiHandle_file *file_handle;
419 struct _WapiHandlePrivate_file *file_private_handle;
423 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
424 (gpointer *)&file_handle,
425 (gpointer *)&file_private_handle);
427 g_warning (G_GNUC_PRETTY_FUNCTION
428 ": error looking up file handle %p", handle);
432 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
433 !(file_handle->fileaccess&GENERIC_ALL)) {
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);
441 ret=fsync(file_private_handle->fd);
444 g_message(G_GNUC_PRETTY_FUNCTION
445 ": write of handle %p fd %d error: %s", handle,
446 file_private_handle->fd, strerror(errno));
455 static guint32 file_seek(gpointer handle, gint32 movedistance,
456 gint32 *highmovedistance, WapiSeekMethod method)
458 struct _WapiHandle_file *file_handle;
459 struct _WapiHandlePrivate_file *file_private_handle;
461 off_t offset, newpos;
465 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
466 (gpointer *)&file_handle,
467 (gpointer *)&file_private_handle);
469 g_warning (G_GNUC_PRETTY_FUNCTION
470 ": error looking up file handle %p", handle);
471 return(INVALID_SET_FILE_POINTER);
474 if(!(file_handle->fileaccess&GENERIC_READ) &&
475 !(file_handle->fileaccess&GENERIC_WRITE) &&
476 !(file_handle->fileaccess&GENERIC_ALL)) {
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);
481 return(INVALID_SET_FILE_POINTER);
496 g_message(G_GNUC_PRETTY_FUNCTION ": invalid seek type %d",
500 return(INVALID_SET_FILE_POINTER);
503 #ifdef HAVE_LARGE_FILE_SUPPORT
504 if(highmovedistance==NULL) {
507 g_message(G_GNUC_PRETTY_FUNCTION
508 ": setting offset to %lld (low %d)", offset,
512 offset=((gint64) *highmovedistance << 32) | movedistance;
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);
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);
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);
534 newpos=lseek(file_private_handle->fd, offset, whence);
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));
542 return(INVALID_SET_FILE_POINTER);
546 #ifdef HAVE_LARGE_FILE_SUPPORT
547 g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %lld", newpos);
549 g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %ld", newpos);
553 #ifdef HAVE_LARGE_FILE_SUPPORT
554 ret=newpos & 0xFFFFFFFF;
555 if(highmovedistance!=NULL) {
556 *highmovedistance=newpos>>32;
560 if(highmovedistance!=NULL) {
561 /* Accurate, but potentially dodgy :-) */
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);
576 static gboolean file_setendoffile(gpointer handle)
578 struct _WapiHandle_file *file_handle;
579 struct _WapiHandlePrivate_file *file_private_handle;
585 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
586 (gpointer *)&file_handle,
587 (gpointer *)&file_private_handle);
589 g_warning (G_GNUC_PRETTY_FUNCTION
590 ": error looking up file handle %p", handle);
594 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
595 !(file_handle->fileaccess&GENERIC_ALL)) {
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);
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.
609 ret=fstat(file_private_handle->fd, &statbuf);
612 g_message(G_GNUC_PRETTY_FUNCTION
613 ": handle %p fd %d fstat failed: %s", handle,
614 file_private_handle->fd, strerror(errno));
619 size=statbuf.st_size;
621 pos=lseek(file_private_handle->fd, (off_t)0, SEEK_CUR);
624 g_message(G_GNUC_PRETTY_FUNCTION
625 ": handle %p fd %d lseek failed: %s", handle,
626 file_private_handle->fd, strerror(errno));
634 ret=write(file_private_handle->fd, "", 1);
637 g_message(G_GNUC_PRETTY_FUNCTION
638 ": handle %p fd %d extend write failed: %s",
639 handle, file_private_handle->fd,
647 /* always truncate, because the extend write() adds an extra
648 * byte to the end of the file
650 ret=ftruncate(file_private_handle->fd, pos);
653 g_message(G_GNUC_PRETTY_FUNCTION
654 ": handle %p fd %d ftruncate failed: %s", handle,
655 file_private_handle->fd, strerror(errno));
664 static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
666 struct _WapiHandle_file *file_handle;
667 struct _WapiHandlePrivate_file *file_private_handle;
673 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
674 (gpointer *)&file_handle,
675 (gpointer *)&file_private_handle);
677 g_warning (G_GNUC_PRETTY_FUNCTION
678 ": error looking up file handle %p", handle);
679 return(INVALID_FILE_SIZE);
682 if(!(file_handle->fileaccess&GENERIC_READ) &&
683 !(file_handle->fileaccess&GENERIC_WRITE) &&
684 !(file_handle->fileaccess&GENERIC_ALL)) {
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);
689 return(INVALID_FILE_SIZE);
692 ret=fstat(file_private_handle->fd, &statbuf);
695 g_message(G_GNUC_PRETTY_FUNCTION
696 ": handle %p fd %d fstat failed: %s", handle,
697 file_private_handle->fd, strerror(errno));
700 return(INVALID_FILE_SIZE);
703 #ifdef HAVE_LARGE_FILE_SUPPORT
704 size=statbuf.st_size & 0xFFFFFFFF;
706 *highsize=statbuf.st_size>>32;
710 /* Accurate, but potentially dodgy :-) */
713 size=statbuf.st_size;
717 g_message(G_GNUC_PRETTY_FUNCTION ": Returning size %d/%d", size,
724 static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
725 WapiFileTime *last_access,
726 WapiFileTime *last_write)
728 struct _WapiHandle_file *file_handle;
729 struct _WapiHandlePrivate_file *file_private_handle;
732 guint64 create_ticks, access_ticks, write_ticks;
735 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
736 (gpointer *)&file_handle,
737 (gpointer *)&file_private_handle);
739 g_warning (G_GNUC_PRETTY_FUNCTION
740 ": error looking up file handle %p", handle);
744 if(!(file_handle->fileaccess&GENERIC_READ) &&
745 !(file_handle->fileaccess&GENERIC_ALL)) {
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);
753 ret=fstat(file_private_handle->fd, &statbuf);
756 g_message(G_GNUC_PRETTY_FUNCTION
757 ": handle %p fd %d fstat failed: %s", handle,
758 file_private_handle->fd, strerror(errno));
765 g_message(G_GNUC_PRETTY_FUNCTION
766 ": atime: %ld ctime: %ld mtime: %ld",
767 statbuf.st_atime, statbuf.st_ctime,
771 /* Try and guess a meaningful create time by using the older
774 /* The magic constant comes from msdn documentation
775 * "Converting a time_t Value to a File Time"
777 if(statbuf.st_atime < statbuf.st_ctime) {
778 create_ticks=((guint64)statbuf.st_atime*10000000)
779 + 116444736000000000UL;
781 create_ticks=((guint64)statbuf.st_ctime*10000000)
782 + 116444736000000000UL;
785 access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000UL;
786 write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000UL;
789 g_message(G_GNUC_PRETTY_FUNCTION
790 ": aticks: %llu cticks: %llu wticks: %llu",
791 access_ticks, create_ticks, write_ticks);
794 if(create_time!=NULL) {
795 create_time->dwLowDateTime = create_ticks & 0xFFFFFFFF;
796 create_time->dwHighDateTime = create_ticks >> 32;
799 if(last_access!=NULL) {
800 last_access->dwLowDateTime = access_ticks & 0xFFFFFFFF;
801 last_access->dwHighDateTime = access_ticks >> 32;
804 if(last_write!=NULL) {
805 last_write->dwLowDateTime = write_ticks & 0xFFFFFFFF;
806 last_write->dwHighDateTime = write_ticks >> 32;
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)
817 struct _WapiHandle_file *file_handle;
818 struct _WapiHandlePrivate_file *file_private_handle;
821 struct utimbuf utbuf;
823 guint64 access_ticks, write_ticks;
826 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
827 (gpointer *)&file_handle,
828 (gpointer *)&file_private_handle);
830 g_warning (G_GNUC_PRETTY_FUNCTION
831 ": error looking up file handle %p", handle);
835 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
836 !(file_handle->fileaccess&GENERIC_ALL)) {
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);
844 if(file_handle->filename==0) {
846 g_message(G_GNUC_PRETTY_FUNCTION
847 ": handle %p fd %d unknown filename", handle,
848 file_private_handle->fd);
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
857 ret=fstat(file_private_handle->fd, &statbuf);
860 g_message(G_GNUC_PRETTY_FUNCTION
861 ": handle %p fd %d fstat failed: %s", handle,
862 file_private_handle->fd, strerror(errno));
868 if(last_access!=NULL) {
869 access_ticks=((guint64)last_access->dwHighDateTime << 32) +
870 last_access->dwLowDateTime;
871 utbuf.actime=(access_ticks - 116444736000000000) / 10000000;
873 utbuf.actime=statbuf.st_atime;
876 if(last_write!=NULL) {
877 write_ticks=((guint64)last_write->dwHighDateTime << 32) +
878 last_write->dwLowDateTime;
879 utbuf.modtime=(write_ticks - 116444736000000000) / 10000000;
881 utbuf.modtime=statbuf.st_mtime;
885 g_message(G_GNUC_PRETTY_FUNCTION
886 ": setting handle %p access %ld write %ld", handle,
887 utbuf.actime, utbuf.modtime);
890 name=_wapi_handle_scratch_lookup_as_string (file_handle->filename);
892 ret=utime(name, &utbuf);
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));
909 static void console_close_shared (gpointer handle)
911 struct _WapiHandle_file *console_handle;
914 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
915 (gpointer *)&console_handle, NULL);
917 g_warning (G_GNUC_PRETTY_FUNCTION
918 ": error looking up console handle %p", handle);
923 g_message(G_GNUC_PRETTY_FUNCTION ": closing console handle %p", handle);
926 if(console_handle->filename!=0) {
927 _wapi_handle_scratch_delete (console_handle->filename);
928 console_handle->filename=0;
930 if(console_handle->security_attributes!=0) {
931 _wapi_handle_scratch_delete (console_handle->security_attributes);
932 console_handle->security_attributes=0;
936 static void console_close_private (gpointer handle)
938 struct _WapiHandlePrivate_file *console_private_handle;
941 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
942 (gpointer *)&console_private_handle);
944 g_warning (G_GNUC_PRETTY_FUNCTION
945 ": error looking up console handle %p", handle);
950 g_message(G_GNUC_PRETTY_FUNCTION
951 ": closing console handle %p with fd %d", handle,
952 console_private_handle->fd);
955 close(console_private_handle->fd);
958 static WapiFileType console_getfiletype(void)
960 return(FILE_TYPE_CHAR);
963 static gboolean console_read(gpointer handle, gpointer buffer,
964 guint32 numbytes, guint32 *bytesread,
965 WapiOverlapped *overlapped G_GNUC_UNUSED)
967 struct _WapiHandle_file *console_handle;
968 struct _WapiHandlePrivate_file *console_private_handle;
972 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
973 (gpointer *)&console_handle,
974 (gpointer *)&console_private_handle);
976 g_warning (G_GNUC_PRETTY_FUNCTION
977 ": error looking up console handle %p", handle);
981 if(bytesread!=NULL) {
985 if(!(console_handle->fileaccess&GENERIC_READ) &&
986 !(console_handle->fileaccess&GENERIC_ALL)) {
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);
994 ret=read(console_private_handle->fd, buffer, numbytes);
997 g_message(G_GNUC_PRETTY_FUNCTION
998 ": read of handle %p fd %d error: %s", handle,
999 console_private_handle->fd, strerror(errno));
1005 if(bytesread!=NULL) {
1012 static gboolean console_write(gpointer handle, gconstpointer buffer,
1013 guint32 numbytes, guint32 *byteswritten,
1014 WapiOverlapped *overlapped G_GNUC_UNUSED)
1016 struct _WapiHandle_file *console_handle;
1017 struct _WapiHandlePrivate_file *console_private_handle;
1021 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1022 (gpointer *)&console_handle,
1023 (gpointer *)&console_private_handle);
1025 g_warning (G_GNUC_PRETTY_FUNCTION
1026 ": error looking up console handle %p", handle);
1030 if(byteswritten!=NULL) {
1034 if(!(console_handle->fileaccess&GENERIC_WRITE) &&
1035 !(console_handle->fileaccess&GENERIC_ALL)) {
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);
1043 ret=write(console_private_handle->fd, buffer, numbytes);
1046 g_message(G_GNUC_PRETTY_FUNCTION
1047 ": write of handle %p fd %d error: %s", handle,
1048 console_private_handle->fd, strerror(errno));
1053 if(byteswritten!=NULL) {
1060 static void pipe_close_shared (gpointer handle)
1062 struct _WapiHandle_file *pipe_handle;
1065 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1066 (gpointer *)&pipe_handle, NULL);
1068 g_warning (G_GNUC_PRETTY_FUNCTION
1069 ": error looking up pipe handle %p", handle);
1074 g_message(G_GNUC_PRETTY_FUNCTION ": closing pipe handle %p", handle);
1077 if(pipe_handle->filename!=0) {
1078 _wapi_handle_scratch_delete (pipe_handle->filename);
1079 pipe_handle->filename=0;
1081 if(pipe_handle->security_attributes!=0) {
1082 _wapi_handle_scratch_delete (pipe_handle->security_attributes);
1083 pipe_handle->security_attributes=0;
1087 static void pipe_close_private (gpointer handle)
1089 struct _WapiHandlePrivate_file *pipe_private_handle;
1092 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE, NULL,
1093 (gpointer *)&pipe_private_handle);
1095 g_warning (G_GNUC_PRETTY_FUNCTION
1096 ": error looking up pipe handle %p", handle);
1101 g_message(G_GNUC_PRETTY_FUNCTION
1102 ": closing pipe handle %p with fd %d", handle,
1103 pipe_private_handle->fd);
1106 close(pipe_private_handle->fd);
1109 static WapiFileType pipe_getfiletype(void)
1111 return(FILE_TYPE_PIPE);
1114 static gboolean pipe_read (gpointer handle, gpointer buffer,
1115 guint32 numbytes, guint32 *bytesread,
1116 WapiOverlapped *overlapped G_GNUC_UNUSED)
1118 struct _WapiHandle_file *pipe_handle;
1119 struct _WapiHandlePrivate_file *pipe_private_handle;
1123 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1124 (gpointer *)&pipe_handle,
1125 (gpointer *)&pipe_private_handle);
1127 g_warning (G_GNUC_PRETTY_FUNCTION
1128 ": error looking up pipe handle %p", handle);
1132 if(bytesread!=NULL) {
1136 if(!(pipe_handle->fileaccess&GENERIC_READ) &&
1137 !(pipe_handle->fileaccess&GENERIC_ALL)) {
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);
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);
1151 ret=read(pipe_private_handle->fd, buffer, numbytes);
1154 g_message(G_GNUC_PRETTY_FUNCTION
1155 ": read of handle %p fd %d error: %s", handle,
1156 pipe_private_handle->fd, strerror(errno));
1163 g_message (G_GNUC_PRETTY_FUNCTION ": read %d bytes from pipe", ret);
1166 if(bytesread!=NULL) {
1173 static gboolean pipe_write(gpointer handle, gconstpointer buffer,
1174 guint32 numbytes, guint32 *byteswritten,
1175 WapiOverlapped *overlapped G_GNUC_UNUSED)
1177 struct _WapiHandle_file *pipe_handle;
1178 struct _WapiHandlePrivate_file *pipe_private_handle;
1182 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1183 (gpointer *)&pipe_handle,
1184 (gpointer *)&pipe_private_handle);
1186 g_warning (G_GNUC_PRETTY_FUNCTION
1187 ": error looking up pipe handle %p", handle);
1191 if(byteswritten!=NULL) {
1195 if(!(pipe_handle->fileaccess&GENERIC_WRITE) &&
1196 !(pipe_handle->fileaccess&GENERIC_ALL)) {
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);
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);
1210 ret=write(pipe_private_handle->fd, buffer, numbytes);
1213 g_message(G_GNUC_PRETTY_FUNCTION
1214 ": write of handle %p fd %d error: %s", handle,
1215 pipe_private_handle->fd, strerror(errno));
1220 if(byteswritten!=NULL) {
1227 static int convert_flags(guint32 fileaccess, guint32 createmode)
1231 switch(fileaccess) {
1238 case GENERIC_READ|GENERIC_WRITE:
1243 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown access type 0x%x",
1249 switch(createmode) {
1251 flags|=O_CREAT|O_EXCL;
1254 flags|=O_CREAT|O_TRUNC;
1261 case TRUNCATE_EXISTING:
1266 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown create mode 0x%x",
1275 static guint32 convert_from_flags(int flags)
1277 guint32 fileaccess=0;
1280 #define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
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;
1291 g_message(G_GNUC_PRETTY_FUNCTION
1292 ": Can't figure out flags 0x%x", flags);
1296 /* Maybe sort out create mode too */
1301 static mode_t convert_perms(guint32 sharemode)
1305 if(sharemode&FILE_SHARE_READ) {
1308 if(sharemode&FILE_SHARE_WRITE) {
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.
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().
1339 * Return value: the new handle, or %INVALID_HANDLE_VALUE on error.
1341 gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
1342 guint32 sharemode, WapiSecurityAttributes *security,
1343 guint32 createmode, guint32 attrs,
1344 gpointer template G_GNUC_UNUSED)
1346 struct _WapiHandle_file *file_handle;
1347 struct _WapiHandlePrivate_file *file_private_handle;
1350 int flags=convert_flags(fileaccess, createmode);
1351 mode_t perms=convert_perms(sharemode);
1355 mono_once (&io_ops_once, io_ops_init);
1359 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1362 return(INVALID_HANDLE_VALUE);
1365 filename=_wapi_unicode_to_utf8(name);
1366 if(filename==NULL) {
1368 g_message(G_GNUC_PRETTY_FUNCTION
1369 ": unicode conversion returned NULL");
1372 return(INVALID_HANDLE_VALUE);
1375 ret=open(filename, flags, perms);
1379 g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
1380 filename, strerror(errno));
1382 _wapi_set_last_error_from_errno ();
1385 return(INVALID_HANDLE_VALUE);
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");
1394 return(INVALID_HANDLE_VALUE);
1397 _wapi_handle_lock_handle (handle);
1399 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
1400 (gpointer *)&file_handle,
1401 (gpointer *)&file_private_handle);
1403 g_warning (G_GNUC_PRETTY_FUNCTION
1404 ": error looking up file handle %p", handle);
1405 _wapi_handle_unlock_handle (handle);
1408 return(INVALID_HANDLE_VALUE);
1411 file_private_handle->fd=ret;
1412 file_private_handle->assigned=TRUE;
1413 file_handle->filename=_wapi_handle_scratch_store (filename,
1415 if(security!=NULL) {
1416 file_handle->security_attributes=_wapi_handle_scratch_store (
1417 security, sizeof(WapiSecurityAttributes));
1420 file_handle->fileaccess=fileaccess;
1421 file_handle->sharemode=sharemode;
1422 file_handle->attrs=attrs;
1425 g_message(G_GNUC_PRETTY_FUNCTION
1426 ": returning handle %p with fd %d", handle,
1427 file_private_handle->fd);
1430 _wapi_handle_unlock_handle (handle);
1438 * @name: a pointer to a NULL-terminated unicode string, that names
1439 * the file to be deleted.
1441 * Deletes file @name.
1443 * Return value: %TRUE on success, %FALSE otherwise.
1445 gboolean DeleteFile(const gunichar2 *name)
1452 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1458 filename=_wapi_unicode_to_utf8(name);
1459 if(filename==NULL) {
1461 g_message(G_GNUC_PRETTY_FUNCTION
1462 ": unicode conversion returned NULL");
1468 ret=unlink(filename);
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.
1486 * Renames file @name to @dest_name
1488 * Return value: %TRUE on success, %FALSE otherwise.
1490 gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
1492 gchar *utf8_name, *utf8_dest_name;
1495 utf8_name = _wapi_unicode_to_utf8 (name);
1496 if (utf8_name == NULL) {
1498 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1504 utf8_dest_name = _wapi_unicode_to_utf8 (dest_name);
1505 if (utf8_dest_name == NULL) {
1507 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1514 result = rename (utf8_name, utf8_dest_name);
1516 g_free (utf8_dest_name);
1523 SetLastError (ERROR_ALREADY_EXISTS);
1527 _wapi_set_last_error_from_errno ();
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.
1542 * Copies file @name to @dest_name
1544 * Return value: %TRUE on success, %FALSE otherwise.
1546 gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
1547 gboolean fail_if_exists)
1554 attrs = GetFileAttributes (name);
1555 if (attrs == INVALID_FILE_ATTRIBUTES) {
1556 SetLastError (ERROR_FILE_NOT_FOUND);
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 ();
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 ();
1575 buffer = g_new (gchar, 2048);
1578 if (ReadFile (src, buffer,sizeof (buffer), &remain, NULL) == 0) {
1579 _wapi_set_last_error_from_errno ();
1581 g_message (G_GNUC_PRETTY_FUNCTION ": read failed.");
1592 while (remain > 0) {
1593 if (WriteFile (dest, buffer, remain, &n, NULL) == 0) {
1594 _wapi_set_last_error_from_errno ();
1596 g_message (G_GNUC_PRETTY_FUNCTION ": write failed.");
1615 static gboolean console_find_fd (gpointer handle, gpointer user_data)
1617 struct _WapiHandlePrivate_file *file_private_handle;
1621 fd=GPOINTER_TO_UINT (user_data);
1624 g_message (G_GNUC_PRETTY_FUNCTION
1625 ": Looking up a console handle for fd %d", fd);
1628 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
1629 (gpointer *)&file_private_handle);
1631 g_warning (G_GNUC_PRETTY_FUNCTION
1632 ": error looking up console handle %p", handle);
1636 if(file_private_handle->fd==fd &&
1637 file_private_handle->assigned==TRUE) {
1639 g_message (G_GNUC_PRETTY_FUNCTION
1640 ": Returning console handle %p", handle);
1651 * @stdhandle: specifies the file descriptor
1653 * Returns a handle for stdin, stdout, or stderr. Always returns the
1654 * same handle for the same @stdhandle.
1656 * Return value: the handle, or %INVALID_HANDLE_VALUE on error
1659 gpointer GetStdHandle(WapiStdHandle stdhandle)
1661 struct _WapiHandle_file *file_handle;
1662 struct _WapiHandlePrivate_file *file_private_handle;
1668 mono_once (&io_ops_once, io_ops_init);
1671 case STD_INPUT_HANDLE:
1676 case STD_OUTPUT_HANDLE:
1681 case STD_ERROR_HANDLE:
1688 g_message(G_GNUC_PRETTY_FUNCTION
1689 ": unknown standard handle type");
1692 return(INVALID_HANDLE_VALUE);
1696 g_message(G_GNUC_PRETTY_FUNCTION ": creating standard handle type %s",
1700 /* Check if fd is valid */
1701 flags=fcntl(fd, F_GETFL);
1703 /* Invalid fd. Not really much point checking for EBADF
1707 g_message(G_GNUC_PRETTY_FUNCTION ": fcntl error on fd %d: %s",
1708 fd, strerror(errno));
1711 return(INVALID_HANDLE_VALUE);
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);
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");
1726 _wapi_handle_lock_handle (handle);
1728 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1729 (gpointer *)&file_handle,
1730 (gpointer *)&file_private_handle);
1732 g_warning (G_GNUC_PRETTY_FUNCTION
1733 ": error looking up console handle %p",
1735 _wapi_handle_unlock_handle (handle);
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;
1749 g_message(G_GNUC_PRETTY_FUNCTION
1750 ": returning handle %p with fd %d", handle,
1751 file_private_handle->fd);
1754 _wapi_handle_unlock_handle (handle);
1757 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1758 (gpointer *)&file_handle,
1759 (gpointer *)&file_private_handle);
1761 g_warning (G_GNUC_PRETTY_FUNCTION
1762 ": error looking up console handle %p",
1767 g_message(G_GNUC_PRETTY_FUNCTION
1768 ": reusing handle %p with fd %d", handle,
1769 file_private_handle->fd);
1772 /* Add a reference to this reused handle */
1773 _wapi_handle_ref (handle);
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
1788 * @overlapped: points to a required %WapiOverlapped structure if
1789 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
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.
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.
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
1806 gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
1807 guint32 *bytesread, WapiOverlapped *overlapped)
1809 WapiHandleType type=_wapi_handle_type (handle);
1811 if(io_ops[type].readfile==NULL) {
1815 return(io_ops[type].readfile (handle, buffer, numbytes, bytesread,
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
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.
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.
1842 * Return value: %TRUE if the write succeeds, %FALSE on error.
1844 gboolean WriteFile(gpointer handle, gconstpointer buffer, guint32 numbytes,
1845 guint32 *byteswritten, WapiOverlapped *overlapped)
1847 WapiHandleType type=_wapi_handle_type (handle);
1849 if(io_ops[type].writefile==NULL) {
1853 return(io_ops[type].writefile (handle, buffer, numbytes, byteswritten,
1859 * @handle: Handle to open file. The handle must have
1860 * %GENERIC_WRITE access.
1862 * Flushes buffers of the file and causes all unwritten data to
1865 * Return value: %TRUE on success, %FALSE otherwise.
1867 gboolean FlushFileBuffers(gpointer handle)
1869 WapiHandleType type=_wapi_handle_type (handle);
1871 if(io_ops[type].flushfile==NULL) {
1875 return(io_ops[type].flushfile (handle));
1880 * @handle: The file handle to set. The handle must have
1881 * %GENERIC_WRITE access.
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.
1886 * Return value: %TRUE on success, %FALSE otherwise.
1888 gboolean SetEndOfFile(gpointer handle)
1890 WapiHandleType type=_wapi_handle_type (handle);
1892 if(io_ops[type].setendoffile==NULL) {
1896 return(io_ops[type].setendoffile (handle));
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
1908 * @method: The starting point for the file pointer move.
1910 * Sets the file pointer of an open file.
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.
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.
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.
1928 guint32 SetFilePointer(gpointer handle, gint32 movedistance,
1929 gint32 *highmovedistance, WapiSeekMethod method)
1931 WapiHandleType type=_wapi_handle_type (handle);
1933 if(io_ops[type].seek==NULL) {
1937 return(io_ops[type].seek (handle, movedistance, highmovedistance,
1943 * @handle: The file handle to test.
1945 * Finds the type of file @handle.
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.
1952 WapiFileType GetFileType(gpointer handle)
1954 WapiHandleType type=_wapi_handle_type (handle);
1956 if(io_ops[type].getfiletype==NULL) {
1957 return(FILE_TYPE_UNKNOWN);
1960 return(io_ops[type].getfiletype ());
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
1970 * Retrieves the size of the file @handle.
1972 * If the library is compiled without large file support, @highsize
1973 * has its value set to zero on a successful return.
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.
1979 guint32 GetFileSize(gpointer handle, guint32 *highsize)
1981 WapiHandleType type=_wapi_handle_type (handle);
1983 if(io_ops[type].getfilesize==NULL) {
1987 return(io_ops[type].getfilesize (handle, highsize));
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
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
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
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
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
2013 * Return value: %TRUE on success, %FALSE otherwise.
2015 gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
2016 WapiFileTime *last_access, WapiFileTime *last_write)
2018 WapiHandleType type=_wapi_handle_type (handle);
2020 if(io_ops[type].getfiletime==NULL) {
2024 return(io_ops[type].getfiletime (handle, create_time, last_access,
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
2035 * @last_access: Points to a %WapiFileTime structure that contains the
2036 * number of ticks since the epoch when the file was last accessed.
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.
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
2047 * Create time isn't recorded on POSIX file systems, and is ignored.
2049 * Return value: %TRUE on success, %FALSE otherwise.
2051 gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
2052 const WapiFileTime *last_access,
2053 const WapiFileTime *last_write)
2055 WapiHandleType type=_wapi_handle_type (handle);
2057 if(io_ops[type].setfiletime==NULL) {
2061 return(io_ops[type].setfiletime (handle, create_time, last_access,
2065 /* A tick is a 100-nanosecond interval. File time epoch is Midnight,
2066 * January 1 1601 GMT
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
2075 #define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
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},
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
2089 * Converts a tick count into broken-out time values.
2091 * Return value: %TRUE on success, %FALSE otherwise.
2093 gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
2094 WapiSystemTime *system_time)
2096 gint64 file_ticks, totaldays, rem, y;
2099 if(system_time==NULL) {
2101 g_message(G_GNUC_PRETTY_FUNCTION ": system_time NULL");
2107 file_ticks=((gint64)file_time->dwHighDateTime << 32) +
2108 file_time->dwLowDateTime;
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
2116 g_message(G_GNUC_PRETTY_FUNCTION ": file_time too big");
2122 totaldays=(file_ticks / TICKS_PER_DAY);
2123 rem = file_ticks % TICKS_PER_DAY;
2125 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld rem: %lld",
2129 system_time->wHour=rem/TICKS_PER_HOUR;
2130 rem %= TICKS_PER_HOUR;
2132 g_message(G_GNUC_PRETTY_FUNCTION ": Hour: %d rem: %lld",
2133 system_time->wHour, rem);
2136 system_time->wMinute = rem / TICKS_PER_MINUTE;
2137 rem %= TICKS_PER_MINUTE;
2139 g_message(G_GNUC_PRETTY_FUNCTION ": Minute: %d rem: %lld",
2140 system_time->wMinute, rem);
2143 system_time->wSecond = rem / TICKS_PER_SECOND;
2144 rem %= TICKS_PER_SECOND;
2146 g_message(G_GNUC_PRETTY_FUNCTION ": Second: %d rem: %lld",
2147 system_time->wSecond, rem);
2150 system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
2152 g_message(G_GNUC_PRETTY_FUNCTION ": Milliseconds: %d",
2153 system_time->wMilliseconds);
2156 /* January 1, 1601 was a Monday, according to Emacs calendar */
2157 system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
2159 g_message(G_GNUC_PRETTY_FUNCTION ": Day of week: %d",
2160 system_time->wDayOfWeek);
2163 /* This algorithm to find year and month given days from epoch
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))
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);
2175 g_message(G_GNUC_PRETTY_FUNCTION
2176 ": totaldays: %lld yg: %lld y: %lld", totaldays, yg,
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));
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));
2188 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld",
2193 g_message(G_GNUC_PRETTY_FUNCTION ": y: %lld", y);
2197 system_time->wYear = y;
2199 g_message(G_GNUC_PRETTY_FUNCTION ": Year: %d", system_time->wYear);
2202 ip = mon_yday[isleap(y)];
2204 for(y=11; totaldays < ip[y]; --y) {
2209 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld", totaldays);
2212 system_time->wMonth = y + 1;
2214 g_message(G_GNUC_PRETTY_FUNCTION ": Month: %d", system_time->wMonth);
2217 system_time->wDay = totaldays + 1;
2219 g_message(G_GNUC_PRETTY_FUNCTION ": Day: %d", system_time->wDay);
2225 gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
2227 struct _WapiHandle_find *find_handle;
2230 gchar *utf8_pattern = NULL;
2233 if (pattern == NULL) {
2235 g_message (G_GNUC_PRETTY_FUNCTION ": pattern is NULL");
2238 return INVALID_HANDLE_VALUE;
2241 utf8_pattern = _wapi_unicode_to_utf8 (pattern);
2242 if (utf8_pattern == NULL) {
2244 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2247 return INVALID_HANDLE_VALUE;
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);
2256 return(INVALID_HANDLE_VALUE);
2259 _wapi_handle_lock_handle (handle);
2261 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2262 (gpointer *)&find_handle, NULL);
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);
2269 return(INVALID_HANDLE_VALUE);
2272 result = glob (utf8_pattern, 0, NULL, &find_handle->glob);
2273 g_free (utf8_pattern);
2276 globfree (&find_handle->glob);
2277 _wapi_handle_unlock_handle (handle);
2278 _wapi_handle_unref (handle);
2283 SetLastError (ERROR_NO_MORE_FILES);
2289 g_message (G_GNUC_PRETTY_FUNCTION ": glob failed with code %d.", result);
2295 return INVALID_HANDLE_VALUE;
2298 find_handle->count = 0;
2299 if (!FindNextFile (handle, find_data)) {
2301 SetLastError (ERROR_NO_MORE_FILES);
2302 return INVALID_HANDLE_VALUE;
2305 _wapi_handle_unlock_handle (handle);
2310 gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
2312 struct _WapiHandle_find *find_handle;
2315 const gchar *filename;
2317 gchar *base_filename;
2318 gunichar2 *utf16_basename;
2322 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2323 (gpointer *)&find_handle, NULL);
2325 g_warning (G_GNUC_PRETTY_FUNCTION
2326 ": error looking up find handle %p", handle);
2327 SetLastError (ERROR_INVALID_HANDLE);
2331 if (find_handle->count >= find_handle->glob.gl_pathc) {
2332 SetLastError (ERROR_NO_MORE_FILES);
2336 /* stat next glob match */
2338 filename = find_handle->glob.gl_pathv [find_handle->count ++];
2339 if (stat (filename, &buf) != 0) {
2341 g_message (G_GNUC_PRETTY_FUNCTION ": stat failed: %s", filename);
2344 SetLastError (ERROR_NO_MORE_FILES);
2348 /* fill data block */
2350 if (buf.st_mtime < buf.st_ctime)
2351 create_time = buf.st_mtime;
2353 create_time = buf.st_ctime;
2355 find_data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
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);
2361 if (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2362 find_data->nFileSizeHigh = 0;
2363 find_data->nFileSizeLow = 0;
2366 find_data->nFileSizeHigh = buf.st_size >> 32;
2367 find_data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2370 find_data->dwReserved0 = 0;
2371 find_data->dwReserved1 = 0;
2373 base_filename = g_path_get_basename (filename);
2374 utf16_basename = g_utf8_to_utf16 (base_filename, MAX_PATH, NULL, NULL, NULL);
2377 while (utf16_basename [i] != 0) { /* copy basename */
2378 find_data->cFileName [i] = utf16_basename [i];
2382 find_data->cFileName[i] = 0; /* null terminate */
2383 find_data->cAlternateFileName [0] = 0; /* not used */
2385 g_free (base_filename);
2386 g_free (utf16_basename);
2392 * @wapi_handle: the find handle to close.
2394 * Closes find handle @wapi_handle
2396 * Return value: %TRUE on success, %FALSE otherwise.
2398 gboolean FindClose (gpointer handle)
2400 struct _WapiHandle_find *find_handle;
2403 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2404 (gpointer *)&find_handle, NULL);
2406 g_warning (G_GNUC_PRETTY_FUNCTION
2407 ": error looking up find handle %p", handle);
2408 SetLastError (ERROR_INVALID_HANDLE);
2412 globfree (&find_handle->glob);
2413 _wapi_handle_unref (handle);
2420 * @name: a pointer to a NULL-terminated unicode string, that names
2421 * the directory to be created.
2422 * @security: ignored for now
2424 * Creates directory @name
2426 * Return value: %TRUE on success, %FALSE otherwise.
2428 gboolean CreateDirectory (const gunichar2 *name, WapiSecurityAttributes *security)
2433 utf8_name = _wapi_unicode_to_utf8 (name);
2434 if (utf8_name == NULL) {
2436 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2442 result = mkdir (utf8_name, 0777);
2452 _wapi_set_last_error_from_errno ();
2461 * @name: a pointer to a NULL-terminated unicode string, that names
2462 * the directory to be removed.
2464 * Removes directory @name
2466 * Return value: %TRUE on success, %FALSE otherwise.
2468 gboolean RemoveDirectory (const gunichar2 *name)
2473 utf8_name = _wapi_unicode_to_utf8 (name);
2474 if (utf8_name == NULL) {
2476 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2482 result = rmdir (utf8_name);
2488 _wapi_set_last_error_from_errno ();
2493 * GetFileAttributes:
2494 * @name: a pointer to a NULL-terminated unicode filename.
2496 * Gets the attributes for @name;
2498 * Return value: %INVALID_FILE_ATTRIBUTES on failure
2500 guint32 GetFileAttributes (const gunichar2 *name)
2506 utf8_name = _wapi_unicode_to_utf8 (name);
2507 if (utf8_name == NULL) {
2509 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2512 SetLastError (ERROR_INVALID_PARAMETER);
2513 return (INVALID_FILE_ATTRIBUTES);
2516 result = stat (utf8_name, &buf);
2520 SetLastError (ERROR_FILE_NOT_FOUND);
2521 return (INVALID_FILE_ATTRIBUTES);
2524 return _wapi_stat_to_file_attributes (&buf);
2528 * GetFileAttributesEx:
2529 * @name: a pointer to a NULL-terminated unicode filename.
2530 * @level: must be GetFileExInfoStandard
2531 * @info: pointer to a WapiFileAttributesData structure
2533 * Gets attributes, size and filetimes for @name;
2535 * Return value: %TRUE on success, %FALSE on failure
2537 gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels level, gpointer info)
2540 WapiFileAttributesData *data;
2546 if (level != GetFileExInfoStandard) {
2548 g_message (G_GNUC_PRETTY_FUNCTION ": info level %d not supported.", level);
2554 utf8_name = _wapi_unicode_to_utf8 (name);
2555 if (utf8_name == NULL) {
2557 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2560 SetLastError (ERROR_INVALID_PARAMETER);
2564 result = stat (utf8_name, &buf);
2568 SetLastError (ERROR_FILE_NOT_FOUND);
2572 /* fill data block */
2574 data = (WapiFileAttributesData *)info;
2576 if (buf.st_mtime < buf.st_ctime)
2577 create_time = buf.st_mtime;
2579 create_time = buf.st_ctime;
2581 data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
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);
2587 if (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2588 data->nFileSizeHigh = 0;
2589 data->nFileSizeLow = 0;
2592 data->nFileSizeHigh = buf.st_size >> 32;
2593 data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2601 * @name: name of file
2602 * @attrs: attributes to set
2604 * Changes the attributes on a named file.
2606 * Return value: %TRUE on success, %FALSE on failure.
2608 extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
2610 /* FIXME: think of something clever to do on unix */
2616 * Currently we only handle one *internal* case, with a value that is
2617 * not standard: 0x80000000, which means `set executable bit'
2620 utf8_name = _wapi_unicode_to_utf8 (name);
2621 result = stat (utf8_name, &buf);
2624 SetLastError (ERROR_FILE_NOT_FOUND);
2628 if (attrs == 0x80000000){
2629 result = chmod (utf8_name, buf.st_mode | S_IEXEC | S_IXOTH | S_IXGRP);
2633 SetLastError (ERROR_FILE_NOT_FOUND);
2640 SetLastError (ERROR_INVALID_FUNCTION);
2645 * GetCurrentDirectory
2646 * @length: size of the buffer
2647 * @buffer: pointer to buffer that recieves path
2649 * Retrieves the current directory for the current process.
2651 * Return value: number of characters in buffer on success, zero on failure
2653 extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer)
2656 gunichar2 *utf16_path, *ptr;
2659 path = g_get_current_dir ();
2663 /* if buffer too small, return number of characters required.
2664 * this is plain dumb.
2667 count = strlen (path) + 1;
2671 utf16_path = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
2672 if (utf16_path == NULL)
2677 *buffer ++ = *ptr ++;
2681 g_free (utf16_path);
2688 * SetCurrentDirectory
2689 * @path: path to new directory
2691 * Changes the directory path for the current process.
2693 * Return value: %TRUE on success, %FALSE on failure.
2695 extern gboolean SetCurrentDirectory (const gunichar2 *path)
2700 utf8_path = _wapi_unicode_to_utf8 (path);
2701 if (chdir (utf8_path) != 0) {
2702 _wapi_set_last_error_from_errno ();
2712 int _wapi_file_handle_to_fd (gpointer handle)
2714 struct _WapiHandlePrivate_file *file_private_handle;
2718 g_message (G_GNUC_PRETTY_FUNCTION ": looking up fd for %p", handle);
2721 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
2722 (gpointer *)&file_private_handle);
2724 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE, NULL,
2725 (gpointer *)&file_private_handle);
2727 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE, NULL,
2728 (gpointer *)&file_private_handle);
2731 g_message (G_GNUC_PRETTY_FUNCTION
2740 g_message (G_GNUC_PRETTY_FUNCTION ": returning %d",
2741 file_private_handle->fd);
2744 return(file_private_handle->fd);
2747 gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
2748 WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 size)
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;
2760 mono_once (&io_ops_once, io_ops_init);
2763 g_message (G_GNUC_PRETTY_FUNCTION ": Creating pipe");
2769 g_message (G_GNUC_PRETTY_FUNCTION ": Error creating pipe: %s",
2773 _wapi_set_last_error_from_errno ();
2777 /* filedes[0] is open for reading, filedes[1] for writing */
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");
2788 _wapi_handle_lock_handle (read_handle);
2790 ok=_wapi_lookup_handle (read_handle, WAPI_HANDLE_PIPE,
2791 (gpointer *)&pipe_read_handle,
2792 (gpointer *)&pipe_read_private_handle);
2794 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2795 _wapi_handle_unlock_handle (read_handle);
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);
2813 _wapi_handle_lock_handle (write_handle);
2815 ok=_wapi_lookup_handle (write_handle, WAPI_HANDLE_PIPE,
2816 (gpointer *)&pipe_write_handle,
2817 (gpointer *)&pipe_write_private_handle);
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);
2828 pipe_read_private_handle->fd=filedes[0];
2829 pipe_read_private_handle->assigned=TRUE;
2830 pipe_read_handle->fileaccess=GENERIC_READ;
2832 *readpipe=read_handle;
2834 pipe_write_private_handle->fd=filedes[1];
2835 pipe_write_private_handle->assigned=TRUE;
2836 pipe_write_handle->fileaccess=GENERIC_WRITE;
2838 *writepipe=write_handle;
2840 _wapi_handle_unlock_handle (read_handle);
2841 _wapi_handle_unlock_handle (write_handle);
2844 g_message (G_GNUC_PRETTY_FUNCTION
2845 ": Returning pipe: read handle %p, write handle %p",
2846 read_handle, write_handle);