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>
30 #define ACTUALLY_DO_UNICODE
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);
72 static gboolean console_flush(gpointer handle);
74 /* Console is mostly the same as file, except it can block waiting for
77 struct _WapiHandleOps _wapi_console_ops = {
78 console_close_shared, /* close_shared */
79 console_close_private, /* close_private */
85 /* Find handle has no ops.
87 struct _WapiHandleOps _wapi_find_ops = {
89 NULL, /* getfiletype */
96 /* File, console and pipe handles */
97 WapiFileType (*getfiletype)(void);
99 /* File and console handles */
100 gboolean (*readfile)(gpointer handle, gpointer buffer,
101 guint32 numbytes, guint32 *bytesread,
102 WapiOverlapped *overlapped);
103 gboolean (*writefile)(gpointer handle, gconstpointer buffer,
104 guint32 numbytes, guint32 *byteswritten,
105 WapiOverlapped *overlapped);
106 gboolean (*flushfile)(gpointer handle);
109 guint32 (*seek)(gpointer handle, gint32 movedistance,
110 gint32 *highmovedistance, WapiSeekMethod method);
111 gboolean (*setendoffile)(gpointer handle);
112 guint32 (*getfilesize)(gpointer handle, guint32 *highsize);
113 gboolean (*getfiletime)(gpointer handle, WapiFileTime *create_time,
114 WapiFileTime *last_access,
115 WapiFileTime *last_write);
116 gboolean (*setfiletime)(gpointer handle,
117 const WapiFileTime *create_time,
118 const WapiFileTime *last_access,
119 const WapiFileTime *last_write);
120 } io_ops[WAPI_HANDLE_COUNT]={
121 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
124 file_read, file_write,
125 file_flush, file_seek,
131 {console_getfiletype,
135 NULL, NULL, NULL, NULL, NULL},
137 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
139 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
141 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
143 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
144 /* socket (will need at least read and write) */
145 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
147 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
149 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
153 static pthread_once_t io_ops_once=PTHREAD_ONCE_INIT;
155 static void io_ops_init (void)
157 /* _wapi_handle_register_capabilities (WAPI_HANDLE_FILE, */
158 /* WAPI_HANDLE_CAP_WAIT); */
159 /* _wapi_handle_register_capabilities (WAPI_HANDLE_CONSOLE, */
160 /* WAPI_HANDLE_CAP_WAIT); */
163 /* Some utility functions.
165 static void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime)
169 ticks = ((guint64)timeval * 10000000) + 116444736000000000UL;
170 filetime->dwLowDateTime = ticks & 0xFFFFFFFF;
171 filetime->dwHighDateTime = ticks >> 32;
174 static guint32 _wapi_stat_to_file_attributes (struct stat *buf)
178 /* FIXME: this could definitely be better */
180 if (S_ISDIR (buf->st_mode))
181 attrs |= FILE_ATTRIBUTE_DIRECTORY;
183 attrs |= FILE_ATTRIBUTE_ARCHIVE;
185 if (!(buf->st_mode & S_IWUSR))
186 attrs |= FILE_ATTRIBUTE_READONLY;
191 static void _wapi_set_last_error_from_errno (void)
193 /* mapping ideas borrowed from wine. they may need some work */
196 case EACCES: case EPERM: case EROFS:
197 SetLastError (ERROR_ACCESS_DENIED);
201 SetLastError (ERROR_SHARING_VIOLATION);
205 SetLastError (ERROR_LOCK_VIOLATION);
209 SetLastError (ERROR_FILE_EXISTS);
212 case EINVAL: case ESPIPE:
213 SetLastError (ERROR_SEEK);
217 SetLastError (ERROR_CANNOT_MAKE);
220 case ENFILE: case EMFILE:
221 SetLastError (ERROR_NO_MORE_FILES);
224 case ENOENT: case ENOTDIR:
225 SetLastError (ERROR_FILE_NOT_FOUND);
229 SetLastError (ERROR_HANDLE_DISK_FULL);
233 SetLastError (ERROR_DIR_NOT_EMPTY);
237 SetLastError (ERROR_BAD_FORMAT);
241 SetLastError (ERROR_FILENAME_EXCED_RANGE);
245 g_message ("Unknown errno: %s\n", strerror (errno));
246 SetLastError (ERROR_GEN_FAILURE);
253 static void file_close_shared (gpointer handle)
255 struct _WapiHandle_file *file_handle;
258 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
259 (gpointer *)&file_handle, NULL);
261 g_warning (G_GNUC_PRETTY_FUNCTION
262 ": error looking up file handle %p", handle);
267 g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p", handle);
270 if(file_handle->filename!=0) {
271 _wapi_handle_scratch_delete (file_handle->filename);
272 file_handle->filename=0;
274 if(file_handle->security_attributes!=0) {
275 _wapi_handle_scratch_delete (file_handle->security_attributes);
276 file_handle->security_attributes=0;
280 static void file_close_private (gpointer handle)
282 struct _WapiHandlePrivate_file *file_private_handle;
285 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_UNUSED, NULL,
286 (gpointer *)&file_private_handle);
288 g_warning (G_GNUC_PRETTY_FUNCTION
289 ": error looking up file handle %p", handle);
294 g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p with fd %d",
295 handle, file_private_handle->fd);
298 close(file_private_handle->fd);
301 static WapiFileType file_getfiletype(void)
303 return(FILE_TYPE_DISK);
306 static gboolean file_read(gpointer handle, gpointer buffer,
307 guint32 numbytes, guint32 *bytesread,
308 WapiOverlapped *overlapped G_GNUC_UNUSED)
310 struct _WapiHandle_file *file_handle;
311 struct _WapiHandlePrivate_file *file_private_handle;
315 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
316 (gpointer *)&file_handle,
317 (gpointer *)&file_private_handle);
319 g_warning (G_GNUC_PRETTY_FUNCTION
320 ": error looking up file handle %p", handle);
324 if(bytesread!=NULL) {
328 if(!(file_handle->fileaccess&GENERIC_READ) &&
329 !(file_handle->fileaccess&GENERIC_ALL)) {
331 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);
337 ret=read(file_private_handle->fd, buffer, numbytes);
340 g_message(G_GNUC_PRETTY_FUNCTION
341 ": read of handle %p fd %d error: %s", handle,
342 file_private_handle->fd, strerror(errno));
348 if(bytesread!=NULL) {
355 static gboolean file_write(gpointer handle, gconstpointer buffer,
356 guint32 numbytes, guint32 *byteswritten,
357 WapiOverlapped *overlapped G_GNUC_UNUSED)
359 struct _WapiHandle_file *file_handle;
360 struct _WapiHandlePrivate_file *file_private_handle;
364 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
365 (gpointer *)&file_handle,
366 (gpointer *)&file_private_handle);
368 g_warning (G_GNUC_PRETTY_FUNCTION
369 ": error looking up file handle %p", handle);
373 if(byteswritten!=NULL) {
377 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
378 !(file_handle->fileaccess&GENERIC_ALL)) {
380 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);
386 ret=write(file_private_handle->fd, buffer, numbytes);
389 g_message(G_GNUC_PRETTY_FUNCTION
390 ": write of handle %p fd %d error: %s", handle,
391 file_private_handle->fd, strerror(errno));
396 if(byteswritten!=NULL) {
403 static gboolean file_flush(gpointer handle)
405 struct _WapiHandle_file *file_handle;
406 struct _WapiHandlePrivate_file *file_private_handle;
410 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
411 (gpointer *)&file_handle,
412 (gpointer *)&file_private_handle);
414 g_warning (G_GNUC_PRETTY_FUNCTION
415 ": error looking up file handle %p", handle);
419 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
420 !(file_handle->fileaccess&GENERIC_ALL)) {
422 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);
428 ret=fsync(file_private_handle->fd);
431 g_message(G_GNUC_PRETTY_FUNCTION
432 ": write of handle %p fd %d error: %s", handle,
433 file_private_handle->fd, strerror(errno));
442 static guint32 file_seek(gpointer handle, gint32 movedistance,
443 gint32 *highmovedistance, WapiSeekMethod method)
445 struct _WapiHandle_file *file_handle;
446 struct _WapiHandlePrivate_file *file_private_handle;
448 off_t offset, newpos;
452 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
453 (gpointer *)&file_handle,
454 (gpointer *)&file_private_handle);
456 g_warning (G_GNUC_PRETTY_FUNCTION
457 ": error looking up file handle %p", handle);
458 return(INVALID_SET_FILE_POINTER);
461 if(!(file_handle->fileaccess&GENERIC_READ) &&
462 !(file_handle->fileaccess&GENERIC_WRITE) &&
463 !(file_handle->fileaccess&GENERIC_ALL)) {
465 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);
468 return(INVALID_SET_FILE_POINTER);
483 g_message(G_GNUC_PRETTY_FUNCTION ": invalid seek type %d",
487 return(INVALID_SET_FILE_POINTER);
490 #ifdef HAVE_LARGE_FILE_SUPPORT
491 if(highmovedistance==NULL) {
494 g_message(G_GNUC_PRETTY_FUNCTION
495 ": setting offset to %lld (low %d)", offset,
499 offset=((gint64) *highmovedistance << 32) | movedistance;
502 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);
510 #ifdef HAVE_LARGE_FILE_SUPPORT
511 g_message(G_GNUC_PRETTY_FUNCTION
512 ": moving handle %p fd %d by %lld bytes from %d", handle,
513 file_private_handle->fd, offset, whence);
515 g_message(G_GNUC_PRETTY_FUNCTION
516 ": moving handle %p fd %d by %ld bytes from %d", handle,
517 file_private_handle->fd, offset, whence);
521 newpos=lseek(file_private_handle->fd, offset, whence);
524 g_message(G_GNUC_PRETTY_FUNCTION
525 ": lseek on handle %p fd %d returned error %s",
526 handle, file_private_handle->fd, strerror(errno));
529 return(INVALID_SET_FILE_POINTER);
533 #ifdef HAVE_LARGE_FILE_SUPPORT
534 g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %lld", newpos);
536 g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %ld", newpos);
540 #ifdef HAVE_LARGE_FILE_SUPPORT
541 ret=newpos & 0xFFFFFFFF;
542 if(highmovedistance!=NULL) {
543 *highmovedistance=newpos>>32;
547 if(highmovedistance!=NULL) {
548 /* Accurate, but potentially dodgy :-) */
554 g_message(G_GNUC_PRETTY_FUNCTION
555 ": move of handle %p fd %d returning %d/%d", handle,
556 file_private_handle->fd, ret,
557 highmovedistance==NULL?0:*highmovedistance);
563 static gboolean file_setendoffile(gpointer handle)
565 struct _WapiHandle_file *file_handle;
566 struct _WapiHandlePrivate_file *file_private_handle;
572 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
573 (gpointer *)&file_handle,
574 (gpointer *)&file_private_handle);
576 g_warning (G_GNUC_PRETTY_FUNCTION
577 ": error looking up file handle %p", handle);
581 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
582 !(file_handle->fileaccess&GENERIC_ALL)) {
584 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);
590 /* Find the current file position, and the file length. If
591 * the file position is greater than the length, write to
592 * extend the file with a hole. If the file position is less
593 * than the length, truncate the file.
596 ret=fstat(file_private_handle->fd, &statbuf);
599 g_message(G_GNUC_PRETTY_FUNCTION
600 ": handle %p fd %d fstat failed: %s", handle,
601 file_private_handle->fd, strerror(errno));
606 size=statbuf.st_size;
608 pos=lseek(file_private_handle->fd, (off_t)0, SEEK_CUR);
611 g_message(G_GNUC_PRETTY_FUNCTION
612 ": handle %p fd %d lseek failed: %s", handle,
613 file_private_handle->fd, strerror(errno));
621 ret=write(file_private_handle->fd, "", 1);
624 g_message(G_GNUC_PRETTY_FUNCTION
625 ": handle %p fd %d extend write failed: %s",
626 handle, file_private_handle->fd,
634 /* always truncate, because the extend write() adds an extra
635 * byte to the end of the file
637 ret=ftruncate(file_private_handle->fd, pos);
640 g_message(G_GNUC_PRETTY_FUNCTION
641 ": handle %p fd %d ftruncate failed: %s", handle,
642 file_private_handle->fd, strerror(errno));
651 static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
653 struct _WapiHandle_file *file_handle;
654 struct _WapiHandlePrivate_file *file_private_handle;
660 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
661 (gpointer *)&file_handle,
662 (gpointer *)&file_private_handle);
664 g_warning (G_GNUC_PRETTY_FUNCTION
665 ": error looking up file handle %p", handle);
666 return(INVALID_FILE_SIZE);
669 if(!(file_handle->fileaccess&GENERIC_READ) &&
670 !(file_handle->fileaccess&GENERIC_WRITE) &&
671 !(file_handle->fileaccess&GENERIC_ALL)) {
673 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);
676 return(INVALID_FILE_SIZE);
679 ret=fstat(file_private_handle->fd, &statbuf);
682 g_message(G_GNUC_PRETTY_FUNCTION
683 ": handle %p fd %d fstat failed: %s", handle,
684 file_private_handle->fd, strerror(errno));
687 return(INVALID_FILE_SIZE);
690 #ifdef HAVE_LARGE_FILE_SUPPORT
691 size=statbuf.st_size & 0xFFFFFFFF;
693 *highsize=statbuf.st_size>>32;
697 /* Accurate, but potentially dodgy :-) */
700 size=statbuf.st_size;
704 g_message(G_GNUC_PRETTY_FUNCTION ": Returning size %d/%d", size,
711 static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
712 WapiFileTime *last_access,
713 WapiFileTime *last_write)
715 struct _WapiHandle_file *file_handle;
716 struct _WapiHandlePrivate_file *file_private_handle;
719 guint64 create_ticks, access_ticks, write_ticks;
722 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
723 (gpointer *)&file_handle,
724 (gpointer *)&file_private_handle);
726 g_warning (G_GNUC_PRETTY_FUNCTION
727 ": error looking up file handle %p", handle);
731 if(!(file_handle->fileaccess&GENERIC_READ) &&
732 !(file_handle->fileaccess&GENERIC_ALL)) {
734 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);
740 ret=fstat(file_private_handle->fd, &statbuf);
743 g_message(G_GNUC_PRETTY_FUNCTION
744 ": handle %p fd %d fstat failed: %s", handle,
745 file_private_handle->fd, strerror(errno));
752 g_message(G_GNUC_PRETTY_FUNCTION
753 ": atime: %ld ctime: %ld mtime: %ld",
754 statbuf.st_atime, statbuf.st_ctime,
758 /* Try and guess a meaningful create time by using the older
761 /* The magic constant comes from msdn documentation
762 * "Converting a time_t Value to a File Time"
764 if(statbuf.st_atime < statbuf.st_ctime) {
765 create_ticks=((guint64)statbuf.st_atime*10000000)
766 + 116444736000000000UL;
768 create_ticks=((guint64)statbuf.st_ctime*10000000)
769 + 116444736000000000UL;
772 access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000UL;
773 write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000UL;
776 g_message(G_GNUC_PRETTY_FUNCTION
777 ": aticks: %llu cticks: %llu wticks: %llu",
778 access_ticks, create_ticks, write_ticks);
781 if(create_time!=NULL) {
782 create_time->dwLowDateTime = create_ticks & 0xFFFFFFFF;
783 create_time->dwHighDateTime = create_ticks >> 32;
786 if(last_access!=NULL) {
787 last_access->dwLowDateTime = access_ticks & 0xFFFFFFFF;
788 last_access->dwHighDateTime = access_ticks >> 32;
791 if(last_write!=NULL) {
792 last_write->dwLowDateTime = write_ticks & 0xFFFFFFFF;
793 last_write->dwHighDateTime = write_ticks >> 32;
799 static gboolean file_setfiletime(gpointer handle,
800 const WapiFileTime *create_time G_GNUC_UNUSED,
801 const WapiFileTime *last_access,
802 const WapiFileTime *last_write)
804 struct _WapiHandle_file *file_handle;
805 struct _WapiHandlePrivate_file *file_private_handle;
808 struct utimbuf utbuf;
810 guint64 access_ticks, write_ticks;
813 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
814 (gpointer *)&file_handle,
815 (gpointer *)&file_private_handle);
817 g_warning (G_GNUC_PRETTY_FUNCTION
818 ": error looking up file handle %p", handle);
822 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
823 !(file_handle->fileaccess&GENERIC_ALL)) {
825 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);
831 if(file_handle->filename==0) {
833 g_message(G_GNUC_PRETTY_FUNCTION
834 ": handle %p fd %d unknown filename", handle,
835 file_private_handle->fd);
841 /* Get the current times, so we can put the same times back in
842 * the event that one of the FileTime structs is NULL
844 ret=fstat(file_private_handle->fd, &statbuf);
847 g_message(G_GNUC_PRETTY_FUNCTION
848 ": handle %p fd %d fstat failed: %s", handle,
849 file_private_handle->fd, strerror(errno));
855 if(last_access!=NULL) {
856 access_ticks=((guint64)last_access->dwHighDateTime << 32) +
857 last_access->dwLowDateTime;
858 utbuf.actime=(access_ticks - 116444736000000000) / 10000000;
860 utbuf.actime=statbuf.st_atime;
863 if(last_write!=NULL) {
864 write_ticks=((guint64)last_write->dwHighDateTime << 32) +
865 last_write->dwLowDateTime;
866 utbuf.modtime=(write_ticks - 116444736000000000) / 10000000;
868 utbuf.modtime=statbuf.st_mtime;
872 g_message(G_GNUC_PRETTY_FUNCTION
873 ": setting handle %p access %ld write %ld", handle,
874 utbuf.actime, utbuf.modtime);
877 name=_wapi_handle_scratch_lookup_as_string (file_handle->filename);
879 ret=utime(name, &utbuf);
882 g_message(G_GNUC_PRETTY_FUNCTION
883 ": handle %p [%s] fd %d utime failed: %s", handle,
884 name, file_private_handle->fd, strerror(errno));
896 static void console_close_shared (gpointer handle)
898 struct _WapiHandle_file *console_handle;
901 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
902 (gpointer *)&console_handle, NULL);
904 g_warning (G_GNUC_PRETTY_FUNCTION
905 ": error looking up console handle %p", handle);
910 g_message(G_GNUC_PRETTY_FUNCTION ": closing console handle %p", handle);
913 if(console_handle->filename!=0) {
914 _wapi_handle_scratch_delete (console_handle->filename);
915 console_handle->filename=0;
917 if(console_handle->security_attributes!=0) {
918 _wapi_handle_scratch_delete (console_handle->security_attributes);
919 console_handle->security_attributes=0;
923 static void console_close_private (gpointer handle)
925 struct _WapiHandlePrivate_file *console_private_handle;
928 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_UNUSED, NULL,
929 (gpointer *)&console_private_handle);
931 g_warning (G_GNUC_PRETTY_FUNCTION
932 ": error looking up console handle %p", handle);
937 g_message(G_GNUC_PRETTY_FUNCTION
938 ": closing console handle %p with fd %d", handle,
939 console_private_handle->fd);
942 close(console_private_handle->fd);
945 static WapiFileType console_getfiletype(void)
947 return(FILE_TYPE_CHAR);
950 static gboolean console_read(gpointer handle, gpointer buffer,
951 guint32 numbytes, guint32 *bytesread,
952 WapiOverlapped *overlapped G_GNUC_UNUSED)
954 struct _WapiHandle_file *console_handle;
955 struct _WapiHandlePrivate_file *console_private_handle;
959 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
960 (gpointer *)&console_handle,
961 (gpointer *)&console_private_handle);
963 g_warning (G_GNUC_PRETTY_FUNCTION
964 ": error looking up console handle %p", handle);
968 if(bytesread!=NULL) {
972 if(!(console_handle->fileaccess&GENERIC_READ) &&
973 !(console_handle->fileaccess&GENERIC_ALL)) {
975 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);
981 ret=read(console_private_handle->fd, buffer, numbytes);
984 g_message(G_GNUC_PRETTY_FUNCTION
985 ": read of handle %p fd %d error: %s", handle,
986 console_private_handle->fd, strerror(errno));
992 if(bytesread!=NULL) {
999 static gboolean console_write(gpointer handle, gconstpointer buffer,
1000 guint32 numbytes, guint32 *byteswritten,
1001 WapiOverlapped *overlapped G_GNUC_UNUSED)
1003 struct _WapiHandle_file *console_handle;
1004 struct _WapiHandlePrivate_file *console_private_handle;
1008 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1009 (gpointer *)&console_handle,
1010 (gpointer *)&console_private_handle);
1012 g_warning (G_GNUC_PRETTY_FUNCTION
1013 ": error looking up console handle %p", handle);
1017 if(byteswritten!=NULL) {
1021 if(!(console_handle->fileaccess&GENERIC_WRITE) &&
1022 !(console_handle->fileaccess&GENERIC_ALL)) {
1024 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);
1030 ret=write(console_private_handle->fd, buffer, numbytes);
1033 g_message(G_GNUC_PRETTY_FUNCTION
1034 ": write of handle %p fd %d error: %s", handle,
1035 console_private_handle->fd, strerror(errno));
1040 if(byteswritten!=NULL) {
1047 static gboolean console_flush(gpointer handle)
1049 struct _WapiHandle_file *console_handle;
1050 struct _WapiHandlePrivate_file *console_private_handle;
1054 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1055 (gpointer *)&console_handle,
1056 (gpointer *)&console_private_handle);
1058 g_warning (G_GNUC_PRETTY_FUNCTION
1059 ": error looking up console handle %p", handle);
1063 if(!(console_handle->fileaccess&GENERIC_WRITE) &&
1064 !(console_handle->fileaccess&GENERIC_ALL)) {
1066 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);
1072 ret=fsync(console_private_handle->fd);
1075 g_message(G_GNUC_PRETTY_FUNCTION
1076 ": write of handle %p fd %d error: %s", handle,
1077 console_private_handle->fd, strerror(errno));
1086 static int convert_flags(guint32 fileaccess, guint32 createmode)
1090 switch(fileaccess) {
1097 case GENERIC_READ|GENERIC_WRITE:
1102 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown access type 0x%x",
1108 switch(createmode) {
1110 flags|=O_CREAT|O_EXCL;
1113 flags|=O_CREAT|O_TRUNC;
1120 case TRUNCATE_EXISTING:
1125 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown create mode 0x%x",
1134 static guint32 convert_from_flags(int flags)
1136 guint32 fileaccess=0;
1138 if(flags&O_RDONLY) {
1139 fileaccess=GENERIC_READ;
1140 } else if (flags&O_WRONLY) {
1141 fileaccess=GENERIC_WRITE;
1142 } else if (flags&O_RDWR) {
1143 fileaccess=GENERIC_READ|GENERIC_WRITE;
1146 g_message(G_GNUC_PRETTY_FUNCTION
1147 ": Can't figure out flags 0x%x", flags);
1151 /* Maybe sort out create mode too */
1156 static mode_t convert_perms(guint32 sharemode)
1160 if(sharemode&FILE_SHARE_READ) {
1163 if(sharemode&FILE_SHARE_WRITE) {
1173 * @name: a pointer to a NULL-terminated unicode string, that names
1174 * the file or other object to create.
1175 * @fileaccess: specifies the file access mode
1176 * @sharemode: whether the file should be shared. This parameter is
1177 * currently ignored.
1178 * @security: Ignored for now.
1179 * @createmode: specifies whether to create a new file, whether to
1180 * overwrite an existing file, whether to truncate the file, etc.
1181 * @attrs: specifies file attributes and flags. On win32 attributes
1182 * are characteristics of the file, not the handle, and are ignored
1183 * when an existing file is opened. Flags give the library hints on
1184 * how to process a file to optimise performance.
1185 * @template: the handle of an open %GENERIC_READ file that specifies
1186 * attributes to apply to a newly created file, ignoring @attrs.
1187 * Normally this parameter is NULL. This parameter is ignored when an
1188 * existing file is opened.
1190 * Creates a new file handle. This only applies to normal files:
1191 * pipes are handled by CreatePipe(), and console handles are created
1192 * with GetStdHandle().
1194 * Return value: the new handle, or %INVALID_HANDLE_VALUE on error.
1196 gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
1197 guint32 sharemode, WapiSecurityAttributes *security,
1198 guint32 createmode, guint32 attrs,
1199 gpointer template G_GNUC_UNUSED)
1201 struct _WapiHandle_file *file_handle;
1202 struct _WapiHandlePrivate_file *file_private_handle;
1205 int flags=convert_flags(fileaccess, createmode);
1206 mode_t perms=convert_perms(sharemode);
1210 pthread_once (&io_ops_once, io_ops_init);
1214 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1217 return(INVALID_HANDLE_VALUE);
1219 filename=_wapi_unicode_to_utf8(name);
1221 #ifdef ACTUALLY_DO_UNICODE
1222 if(filename==NULL) {
1224 g_message(G_GNUC_PRETTY_FUNCTION
1225 ": unicode conversion returned NULL");
1228 return(INVALID_HANDLE_VALUE);
1232 #ifdef ACTUALLY_DO_UNICODE
1233 ret=open(filename, flags, perms);
1235 ret=open(name, flags, perms);
1240 #ifdef ACTUALLY_DO_UNICODE
1241 g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
1242 filename, strerror(errno));
1244 g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
1245 filename, strerror(errno));
1248 _wapi_set_last_error_from_errno ();
1249 return(INVALID_HANDLE_VALUE);
1252 handle=_wapi_handle_new (WAPI_HANDLE_FILE);
1253 if(handle==_WAPI_HANDLE_INVALID) {
1254 g_warning (G_GNUC_PRETTY_FUNCTION
1255 ": error creating file handle");
1256 return(INVALID_HANDLE_VALUE);
1259 _wapi_handle_lock_handle (handle);
1261 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
1262 (gpointer *)&file_handle,
1263 (gpointer *)&file_private_handle);
1265 g_warning (G_GNUC_PRETTY_FUNCTION
1266 ": error looking up file handle %p", handle);
1267 _wapi_handle_unlock_handle (handle);
1268 return(INVALID_HANDLE_VALUE);
1271 file_private_handle->fd=ret;
1272 #ifdef ACTUALLY_DO_UNICODE
1273 file_handle->filename=_wapi_handle_scratch_store (filename,
1276 file_handle->filename=_wapi_handle_scratch_store (name, strlen (name));
1278 if(security!=NULL) {
1279 file_handle->security_attributes=_wapi_handle_scratch_store (
1280 security, sizeof(WapiSecurityAttributes));
1283 file_handle->fileaccess=fileaccess;
1284 file_handle->sharemode=sharemode;
1285 file_handle->attrs=attrs;
1288 g_message(G_GNUC_PRETTY_FUNCTION
1289 ": returning handle %p with fd %d", handle,
1290 file_private_handle->fd);
1293 _wapi_handle_unlock_handle (handle);
1300 * @name: a pointer to a NULL-terminated unicode string, that names
1301 * the file to be deleted.
1303 * Deletes file @name.
1305 * Return value: %TRUE on success, %FALSE otherwise.
1307 gboolean DeleteFile(const gunichar2 *name)
1314 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
1320 filename=_wapi_unicode_to_utf8(name);
1321 #ifdef ACTUALLY_DO_UNICODE
1322 if(filename==NULL) {
1324 g_message(G_GNUC_PRETTY_FUNCTION
1325 ": unicode conversion returned NULL");
1332 #ifdef ACTUALLY_DO_UNICODE
1333 ret=unlink(filename);
1349 * @name: a pointer to a NULL-terminated unicode string, that names
1350 * the file to be moved.
1351 * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1352 * new name for the file.
1354 * Renames file @name to @dest_name
1356 * Return value: %TRUE on success, %FALSE otherwise.
1358 gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
1360 gchar *utf8_name, *utf8_dest_name;
1363 utf8_name = _wapi_unicode_to_utf8 (name);
1364 if (utf8_name == NULL) {
1366 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1372 utf8_dest_name = _wapi_unicode_to_utf8 (dest_name);
1373 if (utf8_dest_name == NULL) {
1375 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
1382 result = rename (utf8_name, utf8_dest_name);
1384 g_free (utf8_dest_name);
1391 SetLastError (ERROR_ALREADY_EXISTS);
1395 _wapi_set_last_error_from_errno ();
1404 * @name: a pointer to a NULL-terminated unicode string, that names
1405 * the file to be copied.
1406 * @dest_name: a pointer to a NULL-terminated unicode string, that is the
1407 * new name for the file.
1408 * @fail_if_exists: if TRUE and dest_name exists, the copy will fail.
1410 * Copies file @name to @dest_name
1412 * Return value: %TRUE on success, %FALSE otherwise.
1414 gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
1415 gboolean fail_if_exists)
1422 attrs = GetFileAttributes (name);
1424 SetLastError (ERROR_FILE_NOT_FOUND);
1428 src = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1429 NULL, OPEN_EXISTING, 0, NULL);
1430 if (src == INVALID_HANDLE_VALUE) {
1431 _wapi_set_last_error_from_errno ();
1435 dest = CreateFile (dest_name, GENERIC_WRITE, 0, NULL,
1436 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS, attrs, NULL);
1437 if (dest == INVALID_HANDLE_VALUE) {
1438 _wapi_set_last_error_from_errno ();
1443 buffer = g_new (gchar, 2048);
1446 if (ReadFile (src, buffer,sizeof (buffer), &remain, NULL) == 0) {
1447 _wapi_set_last_error_from_errno ();
1449 g_message (G_GNUC_PRETTY_FUNCTION ": read failed.");
1460 while (remain > 0) {
1461 if (WriteFile (dest, buffer, remain, &n, NULL) == 0) {
1462 _wapi_set_last_error_from_errno ();
1464 g_message (G_GNUC_PRETTY_FUNCTION ": write failed.");
1485 * @stdhandle: specifies the file descriptor
1487 * Returns a handle for stdin, stdout, or stderr. Always returns the
1488 * same handle for the same @stdhandle.
1490 * Return value: the handle, or %INVALID_HANDLE_VALUE on error
1493 gpointer GetStdHandle(WapiStdHandle stdhandle)
1495 struct _WapiHandle_file *file_handle;
1496 struct _WapiHandlePrivate_file *file_private_handle;
1502 pthread_once (&io_ops_once, io_ops_init);
1505 case STD_INPUT_HANDLE:
1510 case STD_OUTPUT_HANDLE:
1515 case STD_ERROR_HANDLE:
1522 g_message(G_GNUC_PRETTY_FUNCTION
1523 ": unknown standard handle type");
1526 return(INVALID_HANDLE_VALUE);
1529 /* Check if fd is valid */
1530 flags=fcntl(fd, F_GETFL);
1532 /* Invalid fd. Not really much point checking for EBADF
1536 g_message(G_GNUC_PRETTY_FUNCTION ": fcntl error on fd %d: %s",
1537 fd, strerror(errno));
1540 return(INVALID_HANDLE_VALUE);
1543 handle=_wapi_handle_new (WAPI_HANDLE_CONSOLE);
1544 if(handle==_WAPI_HANDLE_INVALID) {
1545 g_warning (G_GNUC_PRETTY_FUNCTION
1546 ": error creating file handle");
1550 _wapi_handle_lock_handle (handle);
1552 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
1553 (gpointer *)&file_handle,
1554 (gpointer *)&file_private_handle);
1556 g_warning (G_GNUC_PRETTY_FUNCTION
1557 ": error looking up console handle %p", handle);
1558 _wapi_handle_unlock_handle (handle);
1562 file_private_handle->fd=fd;
1563 file_handle->filename=_wapi_handle_scratch_store (name, strlen (name));
1564 /* some default security attributes might be needed */
1565 file_handle->security_attributes=0;
1566 file_handle->fileaccess=convert_from_flags(flags);
1567 file_handle->sharemode=0;
1568 file_handle->attrs=0;
1571 g_message(G_GNUC_PRETTY_FUNCTION ": returning handle %p with fd %d",
1572 handle, file_private_handle->fd);
1575 _wapi_handle_unlock_handle (handle);
1582 * @handle: The file handle to read from. The handle must have
1583 * %GENERIC_READ access.
1584 * @buffer: The buffer to store read data in
1585 * @numbytes: The maximum number of bytes to read
1586 * @bytesread: The actual number of bytes read is stored here. This
1587 * value can be zero if the handle is positioned at the end of the
1589 * @overlapped: points to a required %WapiOverlapped structure if
1590 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1593 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1594 * function reads up to @numbytes bytes from the file from the current
1595 * file position, and stores them in @buffer. If there are not enough
1596 * bytes left in the file, just the amount available will be read.
1597 * The actual number of bytes read is stored in @bytesread.
1599 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1600 * file position is ignored and the read position is taken from data
1601 * in the @overlapped structure.
1603 * Return value: %TRUE if the read succeeds (even if no bytes were
1604 * read due to an attempt to read past the end of the file), %FALSE on
1607 gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
1608 guint32 *bytesread, WapiOverlapped *overlapped)
1610 WapiHandleType type=_wapi_handle_type (handle);
1612 if(io_ops[type].readfile==NULL) {
1616 return(io_ops[type].readfile (handle, buffer, numbytes, bytesread,
1622 * @handle: The file handle to write to. The handle must have
1623 * %GENERIC_WRITE access.
1624 * @buffer: The buffer to read data from.
1625 * @numbytes: The maximum number of bytes to write.
1626 * @byteswritten: The actual number of bytes written is stored here.
1627 * If the handle is positioned at the file end, the length of the file
1628 * is extended. This parameter may be %NULL.
1629 * @overlapped: points to a required %WapiOverlapped structure if
1630 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
1633 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
1634 * function writes up to @numbytes bytes from @buffer to the file at
1635 * the current file position. If @handle is positioned at the end of
1636 * the file, the file is extended. The actual number of bytes written
1637 * is stored in @byteswritten.
1639 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
1640 * file position is ignored and the write position is taken from data
1641 * in the @overlapped structure.
1643 * Return value: %TRUE if the write succeeds, %FALSE on error.
1645 gboolean WriteFile(gpointer handle, gconstpointer buffer, guint32 numbytes,
1646 guint32 *byteswritten, WapiOverlapped *overlapped)
1648 WapiHandleType type=_wapi_handle_type (handle);
1650 if(io_ops[type].writefile==NULL) {
1654 return(io_ops[type].writefile (handle, buffer, numbytes, byteswritten,
1660 * @handle: Handle to open file. The handle must have
1661 * %GENERIC_WRITE access.
1663 * Flushes buffers of the file and causes all unwritten data to
1666 * Return value: %TRUE on success, %FALSE otherwise.
1668 gboolean FlushFileBuffers(gpointer handle)
1670 WapiHandleType type=_wapi_handle_type (handle);
1672 if(io_ops[type].flushfile==NULL) {
1676 return(io_ops[type].flushfile (handle));
1681 * @handle: The file handle to set. The handle must have
1682 * %GENERIC_WRITE access.
1684 * Moves the end-of-file position to the current position of the file
1685 * pointer. This function is used to truncate or extend a file.
1687 * Return value: %TRUE on success, %FALSE otherwise.
1689 gboolean SetEndOfFile(gpointer handle)
1691 WapiHandleType type=_wapi_handle_type (handle);
1693 if(io_ops[type].setendoffile==NULL) {
1697 return(io_ops[type].setendoffile (handle));
1702 * @handle: The file handle to set. The handle must have
1703 * %GENERIC_READ or %GENERIC_WRITE access.
1704 * @movedistance: Low 32 bits of a signed value that specifies the
1705 * number of bytes to move the file pointer.
1706 * @highmovedistance: Pointer to the high 32 bits of a signed value
1707 * that specifies the number of bytes to move the file pointer, or
1709 * @method: The starting point for the file pointer move.
1711 * Sets the file pointer of an open file.
1713 * The distance to move the file pointer is calculated from
1714 * @movedistance and @highmovedistance: If @highmovedistance is %NULL,
1715 * @movedistance is the 32-bit signed value; otherwise, @movedistance
1716 * is the low 32 bits and @highmovedistance a pointer to the high 32
1717 * bits of a 64 bit signed value. A positive distance moves the file
1718 * pointer forward from the position specified by @method; a negative
1719 * distance moves the file pointer backward.
1721 * If the library is compiled without large file support,
1722 * @highmovedistance is ignored and its value is set to zero on a
1723 * successful return.
1725 * Return value: On success, the low 32 bits of the new file pointer.
1726 * If @highmovedistance is not %NULL, the high 32 bits of the new file
1727 * pointer are stored there. On failure, %INVALID_SET_FILE_POINTER.
1729 guint32 SetFilePointer(gpointer handle, gint32 movedistance,
1730 gint32 *highmovedistance, WapiSeekMethod method)
1732 WapiHandleType type=_wapi_handle_type (handle);
1734 if(io_ops[type].seek==NULL) {
1738 return(io_ops[type].seek (handle, movedistance, highmovedistance,
1744 * @handle: The file handle to test.
1746 * Finds the type of file @handle.
1748 * Return value: %FILE_TYPE_UNKNOWN - the type of the file @handle is
1749 * unknown. %FILE_TYPE_DISK - @handle is a disk file.
1750 * %FILE_TYPE_CHAR - @handle is a character device, such as a console.
1751 * %FILE_TYPE_PIPE - @handle is a named or anonymous pipe.
1753 WapiFileType GetFileType(gpointer handle)
1755 WapiHandleType type=_wapi_handle_type (handle);
1757 if(io_ops[type].getfiletype==NULL) {
1761 return(io_ops[type].getfiletype ());
1766 * @handle: The file handle to query. The handle must have
1767 * %GENERIC_READ or %GENERIC_WRITE access.
1768 * @highsize: If non-%NULL, the high 32 bits of the file size are
1771 * Retrieves the size of the file @handle.
1773 * If the library is compiled without large file support, @highsize
1774 * has its value set to zero on a successful return.
1776 * Return value: On success, the low 32 bits of the file size. If
1777 * @highsize is non-%NULL then the high 32 bits of the file size are
1778 * stored here. On failure %INVALID_FILE_SIZE is returned.
1780 guint32 GetFileSize(gpointer handle, guint32 *highsize)
1782 WapiHandleType type=_wapi_handle_type (handle);
1784 if(io_ops[type].getfilesize==NULL) {
1788 return(io_ops[type].getfilesize (handle, highsize));
1793 * @handle: The file handle to query. The handle must have
1794 * %GENERIC_READ access.
1795 * @create_time: Points to a %WapiFileTime structure to receive the
1796 * number of ticks since the epoch that file was created. May be
1798 * @last_access: Points to a %WapiFileTime structure to receive the
1799 * number of ticks since the epoch when file was last accessed. May be
1801 * @last_write: Points to a %WapiFileTime structure to receive the
1802 * number of ticks since the epoch when file was last written to. May
1805 * Finds the number of ticks since the epoch that the file referenced
1806 * by @handle was created, last accessed and last modified. A tick is
1807 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
1810 * Create time isn't recorded on POSIX file systems or reported by
1811 * stat(2), so that time is guessed by returning the oldest of the
1814 * Return value: %TRUE on success, %FALSE otherwise.
1816 gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
1817 WapiFileTime *last_access, WapiFileTime *last_write)
1819 WapiHandleType type=_wapi_handle_type (handle);
1821 if(io_ops[type].getfiletime==NULL) {
1825 return(io_ops[type].getfiletime (handle, create_time, last_access,
1831 * @handle: The file handle to set. The handle must have
1832 * %GENERIC_WRITE access.
1833 * @create_time: Points to a %WapiFileTime structure that contains the
1834 * number of ticks since the epoch that the file was created. May be
1836 * @last_access: Points to a %WapiFileTime structure that contains the
1837 * number of ticks since the epoch when the file was last accessed.
1839 * @last_write: Points to a %WapiFileTime structure that contains the
1840 * number of ticks since the epoch when the file was last written to.
1843 * Sets the number of ticks since the epoch that the file referenced
1844 * by @handle was created, last accessed or last modified. A tick is
1845 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
1848 * Create time isn't recorded on POSIX file systems, and is ignored.
1850 * Return value: %TRUE on success, %FALSE otherwise.
1852 gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
1853 const WapiFileTime *last_access,
1854 const WapiFileTime *last_write)
1856 WapiHandleType type=_wapi_handle_type (handle);
1858 if(io_ops[type].setfiletime==NULL) {
1862 return(io_ops[type].setfiletime (handle, create_time, last_access,
1866 /* A tick is a 100-nanosecond interval. File time epoch is Midnight,
1867 * January 1 1601 GMT
1870 #define TICKS_PER_MILLISECOND 10000L
1871 #define TICKS_PER_SECOND 10000000L
1872 #define TICKS_PER_MINUTE 600000000L
1873 #define TICKS_PER_HOUR 36000000000L
1874 #define TICKS_PER_DAY 864000000000L
1876 #define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
1878 static const guint16 mon_yday[2][13]={
1879 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
1880 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
1884 * FileTimeToSystemTime:
1885 * @file_time: Points to a %WapiFileTime structure that contains the
1886 * number of ticks to convert.
1887 * @system_time: Points to a %WapiSystemTime structure to receive the
1890 * Converts a tick count into broken-out time values.
1892 * Return value: %TRUE on success, %FALSE otherwise.
1894 gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
1895 WapiSystemTime *system_time)
1897 gint64 file_ticks, totaldays, rem, y;
1900 if(system_time==NULL) {
1902 g_message(G_GNUC_PRETTY_FUNCTION ": system_time NULL");
1908 file_ticks=((gint64)file_time->dwHighDateTime << 32) +
1909 file_time->dwLowDateTime;
1911 /* Really compares if file_ticks>=0x8000000000000000
1912 * (LLONG_MAX+1) but we're working with a signed value for the
1913 * year and day calculation to work later
1917 g_message(G_GNUC_PRETTY_FUNCTION ": file_time too big");
1923 totaldays=(file_ticks / TICKS_PER_DAY);
1924 rem = file_ticks % TICKS_PER_DAY;
1926 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld rem: %lld",
1930 system_time->wHour=rem/TICKS_PER_HOUR;
1931 rem %= TICKS_PER_HOUR;
1933 g_message(G_GNUC_PRETTY_FUNCTION ": Hour: %d rem: %lld",
1934 system_time->wHour, rem);
1937 system_time->wMinute = rem / TICKS_PER_MINUTE;
1938 rem %= TICKS_PER_MINUTE;
1940 g_message(G_GNUC_PRETTY_FUNCTION ": Minute: %d rem: %lld",
1941 system_time->wMinute, rem);
1944 system_time->wSecond = rem / TICKS_PER_SECOND;
1945 rem %= TICKS_PER_SECOND;
1947 g_message(G_GNUC_PRETTY_FUNCTION ": Second: %d rem: %lld",
1948 system_time->wSecond, rem);
1951 system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
1953 g_message(G_GNUC_PRETTY_FUNCTION ": Milliseconds: %d",
1954 system_time->wMilliseconds);
1957 /* January 1, 1601 was a Monday, according to Emacs calendar */
1958 system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
1960 g_message(G_GNUC_PRETTY_FUNCTION ": Day of week: %d",
1961 system_time->wDayOfWeek);
1964 /* This algorithm to find year and month given days from epoch
1969 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
1970 #define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400))
1972 while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
1973 /* Guess a corrected year, assuming 365 days per year */
1974 gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
1976 g_message(G_GNUC_PRETTY_FUNCTION
1977 ": totaldays: %lld yg: %lld y: %lld", totaldays, yg,
1979 g_message(G_GNUC_PRETTY_FUNCTION
1980 ": LEAPS(yg): %lld LEAPS(y): %lld",
1981 LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
1984 /* Adjust days and y to match the guessed year. */
1985 totaldays -= ((yg - y) * 365
1986 + LEAPS_THRU_END_OF (yg - 1)
1987 - LEAPS_THRU_END_OF (y - 1));
1989 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld",
1994 g_message(G_GNUC_PRETTY_FUNCTION ": y: %lld", y);
1998 system_time->wYear = y;
2000 g_message(G_GNUC_PRETTY_FUNCTION ": Year: %d", system_time->wYear);
2003 ip = mon_yday[isleap(y)];
2005 for(y=11; totaldays < ip[y]; --y) {
2010 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld", totaldays);
2013 system_time->wMonth = y + 1;
2015 g_message(G_GNUC_PRETTY_FUNCTION ": Month: %d", system_time->wMonth);
2018 system_time->wDay = totaldays + 1;
2020 g_message(G_GNUC_PRETTY_FUNCTION ": Day: %d", system_time->wDay);
2026 gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
2028 struct _WapiHandle_find *find_handle;
2031 gchar *utf8_pattern = NULL;
2034 if (pattern == NULL) {
2036 g_message (G_GNUC_PRETTY_FUNCTION ": pattern is NULL");
2039 return INVALID_HANDLE_VALUE;
2042 utf8_pattern = _wapi_unicode_to_utf8 (pattern);
2043 if (utf8_pattern == NULL) {
2045 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2048 return INVALID_HANDLE_VALUE;
2051 handle=_wapi_handle_new (WAPI_HANDLE_FIND);
2052 if(handle==_WAPI_HANDLE_INVALID) {
2053 g_warning (G_GNUC_PRETTY_FUNCTION
2054 ": error creating find handle");
2055 return(INVALID_HANDLE_VALUE);
2058 _wapi_handle_lock_handle (handle);
2060 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2061 (gpointer *)&find_handle, NULL);
2063 g_warning (G_GNUC_PRETTY_FUNCTION
2064 ": error looking up find handle %p", handle);
2065 _wapi_handle_unlock_handle (handle);
2066 return(INVALID_HANDLE_VALUE);
2069 result = glob (utf8_pattern, 0, NULL, &find_handle->glob);
2070 g_free (utf8_pattern);
2073 globfree (&find_handle->glob);
2074 _wapi_handle_unlock_handle (handle);
2075 _wapi_handle_unref (handle);
2080 SetLastError (ERROR_NO_MORE_FILES);
2086 g_message (G_GNUC_PRETTY_FUNCTION ": glob failed with code %d.", result);
2092 return INVALID_HANDLE_VALUE;
2095 find_handle->count = 0;
2096 if (!FindNextFile (handle, find_data)) {
2098 SetLastError (ERROR_NO_MORE_FILES);
2099 return INVALID_HANDLE_VALUE;
2102 _wapi_handle_unlock_handle (handle);
2107 gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
2109 struct _WapiHandle_find *find_handle;
2112 const gchar *filename;
2114 gchar *base_filename;
2115 gunichar2 *utf16_basename;
2119 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2120 (gpointer *)&find_handle, NULL);
2122 g_warning (G_GNUC_PRETTY_FUNCTION
2123 ": error looking up find handle %p", handle);
2124 SetLastError (ERROR_INVALID_HANDLE);
2128 if (find_handle->count >= find_handle->glob.gl_pathc) {
2129 SetLastError (ERROR_NO_MORE_FILES);
2133 /* stat next glob match */
2135 filename = find_handle->glob.gl_pathv [find_handle->count ++];
2136 if (stat (filename, &buf) != 0) {
2138 g_message (G_GNUC_PRETTY_FUNCTION ": stat failed: %s", filename);
2141 SetLastError (ERROR_NO_MORE_FILES);
2145 /* fill data block */
2147 if (buf.st_mtime < buf.st_ctime)
2148 create_time = buf.st_mtime;
2150 create_time = buf.st_ctime;
2152 find_data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2154 _wapi_time_t_to_filetime (create_time, &find_data->ftCreationTime);
2155 _wapi_time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
2156 _wapi_time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime);
2158 if (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2159 find_data->nFileSizeHigh = 0;
2160 find_data->nFileSizeLow = 0;
2163 find_data->nFileSizeHigh = buf.st_size >> 32;
2164 find_data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2167 find_data->dwReserved0 = 0;
2168 find_data->dwReserved1 = 0;
2170 base_filename = g_path_get_basename (filename);
2171 utf16_basename = g_utf8_to_utf16 (base_filename, MAX_PATH, NULL, NULL, NULL);
2174 while (utf16_basename [i] != 0) { /* copy basename */
2175 find_data->cFileName [i] = utf16_basename [i];
2179 find_data->cFileName[i] = 0; /* null terminate */
2180 find_data->cAlternateFileName [0] = 0; /* not used */
2182 g_free (base_filename);
2183 g_free (utf16_basename);
2189 * @wapi_handle: the find handle to close.
2191 * Closes find handle @wapi_handle
2193 * Return value: %TRUE on success, %FALSE otherwise.
2195 gboolean FindClose (gpointer handle)
2197 struct _WapiHandle_find *find_handle;
2200 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
2201 (gpointer *)&find_handle, NULL);
2203 g_warning (G_GNUC_PRETTY_FUNCTION
2204 ": error looking up find handle %p", handle);
2205 SetLastError (ERROR_INVALID_HANDLE);
2209 globfree (&find_handle->glob);
2210 _wapi_handle_unref (handle);
2217 * @name: a pointer to a NULL-terminated unicode string, that names
2218 * the directory to be created.
2219 * @security: ignored for now
2221 * Creates directory @name
2223 * Return value: %TRUE on success, %FALSE otherwise.
2225 gboolean CreateDirectory (const gunichar2 *name, WapiSecurityAttributes *security)
2230 utf8_name = _wapi_unicode_to_utf8 (name);
2231 if (utf8_name == NULL) {
2233 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2239 result = mkdir (utf8_name, 0777);
2249 _wapi_set_last_error_from_errno ();
2258 * @name: a pointer to a NULL-terminated unicode string, that names
2259 * the directory to be removed.
2261 * Removes directory @name
2263 * Return value: %TRUE on success, %FALSE otherwise.
2265 gboolean RemoveDirectory (const gunichar2 *name)
2270 utf8_name = _wapi_unicode_to_utf8 (name);
2271 if (utf8_name == NULL) {
2273 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2279 result = rmdir (utf8_name);
2285 _wapi_set_last_error_from_errno ();
2290 * GetFileAttributes:
2291 * @name: a pointer to a NULL-terminated unicode filename.
2293 * Gets the attributes for @name;
2295 * Return value: -1 on failure
2297 guint32 GetFileAttributes (const gunichar2 *name)
2303 utf8_name = _wapi_unicode_to_utf8 (name);
2304 if (utf8_name == NULL) {
2306 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2309 SetLastError (ERROR_INVALID_PARAMETER);
2313 result = stat (utf8_name, &buf);
2317 SetLastError (ERROR_FILE_NOT_FOUND);
2321 return _wapi_stat_to_file_attributes (&buf);
2325 * GetFileAttributesEx:
2326 * @name: a pointer to a NULL-terminated unicode filename.
2327 * @level: must be GetFileExInfoStandard
2328 * @info: pointer to a WapiFileAttributesData structure
2330 * Gets attributes, size and filetimes for @name;
2332 * Return value: %TRUE on success, %FALSE on failure
2334 gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels level, gpointer info)
2337 WapiFileAttributesData *data;
2343 if (level != GetFileExInfoStandard) {
2345 g_message (G_GNUC_PRETTY_FUNCTION ": info level %d not supported.", level);
2351 utf8_name = _wapi_unicode_to_utf8 (name);
2352 if (utf8_name == NULL) {
2354 g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
2357 SetLastError (ERROR_INVALID_PARAMETER);
2361 result = stat (utf8_name, &buf);
2365 SetLastError (ERROR_FILE_NOT_FOUND);
2369 /* fill data block */
2371 data = (WapiFileAttributesData *)info;
2373 if (buf.st_mtime < buf.st_ctime)
2374 create_time = buf.st_mtime;
2376 create_time = buf.st_ctime;
2378 data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
2380 _wapi_time_t_to_filetime (create_time, &data->ftCreationTime);
2381 _wapi_time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
2382 _wapi_time_t_to_filetime (buf.st_mtime, &data->ftLastWriteTime);
2384 if (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2385 data->nFileSizeHigh = 0;
2386 data->nFileSizeLow = 0;
2389 data->nFileSizeHigh = buf.st_size >> 32;
2390 data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
2398 * @name: name of file
2399 * @attrs: attributes to set
2401 * Changes the attributes on a named file.
2403 * Return value: %TRUE on success, %FALSE on failure.
2405 extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
2407 /* FIXME: think of something clever to do on unix */
2409 SetLastError (ERROR_INVALID_FUNCTION);
2414 * GetCurrentDirectory
2415 * @length: size of the buffer
2416 * @buffer: pointer to buffer that recieves path
2418 * Retrieves the current directory for the current process.
2420 * Return value: number of characters in buffer on success, zero on failure
2422 extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer)
2425 gunichar2 *utf16_path, *ptr;
2428 path = g_get_current_dir ();
2432 /* if buffer too small, return number of characters required.
2433 * this is plain dumb.
2436 count = strlen (path) + 1;
2440 utf16_path = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
2441 if (utf16_path == NULL)
2446 *buffer ++ = *ptr ++;
2450 g_free (utf16_path);
2457 * SetCurrentDirectory
2458 * @path: path to new directory
2460 * Changes the directory path for the current process.
2462 * Return value: %TRUE on success, %FALSE on failure.
2464 extern gboolean SetCurrentDirectory (const gunichar2 *path)
2469 utf8_path = _wapi_unicode_to_utf8 (path);
2470 if (chdir (utf8_path) != 0) {
2471 _wapi_set_last_error_from_errno ();