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/wapi-private.h>
24 #include <mono/io-layer/handles-private.h>
25 #include <mono/io-layer/io-private.h>
26 #include <mono/io-layer/timefuncs-private.h>
27 #include <mono/utils/strenc.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 (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=mono_unicode_to_external (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);
1377 /* If we were trying to open a directory with write permissions
1378 * (e.g. O_WRONLY or O_RDWR), this call will fail with
1379 * EISDIR. However, this is a bit bogus because calls to
1380 * manipulate the directory (e.g. SetFileTime) will still work on
1381 * the directory because they use other API calls
1382 * (e.g. utime()). Hence, if we failed with the EISDIR error, try
1383 * to open the directory again without write permission.
1385 if (ret == -1 && errno == EISDIR)
1387 /* Try again but don't try to make it writable */
1388 ret=open(filename, flags & ~(O_RDWR|O_WRONLY), perms);
1393 g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
1394 filename, strerror(errno));
1396 _wapi_set_last_error_from_errno ();
1399 return(INVALID_HANDLE_VALUE);
1402 handle=_wapi_handle_new (WAPI_HANDLE_FILE);
1403 if(handle==_WAPI_HANDLE_INVALID) {
1404 g_warning (G_GNUC_PRETTY_FUNCTION
1405 ": error creating file handle");
1408 return(INVALID_HANDLE_VALUE);
1411 _wapi_handle_lock_handle (handle);
1413 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
1414 (gpointer *)&file_handle,
1415 (gpointer *)&file_private_handle);
1417 g_warning (G_GNUC_PRETTY_FUNCTION
1418 ": error looking up file handle %p", handle);
1419 _wapi_handle_unlock_handle (handle);
1422 return(INVALID_HANDLE_VALUE);
1425 file_private_handle->fd=ret;
1426 file_private_handle->assigned=TRUE;
1427 file_handle->filename=_wapi_handle_scratch_store (filename,
1429 if(security!=NULL) {
1430 file_handle->security_attributes=_wapi_handle_scratch_store (
1431 security, sizeof(WapiSecurityAttributes));
1434 file_handle->fileaccess=fileaccess;
1435 file_handle->sharemode=sharemode;
1436 file_handle->attrs=attrs;
1439 g_message(G_GNUC_PRETTY_FUNCTION
1440 ": returning handle %p with fd %d", handle,
1441 file_private_handle->fd);
1444 _wapi_handle_unlock_handle (handle);
1452 * @name: a pointer to a NULL-terminated unicode string, that names
1453 * the file to be deleted.
1455 * Deletes file @name.
1457 * Return value: %TRUE on success, %FALSE otherwise.
1459 gboolean DeleteFile(const gunichar2 *name)
1466 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1472 filename=mono_unicode_to_external(name);
1473 if(filename==NULL) {
1475 g_message(G_GNUC_PRETTY_FUNCTION
1476 ": unicode conversion returned NULL");
1482 ret=unlink(filename);
1490 _wapi_set_last_error_from_errno ();
1496 * @name: a pointer to a NULL-terminated unicode string, that names
1497 * the file to be moved.
1498 * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1499 * new name for the file.
1501 * Renames file @name to @dest_name
1503 * Return value: %TRUE on success, %FALSE otherwise.
1505 gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
1507 gchar *utf8_name, *utf8_dest_name;
1510 utf8_name = mono_unicode_to_external (name);
1511 if (utf8_name == NULL) {
1513 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1519 utf8_dest_name = mono_unicode_to_external (dest_name);
1520 if (utf8_dest_name == NULL) {
1522 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1529 result = rename (utf8_name, utf8_dest_name);
1531 g_free (utf8_dest_name);
1533 if (result != 0 && errno == EXDEV) {
1534 /* Try a copy to the new location, and delete the source */
1535 if (CopyFile (name, dest_name, TRUE)==FALSE) {
1539 return(DeleteFile (name));
1548 SetLastError (ERROR_ALREADY_EXISTS);
1552 _wapi_set_last_error_from_errno ();
1561 * @name: a pointer to a NULL-terminated unicode string, that names
1562 * the file to be copied.
1563 * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1564 * new name for the file.
1565 * @fail_if_exists: if TRUE and dest_name exists, the copy will fail.
1567 * Copies file @name to @dest_name
1569 * Return value: %TRUE on success, %FALSE otherwise.
1571 gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
1572 gboolean fail_if_exists)
1580 struct _WapiHandlePrivate_file *file_private_handle;
1583 attrs = GetFileAttributes (name);
1584 if (attrs == INVALID_FILE_ATTRIBUTES) {
1585 SetLastError (ERROR_FILE_NOT_FOUND);
1589 src = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1590 NULL, OPEN_EXISTING, 0, NULL);
1591 if (src == INVALID_HANDLE_VALUE) {
1592 _wapi_set_last_error_from_errno ();
1596 dest = CreateFile (dest_name, GENERIC_WRITE, 0, NULL,
1597 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS, attrs, NULL);
1598 if (dest == INVALID_HANDLE_VALUE) {
1599 _wapi_set_last_error_from_errno ();
1604 buffer = g_new (gchar, 2048);
1607 if (ReadFile (src, buffer,sizeof (buffer), &remain, NULL) == 0) {
1608 _wapi_set_last_error_from_errno ();
1610 g_message (G_GNUC_PRETTY_FUNCTION ": read failed.");
1621 while (remain > 0) {
1622 if (WriteFile (dest, buffer, remain, &n, NULL) == 0) {
1623 _wapi_set_last_error_from_errno ();
1625 g_message (G_GNUC_PRETTY_FUNCTION ": write failed.");
1639 ok=_wapi_lookup_handle (src, WAPI_HANDLE_FILE,
1640 NULL, (gpointer *)&file_private_handle);
1642 g_warning (G_GNUC_PRETTY_FUNCTION
1643 ": error looking up file handle %p", src);
1648 fd_in=file_private_handle->fd;
1651 ok=_wapi_lookup_handle (dest, WAPI_HANDLE_FILE,
1652 NULL, (gpointer *)&file_private_handle);
1654 g_warning (G_GNUC_PRETTY_FUNCTION
1655 ": error looking up file handle %p", dest);
1660 fd_out=file_private_handle->fd;
1661 fchmod(fd_out, st.st_mode);
1669 static mono_once_t stdhandle_once=MONO_ONCE_INIT;
1670 static gpointer stdin_handle=NULL;
1671 static gpointer stdout_handle=NULL;
1672 static gpointer stderr_handle=NULL;
1674 static gpointer stdhandle_create (int fd, const guchar *name)
1676 struct _WapiHandle_file *file_handle;
1677 struct _WapiHandlePrivate_file *file_private_handle;
1683 g_message(G_GNUC_PRETTY_FUNCTION ": creating standard handle type %s",
1687 /* Check if fd is valid */
1688 flags=fcntl(fd, F_GETFL);
1690 /* Invalid fd. Not really much point checking for EBADF
1694 g_message(G_GNUC_PRETTY_FUNCTION ": fcntl error on fd %d: %s",
1695 fd, strerror(errno));
1698 return(INVALID_HANDLE_VALUE);
1701 handle=_wapi_handle_new (WAPI_HANDLE_CONSOLE);
1702 if(handle==_WAPI_HANDLE_INVALID) {
1703 g_warning (G_GNUC_PRETTY_FUNCTION
1704 ": error creating file handle");
1708 _wapi_handle_lock_handle (handle);
1710 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1711 (gpointer *)&file_handle,
1712 (gpointer *)&file_private_handle);
1714 g_warning (G_GNUC_PRETTY_FUNCTION
1715 ": error looking up console handle %p", handle);
1716 _wapi_handle_unlock_handle (handle);
1720 file_private_handle->fd=fd;
1721 file_private_handle->assigned=TRUE;
1722 file_handle->filename=_wapi_handle_scratch_store (name, strlen (name));
1723 /* some default security attributes might be needed */
1724 file_handle->security_attributes=0;
1725 file_handle->fileaccess=convert_from_flags(flags);
1726 file_handle->sharemode=0;
1727 file_handle->attrs=0;
1730 g_message(G_GNUC_PRETTY_FUNCTION ": returning handle %p with fd %d",
1731 handle, file_private_handle->fd);
1734 _wapi_handle_unlock_handle (handle);
1739 static void stdhandle_init (void)
1741 stdin_handle=stdhandle_create (0, "<stdin>");
1742 stdout_handle=stdhandle_create (1, "<stdout>");
1743 stderr_handle=stdhandle_create (2, "<stderr>");
1748 * @stdhandle: specifies the file descriptor
1750 * Returns a handle for stdin, stdout, or stderr. Always returns the
1751 * same handle for the same @stdhandle.
1753 * Return value: the handle, or %INVALID_HANDLE_VALUE on error
1756 gpointer GetStdHandle(WapiStdHandle stdhandle)
1760 mono_once (&io_ops_once, io_ops_init);
1761 mono_once (&stdhandle_once, stdhandle_init);
1764 case STD_INPUT_HANDLE:
1765 handle=stdin_handle;
1768 case STD_OUTPUT_HANDLE:
1769 handle=stdout_handle;
1772 case STD_ERROR_HANDLE:
1773 handle=stderr_handle;
1778 g_message(G_GNUC_PRETTY_FUNCTION
1779 ": unknown standard handle type");
1782 return(INVALID_HANDLE_VALUE);
1785 /* Add a reference to this handle */
1786 _wapi_handle_ref (handle);
1793 * @handle: The file handle to read from. The handle must have
1794 * %GENERIC_READ access.
1795 * @buffer: The buffer to store read data in
1796 * @numbytes: The maximum number of bytes to read
1797 * @bytesread: The actual number of bytes read is stored here. This
1798 * value can be zero if the handle is positioned at the end of the
1800 * @overlapped: points to a required %WapiOverlapped structure if
1801 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1804 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1805 * function reads up to @numbytes bytes from the file from the current
1806 * file position, and stores them in @buffer. If there are not enough
1807 * bytes left in the file, just the amount available will be read.
1808 * The actual number of bytes read is stored in @bytesread.
1810 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1811 * file position is ignored and the read position is taken from data
1812 * in the @overlapped structure.
1814 * Return value: %TRUE if the read succeeds (even if no bytes were
1815 * read due to an attempt to read past the end of the file), %FALSE on
1818 gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
1819 guint32 *bytesread, WapiOverlapped *overlapped)
1821 WapiHandleType type=_wapi_handle_type (handle);
1823 if(io_ops[type].readfile==NULL) {
1827 return(io_ops[type].readfile (handle, buffer, numbytes, bytesread,
1833 * @handle: The file handle to write to. The handle must have
1834 * %GENERIC_WRITE access.
1835 * @buffer: The buffer to read data from.
1836 * @numbytes: The maximum number of bytes to write.
1837 * @byteswritten: The actual number of bytes written is stored here.
1838 * If the handle is positioned at the file end, the length of the file
1839 * is extended. This parameter may be %NULL.
1840 * @overlapped: points to a required %WapiOverlapped structure if
1841 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1844 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1845 * function writes up to @numbytes bytes from @buffer to the file at
1846 * the current file position. If @handle is positioned at the end of
1847 * the file, the file is extended. The actual number of bytes written
1848 * is stored in @byteswritten.
1850 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1851 * file position is ignored and the write position is taken from data
1852 * in the @overlapped structure.
1854 * Return value: %TRUE if the write succeeds, %FALSE on error.
1856 gboolean WriteFile(gpointer handle, gconstpointer buffer, guint32 numbytes,
1857 guint32 *byteswritten, WapiOverlapped *overlapped)
1859 WapiHandleType type=_wapi_handle_type (handle);
1861 if(io_ops[type].writefile==NULL) {
1865 return(io_ops[type].writefile (handle, buffer, numbytes, byteswritten,
1871 * @handle: Handle to open file. The handle must have
1872 * %GENERIC_WRITE access.
1874 * Flushes buffers of the file and causes all unwritten data to
1877 * Return value: %TRUE on success, %FALSE otherwise.
1879 gboolean FlushFileBuffers(gpointer handle)
1881 WapiHandleType type=_wapi_handle_type (handle);
1883 if(io_ops[type].flushfile==NULL) {
1887 return(io_ops[type].flushfile (handle));
1892 * @handle: The file handle to set. The handle must have
1893 * %GENERIC_WRITE access.
1895 * Moves the end-of-file position to the current position of the file
1896 * pointer. This function is used to truncate or extend a file.
1898 * Return value: %TRUE on success, %FALSE otherwise.
1900 gboolean SetEndOfFile(gpointer handle)
1902 WapiHandleType type=_wapi_handle_type (handle);
1904 if(io_ops[type].setendoffile==NULL) {
1908 return(io_ops[type].setendoffile (handle));
1913 * @handle: The file handle to set. The handle must have
1914 * %GENERIC_READ or %GENERIC_WRITE access.
1915 * @movedistance: Low 32 bits of a signed value that specifies the
1916 * number of bytes to move the file pointer.
1917 * @highmovedistance: Pointer to the high 32 bits of a signed value
1918 * that specifies the number of bytes to move the file pointer, or
1920 * @method: The starting point for the file pointer move.
1922 * Sets the file pointer of an open file.
1924 * The distance to move the file pointer is calculated from
1925 * @movedistance and @highmovedistance: If @highmovedistance is %NULL,
1926 * @movedistance is the 32-bit signed value; otherwise, @movedistance
1927 * is the low 32 bits and @highmovedistance a pointer to the high 32
1928 * bits of a 64 bit signed value. A positive distance moves the file
1929 * pointer forward from the position specified by @method; a negative
1930 * distance moves the file pointer backward.
1932 * If the library is compiled without large file support,
1933 * @highmovedistance is ignored and its value is set to zero on a
1934 * successful return.
1936 * Return value: On success, the low 32 bits of the new file pointer.
1937 * If @highmovedistance is not %NULL, the high 32 bits of the new file
1938 * pointer are stored there. On failure, %INVALID_SET_FILE_POINTER.
1940 guint32 SetFilePointer(gpointer handle, gint32 movedistance,
1941 gint32 *highmovedistance, WapiSeekMethod method)
1943 WapiHandleType type=_wapi_handle_type (handle);
1945 if(io_ops[type].seek==NULL) {
1949 return(io_ops[type].seek (handle, movedistance, highmovedistance,
1955 * @handle: The file handle to test.
1957 * Finds the type of file @handle.
1959 * Return value: %FILE_TYPE_UNKNOWN - the type of the file @handle is
1960 * unknown. %FILE_TYPE_DISK - @handle is a disk file.
1961 * %FILE_TYPE_CHAR - @handle is a character device, such as a console.
1962 * %FILE_TYPE_PIPE - @handle is a named or anonymous pipe.
1964 WapiFileType GetFileType(gpointer handle)
1966 WapiHandleType type=_wapi_handle_type (handle);
1968 if(io_ops[type].getfiletype==NULL) {
1969 return(FILE_TYPE_UNKNOWN);
1972 return(io_ops[type].getfiletype ());
1977 * @handle: The file handle to query. The handle must have
1978 * %GENERIC_READ or %GENERIC_WRITE access.
1979 * @highsize: If non-%NULL, the high 32 bits of the file size are
1982 * Retrieves the size of the file @handle.
1984 * If the library is compiled without large file support, @highsize
1985 * has its value set to zero on a successful return.
1987 * Return value: On success, the low 32 bits of the file size. If
1988 * @highsize is non-%NULL then the high 32 bits of the file size are
1989 * stored here. On failure %INVALID_FILE_SIZE is returned.
1991 guint32 GetFileSize(gpointer handle, guint32 *highsize)
1993 WapiHandleType type=_wapi_handle_type (handle);
1995 if(io_ops[type].getfilesize==NULL) {
1999 return(io_ops[type].getfilesize (handle, highsize));
2004 * @handle: The file handle to query. The handle must have
2005 * %GENERIC_READ access.
2006 * @create_time: Points to a %WapiFileTime structure to receive the
2007 * number of ticks since the epoch that file was created. May be
2009 * @last_access: Points to a %WapiFileTime structure to receive the
2010 * number of ticks since the epoch when file was last accessed. May be
2012 * @last_write: Points to a %WapiFileTime structure to receive the
2013 * number of ticks since the epoch when file was last written to. May
2016 * Finds the number of ticks since the epoch that the file referenced
2017 * by @handle was created, last accessed and last modified. A tick is
2018 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
2021 * Create time isn't recorded on POSIX file systems or reported by
2022 * stat(2), so that time is guessed by returning the oldest of the
2025 * Return value: %TRUE on success, %FALSE otherwise.
2027 gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
2028 WapiFileTime *last_access, WapiFileTime *last_write)
2030 WapiHandleType type=_wapi_handle_type (handle);
2032 if(io_ops[type].getfiletime==NULL) {
2036 return(io_ops[type].getfiletime (handle, create_time, last_access,
2042 * @handle: The file handle to set. The handle must have
2043 * %GENERIC_WRITE access.
2044 * @create_time: Points to a %WapiFileTime structure that contains the
2045 * number of ticks since the epoch that the file was created. May be
2047 * @last_access: Points to a %WapiFileTime structure that contains the
2048 * number of ticks since the epoch when the file was last accessed.
2050 * @last_write: Points to a %WapiFileTime structure that contains the
2051 * number of ticks since the epoch when the file was last written to.
2054 * Sets the number of ticks since the epoch that the file referenced
2055 * by @handle was created, last accessed or last modified. A tick is
2056 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
2059 * Create time isn't recorded on POSIX file systems, and is ignored.
2061 * Return value: %TRUE on success, %FALSE otherwise.
2063 gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
2064 const WapiFileTime *last_access,
2065 const WapiFileTime *last_write)
2067 WapiHandleType type=_wapi_handle_type (handle);
2069 if(io_ops[type].setfiletime==NULL) {
2073 return(io_ops[type].setfiletime (handle, create_time, last_access,
2077 /* A tick is a 100-nanosecond interval. File time epoch is Midnight,
2078 * January 1 1601 GMT
2081 #define TICKS_PER_MILLISECOND 10000L
2082 #define TICKS_PER_SECOND 10000000L
2083 #define TICKS_PER_MINUTE 600000000L
2084 #define TICKS_PER_HOUR 36000000000L
2085 #define TICKS_PER_DAY 864000000000L
2087 #define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
2089 static const guint16 mon_yday[2][13]={
2090 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
2091 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
2095 * FileTimeToSystemTime:
2096 * @file_time: Points to a %WapiFileTime structure that contains the
2097 * number of ticks to convert.
2098 * @system_time: Points to a %WapiSystemTime structure to receive the
2101 * Converts a tick count into broken-out time values.
2103 * Return value: %TRUE on success, %FALSE otherwise.
2105 gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
2106 WapiSystemTime *system_time)
2108 gint64 file_ticks, totaldays, rem, y;
2111 if(system_time==NULL) {
2113 g_message(G_GNUC_PRETTY_FUNCTION ": system_time NULL");
2119 file_ticks=((gint64)file_time->dwHighDateTime << 32) +
2120 file_time->dwLowDateTime;
2122 /* Really compares if file_ticks>=0x8000000000000000
2123 * (LLONG_MAX+1) but we're working with a signed value for the
2124 * year and day calculation to work later
2128 g_message(G_GNUC_PRETTY_FUNCTION ": file_time too big");
2134 totaldays=(file_ticks / TICKS_PER_DAY);
2135 rem = file_ticks % TICKS_PER_DAY;
2137 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld rem: %lld",
2141 system_time->wHour=rem/TICKS_PER_HOUR;
2142 rem %= TICKS_PER_HOUR;
2144 g_message(G_GNUC_PRETTY_FUNCTION ": Hour: %d rem: %lld",
2145 system_time->wHour, rem);
2148 system_time->wMinute = rem / TICKS_PER_MINUTE;
2149 rem %= TICKS_PER_MINUTE;
2151 g_message(G_GNUC_PRETTY_FUNCTION ": Minute: %d rem: %lld",
2152 system_time->wMinute, rem);
2155 system_time->wSecond = rem / TICKS_PER_SECOND;
2156 rem %= TICKS_PER_SECOND;
2158 g_message(G_GNUC_PRETTY_FUNCTION ": Second: %d rem: %lld",
2159 system_time->wSecond, rem);
2162 system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
2164 g_message(G_GNUC_PRETTY_FUNCTION ": Milliseconds: %d",
2165 system_time->wMilliseconds);
2168 /* January 1, 1601 was a Monday, according to Emacs calendar */
2169 system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
2171 g_message(G_GNUC_PRETTY_FUNCTION ": Day of week: %d",
2172 system_time->wDayOfWeek);
2175 /* This algorithm to find year and month given days from epoch
2180 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
2181 #define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400))
2183 while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
2184 /* Guess a corrected year, assuming 365 days per year */
2185 gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
2187 g_message(G_GNUC_PRETTY_FUNCTION
2188 ": totaldays: %lld yg: %lld y: %lld", totaldays, yg,
2190 g_message(G_GNUC_PRETTY_FUNCTION
2191 ": LEAPS(yg): %lld LEAPS(y): %lld",
2192 LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
2195 /* Adjust days and y to match the guessed year. */
2196 totaldays -= ((yg - y) * 365
2197 + LEAPS_THRU_END_OF (yg - 1)
2198 - LEAPS_THRU_END_OF (y - 1));
2200 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld",
2205 g_message(G_GNUC_PRETTY_FUNCTION ": y: %lld", y);
2209 system_time->wYear = y;
2211 g_message(G_GNUC_PRETTY_FUNCTION ": Year: %d", system_time->wYear);
2214 ip = mon_yday[isleap(y)];
2216 for(y=11; totaldays < ip[y]; --y) {
2221 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld", totaldays);
2224 system_time->wMonth = y + 1;
2226 g_message(G_GNUC_PRETTY_FUNCTION ": Month: %d", system_time->wMonth);
2229 system_time->wDay = totaldays + 1;
2231 g_message(G_GNUC_PRETTY_FUNCTION ": Day: %d", system_time->wDay);
2237 gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
2239 struct _WapiHandle_find *find_handle;
2242 gchar *utf8_pattern = NULL;
2245 if (pattern == NULL) {
2247 g_message (G_GNUC_PRETTY_FUNCTION ": pattern is NULL");
2250 return INVALID_HANDLE_VALUE;
2253 utf8_pattern = mono_unicode_to_external (pattern);
2254 if (utf8_pattern == NULL) {
2256 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2259 return INVALID_HANDLE_VALUE;
2263 g_message (G_GNUC_PRETTY_FUNCTION ": looking for [%s]",
2267 handle=_wapi_handle_new (WAPI_HANDLE_FIND);
2268 if(handle==_WAPI_HANDLE_INVALID) {
2269 g_warning (G_GNUC_PRETTY_FUNCTION
2270 ": error creating find handle");
2271 g_free (utf8_pattern);
2273 return(INVALID_HANDLE_VALUE);
2276 _wapi_handle_lock_handle (handle);
2278 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2279 (gpointer *)&find_handle, NULL);
2281 g_warning (G_GNUC_PRETTY_FUNCTION
2282 ": error looking up find handle %p", handle);
2283 _wapi_handle_unlock_handle (handle);
2284 g_free (utf8_pattern);
2286 return(INVALID_HANDLE_VALUE);
2290 /* glibc extension */
2291 result = glob (utf8_pattern, GLOB_PERIOD, NULL, &find_handle->glob);
2293 result = glob (utf8_pattern, 0, NULL, &find_handle->glob);
2295 /* If the last element of the pattern begins
2296 * '<slash>*' (stupid compiler) then add a '/.*'
2299 int len=strlen(utf8_pattern);
2300 if(len==1 && utf8_pattern[0]=='*') {
2301 result = glob (".*", GLOB_APPEND, NULL,
2302 &find_handle->glob);
2304 gchar *last_star=g_strrstr(utf8_pattern, "/*");
2305 gchar *last_slash=g_strrstr(utf8_pattern, "/");
2306 if(last_star==last_slash) {
2307 gchar *append_pattern;
2308 int dotpos=(int)(last_slash-utf8_pattern)+1;
2310 append_pattern=g_new0(gchar, len+2);
2311 strncpy(append_pattern, utf8_pattern, dotpos);
2312 append_pattern[dotpos]='.';
2313 strcpy(append_pattern+dotpos+1, last_slash+1);
2316 g_message (G_GNUC_PRETTY_FUNCTION ": appending glob [%s]", append_pattern);
2318 result = glob (append_pattern, GLOB_APPEND,
2319 NULL, &find_handle->glob);
2321 g_free (append_pattern);
2325 #endif /* !GLOB_PERIOD */
2327 g_free (utf8_pattern);
2330 globfree (&find_handle->glob);
2331 _wapi_handle_unlock_handle (handle);
2332 _wapi_handle_unref (handle);
2337 SetLastError (ERROR_NO_MORE_FILES);
2343 g_message (G_GNUC_PRETTY_FUNCTION ": glob failed with code %d.", result);
2349 return INVALID_HANDLE_VALUE;
2352 find_handle->count = 0;
2353 if (!FindNextFile (handle, find_data)) {
2354 _wapi_handle_unlock_handle (handle);
2356 SetLastError (ERROR_NO_MORE_FILES);
2357 return INVALID_HANDLE_VALUE;
2360 _wapi_handle_unlock_handle (handle);
2365 gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
2367 struct _WapiHandle_find *find_handle;
2370 const gchar *filename;
2371 gchar *utf8_filename, *utf8_basename;
2372 gunichar2 *utf16_basename;
2376 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2377 (gpointer *)&find_handle, NULL);
2379 g_warning (G_GNUC_PRETTY_FUNCTION
2380 ": error looking up find handle %p", handle);
2381 SetLastError (ERROR_INVALID_HANDLE);
2386 if (find_handle->count >= find_handle->glob.gl_pathc) {
2387 SetLastError (ERROR_NO_MORE_FILES);
2391 /* stat next glob match */
2393 filename = find_handle->glob.gl_pathv [find_handle->count ++];
2394 if (lstat (filename, &buf) != 0) {
2396 g_message (G_GNUC_PRETTY_FUNCTION ": stat failed: %s", filename);
2399 SetLastError (ERROR_NO_MORE_FILES);
2403 /* Check for dangling symlinks, and ignore them (principle of
2404 * least surprise, avoiding confusion where we report the file
2405 * exists, but when someone tries to open it we would report
2408 if(S_ISLNK (buf.st_mode)) {
2409 if(stat (filename, &buf) != 0) {
2414 utf8_filename=mono_utf8_from_external (filename);
2415 if(utf8_filename==NULL) {
2416 /* We couldn't turn this filename into utf8 (eg the
2417 * encoding of the name wasn't convertible), so just
2423 /* fill data block */
2425 if (buf.st_mtime < buf.st_ctime)
2426 create_time = buf.st_mtime;
2428 create_time = buf.st_ctime;
2430 find_data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2432 _wapi_time_t_to_filetime (create_time, &find_data->ftCreationTime);
2433 _wapi_time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
2434 _wapi_time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime);
2436 if (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2437 find_data->nFileSizeHigh = 0;
2438 find_data->nFileSizeLow = 0;
2441 find_data->nFileSizeHigh = buf.st_size >> 32;
2442 find_data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2445 find_data->dwReserved0 = 0;
2446 find_data->dwReserved1 = 0;
2448 utf8_basename = g_path_get_basename (utf8_filename);
2449 utf16_basename = g_utf8_to_utf16 (utf8_basename, -1, NULL, &bytes,
2451 if(utf16_basename==NULL) {
2452 g_free (utf8_basename);
2453 g_free (utf8_filename);
2457 /* utf16 is 2 * utf8 */
2460 memset (find_data->cFileName, '\0', (MAX_PATH*2));
2462 /* Truncating a utf16 string like this might leave the last
2465 memcpy (find_data->cFileName, utf16_basename,
2466 bytes<(MAX_PATH*2)-2?bytes:(MAX_PATH*2)-2);
2468 find_data->cAlternateFileName [0] = 0; /* not used */
2470 g_free (utf8_basename);
2471 g_free (utf8_filename);
2472 g_free (utf16_basename);
2478 * @wapi_handle: the find handle to close.
2480 * Closes find handle @wapi_handle
2482 * Return value: %TRUE on success, %FALSE otherwise.
2484 gboolean FindClose (gpointer handle)
2486 struct _WapiHandle_find *find_handle;
2489 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2490 (gpointer *)&find_handle, NULL);
2492 g_warning (G_GNUC_PRETTY_FUNCTION
2493 ": error looking up find handle %p", handle);
2494 SetLastError (ERROR_INVALID_HANDLE);
2498 globfree (&find_handle->glob);
2499 _wapi_handle_unref (handle);
2506 * @name: a pointer to a NULL-terminated unicode string, that names
2507 * the directory to be created.
2508 * @security: ignored for now
2510 * Creates directory @name
2512 * Return value: %TRUE on success, %FALSE otherwise.
2514 gboolean CreateDirectory (const gunichar2 *name, WapiSecurityAttributes *security)
2521 utf8_name = mono_unicode_to_external (name);
2522 if (utf8_name == NULL) {
2524 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2530 result = mkdir (utf8_name, 0777);
2537 if (errno == EEXIST) {
2538 result = stat (utf8_name, &buf);
2540 _wapi_set_last_error_from_errno ();
2546 attrs = _wapi_stat_to_file_attributes (&buf);
2547 if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
2551 _wapi_set_last_error_from_errno ();
2555 _wapi_set_last_error_from_errno ();
2562 * @name: a pointer to a NULL-terminated unicode string, that names
2563 * the directory to be removed.
2565 * Removes directory @name
2567 * Return value: %TRUE on success, %FALSE otherwise.
2569 gboolean RemoveDirectory (const gunichar2 *name)
2574 utf8_name = mono_unicode_to_external (name);
2575 if (utf8_name == NULL) {
2577 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2583 result = rmdir (utf8_name);
2589 _wapi_set_last_error_from_errno ();
2594 * GetFileAttributes:
2595 * @name: a pointer to a NULL-terminated unicode filename.
2597 * Gets the attributes for @name;
2599 * Return value: %INVALID_FILE_ATTRIBUTES on failure
2601 guint32 GetFileAttributes (const gunichar2 *name)
2607 utf8_name = mono_unicode_to_external (name);
2608 if (utf8_name == NULL) {
2610 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2613 SetLastError (ERROR_INVALID_PARAMETER);
2614 return (INVALID_FILE_ATTRIBUTES);
2617 result = stat (utf8_name, &buf);
2621 SetLastError (ERROR_FILE_NOT_FOUND);
2622 return (INVALID_FILE_ATTRIBUTES);
2625 return _wapi_stat_to_file_attributes (&buf);
2629 * GetFileAttributesEx:
2630 * @name: a pointer to a NULL-terminated unicode filename.
2631 * @level: must be GetFileExInfoStandard
2632 * @info: pointer to a WapiFileAttributesData structure
2634 * Gets attributes, size and filetimes for @name;
2636 * Return value: %TRUE on success, %FALSE on failure
2638 gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels level, gpointer info)
2641 WapiFileAttributesData *data;
2647 if (level != GetFileExInfoStandard) {
2649 g_message (G_GNUC_PRETTY_FUNCTION ": info level %d not supported.", level);
2655 utf8_name = mono_unicode_to_external (name);
2656 if (utf8_name == NULL) {
2658 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2661 SetLastError (ERROR_INVALID_PARAMETER);
2665 result = stat (utf8_name, &buf);
2669 SetLastError (ERROR_FILE_NOT_FOUND);
2673 /* fill data block */
2675 data = (WapiFileAttributesData *)info;
2677 if (buf.st_mtime < buf.st_ctime)
2678 create_time = buf.st_mtime;
2680 create_time = buf.st_ctime;
2682 data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2684 _wapi_time_t_to_filetime (create_time, &data->ftCreationTime);
2685 _wapi_time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
2686 _wapi_time_t_to_filetime (buf.st_mtime, &data->ftLastWriteTime);
2688 if (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2689 data->nFileSizeHigh = 0;
2690 data->nFileSizeLow = 0;
2693 data->nFileSizeHigh = buf.st_size >> 32;
2694 data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2702 * @name: name of file
2703 * @attrs: attributes to set
2705 * Changes the attributes on a named file.
2707 * Return value: %TRUE on success, %FALSE on failure.
2709 extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
2711 /* FIXME: think of something clever to do on unix */
2717 * Currently we only handle one *internal* case, with a value that is
2718 * not standard: 0x80000000, which means `set executable bit'
2721 utf8_name = mono_unicode_to_external (name);
2722 result = stat (utf8_name, &buf);
2725 SetLastError (ERROR_FILE_NOT_FOUND);
2729 /* Contrary to the documentation, ms allows NORMAL to be
2730 * specified along with other attributes, so dont bother to
2731 * catch that case here.
2733 if (attrs & FILE_ATTRIBUTE_READONLY) {
2734 result = chmod (utf8_name, buf.st_mode & ~(S_IWRITE | S_IWOTH | S_IWGRP));
2736 result = chmod (utf8_name, buf.st_mode | S_IWRITE);
2739 /* Ignore the other attributes for now */
2741 if (attrs & 0x80000000){
2742 result = chmod (utf8_name, buf.st_mode | S_IEXEC | S_IXOTH | S_IXGRP);
2744 /* Don't bother to reset executable (might need to change this
2751 SetLastError (ERROR_FILE_NOT_FOUND);
2759 * GetCurrentDirectory
2760 * @length: size of the buffer
2761 * @buffer: pointer to buffer that recieves path
2763 * Retrieves the current directory for the current process.
2765 * Return value: number of characters in buffer on success, zero on failure
2767 extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer)
2770 gunichar2 *utf16_path;
2774 path = g_get_current_dir ();
2778 utf16_path=mono_unicode_from_external (path, &bytes);
2780 /* if buffer too small, return number of characters required.
2781 * this is plain dumb.
2784 count = (bytes/2)+1;
2785 if (count > length) {
2787 g_free (utf16_path);
2792 /* Add the terminator */
2793 memset (buffer, '\0', bytes+2);
2794 memcpy (buffer, utf16_path, bytes);
2796 g_free (utf16_path);
2803 * SetCurrentDirectory
2804 * @path: path to new directory
2806 * Changes the directory path for the current process.
2808 * Return value: %TRUE on success, %FALSE on failure.
2810 extern gboolean SetCurrentDirectory (const gunichar2 *path)
2815 utf8_path = mono_unicode_to_external (path);
2816 if (chdir (utf8_path) != 0) {
2817 _wapi_set_last_error_from_errno ();
2827 int _wapi_file_handle_to_fd (gpointer handle)
2829 struct _WapiHandlePrivate_file *file_private_handle;
2833 g_message (G_GNUC_PRETTY_FUNCTION ": looking up fd for %p", handle);
2836 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
2837 (gpointer *)&file_private_handle);
2839 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE, NULL,
2840 (gpointer *)&file_private_handle);
2842 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE, NULL,
2843 (gpointer *)&file_private_handle);
2846 g_message (G_GNUC_PRETTY_FUNCTION
2855 g_message (G_GNUC_PRETTY_FUNCTION ": returning %d",
2856 file_private_handle->fd);
2859 return(file_private_handle->fd);
2862 gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
2863 WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 size)
2865 struct _WapiHandle_file *pipe_read_handle;
2866 struct _WapiHandle_file *pipe_write_handle;
2867 struct _WapiHandlePrivate_file *pipe_read_private_handle;
2868 struct _WapiHandlePrivate_file *pipe_write_private_handle;
2869 gpointer read_handle;
2870 gpointer write_handle;
2875 mono_once (&io_ops_once, io_ops_init);
2878 g_message (G_GNUC_PRETTY_FUNCTION ": Creating pipe");
2884 g_message (G_GNUC_PRETTY_FUNCTION ": Error creating pipe: %s",
2888 _wapi_set_last_error_from_errno ();
2892 /* filedes[0] is open for reading, filedes[1] for writing */
2894 read_handle=_wapi_handle_new (WAPI_HANDLE_PIPE);
2895 if(read_handle==_WAPI_HANDLE_INVALID) {
2896 g_warning (G_GNUC_PRETTY_FUNCTION
2897 ": error creating pipe read handle");
2903 _wapi_handle_lock_handle (read_handle);
2905 ok=_wapi_lookup_handle (read_handle, WAPI_HANDLE_PIPE,
2906 (gpointer *)&pipe_read_handle,
2907 (gpointer *)&pipe_read_private_handle);
2909 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2910 _wapi_handle_unlock_handle (read_handle);
2916 write_handle=_wapi_handle_new (WAPI_HANDLE_PIPE);
2917 if(write_handle==_WAPI_HANDLE_INVALID) {
2918 g_warning (G_GNUC_PRETTY_FUNCTION
2919 ": error creating pipe write handle");
2920 _wapi_handle_unlock_handle (read_handle);
2921 _wapi_handle_unref (read_handle);
2928 _wapi_handle_lock_handle (write_handle);
2930 ok=_wapi_lookup_handle (write_handle, WAPI_HANDLE_PIPE,
2931 (gpointer *)&pipe_write_handle,
2932 (gpointer *)&pipe_write_private_handle);
2934 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2935 _wapi_handle_unlock_handle (read_handle);
2936 _wapi_handle_unref (read_handle);
2937 _wapi_handle_unlock_handle (write_handle);
2943 pipe_read_private_handle->fd=filedes[0];
2944 pipe_read_private_handle->assigned=TRUE;
2945 pipe_read_handle->fileaccess=GENERIC_READ;
2947 *readpipe=read_handle;
2949 pipe_write_private_handle->fd=filedes[1];
2950 pipe_write_private_handle->assigned=TRUE;
2951 pipe_write_handle->fileaccess=GENERIC_WRITE;
2953 *writepipe=write_handle;
2955 _wapi_handle_unlock_handle (read_handle);
2956 _wapi_handle_unlock_handle (write_handle);
2959 g_message (G_GNUC_PRETTY_FUNCTION
2960 ": Returning pipe: read handle %p, write handle %p",
2961 read_handle, write_handle);
2967 guint32 GetTempPath (guint32 len, gunichar2 *buf)
2969 gchar *tmpdir=g_strdup (g_get_tmp_dir ());
2970 gunichar2 *tmpdir16=NULL;
2975 if(tmpdir[strlen (tmpdir)]!='/') {
2977 tmpdir=g_strdup_printf ("%s/", g_get_tmp_dir ());
2980 tmpdir16=mono_unicode_from_external (tmpdir, &bytes);
2981 if(tmpdir16==NULL) {
2989 g_message (G_GNUC_PRETTY_FUNCTION
2990 ": Size %d smaller than needed (%ld)", len,
2996 /* Add the terminator */
2997 memset (buf, '\0', bytes+2);
2998 memcpy (buf, tmpdir16, bytes);
3004 if(tmpdir16!=NULL) {