+/*
+ * io.c: File, console and find handles
+ *
+ * Author:
+ * Dick Porter (dick@ximian.com)
+ *
+ * (C) 2002 Ximian, Inc.
+ */
+
#include <config.h>
#include <glib.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <glob.h>
+#include <stdio.h>
#include <utime.h>
-#include "mono/io-layer/wapi.h"
-#include "unicode.h"
-#include "wapi-private.h"
+#include <mono/io-layer/wapi.h>
+#include <mono/io-layer/unicode.h>
+#include <mono/io-layer/wapi-private.h>
+#include <mono/io-layer/handles-private.h>
+#include <mono/io-layer/io-private.h>
#undef DEBUG
#define ACTUALLY_DO_UNICODE
-/* Currently used for both FILE and CONSOLE handle types. This may
- * have to change in future.
- */
-struct _WapiHandle_file
-{
- WapiHandle handle;
- int fd;
- guchar *filename;
- WapiSecurityAttributes *security_attributes;
- guint32 fileaccess;
- guint32 sharemode;
- guint32 attrs;
-};
-
-static void file_close(WapiHandle *handle);
+static void file_close_shared (gpointer handle);
+static void file_close_private (gpointer handle);
static WapiFileType file_getfiletype(void);
-static gboolean file_read(WapiHandle *handle, gpointer buffer,
+static gboolean file_read(gpointer handle, gpointer buffer,
guint32 numbytes, guint32 *bytesread,
WapiOverlapped *overlapped);
-static gboolean file_write(WapiHandle *handle, gconstpointer buffer,
+static gboolean file_write(gpointer handle, gconstpointer buffer,
guint32 numbytes, guint32 *byteswritten,
WapiOverlapped *overlapped);
-static guint32 file_seek(WapiHandle *handle, gint32 movedistance,
+static gboolean file_flush(gpointer handle);
+static guint32 file_seek(gpointer handle, gint32 movedistance,
gint32 *highmovedistance, WapiSeekMethod method);
-static gboolean file_setendoffile(WapiHandle *handle);
-static guint32 file_getfilesize(WapiHandle *handle, guint32 *highsize);
-static gboolean file_getfiletime(WapiHandle *handle, WapiFileTime *create_time,
+static gboolean file_setendoffile(gpointer handle);
+static guint32 file_getfilesize(gpointer handle, guint32 *highsize);
+static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
WapiFileTime *last_access,
WapiFileTime *last_write);
-static gboolean file_setfiletime(WapiHandle *handle,
+static gboolean file_setfiletime(gpointer handle,
const WapiFileTime *create_time,
const WapiFileTime *last_access,
const WapiFileTime *last_write);
/* File handle is only signalled for overlapped IO */
-static struct _WapiHandleOps file_ops = {
- file_close, /* close */
- file_getfiletype, /* getfiletype */
- file_read, /* readfile */
- file_write, /* writefile */
- file_seek, /* seek */
- file_setendoffile, /* setendoffile */
- file_getfilesize, /* getfilesize */
- file_getfiletime, /* getfiletime */
- file_setfiletime, /* setfiletime */
- NULL, /* wait */
- NULL, /* wait_multiple */
+struct _WapiHandleOps _wapi_file_ops = {
+ file_close_shared, /* close_shared */
+ file_close_private, /* close_private */
NULL, /* signal */
+ NULL, /* own */
+ NULL, /* is_owned */
};
+static void console_close_shared (gpointer handle);
+static void console_close_private (gpointer handle);
static WapiFileType console_getfiletype(void);
+static gboolean console_read(gpointer handle, gpointer buffer,
+ guint32 numbytes, guint32 *bytesread,
+ WapiOverlapped *overlapped);
+static gboolean console_write(gpointer handle, gconstpointer buffer,
+ guint32 numbytes, guint32 *byteswritten,
+ WapiOverlapped *overlapped);
+static gboolean console_flush(gpointer handle);
/* Console is mostly the same as file, except it can block waiting for
* input or output
*/
-static struct _WapiHandleOps console_ops = {
- file_close, /* close */
- console_getfiletype, /* getfiletype */
- file_read, /* readfile */
- file_write, /* writefile */
- NULL, /* seek */
- NULL, /* setendoffile */
- NULL, /* getfilesize */
- NULL, /* getfiletime */
- NULL, /* setfiletime */
- NULL, /* FIXME: wait */
- NULL, /* FIXME: wait_multiple */
+struct _WapiHandleOps _wapi_console_ops = {
+ console_close_shared, /* close_shared */
+ console_close_private, /* close_private */
+ NULL, /* signal */
+ NULL, /* own */
+ NULL, /* is_owned */
+};
+
+/* Find handle has no ops.
+ */
+struct _WapiHandleOps _wapi_find_ops = {
+ NULL, /* close */
+ NULL, /* getfiletype */
NULL, /* signal */
+ NULL, /* own */
+ NULL, /* is_owned */
+};
+
+static struct {
+ /* File, console and pipe handles */
+ WapiFileType (*getfiletype)(void);
+
+ /* File and console handles */
+ gboolean (*readfile)(gpointer handle, gpointer buffer,
+ guint32 numbytes, guint32 *bytesread,
+ WapiOverlapped *overlapped);
+ gboolean (*writefile)(gpointer handle, gconstpointer buffer,
+ guint32 numbytes, guint32 *byteswritten,
+ WapiOverlapped *overlapped);
+ gboolean (*flushfile)(gpointer handle);
+
+ /* File handles */
+ guint32 (*seek)(gpointer handle, gint32 movedistance,
+ gint32 *highmovedistance, WapiSeekMethod method);
+ gboolean (*setendoffile)(gpointer handle);
+ guint32 (*getfilesize)(gpointer handle, guint32 *highsize);
+ gboolean (*getfiletime)(gpointer handle, WapiFileTime *create_time,
+ WapiFileTime *last_access,
+ WapiFileTime *last_write);
+ gboolean (*setfiletime)(gpointer handle,
+ const WapiFileTime *create_time,
+ const WapiFileTime *last_access,
+ const WapiFileTime *last_write);
+} io_ops[WAPI_HANDLE_COUNT]={
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* file */
+ {file_getfiletype,
+ file_read, file_write,
+ file_flush, file_seek,
+ file_setendoffile,
+ file_getfilesize,
+ file_getfiletime,
+ file_setfiletime},
+ /* console */
+ {console_getfiletype,
+ console_read,
+ console_write,
+ console_flush,
+ NULL, NULL, NULL, NULL, NULL},
+ /* thread */
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* sem */
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* mutex */
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* event */
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* socket (will need at least read and write) */
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* find */
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* process */
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
};
-static void file_close(WapiHandle *handle)
+
+static pthread_once_t io_ops_once=PTHREAD_ONCE_INIT;
+
+static void io_ops_init (void)
+{
+/* _wapi_handle_register_capabilities (WAPI_HANDLE_FILE, */
+/* WAPI_HANDLE_CAP_WAIT); */
+/* _wapi_handle_register_capabilities (WAPI_HANDLE_CONSOLE, */
+/* WAPI_HANDLE_CAP_WAIT); */
+}
+
+/* Some utility functions.
+ */
+static void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime)
+{
+ guint64 ticks;
+
+ ticks = ((guint64)timeval * 10000000) + 116444736000000000UL;
+ filetime->dwLowDateTime = ticks & 0xFFFFFFFF;
+ filetime->dwHighDateTime = ticks >> 32;
+}
+
+static guint32 _wapi_stat_to_file_attributes (struct stat *buf)
+{
+ guint32 attrs = 0;
+
+ /* FIXME: this could definitely be better */
+
+ if (S_ISDIR (buf->st_mode))
+ attrs |= FILE_ATTRIBUTE_DIRECTORY;
+ else
+ attrs |= FILE_ATTRIBUTE_ARCHIVE;
+
+ if (!(buf->st_mode & S_IWUSR))
+ attrs |= FILE_ATTRIBUTE_READONLY;
+
+ return attrs;
+}
+
+static void _wapi_set_last_error_from_errno (void)
+{
+ /* mapping ideas borrowed from wine. they may need some work */
+
+ switch (errno) {
+ case EACCES: case EPERM: case EROFS:
+ SetLastError (ERROR_ACCESS_DENIED);
+ break;
+
+ case EAGAIN:
+ SetLastError (ERROR_SHARING_VIOLATION);
+ break;
+
+ case EBUSY:
+ SetLastError (ERROR_LOCK_VIOLATION);
+ break;
+
+ case EEXIST:
+ SetLastError (ERROR_FILE_EXISTS);
+ break;
+
+ case EINVAL: case ESPIPE:
+ SetLastError (ERROR_SEEK);
+ break;
+
+ case EISDIR:
+ SetLastError (ERROR_CANNOT_MAKE);
+ break;
+
+ case ENFILE: case EMFILE:
+ SetLastError (ERROR_NO_MORE_FILES);
+ break;
+
+ case ENOENT: case ENOTDIR:
+ SetLastError (ERROR_FILE_NOT_FOUND);
+ break;
+
+ case ENOSPC:
+ SetLastError (ERROR_HANDLE_DISK_FULL);
+ break;
+
+ case ENOTEMPTY:
+ SetLastError (ERROR_DIR_NOT_EMPTY);
+ break;
+
+ case ENOEXEC:
+ SetLastError (ERROR_BAD_FORMAT);
+ break;
+
+ case ENAMETOOLONG:
+ SetLastError (ERROR_FILENAME_EXCED_RANGE);
+ break;
+
+ default:
+ g_message ("Unknown errno: %s\n", strerror (errno));
+ SetLastError (ERROR_GEN_FAILURE);
+ break;
+ }
+}
+
+/* Handle ops.
+ */
+static void file_close_shared (gpointer handle)
{
- struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
+ struct _WapiHandle_file *file_handle;
+ gboolean ok;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle, NULL);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return;
+ }
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p with fd %d",
- file_handle, file_handle->fd);
+ g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p", handle);
#endif
- close(file_handle->fd);
- if(file_handle->filename!=NULL) {
- g_free(file_handle->filename);
- file_handle->filename=NULL;
+ if(file_handle->filename!=0) {
+ _wapi_handle_scratch_delete (file_handle->filename);
+ file_handle->filename=0;
+ }
+ if(file_handle->security_attributes!=0) {
+ _wapi_handle_scratch_delete (file_handle->security_attributes);
+ file_handle->security_attributes=0;
+ }
+}
+
+static void file_close_private (gpointer handle)
+{
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_UNUSED, NULL,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return;
}
+
+#ifdef DEBUG
+ g_message(G_GNUC_PRETTY_FUNCTION ": closing file handle %p with fd %d",
+ handle, file_private_handle->fd);
+#endif
+
+ close(file_private_handle->fd);
}
static WapiFileType file_getfiletype(void)
return(FILE_TYPE_DISK);
}
-static gboolean file_read(WapiHandle *handle, gpointer buffer,
+static gboolean file_read(gpointer handle, gpointer buffer,
guint32 numbytes, guint32 *bytesread,
WapiOverlapped *overlapped G_GNUC_UNUSED)
{
- struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
+ struct _WapiHandle_file *file_handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
int ret;
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return(FALSE);
+ }
+
if(bytesread!=NULL) {
*bytesread=0;
}
if(!(file_handle->fileaccess&GENERIC_READ) &&
!(file_handle->fileaccess&GENERIC_ALL)) {
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ access: %u", handle, file_handle->fd, file_handle->fileaccess);
+ 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);
#endif
return(FALSE);
}
- ret=read(file_handle->fd, buffer, numbytes);
+ ret=read(file_private_handle->fd, buffer, numbytes);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": read of handle %p fd %d error: %s", handle,
- file_handle->fd, strerror(errno));
+ file_private_handle->fd, strerror(errno));
#endif
return(FALSE);
return(TRUE);
}
-static gboolean file_write(WapiHandle *handle, gconstpointer buffer,
+static gboolean file_write(gpointer handle, gconstpointer buffer,
guint32 numbytes, guint32 *byteswritten,
WapiOverlapped *overlapped G_GNUC_UNUSED)
{
- struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
+ struct _WapiHandle_file *file_handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
int ret;
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return(FALSE);
+ }
+
if(byteswritten!=NULL) {
*byteswritten=0;
}
if(!(file_handle->fileaccess&GENERIC_WRITE) &&
!(file_handle->fileaccess&GENERIC_ALL)) {
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_handle->fd, file_handle->fileaccess);
+ 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);
#endif
return(FALSE);
}
- ret=write(file_handle->fd, buffer, numbytes);
+ ret=write(file_private_handle->fd, buffer, numbytes);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": write of handle %p fd %d error: %s", handle,
- file_handle->fd, strerror(errno));
+ file_private_handle->fd, strerror(errno));
#endif
return(FALSE);
return(TRUE);
}
-static guint32 file_seek(WapiHandle *handle, gint32 movedistance,
+static gboolean file_flush(gpointer handle)
+{
+ struct _WapiHandle_file *file_handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
+ int ret;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return(FALSE);
+ }
+
+ if(!(file_handle->fileaccess&GENERIC_WRITE) &&
+ !(file_handle->fileaccess&GENERIC_ALL)) {
+#ifdef DEBUG
+ 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);
+#endif
+
+ return(FALSE);
+ }
+
+ ret=fsync(file_private_handle->fd);
+ if (ret==-1) {
+#ifdef DEBUG
+ g_message(G_GNUC_PRETTY_FUNCTION
+ ": write of handle %p fd %d error: %s", handle,
+ file_private_handle->fd, strerror(errno));
+#endif
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+static guint32 file_seek(gpointer handle, gint32 movedistance,
gint32 *highmovedistance, WapiSeekMethod method)
{
- struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
+ struct _WapiHandle_file *file_handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
off_t offset, newpos;
int whence;
guint32 ret;
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return(INVALID_SET_FILE_POINTER);
+ }
+
if(!(file_handle->fileaccess&GENERIC_READ) &&
!(file_handle->fileaccess&GENERIC_WRITE) &&
!(file_handle->fileaccess&GENERIC_ALL)) {
#ifdef DEBUG
- 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);
+ 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);
#endif
return(INVALID_SET_FILE_POINTER);
#ifdef HAVE_LARGE_FILE_SUPPORT
g_message(G_GNUC_PRETTY_FUNCTION
": moving handle %p fd %d by %lld bytes from %d", handle,
- file_handle->fd, offset, whence);
+ file_private_handle->fd, offset, whence);
#else
g_message(G_GNUC_PRETTY_FUNCTION
": moving handle %p fd %d by %ld bytes from %d", handle,
- file_handle->fd, offset, whence);
+ file_private_handle->fd, offset, whence);
#endif
#endif
- newpos=lseek(file_handle->fd, offset, whence);
+ newpos=lseek(file_private_handle->fd, offset, whence);
if(newpos==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": lseek on handle %p fd %d returned error %s",
- handle, file_handle->fd, strerror(errno));
+ handle, file_private_handle->fd, strerror(errno));
#endif
return(INVALID_SET_FILE_POINTER);
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": move of handle %p fd %d returning %d/%d", handle,
- file_handle->fd, ret,
+ file_private_handle->fd, ret,
highmovedistance==NULL?0:*highmovedistance);
#endif
return(ret);
}
-static gboolean file_setendoffile(WapiHandle *handle)
+static gboolean file_setendoffile(gpointer handle)
{
- struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
+ struct _WapiHandle_file *file_handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
struct stat statbuf;
off_t size, pos;
int ret;
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return(FALSE);
+ }
+
if(!(file_handle->fileaccess&GENERIC_WRITE) &&
!(file_handle->fileaccess&GENERIC_ALL)) {
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_handle->fd, file_handle->fileaccess);
+ 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);
#endif
return(FALSE);
* than the length, truncate the file.
*/
- ret=fstat(file_handle->fd, &statbuf);
+ ret=fstat(file_private_handle->fd, &statbuf);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p fd %d fstat failed: %s", handle,
- file_handle->fd, strerror(errno));
+ file_private_handle->fd, strerror(errno));
#endif
return(FALSE);
}
size=statbuf.st_size;
- pos=lseek(file_handle->fd, (off_t)0, SEEK_CUR);
+ pos=lseek(file_private_handle->fd, (off_t)0, SEEK_CUR);
if(pos==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p fd %d lseek failed: %s", handle,
- file_handle->fd, strerror(errno));
+ file_private_handle->fd, strerror(errno));
#endif
return(FALSE);
if(pos>size) {
/* extend */
- ret=write(file_handle->fd, "", 1);
+ ret=write(file_private_handle->fd, "", 1);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p fd %d extend write failed: %s",
- handle, file_handle->fd, strerror(errno));
+ handle, file_private_handle->fd,
+ strerror(errno));
#endif
return(FALSE);
/* always truncate, because the extend write() adds an extra
* byte to the end of the file
*/
- ret=ftruncate(file_handle->fd, pos);
+ ret=ftruncate(file_private_handle->fd, pos);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p fd %d ftruncate failed: %s", handle,
- file_handle->fd, strerror(errno));
+ file_private_handle->fd, strerror(errno));
#endif
return(FALSE);
return(TRUE);
}
-static guint32 file_getfilesize(WapiHandle *handle, guint32 *highsize)
+static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
{
- struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
+ struct _WapiHandle_file *file_handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
struct stat statbuf;
guint32 size;
int ret;
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return(INVALID_FILE_SIZE);
+ }
+
if(!(file_handle->fileaccess&GENERIC_READ) &&
!(file_handle->fileaccess&GENERIC_WRITE) &&
!(file_handle->fileaccess&GENERIC_ALL)) {
#ifdef DEBUG
- 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);
+ 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);
#endif
return(INVALID_FILE_SIZE);
}
- ret=fstat(file_handle->fd, &statbuf);
+ ret=fstat(file_private_handle->fd, &statbuf);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p fd %d fstat failed: %s", handle,
- file_handle->fd, strerror(errno));
+ file_private_handle->fd, strerror(errno));
#endif
return(INVALID_FILE_SIZE);
return(size);
}
-static gboolean file_getfiletime(WapiHandle *handle, WapiFileTime *create_time,
+static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
WapiFileTime *last_access,
WapiFileTime *last_write)
{
- struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
+ struct _WapiHandle_file *file_handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
struct stat statbuf;
guint64 create_ticks, access_ticks, write_ticks;
int ret;
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return(FALSE);
+ }
+
if(!(file_handle->fileaccess&GENERIC_READ) &&
!(file_handle->fileaccess&GENERIC_ALL)) {
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_READ access: %u", handle, file_handle->fd, file_handle->fileaccess);
+ 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);
#endif
return(FALSE);
}
- ret=fstat(file_handle->fd, &statbuf);
+ ret=fstat(file_private_handle->fd, &statbuf);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p fd %d fstat failed: %s", handle,
- file_handle->fd, strerror(errno));
+ file_private_handle->fd, strerror(errno));
#endif
return(FALSE);
return(TRUE);
}
-static gboolean file_setfiletime(WapiHandle *handle,
+static gboolean file_setfiletime(gpointer handle,
const WapiFileTime *create_time G_GNUC_UNUSED,
const WapiFileTime *last_access,
const WapiFileTime *last_write)
{
- struct _WapiHandle_file *file_handle=(struct _WapiHandle_file *)handle;
+ struct _WapiHandle_file *file_handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
+ guchar *name;
struct utimbuf utbuf;
struct stat statbuf;
guint64 access_ticks, write_ticks;
int ret;
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ return(FALSE);
+ }
+
if(!(file_handle->fileaccess&GENERIC_WRITE) &&
!(file_handle->fileaccess&GENERIC_ALL)) {
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": handle %p fd %d doesn't have GENERIC_WRITE access: %u", handle, file_handle->fd, file_handle->fileaccess);
+ 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);
#endif
return(FALSE);
}
- if(file_handle->filename==NULL) {
+ if(file_handle->filename==0) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p fd %d unknown filename", handle,
- file_handle->fd);
+ file_private_handle->fd);
#endif
return(FALSE);
/* Get the current times, so we can put the same times back in
* the event that one of the FileTime structs is NULL
*/
- ret=fstat(file_handle->fd, &statbuf);
+ ret=fstat(file_private_handle->fd, &statbuf);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p fd %d fstat failed: %s", handle,
- file_handle->fd, strerror(errno));
+ file_private_handle->fd, strerror(errno));
#endif
return(FALSE);
utbuf.actime, utbuf.modtime);
#endif
- ret=utime(file_handle->filename, &utbuf);
+ name=_wapi_handle_scratch_lookup_as_string (file_handle->filename);
+
+ ret=utime(name, &utbuf);
if(ret==-1) {
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
": handle %p [%s] fd %d utime failed: %s", handle,
- file_handle->filename, file_handle->fd,
- strerror(errno));
-#endif
+ name, file_private_handle->fd, strerror(errno));
+#endif
+ g_free (name);
return(FALSE);
}
+ g_free (name);
+
return(TRUE);
}
+static void console_close_shared (gpointer handle)
+{
+ struct _WapiHandle_file *console_handle;
+ gboolean ok;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
+ (gpointer *)&console_handle, NULL);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up console handle %p", handle);
+ return;
+ }
+
+#ifdef DEBUG
+ g_message(G_GNUC_PRETTY_FUNCTION ": closing console handle %p", handle);
+#endif
+
+ if(console_handle->filename!=0) {
+ _wapi_handle_scratch_delete (console_handle->filename);
+ console_handle->filename=0;
+ }
+ if(console_handle->security_attributes!=0) {
+ _wapi_handle_scratch_delete (console_handle->security_attributes);
+ console_handle->security_attributes=0;
+ }
+}
+
+static void console_close_private (gpointer handle)
+{
+ struct _WapiHandlePrivate_file *console_private_handle;
+ gboolean ok;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_UNUSED, NULL,
+ (gpointer *)&console_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up console handle %p", handle);
+ return;
+ }
+
+#ifdef DEBUG
+ g_message(G_GNUC_PRETTY_FUNCTION
+ ": closing console handle %p with fd %d", handle,
+ console_private_handle->fd);
+#endif
+
+ close(console_private_handle->fd);
+}
+
static WapiFileType console_getfiletype(void)
{
return(FILE_TYPE_CHAR);
}
+static gboolean console_read(gpointer handle, gpointer buffer,
+ guint32 numbytes, guint32 *bytesread,
+ WapiOverlapped *overlapped G_GNUC_UNUSED)
+{
+ struct _WapiHandle_file *console_handle;
+ struct _WapiHandlePrivate_file *console_private_handle;
+ gboolean ok;
+ int ret;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&console_handle,
+ (gpointer *)&console_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up console handle %p", handle);
+ return(FALSE);
+ }
+
+ if(bytesread!=NULL) {
+ *bytesread=0;
+ }
+
+ if(!(console_handle->fileaccess&GENERIC_READ) &&
+ !(console_handle->fileaccess&GENERIC_ALL)) {
+#ifdef DEBUG
+ 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);
+#endif
+
+ return(FALSE);
+ }
+
+ ret=read(console_private_handle->fd, buffer, numbytes);
+ if(ret==-1) {
+#ifdef DEBUG
+ g_message(G_GNUC_PRETTY_FUNCTION
+ ": read of handle %p fd %d error: %s", handle,
+ console_private_handle->fd, strerror(errno));
+#endif
+
+ return(FALSE);
+ }
+
+ if(bytesread!=NULL) {
+ *bytesread=ret;
+ }
+
+ return(TRUE);
+}
+
+static gboolean console_write(gpointer handle, gconstpointer buffer,
+ guint32 numbytes, guint32 *byteswritten,
+ WapiOverlapped *overlapped G_GNUC_UNUSED)
+{
+ struct _WapiHandle_file *console_handle;
+ struct _WapiHandlePrivate_file *console_private_handle;
+ gboolean ok;
+ int ret;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
+ (gpointer *)&console_handle,
+ (gpointer *)&console_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up console handle %p", handle);
+ return(FALSE);
+ }
+
+ if(byteswritten!=NULL) {
+ *byteswritten=0;
+ }
+
+ if(!(console_handle->fileaccess&GENERIC_WRITE) &&
+ !(console_handle->fileaccess&GENERIC_ALL)) {
+#ifdef DEBUG
+ 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);
+#endif
+
+ return(FALSE);
+ }
+
+ ret=write(console_private_handle->fd, buffer, numbytes);
+ if(ret==-1) {
+#ifdef DEBUG
+ g_message(G_GNUC_PRETTY_FUNCTION
+ ": write of handle %p fd %d error: %s", handle,
+ console_private_handle->fd, strerror(errno));
+#endif
+
+ return(FALSE);
+ }
+ if(byteswritten!=NULL) {
+ *byteswritten=ret;
+ }
+
+ return(TRUE);
+}
+
+static gboolean console_flush(gpointer handle)
+{
+ struct _WapiHandle_file *console_handle;
+ struct _WapiHandlePrivate_file *console_private_handle;
+ gboolean ok;
+ int ret;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
+ (gpointer *)&console_handle,
+ (gpointer *)&console_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up console handle %p", handle);
+ return(FALSE);
+ }
+
+ if(!(console_handle->fileaccess&GENERIC_WRITE) &&
+ !(console_handle->fileaccess&GENERIC_ALL)) {
+#ifdef DEBUG
+ 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);
+#endif
+
+ return(FALSE);
+ }
+
+ ret=fsync(console_private_handle->fd);
+ if (ret==-1) {
+#ifdef DEBUG
+ g_message(G_GNUC_PRETTY_FUNCTION
+ ": write of handle %p fd %d error: %s", handle,
+ console_private_handle->fd, strerror(errno));
+#endif
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
static int convert_flags(guint32 fileaccess, guint32 createmode)
{
int flags=0;
*
* Return value: the new handle, or %INVALID_HANDLE_VALUE on error.
*/
-WapiHandle *CreateFile(const guchar *name, guint32 fileaccess,
- guint32 sharemode, WapiSecurityAttributes *security,
- guint32 createmode, guint32 attrs,
- WapiHandle *template G_GNUC_UNUSED)
+gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
+ guint32 sharemode, WapiSecurityAttributes *security,
+ guint32 createmode, guint32 attrs,
+ gpointer template G_GNUC_UNUSED)
{
struct _WapiHandle_file *file_handle;
- WapiHandle *handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gpointer handle;
+ gboolean ok;
int flags=convert_flags(fileaccess, createmode);
mode_t perms=convert_perms(sharemode);
- guchar *filename;
+ gchar *filename;
int ret;
+
+ pthread_once (&io_ops_once, io_ops_init);
if(name==NULL) {
#ifdef DEBUG
if(ret==-1) {
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file: %s",
- strerror(errno));
+#ifdef ACTUALLY_DO_UNICODE
+ g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
+ filename, strerror(errno));
+#else
+ g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
+ filename, strerror(errno));
+#endif
#endif
+ _wapi_set_last_error_from_errno ();
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ handle=_wapi_handle_new (WAPI_HANDLE_FILE);
+ if(handle==_WAPI_HANDLE_INVALID) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error creating file handle");
return(INVALID_HANDLE_VALUE);
}
- file_handle=g_new0(struct _WapiHandle_file, 1);
- handle=(WapiHandle *)file_handle;
+ _wapi_handle_lock_handle (handle);
- _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_FILE, file_ops);
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up file handle %p", handle);
+ _wapi_handle_unlock_handle (handle);
+ return(INVALID_HANDLE_VALUE);
+ }
- file_handle->fd=ret;
+ file_private_handle->fd=ret;
#ifdef ACTUALLY_DO_UNICODE
- file_handle->filename=filename;
+ file_handle->filename=_wapi_handle_scratch_store (filename,
+ strlen (filename));
#else
- file_handle->filename=g_strdup(name);
+ file_handle->filename=_wapi_handle_scratch_store (name, strlen (name));
#endif
- file_handle->security_attributes=security;
- file_handle->fileaccess=fileaccess;
+ if(security!=NULL) {
+ file_handle->security_attributes=_wapi_handle_scratch_store (
+ security, sizeof(WapiSecurityAttributes));
+ }
+
+ file_handle->fileaccess=fileaccess;
file_handle->sharemode=sharemode;
file_handle->attrs=attrs;
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION
- ": returning handle %p [%s] with fd %d",
- handle, file_handle->filename, file_handle->fd);
+ ": returning handle %p with fd %d", handle,
+ file_private_handle->fd);
#endif
+ _wapi_handle_unlock_handle (handle);
+
return(handle);
}
*
* Return value: %TRUE on success, %FALSE otherwise.
*/
-gboolean DeleteFile(const guchar *name)
+gboolean DeleteFile(const gunichar2 *name)
{
- guchar *filename;
+ gchar *filename;
int ret;
if(name==NULL) {
}
}
+/**
+ * MoveFile:
+ * @name: a pointer to a NULL-terminated unicode string, that names
+ * the file to be moved.
+ * @dest_name: a pointer to a NULL-terminated unicode string, that is the
+ * new name for the file.
+ *
+ * Renames file @name to @dest_name
+ *
+ * Return value: %TRUE on success, %FALSE otherwise.
+ */
+gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
+{
+ gchar *utf8_name, *utf8_dest_name;
+ int result;
+
+ utf8_name = _wapi_unicode_to_utf8 (name);
+ if (utf8_name == NULL) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
+#endif
+
+ return FALSE;
+ }
+
+ utf8_dest_name = _wapi_unicode_to_utf8 (dest_name);
+ if (utf8_dest_name == NULL) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
+#endif
+
+ g_free (utf8_name);
+ return FALSE;
+ }
+
+ result = rename (utf8_name, utf8_dest_name);
+ g_free (utf8_name);
+ g_free (utf8_dest_name);
+
+ if (result == 0)
+ return TRUE;
+
+ switch (errno) {
+ case EEXIST:
+ SetLastError (ERROR_ALREADY_EXISTS);
+ break;
+
+ default:
+ _wapi_set_last_error_from_errno ();
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ * CopyFile:
+ * @name: a pointer to a NULL-terminated unicode string, that names
+ * the file to be copied.
+ * @dest_name: a pointer to a NULL-terminated unicode string, that is the
+ * new name for the file.
+ * @fail_if_exists: if TRUE and dest_name exists, the copy will fail.
+ *
+ * Copies file @name to @dest_name
+ *
+ * Return value: %TRUE on success, %FALSE otherwise.
+ */
+gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
+ gboolean fail_if_exists)
+{
+ gpointer src, dest;
+ guint32 attrs;
+ char *buffer;
+ int remain, n;
+
+ attrs = GetFileAttributes (name);
+ if (attrs == -1) {
+ SetLastError (ERROR_FILE_NOT_FOUND);
+ return FALSE;
+ }
+
+ src = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (src == INVALID_HANDLE_VALUE) {
+ _wapi_set_last_error_from_errno ();
+ return FALSE;
+ }
+
+ dest = CreateFile (dest_name, GENERIC_WRITE, 0, NULL,
+ fail_if_exists ? CREATE_NEW : CREATE_ALWAYS, attrs, NULL);
+ if (dest == INVALID_HANDLE_VALUE) {
+ _wapi_set_last_error_from_errno ();
+ CloseHandle (src);
+ return FALSE;
+ }
+
+ buffer = g_new (gchar, 2048);
+
+ for (;;) {
+ if (ReadFile (src, buffer,sizeof (buffer), &remain, NULL) == 0) {
+ _wapi_set_last_error_from_errno ();
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": read failed.");
+#endif
+
+ CloseHandle (dest);
+ CloseHandle (src);
+ return FALSE;
+ }
+
+ if (remain == 0)
+ break;
+
+ while (remain > 0) {
+ if (WriteFile (dest, buffer, remain, &n, NULL) == 0) {
+ _wapi_set_last_error_from_errno ();
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": write failed.");
+#endif
+
+ CloseHandle (dest);
+ CloseHandle (src);
+ return FALSE;
+ }
+
+ remain -= n;
+ }
+ }
+
+ g_free (buffer);
+
+ CloseHandle (dest);
+ CloseHandle (src);
+ return TRUE;
+}
+
/**
* GetStdHandle:
* @stdhandle: specifies the file descriptor
*
* Return value: the handle, or %INVALID_HANDLE_VALUE on error
*/
-WapiHandle *GetStdHandle(WapiStdHandle stdhandle)
+
+gpointer GetStdHandle(WapiStdHandle stdhandle)
{
struct _WapiHandle_file *file_handle;
- WapiHandle *handle;
+ struct _WapiHandlePrivate_file *file_private_handle;
+ gboolean ok;
+ gpointer handle;
+ const guchar *name;
int flags, fd;
+
+ pthread_once (&io_ops_once, io_ops_init);
switch(stdhandle) {
case STD_INPUT_HANDLE:
fd=0;
+ name="<stdin>";
break;
case STD_OUTPUT_HANDLE:
fd=1;
+ name="<stdout>";
break;
case STD_ERROR_HANDLE:
fd=2;
+ name="<stderr>";
break;
default:
return(INVALID_HANDLE_VALUE);
}
- file_handle=g_new0(struct _WapiHandle_file, 1);
- handle=(WapiHandle *)file_handle;
-
- _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_CONSOLE, console_ops);
+ handle=_wapi_handle_new (WAPI_HANDLE_CONSOLE);
+ if(handle==_WAPI_HANDLE_INVALID) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error creating file handle");
+ return(NULL);
+ }
- file_handle->fd=fd;
- /* We might want to set file_handle->filename to something
- * like "<stdin>" if we ever want to display handle internal
- * details somehow
- */
- file_handle->security_attributes=/*some default*/NULL;
+ _wapi_handle_lock_handle (handle);
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
+ (gpointer *)&file_handle,
+ (gpointer *)&file_private_handle);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up console handle %p", handle);
+ _wapi_handle_unlock_handle (handle);
+ return(NULL);
+ }
+
+ file_private_handle->fd=fd;
+ file_handle->filename=_wapi_handle_scratch_store (name, strlen (name));
+ /* some default security attributes might be needed */
+ file_handle->security_attributes=0;
file_handle->fileaccess=convert_from_flags(flags);
file_handle->sharemode=0;
file_handle->attrs=0;
#ifdef DEBUG
g_message(G_GNUC_PRETTY_FUNCTION ": returning handle %p with fd %d",
- handle, file_handle->fd);
+ handle, file_private_handle->fd);
#endif
+ _wapi_handle_unlock_handle (handle);
+
return(handle);
}
* read due to an attempt to read past the end of the file), %FALSE on
* error.
*/
-gboolean ReadFile(WapiHandle *handle, gpointer buffer, guint32 numbytes,
+gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
guint32 *bytesread, WapiOverlapped *overlapped)
{
- if(handle->ops->readfile==NULL) {
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].readfile==NULL) {
return(FALSE);
}
- return(handle->ops->readfile(handle, buffer, numbytes, bytesread,
- overlapped));
+ return(io_ops[type].readfile (handle, buffer, numbytes, bytesread,
+ overlapped));
}
/**
*
* Return value: %TRUE if the write succeeds, %FALSE on error.
*/
-gboolean WriteFile(WapiHandle *handle, gconstpointer buffer, guint32 numbytes,
+gboolean WriteFile(gpointer handle, gconstpointer buffer, guint32 numbytes,
guint32 *byteswritten, WapiOverlapped *overlapped)
{
- if(handle->ops->writefile==NULL) {
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].writefile==NULL) {
return(FALSE);
}
- return(handle->ops->writefile(handle, buffer, numbytes, byteswritten,
- overlapped));
+ return(io_ops[type].writefile (handle, buffer, numbytes, byteswritten,
+ overlapped));
+}
+
+/**
+ * FlushFileBuffers:
+ * @handle: Handle to open file. The handle must have
+ * %GENERIC_WRITE access.
+ *
+ * Flushes buffers of the file and causes all unwritten data to
+ * be written.
+ *
+ * Return value: %TRUE on success, %FALSE otherwise.
+ */
+gboolean FlushFileBuffers(gpointer handle)
+{
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].flushfile==NULL) {
+ return(FALSE);
+ }
+
+ return(io_ops[type].flushfile (handle));
}
/**
*
* Return value: %TRUE on success, %FALSE otherwise.
*/
-gboolean SetEndOfFile(WapiHandle *handle)
+gboolean SetEndOfFile(gpointer handle)
{
- if(handle->ops->setendoffile==NULL) {
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].setendoffile==NULL) {
return(FALSE);
}
- return(handle->ops->setendoffile(handle));
+ return(io_ops[type].setendoffile (handle));
}
/**
* If @highmovedistance is not %NULL, the high 32 bits of the new file
* pointer are stored there. On failure, %INVALID_SET_FILE_POINTER.
*/
-guint32 SetFilePointer(WapiHandle *handle, gint32 movedistance,
+guint32 SetFilePointer(gpointer handle, gint32 movedistance,
gint32 *highmovedistance, WapiSeekMethod method)
{
- if(handle->ops->seek==NULL) {
- return(INVALID_SET_FILE_POINTER);
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].seek==NULL) {
+ return(FALSE);
}
- return(handle->ops->seek(handle, movedistance, highmovedistance,
- method));
+ return(io_ops[type].seek (handle, movedistance, highmovedistance,
+ method));
}
/**
* %FILE_TYPE_CHAR - @handle is a character device, such as a console.
* %FILE_TYPE_PIPE - @handle is a named or anonymous pipe.
*/
-WapiFileType GetFileType(WapiHandle *handle)
+WapiFileType GetFileType(gpointer handle)
{
- if(handle->ops->getfiletype==NULL) {
- return(FILE_TYPE_UNKNOWN);
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].getfiletype==NULL) {
+ return(FALSE);
}
- return(handle->ops->getfiletype());
+ return(io_ops[type].getfiletype ());
}
/**
* @highsize is non-%NULL then the high 32 bits of the file size are
* stored here. On failure %INVALID_FILE_SIZE is returned.
*/
-guint32 GetFileSize(WapiHandle *handle, guint32 *highsize)
+guint32 GetFileSize(gpointer handle, guint32 *highsize)
{
- if(handle->ops->getfilesize==NULL) {
- return(INVALID_FILE_SIZE);
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].getfilesize==NULL) {
+ return(FALSE);
}
- return(handle->ops->getfilesize(handle, highsize));
+ return(io_ops[type].getfilesize (handle, highsize));
}
/**
*
* Return value: %TRUE on success, %FALSE otherwise.
*/
-gboolean GetFileTime(WapiHandle *handle, WapiFileTime *create_time,
+gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
WapiFileTime *last_access, WapiFileTime *last_write)
{
- if(handle->ops->getfiletime==NULL) {
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].getfiletime==NULL) {
return(FALSE);
}
- return(handle->ops->getfiletime(handle, create_time, last_access,
- last_write));
+ return(io_ops[type].getfiletime (handle, create_time, last_access,
+ last_write));
}
/**
*
* Return value: %TRUE on success, %FALSE otherwise.
*/
-gboolean SetFileTime(WapiHandle *handle, const WapiFileTime *create_time,
+gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
const WapiFileTime *last_access,
const WapiFileTime *last_write)
{
- if(handle->ops->setfiletime==NULL) {
+ WapiHandleType type=_wapi_handle_type (handle);
+
+ if(io_ops[type].setfiletime==NULL) {
return(FALSE);
}
- return(handle->ops->setfiletime(handle, create_time, last_access,
- last_write));
+ return(io_ops[type].setfiletime (handle, create_time, last_access,
+ last_write));
}
/* A tick is a 100-nanosecond interval. File time epoch is Midnight,
return(TRUE);
}
+
+gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
+{
+ struct _WapiHandle_find *find_handle;
+ gpointer handle;
+ gboolean ok;
+ gchar *utf8_pattern = NULL;
+ int result;
+
+ if (pattern == NULL) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": pattern is NULL");
+#endif
+
+ return INVALID_HANDLE_VALUE;
+ }
+
+ utf8_pattern = _wapi_unicode_to_utf8 (pattern);
+ if (utf8_pattern == NULL) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
+#endif
+
+ return INVALID_HANDLE_VALUE;
+ }
+
+ handle=_wapi_handle_new (WAPI_HANDLE_FIND);
+ if(handle==_WAPI_HANDLE_INVALID) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error creating find handle");
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ _wapi_handle_lock_handle (handle);
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
+ (gpointer *)&find_handle, NULL);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up find handle %p", handle);
+ _wapi_handle_unlock_handle (handle);
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ result = glob (utf8_pattern, 0, NULL, &find_handle->glob);
+ g_free (utf8_pattern);
+
+ if (result != 0) {
+ globfree (&find_handle->glob);
+ _wapi_handle_unlock_handle (handle);
+ _wapi_handle_unref (handle);
+
+ switch (result) {
+#ifdef GLOB_NOMATCH
+ case GLOB_NOMATCH:
+ SetLastError (ERROR_NO_MORE_FILES);
+ break;
+#endif
+
+ default:
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": glob failed with code %d.", result);
+#endif
+
+ break;
+ }
+
+ return INVALID_HANDLE_VALUE;
+ }
+
+ find_handle->count = 0;
+ if (!FindNextFile (handle, find_data)) {
+ FindClose (handle);
+ SetLastError (ERROR_NO_MORE_FILES);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ _wapi_handle_unlock_handle (handle);
+
+ return (handle);
+}
+
+gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
+{
+ struct _WapiHandle_find *find_handle;
+ gboolean ok;
+ struct stat buf;
+ const gchar *filename;
+
+ gchar *base_filename;
+ gunichar2 *utf16_basename;
+ time_t create_time;
+ int i;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
+ (gpointer *)&find_handle, NULL);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up find handle %p", handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ if (find_handle->count >= find_handle->glob.gl_pathc) {
+ SetLastError (ERROR_NO_MORE_FILES);
+ return FALSE;
+ }
+
+ /* stat next glob match */
+
+ filename = find_handle->glob.gl_pathv [find_handle->count ++];
+ if (stat (filename, &buf) != 0) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": stat failed: %s", filename);
+#endif
+
+ SetLastError (ERROR_NO_MORE_FILES);
+ return FALSE;
+ }
+
+ /* fill data block */
+
+ if (buf.st_mtime < buf.st_ctime)
+ create_time = buf.st_mtime;
+ else
+ create_time = buf.st_ctime;
+
+ find_data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
+
+ _wapi_time_t_to_filetime (create_time, &find_data->ftCreationTime);
+ _wapi_time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
+ _wapi_time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime);
+
+ if (find_data->dwFileAttributes && FILE_ATTRIBUTE_DIRECTORY) {
+ find_data->nFileSizeHigh = 0;
+ find_data->nFileSizeLow = 0;
+ }
+ else {
+ find_data->nFileSizeHigh = buf.st_size >> 32;
+ find_data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
+ }
+
+ find_data->dwReserved0 = 0;
+ find_data->dwReserved1 = 0;
+
+ base_filename = g_path_get_basename (filename);
+ utf16_basename = g_utf8_to_utf16 (base_filename, MAX_PATH, NULL, NULL, NULL);
+
+ i = 0;
+ while (utf16_basename [i] != 0) { /* copy basename */
+ find_data->cFileName [i] = utf16_basename [i];
+ ++ i;
+ }
+
+ find_data->cFileName[i] = 0; /* null terminate */
+ find_data->cAlternateFileName [0] = 0; /* not used */
+
+ g_free (base_filename);
+ g_free (utf16_basename);
+ return TRUE;
+}
+
+/**
+ * FindClose:
+ * @wapi_handle: the find handle to close.
+ *
+ * Closes find handle @wapi_handle
+ *
+ * Return value: %TRUE on success, %FALSE otherwise.
+ */
+gboolean FindClose (gpointer handle)
+{
+ struct _WapiHandle_find *find_handle;
+ gboolean ok;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
+ (gpointer *)&find_handle, NULL);
+ if(ok==FALSE) {
+ g_warning (G_GNUC_PRETTY_FUNCTION
+ ": error looking up find handle %p", handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ globfree (&find_handle->glob);
+ _wapi_handle_unref (handle);
+
+ return TRUE;
+}
+
+/**
+ * CreateDirectory:
+ * @name: a pointer to a NULL-terminated unicode string, that names
+ * the directory to be created.
+ * @security: ignored for now
+ *
+ * Creates directory @name
+ *
+ * Return value: %TRUE on success, %FALSE otherwise.
+ */
+gboolean CreateDirectory (const gunichar2 *name, WapiSecurityAttributes *security)
+{
+ gchar *utf8_name;
+ int result;
+
+ utf8_name = _wapi_unicode_to_utf8 (name);
+ if (utf8_name == NULL) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
+#endif
+
+ return FALSE;
+ }
+
+ result = mkdir (utf8_name, 0777);
+ g_free (utf8_name);
+
+ if (result == 0)
+ return TRUE;
+
+ switch (errno) {
+ case EEXIST:
+ return TRUE;
+ default:
+ _wapi_set_last_error_from_errno ();
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ * RemoveDirectory:
+ * @name: a pointer to a NULL-terminated unicode string, that names
+ * the directory to be removed.
+ *
+ * Removes directory @name
+ *
+ * Return value: %TRUE on success, %FALSE otherwise.
+ */
+gboolean RemoveDirectory (const gunichar2 *name)
+{
+ gchar *utf8_name;
+ int result;
+
+ utf8_name = _wapi_unicode_to_utf8 (name);
+ if (utf8_name == NULL) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
+#endif
+
+ return FALSE;
+ }
+
+ result = rmdir (utf8_name);
+ g_free (utf8_name);
+
+ if (result == 0)
+ return TRUE;
+
+ _wapi_set_last_error_from_errno ();
+ return FALSE;
+}
+
+/**
+ * GetFileAttributes:
+ * @name: a pointer to a NULL-terminated unicode filename.
+ *
+ * Gets the attributes for @name;
+ *
+ * Return value: -1 on failure
+ */
+guint32 GetFileAttributes (const gunichar2 *name)
+{
+ gchar *utf8_name;
+ struct stat buf;
+ int result;
+
+ utf8_name = _wapi_unicode_to_utf8 (name);
+ if (utf8_name == NULL) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
+#endif
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return -1;
+ }
+
+ result = stat (utf8_name, &buf);
+ g_free (utf8_name);
+
+ if (result != 0) {
+ SetLastError (ERROR_FILE_NOT_FOUND);
+ return -1;
+ }
+
+ return _wapi_stat_to_file_attributes (&buf);
+}
+
+/**
+ * GetFileAttributesEx:
+ * @name: a pointer to a NULL-terminated unicode filename.
+ * @level: must be GetFileExInfoStandard
+ * @info: pointer to a WapiFileAttributesData structure
+ *
+ * Gets attributes, size and filetimes for @name;
+ *
+ * Return value: %TRUE on success, %FALSE on failure
+ */
+gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels level, gpointer info)
+{
+ gchar *utf8_name;
+ WapiFileAttributesData *data;
+
+ struct stat buf;
+ time_t create_time;
+ int result;
+
+ if (level != GetFileExInfoStandard) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": info level %d not supported.", level);
+#endif
+
+ return FALSE;
+ }
+
+ utf8_name = _wapi_unicode_to_utf8 (name);
+ if (utf8_name == NULL) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION ": unicode conversion returned NULL");
+#endif
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ result = stat (utf8_name, &buf);
+ g_free (utf8_name);
+
+ if (result != 0) {
+ SetLastError (ERROR_FILE_NOT_FOUND);
+ return FALSE;
+ }
+
+ /* fill data block */
+
+ data = (WapiFileAttributesData *)info;
+
+ if (buf.st_mtime < buf.st_ctime)
+ create_time = buf.st_mtime;
+ else
+ create_time = buf.st_ctime;
+
+ data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
+
+ _wapi_time_t_to_filetime (create_time, &data->ftCreationTime);
+ _wapi_time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
+ _wapi_time_t_to_filetime (buf.st_mtime, &data->ftLastWriteTime);
+
+ if (data->dwFileAttributes && FILE_ATTRIBUTE_DIRECTORY) {
+ data->nFileSizeHigh = 0;
+ data->nFileSizeLow = 0;
+ }
+ else {
+ data->nFileSizeHigh = buf.st_size >> 32;
+ data->nFileSizeLow = buf.st_size & 0xFFFFFFFF;
+ }
+
+ return TRUE;
+}
+
+/**
+ * SetFileAttributes
+ * @name: name of file
+ * @attrs: attributes to set
+ *
+ * Changes the attributes on a named file.
+ *
+ * Return value: %TRUE on success, %FALSE on failure.
+ */
+extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
+{
+ /* FIXME: think of something clever to do on unix */
+
+ SetLastError (ERROR_INVALID_FUNCTION);
+ return FALSE;
+}
+
+/**
+ * GetCurrentDirectory
+ * @length: size of the buffer
+ * @buffer: pointer to buffer that recieves path
+ *
+ * Retrieves the current directory for the current process.
+ *
+ * Return value: number of characters in buffer on success, zero on failure
+ */
+extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer)
+{
+ gchar *path;
+ gunichar2 *utf16_path, *ptr;
+ glong count = 0;
+
+ path = g_get_current_dir ();
+ if (path == NULL)
+ return 0;
+
+ /* if buffer too small, return number of characters required.
+ * this is plain dumb.
+ */
+
+ count = strlen (path) + 1;
+ if (count > length)
+ return count;
+
+ utf16_path = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
+ if (utf16_path == NULL)
+ return 0;
+
+ ptr = utf16_path;
+ while (*ptr)
+ *buffer ++ = *ptr ++;
+
+ *buffer = 0;
+
+ g_free (utf16_path);
+ g_free (path);
+
+ return count;
+}
+
+/**
+ * SetCurrentDirectory
+ * @path: path to new directory
+ *
+ * Changes the directory path for the current process.
+ *
+ * Return value: %TRUE on success, %FALSE on failure.
+ */
+extern gboolean SetCurrentDirectory (const gunichar2 *path)
+{
+ gchar *utf8_path;
+ gboolean result;
+
+ utf8_path = _wapi_unicode_to_utf8 (path);
+ if (chdir (utf8_path) != 0) {
+ _wapi_set_last_error_from_errno ();
+ result = FALSE;
+ }
+ else
+ result = TRUE;
+
+ g_free (utf8_path);
+ return result;
+}