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 (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);
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=_wapi_unicode_to_utf8(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 = _wapi_unicode_to_utf8 (name);
1511 if (utf8_name == NULL) {
1513 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1519 utf8_dest_name = _wapi_unicode_to_utf8 (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);
1538 SetLastError (ERROR_ALREADY_EXISTS);
1542 _wapi_set_last_error_from_errno ();
1551 * @name: a pointer to a NULL-terminated unicode string, that names
1552 * the file to be copied.
1553 * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1554 * new name for the file.
1555 * @fail_if_exists: if TRUE and dest_name exists, the copy will fail.
1557 * Copies file @name to @dest_name
1559 * Return value: %TRUE on success, %FALSE otherwise.
1561 gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
1562 gboolean fail_if_exists)
1570 struct _WapiHandlePrivate_file *file_private_handle;
1573 attrs = GetFileAttributes (name);
1574 if (attrs == INVALID_FILE_ATTRIBUTES) {
1575 SetLastError (ERROR_FILE_NOT_FOUND);
1579 src = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1580 NULL, OPEN_EXISTING, 0, NULL);
1581 if (src == INVALID_HANDLE_VALUE) {
1582 _wapi_set_last_error_from_errno ();
1586 dest = CreateFile (dest_name, GENERIC_WRITE, 0, NULL,
1587 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS, attrs, NULL);
1588 if (dest == INVALID_HANDLE_VALUE) {
1589 _wapi_set_last_error_from_errno ();
1594 buffer = g_new (gchar, 2048);
1597 if (ReadFile (src, buffer,sizeof (buffer), &remain, NULL) == 0) {
1598 _wapi_set_last_error_from_errno ();
1600 g_message (G_GNUC_PRETTY_FUNCTION ": read failed.");
1611 while (remain > 0) {
1612 if (WriteFile (dest, buffer, remain, &n, NULL) == 0) {
1613 _wapi_set_last_error_from_errno ();
1615 g_message (G_GNUC_PRETTY_FUNCTION ": write failed.");
1629 ok=_wapi_lookup_handle (src, WAPI_HANDLE_FILE,
1630 NULL, (gpointer *)&file_private_handle);
1632 g_warning (G_GNUC_PRETTY_FUNCTION
1633 ": error looking up file handle %p", src);
1638 fd_in=file_private_handle->fd;
1641 ok=_wapi_lookup_handle (dest, WAPI_HANDLE_FILE,
1642 NULL, (gpointer *)&file_private_handle);
1644 g_warning (G_GNUC_PRETTY_FUNCTION
1645 ": error looking up file handle %p", dest);
1650 fd_out=file_private_handle->fd;
1651 fchmod(fd_out, st.st_mode);
1659 static mono_once_t stdhandle_once=MONO_ONCE_INIT;
1660 static gpointer stdin_handle=NULL;
1661 static gpointer stdout_handle=NULL;
1662 static gpointer stderr_handle=NULL;
1664 static gpointer stdhandle_create (int fd, const guchar *name)
1666 struct _WapiHandle_file *file_handle;
1667 struct _WapiHandlePrivate_file *file_private_handle;
1673 g_message(G_GNUC_PRETTY_FUNCTION ": creating standard handle type %s",
1677 /* Check if fd is valid */
1678 flags=fcntl(fd, F_GETFL);
1680 /* Invalid fd. Not really much point checking for EBADF
1684 g_message(G_GNUC_PRETTY_FUNCTION ": fcntl error on fd %d: %s",
1685 fd, strerror(errno));
1688 return(INVALID_HANDLE_VALUE);
1691 handle=_wapi_handle_new (WAPI_HANDLE_CONSOLE);
1692 if(handle==_WAPI_HANDLE_INVALID) {
1693 g_warning (G_GNUC_PRETTY_FUNCTION
1694 ": error creating file handle");
1698 _wapi_handle_lock_handle (handle);
1700 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1701 (gpointer *)&file_handle,
1702 (gpointer *)&file_private_handle);
1704 g_warning (G_GNUC_PRETTY_FUNCTION
1705 ": error looking up console handle %p", handle);
1706 _wapi_handle_unlock_handle (handle);
1710 file_private_handle->fd=fd;
1711 file_private_handle->assigned=TRUE;
1712 file_handle->filename=_wapi_handle_scratch_store (name, strlen (name));
1713 /* some default security attributes might be needed */
1714 file_handle->security_attributes=0;
1715 file_handle->fileaccess=convert_from_flags(flags);
1716 file_handle->sharemode=0;
1717 file_handle->attrs=0;
1720 g_message(G_GNUC_PRETTY_FUNCTION ": returning handle %p with fd %d",
1721 handle, file_private_handle->fd);
1724 _wapi_handle_unlock_handle (handle);
1729 static void stdhandle_init (void)
1731 stdin_handle=stdhandle_create (0, "<stdin>");
1732 stdout_handle=stdhandle_create (1, "<stdout>");
1733 stderr_handle=stdhandle_create (2, "<stderr>");
1738 * @stdhandle: specifies the file descriptor
1740 * Returns a handle for stdin, stdout, or stderr. Always returns the
1741 * same handle for the same @stdhandle.
1743 * Return value: the handle, or %INVALID_HANDLE_VALUE on error
1746 gpointer GetStdHandle(WapiStdHandle stdhandle)
1750 mono_once (&io_ops_once, io_ops_init);
1751 mono_once (&stdhandle_once, stdhandle_init);
1754 case STD_INPUT_HANDLE:
1755 handle=stdin_handle;
1758 case STD_OUTPUT_HANDLE:
1759 handle=stdout_handle;
1762 case STD_ERROR_HANDLE:
1763 handle=stderr_handle;
1768 g_message(G_GNUC_PRETTY_FUNCTION
1769 ": unknown standard handle type");
1772 return(INVALID_HANDLE_VALUE);
1775 /* Add a reference to this handle */
1776 _wapi_handle_ref (handle);
1783 * @handle: The file handle to read from. The handle must have
1784 * %GENERIC_READ access.
1785 * @buffer: The buffer to store read data in
1786 * @numbytes: The maximum number of bytes to read
1787 * @bytesread: The actual number of bytes read is stored here. This
1788 * value can be zero if the handle is positioned at the end of the
1790 * @overlapped: points to a required %WapiOverlapped structure if
1791 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1794 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1795 * function reads up to @numbytes bytes from the file from the current
1796 * file position, and stores them in @buffer. If there are not enough
1797 * bytes left in the file, just the amount available will be read.
1798 * The actual number of bytes read is stored in @bytesread.
1800 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1801 * file position is ignored and the read position is taken from data
1802 * in the @overlapped structure.
1804 * Return value: %TRUE if the read succeeds (even if no bytes were
1805 * read due to an attempt to read past the end of the file), %FALSE on
1808 gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
1809 guint32 *bytesread, WapiOverlapped *overlapped)
1811 WapiHandleType type=_wapi_handle_type (handle);
1813 if(io_ops[type].readfile==NULL) {
1817 return(io_ops[type].readfile (handle, buffer, numbytes, bytesread,
1823 * @handle: The file handle to write to. The handle must have
1824 * %GENERIC_WRITE access.
1825 * @buffer: The buffer to read data from.
1826 * @numbytes: The maximum number of bytes to write.
1827 * @byteswritten: The actual number of bytes written is stored here.
1828 * If the handle is positioned at the file end, the length of the file
1829 * is extended. This parameter may be %NULL.
1830 * @overlapped: points to a required %WapiOverlapped structure if
1831 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1834 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1835 * function writes up to @numbytes bytes from @buffer to the file at
1836 * the current file position. If @handle is positioned at the end of
1837 * the file, the file is extended. The actual number of bytes written
1838 * is stored in @byteswritten.
1840 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1841 * file position is ignored and the write position is taken from data
1842 * in the @overlapped structure.
1844 * Return value: %TRUE if the write succeeds, %FALSE on error.
1846 gboolean WriteFile(gpointer handle, gconstpointer buffer, guint32 numbytes,
1847 guint32 *byteswritten, WapiOverlapped *overlapped)
1849 WapiHandleType type=_wapi_handle_type (handle);
1851 if(io_ops[type].writefile==NULL) {
1855 return(io_ops[type].writefile (handle, buffer, numbytes, byteswritten,
1861 * @handle: Handle to open file. The handle must have
1862 * %GENERIC_WRITE access.
1864 * Flushes buffers of the file and causes all unwritten data to
1867 * Return value: %TRUE on success, %FALSE otherwise.
1869 gboolean FlushFileBuffers(gpointer handle)
1871 WapiHandleType type=_wapi_handle_type (handle);
1873 if(io_ops[type].flushfile==NULL) {
1877 return(io_ops[type].flushfile (handle));
1882 * @handle: The file handle to set. The handle must have
1883 * %GENERIC_WRITE access.
1885 * Moves the end-of-file position to the current position of the file
1886 * pointer. This function is used to truncate or extend a file.
1888 * Return value: %TRUE on success, %FALSE otherwise.
1890 gboolean SetEndOfFile(gpointer handle)
1892 WapiHandleType type=_wapi_handle_type (handle);
1894 if(io_ops[type].setendoffile==NULL) {
1898 return(io_ops[type].setendoffile (handle));
1903 * @handle: The file handle to set. The handle must have
1904 * %GENERIC_READ or %GENERIC_WRITE access.
1905 * @movedistance: Low 32 bits of a signed value that specifies the
1906 * number of bytes to move the file pointer.
1907 * @highmovedistance: Pointer to the high 32 bits of a signed value
1908 * that specifies the number of bytes to move the file pointer, or
1910 * @method: The starting point for the file pointer move.
1912 * Sets the file pointer of an open file.
1914 * The distance to move the file pointer is calculated from
1915 * @movedistance and @highmovedistance: If @highmovedistance is %NULL,
1916 * @movedistance is the 32-bit signed value; otherwise, @movedistance
1917 * is the low 32 bits and @highmovedistance a pointer to the high 32
1918 * bits of a 64 bit signed value. A positive distance moves the file
1919 * pointer forward from the position specified by @method; a negative
1920 * distance moves the file pointer backward.
1922 * If the library is compiled without large file support,
1923 * @highmovedistance is ignored and its value is set to zero on a
1924 * successful return.
1926 * Return value: On success, the low 32 bits of the new file pointer.
1927 * If @highmovedistance is not %NULL, the high 32 bits of the new file
1928 * pointer are stored there. On failure, %INVALID_SET_FILE_POINTER.
1930 guint32 SetFilePointer(gpointer handle, gint32 movedistance,
1931 gint32 *highmovedistance, WapiSeekMethod method)
1933 WapiHandleType type=_wapi_handle_type (handle);
1935 if(io_ops[type].seek==NULL) {
1939 return(io_ops[type].seek (handle, movedistance, highmovedistance,
1945 * @handle: The file handle to test.
1947 * Finds the type of file @handle.
1949 * Return value: %FILE_TYPE_UNKNOWN - the type of the file @handle is
1950 * unknown. %FILE_TYPE_DISK - @handle is a disk file.
1951 * %FILE_TYPE_CHAR - @handle is a character device, such as a console.
1952 * %FILE_TYPE_PIPE - @handle is a named or anonymous pipe.
1954 WapiFileType GetFileType(gpointer handle)
1956 WapiHandleType type=_wapi_handle_type (handle);
1958 if(io_ops[type].getfiletype==NULL) {
1959 return(FILE_TYPE_UNKNOWN);
1962 return(io_ops[type].getfiletype ());
1967 * @handle: The file handle to query. The handle must have
1968 * %GENERIC_READ or %GENERIC_WRITE access.
1969 * @highsize: If non-%NULL, the high 32 bits of the file size are
1972 * Retrieves the size of the file @handle.
1974 * If the library is compiled without large file support, @highsize
1975 * has its value set to zero on a successful return.
1977 * Return value: On success, the low 32 bits of the file size. If
1978 * @highsize is non-%NULL then the high 32 bits of the file size are
1979 * stored here. On failure %INVALID_FILE_SIZE is returned.
1981 guint32 GetFileSize(gpointer handle, guint32 *highsize)
1983 WapiHandleType type=_wapi_handle_type (handle);
1985 if(io_ops[type].getfilesize==NULL) {
1989 return(io_ops[type].getfilesize (handle, highsize));
1994 * @handle: The file handle to query. The handle must have
1995 * %GENERIC_READ access.
1996 * @create_time: Points to a %WapiFileTime structure to receive the
1997 * number of ticks since the epoch that file was created. May be
1999 * @last_access: Points to a %WapiFileTime structure to receive the
2000 * number of ticks since the epoch when file was last accessed. May be
2002 * @last_write: Points to a %WapiFileTime structure to receive the
2003 * number of ticks since the epoch when file was last written to. May
2006 * Finds the number of ticks since the epoch that the file referenced
2007 * by @handle was created, last accessed and last modified. A tick is
2008 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
2011 * Create time isn't recorded on POSIX file systems or reported by
2012 * stat(2), so that time is guessed by returning the oldest of the
2015 * Return value: %TRUE on success, %FALSE otherwise.
2017 gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
2018 WapiFileTime *last_access, WapiFileTime *last_write)
2020 WapiHandleType type=_wapi_handle_type (handle);
2022 if(io_ops[type].getfiletime==NULL) {
2026 return(io_ops[type].getfiletime (handle, create_time, last_access,
2032 * @handle: The file handle to set. The handle must have
2033 * %GENERIC_WRITE access.
2034 * @create_time: Points to a %WapiFileTime structure that contains the
2035 * number of ticks since the epoch that the file was created. May be
2037 * @last_access: Points to a %WapiFileTime structure that contains the
2038 * number of ticks since the epoch when the file was last accessed.
2040 * @last_write: Points to a %WapiFileTime structure that contains the
2041 * number of ticks since the epoch when the file was last written to.
2044 * Sets the number of ticks since the epoch that the file referenced
2045 * by @handle was created, last accessed or last modified. A tick is
2046 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
2049 * Create time isn't recorded on POSIX file systems, and is ignored.
2051 * Return value: %TRUE on success, %FALSE otherwise.
2053 gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
2054 const WapiFileTime *last_access,
2055 const WapiFileTime *last_write)
2057 WapiHandleType type=_wapi_handle_type (handle);
2059 if(io_ops[type].setfiletime==NULL) {
2063 return(io_ops[type].setfiletime (handle, create_time, last_access,
2067 /* A tick is a 100-nanosecond interval. File time epoch is Midnight,
2068 * January 1 1601 GMT
2071 #define TICKS_PER_MILLISECOND 10000L
2072 #define TICKS_PER_SECOND 10000000L
2073 #define TICKS_PER_MINUTE 600000000L
2074 #define TICKS_PER_HOUR 36000000000L
2075 #define TICKS_PER_DAY 864000000000L
2077 #define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
2079 static const guint16 mon_yday[2][13]={
2080 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
2081 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
2085 * FileTimeToSystemTime:
2086 * @file_time: Points to a %WapiFileTime structure that contains the
2087 * number of ticks to convert.
2088 * @system_time: Points to a %WapiSystemTime structure to receive the
2091 * Converts a tick count into broken-out time values.
2093 * Return value: %TRUE on success, %FALSE otherwise.
2095 gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
2096 WapiSystemTime *system_time)
2098 gint64 file_ticks, totaldays, rem, y;
2101 if(system_time==NULL) {
2103 g_message(G_GNUC_PRETTY_FUNCTION ": system_time NULL");
2109 file_ticks=((gint64)file_time->dwHighDateTime << 32) +
2110 file_time->dwLowDateTime;
2112 /* Really compares if file_ticks>=0x8000000000000000
2113 * (LLONG_MAX+1) but we're working with a signed value for the
2114 * year and day calculation to work later
2118 g_message(G_GNUC_PRETTY_FUNCTION ": file_time too big");
2124 totaldays=(file_ticks / TICKS_PER_DAY);
2125 rem = file_ticks % TICKS_PER_DAY;
2127 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld rem: %lld",
2131 system_time->wHour=rem/TICKS_PER_HOUR;
2132 rem %= TICKS_PER_HOUR;
2134 g_message(G_GNUC_PRETTY_FUNCTION ": Hour: %d rem: %lld",
2135 system_time->wHour, rem);
2138 system_time->wMinute = rem / TICKS_PER_MINUTE;
2139 rem %= TICKS_PER_MINUTE;
2141 g_message(G_GNUC_PRETTY_FUNCTION ": Minute: %d rem: %lld",
2142 system_time->wMinute, rem);
2145 system_time->wSecond = rem / TICKS_PER_SECOND;
2146 rem %= TICKS_PER_SECOND;
2148 g_message(G_GNUC_PRETTY_FUNCTION ": Second: %d rem: %lld",
2149 system_time->wSecond, rem);
2152 system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
2154 g_message(G_GNUC_PRETTY_FUNCTION ": Milliseconds: %d",
2155 system_time->wMilliseconds);
2158 /* January 1, 1601 was a Monday, according to Emacs calendar */
2159 system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
2161 g_message(G_GNUC_PRETTY_FUNCTION ": Day of week: %d",
2162 system_time->wDayOfWeek);
2165 /* This algorithm to find year and month given days from epoch
2170 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
2171 #define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400))
2173 while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
2174 /* Guess a corrected year, assuming 365 days per year */
2175 gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
2177 g_message(G_GNUC_PRETTY_FUNCTION
2178 ": totaldays: %lld yg: %lld y: %lld", totaldays, yg,
2180 g_message(G_GNUC_PRETTY_FUNCTION
2181 ": LEAPS(yg): %lld LEAPS(y): %lld",
2182 LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
2185 /* Adjust days and y to match the guessed year. */
2186 totaldays -= ((yg - y) * 365
2187 + LEAPS_THRU_END_OF (yg - 1)
2188 - LEAPS_THRU_END_OF (y - 1));
2190 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld",
2195 g_message(G_GNUC_PRETTY_FUNCTION ": y: %lld", y);
2199 system_time->wYear = y;
2201 g_message(G_GNUC_PRETTY_FUNCTION ": Year: %d", system_time->wYear);
2204 ip = mon_yday[isleap(y)];
2206 for(y=11; totaldays < ip[y]; --y) {
2211 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld", totaldays);
2214 system_time->wMonth = y + 1;
2216 g_message(G_GNUC_PRETTY_FUNCTION ": Month: %d", system_time->wMonth);
2219 system_time->wDay = totaldays + 1;
2221 g_message(G_GNUC_PRETTY_FUNCTION ": Day: %d", system_time->wDay);
2227 gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
2229 struct _WapiHandle_find *find_handle;
2232 gchar *utf8_pattern = NULL;
2235 if (pattern == NULL) {
2237 g_message (G_GNUC_PRETTY_FUNCTION ": pattern is NULL");
2240 return INVALID_HANDLE_VALUE;
2243 utf8_pattern = _wapi_unicode_to_utf8 (pattern);
2244 if (utf8_pattern == NULL) {
2246 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2249 return INVALID_HANDLE_VALUE;
2253 g_message (G_GNUC_PRETTY_FUNCTION ": looking for [%s]",
2257 handle=_wapi_handle_new (WAPI_HANDLE_FIND);
2258 if(handle==_WAPI_HANDLE_INVALID) {
2259 g_warning (G_GNUC_PRETTY_FUNCTION
2260 ": error creating find handle");
2261 g_free (utf8_pattern);
2263 return(INVALID_HANDLE_VALUE);
2266 _wapi_handle_lock_handle (handle);
2268 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2269 (gpointer *)&find_handle, NULL);
2271 g_warning (G_GNUC_PRETTY_FUNCTION
2272 ": error looking up find handle %p", handle);
2273 _wapi_handle_unlock_handle (handle);
2274 g_free (utf8_pattern);
2276 return(INVALID_HANDLE_VALUE);
2280 /* glibc extension */
2281 result = glob (utf8_pattern, GLOB_PERIOD, NULL, &find_handle->glob);
2283 result = glob (utf8_pattern, 0, NULL, &find_handle->glob);
2285 /* If the last element of the pattern begins
2286 * '<slash>*' (stupid compiler) then add a '/.*'
2289 int len=strlen(utf8_pattern);
2290 if(len==1 && utf8_pattern[0]=='*') {
2291 result = glob (".*", GLOB_APPEND, NULL,
2292 &find_handle->glob);
2294 gchar *last_star=g_strrstr(utf8_pattern, "/*");
2295 gchar *last_slash=g_strrstr(utf8_pattern, "/");
2296 if(last_star==last_slash) {
2297 gchar *append_pattern;
2298 int dotpos=(int)(last_slash-utf8_pattern)+1;
2300 append_pattern=g_new0(gchar, len+2);
2301 strncpy(append_pattern, utf8_pattern, dotpos);
2302 append_pattern[dotpos]='.';
2303 strcpy(append_pattern+dotpos+1, last_slash+1);
2306 g_message (G_GNUC_PRETTY_FUNCTION ": appending glob [%s]", append_pattern);
2308 result = glob (append_pattern, GLOB_APPEND,
2309 NULL, &find_handle->glob);
2311 g_free (append_pattern);
2315 #endif /* !GLOB_PERIOD */
2317 g_free (utf8_pattern);
2320 globfree (&find_handle->glob);
2321 _wapi_handle_unlock_handle (handle);
2322 _wapi_handle_unref (handle);
2327 SetLastError (ERROR_NO_MORE_FILES);
2333 g_message (G_GNUC_PRETTY_FUNCTION ": glob failed with code %d.", result);
2339 return INVALID_HANDLE_VALUE;
2342 find_handle->count = 0;
2343 if (!FindNextFile (handle, find_data)) {
2345 SetLastError (ERROR_NO_MORE_FILES);
2346 return INVALID_HANDLE_VALUE;
2349 _wapi_handle_unlock_handle (handle);
2354 gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
2356 struct _WapiHandle_find *find_handle;
2359 const gchar *filename;
2360 gchar *utf8_filename;
2362 gchar *base_filename;
2363 gunichar2 *utf16_basename;
2367 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2368 (gpointer *)&find_handle, NULL);
2370 g_warning (G_GNUC_PRETTY_FUNCTION
2371 ": error looking up find handle %p", handle);
2372 SetLastError (ERROR_INVALID_HANDLE);
2377 if (find_handle->count >= find_handle->glob.gl_pathc) {
2378 SetLastError (ERROR_NO_MORE_FILES);
2382 /* stat next glob match */
2384 filename = find_handle->glob.gl_pathv [find_handle->count ++];
2385 if (lstat (filename, &buf) != 0) {
2387 g_message (G_GNUC_PRETTY_FUNCTION ": stat failed: %s", filename);
2390 SetLastError (ERROR_NO_MORE_FILES);
2394 /* Check for dangling symlinks, and ignore them (principle of
2395 * least surprise, avoiding confusion where we report the file
2396 * exists, but when someone tries to open it we would report
2399 if(S_ISLNK (buf.st_mode)) {
2400 if(stat (filename, &buf) != 0) {
2405 /* Work around glib brain-damage, where it expects all filenames
2406 * to be validly utf8-encoded
2408 if(g_utf8_validate(filename, -1, NULL)) {
2409 utf8_filename=g_strdup(filename);
2411 utf8_filename=g_locale_to_utf8(filename, -1, NULL, NULL, NULL);
2414 /* Final check... */
2415 if(g_utf8_validate(utf8_filename, -1, NULL)==FALSE) {
2416 /* glib can't cope with this filename, so just ignore it
2417 * instead of crashing.
2419 g_free(utf8_filename);
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 base_filename = g_path_get_basename (utf8_filename);
2449 utf16_basename = g_utf8_to_utf16 (base_filename, MAX_PATH, NULL, NULL, NULL);
2452 while (utf16_basename [i] != 0) { /* copy basename */
2453 find_data->cFileName [i] = utf16_basename [i];
2457 find_data->cFileName[i] = 0; /* null terminate */
2458 find_data->cAlternateFileName [0] = 0; /* not used */
2460 g_free (base_filename);
2461 g_free (utf8_filename);
2462 g_free (utf16_basename);
2468 * @wapi_handle: the find handle to close.
2470 * Closes find handle @wapi_handle
2472 * Return value: %TRUE on success, %FALSE otherwise.
2474 gboolean FindClose (gpointer handle)
2476 struct _WapiHandle_find *find_handle;
2479 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2480 (gpointer *)&find_handle, NULL);
2482 g_warning (G_GNUC_PRETTY_FUNCTION
2483 ": error looking up find handle %p", handle);
2484 SetLastError (ERROR_INVALID_HANDLE);
2488 globfree (&find_handle->glob);
2489 _wapi_handle_unref (handle);
2496 * @name: a pointer to a NULL-terminated unicode string, that names
2497 * the directory to be created.
2498 * @security: ignored for now
2500 * Creates directory @name
2502 * Return value: %TRUE on success, %FALSE otherwise.
2504 gboolean CreateDirectory (const gunichar2 *name, WapiSecurityAttributes *security)
2509 utf8_name = _wapi_unicode_to_utf8 (name);
2510 if (utf8_name == NULL) {
2512 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2518 result = mkdir (utf8_name, 0777);
2528 _wapi_set_last_error_from_errno ();
2537 * @name: a pointer to a NULL-terminated unicode string, that names
2538 * the directory to be removed.
2540 * Removes directory @name
2542 * Return value: %TRUE on success, %FALSE otherwise.
2544 gboolean RemoveDirectory (const gunichar2 *name)
2549 utf8_name = _wapi_unicode_to_utf8 (name);
2550 if (utf8_name == NULL) {
2552 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2558 result = rmdir (utf8_name);
2564 _wapi_set_last_error_from_errno ();
2569 * GetFileAttributes:
2570 * @name: a pointer to a NULL-terminated unicode filename.
2572 * Gets the attributes for @name;
2574 * Return value: %INVALID_FILE_ATTRIBUTES on failure
2576 guint32 GetFileAttributes (const gunichar2 *name)
2582 utf8_name = _wapi_unicode_to_utf8 (name);
2583 if (utf8_name == NULL) {
2585 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2588 SetLastError (ERROR_INVALID_PARAMETER);
2589 return (INVALID_FILE_ATTRIBUTES);
2592 result = stat (utf8_name, &buf);
2596 SetLastError (ERROR_FILE_NOT_FOUND);
2597 return (INVALID_FILE_ATTRIBUTES);
2600 return _wapi_stat_to_file_attributes (&buf);
2604 * GetFileAttributesEx:
2605 * @name: a pointer to a NULL-terminated unicode filename.
2606 * @level: must be GetFileExInfoStandard
2607 * @info: pointer to a WapiFileAttributesData structure
2609 * Gets attributes, size and filetimes for @name;
2611 * Return value: %TRUE on success, %FALSE on failure
2613 gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels level, gpointer info)
2616 WapiFileAttributesData *data;
2622 if (level != GetFileExInfoStandard) {
2624 g_message (G_GNUC_PRETTY_FUNCTION ": info level %d not supported.", level);
2630 utf8_name = _wapi_unicode_to_utf8 (name);
2631 if (utf8_name == NULL) {
2633 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2636 SetLastError (ERROR_INVALID_PARAMETER);
2640 result = stat (utf8_name, &buf);
2644 SetLastError (ERROR_FILE_NOT_FOUND);
2648 /* fill data block */
2650 data = (WapiFileAttributesData *)info;
2652 if (buf.st_mtime < buf.st_ctime)
2653 create_time = buf.st_mtime;
2655 create_time = buf.st_ctime;
2657 data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2659 _wapi_time_t_to_filetime (create_time, &data->ftCreationTime);
2660 _wapi_time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
2661 _wapi_time_t_to_filetime (buf.st_mtime, &data->ftLastWriteTime);
2663 if (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2664 data->nFileSizeHigh = 0;
2665 data->nFileSizeLow = 0;
2668 data->nFileSizeHigh = buf.st_size >> 32;
2669 data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2677 * @name: name of file
2678 * @attrs: attributes to set
2680 * Changes the attributes on a named file.
2682 * Return value: %TRUE on success, %FALSE on failure.
2684 extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
2686 /* FIXME: think of something clever to do on unix */
2692 * Currently we only handle one *internal* case, with a value that is
2693 * not standard: 0x80000000, which means `set executable bit'
2696 utf8_name = _wapi_unicode_to_utf8 (name);
2697 result = stat (utf8_name, &buf);
2700 SetLastError (ERROR_FILE_NOT_FOUND);
2704 /* Contrary to the documentation, ms allows NORMAL to be
2705 * specified along with other attributes, so dont bother to
2706 * catch that case here.
2708 if (attrs & FILE_ATTRIBUTE_READONLY) {
2709 result = chmod (utf8_name, buf.st_mode & ~(S_IWRITE | S_IWOTH | S_IWGRP));
2711 result = chmod (utf8_name, buf.st_mode | S_IWRITE);
2714 /* Ignore the other attributes for now */
2716 if (attrs & 0x80000000){
2717 result = chmod (utf8_name, buf.st_mode | S_IEXEC | S_IXOTH | S_IXGRP);
2719 /* Don't bother to reset executable (might need to change this
2726 SetLastError (ERROR_FILE_NOT_FOUND);
2734 * GetCurrentDirectory
2735 * @length: size of the buffer
2736 * @buffer: pointer to buffer that recieves path
2738 * Retrieves the current directory for the current process.
2740 * Return value: number of characters in buffer on success, zero on failure
2742 extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer)
2744 gchar *path, *utf8_path;
2745 gunichar2 *utf16_path, *ptr;
2748 path = g_get_current_dir ();
2752 /* No, g_get_current_dir () does not return utf8 strings */
2753 if(g_utf8_validate(path, -1, NULL)) {
2754 utf8_path=g_strdup(path);
2756 utf8_path=g_locale_to_utf8(path, -1, NULL, NULL, NULL);
2759 if(g_utf8_validate(utf8_path, -1, NULL)==FALSE) {
2764 /* if buffer too small, return number of characters required.
2765 * this is plain dumb.
2768 count = strlen (utf8_path) + 1;
2769 if (count > length) {
2774 utf16_path = g_utf8_to_utf16 (utf8_path, -1, NULL, NULL, NULL);
2775 if (utf16_path == NULL) {
2782 *buffer ++ = *ptr ++;
2787 g_free (utf16_path);
2794 * SetCurrentDirectory
2795 * @path: path to new directory
2797 * Changes the directory path for the current process.
2799 * Return value: %TRUE on success, %FALSE on failure.
2801 extern gboolean SetCurrentDirectory (const gunichar2 *path)
2806 utf8_path = _wapi_unicode_to_utf8 (path);
2807 if (chdir (utf8_path) != 0) {
2808 _wapi_set_last_error_from_errno ();
2818 int _wapi_file_handle_to_fd (gpointer handle)
2820 struct _WapiHandlePrivate_file *file_private_handle;
2824 g_message (G_GNUC_PRETTY_FUNCTION ": looking up fd for %p", handle);
2827 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
2828 (gpointer *)&file_private_handle);
2830 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE, NULL,
2831 (gpointer *)&file_private_handle);
2833 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE, NULL,
2834 (gpointer *)&file_private_handle);
2837 g_message (G_GNUC_PRETTY_FUNCTION
2846 g_message (G_GNUC_PRETTY_FUNCTION ": returning %d",
2847 file_private_handle->fd);
2850 return(file_private_handle->fd);
2853 gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
2854 WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 size)
2856 struct _WapiHandle_file *pipe_read_handle;
2857 struct _WapiHandle_file *pipe_write_handle;
2858 struct _WapiHandlePrivate_file *pipe_read_private_handle;
2859 struct _WapiHandlePrivate_file *pipe_write_private_handle;
2860 gpointer read_handle;
2861 gpointer write_handle;
2866 mono_once (&io_ops_once, io_ops_init);
2869 g_message (G_GNUC_PRETTY_FUNCTION ": Creating pipe");
2875 g_message (G_GNUC_PRETTY_FUNCTION ": Error creating pipe: %s",
2879 _wapi_set_last_error_from_errno ();
2883 /* filedes[0] is open for reading, filedes[1] for writing */
2885 read_handle=_wapi_handle_new (WAPI_HANDLE_PIPE);
2886 if(read_handle==_WAPI_HANDLE_INVALID) {
2887 g_warning (G_GNUC_PRETTY_FUNCTION
2888 ": error creating pipe read handle");
2894 _wapi_handle_lock_handle (read_handle);
2896 ok=_wapi_lookup_handle (read_handle, WAPI_HANDLE_PIPE,
2897 (gpointer *)&pipe_read_handle,
2898 (gpointer *)&pipe_read_private_handle);
2900 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2901 _wapi_handle_unlock_handle (read_handle);
2907 write_handle=_wapi_handle_new (WAPI_HANDLE_PIPE);
2908 if(write_handle==_WAPI_HANDLE_INVALID) {
2909 g_warning (G_GNUC_PRETTY_FUNCTION
2910 ": error creating pipe write handle");
2911 _wapi_handle_unlock_handle (read_handle);
2912 _wapi_handle_unref (read_handle);
2919 _wapi_handle_lock_handle (write_handle);
2921 ok=_wapi_lookup_handle (write_handle, WAPI_HANDLE_PIPE,
2922 (gpointer *)&pipe_write_handle,
2923 (gpointer *)&pipe_write_private_handle);
2925 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2926 _wapi_handle_unlock_handle (read_handle);
2927 _wapi_handle_unref (read_handle);
2928 _wapi_handle_unlock_handle (write_handle);
2934 pipe_read_private_handle->fd=filedes[0];
2935 pipe_read_private_handle->assigned=TRUE;
2936 pipe_read_handle->fileaccess=GENERIC_READ;
2938 *readpipe=read_handle;
2940 pipe_write_private_handle->fd=filedes[1];
2941 pipe_write_private_handle->assigned=TRUE;
2942 pipe_write_handle->fileaccess=GENERIC_WRITE;
2944 *writepipe=write_handle;
2946 _wapi_handle_unlock_handle (read_handle);
2947 _wapi_handle_unlock_handle (write_handle);
2950 g_message (G_GNUC_PRETTY_FUNCTION
2951 ": Returning pipe: read handle %p, write handle %p",
2952 read_handle, write_handle);
2958 guint32 GetTempPath (guint32 len, gunichar2 *buf)
2960 gchar *tmpdir=g_strdup (g_get_tmp_dir ());
2962 gunichar2 *tmpdir16=NULL;
2963 glong dirlen, bytes;
2966 if(tmpdir[strlen (tmpdir)]!='/') {
2968 tmpdir=g_strdup_printf ("%s/", g_get_tmp_dir ());
2971 /* g_get_tmp_dir () doesn't return utf8 either */
2972 if(g_utf8_validate(tmpdir, -1, NULL)) {
2973 utf8_tmpdir=g_strdup(tmpdir);
2975 utf8_tmpdir=g_locale_to_utf8(tmpdir, -1, NULL, NULL, NULL);
2978 if(g_utf8_validate(utf8_tmpdir, -1, NULL)==FALSE) {
2979 /* FIXME - set error code */
2981 g_message (G_GNUC_PRETTY_FUNCTION ": UTF8 error");
2985 g_free(utf8_tmpdir);
2989 tmpdir16=g_utf8_to_utf16 (utf8_tmpdir, -1, NULL, &dirlen, NULL);
2990 if(tmpdir16==NULL) {
2991 /* FIXME - set error code */
2993 g_message (G_GNUC_PRETTY_FUNCTION ": Error");
3000 g_message (G_GNUC_PRETTY_FUNCTION
3001 ": Size %d smaller than needed (%ld)", len,
3007 /* Add the terminator and convert to bytes */
3009 memcpy (buf, tmpdir16, bytes);
3015 if(tmpdir16!=NULL) {
3018 g_free (utf8_tmpdir);