2 * io.c: File, console and find handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
18 #include <sys/types.h>
23 #include <mono/io-layer/wapi.h>
24 #include <mono/io-layer/unicode.h>
25 #include <mono/io-layer/wapi-private.h>
26 #include <mono/io-layer/handles-private.h>
27 #include <mono/io-layer/io-private.h>
28 #include <mono/io-layer/timefuncs-private.h>
32 static void file_close_shared (gpointer handle);
33 static void file_close_private (gpointer handle);
34 static WapiFileType file_getfiletype(void);
35 static gboolean file_read(gpointer handle, gpointer buffer,
36 guint32 numbytes, guint32 *bytesread,
37 WapiOverlapped *overlapped);
38 static gboolean file_write(gpointer handle, gconstpointer buffer,
39 guint32 numbytes, guint32 *byteswritten,
40 WapiOverlapped *overlapped);
41 static gboolean file_flush(gpointer handle);
42 static guint32 file_seek(gpointer handle, gint32 movedistance,
43 gint32 *highmovedistance, WapiSeekMethod method);
44 static gboolean file_setendoffile(gpointer handle);
45 static guint32 file_getfilesize(gpointer handle, guint32 *highsize);
46 static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
47 WapiFileTime *last_access,
48 WapiFileTime *last_write);
49 static gboolean file_setfiletime(gpointer handle,
50 const WapiFileTime *create_time,
51 const WapiFileTime *last_access,
52 const WapiFileTime *last_write);
54 /* File handle is only signalled for overlapped IO */
55 struct _WapiHandleOps _wapi_file_ops = {
56 file_close_shared, /* close_shared */
57 file_close_private, /* close_private */
63 static void console_close_shared (gpointer handle);
64 static void console_close_private (gpointer handle);
65 static WapiFileType console_getfiletype(void);
66 static gboolean console_read(gpointer handle, gpointer buffer,
67 guint32 numbytes, guint32 *bytesread,
68 WapiOverlapped *overlapped);
69 static gboolean console_write(gpointer handle, gconstpointer buffer,
70 guint32 numbytes, guint32 *byteswritten,
71 WapiOverlapped *overlapped);
73 /* Console is mostly the same as file, except it can block waiting for
76 struct _WapiHandleOps _wapi_console_ops = {
77 console_close_shared, /* close_shared */
78 console_close_private, /* close_private */
84 /* Find handle has no ops.
86 struct _WapiHandleOps _wapi_find_ops = {
87 NULL, /* close_shared */
88 NULL, /* close_private */
94 static void pipe_close_shared (gpointer handle);
95 static void pipe_close_private (gpointer handle);
96 static WapiFileType pipe_getfiletype (void);
97 static gboolean pipe_read (gpointer handle, gpointer buffer, guint32 numbytes,
98 guint32 *bytesread, WapiOverlapped *overlapped);
99 static gboolean pipe_write (gpointer handle, gconstpointer buffer,
100 guint32 numbytes, guint32 *byteswritten,
101 WapiOverlapped *overlapped);
105 struct _WapiHandleOps _wapi_pipe_ops = {
106 pipe_close_shared, /* close_shared */
107 pipe_close_private, /* close_private */
114 /* File, console and pipe handles */
115 WapiFileType (*getfiletype)(void);
117 /* File, console and pipe handles */
118 gboolean (*readfile)(gpointer handle, gpointer buffer,
119 guint32 numbytes, guint32 *bytesread,
120 WapiOverlapped *overlapped);
121 gboolean (*writefile)(gpointer handle, gconstpointer buffer,
122 guint32 numbytes, guint32 *byteswritten,
123 WapiOverlapped *overlapped);
124 gboolean (*flushfile)(gpointer handle);
127 guint32 (*seek)(gpointer handle, gint32 movedistance,
128 gint32 *highmovedistance, WapiSeekMethod method);
129 gboolean (*setendoffile)(gpointer handle);
130 guint32 (*getfilesize)(gpointer handle, guint32 *highsize);
131 gboolean (*getfiletime)(gpointer handle, WapiFileTime *create_time,
132 WapiFileTime *last_access,
133 WapiFileTime *last_write);
134 gboolean (*setfiletime)(gpointer handle,
135 const WapiFileTime *create_time,
136 const WapiFileTime *last_access,
137 const WapiFileTime *last_write);
138 } io_ops[WAPI_HANDLE_COUNT]={
139 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
142 file_read, file_write,
143 file_flush, file_seek,
149 {console_getfiletype,
152 NULL, NULL, NULL, NULL, NULL, NULL},
154 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
156 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
158 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
160 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
161 /* socket (will need at least read and write) */
162 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
164 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
166 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
171 NULL, NULL, NULL, NULL, NULL, NULL},
175 static mono_once_t io_ops_once=MONO_ONCE_INIT;
177 static void io_ops_init (void)
179 /* _wapi_handle_register_capabilities (WAPI_HANDLE_FILE, */
180 /* WAPI_HANDLE_CAP_WAIT); */
181 /* _wapi_handle_register_capabilities (WAPI_HANDLE_CONSOLE, */
182 /* WAPI_HANDLE_CAP_WAIT); */
185 /* Some utility functions.
188 static guint32 _wapi_stat_to_file_attributes (struct stat *buf)
192 /* FIXME: this could definitely be better */
194 if (S_ISDIR (buf->st_mode))
195 attrs |= FILE_ATTRIBUTE_DIRECTORY;
197 attrs |= FILE_ATTRIBUTE_ARCHIVE;
199 if (!(buf->st_mode & S_IWUSR))
200 attrs |= FILE_ATTRIBUTE_READONLY;
205 static void _wapi_set_last_error_from_errno (void)
207 /* mapping ideas borrowed from wine. they may need some work */
210 case EACCES: case EPERM: case EROFS:
211 SetLastError (ERROR_ACCESS_DENIED);
215 SetLastError (ERROR_SHARING_VIOLATION);
219 SetLastError (ERROR_LOCK_VIOLATION);
223 SetLastError (ERROR_FILE_EXISTS);
226 case EINVAL: case ESPIPE:
227 SetLastError (ERROR_SEEK);
231 SetLastError (ERROR_CANNOT_MAKE);
234 case ENFILE: case EMFILE:
235 SetLastError (ERROR_NO_MORE_FILES);
238 case ENOENT: case ENOTDIR:
239 SetLastError (ERROR_FILE_NOT_FOUND);
243 SetLastError (ERROR_HANDLE_DISK_FULL);
247 SetLastError (ERROR_DIR_NOT_EMPTY);
251 SetLastError (ERROR_BAD_FORMAT);
255 SetLastError (ERROR_FILENAME_EXCED_RANGE);
259 g_message ("Unknown errno: %s\n", strerror (errno));
260 SetLastError (ERROR_GEN_FAILURE);
267 static void file_close_shared (gpointer handle)
269 struct _WapiHandle_file *file_handle;
272 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
273 (gpointer *)&file_handle, NULL);
275 g_warning (G_GNUC_PRETTY_FUNCTION
276 ": error looking up file handle %p", handle);
281 g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p", handle);
284 if(file_handle->filename!=0) {
285 _wapi_handle_scratch_delete (file_handle->filename);
286 file_handle->filename=0;
288 if(file_handle->security_attributes!=0) {
289 _wapi_handle_scratch_delete (file_handle->security_attributes);
290 file_handle->security_attributes=0;
294 static void file_close_private (gpointer handle)
296 struct _WapiHandlePrivate_file *file_private_handle;
299 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE, NULL,
300 (gpointer *)&file_private_handle);
302 g_warning (G_GNUC_PRETTY_FUNCTION
303 ": error looking up file handle %p", handle);
308 g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p with fd %d",
309 handle, file_private_handle->fd);
312 close(file_private_handle->fd);
315 static WapiFileType file_getfiletype(void)
317 return(FILE_TYPE_DISK);
320 static gboolean file_read(gpointer handle, gpointer buffer,
321 guint32 numbytes, guint32 *bytesread,
322 WapiOverlapped *overlapped G_GNUC_UNUSED)
324 struct _WapiHandle_file *file_handle;
325 struct _WapiHandlePrivate_file *file_private_handle;
329 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
330 (gpointer *)&file_handle,
331 (gpointer *)&file_private_handle);
333 g_warning (G_GNUC_PRETTY_FUNCTION
334 ": error looking up file handle %p", handle);
338 if(bytesread!=NULL) {
342 if(!(file_handle->fileaccess&GENERIC_READ) &&
343 !(file_handle->fileaccess&GENERIC_ALL)) {
345 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);
351 ret=read(file_private_handle->fd, buffer, numbytes);
354 g_message(G_GNUC_PRETTY_FUNCTION
355 ": read of handle %p fd %d error: %s", handle,
356 file_private_handle->fd, strerror(errno));
362 if(bytesread!=NULL) {
369 static gboolean file_write(gpointer handle, gconstpointer buffer,
370 guint32 numbytes, guint32 *byteswritten,
371 WapiOverlapped *overlapped G_GNUC_UNUSED)
373 struct _WapiHandle_file *file_handle;
374 struct _WapiHandlePrivate_file *file_private_handle;
378 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
379 (gpointer *)&file_handle,
380 (gpointer *)&file_private_handle);
382 g_warning (G_GNUC_PRETTY_FUNCTION
383 ": error looking up file handle %p", handle);
387 if(byteswritten!=NULL) {
391 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
392 !(file_handle->fileaccess&GENERIC_ALL)) {
394 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);
400 ret=write(file_private_handle->fd, buffer, numbytes);
403 g_message(G_GNUC_PRETTY_FUNCTION
404 ": write of handle %p fd %d error: %s", handle,
405 file_private_handle->fd, strerror(errno));
410 if(byteswritten!=NULL) {
417 static gboolean file_flush(gpointer handle)
419 struct _WapiHandle_file *file_handle;
420 struct _WapiHandlePrivate_file *file_private_handle;
424 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
425 (gpointer *)&file_handle,
426 (gpointer *)&file_private_handle);
428 g_warning (G_GNUC_PRETTY_FUNCTION
429 ": error looking up file handle %p", handle);
433 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
434 !(file_handle->fileaccess&GENERIC_ALL)) {
436 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);
442 ret=fsync(file_private_handle->fd);
445 g_message(G_GNUC_PRETTY_FUNCTION
446 ": write of handle %p fd %d error: %s", handle,
447 file_private_handle->fd, strerror(errno));
456 static guint32 file_seek(gpointer handle, gint32 movedistance,
457 gint32 *highmovedistance, WapiSeekMethod method)
459 struct _WapiHandle_file *file_handle;
460 struct _WapiHandlePrivate_file *file_private_handle;
462 off_t offset, newpos;
466 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
467 (gpointer *)&file_handle,
468 (gpointer *)&file_private_handle);
470 g_warning (G_GNUC_PRETTY_FUNCTION
471 ": error looking up file handle %p", handle);
472 return(INVALID_SET_FILE_POINTER);
475 if(!(file_handle->fileaccess&GENERIC_READ) &&
476 !(file_handle->fileaccess&GENERIC_WRITE) &&
477 !(file_handle->fileaccess&GENERIC_ALL)) {
479 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);
482 return(INVALID_SET_FILE_POINTER);
497 g_message(G_GNUC_PRETTY_FUNCTION ": invalid seek type %d",
501 return(INVALID_SET_FILE_POINTER);
504 #ifdef HAVE_LARGE_FILE_SUPPORT
505 if(highmovedistance==NULL) {
508 g_message(G_GNUC_PRETTY_FUNCTION
509 ": setting offset to %lld (low %d)", offset,
513 offset=((gint64) *highmovedistance << 32) | movedistance;
516 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);
524 #ifdef HAVE_LARGE_FILE_SUPPORT
525 g_message(G_GNUC_PRETTY_FUNCTION
526 ": moving handle %p fd %d by %lld bytes from %d", handle,
527 file_private_handle->fd, offset, whence);
529 g_message(G_GNUC_PRETTY_FUNCTION
530 ": moving handle %p fd %d by %ld bytes from %d", handle,
531 file_private_handle->fd, offset, whence);
535 newpos=lseek(file_private_handle->fd, offset, whence);
538 g_message(G_GNUC_PRETTY_FUNCTION
539 ": lseek on handle %p fd %d returned error %s",
540 handle, file_private_handle->fd, strerror(errno));
543 return(INVALID_SET_FILE_POINTER);
547 #ifdef HAVE_LARGE_FILE_SUPPORT
548 g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %lld", newpos);
550 g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %ld", newpos);
554 #ifdef HAVE_LARGE_FILE_SUPPORT
555 ret=newpos & 0xFFFFFFFF;
556 if(highmovedistance!=NULL) {
557 *highmovedistance=newpos>>32;
561 if(highmovedistance!=NULL) {
562 /* Accurate, but potentially dodgy :-) */
568 g_message(G_GNUC_PRETTY_FUNCTION
569 ": move of handle %p fd %d returning %d/%d", handle,
570 file_private_handle->fd, ret,
571 highmovedistance==NULL?0:*highmovedistance);
577 static gboolean file_setendoffile(gpointer handle)
579 struct _WapiHandle_file *file_handle;
580 struct _WapiHandlePrivate_file *file_private_handle;
586 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
587 (gpointer *)&file_handle,
588 (gpointer *)&file_private_handle);
590 g_warning (G_GNUC_PRETTY_FUNCTION
591 ": error looking up file handle %p", handle);
595 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
596 !(file_handle->fileaccess&GENERIC_ALL)) {
598 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);
604 /* Find the current file position, and the file length. If
605 * the file position is greater than the length, write to
606 * extend the file with a hole. If the file position is less
607 * than the length, truncate the file.
610 ret=fstat(file_private_handle->fd, &statbuf);
613 g_message(G_GNUC_PRETTY_FUNCTION
614 ": handle %p fd %d fstat failed: %s", handle,
615 file_private_handle->fd, strerror(errno));
620 size=statbuf.st_size;
622 pos=lseek(file_private_handle->fd, (off_t)0, SEEK_CUR);
625 g_message(G_GNUC_PRETTY_FUNCTION
626 ": handle %p fd %d lseek failed: %s", handle,
627 file_private_handle->fd, strerror(errno));
635 ret=write(file_private_handle->fd, "", 1);
638 g_message(G_GNUC_PRETTY_FUNCTION
639 ": handle %p fd %d extend write failed: %s",
640 handle, file_private_handle->fd,
648 /* always truncate, because the extend write() adds an extra
649 * byte to the end of the file
651 ret=ftruncate(file_private_handle->fd, pos);
654 g_message(G_GNUC_PRETTY_FUNCTION
655 ": handle %p fd %d ftruncate failed: %s", handle,
656 file_private_handle->fd, strerror(errno));
665 static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
667 struct _WapiHandle_file *file_handle;
668 struct _WapiHandlePrivate_file *file_private_handle;
674 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
675 (gpointer *)&file_handle,
676 (gpointer *)&file_private_handle);
678 g_warning (G_GNUC_PRETTY_FUNCTION
679 ": error looking up file handle %p", handle);
680 return(INVALID_FILE_SIZE);
683 if(!(file_handle->fileaccess&GENERIC_READ) &&
684 !(file_handle->fileaccess&GENERIC_WRITE) &&
685 !(file_handle->fileaccess&GENERIC_ALL)) {
687 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);
690 return(INVALID_FILE_SIZE);
693 ret=fstat(file_private_handle->fd, &statbuf);
696 g_message(G_GNUC_PRETTY_FUNCTION
697 ": handle %p fd %d fstat failed: %s", handle,
698 file_private_handle->fd, strerror(errno));
701 return(INVALID_FILE_SIZE);
704 #ifdef HAVE_LARGE_FILE_SUPPORT
705 size=statbuf.st_size & 0xFFFFFFFF;
707 *highsize=statbuf.st_size>>32;
711 /* Accurate, but potentially dodgy :-) */
714 size=statbuf.st_size;
718 g_message(G_GNUC_PRETTY_FUNCTION ": Returning size %d/%d", size,
725 static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
726 WapiFileTime *last_access,
727 WapiFileTime *last_write)
729 struct _WapiHandle_file *file_handle;
730 struct _WapiHandlePrivate_file *file_private_handle;
733 guint64 create_ticks, access_ticks, write_ticks;
736 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
737 (gpointer *)&file_handle,
738 (gpointer *)&file_private_handle);
740 g_warning (G_GNUC_PRETTY_FUNCTION
741 ": error looking up file handle %p", handle);
745 if(!(file_handle->fileaccess&GENERIC_READ) &&
746 !(file_handle->fileaccess&GENERIC_ALL)) {
748 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);
754 ret=fstat(file_private_handle->fd, &statbuf);
757 g_message(G_GNUC_PRETTY_FUNCTION
758 ": handle %p fd %d fstat failed: %s", handle,
759 file_private_handle->fd, strerror(errno));
766 g_message(G_GNUC_PRETTY_FUNCTION
767 ": atime: %ld ctime: %ld mtime: %ld",
768 statbuf.st_atime, statbuf.st_ctime,
772 /* Try and guess a meaningful create time by using the older
775 /* The magic constant comes from msdn documentation
776 * "Converting a time_t Value to a File Time"
778 if(statbuf.st_atime < statbuf.st_ctime) {
779 create_ticks=((guint64)statbuf.st_atime*10000000)
780 + 116444736000000000UL;
782 create_ticks=((guint64)statbuf.st_ctime*10000000)
783 + 116444736000000000UL;
786 access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000UL;
787 write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000UL;
790 g_message(G_GNUC_PRETTY_FUNCTION
791 ": aticks: %llu cticks: %llu wticks: %llu",
792 access_ticks, create_ticks, write_ticks);
795 if(create_time!=NULL) {
796 create_time->dwLowDateTime = create_ticks & 0xFFFFFFFF;
797 create_time->dwHighDateTime = create_ticks >> 32;
800 if(last_access!=NULL) {
801 last_access->dwLowDateTime = access_ticks & 0xFFFFFFFF;
802 last_access->dwHighDateTime = access_ticks >> 32;
805 if(last_write!=NULL) {
806 last_write->dwLowDateTime = write_ticks & 0xFFFFFFFF;
807 last_write->dwHighDateTime = write_ticks >> 32;
813 static gboolean file_setfiletime(gpointer handle,
814 const WapiFileTime *create_time G_GNUC_UNUSED,
815 const WapiFileTime *last_access,
816 const WapiFileTime *last_write)
818 struct _WapiHandle_file *file_handle;
819 struct _WapiHandlePrivate_file *file_private_handle;
822 struct utimbuf utbuf;
824 guint64 access_ticks, write_ticks;
827 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
828 (gpointer *)&file_handle,
829 (gpointer *)&file_private_handle);
831 g_warning (G_GNUC_PRETTY_FUNCTION
832 ": error looking up file handle %p", handle);
836 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
837 !(file_handle->fileaccess&GENERIC_ALL)) {
839 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);
845 if(file_handle->filename==0) {
847 g_message(G_GNUC_PRETTY_FUNCTION
848 ": handle %p fd %d unknown filename", handle,
849 file_private_handle->fd);
855 /* Get the current times, so we can put the same times back in
856 * the event that one of the FileTime structs is NULL
858 ret=fstat(file_private_handle->fd, &statbuf);
861 g_message(G_GNUC_PRETTY_FUNCTION
862 ": handle %p fd %d fstat failed: %s", handle,
863 file_private_handle->fd, strerror(errno));
869 if(last_access!=NULL) {
870 access_ticks=((guint64)last_access->dwHighDateTime << 32) +
871 last_access->dwLowDateTime;
872 utbuf.actime=(access_ticks - 116444736000000000) / 10000000;
874 utbuf.actime=statbuf.st_atime;
877 if(last_write!=NULL) {
878 write_ticks=((guint64)last_write->dwHighDateTime << 32) +
879 last_write->dwLowDateTime;
880 utbuf.modtime=(write_ticks - 116444736000000000) / 10000000;
882 utbuf.modtime=statbuf.st_mtime;
886 g_message(G_GNUC_PRETTY_FUNCTION
887 ": setting handle %p access %ld write %ld", handle,
888 utbuf.actime, utbuf.modtime);
891 name=_wapi_handle_scratch_lookup_as_string (file_handle->filename);
893 ret=utime(name, &utbuf);
896 g_message(G_GNUC_PRETTY_FUNCTION
897 ": handle %p [%s] fd %d utime failed: %s", handle,
898 name, file_private_handle->fd, strerror(errno));
910 static void console_close_shared (gpointer handle)
912 struct _WapiHandle_file *console_handle;
915 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
916 (gpointer *)&console_handle, NULL);
918 g_warning (G_GNUC_PRETTY_FUNCTION
919 ": error looking up console handle %p", handle);
924 g_message(G_GNUC_PRETTY_FUNCTION ": closing console handle %p", handle);
927 if(console_handle->filename!=0) {
928 _wapi_handle_scratch_delete (console_handle->filename);
929 console_handle->filename=0;
931 if(console_handle->security_attributes!=0) {
932 _wapi_handle_scratch_delete (console_handle->security_attributes);
933 console_handle->security_attributes=0;
937 static void console_close_private (gpointer handle)
939 struct _WapiHandlePrivate_file *console_private_handle;
942 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
943 (gpointer *)&console_private_handle);
945 g_warning (G_GNUC_PRETTY_FUNCTION
946 ": error looking up console handle %p", handle);
951 g_message(G_GNUC_PRETTY_FUNCTION
952 ": closing console handle %p with fd %d", handle,
953 console_private_handle->fd);
956 close(console_private_handle->fd);
959 static WapiFileType console_getfiletype(void)
961 return(FILE_TYPE_CHAR);
964 static gboolean console_read(gpointer handle, gpointer buffer,
965 guint32 numbytes, guint32 *bytesread,
966 WapiOverlapped *overlapped G_GNUC_UNUSED)
968 struct _WapiHandle_file *console_handle;
969 struct _WapiHandlePrivate_file *console_private_handle;
973 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
974 (gpointer *)&console_handle,
975 (gpointer *)&console_private_handle);
977 g_warning (G_GNUC_PRETTY_FUNCTION
978 ": error looking up console handle %p", handle);
982 if(bytesread!=NULL) {
986 if(!(console_handle->fileaccess&GENERIC_READ) &&
987 !(console_handle->fileaccess&GENERIC_ALL)) {
989 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);
995 ret=read(console_private_handle->fd, buffer, numbytes);
998 g_message(G_GNUC_PRETTY_FUNCTION
999 ": read of handle %p fd %d error: %s", handle,
1000 console_private_handle->fd, strerror(errno));
1006 if(bytesread!=NULL) {
1013 static gboolean console_write(gpointer handle, gconstpointer buffer,
1014 guint32 numbytes, guint32 *byteswritten,
1015 WapiOverlapped *overlapped G_GNUC_UNUSED)
1017 struct _WapiHandle_file *console_handle;
1018 struct _WapiHandlePrivate_file *console_private_handle;
1022 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1023 (gpointer *)&console_handle,
1024 (gpointer *)&console_private_handle);
1026 g_warning (G_GNUC_PRETTY_FUNCTION
1027 ": error looking up console handle %p", handle);
1031 if(byteswritten!=NULL) {
1035 if(!(console_handle->fileaccess&GENERIC_WRITE) &&
1036 !(console_handle->fileaccess&GENERIC_ALL)) {
1038 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);
1044 ret=write(console_private_handle->fd, buffer, numbytes);
1047 g_message(G_GNUC_PRETTY_FUNCTION
1048 ": write of handle %p fd %d error: %s", handle,
1049 console_private_handle->fd, strerror(errno));
1054 if(byteswritten!=NULL) {
1061 static void pipe_close_shared (gpointer handle)
1063 struct _WapiHandle_file *pipe_handle;
1066 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1067 (gpointer *)&pipe_handle, NULL);
1069 g_warning (G_GNUC_PRETTY_FUNCTION
1070 ": error looking up pipe handle %p", handle);
1075 g_message(G_GNUC_PRETTY_FUNCTION ": closing pipe handle %p", handle);
1078 if(pipe_handle->filename!=0) {
1079 _wapi_handle_scratch_delete (pipe_handle->filename);
1080 pipe_handle->filename=0;
1082 if(pipe_handle->security_attributes!=0) {
1083 _wapi_handle_scratch_delete (pipe_handle->security_attributes);
1084 pipe_handle->security_attributes=0;
1088 static void pipe_close_private (gpointer handle)
1090 struct _WapiHandlePrivate_file *pipe_private_handle;
1093 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE, NULL,
1094 (gpointer *)&pipe_private_handle);
1096 g_warning (G_GNUC_PRETTY_FUNCTION
1097 ": error looking up pipe handle %p", handle);
1102 g_message(G_GNUC_PRETTY_FUNCTION
1103 ": closing pipe handle %p with fd %d", handle,
1104 pipe_private_handle->fd);
1107 close(pipe_private_handle->fd);
1110 static WapiFileType pipe_getfiletype(void)
1112 return(FILE_TYPE_PIPE);
1115 static gboolean pipe_read (gpointer handle, gpointer buffer,
1116 guint32 numbytes, guint32 *bytesread,
1117 WapiOverlapped *overlapped G_GNUC_UNUSED)
1119 struct _WapiHandle_file *pipe_handle;
1120 struct _WapiHandlePrivate_file *pipe_private_handle;
1124 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1125 (gpointer *)&pipe_handle,
1126 (gpointer *)&pipe_private_handle);
1128 g_warning (G_GNUC_PRETTY_FUNCTION
1129 ": error looking up pipe handle %p", handle);
1133 if(bytesread!=NULL) {
1137 if(!(pipe_handle->fileaccess&GENERIC_READ) &&
1138 !(pipe_handle->fileaccess&GENERIC_ALL)) {
1140 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);
1147 g_message (G_GNUC_PRETTY_FUNCTION
1148 ": reading up to %d bytes from pipe %p (fd %d)", numbytes,
1149 handle, pipe_private_handle->fd);
1152 ret=read(pipe_private_handle->fd, buffer, numbytes);
1155 g_message(G_GNUC_PRETTY_FUNCTION
1156 ": read of handle %p fd %d error: %s", handle,
1157 pipe_private_handle->fd, strerror(errno));
1164 g_message (G_GNUC_PRETTY_FUNCTION ": read %d bytes from pipe", ret);
1167 if(bytesread!=NULL) {
1174 static gboolean pipe_write(gpointer handle, gconstpointer buffer,
1175 guint32 numbytes, guint32 *byteswritten,
1176 WapiOverlapped *overlapped G_GNUC_UNUSED)
1178 struct _WapiHandle_file *pipe_handle;
1179 struct _WapiHandlePrivate_file *pipe_private_handle;
1183 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
1184 (gpointer *)&pipe_handle,
1185 (gpointer *)&pipe_private_handle);
1187 g_warning (G_GNUC_PRETTY_FUNCTION
1188 ": error looking up pipe handle %p", handle);
1192 if(byteswritten!=NULL) {
1196 if(!(pipe_handle->fileaccess&GENERIC_WRITE) &&
1197 !(pipe_handle->fileaccess&GENERIC_ALL)) {
1199 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 ret=write(pipe_private_handle->fd, buffer, numbytes);
1208 g_message(G_GNUC_PRETTY_FUNCTION
1209 ": write of handle %p fd %d error: %s", handle,
1210 pipe_private_handle->fd, strerror(errno));
1215 if(byteswritten!=NULL) {
1222 static int convert_flags(guint32 fileaccess, guint32 createmode)
1226 switch(fileaccess) {
1233 case GENERIC_READ|GENERIC_WRITE:
1238 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown access type 0x%x",
1244 switch(createmode) {
1246 flags|=O_CREAT|O_EXCL;
1249 flags|=O_CREAT|O_TRUNC;
1256 case TRUNCATE_EXISTING:
1261 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown create mode 0x%x",
1270 static guint32 convert_from_flags(int flags)
1272 guint32 fileaccess=0;
1275 #define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
1278 if((flags & O_ACCMODE) == O_RDONLY) {
1279 fileaccess=GENERIC_READ;
1280 } else if ((flags & O_ACCMODE) == O_WRONLY) {
1281 fileaccess=GENERIC_WRITE;
1282 } else if ((flags & O_ACCMODE) == O_RDWR) {
1283 fileaccess=GENERIC_READ|GENERIC_WRITE;
1286 g_message(G_GNUC_PRETTY_FUNCTION
1287 ": Can't figure out flags 0x%x", flags);
1291 /* Maybe sort out create mode too */
1296 static mode_t convert_perms(guint32 sharemode)
1300 if(sharemode&FILE_SHARE_READ) {
1303 if(sharemode&FILE_SHARE_WRITE) {
1313 * @name: a pointer to a NULL-terminated unicode string, that names
1314 * the file or other object to create.
1315 * @fileaccess: specifies the file access mode
1316 * @sharemode: whether the file should be shared. This parameter is
1317 * currently ignored.
1318 * @security: Ignored for now.
1319 * @createmode: specifies whether to create a new file, whether to
1320 * overwrite an existing file, whether to truncate the file, etc.
1321 * @attrs: specifies file attributes and flags. On win32 attributes
1322 * are characteristics of the file, not the handle, and are ignored
1323 * when an existing file is opened. Flags give the library hints on
1324 * how to process a file to optimise performance.
1325 * @template: the handle of an open %GENERIC_READ file that specifies
1326 * attributes to apply to a newly created file, ignoring @attrs.
1327 * Normally this parameter is NULL. This parameter is ignored when an
1328 * existing file is opened.
1330 * Creates a new file handle. This only applies to normal files:
1331 * pipes are handled by CreatePipe(), and console handles are created
1332 * with GetStdHandle().
1334 * Return value: the new handle, or %INVALID_HANDLE_VALUE on error.
1336 gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
1337 guint32 sharemode, WapiSecurityAttributes *security,
1338 guint32 createmode, guint32 attrs,
1339 gpointer template G_GNUC_UNUSED)
1341 struct _WapiHandle_file *file_handle;
1342 struct _WapiHandlePrivate_file *file_private_handle;
1345 int flags=convert_flags(fileaccess, createmode);
1346 mode_t perms=convert_perms(sharemode);
1350 mono_once (&io_ops_once, io_ops_init);
1354 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1357 return(INVALID_HANDLE_VALUE);
1360 filename=_wapi_unicode_to_utf8(name);
1361 if(filename==NULL) {
1363 g_message(G_GNUC_PRETTY_FUNCTION
1364 ": unicode conversion returned NULL");
1367 return(INVALID_HANDLE_VALUE);
1370 ret=open(filename, flags, perms);
1374 g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
1375 filename, strerror(errno));
1377 _wapi_set_last_error_from_errno ();
1380 return(INVALID_HANDLE_VALUE);
1383 handle=_wapi_handle_new (WAPI_HANDLE_FILE);
1384 if(handle==_WAPI_HANDLE_INVALID) {
1385 g_warning (G_GNUC_PRETTY_FUNCTION
1386 ": error creating file handle");
1389 return(INVALID_HANDLE_VALUE);
1392 _wapi_handle_lock_handle (handle);
1394 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
1395 (gpointer *)&file_handle,
1396 (gpointer *)&file_private_handle);
1398 g_warning (G_GNUC_PRETTY_FUNCTION
1399 ": error looking up file handle %p", handle);
1400 _wapi_handle_unlock_handle (handle);
1403 return(INVALID_HANDLE_VALUE);
1406 file_private_handle->fd=ret;
1407 file_private_handle->assigned=TRUE;
1408 file_handle->filename=_wapi_handle_scratch_store (filename,
1410 if(security!=NULL) {
1411 file_handle->security_attributes=_wapi_handle_scratch_store (
1412 security, sizeof(WapiSecurityAttributes));
1415 file_handle->fileaccess=fileaccess;
1416 file_handle->sharemode=sharemode;
1417 file_handle->attrs=attrs;
1420 g_message(G_GNUC_PRETTY_FUNCTION
1421 ": returning handle %p with fd %d", handle,
1422 file_private_handle->fd);
1425 _wapi_handle_unlock_handle (handle);
1433 * @name: a pointer to a NULL-terminated unicode string, that names
1434 * the file to be deleted.
1436 * Deletes file @name.
1438 * Return value: %TRUE on success, %FALSE otherwise.
1440 gboolean DeleteFile(const gunichar2 *name)
1447 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1453 filename=_wapi_unicode_to_utf8(name);
1454 if(filename==NULL) {
1456 g_message(G_GNUC_PRETTY_FUNCTION
1457 ": unicode conversion returned NULL");
1463 ret=unlink(filename);
1476 * @name: a pointer to a NULL-terminated unicode string, that names
1477 * the file to be moved.
1478 * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1479 * new name for the file.
1481 * Renames file @name to @dest_name
1483 * Return value: %TRUE on success, %FALSE otherwise.
1485 gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
1487 gchar *utf8_name, *utf8_dest_name;
1490 utf8_name = _wapi_unicode_to_utf8 (name);
1491 if (utf8_name == NULL) {
1493 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1499 utf8_dest_name = _wapi_unicode_to_utf8 (dest_name);
1500 if (utf8_dest_name == NULL) {
1502 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1509 result = rename (utf8_name, utf8_dest_name);
1511 g_free (utf8_dest_name);
1518 SetLastError (ERROR_ALREADY_EXISTS);
1522 _wapi_set_last_error_from_errno ();
1531 * @name: a pointer to a NULL-terminated unicode string, that names
1532 * the file to be copied.
1533 * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1534 * new name for the file.
1535 * @fail_if_exists: if TRUE and dest_name exists, the copy will fail.
1537 * Copies file @name to @dest_name
1539 * Return value: %TRUE on success, %FALSE otherwise.
1541 gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
1542 gboolean fail_if_exists)
1549 attrs = GetFileAttributes (name);
1551 SetLastError (ERROR_FILE_NOT_FOUND);
1555 src = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1556 NULL, OPEN_EXISTING, 0, NULL);
1557 if (src == INVALID_HANDLE_VALUE) {
1558 _wapi_set_last_error_from_errno ();
1562 dest = CreateFile (dest_name, GENERIC_WRITE, 0, NULL,
1563 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS, attrs, NULL);
1564 if (dest == INVALID_HANDLE_VALUE) {
1565 _wapi_set_last_error_from_errno ();
1570 buffer = g_new (gchar, 2048);
1573 if (ReadFile (src, buffer,sizeof (buffer), &remain, NULL) == 0) {
1574 _wapi_set_last_error_from_errno ();
1576 g_message (G_GNUC_PRETTY_FUNCTION ": read failed.");
1587 while (remain > 0) {
1588 if (WriteFile (dest, buffer, remain, &n, NULL) == 0) {
1589 _wapi_set_last_error_from_errno ();
1591 g_message (G_GNUC_PRETTY_FUNCTION ": write failed.");
1610 static gboolean console_find_fd (gpointer handle, gpointer user_data)
1612 struct _WapiHandlePrivate_file *file_private_handle;
1616 fd=GPOINTER_TO_UINT (user_data);
1619 g_message (G_GNUC_PRETTY_FUNCTION
1620 ": Looking up a console handle for fd %d", fd);
1623 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
1624 (gpointer *)&file_private_handle);
1626 g_warning (G_GNUC_PRETTY_FUNCTION
1627 ": error looking up console handle %p", handle);
1631 if(file_private_handle->fd==fd &&
1632 file_private_handle->assigned==TRUE) {
1634 g_message (G_GNUC_PRETTY_FUNCTION
1635 ": Returning console handle %p", handle);
1646 * @stdhandle: specifies the file descriptor
1648 * Returns a handle for stdin, stdout, or stderr. Always returns the
1649 * same handle for the same @stdhandle.
1651 * Return value: the handle, or %INVALID_HANDLE_VALUE on error
1654 gpointer GetStdHandle(WapiStdHandle stdhandle)
1656 struct _WapiHandle_file *file_handle;
1657 struct _WapiHandlePrivate_file *file_private_handle;
1663 mono_once (&io_ops_once, io_ops_init);
1666 case STD_INPUT_HANDLE:
1671 case STD_OUTPUT_HANDLE:
1676 case STD_ERROR_HANDLE:
1683 g_message(G_GNUC_PRETTY_FUNCTION
1684 ": unknown standard handle type");
1687 return(INVALID_HANDLE_VALUE);
1691 g_message(G_GNUC_PRETTY_FUNCTION ": creating standard handle type %s",
1695 /* Check if fd is valid */
1696 flags=fcntl(fd, F_GETFL);
1698 /* Invalid fd. Not really much point checking for EBADF
1702 g_message(G_GNUC_PRETTY_FUNCTION ": fcntl error on fd %d: %s",
1703 fd, strerror(errno));
1706 return(INVALID_HANDLE_VALUE);
1709 /* See if we already have a handle for this fd */
1710 handle=_wapi_search_handle (WAPI_HANDLE_CONSOLE, console_find_fd,
1711 GUINT_TO_POINTER (fd), NULL, NULL);
1713 /* Create a new one */
1714 handle=_wapi_handle_new (WAPI_HANDLE_CONSOLE);
1715 if(handle==_WAPI_HANDLE_INVALID) {
1716 g_warning (G_GNUC_PRETTY_FUNCTION
1717 ": error creating file handle");
1721 _wapi_handle_lock_handle (handle);
1723 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1724 (gpointer *)&file_handle,
1725 (gpointer *)&file_private_handle);
1727 g_warning (G_GNUC_PRETTY_FUNCTION
1728 ": error looking up console handle %p",
1730 _wapi_handle_unlock_handle (handle);
1734 file_private_handle->fd=fd;
1735 file_private_handle->assigned=TRUE;
1736 file_handle->filename=_wapi_handle_scratch_store (name, strlen (name));
1737 /* some default security attributes might be needed */
1738 file_handle->security_attributes=0;
1739 file_handle->fileaccess=convert_from_flags(flags);
1740 file_handle->sharemode=0;
1741 file_handle->attrs=0;
1744 g_message(G_GNUC_PRETTY_FUNCTION
1745 ": returning handle %p with fd %d", handle,
1746 file_private_handle->fd);
1749 _wapi_handle_unlock_handle (handle);
1752 g_message(G_GNUC_PRETTY_FUNCTION
1753 ": reusing handle %p with fd %d", handle,
1754 file_private_handle->fd);
1757 /* Add a reference to this reused handle */
1758 _wapi_handle_ref (handle);
1766 * @handle: The file handle to read from. The handle must have
1767 * %GENERIC_READ access.
1768 * @buffer: The buffer to store read data in
1769 * @numbytes: The maximum number of bytes to read
1770 * @bytesread: The actual number of bytes read is stored here. This
1771 * value can be zero if the handle is positioned at the end of the
1773 * @overlapped: points to a required %WapiOverlapped structure if
1774 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1777 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1778 * function reads up to @numbytes bytes from the file from the current
1779 * file position, and stores them in @buffer. If there are not enough
1780 * bytes left in the file, just the amount available will be read.
1781 * The actual number of bytes read is stored in @bytesread.
1783 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1784 * file position is ignored and the read position is taken from data
1785 * in the @overlapped structure.
1787 * Return value: %TRUE if the read succeeds (even if no bytes were
1788 * read due to an attempt to read past the end of the file), %FALSE on
1791 gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
1792 guint32 *bytesread, WapiOverlapped *overlapped)
1794 WapiHandleType type=_wapi_handle_type (handle);
1796 if(io_ops[type].readfile==NULL) {
1800 return(io_ops[type].readfile (handle, buffer, numbytes, bytesread,
1806 * @handle: The file handle to write to. The handle must have
1807 * %GENERIC_WRITE access.
1808 * @buffer: The buffer to read data from.
1809 * @numbytes: The maximum number of bytes to write.
1810 * @byteswritten: The actual number of bytes written is stored here.
1811 * If the handle is positioned at the file end, the length of the file
1812 * is extended. This parameter may be %NULL.
1813 * @overlapped: points to a required %WapiOverlapped structure if
1814 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1817 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1818 * function writes up to @numbytes bytes from @buffer to the file at
1819 * the current file position. If @handle is positioned at the end of
1820 * the file, the file is extended. The actual number of bytes written
1821 * is stored in @byteswritten.
1823 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1824 * file position is ignored and the write position is taken from data
1825 * in the @overlapped structure.
1827 * Return value: %TRUE if the write succeeds, %FALSE on error.
1829 gboolean WriteFile(gpointer handle, gconstpointer buffer, guint32 numbytes,
1830 guint32 *byteswritten, WapiOverlapped *overlapped)
1832 WapiHandleType type=_wapi_handle_type (handle);
1834 if(io_ops[type].writefile==NULL) {
1838 return(io_ops[type].writefile (handle, buffer, numbytes, byteswritten,
1844 * @handle: Handle to open file. The handle must have
1845 * %GENERIC_WRITE access.
1847 * Flushes buffers of the file and causes all unwritten data to
1850 * Return value: %TRUE on success, %FALSE otherwise.
1852 gboolean FlushFileBuffers(gpointer handle)
1854 WapiHandleType type=_wapi_handle_type (handle);
1856 if(io_ops[type].flushfile==NULL) {
1860 return(io_ops[type].flushfile (handle));
1865 * @handle: The file handle to set. The handle must have
1866 * %GENERIC_WRITE access.
1868 * Moves the end-of-file position to the current position of the file
1869 * pointer. This function is used to truncate or extend a file.
1871 * Return value: %TRUE on success, %FALSE otherwise.
1873 gboolean SetEndOfFile(gpointer handle)
1875 WapiHandleType type=_wapi_handle_type (handle);
1877 if(io_ops[type].setendoffile==NULL) {
1881 return(io_ops[type].setendoffile (handle));
1886 * @handle: The file handle to set. The handle must have
1887 * %GENERIC_READ or %GENERIC_WRITE access.
1888 * @movedistance: Low 32 bits of a signed value that specifies the
1889 * number of bytes to move the file pointer.
1890 * @highmovedistance: Pointer to the high 32 bits of a signed value
1891 * that specifies the number of bytes to move the file pointer, or
1893 * @method: The starting point for the file pointer move.
1895 * Sets the file pointer of an open file.
1897 * The distance to move the file pointer is calculated from
1898 * @movedistance and @highmovedistance: If @highmovedistance is %NULL,
1899 * @movedistance is the 32-bit signed value; otherwise, @movedistance
1900 * is the low 32 bits and @highmovedistance a pointer to the high 32
1901 * bits of a 64 bit signed value. A positive distance moves the file
1902 * pointer forward from the position specified by @method; a negative
1903 * distance moves the file pointer backward.
1905 * If the library is compiled without large file support,
1906 * @highmovedistance is ignored and its value is set to zero on a
1907 * successful return.
1909 * Return value: On success, the low 32 bits of the new file pointer.
1910 * If @highmovedistance is not %NULL, the high 32 bits of the new file
1911 * pointer are stored there. On failure, %INVALID_SET_FILE_POINTER.
1913 guint32 SetFilePointer(gpointer handle, gint32 movedistance,
1914 gint32 *highmovedistance, WapiSeekMethod method)
1916 WapiHandleType type=_wapi_handle_type (handle);
1918 if(io_ops[type].seek==NULL) {
1922 return(io_ops[type].seek (handle, movedistance, highmovedistance,
1928 * @handle: The file handle to test.
1930 * Finds the type of file @handle.
1932 * Return value: %FILE_TYPE_UNKNOWN - the type of the file @handle is
1933 * unknown. %FILE_TYPE_DISK - @handle is a disk file.
1934 * %FILE_TYPE_CHAR - @handle is a character device, such as a console.
1935 * %FILE_TYPE_PIPE - @handle is a named or anonymous pipe.
1937 WapiFileType GetFileType(gpointer handle)
1939 WapiHandleType type=_wapi_handle_type (handle);
1941 if(io_ops[type].getfiletype==NULL) {
1942 return(FILE_TYPE_UNKNOWN);
1945 return(io_ops[type].getfiletype ());
1950 * @handle: The file handle to query. The handle must have
1951 * %GENERIC_READ or %GENERIC_WRITE access.
1952 * @highsize: If non-%NULL, the high 32 bits of the file size are
1955 * Retrieves the size of the file @handle.
1957 * If the library is compiled without large file support, @highsize
1958 * has its value set to zero on a successful return.
1960 * Return value: On success, the low 32 bits of the file size. If
1961 * @highsize is non-%NULL then the high 32 bits of the file size are
1962 * stored here. On failure %INVALID_FILE_SIZE is returned.
1964 guint32 GetFileSize(gpointer handle, guint32 *highsize)
1966 WapiHandleType type=_wapi_handle_type (handle);
1968 if(io_ops[type].getfilesize==NULL) {
1972 return(io_ops[type].getfilesize (handle, highsize));
1977 * @handle: The file handle to query. The handle must have
1978 * %GENERIC_READ access.
1979 * @create_time: Points to a %WapiFileTime structure to receive the
1980 * number of ticks since the epoch that file was created. May be
1982 * @last_access: Points to a %WapiFileTime structure to receive the
1983 * number of ticks since the epoch when file was last accessed. May be
1985 * @last_write: Points to a %WapiFileTime structure to receive the
1986 * number of ticks since the epoch when file was last written to. May
1989 * Finds the number of ticks since the epoch that the file referenced
1990 * by @handle was created, last accessed and last modified. A tick is
1991 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
1994 * Create time isn't recorded on POSIX file systems or reported by
1995 * stat(2), so that time is guessed by returning the oldest of the
1998 * Return value: %TRUE on success, %FALSE otherwise.
2000 gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
2001 WapiFileTime *last_access, WapiFileTime *last_write)
2003 WapiHandleType type=_wapi_handle_type (handle);
2005 if(io_ops[type].getfiletime==NULL) {
2009 return(io_ops[type].getfiletime (handle, create_time, last_access,
2015 * @handle: The file handle to set. The handle must have
2016 * %GENERIC_WRITE access.
2017 * @create_time: Points to a %WapiFileTime structure that contains the
2018 * number of ticks since the epoch that the file was created. May be
2020 * @last_access: Points to a %WapiFileTime structure that contains the
2021 * number of ticks since the epoch when the file was last accessed.
2023 * @last_write: Points to a %WapiFileTime structure that contains the
2024 * number of ticks since the epoch when the file was last written to.
2027 * Sets the number of ticks since the epoch that the file referenced
2028 * by @handle was created, last accessed or last modified. A tick is
2029 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
2032 * Create time isn't recorded on POSIX file systems, and is ignored.
2034 * Return value: %TRUE on success, %FALSE otherwise.
2036 gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
2037 const WapiFileTime *last_access,
2038 const WapiFileTime *last_write)
2040 WapiHandleType type=_wapi_handle_type (handle);
2042 if(io_ops[type].setfiletime==NULL) {
2046 return(io_ops[type].setfiletime (handle, create_time, last_access,
2050 /* A tick is a 100-nanosecond interval. File time epoch is Midnight,
2051 * January 1 1601 GMT
2054 #define TICKS_PER_MILLISECOND 10000L
2055 #define TICKS_PER_SECOND 10000000L
2056 #define TICKS_PER_MINUTE 600000000L
2057 #define TICKS_PER_HOUR 36000000000L
2058 #define TICKS_PER_DAY 864000000000L
2060 #define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
2062 static const guint16 mon_yday[2][13]={
2063 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
2064 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
2068 * FileTimeToSystemTime:
2069 * @file_time: Points to a %WapiFileTime structure that contains the
2070 * number of ticks to convert.
2071 * @system_time: Points to a %WapiSystemTime structure to receive the
2074 * Converts a tick count into broken-out time values.
2076 * Return value: %TRUE on success, %FALSE otherwise.
2078 gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
2079 WapiSystemTime *system_time)
2081 gint64 file_ticks, totaldays, rem, y;
2084 if(system_time==NULL) {
2086 g_message(G_GNUC_PRETTY_FUNCTION ": system_time NULL");
2092 file_ticks=((gint64)file_time->dwHighDateTime << 32) +
2093 file_time->dwLowDateTime;
2095 /* Really compares if file_ticks>=0x8000000000000000
2096 * (LLONG_MAX+1) but we're working with a signed value for the
2097 * year and day calculation to work later
2101 g_message(G_GNUC_PRETTY_FUNCTION ": file_time too big");
2107 totaldays=(file_ticks / TICKS_PER_DAY);
2108 rem = file_ticks % TICKS_PER_DAY;
2110 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld rem: %lld",
2114 system_time->wHour=rem/TICKS_PER_HOUR;
2115 rem %= TICKS_PER_HOUR;
2117 g_message(G_GNUC_PRETTY_FUNCTION ": Hour: %d rem: %lld",
2118 system_time->wHour, rem);
2121 system_time->wMinute = rem / TICKS_PER_MINUTE;
2122 rem %= TICKS_PER_MINUTE;
2124 g_message(G_GNUC_PRETTY_FUNCTION ": Minute: %d rem: %lld",
2125 system_time->wMinute, rem);
2128 system_time->wSecond = rem / TICKS_PER_SECOND;
2129 rem %= TICKS_PER_SECOND;
2131 g_message(G_GNUC_PRETTY_FUNCTION ": Second: %d rem: %lld",
2132 system_time->wSecond, rem);
2135 system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
2137 g_message(G_GNUC_PRETTY_FUNCTION ": Milliseconds: %d",
2138 system_time->wMilliseconds);
2141 /* January 1, 1601 was a Monday, according to Emacs calendar */
2142 system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
2144 g_message(G_GNUC_PRETTY_FUNCTION ": Day of week: %d",
2145 system_time->wDayOfWeek);
2148 /* This algorithm to find year and month given days from epoch
2153 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
2154 #define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400))
2156 while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
2157 /* Guess a corrected year, assuming 365 days per year */
2158 gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
2160 g_message(G_GNUC_PRETTY_FUNCTION
2161 ": totaldays: %lld yg: %lld y: %lld", totaldays, yg,
2163 g_message(G_GNUC_PRETTY_FUNCTION
2164 ": LEAPS(yg): %lld LEAPS(y): %lld",
2165 LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
2168 /* Adjust days and y to match the guessed year. */
2169 totaldays -= ((yg - y) * 365
2170 + LEAPS_THRU_END_OF (yg - 1)
2171 - LEAPS_THRU_END_OF (y - 1));
2173 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld",
2178 g_message(G_GNUC_PRETTY_FUNCTION ": y: %lld", y);
2182 system_time->wYear = y;
2184 g_message(G_GNUC_PRETTY_FUNCTION ": Year: %d", system_time->wYear);
2187 ip = mon_yday[isleap(y)];
2189 for(y=11; totaldays < ip[y]; --y) {
2194 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld", totaldays);
2197 system_time->wMonth = y + 1;
2199 g_message(G_GNUC_PRETTY_FUNCTION ": Month: %d", system_time->wMonth);
2202 system_time->wDay = totaldays + 1;
2204 g_message(G_GNUC_PRETTY_FUNCTION ": Day: %d", system_time->wDay);
2210 gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
2212 struct _WapiHandle_find *find_handle;
2215 gchar *utf8_pattern = NULL;
2218 if (pattern == NULL) {
2220 g_message (G_GNUC_PRETTY_FUNCTION ": pattern is NULL");
2223 return INVALID_HANDLE_VALUE;
2226 utf8_pattern = _wapi_unicode_to_utf8 (pattern);
2227 if (utf8_pattern == NULL) {
2229 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2232 return INVALID_HANDLE_VALUE;
2235 handle=_wapi_handle_new (WAPI_HANDLE_FIND);
2236 if(handle==_WAPI_HANDLE_INVALID) {
2237 g_warning (G_GNUC_PRETTY_FUNCTION
2238 ": error creating find handle");
2239 g_free (utf8_pattern);
2241 return(INVALID_HANDLE_VALUE);
2244 _wapi_handle_lock_handle (handle);
2246 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2247 (gpointer *)&find_handle, NULL);
2249 g_warning (G_GNUC_PRETTY_FUNCTION
2250 ": error looking up find handle %p", handle);
2251 _wapi_handle_unlock_handle (handle);
2252 g_free (utf8_pattern);
2254 return(INVALID_HANDLE_VALUE);
2257 result = glob (utf8_pattern, 0, NULL, &find_handle->glob);
2258 g_free (utf8_pattern);
2261 globfree (&find_handle->glob);
2262 _wapi_handle_unlock_handle (handle);
2263 _wapi_handle_unref (handle);
2268 SetLastError (ERROR_NO_MORE_FILES);
2274 g_message (G_GNUC_PRETTY_FUNCTION ": glob failed with code %d.", result);
2280 return INVALID_HANDLE_VALUE;
2283 find_handle->count = 0;
2284 if (!FindNextFile (handle, find_data)) {
2286 SetLastError (ERROR_NO_MORE_FILES);
2287 return INVALID_HANDLE_VALUE;
2290 _wapi_handle_unlock_handle (handle);
2295 gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
2297 struct _WapiHandle_find *find_handle;
2300 const gchar *filename;
2302 gchar *base_filename;
2303 gunichar2 *utf16_basename;
2307 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2308 (gpointer *)&find_handle, NULL);
2310 g_warning (G_GNUC_PRETTY_FUNCTION
2311 ": error looking up find handle %p", handle);
2312 SetLastError (ERROR_INVALID_HANDLE);
2316 if (find_handle->count >= find_handle->glob.gl_pathc) {
2317 SetLastError (ERROR_NO_MORE_FILES);
2321 /* stat next glob match */
2323 filename = find_handle->glob.gl_pathv [find_handle->count ++];
2324 if (stat (filename, &buf) != 0) {
2326 g_message (G_GNUC_PRETTY_FUNCTION ": stat failed: %s", filename);
2329 SetLastError (ERROR_NO_MORE_FILES);
2333 /* fill data block */
2335 if (buf.st_mtime < buf.st_ctime)
2336 create_time = buf.st_mtime;
2338 create_time = buf.st_ctime;
2340 find_data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2342 _wapi_time_t_to_filetime (create_time, &find_data->ftCreationTime);
2343 _wapi_time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
2344 _wapi_time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime);
2346 if (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2347 find_data->nFileSizeHigh = 0;
2348 find_data->nFileSizeLow = 0;
2351 find_data->nFileSizeHigh = buf.st_size >> 32;
2352 find_data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2355 find_data->dwReserved0 = 0;
2356 find_data->dwReserved1 = 0;
2358 base_filename = g_path_get_basename (filename);
2359 utf16_basename = g_utf8_to_utf16 (base_filename, MAX_PATH, NULL, NULL, NULL);
2362 while (utf16_basename [i] != 0) { /* copy basename */
2363 find_data->cFileName [i] = utf16_basename [i];
2367 find_data->cFileName[i] = 0; /* null terminate */
2368 find_data->cAlternateFileName [0] = 0; /* not used */
2370 g_free (base_filename);
2371 g_free (utf16_basename);
2377 * @wapi_handle: the find handle to close.
2379 * Closes find handle @wapi_handle
2381 * Return value: %TRUE on success, %FALSE otherwise.
2383 gboolean FindClose (gpointer handle)
2385 struct _WapiHandle_find *find_handle;
2388 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2389 (gpointer *)&find_handle, NULL);
2391 g_warning (G_GNUC_PRETTY_FUNCTION
2392 ": error looking up find handle %p", handle);
2393 SetLastError (ERROR_INVALID_HANDLE);
2397 globfree (&find_handle->glob);
2398 _wapi_handle_unref (handle);
2405 * @name: a pointer to a NULL-terminated unicode string, that names
2406 * the directory to be created.
2407 * @security: ignored for now
2409 * Creates directory @name
2411 * Return value: %TRUE on success, %FALSE otherwise.
2413 gboolean CreateDirectory (const gunichar2 *name, WapiSecurityAttributes *security)
2418 utf8_name = _wapi_unicode_to_utf8 (name);
2419 if (utf8_name == NULL) {
2421 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2427 result = mkdir (utf8_name, 0777);
2437 _wapi_set_last_error_from_errno ();
2446 * @name: a pointer to a NULL-terminated unicode string, that names
2447 * the directory to be removed.
2449 * Removes directory @name
2451 * Return value: %TRUE on success, %FALSE otherwise.
2453 gboolean RemoveDirectory (const gunichar2 *name)
2458 utf8_name = _wapi_unicode_to_utf8 (name);
2459 if (utf8_name == NULL) {
2461 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2467 result = rmdir (utf8_name);
2473 _wapi_set_last_error_from_errno ();
2478 * GetFileAttributes:
2479 * @name: a pointer to a NULL-terminated unicode filename.
2481 * Gets the attributes for @name;
2483 * Return value: -1 on failure
2485 guint32 GetFileAttributes (const gunichar2 *name)
2491 utf8_name = _wapi_unicode_to_utf8 (name);
2492 if (utf8_name == NULL) {
2494 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2497 SetLastError (ERROR_INVALID_PARAMETER);
2501 result = stat (utf8_name, &buf);
2505 SetLastError (ERROR_FILE_NOT_FOUND);
2509 return _wapi_stat_to_file_attributes (&buf);
2513 * GetFileAttributesEx:
2514 * @name: a pointer to a NULL-terminated unicode filename.
2515 * @level: must be GetFileExInfoStandard
2516 * @info: pointer to a WapiFileAttributesData structure
2518 * Gets attributes, size and filetimes for @name;
2520 * Return value: %TRUE on success, %FALSE on failure
2522 gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels level, gpointer info)
2525 WapiFileAttributesData *data;
2531 if (level != GetFileExInfoStandard) {
2533 g_message (G_GNUC_PRETTY_FUNCTION ": info level %d not supported.", level);
2539 utf8_name = _wapi_unicode_to_utf8 (name);
2540 if (utf8_name == NULL) {
2542 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2545 SetLastError (ERROR_INVALID_PARAMETER);
2549 result = stat (utf8_name, &buf);
2553 SetLastError (ERROR_FILE_NOT_FOUND);
2557 /* fill data block */
2559 data = (WapiFileAttributesData *)info;
2561 if (buf.st_mtime < buf.st_ctime)
2562 create_time = buf.st_mtime;
2564 create_time = buf.st_ctime;
2566 data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2568 _wapi_time_t_to_filetime (create_time, &data->ftCreationTime);
2569 _wapi_time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
2570 _wapi_time_t_to_filetime (buf.st_mtime, &data->ftLastWriteTime);
2572 if (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2573 data->nFileSizeHigh = 0;
2574 data->nFileSizeLow = 0;
2577 data->nFileSizeHigh = buf.st_size >> 32;
2578 data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2586 * @name: name of file
2587 * @attrs: attributes to set
2589 * Changes the attributes on a named file.
2591 * Return value: %TRUE on success, %FALSE on failure.
2593 extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
2595 /* FIXME: think of something clever to do on unix */
2597 SetLastError (ERROR_INVALID_FUNCTION);
2602 * GetCurrentDirectory
2603 * @length: size of the buffer
2604 * @buffer: pointer to buffer that recieves path
2606 * Retrieves the current directory for the current process.
2608 * Return value: number of characters in buffer on success, zero on failure
2610 extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer)
2613 gunichar2 *utf16_path, *ptr;
2616 path = g_get_current_dir ();
2620 /* if buffer too small, return number of characters required.
2621 * this is plain dumb.
2624 count = strlen (path) + 1;
2628 utf16_path = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
2629 if (utf16_path == NULL)
2634 *buffer ++ = *ptr ++;
2638 g_free (utf16_path);
2645 * SetCurrentDirectory
2646 * @path: path to new directory
2648 * Changes the directory path for the current process.
2650 * Return value: %TRUE on success, %FALSE on failure.
2652 extern gboolean SetCurrentDirectory (const gunichar2 *path)
2657 utf8_path = _wapi_unicode_to_utf8 (path);
2658 if (chdir (utf8_path) != 0) {
2659 _wapi_set_last_error_from_errno ();
2669 int _wapi_file_handle_to_fd (gpointer handle)
2671 struct _WapiHandlePrivate_file *file_private_handle;
2675 g_message (G_GNUC_PRETTY_FUNCTION ": looking up fd for %p", handle);
2678 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE, NULL,
2679 (gpointer *)&file_private_handle);
2681 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE, NULL,
2682 (gpointer *)&file_private_handle);
2684 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE, NULL,
2685 (gpointer *)&file_private_handle);
2688 g_message (G_GNUC_PRETTY_FUNCTION
2697 g_message (G_GNUC_PRETTY_FUNCTION ": returning %d",
2698 file_private_handle->fd);
2701 return(file_private_handle->fd);
2704 gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
2705 WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 size)
2707 struct _WapiHandle_file *pipe_read_handle;
2708 struct _WapiHandle_file *pipe_write_handle;
2709 struct _WapiHandlePrivate_file *pipe_read_private_handle;
2710 struct _WapiHandlePrivate_file *pipe_write_private_handle;
2711 gpointer read_handle;
2712 gpointer write_handle;
2717 mono_once (&io_ops_once, io_ops_init);
2720 g_message (G_GNUC_PRETTY_FUNCTION ": Creating pipe");
2726 g_message (G_GNUC_PRETTY_FUNCTION ": Error creating pipe: %s",
2730 _wapi_set_last_error_from_errno ();
2734 /* filedes[0] is open for reading, filedes[1] for writing */
2736 read_handle=_wapi_handle_new (WAPI_HANDLE_PIPE);
2737 if(read_handle==_WAPI_HANDLE_INVALID) {
2738 g_warning (G_GNUC_PRETTY_FUNCTION
2739 ": error creating pipe read handle");
2745 _wapi_handle_lock_handle (read_handle);
2747 ok=_wapi_lookup_handle (read_handle, WAPI_HANDLE_PIPE,
2748 (gpointer *)&pipe_read_handle,
2749 (gpointer *)&pipe_read_private_handle);
2751 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2752 _wapi_handle_unlock_handle (read_handle);
2758 write_handle=_wapi_handle_new (WAPI_HANDLE_PIPE);
2759 if(write_handle==_WAPI_HANDLE_INVALID) {
2760 g_warning (G_GNUC_PRETTY_FUNCTION
2761 ": error creating pipe write handle");
2762 _wapi_handle_unlock_handle (read_handle);
2763 _wapi_handle_unref (read_handle);
2770 _wapi_handle_lock_handle (write_handle);
2772 ok=_wapi_lookup_handle (write_handle, WAPI_HANDLE_PIPE,
2773 (gpointer *)&pipe_write_handle,
2774 (gpointer *)&pipe_write_private_handle);
2776 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up pipe handle %p", read_handle);
2777 _wapi_handle_unlock_handle (read_handle);
2778 _wapi_handle_unref (read_handle);
2779 _wapi_handle_unlock_handle (write_handle);
2785 pipe_read_private_handle->fd=filedes[0];
2786 pipe_read_private_handle->assigned=TRUE;
2787 pipe_read_handle->fileaccess=GENERIC_READ;
2789 *readpipe=read_handle;
2791 pipe_write_private_handle->fd=filedes[1];
2792 pipe_write_private_handle->assigned=TRUE;
2793 pipe_write_handle->fileaccess=GENERIC_WRITE;
2795 *writepipe=write_handle;
2797 _wapi_handle_unlock_handle (read_handle);
2798 _wapi_handle_unlock_handle (write_handle);
2801 g_message (G_GNUC_PRETTY_FUNCTION
2802 ": Returning pipe: read handle %p, write handle %p",
2803 read_handle, write_handle);