12 #include "mono/io-layer/wapi.h"
14 #include "wapi-private.h"
17 #define ACTUALLY_DO_UNICODE
19 /* Currently used for both FILE and CONSOLE handle types. This may
20 * have to change in future.
22 struct _WapiHandle_file
27 WapiSecurityAttributes *security_attributes;
33 static void file_close(WapiHandle *handle);
34 static WapiFileType file_getfiletype(void);
35 static gboolean file_read(WapiHandle *handle, gpointer buffer,
36 guint32 numbytes, guint32 *bytesread,
37 WapiOverlapped *overlapped);
38 static gboolean file_write(WapiHandle *handle, gconstpointer buffer,
39 guint32 numbytes, guint32 *byteswritten,
40 WapiOverlapped *overlapped);
41 static guint32 file_seek(WapiHandle *handle, gint32 movedistance,
42 gint32 *highmovedistance, WapiSeekMethod method);
43 static gboolean file_setendoffile(WapiHandle *handle);
44 static guint32 file_getfilesize(WapiHandle *handle, guint32 *highsize);
45 static gboolean file_getfiletime(WapiHandle *handle, WapiFileTime *create_time,
46 WapiFileTime *last_access,
47 WapiFileTime *last_write);
48 static gboolean file_setfiletime(WapiHandle *handle,
49 const WapiFileTime *create_time,
50 const WapiFileTime *last_access,
51 const WapiFileTime *last_write);
53 /* File handle is only signalled for overlapped IO */
54 static struct _WapiHandleOps file_ops = {
55 file_close, /* close */
56 file_getfiletype, /* getfiletype */
57 file_read, /* readfile */
58 file_write, /* writefile */
60 file_setendoffile, /* setendoffile */
61 file_getfilesize, /* getfilesize */
62 file_getfiletime, /* getfiletime */
63 file_setfiletime, /* setfiletime */
65 NULL, /* wait_multiple */
69 static WapiFileType console_getfiletype(void);
71 /* Console is mostly the same as file, except it can block waiting for
74 static struct _WapiHandleOps console_ops = {
75 file_close, /* close */
76 console_getfiletype, /* getfiletype */
77 file_read, /* readfile */
78 file_write, /* writefile */
80 NULL, /* setendoffile */
81 NULL, /* getfilesize */
82 NULL, /* getfiletime */
83 NULL, /* setfiletime */
84 NULL, /* FIXME: wait */
85 NULL, /* FIXME: wait_multiple */
89 static void file_close(WapiHandle *handle)
91 struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
94 g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p with fd %d",
95 file_handle, file_handle->fd);
98 close(file_handle->fd);
99 if(file_handle->filename!=NULL) {
100 g_free(file_handle->filename);
101 file_handle->filename=NULL;
105 static WapiFileType file_getfiletype(void)
107 return(FILE_TYPE_DISK);
110 static gboolean file_read(WapiHandle *handle, gpointer buffer,
111 guint32 numbytes, guint32 *bytesread,
112 WapiOverlapped *overlapped G_GNUC_UNUSED)
114 struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
117 if(bytesread!=NULL) {
121 if(!(file_handle->fileaccess&GENERIC_READ) &&
122 !(file_handle->fileaccess&GENERIC_ALL)) {
124 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ access: %u", handle, file_handle->fd, file_handle->fileaccess);
130 ret=read(file_handle->fd, buffer, numbytes);
133 g_message(G_GNUC_PRETTY_FUNCTION
134 ": read of handle %p fd %d error: %s", handle,
135 file_handle->fd, strerror(errno));
141 if(bytesread!=NULL) {
148 static gboolean file_write(WapiHandle *handle, gconstpointer buffer,
149 guint32 numbytes, guint32 *byteswritten,
150 WapiOverlapped *overlapped G_GNUC_UNUSED)
152 struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
155 if(byteswritten!=NULL) {
159 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
160 !(file_handle->fileaccess&GENERIC_ALL)) {
162 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_handle->fd, file_handle->fileaccess);
168 ret=write(file_handle->fd, buffer, numbytes);
171 g_message(G_GNUC_PRETTY_FUNCTION
172 ": write of handle %p fd %d error: %s", handle,
173 file_handle->fd, strerror(errno));
178 if(byteswritten!=NULL) {
185 static guint32 file_seek(WapiHandle *handle, gint32 movedistance,
186 gint32 *highmovedistance, WapiSeekMethod method)
188 struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
189 off_t offset, newpos;
193 if(!(file_handle->fileaccess&GENERIC_READ) &&
194 !(file_handle->fileaccess&GENERIC_WRITE) &&
195 !(file_handle->fileaccess&GENERIC_ALL)) {
197 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", handle, file_handle->fd, file_handle->fileaccess);
200 return(INVALID_SET_FILE_POINTER);
215 g_message(G_GNUC_PRETTY_FUNCTION ": invalid seek type %d",
219 return(INVALID_SET_FILE_POINTER);
222 #ifdef HAVE_LARGE_FILE_SUPPORT
223 if(highmovedistance==NULL) {
226 g_message(G_GNUC_PRETTY_FUNCTION
227 ": setting offset to %lld (low %d)", offset,
231 offset=((gint64) *highmovedistance << 32) | movedistance;
234 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);
242 #ifdef HAVE_LARGE_FILE_SUPPORT
243 g_message(G_GNUC_PRETTY_FUNCTION
244 ": moving handle %p fd %d by %lld bytes from %d", handle,
245 file_handle->fd, offset, whence);
247 g_message(G_GNUC_PRETTY_FUNCTION
248 ": moving handle %p fd %d by %ld bytes from %d", handle,
249 file_handle->fd, offset, whence);
253 newpos=lseek(file_handle->fd, offset, whence);
256 g_message(G_GNUC_PRETTY_FUNCTION
257 ": lseek on handle %p fd %d returned error %s",
258 handle, file_handle->fd, strerror(errno));
261 return(INVALID_SET_FILE_POINTER);
265 #ifdef HAVE_LARGE_FILE_SUPPORT
266 g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %lld", newpos);
268 g_message(G_GNUC_PRETTY_FUNCTION ": lseek returns %ld", newpos);
272 #ifdef HAVE_LARGE_FILE_SUPPORT
273 ret=newpos & 0xFFFFFFFF;
274 if(highmovedistance!=NULL) {
275 *highmovedistance=newpos>>32;
279 if(highmovedistance!=NULL) {
280 /* Accurate, but potentially dodgy :-) */
286 g_message(G_GNUC_PRETTY_FUNCTION
287 ": move of handle %p fd %d returning %d/%d", handle,
288 file_handle->fd, ret,
289 highmovedistance==NULL?0:*highmovedistance);
295 static gboolean file_setendoffile(WapiHandle *handle)
297 struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
302 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
303 !(file_handle->fileaccess&GENERIC_ALL)) {
305 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_handle->fd, file_handle->fileaccess);
311 /* Find the current file position, and the file length. If
312 * the file position is greater than the length, write to
313 * extend the file with a hole. If the file position is less
314 * than the length, truncate the file.
317 ret=fstat(file_handle->fd, &statbuf);
320 g_message(G_GNUC_PRETTY_FUNCTION
321 ": handle %p fd %d fstat failed: %s", handle,
322 file_handle->fd, strerror(errno));
327 size=statbuf.st_size;
329 pos=lseek(file_handle->fd, (off_t)0, SEEK_CUR);
332 g_message(G_GNUC_PRETTY_FUNCTION
333 ": handle %p fd %d lseek failed: %s", handle,
334 file_handle->fd, strerror(errno));
342 ret=write(file_handle->fd, "", 1);
345 g_message(G_GNUC_PRETTY_FUNCTION
346 ": handle %p fd %d extend write failed: %s",
347 handle, file_handle->fd, strerror(errno));
354 /* always truncate, because the extend write() adds an extra
355 * byte to the end of the file
357 ret=ftruncate(file_handle->fd, pos);
360 g_message(G_GNUC_PRETTY_FUNCTION
361 ": handle %p fd %d ftruncate failed: %s", handle,
362 file_handle->fd, strerror(errno));
371 static guint32 file_getfilesize(WapiHandle *handle, guint32 *highsize)
373 struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
378 if(!(file_handle->fileaccess&GENERIC_READ) &&
379 !(file_handle->fileaccess&GENERIC_WRITE) &&
380 !(file_handle->fileaccess&GENERIC_ALL)) {
382 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", handle, file_handle->fd, file_handle->fileaccess);
385 return(INVALID_FILE_SIZE);
388 ret=fstat(file_handle->fd, &statbuf);
391 g_message(G_GNUC_PRETTY_FUNCTION
392 ": handle %p fd %d fstat failed: %s", handle,
393 file_handle->fd, strerror(errno));
396 return(INVALID_FILE_SIZE);
399 #ifdef HAVE_LARGE_FILE_SUPPORT
400 size=statbuf.st_size & 0xFFFFFFFF;
402 *highsize=statbuf.st_size>>32;
406 /* Accurate, but potentially dodgy :-) */
409 size=statbuf.st_size;
413 g_message(G_GNUC_PRETTY_FUNCTION ": Returning size %d/%d", size,
420 static gboolean file_getfiletime(WapiHandle *handle, WapiFileTime *create_time,
421 WapiFileTime *last_access,
422 WapiFileTime *last_write)
424 struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
426 guint64 create_ticks, access_ticks, write_ticks;
429 if(!(file_handle->fileaccess&GENERIC_READ) &&
430 !(file_handle->fileaccess&GENERIC_ALL)) {
432 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ access: %u", handle, file_handle->fd, file_handle->fileaccess);
438 ret=fstat(file_handle->fd, &statbuf);
441 g_message(G_GNUC_PRETTY_FUNCTION
442 ": handle %p fd %d fstat failed: %s", handle,
443 file_handle->fd, strerror(errno));
450 g_message(G_GNUC_PRETTY_FUNCTION
451 ": atime: %ld ctime: %ld mtime: %ld",
452 statbuf.st_atime, statbuf.st_ctime,
456 /* Try and guess a meaningful create time by using the older
459 /* The magic constant comes from msdn documentation
460 * "Converting a time_t Value to a File Time"
462 if(statbuf.st_atime < statbuf.st_ctime) {
463 create_ticks=((guint64)statbuf.st_atime*10000000)
464 + 116444736000000000UL;
466 create_ticks=((guint64)statbuf.st_ctime*10000000)
467 + 116444736000000000UL;
470 access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000UL;
471 write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000UL;
474 g_message(G_GNUC_PRETTY_FUNCTION
475 ": aticks: %llu cticks: %llu wticks: %llu",
476 access_ticks, create_ticks, write_ticks);
479 if(create_time!=NULL) {
480 create_time->dwLowDateTime = create_ticks & 0xFFFFFFFF;
481 create_time->dwHighDateTime = create_ticks >> 32;
484 if(last_access!=NULL) {
485 last_access->dwLowDateTime = access_ticks & 0xFFFFFFFF;
486 last_access->dwHighDateTime = access_ticks >> 32;
489 if(last_write!=NULL) {
490 last_write->dwLowDateTime = write_ticks & 0xFFFFFFFF;
491 last_write->dwHighDateTime = write_ticks >> 32;
497 static gboolean file_setfiletime(WapiHandle *handle,
498 const WapiFileTime *create_time G_GNUC_UNUSED,
499 const WapiFileTime *last_access,
500 const WapiFileTime *last_write)
502 struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
503 struct utimbuf utbuf;
505 guint64 access_ticks, write_ticks;
508 if(!(file_handle->fileaccess&GENERIC_WRITE) &&
509 !(file_handle->fileaccess&GENERIC_ALL)) {
511 g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_handle->fd, file_handle->fileaccess);
517 if(file_handle->filename==NULL) {
519 g_message(G_GNUC_PRETTY_FUNCTION
520 ": handle %p fd %d unknown filename", handle,
527 /* Get the current times, so we can put the same times back in
528 * the event that one of the FileTime structs is NULL
530 ret=fstat(file_handle->fd, &statbuf);
533 g_message(G_GNUC_PRETTY_FUNCTION
534 ": handle %p fd %d fstat failed: %s", handle,
535 file_handle->fd, strerror(errno));
541 if(last_access!=NULL) {
542 access_ticks=((guint64)last_access->dwHighDateTime << 32) +
543 last_access->dwLowDateTime;
544 utbuf.actime=(access_ticks - 116444736000000000) / 10000000;
546 utbuf.actime=statbuf.st_atime;
549 if(last_write!=NULL) {
550 write_ticks=((guint64)last_write->dwHighDateTime << 32) +
551 last_write->dwLowDateTime;
552 utbuf.modtime=(write_ticks - 116444736000000000) / 10000000;
554 utbuf.modtime=statbuf.st_mtime;
558 g_message(G_GNUC_PRETTY_FUNCTION
559 ": setting handle %p access %ld write %ld", handle,
560 utbuf.actime, utbuf.modtime);
563 ret=utime(file_handle->filename, &utbuf);
566 g_message(G_GNUC_PRETTY_FUNCTION
567 ": handle %p [%s] fd %d utime failed: %s", handle,
568 file_handle->filename, file_handle->fd,
578 static WapiFileType console_getfiletype(void)
580 return(FILE_TYPE_CHAR);
583 static int convert_flags(guint32 fileaccess, guint32 createmode)
594 case GENERIC_READ|GENERIC_WRITE:
599 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown access type 0x%x",
607 flags|=O_CREAT|O_EXCL;
610 flags|=O_CREAT|O_TRUNC;
617 case TRUNCATE_EXISTING:
622 g_message(G_GNUC_PRETTY_FUNCTION ": Unknown create mode 0x%x",
631 static guint32 convert_from_flags(int flags)
633 guint32 fileaccess=0;
636 fileaccess=GENERIC_READ;
637 } else if (flags&O_WRONLY) {
638 fileaccess=GENERIC_WRITE;
639 } else if (flags&O_RDWR) {
640 fileaccess=GENERIC_READ|GENERIC_WRITE;
643 g_message(G_GNUC_PRETTY_FUNCTION
644 ": Can't figure out flags 0x%x", flags);
648 /* Maybe sort out create mode too */
653 static mode_t convert_perms(guint32 sharemode)
657 if(sharemode&FILE_SHARE_READ) {
660 if(sharemode&FILE_SHARE_WRITE) {
670 * @name: a pointer to a NULL-terminated unicode string, that names
671 * the file or other object to create.
672 * @fileaccess: specifies the file access mode
673 * @sharemode: whether the file should be shared. This parameter is
675 * @security: Ignored for now.
676 * @createmode: specifies whether to create a new file, whether to
677 * overwrite an existing file, whether to truncate the file, etc.
678 * @attrs: specifies file attributes and flags. On win32 attributes
679 * are characteristics of the file, not the handle, and are ignored
680 * when an existing file is opened. Flags give the library hints on
681 * how to process a file to optimise performance.
682 * @template: the handle of an open %GENERIC_READ file that specifies
683 * attributes to apply to a newly created file, ignoring @attrs.
684 * Normally this parameter is NULL. This parameter is ignored when an
685 * existing file is opened.
687 * Creates a new file handle. This only applies to normal files:
688 * pipes are handled by CreatePipe(), and console handles are created
689 * with GetStdHandle().
691 * Return value: the new handle, or %INVALID_HANDLE_VALUE on error.
693 WapiHandle *CreateFile(const guchar *name, guint32 fileaccess,
694 guint32 sharemode, WapiSecurityAttributes *security,
695 guint32 createmode, guint32 attrs,
696 WapiHandle *template G_GNUC_UNUSED)
698 struct _WapiHandle_file *file_handle;
700 int flags=convert_flags(fileaccess, createmode);
701 mode_t perms=convert_perms(sharemode);
707 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
710 return(INVALID_HANDLE_VALUE);
713 filename=_wapi_unicode_to_utf8(name);
714 #ifdef ACTUALLY_DO_UNICODE
717 g_message(G_GNUC_PRETTY_FUNCTION
718 ": unicode conversion returned NULL");
721 return(INVALID_HANDLE_VALUE);
725 #ifdef ACTUALLY_DO_UNICODE
726 ret=open(filename, flags, perms);
728 ret=open(name, flags, perms);
733 g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file: %s",
736 return(INVALID_HANDLE_VALUE);
739 file_handle=g_new0(struct _WapiHandle_file, 1);
740 handle=(WapiHandle *)file_handle;
742 _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_FILE, file_ops);
745 #ifdef ACTUALLY_DO_UNICODE
746 file_handle->filename=filename;
748 file_handle->filename=g_strdup(name);
750 file_handle->security_attributes=security;
751 file_handle->fileaccess=fileaccess;
752 file_handle->sharemode=sharemode;
753 file_handle->attrs=attrs;
756 g_message(G_GNUC_PRETTY_FUNCTION
757 ": returning handle %p [%s] with fd %d",
758 handle, file_handle->filename, file_handle->fd);
766 * @name: a pointer to a NULL-terminated unicode string, that names
767 * the file to be deleted.
769 * Deletes file @name.
771 * Return value: %TRUE on success, %FALSE otherwise.
773 gboolean DeleteFile(const guchar *name)
780 g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
786 filename=_wapi_unicode_to_utf8(name);
787 #ifdef ACTUALLY_DO_UNICODE
790 g_message(G_GNUC_PRETTY_FUNCTION
791 ": unicode conversion returned NULL");
798 #ifdef ACTUALLY_DO_UNICODE
799 ret=unlink(filename);
815 * @stdhandle: specifies the file descriptor
817 * Returns a handle for stdin, stdout, or stderr. Always returns the
818 * same handle for the same @stdhandle.
820 * Return value: the handle, or %INVALID_HANDLE_VALUE on error
822 WapiHandle *GetStdHandle(WapiStdHandle stdhandle)
824 struct _WapiHandle_file *file_handle;
829 case STD_INPUT_HANDLE:
833 case STD_OUTPUT_HANDLE:
837 case STD_ERROR_HANDLE:
843 g_message(G_GNUC_PRETTY_FUNCTION
844 ": unknown standard handle type");
847 return(INVALID_HANDLE_VALUE);
850 /* Check if fd is valid */
851 flags=fcntl(fd, F_GETFL);
853 /* Invalid fd. Not really much point checking for EBADF
857 g_message(G_GNUC_PRETTY_FUNCTION ": fcntl error on fd %d: %s",
858 fd, strerror(errno));
861 return(INVALID_HANDLE_VALUE);
864 file_handle=g_new0(struct _WapiHandle_file, 1);
865 handle=(WapiHandle *)file_handle;
867 _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_CONSOLE, console_ops);
870 /* We might want to set file_handle->filename to something
871 * like "<stdin>" if we ever want to display handle internal
874 file_handle->security_attributes=/*some default*/NULL;
875 file_handle->fileaccess=convert_from_flags(flags);
876 file_handle->sharemode=0;
877 file_handle->attrs=0;
880 g_message(G_GNUC_PRETTY_FUNCTION ": returning handle %p with fd %d",
881 handle, file_handle->fd);
889 * @handle: The file handle to read from. The handle must have
890 * %GENERIC_READ access.
891 * @buffer: The buffer to store read data in
892 * @numbytes: The maximum number of bytes to read
893 * @bytesread: The actual number of bytes read is stored here. This
894 * value can be zero if the handle is positioned at the end of the
896 * @overlapped: points to a required %WapiOverlapped structure if
897 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
900 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
901 * function reads up to @numbytes bytes from the file from the current
902 * file position, and stores them in @buffer. If there are not enough
903 * bytes left in the file, just the amount available will be read.
904 * The actual number of bytes read is stored in @bytesread.
906 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
907 * file position is ignored and the read position is taken from data
908 * in the @overlapped structure.
910 * Return value: %TRUE if the read succeeds (even if no bytes were
911 * read due to an attempt to read past the end of the file), %FALSE on
914 gboolean ReadFile(WapiHandle *handle, gpointer buffer, guint32 numbytes,
915 guint32 *bytesread, WapiOverlapped *overlapped)
917 if(handle->ops->readfile==NULL) {
921 return(handle->ops->readfile(handle, buffer, numbytes, bytesread,
927 * @handle: The file handle to write to. The handle must have
928 * %GENERIC_WRITE access.
929 * @buffer: The buffer to read data from.
930 * @numbytes: The maximum number of bytes to write.
931 * @byteswritten: The actual number of bytes written is stored here.
932 * If the handle is positioned at the file end, the length of the file
933 * is extended. This parameter may be %NULL.
934 * @overlapped: points to a required %WapiOverlapped structure if
935 * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
938 * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
939 * function writes up to @numbytes bytes from @buffer to the file at
940 * the current file position. If @handle is positioned at the end of
941 * the file, the file is extended. The actual number of bytes written
942 * is stored in @byteswritten.
944 * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
945 * file position is ignored and the write position is taken from data
946 * in the @overlapped structure.
948 * Return value: %TRUE if the write succeeds, %FALSE on error.
950 gboolean WriteFile(WapiHandle *handle, gconstpointer buffer, guint32 numbytes,
951 guint32 *byteswritten, WapiOverlapped *overlapped)
953 if(handle->ops->writefile==NULL) {
957 return(handle->ops->writefile(handle, buffer, numbytes, byteswritten,
963 * @handle: The file handle to set. The handle must have
964 * %GENERIC_WRITE access.
966 * Moves the end-of-file position to the current position of the file
967 * pointer. This function is used to truncate or extend a file.
969 * Return value: %TRUE on success, %FALSE otherwise.
971 gboolean SetEndOfFile(WapiHandle *handle)
973 if(handle->ops->setendoffile==NULL) {
977 return(handle->ops->setendoffile(handle));
982 * @handle: The file handle to set. The handle must have
983 * %GENERIC_READ or %GENERIC_WRITE access.
984 * @movedistance: Low 32 bits of a signed value that specifies the
985 * number of bytes to move the file pointer.
986 * @highmovedistance: Pointer to the high 32 bits of a signed value
987 * that specifies the number of bytes to move the file pointer, or
989 * @method: The starting point for the file pointer move.
991 * Sets the file pointer of an open file.
993 * The distance to move the file pointer is calculated from
994 * @movedistance and @highmovedistance: If @highmovedistance is %NULL,
995 * @movedistance is the 32-bit signed value; otherwise, @movedistance
996 * is the low 32 bits and @highmovedistance a pointer to the high 32
997 * bits of a 64 bit signed value. A positive distance moves the file
998 * pointer forward from the position specified by @method; a negative
999 * distance moves the file pointer backward.
1001 * If the library is compiled without large file support,
1002 * @highmovedistance is ignored and its value is set to zero on a
1003 * successful return.
1005 * Return value: On success, the low 32 bits of the new file pointer.
1006 * If @highmovedistance is not %NULL, the high 32 bits of the new file
1007 * pointer are stored there. On failure, %INVALID_SET_FILE_POINTER.
1009 guint32 SetFilePointer(WapiHandle *handle, gint32 movedistance,
1010 gint32 *highmovedistance, WapiSeekMethod method)
1012 if(handle->ops->seek==NULL) {
1013 return(INVALID_SET_FILE_POINTER);
1016 return(handle->ops->seek(handle, movedistance, highmovedistance,
1022 * @handle: The file handle to test.
1024 * Finds the type of file @handle.
1026 * Return value: %FILE_TYPE_UNKNOWN - the type of the file @handle is
1027 * unknown. %FILE_TYPE_DISK - @handle is a disk file.
1028 * %FILE_TYPE_CHAR - @handle is a character device, such as a console.
1029 * %FILE_TYPE_PIPE - @handle is a named or anonymous pipe.
1031 WapiFileType GetFileType(WapiHandle *handle)
1033 if(handle->ops->getfiletype==NULL) {
1034 return(FILE_TYPE_UNKNOWN);
1037 return(handle->ops->getfiletype());
1042 * @handle: The file handle to query. The handle must have
1043 * %GENERIC_READ or %GENERIC_WRITE access.
1044 * @highsize: If non-%NULL, the high 32 bits of the file size are
1047 * Retrieves the size of the file @handle.
1049 * If the library is compiled without large file support, @highsize
1050 * has its value set to zero on a successful return.
1052 * Return value: On success, the low 32 bits of the file size. If
1053 * @highsize is non-%NULL then the high 32 bits of the file size are
1054 * stored here. On failure %INVALID_FILE_SIZE is returned.
1056 guint32 GetFileSize(WapiHandle *handle, guint32 *highsize)
1058 if(handle->ops->getfilesize==NULL) {
1059 return(INVALID_FILE_SIZE);
1062 return(handle->ops->getfilesize(handle, highsize));
1067 * @handle: The file handle to query. The handle must have
1068 * %GENERIC_READ access.
1069 * @create_time: Points to a %WapiFileTime structure to receive the
1070 * number of ticks since the epoch that file was created. May be
1072 * @last_access: Points to a %WapiFileTime structure to receive the
1073 * number of ticks since the epoch when file was last accessed. May be
1075 * @last_write: Points to a %WapiFileTime structure to receive the
1076 * number of ticks since the epoch when file was last written to. May
1079 * Finds the number of ticks since the epoch that the file referenced
1080 * by @handle was created, last accessed and last modified. A tick is
1081 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
1084 * Create time isn't recorded on POSIX file systems or reported by
1085 * stat(2), so that time is guessed by returning the oldest of the
1088 * Return value: %TRUE on success, %FALSE otherwise.
1090 gboolean GetFileTime(WapiHandle *handle, WapiFileTime *create_time,
1091 WapiFileTime *last_access, WapiFileTime *last_write)
1093 if(handle->ops->getfiletime==NULL) {
1097 return(handle->ops->getfiletime(handle, create_time, last_access,
1103 * @handle: The file handle to set. The handle must have
1104 * %GENERIC_WRITE access.
1105 * @create_time: Points to a %WapiFileTime structure that contains the
1106 * number of ticks since the epoch that the file was created. May be
1108 * @last_access: Points to a %WapiFileTime structure that contains the
1109 * number of ticks since the epoch when the file was last accessed.
1111 * @last_write: Points to a %WapiFileTime structure that contains the
1112 * number of ticks since the epoch when the file was last written to.
1115 * Sets the number of ticks since the epoch that the file referenced
1116 * by @handle was created, last accessed or last modified. A tick is
1117 * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
1120 * Create time isn't recorded on POSIX file systems, and is ignored.
1122 * Return value: %TRUE on success, %FALSE otherwise.
1124 gboolean SetFileTime(WapiHandle *handle, const WapiFileTime *create_time,
1125 const WapiFileTime *last_access,
1126 const WapiFileTime *last_write)
1128 if(handle->ops->setfiletime==NULL) {
1132 return(handle->ops->setfiletime(handle, create_time, last_access,
1136 /* A tick is a 100-nanosecond interval. File time epoch is Midnight,
1137 * January 1 1601 GMT
1140 #define TICKS_PER_MILLISECOND 10000L
1141 #define TICKS_PER_SECOND 10000000L
1142 #define TICKS_PER_MINUTE 600000000L
1143 #define TICKS_PER_HOUR 36000000000L
1144 #define TICKS_PER_DAY 864000000000L
1146 #define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
1148 static const guint16 mon_yday[2][13]={
1149 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
1150 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
1154 * FileTimeToSystemTime:
1155 * @file_time: Points to a %WapiFileTime structure that contains the
1156 * number of ticks to convert.
1157 * @system_time: Points to a %WapiSystemTime structure to receive the
1160 * Converts a tick count into broken-out time values.
1162 * Return value: %TRUE on success, %FALSE otherwise.
1164 gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
1165 WapiSystemTime *system_time)
1167 gint64 file_ticks, totaldays, rem, y;
1170 if(system_time==NULL) {
1172 g_message(G_GNUC_PRETTY_FUNCTION ": system_time NULL");
1178 file_ticks=((gint64)file_time->dwHighDateTime << 32) +
1179 file_time->dwLowDateTime;
1181 /* Really compares if file_ticks>=0x8000000000000000
1182 * (LLONG_MAX+1) but we're working with a signed value for the
1183 * year and day calculation to work later
1187 g_message(G_GNUC_PRETTY_FUNCTION ": file_time too big");
1193 totaldays=(file_ticks / TICKS_PER_DAY);
1194 rem = file_ticks % TICKS_PER_DAY;
1196 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld rem: %lld",
1200 system_time->wHour=rem/TICKS_PER_HOUR;
1201 rem %= TICKS_PER_HOUR;
1203 g_message(G_GNUC_PRETTY_FUNCTION ": Hour: %d rem: %lld",
1204 system_time->wHour, rem);
1207 system_time->wMinute = rem / TICKS_PER_MINUTE;
1208 rem %= TICKS_PER_MINUTE;
1210 g_message(G_GNUC_PRETTY_FUNCTION ": Minute: %d rem: %lld",
1211 system_time->wMinute, rem);
1214 system_time->wSecond = rem / TICKS_PER_SECOND;
1215 rem %= TICKS_PER_SECOND;
1217 g_message(G_GNUC_PRETTY_FUNCTION ": Second: %d rem: %lld",
1218 system_time->wSecond, rem);
1221 system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
1223 g_message(G_GNUC_PRETTY_FUNCTION ": Milliseconds: %d",
1224 system_time->wMilliseconds);
1227 /* January 1, 1601 was a Monday, according to Emacs calendar */
1228 system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
1230 g_message(G_GNUC_PRETTY_FUNCTION ": Day of week: %d",
1231 system_time->wDayOfWeek);
1234 /* This algorithm to find year and month given days from epoch
1239 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
1240 #define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400))
1242 while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
1243 /* Guess a corrected year, assuming 365 days per year */
1244 gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
1246 g_message(G_GNUC_PRETTY_FUNCTION
1247 ": totaldays: %lld yg: %lld y: %lld", totaldays, yg,
1249 g_message(G_GNUC_PRETTY_FUNCTION
1250 ": LEAPS(yg): %lld LEAPS(y): %lld",
1251 LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
1254 /* Adjust days and y to match the guessed year. */
1255 totaldays -= ((yg - y) * 365
1256 + LEAPS_THRU_END_OF (yg - 1)
1257 - LEAPS_THRU_END_OF (y - 1));
1259 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld",
1264 g_message(G_GNUC_PRETTY_FUNCTION ": y: %lld", y);
1268 system_time->wYear = y;
1270 g_message(G_GNUC_PRETTY_FUNCTION ": Year: %d", system_time->wYear);
1273 ip = mon_yday[isleap(y)];
1275 for(y=11; totaldays < ip[y]; --y) {
1280 g_message(G_GNUC_PRETTY_FUNCTION ": totaldays: %lld", totaldays);
1283 system_time->wMonth = y + 1;
1285 g_message(G_GNUC_PRETTY_FUNCTION ": Month: %d", system_time->wMonth);
1288 system_time->wDay = totaldays + 1;
1290 g_message(G_GNUC_PRETTY_FUNCTION ": Day: %d", system_time->wDay);