// The above is an internal value used by Path.GetTempFile to
// get a file with 600 permissions, regardless of the umask
// settings. If a value "1" must be introduced here, update
- // both metadata/file-io.c and Path.GetTempFile
+ // both metadata/w32file.c and Path.GetTempFile
//
}
}
OTHER_H = \
error.h \
- io.h \
- io-trace.h \
io-layer.h \
- io-portability.h \
- uglify.h \
wapi.h \
wapi-remap.h
OTHER_SRC = \
error.c \
error.h \
- io.c \
- io.h \
- io-portability.c \
- io-portability.h \
- io-private.h \
io-layer.h \
- locking.c \
- posix.c \
- uglify.h \
- wapi_glob.h \
- wapi_glob.c \
wapi.h \
- wapi-private.h \
wapi.c
#include <errno.h>
#include "mono/io-layer/wapi.h"
-#include "mono/io-layer/wapi-private.h"
#include "mono/utils/mono-lazy-init.h"
static pthread_key_t error_key;
g_assert (ret == 0);
}
-static void error_cleanup (void)
-{
- int ret;
-
- ret = pthread_key_delete (error_key);
- g_assert (ret == 0);
-}
-
-void _wapi_error_cleanup (void)
-{
- mono_lazy_cleanup (&error_key_once, error_cleanup);
-}
-
/**
* GetLastError:
*
guint32 err;
void *errptr;
- if (_wapi_has_shut_down)
- return 0;
mono_lazy_initialize(&error_key_once, error_init);
errptr=pthread_getspecific(error_key);
err=GPOINTER_TO_UINT(errptr);
{
int ret;
- if (_wapi_has_shut_down)
- return;
/* Set the thread-local error code */
mono_lazy_initialize(&error_key_once, error_init);
ret = pthread_setspecific(error_key, GUINT_TO_POINTER(code));
guint32 GetLastError (void);
void SetLastError (guint32 code);
gint _wapi_get_win32_file_error (gint err);
-void _wapi_error_cleanup (void);
G_END_DECLS
#else /* EVERYONE ELSE */
#include "mono/io-layer/wapi.h"
-#include "mono/io-layer/uglify.h"
#endif /* HOST_WIN32 */
#ifdef __native_client__
+++ /dev/null
-/*
- * io-portability.c: Optional filename mangling to try to cope with
- * badly-written non-portable windows apps
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * Copyright (c) 2006 Novell, Inc.
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#include <config.h>
-#include <glib.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#ifdef HAVE_DIRENT_H
-# include <dirent.h>
-#endif
-#include <utime.h>
-#include <sys/stat.h>
-
-#include <mono/io-layer/error.h>
-#include <mono/io-layer/wapi_glob.h>
-#include <mono/io-layer/io-portability.h>
-#include <mono/utils/mono-io-portability.h>
-
-#undef DEBUG
-
-int _wapi_open (const char *pathname, int flags, mode_t mode)
-{
- int fd;
- gchar *located_filename;
-
- if (flags & O_CREAT) {
- located_filename = mono_portability_find_file (pathname, FALSE);
- if (located_filename == NULL) {
- fd = open (pathname, flags, mode);
- } else {
- fd = open (located_filename, flags, mode);
- g_free (located_filename);
- }
- } else {
- fd = open (pathname, flags, mode);
- if (fd == -1 &&
- (errno == ENOENT || errno == ENOTDIR) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- located_filename = mono_portability_find_file (pathname, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return (-1);
- }
-
- fd = open (located_filename, flags, mode);
- g_free (located_filename);
- }
- }
-
-
- return(fd);
-}
-
-int _wapi_access (const char *pathname, int mode)
-{
- int ret;
-
- ret = access (pathname, mode);
- if (ret == -1 &&
- (errno == ENOENT || errno == ENOTDIR) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_filename = mono_portability_find_file (pathname, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return(-1);
- }
-
- ret = access (located_filename, mode);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-int _wapi_chmod (const char *pathname, mode_t mode)
-{
- int ret;
-
- ret = chmod (pathname, mode);
- if (ret == -1 &&
- (errno == ENOENT || errno == ENOTDIR) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_filename = mono_portability_find_file (pathname, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return(-1);
- }
-
- ret = chmod (located_filename, mode);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-int _wapi_utime (const char *filename, const struct utimbuf *buf)
-{
- int ret;
-
- ret = utime (filename, buf);
- if (ret == -1 &&
- errno == ENOENT &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_filename = mono_portability_find_file (filename, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return(-1);
- }
-
- ret = utime (located_filename, buf);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-int _wapi_unlink (const char *pathname)
-{
- int ret;
-
- ret = unlink (pathname);
- if (ret == -1 &&
- (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_filename = mono_portability_find_file (pathname, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return(-1);
- }
-
- ret = unlink (located_filename);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-int _wapi_rename (const char *oldpath, const char *newpath)
-{
- int ret;
- gchar *located_newpath = mono_portability_find_file (newpath, FALSE);
-
- if (located_newpath == NULL) {
- ret = rename (oldpath, newpath);
- } else {
- ret = rename (oldpath, located_newpath);
-
- if (ret == -1 &&
- (errno == EISDIR || errno == ENAMETOOLONG ||
- errno == ENOENT || errno == ENOTDIR || errno == EXDEV) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_oldpath = mono_portability_find_file (oldpath, TRUE);
-
- if (located_oldpath == NULL) {
- g_free (located_oldpath);
- g_free (located_newpath);
-
- errno = saved_errno;
- return(-1);
- }
-
- ret = rename (located_oldpath, located_newpath);
- g_free (located_oldpath);
- }
- g_free (located_newpath);
- }
-
- return(ret);
-}
-
-int _wapi_stat (const char *path, struct stat *buf)
-{
- int ret;
-
- ret = stat (path, buf);
- if (ret == -1 &&
- (errno == ENOENT || errno == ENOTDIR) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_filename = mono_portability_find_file (path, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return(-1);
- }
-
- ret = stat (located_filename, buf);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-int _wapi_lstat (const char *path, struct stat *buf)
-{
- int ret;
-
- ret = lstat (path, buf);
- if (ret == -1 &&
- (errno == ENOENT || errno == ENOTDIR) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_filename = mono_portability_find_file (path, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return(-1);
- }
-
- ret = lstat (located_filename, buf);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-int _wapi_mkdir (const char *pathname, mode_t mode)
-{
- int ret;
- gchar *located_filename = mono_portability_find_file (pathname, FALSE);
-
- if (located_filename == NULL) {
- ret = mkdir (pathname, mode);
- } else {
- ret = mkdir (located_filename, mode);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-int _wapi_rmdir (const char *pathname)
-{
- int ret;
-
- ret = rmdir (pathname);
- if (ret == -1 &&
- (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_filename = mono_portability_find_file (pathname, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return(-1);
- }
-
- ret = rmdir (located_filename);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-int _wapi_chdir (const char *path)
-{
- int ret;
-
- ret = chdir (path);
- if (ret == -1 &&
- (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) &&
- IS_PORTABILITY_SET) {
- int saved_errno = errno;
- gchar *located_filename = mono_portability_find_file (path, TRUE);
-
- if (located_filename == NULL) {
- errno = saved_errno;
- return(-1);
- }
-
- ret = chdir (located_filename);
- g_free (located_filename);
- }
-
- return(ret);
-}
-
-gchar *_wapi_basename (const gchar *filename)
-{
- gchar *new_filename = g_strdup (filename), *ret;
-
- if (IS_PORTABILITY_SET) {
- g_strdelimit (new_filename, "\\", '/');
- }
-
- if (IS_PORTABILITY_DRIVE &&
- g_ascii_isalpha (new_filename[0]) &&
- (new_filename[1] == ':')) {
- int len = strlen (new_filename);
-
- g_memmove (new_filename, new_filename + 2, len - 2);
- new_filename[len - 2] = '\0';
- }
-
- ret = g_path_get_basename (new_filename);
- g_free (new_filename);
-
- return(ret);
-}
-
-gchar *_wapi_dirname (const gchar *filename)
-{
- gchar *new_filename = g_strdup (filename), *ret;
-
- if (IS_PORTABILITY_SET) {
- g_strdelimit (new_filename, "\\", '/');
- }
-
- if (IS_PORTABILITY_DRIVE &&
- g_ascii_isalpha (new_filename[0]) &&
- (new_filename[1] == ':')) {
- int len = strlen (new_filename);
-
- g_memmove (new_filename, new_filename + 2, len - 2);
- new_filename[len - 2] = '\0';
- }
-
- ret = g_path_get_dirname (new_filename);
- g_free (new_filename);
-
- return(ret);
-}
-
-GDir *_wapi_g_dir_open (const gchar *path, guint flags, GError **error)
-{
- GDir *ret;
-
- ret = g_dir_open (path, flags, error);
- if (ret == NULL &&
- ((*error)->code == G_FILE_ERROR_NOENT ||
- (*error)->code == G_FILE_ERROR_NOTDIR ||
- (*error)->code == G_FILE_ERROR_NAMETOOLONG) &&
- IS_PORTABILITY_SET) {
- gchar *located_filename = mono_portability_find_file (path, TRUE);
- GError *tmp_error = NULL;
-
- if (located_filename == NULL) {
- return(NULL);
- }
-
- ret = g_dir_open (located_filename, flags, &tmp_error);
- g_free (located_filename);
- if (tmp_error == NULL) {
- g_clear_error (error);
- }
- }
-
- return(ret);
-}
-
-
-static gint
-file_compare (gconstpointer a, gconstpointer b)
-{
- gchar *astr = *(gchar **) a;
- gchar *bstr = *(gchar **) b;
-
- return strcmp (astr, bstr);
-}
-
-static gint
-get_errno_from_g_file_error (gint error)
-{
- switch (error) {
-#ifdef EACCESS
- case G_FILE_ERROR_ACCES:
- error = EACCES;
- break;
-#endif
-#ifdef ENAMETOOLONG
- case G_FILE_ERROR_NAMETOOLONG:
- error = ENAMETOOLONG;
- break;
-#endif
-#ifdef ENOENT
- case G_FILE_ERROR_NOENT:
- error = ENOENT;
- break;
-#endif
-#ifdef ENOTDIR
- case G_FILE_ERROR_NOTDIR:
- error = ENOTDIR;
- break;
-#endif
-#ifdef ENXIO
- case G_FILE_ERROR_NXIO:
- error = ENXIO;
- break;
-#endif
-#ifdef ENODEV
- case G_FILE_ERROR_NODEV:
- error = ENODEV;
- break;
-#endif
-#ifdef EROFS
- case G_FILE_ERROR_ROFS:
- error = EROFS;
- break;
-#endif
-#ifdef ETXTBSY
- case G_FILE_ERROR_TXTBSY:
- error = ETXTBSY;
- break;
-#endif
-#ifdef EFAULT
- case G_FILE_ERROR_FAULT:
- error = EFAULT;
- break;
-#endif
-#ifdef ELOOP
- case G_FILE_ERROR_LOOP:
- error = ELOOP;
- break;
-#endif
-#ifdef ENOSPC
- case G_FILE_ERROR_NOSPC:
- error = ENOSPC;
- break;
-#endif
-#ifdef ENOMEM
- case G_FILE_ERROR_NOMEM:
- error = ENOMEM;
- break;
-#endif
-#ifdef EMFILE
- case G_FILE_ERROR_MFILE:
- error = EMFILE;
- break;
-#endif
-#ifdef ENFILE
- case G_FILE_ERROR_NFILE:
- error = ENFILE;
- break;
-#endif
-#ifdef EBADF
- case G_FILE_ERROR_BADF:
- error = EBADF;
- break;
-#endif
-#ifdef EINVAL
- case G_FILE_ERROR_INVAL:
- error = EINVAL;
- break;
-#endif
-#ifdef EPIPE
- case G_FILE_ERROR_PIPE:
- error = EPIPE;
- break;
-#endif
-#ifdef EAGAIN
- case G_FILE_ERROR_AGAIN:
- error = EAGAIN;
- break;
-#endif
-#ifdef EINTR
- case G_FILE_ERROR_INTR:
- error = EINTR;
- break;
-#endif
-#ifdef EWIO
- case G_FILE_ERROR_IO:
- error = EIO;
- break;
-#endif
-#ifdef EPERM
- case G_FILE_ERROR_PERM:
- error = EPERM;
- break;
-#endif
- case G_FILE_ERROR_FAILED:
- error = ERROR_INVALID_PARAMETER;
- break;
- }
-
- return error;
-}
-
-/* scandir using glib */
-gint _wapi_io_scandir (const gchar *dirname, const gchar *pattern,
- gchar ***namelist)
-{
- GError *error = NULL;
- GDir *dir;
- GPtrArray *names;
- gint result;
- wapi_glob_t glob_buf;
- int flags = 0, i;
-
- dir = _wapi_g_dir_open (dirname, 0, &error);
- if (dir == NULL) {
- /* g_dir_open returns ENOENT on directories on which we don't
- * have read/x permission */
- gint errnum = get_errno_from_g_file_error (error->code);
- g_error_free (error);
- if (errnum == ENOENT &&
- !_wapi_access (dirname, F_OK) &&
- _wapi_access (dirname, R_OK|X_OK)) {
- errnum = EACCES;
- }
-
- errno = errnum;
- return -1;
- }
-
- if (IS_PORTABILITY_CASE) {
- flags = WAPI_GLOB_IGNORECASE;
- }
-
- result = _wapi_glob (dir, pattern, flags, &glob_buf);
- if (g_str_has_suffix (pattern, ".*")) {
- /* Special-case the patterns ending in '.*', as
- * windows also matches entries with no extension with
- * this pattern.
- *
- * TODO: should this be a MONO_IOMAP option?
- */
- gchar *pattern2 = g_strndup (pattern, strlen (pattern) - 2);
- gint result2;
-
- g_dir_rewind (dir);
- result2 = _wapi_glob (dir, pattern2, flags | WAPI_GLOB_APPEND | WAPI_GLOB_UNIQUE, &glob_buf);
-
- g_free (pattern2);
-
- if (result != 0) {
- result = result2;
- }
- }
-
- g_dir_close (dir);
- if (glob_buf.gl_pathc == 0) {
- return(0);
- } else if (result != 0) {
- return(-1);
- }
-
- names = g_ptr_array_new ();
- for (i = 0; i < glob_buf.gl_pathc; i++) {
- g_ptr_array_add (names, g_strdup (glob_buf.gl_pathv[i]));
- }
-
- _wapi_globfree (&glob_buf);
-
- result = names->len;
- if (result > 0) {
- g_ptr_array_sort (names, file_compare);
- g_ptr_array_set_size (names, result + 1);
-
- *namelist = (gchar **) g_ptr_array_free (names, FALSE);
- } else {
- g_ptr_array_free (names, TRUE);
- }
-
- return result;
-}
+++ /dev/null
-/*
- * io-portability.h: Optional filename mangling to try to cope with
- * badly-written non-portable windows apps
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * Copyright (C) 2006 Novell, Inc.
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#ifndef _WAPI_IO_PORTABILITY_H_
-#define _WAPI_IO_PORTABILITY_H_
-
-#include <glib.h>
-#include <sys/types.h>
-#include <utime.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-G_BEGIN_DECLS
-
-extern int _wapi_open (const char *pathname, int flags, mode_t mode);
-extern int _wapi_access (const char *pathname, int mode);
-extern int _wapi_chmod (const char *pathname, mode_t mode);
-extern int _wapi_utime (const char *filename, const struct utimbuf *buf);
-extern int _wapi_unlink (const char *pathname);
-extern int _wapi_rename (const char *oldpath, const char *newpath);
-extern int _wapi_stat (const char *path, struct stat *buf);
-extern int _wapi_lstat (const char *path, struct stat *buf);
-extern int _wapi_mkdir (const char *pathname, mode_t mode);
-extern int _wapi_rmdir (const char *pathname);
-extern int _wapi_chdir (const char *path);
-extern gchar *_wapi_basename (const gchar *filename);
-extern gchar *_wapi_dirname (const gchar *filename);
-extern GDir *_wapi_g_dir_open (const gchar *path, guint flags, GError **error);
-extern gint _wapi_io_scandir (const gchar *dirname, const gchar *pattern,
- gchar ***namelist);
-
-G_END_DECLS
-
-#endif /* _WAPI_IO_PORTABILITY_H_ */
+++ /dev/null
-/*
- * io-private.h: Private definitions for file, console and find handles
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- * Copyright 2011 Xamarin Inc
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#ifndef _WAPI_IO_PRIVATE_H_
-#define _WAPI_IO_PRIVATE_H_
-
-#include <config.h>
-#include <glib.h>
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-
-#include <mono/io-layer/io.h>
-#include <mono/io-layer/wapi-private.h>
-
-extern gboolean _wapi_lock_file_region (int fd, off_t offset, off_t length);
-extern gboolean _wapi_unlock_file_region (int fd, off_t offset, off_t length);
-extern gpointer _wapi_stdhandle_create (int fd, const gchar *name);
-
-/* Currently used for both FILE, CONSOLE and PIPE handle types. This may
- * have to change in future.
- */
-struct _WapiHandle_file
-{
- gchar *filename;
- struct _WapiFileShare *share_info; /* Pointer into shared mem */
- int fd;
- guint32 security_attributes;
- guint32 fileaccess;
- guint32 sharemode;
- guint32 attrs;
-};
-
-struct _WapiHandle_find
-{
- gchar **namelist;
- gchar *dir_part;
- int num;
- size_t count;
-};
-
-#endif /* _WAPI_IO_PRIVATE_H_ */
+++ /dev/null
-/*
- * io-trace.h: tracing macros
- *
- * Authors:
- * Marek Habersack <grendel@twistedcode.net>
- *
- * Copyright 2016 Xamarin, Inc (http://xamarin.com/)
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#ifndef __IO_TRACE_H
-
-#ifdef DISABLE_IO_LAYER_TRACE
-#define MONO_TRACE(...)
-#else
-#include "mono/utils/mono-logger-internals.h"
-#define MONO_TRACE(...) mono_trace (__VA_ARGS__)
-#endif
-
-#endif
+++ /dev/null
-/*
- * io.c: File, console and find handles
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- * Copyright (c) 2002-2006 Novell, Inc.
- * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#include <config.h>
-#include <glib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#ifdef HAVE_SYS_STATVFS_H
-#include <sys/statvfs.h>
-#endif
-#if defined(HAVE_SYS_STATFS_H)
-#include <sys/statfs.h>
-#endif
-#if defined(HAVE_SYS_PARAM_H) && defined(HAVE_SYS_MOUNT_H)
-#include <sys/param.h>
-#include <sys/mount.h>
-#endif
-#include <sys/types.h>
-#include <stdio.h>
-#include <utime.h>
-#ifdef __linux__
-#include <sys/ioctl.h>
-#include <linux/fs.h>
-#include <mono/utils/linux_magic.h>
-#endif
-
-#include <mono/io-layer/wapi.h>
-#include <mono/io-layer/wapi-private.h>
-#include <mono/io-layer/io-private.h>
-#include <mono/io-layer/io-portability.h>
-#include <mono/io-layer/io-trace.h>
-#include <mono/utils/strenc.h>
-#include <mono/utils/mono-once.h>
-#include <mono/utils/mono-logger-internals.h>
-#include <mono/metadata/w32handle.h>
-
-/*
- * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
- * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
- * 4MB array.
- */
-static GHashTable *file_share_hash;
-static mono_mutex_t file_share_mutex;
-
-static void
-time_t_to_filetime (time_t timeval, WapiFileTime *filetime)
-{
- guint64 ticks;
-
- ticks = ((guint64)timeval * 10000000) + 116444736000000000ULL;
- filetime->dwLowDateTime = ticks & 0xFFFFFFFF;
- filetime->dwHighDateTime = ticks >> 32;
-}
-
-static void
-_wapi_handle_share_release (_WapiFileShare *share_info)
-{
- /* Prevent new entries racing with us */
- mono_os_mutex_lock (&file_share_mutex);
-
- g_assert (share_info->handle_refs > 0);
- share_info->handle_refs -= 1;
-
- if (share_info->handle_refs == 0)
- g_hash_table_remove (file_share_hash, share_info);
-
- mono_os_mutex_unlock (&file_share_mutex);
-}
-
-static gint
-wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
-{
- const _WapiFileShare *s1 = (const _WapiFileShare *)ka;
- const _WapiFileShare *s2 = (const _WapiFileShare *)kb;
-
- return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
-}
-
-static guint
-wapi_share_info_hash (gconstpointer data)
-{
- const _WapiFileShare *s = (const _WapiFileShare *)data;
-
- return s->inode;
-}
-
-static gboolean
-_wapi_handle_get_or_set_share (guint64 device, guint64 inode, guint32 new_sharemode, guint32 new_access,
- guint32 *old_sharemode, guint32 *old_access, struct _WapiFileShare **share_info)
-{
- struct _WapiFileShare *file_share;
- gboolean exists = FALSE;
-
- /* Prevent new entries racing with us */
- mono_os_mutex_lock (&file_share_mutex);
-
- _WapiFileShare tmp;
-
- /*
- * Instead of allocating a 4MB array, we use a hash table to keep track of this
- * info. This is needed even if SHM is disabled, to track sharing inside
- * the current process.
- */
- if (!file_share_hash)
- file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
-
- tmp.device = device;
- tmp.inode = inode;
-
- file_share = (_WapiFileShare *)g_hash_table_lookup (file_share_hash, &tmp);
- if (file_share) {
- *old_sharemode = file_share->sharemode;
- *old_access = file_share->access;
- *share_info = file_share;
-
- g_assert (file_share->handle_refs > 0);
- file_share->handle_refs += 1;
-
- exists = TRUE;
- } else {
- file_share = g_new0 (_WapiFileShare, 1);
-
- file_share->device = device;
- file_share->inode = inode;
- file_share->opened_by_pid = wapi_getpid ();
- file_share->sharemode = new_sharemode;
- file_share->access = new_access;
- file_share->handle_refs = 1;
- *share_info = file_share;
-
- g_hash_table_insert (file_share_hash, file_share, file_share);
- }
-
- mono_os_mutex_unlock (&file_share_mutex);
-
- return(exists);
-}
-
-static void file_close (gpointer handle, gpointer data);
-static void file_details (gpointer data);
-static const gchar* file_typename (void);
-static gsize file_typesize (void);
-static WapiFileType file_getfiletype(void);
-static gboolean file_read(gpointer handle, gpointer buffer,
- guint32 numbytes, guint32 *bytesread,
- WapiOverlapped *overlapped);
-static gboolean file_write(gpointer handle, gconstpointer buffer,
- guint32 numbytes, guint32 *byteswritten,
- WapiOverlapped *overlapped);
-static gboolean file_flush(gpointer handle);
-static guint32 file_seek(gpointer handle, gint32 movedistance,
- gint32 *highmovedistance, WapiSeekMethod method);
-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(gpointer handle,
- const WapiFileTime *create_time,
- const WapiFileTime *last_access,
- const WapiFileTime *last_write);
-static guint32 GetDriveTypeFromPath (const gchar *utf8_root_path_name);
-
-/* File handle is only signalled for overlapped IO */
-static MonoW32HandleOps _wapi_file_ops = {
- file_close, /* close */
- NULL, /* signal */
- NULL, /* own */
- NULL, /* is_owned */
- NULL, /* special_wait */
- NULL, /* prewait */
- file_details, /* details */
- file_typename, /* typename */
- file_typesize, /* typesize */
-};
-
-static void console_close (gpointer handle, gpointer data);
-static void console_details (gpointer data);
-static const gchar* console_typename (void);
-static gsize console_typesize (void);
-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);
-
-/* Console is mostly the same as file, except it can block waiting for
- * input or output
- */
-static MonoW32HandleOps _wapi_console_ops = {
- console_close, /* close */
- NULL, /* signal */
- NULL, /* own */
- NULL, /* is_owned */
- NULL, /* special_wait */
- NULL, /* prewait */
- console_details, /* details */
- console_typename, /* typename */
- console_typesize, /* typesize */
-};
-
-static const gchar* find_typename (void);
-static gsize find_typesize (void);
-
-static MonoW32HandleOps _wapi_find_ops = {
- NULL, /* close */
- NULL, /* signal */
- NULL, /* own */
- NULL, /* is_owned */
- NULL, /* special_wait */
- NULL, /* prewait */
- NULL, /* details */
- find_typename, /* typename */
- find_typesize, /* typesize */
-};
-
-static void pipe_close (gpointer handle, gpointer data);
-static void pipe_details (gpointer data);
-static const gchar* pipe_typename (void);
-static gsize pipe_typesize (void);
-static WapiFileType pipe_getfiletype (void);
-static gboolean pipe_read (gpointer handle, gpointer buffer, guint32 numbytes,
- guint32 *bytesread, WapiOverlapped *overlapped);
-static gboolean pipe_write (gpointer handle, gconstpointer buffer,
- guint32 numbytes, guint32 *byteswritten,
- WapiOverlapped *overlapped);
-
-/* Pipe handles
- */
-static MonoW32HandleOps _wapi_pipe_ops = {
- pipe_close, /* close */
- NULL, /* signal */
- NULL, /* own */
- NULL, /* is_owned */
- NULL, /* special_wait */
- NULL, /* prewait */
- pipe_details, /* details */
- pipe_typename, /* typename */
- pipe_typesize, /* typesize */
-};
-
-static const struct {
- /* File, console and pipe handles */
- WapiFileType (*getfiletype)(void);
-
- /* File, console and pipe 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[MONO_W32HANDLE_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,
- NULL, 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},
- /* pipe */
- {pipe_getfiletype,
- pipe_read,
- pipe_write,
- NULL, NULL, NULL, NULL, NULL, NULL},
-};
-
-static gboolean lock_while_writing = FALSE;
-
-/* Some utility functions.
- */
-
-/*
- * Check if a file is writable by the current user.
- *
- * This is is a best effort kind of thing. It assumes a reasonable sane set
- * of permissions by the underlying OS.
- *
- * We generally assume that basic unix permission bits are authoritative. Which might not
- * be the case under systems with extended permissions systems (posix ACLs, SELinux, OSX/iOS sandboxing, etc)
- *
- * The choice of access as the fallback is due to the expected lower overhead compared to trying to open the file.
- *
- * The only expected problem with using access are for root, setuid or setgid programs as access is not consistent
- * under those situations. It's to be expected that this should not happen in practice as those bits are very dangerous
- * and should not be used with a dynamic runtime.
- */
-static gboolean
-is_file_writable (struct stat *st, const char *path)
-{
-#if __APPLE__
- // OS X Finder "locked" or `ls -lO` "uchg".
- // This only covers one of several cases where an OS X file could be unwritable through special flags.
- if (st->st_flags & (UF_IMMUTABLE|SF_IMMUTABLE))
- return 0;
-#endif
-
- /* Is it globally writable? */
- if (st->st_mode & S_IWOTH)
- return 1;
-
- /* Am I the owner? */
- if ((st->st_uid == geteuid ()) && (st->st_mode & S_IWUSR))
- return 1;
-
- /* Am I in the same group? */
- if ((st->st_gid == getegid ()) && (st->st_mode & S_IWGRP))
- return 1;
-
- /* Fallback to using access(2). It's not ideal as it might not take into consideration euid/egid
- * but it's the only sane option we have on unix.
- */
- return access (path, W_OK) == 0;
-}
-
-
-static guint32 _wapi_stat_to_file_attributes (const gchar *pathname,
- struct stat *buf,
- struct stat *lbuf)
-{
- guint32 attrs = 0;
- gchar *filename;
-
- /* FIXME: this could definitely be better, but there seems to
- * be no pattern to the attributes that are set
- */
-
- /* Sockets (0140000) != Directory (040000) + Regular file (0100000) */
- if (S_ISSOCK (buf->st_mode))
- buf->st_mode &= ~S_IFSOCK; /* don't consider socket protection */
-
- filename = _wapi_basename (pathname);
-
- if (S_ISDIR (buf->st_mode)) {
- attrs = FILE_ATTRIBUTE_DIRECTORY;
- if (!is_file_writable (buf, pathname)) {
- attrs |= FILE_ATTRIBUTE_READONLY;
- }
- if (filename[0] == '.') {
- attrs |= FILE_ATTRIBUTE_HIDDEN;
- }
- } else {
- if (!is_file_writable (buf, pathname)) {
- attrs = FILE_ATTRIBUTE_READONLY;
-
- if (filename[0] == '.') {
- attrs |= FILE_ATTRIBUTE_HIDDEN;
- }
- } else if (filename[0] == '.') {
- attrs = FILE_ATTRIBUTE_HIDDEN;
- } else {
- attrs = FILE_ATTRIBUTE_NORMAL;
- }
- }
-
- if (lbuf != NULL) {
- if (S_ISLNK (lbuf->st_mode)) {
- attrs |= FILE_ATTRIBUTE_REPARSE_POINT;
- }
- }
-
- g_free (filename);
-
- return attrs;
-}
-
-static void
-_wapi_set_last_error_from_errno (void)
-{
- SetLastError (_wapi_get_win32_file_error (errno));
-}
-
-static void _wapi_set_last_path_error_from_errno (const gchar *dir,
- const gchar *path)
-{
- if (errno == ENOENT) {
- /* Check the path - if it's a missing directory then
- * we need to set PATH_NOT_FOUND not FILE_NOT_FOUND
- */
- gchar *dirname;
-
-
- if (dir == NULL) {
- dirname = _wapi_dirname (path);
- } else {
- dirname = g_strdup (dir);
- }
-
- if (_wapi_access (dirname, F_OK) == 0) {
- SetLastError (ERROR_FILE_NOT_FOUND);
- } else {
- SetLastError (ERROR_PATH_NOT_FOUND);
- }
-
- g_free (dirname);
- } else {
- _wapi_set_last_error_from_errno ();
- }
-}
-
-/* Handle ops.
- */
-static void file_close (gpointer handle, gpointer data)
-{
- struct _WapiHandle_file *file_handle = (struct _WapiHandle_file *)data;
- int fd = file_handle->fd;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing file handle %p [%s]", __func__, handle,
- file_handle->filename);
-
- if (file_handle->attrs & FILE_FLAG_DELETE_ON_CLOSE)
- _wapi_unlink (file_handle->filename);
-
- g_free (file_handle->filename);
-
- if (file_handle->share_info)
- _wapi_handle_share_release (file_handle->share_info);
-
- close (fd);
-}
-
-static void file_details (gpointer data)
-{
- struct _WapiHandle_file *file = (struct _WapiHandle_file *)data;
-
- g_print ("[%20s] acc: %c%c%c, shr: %c%c%c, attrs: %5u",
- file->filename,
- file->fileaccess&GENERIC_READ?'R':'.',
- file->fileaccess&GENERIC_WRITE?'W':'.',
- file->fileaccess&GENERIC_EXECUTE?'X':'.',
- file->sharemode&FILE_SHARE_READ?'R':'.',
- file->sharemode&FILE_SHARE_WRITE?'W':'.',
- file->sharemode&FILE_SHARE_DELETE?'D':'.',
- file->attrs);
-}
-
-static const gchar* file_typename (void)
-{
- return "File";
-}
-
-static gsize file_typesize (void)
-{
- return sizeof (struct _WapiHandle_file);
-}
-
-static WapiFileType file_getfiletype(void)
-{
- return(FILE_TYPE_DISK);
-}
-
-static gboolean file_read(gpointer handle, gpointer buffer,
- guint32 numbytes, guint32 *bytesread,
- WapiOverlapped *overlapped)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- int fd, ret;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- fd = file_handle->fd;
- if(bytesread!=NULL) {
- *bytesread=0;
- }
-
- if(!(file_handle->fileaccess & GENERIC_READ) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
- __func__, handle, file_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- do {
- ret = read (fd, buffer, numbytes);
- } while (ret == -1 && errno == EINTR &&
- !mono_thread_info_is_interrupt_state (info));
-
- if(ret==-1) {
- gint err = errno;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of handle %p error: %s", __func__,
- handle, strerror(err));
- SetLastError (_wapi_get_win32_file_error (err));
- return(FALSE);
- }
-
- if (bytesread != NULL) {
- *bytesread = ret;
- }
-
- return(TRUE);
-}
-
-static gboolean file_write(gpointer handle, gconstpointer buffer,
- guint32 numbytes, guint32 *byteswritten,
- WapiOverlapped *overlapped G_GNUC_UNUSED)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- int ret, fd;
- off_t current_pos = 0;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- fd = file_handle->fd;
-
- if(byteswritten!=NULL) {
- *byteswritten=0;
- }
-
- if(!(file_handle->fileaccess & GENERIC_WRITE) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- if (lock_while_writing) {
- /* Need to lock the region we're about to write to,
- * because we only do advisory locking on POSIX
- * systems
- */
- current_pos = lseek (fd, (off_t)0, SEEK_CUR);
- if (current_pos == -1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p lseek failed: %s", __func__,
- handle, strerror (errno));
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
-
- if (_wapi_lock_file_region (fd, current_pos,
- numbytes) == FALSE) {
- /* The error has already been set */
- return(FALSE);
- }
- }
-
- do {
- ret = write (fd, buffer, numbytes);
- } while (ret == -1 && errno == EINTR &&
- !mono_thread_info_is_interrupt_state (info));
-
- if (lock_while_writing) {
- _wapi_unlock_file_region (fd, current_pos, numbytes);
- }
-
- if (ret == -1) {
- if (errno == EINTR) {
- ret = 0;
- } else {
- _wapi_set_last_error_from_errno ();
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of handle %p error: %s",
- __func__, handle, strerror(errno));
-
- return(FALSE);
- }
- }
- if (byteswritten != NULL) {
- *byteswritten = ret;
- }
- return(TRUE);
-}
-
-static gboolean file_flush(gpointer handle)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- int ret, fd;
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- fd = file_handle->fd;
-
- if(!(file_handle->fileaccess & GENERIC_WRITE) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- ret=fsync(fd);
- if (ret==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fsync of handle %p error: %s", __func__, handle,
- strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-static guint32 file_seek(gpointer handle, gint32 movedistance,
- gint32 *highmovedistance, WapiSeekMethod method)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- gint64 offset, newpos;
- int whence, fd;
- guint32 ret;
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(INVALID_SET_FILE_POINTER);
- }
-
- fd = file_handle->fd;
-
- if(!(file_handle->fileaccess & GENERIC_READ) &&
- !(file_handle->fileaccess & GENERIC_WRITE) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(INVALID_SET_FILE_POINTER);
- }
-
- switch(method) {
- case FILE_BEGIN:
- whence=SEEK_SET;
- break;
- case FILE_CURRENT:
- whence=SEEK_CUR;
- break;
- case FILE_END:
- whence=SEEK_END;
- break;
- default:
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: invalid seek type %d", __func__, method);
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return(INVALID_SET_FILE_POINTER);
- }
-
-#ifdef HAVE_LARGE_FILE_SUPPORT
- if(highmovedistance==NULL) {
- offset=movedistance;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting offset to %lld (low %d)", __func__,
- offset, movedistance);
- } else {
- offset=((gint64) *highmovedistance << 32) | (guint32)movedistance;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting offset to %lld 0x%llx (high %d 0x%x, low %d 0x%x)", __func__, offset, offset, *highmovedistance, *highmovedistance, movedistance, movedistance);
- }
-#else
- offset=movedistance;
-#endif
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: moving handle %p by %lld bytes from %d", __func__,
- handle, (long long)offset, whence);
-
-#ifdef PLATFORM_ANDROID
- /* bionic doesn't support -D_FILE_OFFSET_BITS=64 */
- newpos=lseek64(fd, offset, whence);
-#else
- newpos=lseek(fd, offset, whence);
-#endif
- if(newpos==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lseek on handle %p returned error %s",
- __func__, handle, strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(INVALID_SET_FILE_POINTER);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lseek returns %lld", __func__, newpos);
-
-#ifdef HAVE_LARGE_FILE_SUPPORT
- ret=newpos & 0xFFFFFFFF;
- if(highmovedistance!=NULL) {
- *highmovedistance=newpos>>32;
- }
-#else
- ret=newpos;
- if(highmovedistance!=NULL) {
- /* Accurate, but potentially dodgy :-) */
- *highmovedistance=0;
- }
-#endif
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: move of handle %p returning %d/%d", __func__,
- handle, ret, highmovedistance==NULL?0:*highmovedistance);
-
- return(ret);
-}
-
-static gboolean file_setendoffile(gpointer handle)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- struct stat statbuf;
- off_t pos;
- int ret, fd;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
- fd = file_handle->fd;
-
- if(!(file_handle->fileaccess & GENERIC_WRITE) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- /* Find the current file position, and the file length. If
- * the file position is greater than the length, write to
- * extend the file with a hole. If the file position is less
- * than the length, truncate the file.
- */
-
- ret=fstat(fd, &statbuf);
- if(ret==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__,
- handle, strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
-
- pos=lseek(fd, (off_t)0, SEEK_CUR);
- if(pos==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p lseek failed: %s", __func__,
- handle, strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
-
-#ifdef FTRUNCATE_DOESNT_EXTEND
- off_t size = statbuf.st_size;
- /* I haven't bothered to write the configure.ac stuff for this
- * because I don't know if any platform needs it. I'm leaving
- * this code just in case though
- */
- if(pos>size) {
- /* Extend the file. Use write() here, because some
- * manuals say that ftruncate() behaviour is undefined
- * when the file needs extending. The POSIX spec says
- * that on XSI-conformant systems it extends, so if
- * every system we care about conforms, then we can
- * drop this write.
- */
- do {
- ret = write (fd, "", 1);
- } while (ret == -1 && errno == EINTR &&
- !mono_thread_info_is_interrupt_state (info));
-
- if(ret==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p extend write failed: %s", __func__, handle, strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
-
- /* And put the file position back after the write */
- ret = lseek (fd, pos, SEEK_SET);
- if (ret == -1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p second lseek failed: %s",
- __func__, handle, strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
- }
-#endif
-
-/* Native Client has no ftruncate function, even in standalone sel_ldr. */
-#ifndef __native_client__
- /* always truncate, because the extend write() adds an extra
- * byte to the end of the file
- */
- do {
- ret=ftruncate(fd, pos);
- }
- while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
- if(ret==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p ftruncate failed: %s", __func__,
- handle, strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
-#endif
-
- return(TRUE);
-}
-
-static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- struct stat statbuf;
- guint32 size;
- int ret;
- int fd;
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(INVALID_FILE_SIZE);
- }
- fd = file_handle->fd;
-
- if(!(file_handle->fileaccess & GENERIC_READ) &&
- !(file_handle->fileaccess & GENERIC_WRITE) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(INVALID_FILE_SIZE);
- }
-
- /* If the file has a size with the low bits 0xFFFFFFFF the
- * caller can't tell if this is an error, so clear the error
- * value
- */
- SetLastError (ERROR_SUCCESS);
-
- ret = fstat(fd, &statbuf);
- if (ret == -1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__,
- handle, strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(INVALID_FILE_SIZE);
- }
-
- /* fstat indicates block devices as zero-length, so go a different path */
-#ifdef BLKGETSIZE64
- if (S_ISBLK(statbuf.st_mode)) {
- guint64 bigsize;
- if (ioctl(fd, BLKGETSIZE64, &bigsize) < 0) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p ioctl BLKGETSIZE64 failed: %s",
- __func__, handle, strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(INVALID_FILE_SIZE);
- }
-
- size = bigsize & 0xFFFFFFFF;
- if (highsize != NULL) {
- *highsize = bigsize>>32;
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning block device size %d/%d",
- __func__, size, *highsize);
-
- return(size);
- }
-#endif
-
-#ifdef HAVE_LARGE_FILE_SUPPORT
- size = statbuf.st_size & 0xFFFFFFFF;
- if (highsize != NULL) {
- *highsize = statbuf.st_size>>32;
- }
-#else
- if (highsize != NULL) {
- /* Accurate, but potentially dodgy :-) */
- *highsize = 0;
- }
- size = statbuf.st_size;
-#endif
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning size %d/%d", __func__, size, *highsize);
-
- return(size);
-}
-
-static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
- WapiFileTime *last_access,
- WapiFileTime *last_write)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- struct stat statbuf;
- guint64 create_ticks, access_ticks, write_ticks;
- int ret, fd;
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
- fd = file_handle->fd;
-
- if(!(file_handle->fileaccess & GENERIC_READ) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
- __func__, handle, file_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- ret=fstat(fd, &statbuf);
- if(ret==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__, handle,
- strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: atime: %ld ctime: %ld mtime: %ld", __func__,
- statbuf.st_atime, statbuf.st_ctime,
- statbuf.st_mtime);
-
- /* Try and guess a meaningful create time by using the older
- * of atime or ctime
- */
- /* The magic constant comes from msdn documentation
- * "Converting a time_t Value to a File Time"
- */
- if(statbuf.st_atime < statbuf.st_ctime) {
- create_ticks=((guint64)statbuf.st_atime*10000000)
- + 116444736000000000ULL;
- } else {
- create_ticks=((guint64)statbuf.st_ctime*10000000)
- + 116444736000000000ULL;
- }
-
- access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000ULL;
- write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000ULL;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: aticks: %llu cticks: %llu wticks: %llu", __func__,
- access_ticks, create_ticks, write_ticks);
-
- if(create_time!=NULL) {
- create_time->dwLowDateTime = create_ticks & 0xFFFFFFFF;
- create_time->dwHighDateTime = create_ticks >> 32;
- }
-
- if(last_access!=NULL) {
- last_access->dwLowDateTime = access_ticks & 0xFFFFFFFF;
- last_access->dwHighDateTime = access_ticks >> 32;
- }
-
- if(last_write!=NULL) {
- last_write->dwLowDateTime = write_ticks & 0xFFFFFFFF;
- last_write->dwHighDateTime = write_ticks >> 32;
- }
-
- return(TRUE);
-}
-
-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;
- gboolean ok;
- struct utimbuf utbuf;
- struct stat statbuf;
- guint64 access_ticks, write_ticks;
- int ret, fd;
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
- fd = file_handle->fd;
-
- if(!(file_handle->fileaccess & GENERIC_WRITE) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- if(file_handle->filename == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p unknown filename", __func__, handle);
-
- SetLastError (ERROR_INVALID_HANDLE);
- 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 (fd, &statbuf);
- if(ret==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__, handle,
- strerror(errno));
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- if(last_access!=NULL) {
- access_ticks=((guint64)last_access->dwHighDateTime << 32) +
- last_access->dwLowDateTime;
- /* This is (time_t)0. We can actually go to INT_MIN,
- * but this will do for now.
- */
- if (access_ticks < 116444736000000000ULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set access time too early",
- __func__);
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- if (sizeof (utbuf.actime) == 4 && ((access_ticks - 116444736000000000ULL) / 10000000) > INT_MAX) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time that is too big for a 32bits time_t",
- __func__);
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- utbuf.actime=(access_ticks - 116444736000000000ULL) / 10000000;
- } else {
- utbuf.actime=statbuf.st_atime;
- }
-
- if(last_write!=NULL) {
- write_ticks=((guint64)last_write->dwHighDateTime << 32) +
- last_write->dwLowDateTime;
- /* This is (time_t)0. We can actually go to INT_MIN,
- * but this will do for now.
- */
- if (write_ticks < 116444736000000000ULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time too early",
- __func__);
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
- if (sizeof (utbuf.modtime) == 4 && ((write_ticks - 116444736000000000ULL) / 10000000) > INT_MAX) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time that is too big for a 32bits time_t",
- __func__);
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- utbuf.modtime=(write_ticks - 116444736000000000ULL) / 10000000;
- } else {
- utbuf.modtime=statbuf.st_mtime;
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting handle %p access %ld write %ld", __func__,
- handle, utbuf.actime, utbuf.modtime);
-
- ret = _wapi_utime (file_handle->filename, &utbuf);
- if (ret == -1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p [%s] utime failed: %s", __func__,
- handle, file_handle->filename, strerror(errno));
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-static void console_close (gpointer handle, gpointer data)
-{
- struct _WapiHandle_file *console_handle = (struct _WapiHandle_file *)data;
- int fd = console_handle->fd;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing console handle %p", __func__, handle);
-
- g_free (console_handle->filename);
-
- if (fd > 2) {
- if (console_handle->share_info)
- _wapi_handle_share_release (console_handle->share_info);
- close (fd);
- }
-}
-
-static void console_details (gpointer data)
-{
- file_details (data);
-}
-
-static const gchar* console_typename (void)
-{
- return "Console";
-}
-
-static gsize console_typesize (void)
-{
- return sizeof (struct _WapiHandle_file);
-}
-
-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;
- gboolean ok;
- int ret, fd;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
- (gpointer *)&console_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up console handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
- fd = console_handle->fd;
-
- if(bytesread!=NULL) {
- *bytesread=0;
- }
-
- if(!(console_handle->fileaccess & GENERIC_READ) &&
- !(console_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
- __func__, handle, console_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- do {
- ret=read(fd, buffer, numbytes);
- } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
-
- if(ret==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of handle %p error: %s", __func__, handle,
- strerror(errno));
-
- _wapi_set_last_error_from_errno ();
- 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;
- gboolean ok;
- int ret, fd;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
- (gpointer *)&console_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up console handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
- fd = console_handle->fd;
-
- if(byteswritten!=NULL) {
- *byteswritten=0;
- }
-
- if(!(console_handle->fileaccess & GENERIC_WRITE) &&
- !(console_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, console_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- do {
- ret = write(fd, buffer, numbytes);
- } while (ret == -1 && errno == EINTR &&
- !mono_thread_info_is_interrupt_state (info));
-
- if (ret == -1) {
- if (errno == EINTR) {
- ret = 0;
- } else {
- _wapi_set_last_error_from_errno ();
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of handle %p error: %s",
- __func__, handle, strerror(errno));
-
- return(FALSE);
- }
- }
- if(byteswritten!=NULL) {
- *byteswritten=ret;
- }
-
- return(TRUE);
-}
-
-static const gchar* find_typename (void)
-{
- return "Find";
-}
-
-static gsize find_typesize (void)
-{
- return sizeof (struct _WapiHandle_find);
-}
-
-static void pipe_close (gpointer handle, gpointer data)
-{
- struct _WapiHandle_file *pipe_handle = (struct _WapiHandle_file*)data;
- int fd = pipe_handle->fd;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing pipe handle %p fd %d", __func__, handle, fd);
-
- /* No filename with pipe handles */
-
- if (pipe_handle->share_info)
- _wapi_handle_share_release (pipe_handle->share_info);
-
- close (fd);
-}
-
-static void pipe_details (gpointer data)
-{
- file_details (data);
-}
-
-static const gchar* pipe_typename (void)
-{
- return "Pipe";
-}
-
-static gsize pipe_typesize (void)
-{
- return sizeof (struct _WapiHandle_file);
-}
-
-static WapiFileType pipe_getfiletype(void)
-{
- return(FILE_TYPE_PIPE);
-}
-
-static gboolean pipe_read (gpointer handle, gpointer buffer,
- guint32 numbytes, guint32 *bytesread,
- WapiOverlapped *overlapped G_GNUC_UNUSED)
-{
- struct _WapiHandle_file *pipe_handle;
- gboolean ok;
- int ret, fd;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_PIPE,
- (gpointer *)&pipe_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up pipe handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
- fd = pipe_handle->fd;
-
- if(bytesread!=NULL) {
- *bytesread=0;
- }
-
- if(!(pipe_handle->fileaccess & GENERIC_READ) &&
- !(pipe_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
- __func__, handle, pipe_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: reading up to %d bytes from pipe %p", __func__,
- numbytes, handle);
-
- do {
- ret=read(fd, buffer, numbytes);
- } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
-
- if (ret == -1) {
- if (errno == EINTR) {
- ret = 0;
- } else {
- _wapi_set_last_error_from_errno ();
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of handle %p error: %s", __func__,
- handle, strerror(errno));
-
- return(FALSE);
- }
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read %d bytes from pipe %p", __func__, ret, handle);
-
- if(bytesread!=NULL) {
- *bytesread=ret;
- }
-
- return(TRUE);
-}
-
-static gboolean pipe_write(gpointer handle, gconstpointer buffer,
- guint32 numbytes, guint32 *byteswritten,
- WapiOverlapped *overlapped G_GNUC_UNUSED)
-{
- struct _WapiHandle_file *pipe_handle;
- gboolean ok;
- int ret, fd;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_PIPE,
- (gpointer *)&pipe_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up pipe handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
- fd = pipe_handle->fd;
-
- if(byteswritten!=NULL) {
- *byteswritten=0;
- }
-
- if(!(pipe_handle->fileaccess & GENERIC_WRITE) &&
- !(pipe_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, pipe_handle->fileaccess);
-
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: writing up to %d bytes to pipe %p", __func__, numbytes,
- handle);
-
- do {
- ret = write (fd, buffer, numbytes);
- } while (ret == -1 && errno == EINTR &&
- !mono_thread_info_is_interrupt_state (info));
-
- if (ret == -1) {
- if (errno == EINTR) {
- ret = 0;
- } else {
- _wapi_set_last_error_from_errno ();
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of handle %p error: %s", __func__,
- handle, strerror(errno));
-
- return(FALSE);
- }
- }
- if(byteswritten!=NULL) {
- *byteswritten=ret;
- }
-
- return(TRUE);
-}
-
-static int convert_flags(guint32 fileaccess, guint32 createmode)
-{
- int flags=0;
-
- switch(fileaccess) {
- case GENERIC_READ:
- flags=O_RDONLY;
- break;
- case GENERIC_WRITE:
- flags=O_WRONLY;
- break;
- case GENERIC_READ|GENERIC_WRITE:
- flags=O_RDWR;
- break;
- default:
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unknown access type 0x%x", __func__,
- fileaccess);
- break;
- }
-
- switch(createmode) {
- case CREATE_NEW:
- flags|=O_CREAT|O_EXCL;
- break;
- case CREATE_ALWAYS:
- flags|=O_CREAT|O_TRUNC;
- break;
- case OPEN_EXISTING:
- break;
- case OPEN_ALWAYS:
- flags|=O_CREAT;
- break;
- case TRUNCATE_EXISTING:
- flags|=O_TRUNC;
- break;
- default:
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unknown create mode 0x%x", __func__,
- createmode);
- break;
- }
-
- return(flags);
-}
-
-#if 0 /* unused */
-static mode_t convert_perms(guint32 sharemode)
-{
- mode_t perms=0600;
-
- if(sharemode&FILE_SHARE_READ) {
- perms|=044;
- }
- if(sharemode&FILE_SHARE_WRITE) {
- perms|=022;
- }
-
- return(perms);
-}
-#endif
-
-static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode,
- guint32 fileaccess,
- struct _WapiFileShare **share_info)
-{
- gboolean file_already_shared;
- guint32 file_existing_share, file_existing_access;
-
- file_already_shared = _wapi_handle_get_or_set_share (statbuf->st_dev, statbuf->st_ino, sharemode, fileaccess, &file_existing_share, &file_existing_access, share_info);
-
- if (file_already_shared) {
- /* The reference to this share info was incremented
- * when we looked it up, so be careful to put it back
- * if we conclude we can't use this file.
- */
- if (file_existing_share == 0) {
- /* Quick and easy, no possibility to share */
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%x, file has sharing = NONE", __func__, fileaccess);
-
- _wapi_handle_share_release (*share_info);
-
- return(FALSE);
- }
-
- if (((file_existing_share == FILE_SHARE_READ) &&
- (fileaccess != GENERIC_READ)) ||
- ((file_existing_share == FILE_SHARE_WRITE) &&
- (fileaccess != GENERIC_WRITE))) {
- /* New access mode doesn't match up */
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%x, file has sharing: 0x%x", __func__, fileaccess, file_existing_share);
-
- _wapi_handle_share_release (*share_info);
-
- return(FALSE);
- }
-
- if (((file_existing_access & GENERIC_READ) &&
- !(sharemode & FILE_SHARE_READ)) ||
- ((file_existing_access & GENERIC_WRITE) &&
- !(sharemode & FILE_SHARE_WRITE))) {
- /* New share mode doesn't match up */
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Access mode prevents open: requested share: 0x%x, file has access: 0x%x", __func__, sharemode, file_existing_access);
-
- _wapi_handle_share_release (*share_info);
-
- return(FALSE);
- }
- } else {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: New file!", __func__);
- }
-
- return(TRUE);
-}
-
-
-static gboolean
-share_allows_delete (struct stat *statbuf, struct _WapiFileShare **share_info)
-{
- gboolean file_already_shared;
- guint32 file_existing_share, file_existing_access;
-
- file_already_shared = _wapi_handle_get_or_set_share (statbuf->st_dev, statbuf->st_ino, FILE_SHARE_DELETE, GENERIC_READ, &file_existing_share, &file_existing_access, share_info);
-
- if (file_already_shared) {
- /* The reference to this share info was incremented
- * when we looked it up, so be careful to put it back
- * if we conclude we can't use this file.
- */
- if (file_existing_share == 0) {
- /* Quick and easy, no possibility to share */
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%x, file has sharing = NONE", __func__, (*share_info)->access);
-
- _wapi_handle_share_release (*share_info);
-
- return(FALSE);
- }
-
- if (!(file_existing_share & FILE_SHARE_DELETE)) {
- /* New access mode doesn't match up */
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%x, file has sharing: 0x%x", __func__, (*share_info)->access, file_existing_share);
-
- _wapi_handle_share_release (*share_info);
-
- return(FALSE);
- }
- } else {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: New file!", __func__);
- }
-
- return(TRUE);
-}
-
-/**
- * CreateFile:
- * @name: a pointer to a NULL-terminated unicode string, that names
- * the file or other object to create.
- * @fileaccess: specifies the file access mode
- * @sharemode: whether the file should be shared. This parameter is
- * currently ignored.
- * @security: Ignored for now.
- * @createmode: specifies whether to create a new file, whether to
- * overwrite an existing file, whether to truncate the file, etc.
- * @attrs: specifies file attributes and flags. On win32 attributes
- * are characteristics of the file, not the handle, and are ignored
- * when an existing file is opened. Flags give the library hints on
- * how to process a file to optimise performance.
- * @template: the handle of an open %GENERIC_READ file that specifies
- * attributes to apply to a newly created file, ignoring @attrs.
- * Normally this parameter is NULL. This parameter is ignored when an
- * existing file is opened.
- *
- * Creates a new file handle. This only applies to normal files:
- * pipes are handled by CreatePipe(), and console handles are created
- * with GetStdHandle().
- *
- * Return value: the new handle, or %INVALID_HANDLE_VALUE on error.
- */
-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 = {0};
- gpointer handle;
- int flags=convert_flags(fileaccess, createmode);
- /*mode_t perms=convert_perms(sharemode);*/
- /* we don't use sharemode, because that relates to sharing of
- * the file when the file is open and is already handled by
- * other code, perms instead are the on-disk permissions and
- * this is a sane default.
- */
- mode_t perms=0666;
- gchar *filename;
- int fd, ret;
- MonoW32HandleType handle_type;
- struct stat statbuf;
-
- if (attrs & FILE_ATTRIBUTE_TEMPORARY)
- perms = 0600;
-
- if (attrs & FILE_ATTRIBUTE_ENCRYPTED){
- SetLastError (ERROR_ENCRYPTION_FAILED);
- return INVALID_HANDLE_VALUE;
- }
-
- if (name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(INVALID_HANDLE_VALUE);
- }
-
- filename = mono_unicode_to_external (name);
- if (filename == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(INVALID_HANDLE_VALUE);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening %s with share 0x%x and access 0x%x", __func__,
- filename, sharemode, fileaccess);
-
- fd = _wapi_open (filename, flags, perms);
-
- /* If we were trying to open a directory with write permissions
- * (e.g. O_WRONLY or O_RDWR), this call will fail with
- * EISDIR. However, this is a bit bogus because calls to
- * manipulate the directory (e.g. SetFileTime) will still work on
- * the directory because they use other API calls
- * (e.g. utime()). Hence, if we failed with the EISDIR error, try
- * to open the directory again without write permission.
- */
- if (fd == -1 && errno == EISDIR)
- {
- /* Try again but don't try to make it writable */
- fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms);
- }
-
- if (fd == -1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s: %s", __func__, filename,
- strerror(errno));
- _wapi_set_last_path_error_from_errno (NULL, filename);
- g_free (filename);
-
- return(INVALID_HANDLE_VALUE);
- }
-
- if (fd >= mono_w32handle_fd_reserve) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
-
- SetLastError (ERROR_TOO_MANY_OPEN_FILES);
-
- close (fd);
- g_free (filename);
-
- return(INVALID_HANDLE_VALUE);
- }
-
- ret = fstat (fd, &statbuf);
- if (ret == -1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fstat error of file %s: %s", __func__,
- filename, strerror (errno));
- _wapi_set_last_error_from_errno ();
- g_free (filename);
- close (fd);
-
- return(INVALID_HANDLE_VALUE);
- }
-#ifdef __native_client__
- /* Workaround: Native Client currently returns the same fake inode
- * for all files, so do a simple hash on the filename so we don't
- * use the same share info for each file.
- */
- statbuf.st_ino = g_str_hash(filename);
-#endif
-
- if (share_allows_open (&statbuf, sharemode, fileaccess,
- &file_handle.share_info) == FALSE) {
- SetLastError (ERROR_SHARING_VIOLATION);
- g_free (filename);
- close (fd);
-
- return (INVALID_HANDLE_VALUE);
- }
- if (file_handle.share_info == NULL) {
- /* No space, so no more files can be opened */
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No space in the share table", __func__);
-
- SetLastError (ERROR_TOO_MANY_OPEN_FILES);
- close (fd);
- g_free (filename);
-
- return(INVALID_HANDLE_VALUE);
- }
-
- file_handle.filename = filename;
-
- if(security!=NULL) {
- //file_handle->security_attributes=_wapi_handle_scratch_store (
- //security, sizeof(WapiSecurityAttributes));
- }
-
- file_handle.fd = fd;
- file_handle.fileaccess=fileaccess;
- file_handle.sharemode=sharemode;
- file_handle.attrs=attrs;
-
-#ifdef HAVE_POSIX_FADVISE
- if (attrs & FILE_FLAG_SEQUENTIAL_SCAN)
- posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);
- if (attrs & FILE_FLAG_RANDOM_ACCESS)
- posix_fadvise (fd, 0, 0, POSIX_FADV_RANDOM);
-#endif
-
-#ifdef F_RDAHEAD
- if (attrs & FILE_FLAG_SEQUENTIAL_SCAN)
- fcntl(fd, F_RDAHEAD, 1);
-#endif
-
-#ifndef S_ISFIFO
-#define S_ISFIFO(m) ((m & S_IFIFO) != 0)
-#endif
- if (S_ISFIFO (statbuf.st_mode)) {
- handle_type = MONO_W32HANDLE_PIPE;
- /* maintain invariant that pipes have no filename */
- file_handle.filename = NULL;
- g_free (filename);
- filename = NULL;
- } else if (S_ISCHR (statbuf.st_mode)) {
- handle_type = MONO_W32HANDLE_CONSOLE;
- } else {
- handle_type = MONO_W32HANDLE_FILE;
- }
-
- handle = mono_w32handle_new_fd (handle_type, fd, &file_handle);
- if (handle == INVALID_HANDLE_VALUE) {
- g_warning ("%s: error creating file handle", __func__);
- g_free (filename);
- close (fd);
-
- SetLastError (ERROR_GEN_FAILURE);
- return(INVALID_HANDLE_VALUE);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p", __func__, handle);
-
- return(handle);
-}
-
-/**
- * DeleteFile:
- * @name: a pointer to a NULL-terminated unicode string, that names
- * the file to be deleted.
- *
- * Deletes file @name.
- *
- * Return value: %TRUE on success, %FALSE otherwise.
- */
-gboolean DeleteFile(const gunichar2 *name)
-{
- gchar *filename;
- int retval;
- gboolean ret = FALSE;
- guint32 attrs;
-#if 0
- struct stat statbuf;
- struct _WapiFileShare *shareinfo;
-#endif
-
- if(name==NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- filename=mono_unicode_to_external(name);
- if(filename==NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- attrs = GetFileAttributes (name);
- if (attrs == INVALID_FILE_ATTRIBUTES) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file attributes error", __func__);
- /* Error set by GetFileAttributes() */
- g_free (filename);
- return(FALSE);
- }
-
-#if 0
- /* Check to make sure sharing allows us to open the file for
- * writing. See bug 323389.
- *
- * Do the checks that don't need an open file descriptor, for
- * simplicity's sake. If we really have to do the full checks
- * then we can implement that later.
- */
- if (_wapi_stat (filename, &statbuf) < 0) {
- _wapi_set_last_path_error_from_errno (NULL, filename);
- g_free (filename);
- return(FALSE);
- }
-
- if (share_allows_open (&statbuf, 0, GENERIC_WRITE,
- &shareinfo) == FALSE) {
- SetLastError (ERROR_SHARING_VIOLATION);
- g_free (filename);
- return FALSE;
- }
- if (shareinfo)
- _wapi_handle_share_release (shareinfo);
-#endif
-
- retval = _wapi_unlink (filename);
-
- if (retval == -1) {
- _wapi_set_last_path_error_from_errno (NULL, filename);
- } else {
- ret = TRUE;
- }
-
- g_free(filename);
-
- return(ret);
-}
-
-/**
- * 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.
- * MoveFile sets ERROR_ALREADY_EXISTS if the destination exists, except
- * when it is the same file as the source. In that case it silently succeeds.
- *
- * Return value: %TRUE on success, %FALSE otherwise.
- */
-gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
-{
- gchar *utf8_name, *utf8_dest_name;
- int result, errno_copy;
- struct stat stat_src, stat_dest;
- gboolean ret = FALSE;
- struct _WapiFileShare *shareinfo;
-
- if(name==NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_name = mono_unicode_to_external (name);
- if (utf8_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return FALSE;
- }
-
- if(dest_name==NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- g_free (utf8_name);
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_dest_name = mono_unicode_to_external (dest_name);
- if (utf8_dest_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- g_free (utf8_name);
- SetLastError (ERROR_INVALID_NAME);
- return FALSE;
- }
-
- /*
- * In C# land we check for the existence of src, but not for dest.
- * We check it here and return the failure if dest exists and is not
- * the same file as src.
- */
- if (_wapi_stat (utf8_name, &stat_src) < 0) {
- if (errno != ENOENT || _wapi_lstat (utf8_name, &stat_src) < 0) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_name);
- g_free (utf8_name);
- g_free (utf8_dest_name);
- return FALSE;
- }
- }
-
- if (!_wapi_stat (utf8_dest_name, &stat_dest)) {
- if (stat_dest.st_dev != stat_src.st_dev ||
- stat_dest.st_ino != stat_src.st_ino) {
- g_free (utf8_name);
- g_free (utf8_dest_name);
- SetLastError (ERROR_ALREADY_EXISTS);
- return FALSE;
- }
- }
-
- /* Check to make that we have delete sharing permission.
- * See https://bugzilla.xamarin.com/show_bug.cgi?id=17009
- *
- * Do the checks that don't need an open file descriptor, for
- * simplicity's sake. If we really have to do the full checks
- * then we can implement that later.
- */
- if (share_allows_delete (&stat_src, &shareinfo) == FALSE) {
- SetLastError (ERROR_SHARING_VIOLATION);
- return FALSE;
- }
- if (shareinfo)
- _wapi_handle_share_release (shareinfo);
-
- result = _wapi_rename (utf8_name, utf8_dest_name);
- errno_copy = errno;
-
- if (result == -1) {
- switch(errno_copy) {
- case EEXIST:
- SetLastError (ERROR_ALREADY_EXISTS);
- break;
-
- case EXDEV:
- /* Ignore here, it is dealt with below */
- break;
-
- case ENOENT:
- /* We already know src exists. Must be dest that doesn't exist. */
- _wapi_set_last_path_error_from_errno (NULL, utf8_dest_name);
- break;
-
- default:
- _wapi_set_last_error_from_errno ();
- }
- }
-
- g_free (utf8_name);
- g_free (utf8_dest_name);
-
- if (result != 0 && errno_copy == EXDEV) {
- if (S_ISDIR (stat_src.st_mode)) {
- SetLastError (ERROR_NOT_SAME_DEVICE);
- return FALSE;
- }
- /* Try a copy to the new location, and delete the source */
- if (CopyFile (name, dest_name, TRUE)==FALSE) {
- /* CopyFile will set the error */
- return(FALSE);
- }
-
- return(DeleteFile (name));
- }
-
- if (result == 0) {
- ret = TRUE;
- }
-
- return(ret);
-}
-
-static gboolean
-write_file (int src_fd, int dest_fd, struct stat *st_src, gboolean report_errors)
-{
- int remain, n;
- char *buf, *wbuf;
- int buf_size = st_src->st_blksize;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : buf_size);
- buf = (char *) g_malloc (buf_size);
-
- for (;;) {
- remain = read (src_fd, buf, buf_size);
- if (remain < 0) {
- if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
- continue;
-
- if (report_errors)
- _wapi_set_last_error_from_errno ();
-
- g_free (buf);
- return FALSE;
- }
- if (remain == 0) {
- break;
- }
-
- wbuf = buf;
- while (remain > 0) {
- if ((n = write (dest_fd, wbuf, remain)) < 0) {
- if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
- continue;
-
- if (report_errors)
- _wapi_set_last_error_from_errno ();
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write failed.", __func__);
- g_free (buf);
- return FALSE;
- }
-
- remain -= n;
- wbuf += n;
- }
- }
-
- g_free (buf);
- return TRUE ;
-}
-
-/**
- * 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)
-{
- gchar *utf8_src, *utf8_dest;
- int src_fd, dest_fd;
- struct stat st, dest_st;
- struct utimbuf dest_time;
- gboolean ret = TRUE;
- int ret_utime;
-
- if(name==NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_src = mono_unicode_to_external (name);
- if (utf8_src == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of source returned NULL",
- __func__);
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- if(dest_name==NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dest is NULL", __func__);
-
- g_free (utf8_src);
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_dest = mono_unicode_to_external (dest_name);
- if (utf8_dest == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of dest returned NULL",
- __func__);
-
- SetLastError (ERROR_INVALID_PARAMETER);
-
- g_free (utf8_src);
-
- return(FALSE);
- }
-
- src_fd = _wapi_open (utf8_src, O_RDONLY, 0);
- if (src_fd < 0) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_src);
-
- g_free (utf8_src);
- g_free (utf8_dest);
-
- return(FALSE);
- }
-
- if (fstat (src_fd, &st) < 0) {
- _wapi_set_last_error_from_errno ();
-
- g_free (utf8_src);
- g_free (utf8_dest);
- close (src_fd);
-
- return(FALSE);
- }
-
- /* Before trying to open/create the dest, we need to report a 'file busy'
- * error if src and dest are actually the same file. We do the check here to take
- * advantage of the IOMAP capability */
- if (!_wapi_stat (utf8_dest, &dest_st) && st.st_dev == dest_st.st_dev &&
- st.st_ino == dest_st.st_ino) {
-
- g_free (utf8_src);
- g_free (utf8_dest);
- close (src_fd);
-
- SetLastError (ERROR_SHARING_VIOLATION);
- return (FALSE);
- }
-
- if (fail_if_exists) {
- dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL, st.st_mode);
- } else {
- /* FIXME: it kinda sucks that this code path potentially scans
- * the directory twice due to the weird SetLastError()
- * behavior. */
- dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode);
- if (dest_fd < 0) {
- /* The file does not exist, try creating it */
- dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode);
- } else {
- /* Apparently this error is set if we
- * overwrite the dest file
- */
- SetLastError (ERROR_ALREADY_EXISTS);
- }
- }
- if (dest_fd < 0) {
- _wapi_set_last_error_from_errno ();
-
- g_free (utf8_src);
- g_free (utf8_dest);
- close (src_fd);
-
- return(FALSE);
- }
-
- if (!write_file (src_fd, dest_fd, &st, TRUE))
- ret = FALSE;
-
- close (src_fd);
- close (dest_fd);
-
- dest_time.modtime = st.st_mtime;
- dest_time.actime = st.st_atime;
- ret_utime = utime (utf8_dest, &dest_time);
- if (ret_utime == -1)
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file [%s] utime failed: %s", __func__, utf8_dest, strerror(errno));
-
- g_free (utf8_src);
- g_free (utf8_dest);
-
- return ret;
-}
-
-static gchar*
-convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name)
-{
- gchar *utf8_ret;
-
- if (arg == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s is NULL", __func__, arg_name);
- SetLastError (ERROR_INVALID_NAME);
- return NULL;
- }
-
- utf8_ret = mono_unicode_to_external (arg);
- if (utf8_ret == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of %s returned NULL",
- __func__, arg_name);
- SetLastError (ERROR_INVALID_PARAMETER);
- return NULL;
- }
-
- return utf8_ret;
-}
-
-gboolean
-ReplaceFile (const gunichar2 *replacedFileName, const gunichar2 *replacementFileName,
- const gunichar2 *backupFileName, guint32 replaceFlags,
- gpointer exclude, gpointer reserved)
-{
- int result, backup_fd = -1,replaced_fd = -1;
- gchar *utf8_replacedFileName, *utf8_replacementFileName = NULL, *utf8_backupFileName = NULL;
- struct stat stBackup;
- gboolean ret = FALSE;
-
- if (!(utf8_replacedFileName = convert_arg_to_utf8 (replacedFileName, "replacedFileName")))
- return FALSE;
- if (!(utf8_replacementFileName = convert_arg_to_utf8 (replacementFileName, "replacementFileName")))
- goto replace_cleanup;
- if (backupFileName != NULL) {
- if (!(utf8_backupFileName = convert_arg_to_utf8 (backupFileName, "backupFileName")))
- goto replace_cleanup;
- }
-
- if (utf8_backupFileName) {
- // Open the backup file for read so we can restore the file if an error occurs.
- backup_fd = _wapi_open (utf8_backupFileName, O_RDONLY, 0);
- result = _wapi_rename (utf8_replacedFileName, utf8_backupFileName);
- if (result == -1)
- goto replace_cleanup;
- }
-
- result = _wapi_rename (utf8_replacementFileName, utf8_replacedFileName);
- if (result == -1) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_replacementFileName);
- _wapi_rename (utf8_backupFileName, utf8_replacedFileName);
- if (backup_fd != -1 && !fstat (backup_fd, &stBackup)) {
- replaced_fd = _wapi_open (utf8_backupFileName, O_WRONLY | O_CREAT | O_TRUNC,
- stBackup.st_mode);
-
- if (replaced_fd == -1)
- goto replace_cleanup;
-
- write_file (backup_fd, replaced_fd, &stBackup, FALSE);
- }
-
- goto replace_cleanup;
- }
-
- ret = TRUE;
-
-replace_cleanup:
- g_free (utf8_replacedFileName);
- g_free (utf8_replacementFileName);
- g_free (utf8_backupFileName);
- if (backup_fd != -1)
- close (backup_fd);
- if (replaced_fd != -1)
- close (replaced_fd);
- return ret;
-}
-
-/**
- * GetStdHandle:
- * @stdhandle: specifies the file descriptor
- *
- * Returns a handle for stdin, stdout, or stderr. Always returns the
- * same handle for the same @stdhandle.
- *
- * Return value: the handle, or %INVALID_HANDLE_VALUE on error
- */
-
-static mono_mutex_t stdhandle_mutex;
-
-gpointer GetStdHandle(WapiStdHandle stdhandle)
-{
- struct _WapiHandle_file *file_handle;
- gpointer handle;
- int fd;
- const gchar *name;
- gboolean ok;
-
- 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:
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unknown standard handle type", __func__);
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return(INVALID_HANDLE_VALUE);
- }
-
- handle = GINT_TO_POINTER (fd);
-
- mono_os_mutex_lock (&stdhandle_mutex);
-
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
- (gpointer *)&file_handle);
- if (ok == FALSE) {
- /* Need to create this console handle */
- handle = _wapi_stdhandle_create (fd, name);
-
- if (handle == INVALID_HANDLE_VALUE) {
- SetLastError (ERROR_NO_MORE_FILES);
- goto done;
- }
- } else {
- /* Add a reference to this handle */
- mono_w32handle_ref (handle);
- }
-
- done:
- mono_os_mutex_unlock (&stdhandle_mutex);
-
- return(handle);
-}
-
-/**
- * ReadFile:
- * @handle: The file handle to read from. The handle must have
- * %GENERIC_READ access.
- * @buffer: The buffer to store read data in
- * @numbytes: The maximum number of bytes to read
- * @bytesread: The actual number of bytes read is stored here. This
- * value can be zero if the handle is positioned at the end of the
- * file.
- * @overlapped: points to a required %WapiOverlapped structure if
- * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
- * otherwise.
- *
- * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
- * function reads up to @numbytes bytes from the file from the current
- * file position, and stores them in @buffer. If there are not enough
- * bytes left in the file, just the amount available will be read.
- * The actual number of bytes read is stored in @bytesread.
-
- * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
- * file position is ignored and the read position is taken from data
- * in the @overlapped structure.
- *
- * Return value: %TRUE if the read succeeds (even if no bytes were
- * read due to an attempt to read past the end of the file), %FALSE on
- * error.
- */
-gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
- guint32 *bytesread, WapiOverlapped *overlapped)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if(io_ops[type].readfile==NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- return(io_ops[type].readfile (handle, buffer, numbytes, bytesread,
- overlapped));
-}
-
-/**
- * WriteFile:
- * @handle: The file handle to write to. The handle must have
- * %GENERIC_WRITE access.
- * @buffer: The buffer to read data from.
- * @numbytes: The maximum number of bytes to write.
- * @byteswritten: The actual number of bytes written is stored here.
- * If the handle is positioned at the file end, the length of the file
- * is extended. This parameter may be %NULL.
- * @overlapped: points to a required %WapiOverlapped structure if
- * @handle has the %FILE_FLAG_OVERLAPPED option set, should be NULL
- * otherwise.
- *
- * If @handle does not have the %FILE_FLAG_OVERLAPPED option set, this
- * function writes up to @numbytes bytes from @buffer to the file at
- * the current file position. If @handle is positioned at the end of
- * the file, the file is extended. The actual number of bytes written
- * is stored in @byteswritten.
- *
- * If @handle has the %FILE_FLAG_OVERLAPPED option set, the current
- * file position is ignored and the write position is taken from data
- * in the @overlapped structure.
- *
- * Return value: %TRUE if the write succeeds, %FALSE on error.
- */
-gboolean WriteFile(gpointer handle, gconstpointer buffer, guint32 numbytes,
- guint32 *byteswritten, WapiOverlapped *overlapped)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if(io_ops[type].writefile==NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- 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)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if(io_ops[type].flushfile==NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- return(io_ops[type].flushfile (handle));
-}
-
-/**
- * SetEndOfFile:
- * @handle: The file handle to set. The handle must have
- * %GENERIC_WRITE access.
- *
- * Moves the end-of-file position to the current position of the file
- * pointer. This function is used to truncate or extend a file.
- *
- * Return value: %TRUE on success, %FALSE otherwise.
- */
-gboolean SetEndOfFile(gpointer handle)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if (io_ops[type].setendoffile == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- return(io_ops[type].setendoffile (handle));
-}
-
-/**
- * SetFilePointer:
- * @handle: The file handle to set. The handle must have
- * %GENERIC_READ or %GENERIC_WRITE access.
- * @movedistance: Low 32 bits of a signed value that specifies the
- * number of bytes to move the file pointer.
- * @highmovedistance: Pointer to the high 32 bits of a signed value
- * that specifies the number of bytes to move the file pointer, or
- * %NULL.
- * @method: The starting point for the file pointer move.
- *
- * Sets the file pointer of an open file.
- *
- * The distance to move the file pointer is calculated from
- * @movedistance and @highmovedistance: If @highmovedistance is %NULL,
- * @movedistance is the 32-bit signed value; otherwise, @movedistance
- * is the low 32 bits and @highmovedistance a pointer to the high 32
- * bits of a 64 bit signed value. A positive distance moves the file
- * pointer forward from the position specified by @method; a negative
- * distance moves the file pointer backward.
- *
- * If the library is compiled without large file support,
- * @highmovedistance is ignored and its value is set to zero on a
- * successful return.
- *
- * Return value: On success, the low 32 bits of the new file pointer.
- * 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(gpointer handle, gint32 movedistance,
- gint32 *highmovedistance, WapiSeekMethod method)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if (io_ops[type].seek == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(INVALID_SET_FILE_POINTER);
- }
-
- return(io_ops[type].seek (handle, movedistance, highmovedistance,
- method));
-}
-
-/**
- * GetFileType:
- * @handle: The file handle to test.
- *
- * Finds the type of file @handle.
- *
- * Return value: %FILE_TYPE_UNKNOWN - the type of the file @handle is
- * unknown. %FILE_TYPE_DISK - @handle is a disk file.
- * %FILE_TYPE_CHAR - @handle is a character device, such as a console.
- * %FILE_TYPE_PIPE - @handle is a named or anonymous pipe.
- */
-WapiFileType GetFileType(gpointer handle)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if (io_ops[type].getfiletype == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(FILE_TYPE_UNKNOWN);
- }
-
- return(io_ops[type].getfiletype ());
-}
-
-/**
- * GetFileSize:
- * @handle: The file handle to query. The handle must have
- * %GENERIC_READ or %GENERIC_WRITE access.
- * @highsize: If non-%NULL, the high 32 bits of the file size are
- * stored here.
- *
- * Retrieves the size of the file @handle.
- *
- * If the library is compiled without large file support, @highsize
- * has its value set to zero on a successful return.
- *
- * Return value: On success, the low 32 bits of the file size. If
- * @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(gpointer handle, guint32 *highsize)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if (io_ops[type].getfilesize == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(INVALID_FILE_SIZE);
- }
-
- return(io_ops[type].getfilesize (handle, highsize));
-}
-
-/**
- * GetFileTime:
- * @handle: The file handle to query. The handle must have
- * %GENERIC_READ access.
- * @create_time: Points to a %WapiFileTime structure to receive the
- * number of ticks since the epoch that file was created. May be
- * %NULL.
- * @last_access: Points to a %WapiFileTime structure to receive the
- * number of ticks since the epoch when file was last accessed. May be
- * %NULL.
- * @last_write: Points to a %WapiFileTime structure to receive the
- * number of ticks since the epoch when file was last written to. May
- * be %NULL.
- *
- * Finds the number of ticks since the epoch that the file referenced
- * by @handle was created, last accessed and last modified. A tick is
- * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
- * GMT.
- *
- * Create time isn't recorded on POSIX file systems or reported by
- * stat(2), so that time is guessed by returning the oldest of the
- * other times.
- *
- * Return value: %TRUE on success, %FALSE otherwise.
- */
-gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
- WapiFileTime *last_access, WapiFileTime *last_write)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if (io_ops[type].getfiletime == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- return(io_ops[type].getfiletime (handle, create_time, last_access,
- last_write));
-}
-
-/**
- * SetFileTime:
- * @handle: The file handle to set. The handle must have
- * %GENERIC_WRITE access.
- * @create_time: Points to a %WapiFileTime structure that contains the
- * number of ticks since the epoch that the file was created. May be
- * %NULL.
- * @last_access: Points to a %WapiFileTime structure that contains the
- * number of ticks since the epoch when the file was last accessed.
- * May be %NULL.
- * @last_write: Points to a %WapiFileTime structure that contains the
- * number of ticks since the epoch when the file was last written to.
- * May be %NULL.
- *
- * Sets the number of ticks since the epoch that the file referenced
- * by @handle was created, last accessed or last modified. A tick is
- * a 100 nanosecond interval. The epoch is Midnight, January 1 1601
- * GMT.
- *
- * Create time isn't recorded on POSIX file systems, and is ignored.
- *
- * Return value: %TRUE on success, %FALSE otherwise.
- */
-gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
- const WapiFileTime *last_access,
- const WapiFileTime *last_write)
-{
- MonoW32HandleType type;
-
- type = mono_w32handle_get_type (handle);
-
- if (io_ops[type].setfiletime == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- return(io_ops[type].setfiletime (handle, create_time, last_access,
- last_write));
-}
-
-/* A tick is a 100-nanosecond interval. File time epoch is Midnight,
- * January 1 1601 GMT
- */
-
-#define TICKS_PER_MILLISECOND 10000L
-#define TICKS_PER_SECOND 10000000L
-#define TICKS_PER_MINUTE 600000000L
-#define TICKS_PER_HOUR 36000000000LL
-#define TICKS_PER_DAY 864000000000LL
-
-#define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
-
-static const guint16 mon_yday[2][13]={
- {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
- {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
-};
-
-/**
- * FileTimeToSystemTime:
- * @file_time: Points to a %WapiFileTime structure that contains the
- * number of ticks to convert.
- * @system_time: Points to a %WapiSystemTime structure to receive the
- * broken-out time.
- *
- * Converts a tick count into broken-out time values.
- *
- * Return value: %TRUE on success, %FALSE otherwise.
- */
-gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
- WapiSystemTime *system_time)
-{
- gint64 file_ticks, totaldays, rem, y;
- const guint16 *ip;
-
- if(system_time==NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: system_time NULL", __func__);
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- file_ticks=((gint64)file_time->dwHighDateTime << 32) +
- file_time->dwLowDateTime;
-
- /* Really compares if file_ticks>=0x8000000000000000
- * (LLONG_MAX+1) but we're working with a signed value for the
- * year and day calculation to work later
- */
- if(file_ticks<0) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file_time too big", __func__);
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- totaldays=(file_ticks / TICKS_PER_DAY);
- rem = file_ticks % TICKS_PER_DAY;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %lld rem: %lld", __func__, totaldays, rem);
-
- system_time->wHour=rem/TICKS_PER_HOUR;
- rem %= TICKS_PER_HOUR;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hour: %d rem: %lld", __func__, system_time->wHour, rem);
-
- system_time->wMinute = rem / TICKS_PER_MINUTE;
- rem %= TICKS_PER_MINUTE;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Minute: %d rem: %lld", __func__, system_time->wMinute,
- rem);
-
- system_time->wSecond = rem / TICKS_PER_SECOND;
- rem %= TICKS_PER_SECOND;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Second: %d rem: %lld", __func__, system_time->wSecond,
- rem);
-
- system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Milliseconds: %d", __func__,
- system_time->wMilliseconds);
-
- /* January 1, 1601 was a Monday, according to Emacs calendar */
- system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Day of week: %d", __func__, system_time->wDayOfWeek);
-
- /* This algorithm to find year and month given days from epoch
- * from glibc
- */
- y=1601;
-
-#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
-#define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400))
-
- while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
- /* Guess a corrected year, assuming 365 days per year */
- gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %lld yg: %lld y: %lld", __func__,
- totaldays, yg,
- y);
- g_message("%s: LEAPS(yg): %lld LEAPS(y): %lld", __func__,
- LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
-
- /* Adjust days and y to match the guessed year. */
- totaldays -= ((yg - y) * 365
- + LEAPS_THRU_END_OF (yg - 1)
- - LEAPS_THRU_END_OF (y - 1));
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %lld", __func__, totaldays);
- y = yg;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: y: %lld", __func__, y);
- }
-
- system_time->wYear = y;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Year: %d", __func__, system_time->wYear);
-
- ip = mon_yday[isleap(y)];
-
- for(y=11; totaldays < ip[y]; --y) {
- continue;
- }
- totaldays-=ip[y];
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %lld", __func__, totaldays);
-
- system_time->wMonth = y + 1;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Month: %d", __func__, system_time->wMonth);
-
- system_time->wDay = totaldays + 1;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Day: %d", __func__, system_time->wDay);
-
- return(TRUE);
-}
-
-gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
-{
- struct _WapiHandle_find find_handle = {0};
- gpointer handle;
- gchar *utf8_pattern = NULL, *dir_part, *entry_part;
- int result;
-
- if (pattern == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pattern is NULL", __func__);
-
- SetLastError (ERROR_PATH_NOT_FOUND);
- return(INVALID_HANDLE_VALUE);
- }
-
- utf8_pattern = mono_unicode_to_external (pattern);
- if (utf8_pattern == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(INVALID_HANDLE_VALUE);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking for [%s]", __func__, utf8_pattern);
-
- /* Figure out which bit of the pattern is the directory */
- dir_part = _wapi_dirname (utf8_pattern);
- entry_part = _wapi_basename (utf8_pattern);
-
-#if 0
- /* Don't do this check for now, it breaks if directories
- * really do have metachars in their names (see bug 58116).
- * FIXME: Figure out a better solution to keep some checks...
- */
- if (strchr (dir_part, '*') || strchr (dir_part, '?')) {
- SetLastError (ERROR_INVALID_NAME);
- g_free (dir_part);
- g_free (entry_part);
- g_free (utf8_pattern);
- return(INVALID_HANDLE_VALUE);
- }
-#endif
-
- /* The pattern can specify a directory or a set of files.
- *
- * The pattern can have wildcard characters ? and *, but only
- * in the section after the last directory delimiter. (Return
- * ERROR_INVALID_NAME if there are wildcards in earlier path
- * sections.) "*" has the usual 0-or-more chars meaning. "?"
- * means "match one character", "??" seems to mean "match one
- * or two characters", "???" seems to mean "match one, two or
- * three characters", etc. Windows will also try and match
- * the mangled "short name" of files, so 8 character patterns
- * with wildcards will show some surprising results.
- *
- * All the written documentation I can find says that '?'
- * should only match one character, and doesn't mention '??',
- * '???' etc. I'm going to assume that the strict behaviour
- * (ie '???' means three and only three characters) is the
- * correct one, because that lets me use fnmatch(3) rather
- * than mess around with regexes.
- */
-
- find_handle.namelist = NULL;
- result = _wapi_io_scandir (dir_part, entry_part,
- &find_handle.namelist);
-
- if (result == 0) {
- /* No files, which windows seems to call
- * FILE_NOT_FOUND
- */
- SetLastError (ERROR_FILE_NOT_FOUND);
- g_free (utf8_pattern);
- g_free (entry_part);
- g_free (dir_part);
- return (INVALID_HANDLE_VALUE);
- }
-
- if (result < 0) {
- _wapi_set_last_path_error_from_errno (dir_part, NULL);
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: scandir error: %s", __func__, g_strerror (errno));
- g_free (utf8_pattern);
- g_free (entry_part);
- g_free (dir_part);
- return (INVALID_HANDLE_VALUE);
- }
-
- g_free (utf8_pattern);
- g_free (entry_part);
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Got %d matches", __func__, result);
-
- find_handle.dir_part = dir_part;
- find_handle.num = result;
- find_handle.count = 0;
-
- handle = mono_w32handle_new (MONO_W32HANDLE_FIND, &find_handle);
- if (handle == INVALID_HANDLE_VALUE) {
- g_warning ("%s: error creating find handle", __func__);
- g_free (dir_part);
- g_free (entry_part);
- g_free (utf8_pattern);
- SetLastError (ERROR_GEN_FAILURE);
-
- return(INVALID_HANDLE_VALUE);
- }
-
- if (handle != INVALID_HANDLE_VALUE &&
- !FindNextFile (handle, find_data)) {
- FindClose (handle);
- SetLastError (ERROR_NO_MORE_FILES);
- handle = INVALID_HANDLE_VALUE;
- }
-
- return (handle);
-}
-
-gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
-{
- struct _WapiHandle_find *find_handle;
- gboolean ok;
- struct stat buf, linkbuf;
- int result;
- gchar *filename;
- gchar *utf8_filename, *utf8_basename;
- gunichar2 *utf16_basename;
- time_t create_time;
- glong bytes;
- gboolean ret = FALSE;
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FIND,
- (gpointer *)&find_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up find handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- mono_w32handle_lock_handle (handle);
-
-retry:
- if (find_handle->count >= find_handle->num) {
- SetLastError (ERROR_NO_MORE_FILES);
- goto cleanup;
- }
-
- /* stat next match */
-
- filename = g_build_filename (find_handle->dir_part, find_handle->namelist[find_handle->count ++], NULL);
-
- result = _wapi_stat (filename, &buf);
- if (result == -1 && errno == ENOENT) {
- /* Might be a dangling symlink */
- result = _wapi_lstat (filename, &buf);
- }
-
- if (result != 0) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: stat failed: %s", __func__, filename);
-
- g_free (filename);
- goto retry;
- }
-
-#ifndef __native_client__
- result = _wapi_lstat (filename, &linkbuf);
- if (result != 0) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lstat failed: %s", __func__, filename);
-
- g_free (filename);
- goto retry;
- }
-#endif
-
- utf8_filename = mono_utf8_from_external (filename);
- if (utf8_filename == NULL) {
- /* We couldn't turn this filename into utf8 (eg the
- * encoding of the name wasn't convertible), so just
- * ignore it.
- */
- g_warning ("%s: Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODINGS\n", __func__, filename);
-
- g_free (filename);
- goto retry;
- }
- g_free (filename);
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Found [%s]", __func__, utf8_filename);
-
- /* fill data block */
-
- if (buf.st_mtime < buf.st_ctime)
- create_time = buf.st_mtime;
- else
- create_time = buf.st_ctime;
-
-#ifdef __native_client__
- find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, NULL);
-#else
- find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, &linkbuf);
-#endif
-
- time_t_to_filetime (create_time, &find_data->ftCreationTime);
- time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
- 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;
-
- utf8_basename = _wapi_basename (utf8_filename);
- utf16_basename = g_utf8_to_utf16 (utf8_basename, -1, NULL, &bytes,
- NULL);
- if(utf16_basename==NULL) {
- g_free (utf8_basename);
- g_free (utf8_filename);
- goto retry;
- }
- ret = TRUE;
-
- /* utf16 is 2 * utf8 */
- bytes *= 2;
-
- memset (find_data->cFileName, '\0', (MAX_PATH*2));
-
- /* Truncating a utf16 string like this might leave the last
- * char incomplete
- */
- memcpy (find_data->cFileName, utf16_basename,
- bytes<(MAX_PATH*2)-2?bytes:(MAX_PATH*2)-2);
-
- find_data->cAlternateFileName [0] = 0; /* not used */
-
- g_free (utf8_basename);
- g_free (utf8_filename);
- g_free (utf16_basename);
-
-cleanup:
- mono_w32handle_unlock_handle (handle);
-
- return(ret);
-}
-
-/**
- * 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;
-
- if (handle == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FIND,
- (gpointer *)&find_handle);
- if(ok==FALSE) {
- g_warning ("%s: error looking up find handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- mono_w32handle_lock_handle (handle);
-
- g_strfreev (find_handle->namelist);
- g_free (find_handle->dir_part);
-
- mono_w32handle_unlock_handle (handle);
-
- mono_w32handle_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;
-
- if (name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_name = mono_unicode_to_external (name);
- if (utf8_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return FALSE;
- }
-
- result = _wapi_mkdir (utf8_name, 0777);
-
- if (result == 0) {
- g_free (utf8_name);
- return TRUE;
- }
-
- _wapi_set_last_path_error_from_errno (NULL, utf8_name);
- g_free (utf8_name);
- 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;
-
- if (name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_name = mono_unicode_to_external (name);
- if (utf8_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return FALSE;
- }
-
- result = _wapi_rmdir (utf8_name);
- if (result == -1) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_name);
- g_free (utf8_name);
-
- return(FALSE);
- }
- g_free (utf8_name);
-
- return(TRUE);
-}
-
-/**
- * GetFileAttributes:
- * @name: a pointer to a NULL-terminated unicode filename.
- *
- * Gets the attributes for @name;
- *
- * Return value: %INVALID_FILE_ATTRIBUTES on failure
- */
-guint32 GetFileAttributes (const gunichar2 *name)
-{
- gchar *utf8_name;
- struct stat buf, linkbuf;
- int result;
- guint32 ret;
-
- if (name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_name = mono_unicode_to_external (name);
- if (utf8_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return (INVALID_FILE_ATTRIBUTES);
- }
-
- result = _wapi_stat (utf8_name, &buf);
- if (result == -1 && errno == ENOENT) {
- /* Might be a dangling symlink... */
- result = _wapi_lstat (utf8_name, &buf);
- }
-
- if (result != 0) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_name);
- g_free (utf8_name);
- return (INVALID_FILE_ATTRIBUTES);
- }
-
-#ifndef __native_client__
- result = _wapi_lstat (utf8_name, &linkbuf);
- if (result != 0) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_name);
- g_free (utf8_name);
- return (INVALID_FILE_ATTRIBUTES);
- }
-#endif
-
-#ifdef __native_client__
- ret = _wapi_stat_to_file_attributes (utf8_name, &buf, NULL);
-#else
- ret = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf);
-#endif
-
- g_free (utf8_name);
-
- return(ret);
-}
-
-/**
- * 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, linkbuf;
- time_t create_time;
- int result;
-
- if (level != GetFileExInfoStandard) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: info level %d not supported.", __func__,
- level);
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if (name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_name = mono_unicode_to_external (name);
- if (utf8_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- result = _wapi_stat (utf8_name, &buf);
- if (result == -1 && errno == ENOENT) {
- /* Might be a dangling symlink... */
- result = _wapi_lstat (utf8_name, &buf);
- }
-
- if (result != 0) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_name);
- g_free (utf8_name);
- return FALSE;
- }
-
- result = _wapi_lstat (utf8_name, &linkbuf);
- if (result != 0) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_name);
- g_free (utf8_name);
- 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 (utf8_name,
- &buf,
- &linkbuf);
-
- g_free (utf8_name);
-
- time_t_to_filetime (create_time, &data->ftCreationTime);
- time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
- 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 */
- gchar *utf8_name;
- struct stat buf;
- int result;
-
- /*
- * Currently we only handle one *internal* case, with a value that is
- * not standard: 0x80000000, which means `set executable bit'
- */
-
- if (name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
-
- utf8_name = mono_unicode_to_external (name);
- if (utf8_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return FALSE;
- }
-
- result = _wapi_stat (utf8_name, &buf);
- if (result == -1 && errno == ENOENT) {
- /* Might be a dangling symlink... */
- result = _wapi_lstat (utf8_name, &buf);
- }
-
- if (result != 0) {
- _wapi_set_last_path_error_from_errno (NULL, utf8_name);
- g_free (utf8_name);
- return FALSE;
- }
-
- /* Contrary to the documentation, ms allows NORMAL to be
- * specified along with other attributes, so dont bother to
- * catch that case here.
- */
- if (attrs & FILE_ATTRIBUTE_READONLY) {
- result = _wapi_chmod (utf8_name, buf.st_mode & ~(S_IWUSR | S_IWOTH | S_IWGRP));
- } else {
- result = _wapi_chmod (utf8_name, buf.st_mode | S_IWUSR);
- }
-
- /* Ignore the other attributes for now */
-
- if (attrs & 0x80000000){
- mode_t exec_mask = 0;
-
- if ((buf.st_mode & S_IRUSR) != 0)
- exec_mask |= S_IXUSR;
-
- if ((buf.st_mode & S_IRGRP) != 0)
- exec_mask |= S_IXGRP;
-
- if ((buf.st_mode & S_IROTH) != 0)
- exec_mask |= S_IXOTH;
-
- result = chmod (utf8_name, buf.st_mode | exec_mask);
- }
- /* Don't bother to reset executable (might need to change this
- * policy)
- */
-
- g_free (utf8_name);
-
- return(TRUE);
-}
-
-/**
- * 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)
-{
- gunichar2 *utf16_path;
- glong count;
- gsize bytes;
-
-#ifdef __native_client__
- gchar *path = g_get_current_dir ();
- if (length < strlen(path) + 1 || path == NULL)
- return 0;
- memcpy (buffer, path, strlen(path) + 1);
-#else
- if (getcwd ((char*)buffer, length) == NULL) {
- if (errno == ERANGE) { /*buffer length is not big enough */
- gchar *path = g_get_current_dir (); /*FIXME g_get_current_dir doesn't work with broken paths and calling it just to know the path length is silly*/
- if (path == NULL)
- return 0;
- utf16_path = mono_unicode_from_external (path, &bytes);
- g_free (utf16_path);
- g_free (path);
- return (bytes/2)+1;
- }
- _wapi_set_last_error_from_errno ();
- return 0;
- }
-#endif
-
- utf16_path = mono_unicode_from_external ((gchar*)buffer, &bytes);
- count = (bytes/2)+1;
- g_assert (count <= length); /*getcwd must have failed before with ERANGE*/
-
- /* Add the terminator */
- memset (buffer, '\0', bytes+2);
- memcpy (buffer, utf16_path, bytes);
-
- g_free (utf16_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;
-
- if (path == NULL) {
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- utf8_path = mono_unicode_to_external (path);
- if (_wapi_chdir (utf8_path) != 0) {
- _wapi_set_last_error_from_errno ();
- result = FALSE;
- }
- else
- result = TRUE;
-
- g_free (utf8_path);
- return result;
-}
-
-gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
- WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 size)
-{
- struct _WapiHandle_file pipe_read_handle = {0};
- struct _WapiHandle_file pipe_write_handle = {0};
- gpointer read_handle;
- gpointer write_handle;
- int filedes[2];
- int ret;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating pipe", __func__);
-
- ret=pipe (filedes);
- if(ret==-1) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error creating pipe: %s", __func__,
- strerror (errno));
-
- _wapi_set_last_error_from_errno ();
- return(FALSE);
- }
-
- if (filedes[0] >= mono_w32handle_fd_reserve ||
- filedes[1] >= mono_w32handle_fd_reserve) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
-
- SetLastError (ERROR_TOO_MANY_OPEN_FILES);
-
- close (filedes[0]);
- close (filedes[1]);
-
- return(FALSE);
- }
-
- /* filedes[0] is open for reading, filedes[1] for writing */
-
- pipe_read_handle.fd = filedes [0];
- pipe_read_handle.fileaccess = GENERIC_READ;
- read_handle = mono_w32handle_new_fd (MONO_W32HANDLE_PIPE, filedes[0],
- &pipe_read_handle);
- if (read_handle == INVALID_HANDLE_VALUE) {
- g_warning ("%s: error creating pipe read handle", __func__);
- close (filedes[0]);
- close (filedes[1]);
- SetLastError (ERROR_GEN_FAILURE);
-
- return(FALSE);
- }
-
- pipe_write_handle.fd = filedes [1];
- pipe_write_handle.fileaccess = GENERIC_WRITE;
- write_handle = mono_w32handle_new_fd (MONO_W32HANDLE_PIPE, filedes[1],
- &pipe_write_handle);
- if (write_handle == INVALID_HANDLE_VALUE) {
- g_warning ("%s: error creating pipe write handle", __func__);
- mono_w32handle_unref (read_handle);
-
- close (filedes[0]);
- close (filedes[1]);
- SetLastError (ERROR_GEN_FAILURE);
-
- return(FALSE);
- }
-
- *readpipe = read_handle;
- *writepipe = write_handle;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning pipe: read handle %p, write handle %p",
- __func__, read_handle, write_handle);
-
- return(TRUE);
-}
-
-#ifdef HAVE_GETFSSTAT
-/* Darwin has getfsstat */
-gint32 GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
-{
- struct statfs *stats;
- int size, n, i;
- gunichar2 *dir;
- glong length, total = 0;
-
- n = getfsstat (NULL, 0, MNT_NOWAIT);
- if (n == -1)
- return 0;
- size = n * sizeof (struct statfs);
- stats = (struct statfs *) g_malloc (size);
- if (stats == NULL)
- return 0;
- if (getfsstat (stats, size, MNT_NOWAIT) == -1){
- g_free (stats);
- return 0;
- }
- for (i = 0; i < n; i++){
- dir = g_utf8_to_utf16 (stats [i].f_mntonname, -1, NULL, &length, NULL);
- if (total + length < len){
- memcpy (buf + total, dir, sizeof (gunichar2) * length);
- buf [total+length] = 0;
- }
- g_free (dir);
- total += length + 1;
- }
- if (total < len)
- buf [total] = 0;
- total++;
- g_free (stats);
- return total;
-}
-#else
-/* In-place octal sequence replacement */
-static void
-unescape_octal (gchar *str)
-{
- gchar *rptr;
- gchar *wptr;
-
- if (str == NULL)
- return;
-
- rptr = wptr = str;
- while (*rptr != '\0') {
- if (*rptr == '\\') {
- char c;
- rptr++;
- c = (*(rptr++) - '0') << 6;
- c += (*(rptr++) - '0') << 3;
- c += *(rptr++) - '0';
- *wptr++ = c;
- } else if (wptr != rptr) {
- *wptr++ = *rptr++;
- } else {
- rptr++; wptr++;
- }
- }
- *wptr = '\0';
-}
-static gint32 GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf);
-
-#if __linux__
-#define GET_LOGICAL_DRIVE_STRINGS_BUFFER 512
-#define GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER 512
-#define GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER 64
-
-typedef struct
-{
- glong total;
- guint32 buffer_index;
- guint32 mountpoint_index;
- guint32 field_number;
- guint32 allocated_size;
- guint32 fsname_index;
- guint32 fstype_index;
- gchar mountpoint [GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER + 1];
- gchar *mountpoint_allocated;
- gchar buffer [GET_LOGICAL_DRIVE_STRINGS_BUFFER];
- gchar fsname [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1];
- gchar fstype [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1];
- ssize_t nbytes;
- gchar delimiter;
- gboolean check_mount_source;
-} LinuxMountInfoParseState;
-
-static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
-static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
-static void append_to_mountpoint (LinuxMountInfoParseState *state);
-static gboolean add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
-
-gint32 GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
-{
- int fd;
- gint32 ret = 0;
- LinuxMountInfoParseState state;
- gboolean (*parser)(guint32, gunichar2*, LinuxMountInfoParseState*) = NULL;
-
- memset (buf, 0, len * sizeof (gunichar2));
- fd = open ("/proc/self/mountinfo", O_RDONLY);
- if (fd != -1)
- parser = GetLogicalDriveStrings_MountInfo;
- else {
- fd = open ("/proc/mounts", O_RDONLY);
- if (fd != -1)
- parser = GetLogicalDriveStrings_Mounts;
- }
-
- if (!parser) {
- ret = GetLogicalDriveStrings_Mtab (len, buf);
- goto done_and_out;
- }
-
- memset (&state, 0, sizeof (LinuxMountInfoParseState));
- state.field_number = 1;
- state.delimiter = ' ';
-
- while ((state.nbytes = read (fd, state.buffer, GET_LOGICAL_DRIVE_STRINGS_BUFFER)) > 0) {
- state.buffer_index = 0;
-
- while ((*parser)(len, buf, &state)) {
- if (state.buffer [state.buffer_index] == '\n') {
- gboolean quit = add_drive_string (len, buf, &state);
- state.field_number = 1;
- state.buffer_index++;
- if (state.mountpoint_allocated) {
- g_free (state.mountpoint_allocated);
- state.mountpoint_allocated = NULL;
- }
- if (quit) {
- ret = state.total;
- goto done_and_out;
- }
- }
- }
- };
- ret = state.total;
-
- done_and_out:
- if (fd != -1)
- close (fd);
- return ret;
-}
-
-static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
-{
- gchar *ptr;
-
- if (state->field_number == 1)
- state->check_mount_source = TRUE;
-
- while (state->buffer_index < (guint32)state->nbytes) {
- if (state->buffer [state->buffer_index] == state->delimiter) {
- state->field_number++;
- switch (state->field_number) {
- case 2:
- state->mountpoint_index = 0;
- break;
-
- case 3:
- if (state->mountpoint_allocated)
- state->mountpoint_allocated [state->mountpoint_index] = 0;
- else
- state->mountpoint [state->mountpoint_index] = 0;
- break;
-
- default:
- ptr = (gchar*)memchr (state->buffer + state->buffer_index, '\n', GET_LOGICAL_DRIVE_STRINGS_BUFFER - state->buffer_index);
- if (ptr)
- state->buffer_index = (ptr - (gchar*)state->buffer) - 1;
- else
- state->buffer_index = state->nbytes;
- return TRUE;
- }
- state->buffer_index++;
- continue;
- } else if (state->buffer [state->buffer_index] == '\n')
- return TRUE;
-
- switch (state->field_number) {
- case 1:
- if (state->check_mount_source) {
- if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') {
- /* We can ignore the rest, it's a device
- * path */
- state->check_mount_source = FALSE;
- state->fsname [state->fsname_index++] = '/';
- break;
- }
- if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
- state->fsname [state->fsname_index++] = state->buffer [state->buffer_index];
- }
- break;
-
- case 2:
- append_to_mountpoint (state);
- break;
-
- case 3:
- if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
- state->fstype [state->fstype_index++] = state->buffer [state->buffer_index];
- break;
- }
-
- state->buffer_index++;
- }
-
- return FALSE;
-}
-
-static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
-{
- while (state->buffer_index < (guint32)state->nbytes) {
- if (state->buffer [state->buffer_index] == state->delimiter) {
- state->field_number++;
- switch (state->field_number) {
- case 5:
- state->mountpoint_index = 0;
- break;
-
- case 6:
- if (state->mountpoint_allocated)
- state->mountpoint_allocated [state->mountpoint_index] = 0;
- else
- state->mountpoint [state->mountpoint_index] = 0;
- break;
-
- case 7:
- state->delimiter = '-';
- break;
-
- case 8:
- state->delimiter = ' ';
- break;
-
- case 10:
- state->check_mount_source = TRUE;
- break;
- }
- state->buffer_index++;
- continue;
- } else if (state->buffer [state->buffer_index] == '\n')
- return TRUE;
-
- switch (state->field_number) {
- case 5:
- append_to_mountpoint (state);
- break;
-
- case 9:
- if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
- state->fstype [state->fstype_index++] = state->buffer [state->buffer_index];
- break;
-
- case 10:
- if (state->check_mount_source) {
- if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') {
- /* We can ignore the rest, it's a device
- * path */
- state->check_mount_source = FALSE;
- state->fsname [state->fsname_index++] = '/';
- break;
- }
- if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
- state->fsname [state->fsname_index++] = state->buffer [state->buffer_index];
- }
- break;
- }
-
- state->buffer_index++;
- }
-
- return FALSE;
-}
-
-static void
-append_to_mountpoint (LinuxMountInfoParseState *state)
-{
- gchar ch = state->buffer [state->buffer_index];
- if (state->mountpoint_allocated) {
- if (state->mountpoint_index >= state->allocated_size) {
- guint32 newsize = (state->allocated_size << 1) + 1;
- gchar *newbuf = (gchar *)g_malloc0 (newsize * sizeof (gchar));
-
- memcpy (newbuf, state->mountpoint_allocated, state->mountpoint_index);
- g_free (state->mountpoint_allocated);
- state->mountpoint_allocated = newbuf;
- state->allocated_size = newsize;
- }
- state->mountpoint_allocated [state->mountpoint_index++] = ch;
- } else {
- if (state->mountpoint_index >= GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER) {
- state->allocated_size = (state->mountpoint_index << 1) + 1;
- state->mountpoint_allocated = (gchar *)g_malloc0 (state->allocated_size * sizeof (gchar));
- memcpy (state->mountpoint_allocated, state->mountpoint, state->mountpoint_index);
- state->mountpoint_allocated [state->mountpoint_index++] = ch;
- } else
- state->mountpoint [state->mountpoint_index++] = ch;
- }
-}
-
-static gboolean
-add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
-{
- gboolean quit = FALSE;
- gboolean ignore_entry;
-
- if (state->fsname_index == 1 && state->fsname [0] == '/')
- ignore_entry = FALSE;
- else if (memcmp ("overlay", state->fsname, state->fsname_index) == 0 ||
- memcmp ("aufs", state->fstype, state->fstype_index) == 0) {
- /* Don't ignore overlayfs and aufs - these might be used on Docker
- * (https://bugzilla.xamarin.com/show_bug.cgi?id=31021) */
- ignore_entry = FALSE;
- } else if (state->fsname_index == 0 || memcmp ("none", state->fsname, state->fsname_index) == 0) {
- ignore_entry = TRUE;
- } else if (state->fstype_index >= 5 && memcmp ("fuse.", state->fstype, 5) == 0) {
- /* Ignore GNOME's gvfs */
- if (state->fstype_index == 21 && memcmp ("fuse.gvfs-fuse-daemon", state->fstype, state->fstype_index) == 0)
- ignore_entry = TRUE;
- else
- ignore_entry = FALSE;
- } else if (state->fstype_index == 3 && memcmp ("nfs", state->fstype, state->fstype_index) == 0)
- ignore_entry = FALSE;
- else
- ignore_entry = TRUE;
-
- if (!ignore_entry) {
- gunichar2 *dir;
- glong length;
- gchar *mountpoint = state->mountpoint_allocated ? state->mountpoint_allocated : state->mountpoint;
-
- unescape_octal (mountpoint);
- dir = g_utf8_to_utf16 (mountpoint, -1, NULL, &length, NULL);
- if (state->total + length + 1 > len) {
- quit = TRUE;
- state->total = len * 2;
- } else {
- length++;
- memcpy (buf + state->total, dir, sizeof (gunichar2) * length);
- state->total += length;
- }
- g_free (dir);
- }
- state->fsname_index = 0;
- state->fstype_index = 0;
-
- return quit;
-}
-#else
-gint32
-GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
-{
- return GetLogicalDriveStrings_Mtab (len, buf);
-}
-#endif
-static gint32
-GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
-{
- FILE *fp;
- gunichar2 *ptr, *dir;
- glong length, total = 0;
- gchar buffer [512];
- gchar **splitted;
-
- memset (buf, 0, sizeof (gunichar2) * (len + 1));
- buf [0] = '/';
- buf [1] = 0;
- buf [2] = 0;
-
- /* Sigh, mntent and friends don't work well.
- * It stops on the first line that doesn't begin with a '/'.
- * (linux 2.6.5, libc 2.3.2.ds1-12) - Gonz */
- fp = fopen ("/etc/mtab", "rt");
- if (fp == NULL) {
- fp = fopen ("/etc/mnttab", "rt");
- if (fp == NULL)
- return 1;
- }
-
- ptr = buf;
- while (fgets (buffer, 512, fp) != NULL) {
- if (*buffer != '/')
- continue;
-
- splitted = g_strsplit (buffer, " ", 0);
- if (!*splitted || !*(splitted + 1)) {
- g_strfreev (splitted);
- continue;
- }
-
- unescape_octal (*(splitted + 1));
- dir = g_utf8_to_utf16 (*(splitted + 1), -1, NULL, &length, NULL);
- g_strfreev (splitted);
- if (total + length + 1 > len) {
- fclose (fp);
- g_free (dir);
- return len * 2; /* guess */
- }
-
- memcpy (ptr + total, dir, sizeof (gunichar2) * length);
- g_free (dir);
- total += length + 1;
- }
-
- fclose (fp);
- return total;
-/* Commented out, does not work with my mtab!!! - Gonz */
-#ifdef NOTENABLED /* HAVE_MNTENT_H */
-{
- FILE *fp;
- struct mntent *mnt;
- gunichar2 *ptr, *dir;
- glong len, total = 0;
-
-
- fp = setmntent ("/etc/mtab", "rt");
- if (fp == NULL) {
- fp = setmntent ("/etc/mnttab", "rt");
- if (fp == NULL)
- return;
- }
-
- ptr = buf;
- while ((mnt = getmntent (fp)) != NULL) {
- g_print ("GOT %s\n", mnt->mnt_dir);
- dir = g_utf8_to_utf16 (mnt->mnt_dir, &len, NULL, NULL, NULL);
- if (total + len + 1 > len) {
- return len * 2; /* guess */
- }
-
- memcpy (ptr + total, dir, sizeof (gunichar2) * len);
- g_free (dir);
- total += len + 1;
- }
-
- endmntent (fp);
- return total;
-}
-#endif
-}
-#endif
-
-#if defined(HAVE_STATVFS) || defined(HAVE_STATFS)
-gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, ULARGE_INTEGER *free_bytes_avail,
- ULARGE_INTEGER *total_number_of_bytes,
- ULARGE_INTEGER *total_number_of_free_bytes)
-{
-#ifdef HAVE_STATVFS
- struct statvfs fsstat;
-#elif defined(HAVE_STATFS)
- struct statfs fsstat;
-#endif
- gboolean isreadonly;
- gchar *utf8_path_name;
- int ret;
- unsigned long block_size;
-
- if (path_name == NULL) {
- utf8_path_name = g_strdup (g_get_current_dir());
- if (utf8_path_name == NULL) {
- SetLastError (ERROR_DIRECTORY);
- return(FALSE);
- }
- }
- else {
- utf8_path_name = mono_unicode_to_external (path_name);
- if (utf8_path_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
-
- SetLastError (ERROR_INVALID_NAME);
- return(FALSE);
- }
- }
-
- do {
-#ifdef HAVE_STATVFS
- ret = statvfs (utf8_path_name, &fsstat);
- isreadonly = ((fsstat.f_flag & ST_RDONLY) == ST_RDONLY);
- block_size = fsstat.f_frsize;
-#elif defined(HAVE_STATFS)
- ret = statfs (utf8_path_name, &fsstat);
-#if defined (MNT_RDONLY)
- isreadonly = ((fsstat.f_flags & MNT_RDONLY) == MNT_RDONLY);
-#elif defined (MS_RDONLY)
- isreadonly = ((fsstat.f_flags & MS_RDONLY) == MS_RDONLY);
-#endif
- block_size = fsstat.f_bsize;
-#endif
- } while(ret == -1 && errno == EINTR);
-
- g_free(utf8_path_name);
-
- if (ret == -1) {
- _wapi_set_last_error_from_errno ();
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: statvfs failed: %s", __func__, strerror (errno));
- return(FALSE);
- }
-
- /* total number of free bytes for non-root */
- if (free_bytes_avail != NULL) {
- if (isreadonly) {
- free_bytes_avail->QuadPart = 0;
- }
- else {
- free_bytes_avail->QuadPart = block_size * (guint64)fsstat.f_bavail;
- }
- }
-
- /* total number of bytes available for non-root */
- if (total_number_of_bytes != NULL) {
- total_number_of_bytes->QuadPart = block_size * (guint64)fsstat.f_blocks;
- }
-
- /* total number of bytes available for root */
- if (total_number_of_free_bytes != NULL) {
- if (isreadonly) {
- total_number_of_free_bytes->QuadPart = 0;
- }
- else {
- total_number_of_free_bytes->QuadPart = block_size * (guint64)fsstat.f_bfree;
- }
- }
-
- return(TRUE);
-}
-#else
-gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, ULARGE_INTEGER *free_bytes_avail,
- ULARGE_INTEGER *total_number_of_bytes,
- ULARGE_INTEGER *total_number_of_free_bytes)
-{
- if (free_bytes_avail != NULL) {
- free_bytes_avail->QuadPart = (guint64) -1;
- }
-
- if (total_number_of_bytes != NULL) {
- total_number_of_bytes->QuadPart = (guint64) -1;
- }
-
- if (total_number_of_free_bytes != NULL) {
- total_number_of_free_bytes->QuadPart = (guint64) -1;
- }
-
- return(TRUE);
-}
-#endif
-
-/*
- * General Unix support
- */
-typedef struct {
- guint32 drive_type;
-#if __linux__
- const long fstypeid;
-#endif
- const gchar* fstype;
-} _wapi_drive_type;
-
-static _wapi_drive_type _wapi_drive_types[] = {
-#if PLATFORM_MACOSX
- { DRIVE_REMOTE, "afp" },
- { DRIVE_REMOTE, "autofs" },
- { DRIVE_CDROM, "cddafs" },
- { DRIVE_CDROM, "cd9660" },
- { DRIVE_RAMDISK, "devfs" },
- { DRIVE_FIXED, "exfat" },
- { DRIVE_RAMDISK, "fdesc" },
- { DRIVE_REMOTE, "ftp" },
- { DRIVE_FIXED, "hfs" },
- { DRIVE_FIXED, "msdos" },
- { DRIVE_REMOTE, "nfs" },
- { DRIVE_FIXED, "ntfs" },
- { DRIVE_REMOTE, "smbfs" },
- { DRIVE_FIXED, "udf" },
- { DRIVE_REMOTE, "webdav" },
- { DRIVE_UNKNOWN, NULL }
-#elif __linux__
- { DRIVE_FIXED, ADFS_SUPER_MAGIC, "adfs"},
- { DRIVE_FIXED, AFFS_SUPER_MAGIC, "affs"},
- { DRIVE_REMOTE, AFS_SUPER_MAGIC, "afs"},
- { DRIVE_RAMDISK, AUTOFS_SUPER_MAGIC, "autofs"},
- { DRIVE_RAMDISK, AUTOFS_SBI_MAGIC, "autofs4"},
- { DRIVE_REMOTE, CODA_SUPER_MAGIC, "coda" },
- { DRIVE_RAMDISK, CRAMFS_MAGIC, "cramfs"},
- { DRIVE_RAMDISK, CRAMFS_MAGIC_WEND, "cramfs"},
- { DRIVE_REMOTE, CIFS_MAGIC_NUMBER, "cifs"},
- { DRIVE_RAMDISK, DEBUGFS_MAGIC, "debugfs"},
- { DRIVE_RAMDISK, SYSFS_MAGIC, "sysfs"},
- { DRIVE_RAMDISK, SECURITYFS_MAGIC, "securityfs"},
- { DRIVE_RAMDISK, SELINUX_MAGIC, "selinuxfs"},
- { DRIVE_RAMDISK, RAMFS_MAGIC, "ramfs"},
- { DRIVE_FIXED, SQUASHFS_MAGIC, "squashfs"},
- { DRIVE_FIXED, EFS_SUPER_MAGIC, "efs"},
- { DRIVE_FIXED, EXT2_SUPER_MAGIC, "ext"},
- { DRIVE_FIXED, EXT3_SUPER_MAGIC, "ext"},
- { DRIVE_FIXED, EXT4_SUPER_MAGIC, "ext"},
- { DRIVE_REMOTE, XENFS_SUPER_MAGIC, "xenfs"},
- { DRIVE_FIXED, BTRFS_SUPER_MAGIC, "btrfs"},
- { DRIVE_FIXED, HFS_SUPER_MAGIC, "hfs"},
- { DRIVE_FIXED, HFSPLUS_SUPER_MAGIC, "hfsplus"},
- { DRIVE_FIXED, HPFS_SUPER_MAGIC, "hpfs"},
- { DRIVE_RAMDISK, HUGETLBFS_MAGIC, "hugetlbfs"},
- { DRIVE_CDROM, ISOFS_SUPER_MAGIC, "iso"},
- { DRIVE_FIXED, JFFS2_SUPER_MAGIC, "jffs2"},
- { DRIVE_RAMDISK, ANON_INODE_FS_MAGIC, "anon_inode"},
- { DRIVE_FIXED, JFS_SUPER_MAGIC, "jfs"},
- { DRIVE_FIXED, MINIX_SUPER_MAGIC, "minix"},
- { DRIVE_FIXED, MINIX_SUPER_MAGIC2, "minix v2"},
- { DRIVE_FIXED, MINIX2_SUPER_MAGIC, "minix2"},
- { DRIVE_FIXED, MINIX2_SUPER_MAGIC2, "minix2 v2"},
- { DRIVE_FIXED, MINIX3_SUPER_MAGIC, "minix3"},
- { DRIVE_FIXED, MSDOS_SUPER_MAGIC, "msdos"},
- { DRIVE_REMOTE, NCP_SUPER_MAGIC, "ncp"},
- { DRIVE_REMOTE, NFS_SUPER_MAGIC, "nfs"},
- { DRIVE_FIXED, NTFS_SB_MAGIC, "ntfs"},
- { DRIVE_RAMDISK, OPENPROM_SUPER_MAGIC, "openpromfs"},
- { DRIVE_RAMDISK, PROC_SUPER_MAGIC, "proc"},
- { DRIVE_FIXED, QNX4_SUPER_MAGIC, "qnx4"},
- { DRIVE_FIXED, REISERFS_SUPER_MAGIC, "reiserfs"},
- { DRIVE_RAMDISK, ROMFS_MAGIC, "romfs"},
- { DRIVE_REMOTE, SMB_SUPER_MAGIC, "samba"},
- { DRIVE_RAMDISK, CGROUP_SUPER_MAGIC, "cgroupfs"},
- { DRIVE_RAMDISK, FUTEXFS_SUPER_MAGIC, "futexfs"},
- { DRIVE_FIXED, SYSV2_SUPER_MAGIC, "sysv2"},
- { DRIVE_FIXED, SYSV4_SUPER_MAGIC, "sysv4"},
- { DRIVE_RAMDISK, TMPFS_MAGIC, "tmpfs"},
- { DRIVE_RAMDISK, DEVPTS_SUPER_MAGIC, "devpts"},
- { DRIVE_CDROM, UDF_SUPER_MAGIC, "udf"},
- { DRIVE_FIXED, UFS_MAGIC, "ufs"},
- { DRIVE_FIXED, UFS_MAGIC_BW, "ufs"},
- { DRIVE_FIXED, UFS2_MAGIC, "ufs2"},
- { DRIVE_FIXED, UFS_CIGAM, "ufs"},
- { DRIVE_RAMDISK, USBDEVICE_SUPER_MAGIC, "usbdev"},
- { DRIVE_FIXED, XENIX_SUPER_MAGIC, "xenix"},
- { DRIVE_FIXED, XFS_SB_MAGIC, "xfs"},
- { DRIVE_RAMDISK, FUSE_SUPER_MAGIC, "fuse"},
- { DRIVE_FIXED, V9FS_MAGIC, "9p"},
- { DRIVE_REMOTE, CEPH_SUPER_MAGIC, "ceph"},
- { DRIVE_RAMDISK, CONFIGFS_MAGIC, "configfs"},
- { DRIVE_RAMDISK, ECRYPTFS_SUPER_MAGIC, "eCryptfs"},
- { DRIVE_FIXED, EXOFS_SUPER_MAGIC, "exofs"},
- { DRIVE_FIXED, VXFS_SUPER_MAGIC, "vxfs"},
- { DRIVE_FIXED, VXFS_OLT_MAGIC, "vxfs_olt"},
- { DRIVE_REMOTE, GFS2_MAGIC, "gfs2"},
- { DRIVE_FIXED, LOGFS_MAGIC_U32, "logfs"},
- { DRIVE_FIXED, OCFS2_SUPER_MAGIC, "ocfs2"},
- { DRIVE_FIXED, OMFS_MAGIC, "omfs"},
- { DRIVE_FIXED, UBIFS_SUPER_MAGIC, "ubifs"},
- { DRIVE_UNKNOWN, 0, NULL}
-#else
- { DRIVE_RAMDISK, "ramfs" },
- { DRIVE_RAMDISK, "tmpfs" },
- { DRIVE_RAMDISK, "proc" },
- { DRIVE_RAMDISK, "sysfs" },
- { DRIVE_RAMDISK, "debugfs" },
- { DRIVE_RAMDISK, "devpts" },
- { DRIVE_RAMDISK, "securityfs" },
- { DRIVE_CDROM, "iso9660" },
- { DRIVE_FIXED, "ext2" },
- { DRIVE_FIXED, "ext3" },
- { DRIVE_FIXED, "ext4" },
- { DRIVE_FIXED, "sysv" },
- { DRIVE_FIXED, "reiserfs" },
- { DRIVE_FIXED, "ufs" },
- { DRIVE_FIXED, "vfat" },
- { DRIVE_FIXED, "msdos" },
- { DRIVE_FIXED, "udf" },
- { DRIVE_FIXED, "hfs" },
- { DRIVE_FIXED, "hpfs" },
- { DRIVE_FIXED, "qnx4" },
- { DRIVE_FIXED, "ntfs" },
- { DRIVE_FIXED, "ntfs-3g" },
- { DRIVE_REMOTE, "smbfs" },
- { DRIVE_REMOTE, "fuse" },
- { DRIVE_REMOTE, "nfs" },
- { DRIVE_REMOTE, "nfs4" },
- { DRIVE_REMOTE, "cifs" },
- { DRIVE_REMOTE, "ncpfs" },
- { DRIVE_REMOTE, "coda" },
- { DRIVE_REMOTE, "afs" },
- { DRIVE_UNKNOWN, NULL }
-#endif
-};
-
-#if __linux__
-static guint32 _wapi_get_drive_type(long f_type)
-{
- _wapi_drive_type *current;
-
- current = &_wapi_drive_types[0];
- while (current->drive_type != DRIVE_UNKNOWN) {
- if (current->fstypeid == f_type)
- return current->drive_type;
- current++;
- }
-
- return DRIVE_UNKNOWN;
-}
-#else
-static guint32 _wapi_get_drive_type(const gchar* fstype)
-{
- _wapi_drive_type *current;
-
- current = &_wapi_drive_types[0];
- while (current->drive_type != DRIVE_UNKNOWN) {
- if (strcmp (current->fstype, fstype) == 0)
- break;
-
- current++;
- }
-
- return current->drive_type;
-}
-#endif
-
-#if defined (PLATFORM_MACOSX) || defined (__linux__)
-static guint32
-GetDriveTypeFromPath (const char *utf8_root_path_name)
-{
- struct statfs buf;
-
- if (statfs (utf8_root_path_name, &buf) == -1)
- return DRIVE_UNKNOWN;
-#if PLATFORM_MACOSX
- return _wapi_get_drive_type (buf.f_fstypename);
-#else
- return _wapi_get_drive_type (buf.f_type);
-#endif
-}
-#else
-static guint32
-GetDriveTypeFromPath (const gchar *utf8_root_path_name)
-{
- guint32 drive_type;
- FILE *fp;
- gchar buffer [512];
- gchar **splitted;
-
- fp = fopen ("/etc/mtab", "rt");
- if (fp == NULL) {
- fp = fopen ("/etc/mnttab", "rt");
- if (fp == NULL)
- return(DRIVE_UNKNOWN);
- }
-
- drive_type = DRIVE_NO_ROOT_DIR;
- while (fgets (buffer, 512, fp) != NULL) {
- splitted = g_strsplit (buffer, " ", 0);
- if (!*splitted || !*(splitted + 1) || !*(splitted + 2)) {
- g_strfreev (splitted);
- continue;
- }
-
- /* compare given root_path_name with the one from mtab,
- if length of utf8_root_path_name is zero it must be the root dir */
- if (strcmp (*(splitted + 1), utf8_root_path_name) == 0 ||
- (strcmp (*(splitted + 1), "/") == 0 && strlen (utf8_root_path_name) == 0)) {
- drive_type = _wapi_get_drive_type (*(splitted + 2));
- /* it is possible this path might be mounted again with
- a known type...keep looking */
- if (drive_type != DRIVE_UNKNOWN) {
- g_strfreev (splitted);
- break;
- }
- }
-
- g_strfreev (splitted);
- }
-
- fclose (fp);
- return drive_type;
-}
-#endif
-
-guint32 GetDriveType(const gunichar2 *root_path_name)
-{
- gchar *utf8_root_path_name;
- guint32 drive_type;
-
- if (root_path_name == NULL) {
- utf8_root_path_name = g_strdup (g_get_current_dir());
- if (utf8_root_path_name == NULL) {
- return(DRIVE_NO_ROOT_DIR);
- }
- }
- else {
- utf8_root_path_name = mono_unicode_to_external (root_path_name);
- if (utf8_root_path_name == NULL) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
- return(DRIVE_NO_ROOT_DIR);
- }
-
- /* strip trailing slash for compare below */
- if (g_str_has_suffix(utf8_root_path_name, "/") && utf8_root_path_name [1] != 0) {
- utf8_root_path_name[strlen(utf8_root_path_name) - 1] = 0;
- }
- }
- drive_type = GetDriveTypeFromPath (utf8_root_path_name);
- g_free (utf8_root_path_name);
-
- return (drive_type);
-}
-
-#if defined (PLATFORM_MACOSX) || defined (__linux__) || defined(PLATFORM_BSD) || defined(__native_client__) || defined(__FreeBSD_kernel__)
-static gchar*
-get_fstypename (gchar *utfpath)
-{
-#if defined (PLATFORM_MACOSX) || defined (__linux__)
- struct statfs stat;
-#if __linux__
- _wapi_drive_type *current;
-#endif
- if (statfs (utfpath, &stat) == -1)
- return NULL;
-#if PLATFORM_MACOSX
- return g_strdup (stat.f_fstypename);
-#else
- current = &_wapi_drive_types[0];
- while (current->drive_type != DRIVE_UNKNOWN) {
- if (stat.f_type == current->fstypeid)
- return g_strdup (current->fstype);
- current++;
- }
- return NULL;
-#endif
-#else
- return NULL;
-#endif
-}
-
-/* Linux has struct statfs which has a different layout */
-gboolean
-GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesize, int *outserial, int *maxcomp, int *fsflags, gunichar2 *fsbuffer, int fsbuffersize)
-{
- gchar *utfpath;
- gchar *fstypename;
- gboolean status = FALSE;
- glong len;
-
- // We only support getting the file system type
- if (fsbuffer == NULL)
- return 0;
-
- utfpath = mono_unicode_to_external (path);
- if ((fstypename = get_fstypename (utfpath)) != NULL){
- gunichar2 *ret = g_utf8_to_utf16 (fstypename, -1, NULL, &len, NULL);
- if (ret != NULL && len < fsbuffersize){
- memcpy (fsbuffer, ret, len * sizeof (gunichar2));
- fsbuffer [len] = 0;
- status = TRUE;
- }
- if (ret != NULL)
- g_free (ret);
- g_free (fstypename);
- }
- g_free (utfpath);
- return status;
-}
-#endif
-
-void
-_wapi_io_init (void)
-{
- mono_os_mutex_init (&stdhandle_mutex);
- mono_os_mutex_init (&file_share_mutex);
-
- mono_w32handle_register_ops (MONO_W32HANDLE_FILE, &_wapi_file_ops);
- mono_w32handle_register_ops (MONO_W32HANDLE_CONSOLE, &_wapi_console_ops);
- mono_w32handle_register_ops (MONO_W32HANDLE_FIND, &_wapi_find_ops);
- mono_w32handle_register_ops (MONO_W32HANDLE_PIPE, &_wapi_pipe_ops);
-
-/* mono_w32handle_register_capabilities (MONO_W32HANDLE_FILE, */
-/* MONO_W32HANDLE_CAP_WAIT); */
-/* mono_w32handle_register_capabilities (MONO_W32HANDLE_CONSOLE, */
-/* MONO_W32HANDLE_CAP_WAIT); */
-
- if (g_getenv ("MONO_STRICT_IO_EMULATION"))
- lock_while_writing = TRUE;
-}
-
-void
-_wapi_io_cleanup (void)
-{
- mono_os_mutex_destroy (&file_share_mutex);
-
- if (file_share_hash)
- g_hash_table_destroy (file_share_hash);
-}
+++ /dev/null
-/*
- * io.h: File, console and find handles
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- */
-
-#ifndef _WAPI_IO_H_
-#define _WAPI_IO_H_
-
-#include <stdlib.h>
-
-#include "mono/io-layer/wapi.h"
-
-G_BEGIN_DECLS
-
-typedef struct _WapiSecurityAttributes WapiSecurityAttributes;
-
-struct _WapiSecurityAttributes
-{
- guint32 nLength;
- gpointer lpSecurityDescriptor;
- gboolean bInheritHandle;
-};
-
-typedef struct _WapiOverlapped WapiOverlapped;
-
-struct _WapiOverlapped
-{
- guint32 Internal;
- guint32 InternalHigh;
- guint32 Offset;
- guint32 OffsetHigh;
- gpointer hEvent;
- gpointer handle1;
- gpointer handle2;
-};
-
-typedef void (*WapiOverlappedCB) (guint32 error, guint32 numbytes,
- WapiOverlapped *overlapped);
-
-#define GENERIC_READ 0x80000000
-#define GENERIC_WRITE 0x40000000
-#define GENERIC_EXECUTE 0x20000000
-#define GENERIC_ALL 0x10000000
-
-#define FILE_SHARE_READ 0x00000001
-#define FILE_SHARE_WRITE 0x00000002
-#define FILE_SHARE_DELETE 0x00000004
-
-#define CREATE_NEW 1
-#define CREATE_ALWAYS 2
-#define OPEN_EXISTING 3
-#define OPEN_ALWAYS 4
-#define TRUNCATE_EXISTING 5
-
-
-#define FILE_ATTRIBUTE_READONLY 0x00000001
-#define FILE_ATTRIBUTE_HIDDEN 0x00000002
-#define FILE_ATTRIBUTE_SYSTEM 0x00000004
-#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
-#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
-#define FILE_ATTRIBUTE_ENCRYPTED 0x00000040
-#define FILE_ATTRIBUTE_NORMAL 0x00000080
-#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
-#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
-#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
-#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
-#define FILE_ATTRIBUTE_OFFLINE 0x00001000
-#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
-#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
-#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
-#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
-#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
-#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
-#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
-#define FILE_FLAG_RANDOM_ACCESS 0x10000000
-#define FILE_FLAG_NO_BUFFERING 0x20000000
-#define FILE_FLAG_OVERLAPPED 0x40000000
-#define FILE_FLAG_WRITE_THROUGH 0x80000000
-
-#define REPLACEFILE_WRITE_THROUGH 0x00000001
-#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x00000002
-
-#define MAX_PATH 260
-
-typedef enum {
- STD_INPUT_HANDLE=-10,
- STD_OUTPUT_HANDLE=-11,
- STD_ERROR_HANDLE=-12
-} WapiStdHandle;
-
-typedef enum {
- FILE_BEGIN=0,
- FILE_CURRENT=1,
- FILE_END=2
-} WapiSeekMethod;
-
-typedef enum {
- FILE_TYPE_UNKNOWN=0x0000,
- FILE_TYPE_DISK=0x0001,
- FILE_TYPE_CHAR=0x0002,
- FILE_TYPE_PIPE=0x0003,
- FILE_TYPE_REMOTE=0x8000
-} WapiFileType;
-
-typedef enum {
- DRIVE_UNKNOWN=0,
- DRIVE_NO_ROOT_DIR=1,
- DRIVE_REMOVABLE=2,
- DRIVE_FIXED=3,
- DRIVE_REMOTE=4,
- DRIVE_CDROM=5,
- DRIVE_RAMDISK=6
-} WapiDriveType;
-
-typedef enum {
- GetFileExInfoStandard=0x0000,
- GetFileExMaxInfoLevel=0x0001
-} WapiGetFileExInfoLevels;
-
-typedef struct
-{
- guint16 wYear;
- guint16 wMonth;
- guint16 wDayOfWeek;
- guint16 wDay;
- guint16 wHour;
- guint16 wMinute;
- guint16 wSecond;
- guint16 wMilliseconds;
-} WapiSystemTime;
-
-typedef struct {
-#if G_BYTE_ORDER == G_BIG_ENDIAN
- guint32 dwHighDateTime;
- guint32 dwLowDateTime;
-#else
- guint32 dwLowDateTime;
- guint32 dwHighDateTime;
-#endif
-} WapiFileTime;
-
-typedef struct
-{
- guint32 dwFileAttributes;
- WapiFileTime ftCreationTime;
- WapiFileTime ftLastAccessTime;
- WapiFileTime ftLastWriteTime;
- guint32 nFileSizeHigh;
- guint32 nFileSizeLow;
- guint32 dwReserved0;
- guint32 dwReserved1;
- gunichar2 cFileName [MAX_PATH];
- gunichar2 cAlternateFileName [14];
-} WapiFindData;
-
-typedef struct
-{
- guint32 dwFileAttributes;
- WapiFileTime ftCreationTime;
- WapiFileTime ftLastAccessTime;
- WapiFileTime ftLastWriteTime;
- guint32 nFileSizeHigh;
- guint32 nFileSizeLow;
-} WapiFileAttributesData;
-
-typedef union {
- struct {
- guint32 LowPart;
- guint32 HighPart;
- } u;
- guint64 QuadPart;
-} ULARGE_INTEGER;
-
-#define INVALID_SET_FILE_POINTER ((guint32)-1)
-#define INVALID_FILE_SIZE ((guint32)0xFFFFFFFF)
-#define INVALID_FILE_ATTRIBUTES ((guint32)-1)
-
-extern gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
- guint32 sharemode,
- WapiSecurityAttributes *security,
- guint32 createmode,
- guint32 attrs, gpointer tmplate);
-extern gboolean DeleteFile(const gunichar2 *name);
-extern gpointer GetStdHandle(WapiStdHandle stdhandle);
-extern gboolean ReadFile(gpointer handle, gpointer buffer, guint32 numbytes,
- guint32 *bytesread, WapiOverlapped *overlapped);
-extern gboolean WriteFile(gpointer handle, gconstpointer buffer,
- guint32 numbytes, guint32 *byteswritten,
- WapiOverlapped *overlapped);
-extern gboolean FlushFileBuffers(gpointer handle);
-extern gboolean SetEndOfFile(gpointer handle);
-extern guint32 SetFilePointer(gpointer handle, gint32 movedistance,
- gint32 *highmovedistance, guint32 method);
-extern WapiFileType GetFileType(gpointer handle);
-extern guint32 GetFileSize(gpointer handle, guint32 *highsize);
-extern gboolean GetFileTime(gpointer handle, WapiFileTime *create_time,
- WapiFileTime *last_access,
- WapiFileTime *last_write);
-extern gboolean SetFileTime(gpointer handle, const WapiFileTime *create_time,
- const WapiFileTime *last_access,
- const WapiFileTime *last_write);
-extern gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
- WapiSystemTime *system_time);
-extern gpointer FindFirstFile (const gunichar2 *pattern,
- WapiFindData *find_data);
-extern gboolean FindNextFile (gpointer handle, WapiFindData *find_data);
-extern gboolean FindClose (gpointer handle);
-extern gboolean CreateDirectory (const gunichar2 *name,
- WapiSecurityAttributes *security);
-extern gboolean RemoveDirectory (const gunichar2 *name);
-extern gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name);
-extern gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
- gboolean fail_if_exists);
-extern gboolean ReplaceFile (const gunichar2 *replacedFileName, const gunichar2 *replacementFileName,
- const gunichar2 *backupFileName, guint32 replaceFlags,
- gpointer exclude, gpointer reserved);
-extern guint32 GetFileAttributes (const gunichar2 *name);
-extern gboolean GetFileAttributesEx (const gunichar2 *name,
- WapiGetFileExInfoLevels level,
- gpointer info);
-extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs);
-extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer);
-extern gboolean SetCurrentDirectory (const gunichar2 *path);
-extern gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
- WapiSecurityAttributes *security, guint32 size);
-extern gint32 GetLogicalDriveStrings (guint32 len, gunichar2 *buf);
-extern gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, ULARGE_INTEGER *free_bytes_avail,
- ULARGE_INTEGER *total_number_of_bytes,
- ULARGE_INTEGER *total_number_of_free_bytes);
-extern guint32 GetDriveType(const gunichar2 *root_path_name);
-extern gboolean LockFile (gpointer handle, guint32 offset_low,
- guint32 offset_high, guint32 length_low,
- guint32 length_high);
-extern gboolean UnlockFile (gpointer handle, guint32 offset_low,
- guint32 offset_high, guint32 length_low,
- guint32 length_high);
-extern gboolean GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesize, int *outserial, int *maxcomp, int *fsflags, gunichar2 *fsbuffer, int fsbuffersize);
-
-
-extern void _wapi_io_init (void);
-extern void _wapi_io_cleanup (void);
-
-G_END_DECLS
-
-#endif /* _WAPI_IO_H_ */
+++ /dev/null
-/*
- * io.c: File, console and find handles
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- * Copyright (c) 2002-2009 Novell, Inc.
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-#include <config.h>
-#include <stdio.h>
-#include <glib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <mono/io-layer/wapi.h>
-#include <mono/io-layer/wapi-private.h>
-#include <mono/io-layer/io-private.h>
-#include <mono/io-layer/io-trace.h>
-#include <mono/utils/mono-logger-internals.h>
-#include <mono/metadata/w32handle.h>
-
-gboolean
-_wapi_lock_file_region (int fd, off_t offset, off_t length)
-{
-#if defined(__native_client__)
- printf("WARNING: locking.c: _wapi_lock_file_region(): fcntl() not available on Native Client!\n");
- // behave as below -- locks are not available
- return(TRUE);
-#else
- struct flock lock_data;
- int ret;
-
- if (offset < 0 || length < 0) {
- SetLastError (ERROR_INVALID_PARAMETER);
- return(FALSE);
- }
-
- lock_data.l_type = F_WRLCK;
- lock_data.l_whence = SEEK_SET;
- lock_data.l_start = offset;
- lock_data.l_len = length;
-
- do {
- ret = fcntl (fd, F_SETLK, &lock_data);
- } while(ret == -1 && errno == EINTR);
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl returns %d", __func__, ret);
-
- if (ret == -1) {
- /*
- * if locks are not available (NFS for example),
- * ignore the error
- */
- if (errno == ENOLCK
-#ifdef EOPNOTSUPP
- || errno == EOPNOTSUPP
-#endif
-#ifdef ENOTSUP
- || errno == ENOTSUP
-#endif
- ) {
- return (TRUE);
- }
-
- SetLastError (ERROR_LOCK_VIOLATION);
- return(FALSE);
- }
-
- return(TRUE);
-#endif /* __native_client__ */
-}
-
-gboolean
-_wapi_unlock_file_region (int fd, off_t offset, off_t length)
-{
-#if defined(__native_client__)
- printf("WARNING: locking.c: _wapi_unlock_file_region(): fcntl() not available on Native Client!\n");
- return (TRUE);
-#else
- struct flock lock_data;
- int ret;
-
- lock_data.l_type = F_UNLCK;
- lock_data.l_whence = SEEK_SET;
- lock_data.l_start = offset;
- lock_data.l_len = length;
-
- do {
- ret = fcntl (fd, F_SETLK, &lock_data);
- } while(ret == -1 && errno == EINTR);
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl returns %d", __func__, ret);
-
- if (ret == -1) {
- /*
- * if locks are not available (NFS for example),
- * ignore the error
- */
- if (errno == ENOLCK
-#ifdef EOPNOTSUPP
- || errno == EOPNOTSUPP
-#endif
-#ifdef ENOTSUP
- || errno == ENOTSUP
-#endif
- ) {
- return (TRUE);
- }
-
- SetLastError (ERROR_LOCK_VIOLATION);
- return(FALSE);
- }
-
- return(TRUE);
-#endif /* __native_client__ */
-}
-
-gboolean
-LockFile (gpointer handle, guint32 offset_low, guint32 offset_high,
- guint32 length_low, guint32 length_high)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- off_t offset, length;
- int fd = GPOINTER_TO_UINT(handle);
-
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if (ok == FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- if (!(file_handle->fileaccess & GENERIC_READ) &&
- !(file_handle->fileaccess & GENERIC_WRITE) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
-#ifdef HAVE_LARGE_FILE_SUPPORT
- offset = ((gint64)offset_high << 32) | offset_low;
- length = ((gint64)length_high << 32) | length_low;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking handle %p, offset %lld, length %lld", __func__, handle, offset, length);
-#else
- if (offset_high > 0 || length_high > 0) {
- SetLastError (ERROR_INVALID_PARAMETER);
- return (FALSE);
- }
- offset = offset_low;
- length = length_low;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking handle %p, offset %ld, length %ld", __func__,
- handle, offset, length);
-#endif
-
- return(_wapi_lock_file_region (fd, offset, length));
-}
-
-gboolean
-UnlockFile (gpointer handle, guint32 offset_low,
- guint32 offset_high, guint32 length_low,
- guint32 length_high)
-{
- struct _WapiHandle_file *file_handle;
- gboolean ok;
- off_t offset, length;
- int fd = GPOINTER_TO_UINT(handle);
-
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
- (gpointer *)&file_handle);
- if (ok == FALSE) {
- g_warning ("%s: error looking up file handle %p", __func__,
- handle);
- SetLastError (ERROR_INVALID_HANDLE);
- return(FALSE);
- }
-
- if (!(file_handle->fileaccess & GENERIC_READ) &&
- !(file_handle->fileaccess & GENERIC_WRITE) &&
- !(file_handle->fileaccess & GENERIC_ALL)) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
- SetLastError (ERROR_ACCESS_DENIED);
- return(FALSE);
- }
-
-#ifdef HAVE_LARGE_FILE_SUPPORT
- offset = ((gint64)offset_high << 32) | offset_low;
- length = ((gint64)length_high << 32) | length_low;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking handle %p, offset %lld, length %lld", __func__, handle, offset, length);
-#else
- offset = offset_low;
- length = length_low;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking handle %p, offset %ld, length %ld", __func__, handle, offset, length);
-#endif
-
- return(_wapi_unlock_file_region (fd, offset, length));
-}
+++ /dev/null
-/*
- * posix.c: Posix-specific support.
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- * Copyright (c) 2002-2009 Novell, Inc.
- * Copyright 2011 Xamarin Inc
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#include <config.h>
-#include <glib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <stdio.h>
-
-#include <mono/io-layer/wapi.h>
-#include <mono/io-layer/wapi-private.h>
-#include <mono/io-layer/io-private.h>
-#include <mono/io-layer/io-trace.h>
-#include <mono/utils/mono-logger-internals.h>
-#include <mono/metadata/w32handle.h>
-
-static guint32
-convert_from_flags(int flags)
-{
- guint32 fileaccess=0;
-
-#ifndef O_ACCMODE
-#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
-#endif
-
- if((flags & O_ACCMODE) == O_RDONLY) {
- fileaccess=GENERIC_READ;
- } else if ((flags & O_ACCMODE) == O_WRONLY) {
- fileaccess=GENERIC_WRITE;
- } else if ((flags & O_ACCMODE) == O_RDWR) {
- fileaccess=GENERIC_READ|GENERIC_WRITE;
- } else {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't figure out flags 0x%x", __func__, flags);
- }
-
- /* Maybe sort out create mode too */
-
- return(fileaccess);
-}
-
-
-gpointer _wapi_stdhandle_create (int fd, const gchar *name)
-{
- struct _WapiHandle_file file_handle = {0};
- gpointer handle;
- int flags;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating standard handle type %s, fd %d", __func__,
- name, fd);
-
-#if !defined(__native_client__)
- /* Check if fd is valid */
- do {
- flags=fcntl(fd, F_GETFL);
- } while (flags == -1 && errno == EINTR);
-
- if(flags==-1) {
- /* Invalid fd. Not really much point checking for EBADF
- * specifically
- */
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl error on fd %d: %s", __func__, fd,
- strerror(errno));
-
- SetLastError (_wapi_get_win32_file_error (errno));
- return(INVALID_HANDLE_VALUE);
- }
- file_handle.fileaccess=convert_from_flags(flags);
-#else
- /*
- * fcntl will return -1 in nacl, as there is no real file system API.
- * Yet, standard streams are available.
- */
- file_handle.fileaccess = (fd == STDIN_FILENO) ? GENERIC_READ : GENERIC_WRITE;
-#endif
-
- file_handle.fd = fd;
- file_handle.filename = g_strdup(name);
- /* some default security attributes might be needed */
- file_handle.security_attributes=0;
-
- /* Apparently input handles can't be written to. (I don't
- * know if output or error handles can't be read from.)
- */
- if (fd == 0) {
- file_handle.fileaccess &= ~GENERIC_WRITE;
- }
-
- file_handle.sharemode=0;
- file_handle.attrs=0;
-
- handle = mono_w32handle_new_fd (MONO_W32HANDLE_CONSOLE, fd, &file_handle);
- if (handle == INVALID_HANDLE_VALUE) {
- g_warning ("%s: error creating file handle", __func__);
- SetLastError (ERROR_GEN_FAILURE);
- return(INVALID_HANDLE_VALUE);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p", __func__, handle);
-
- return(handle);
-}
-
+++ /dev/null
-/*
- * uglify.h: Optional header to provide the nasty w32 typedefs
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- */
-
-#ifndef _WAPI_UGLIFY_H_
-#define _WAPI_UGLIFY_H_
-
-/* Include this file if you insist on using the nasty Win32 typedefs */
-
-#include <stdlib.h>
-
-#include "mono/io-layer/wapi.h"
-
-typedef const gunichar2 *LPCTSTR;
-typedef gunichar2 *LPTSTR;
-typedef const char *LPCSTR;
-typedef char *LPSTR;
-typedef guint8 BYTE;
-typedef guint8 *LPBYTE;
-typedef guint16 WORD;
-typedef guint32 DWORD;
-typedef gpointer PVOID;
-typedef gpointer LPVOID;
-typedef gboolean BOOL;
-typedef guint32 *LPDWORD;
-typedef gint32 LONG;
-typedef guint32 ULONG;
-typedef gint32 *PLONG;
-typedef guint64 LONGLONG;
-typedef gunichar2 TCHAR;
-typedef size_t SIZE_T;
-typedef guint64 ULONG64;
-typedef guint UINT;
-typedef gconstpointer LPCVOID;
-
-typedef gpointer HANDLE;
-typedef gpointer *LPHANDLE;
-typedef gpointer HMODULE;
-typedef gpointer HINSTANCE;
-typedef gpointer HWND;
-typedef gpointer HKEY;
-
-typedef WapiSecurityAttributes SECURITY_ATTRIBUTES;
-typedef WapiSecurityAttributes *LPSECURITY_ATTRIBUTES;
-typedef WapiOverlapped *LPOVERLAPPED;
-typedef WapiOverlappedCB LPOVERLAPPED_COMPLETION_ROUTINE;
-typedef WapiFileTime FILETIME;
-typedef WapiFileTime *LPFILETIME;
-typedef WapiSystemTime SYSTEMTIME;
-typedef WapiSystemTime *LPSYSTEMTIME;
-typedef WapiFindData WIN32_FIND_DATA;
-typedef WapiFindData *LPWIN32_FIND_DATA;
-typedef WapiFileAttributesData WIN32_FILE_ATTRIBUTE_DATA;
-typedef WapiGetFileExInfoLevels GET_FILEEX_INFO_LEVELS;
-
-#define CONST const
-#define VOID void
-
-#define IN
-#define OUT
-#define WINAPI
-
-#endif /* _WAPI_UGLIFY_H_ */
+++ /dev/null
-/*
- * wapi-private.h: internal definitions of handles and shared memory layout
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002-2006 Novell, Inc.
- */
-
-#ifndef _WAPI_PRIVATE_H_
-#define _WAPI_PRIVATE_H_
-
-#include <config.h>
-#include <glib.h>
-#include <sys/stat.h>
-
-#include <mono/io-layer/wapi.h>
-#include <mono/io-layer/io.h>
-
-#include <mono/utils/mono-os-mutex.h>
-
-/* There doesn't seem to be a defined symbol for this */
-#define _WAPI_THREAD_CURRENT (gpointer)0xFFFFFFFE
-
-extern gboolean _wapi_has_shut_down;
-
-#include <mono/io-layer/io-private.h>
-#include <mono/metadata/w32handle.h>
-
-struct _WapiHandle_shared_ref
-{
- /* This will be split 16:16 with the shared file segment in
- * the top half, when I implement space increases
- */
- guint32 offset;
-};
-
-struct _WapiFileShare
-{
-#ifdef WAPI_FILE_SHARE_PLATFORM_EXTRA_DATA
- WAPI_FILE_SHARE_PLATFORM_EXTRA_DATA
-#endif
- guint64 device;
- guint64 inode;
- pid_t opened_by_pid;
- guint32 sharemode;
- guint32 access;
- guint32 handle_refs;
- guint32 timestamp;
-};
-
-typedef struct _WapiFileShare _WapiFileShare;
-
-#endif /* _WAPI_PRIVATE_H_ */
#define GetLastError wapi_GetLastError
#define SetLastError wapi_SetLastError
#define CloseHandle wapi_CloseHandle
-#define CreateFile wapi_CreateFile
-#define DeleteFile wapi_DeleteFile
-#define GetStdHandle wapi_GetStdHandle
-#define ReadFile wapi_ReadFile
-#define WriteFile wapi_WriteFile
-#define FlushFileBuffers wapi_FlushFileBuffers
-#define SetEndOfFile wapi_SetEndOfFile
-#define SetFilePointer wapi_SetFilePointer
-#define GetFileType wapi_GetFileType
-#define GetFileSize wapi_GetFileSize
-#define GetFileTime wapi_GetFileTime
-#define SetFileTime wapi_SetFileTime
-#define FileTimeToSystemTime wapi_FileTimeToSystemTime
-#define FindFirstFile wapi_FindFirstFile
-#define FindNextFile wapi_FindNextFile
-#define FindClose wapi_FindClose
-#define CreateDirectory wapi_CreateDirectory
-#define RemoveDirectory wapi_RemoveDirectory
-#define MoveFile wapi_MoveFile
-#define CopyFile wapi_CopyFile
-#define ReplaceFile wapi_ReplaceFile
-#define GetFileAttributes wapi_GetFileAttributes
-#define GetFileAttributesEx wapi_GetFileAttributesEx
-#define SetFileAttributes wapi_SetFileAttributes
-#define GetCurrentDirectory wapi_GetCurrentDirectory
-#define SetCurrentDirectory wapi_SetCurrentDirectory
-#define CreatePipe wapi_CreatePipe
-#define GetLogicalDriveStrings wapi_GetLogicalDriveStrings
-#define GetDiskFreeSpaceEx wapi_GetDiskFreeSpaceEx
-#define GetDriveType wapi_GetDriveType
-#define LockFile wapi_LockFile
-#define UnlockFile wapi_UnlockFile
-#define GetVolumeInformation wapi_GetVolumeInformation
-#define ImpersonateLoggedOnUser wapi_ImpersonateLoggedOnUser
-#define RevertToSelf wapi_RevertToSelf
-#define GetSystemInfo wapi_GetSystemInfo
#endif /* __WAPI_REMAP_H__ */
#include "wapi.h"
-#include "io-trace.h"
-#include "io.h"
-
#include "mono/utils/mono-lazy-init.h"
#include "mono/metadata/w32handle.h"
-gboolean _wapi_has_shut_down = FALSE;
-
-void
-wapi_init (void)
-{
- _wapi_io_init ();
-}
-
-void
-wapi_cleanup (void)
-{
- g_assert (_wapi_has_shut_down == FALSE);
- _wapi_has_shut_down = TRUE;
-
- _wapi_error_cleanup ();
- _wapi_io_cleanup ();
-}
-
/* Use this instead of getpid(), to cope with linuxthreads. It's a
* function rather than a variable lookup because we need to get at
* this before share_init() might have been called. */
#ifndef _WAPI_WAPI_H_
#define _WAPI_WAPI_H_
+#include <config.h>
#include <glib.h>
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#include <unistd.h>
+#include <utime.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <mono/io-layer/wapi-remap.h>
-#include <mono/io-layer/io.h>
-#include <mono/io-layer/io-portability.h>
#include <mono/io-layer/error.h>
+#include <mono/utils/mono-logger-internals.h>
G_BEGIN_DECLS
-#define WAIT_FAILED ((int) 0xFFFFFFFF)
-#define WAIT_OBJECT_0 ((int) 0x00000000)
-#define WAIT_ABANDONED_0 ((int) 0x00000080)
-#define WAIT_TIMEOUT ((int) 0x00000102)
-#define WAIT_IO_COMPLETION ((int) 0x000000C0)
+#define WAIT_FAILED ((gint) 0xFFFFFFFF)
+#define WAIT_OBJECT_0 ((gint) 0x00000000)
+#define WAIT_ABANDONED_0 ((gint) 0x00000080)
+#define WAIT_TIMEOUT ((gint) 0x00000102)
+#define WAIT_IO_COMPLETION ((gint) 0x000000C0)
-void
-wapi_init (void);
+#ifdef DISABLE_IO_LAYER_TRACE
+#define MONO_TRACE(...)
+#else
+#define MONO_TRACE(...) mono_trace (__VA_ARGS__)
+#endif
-void
-wapi_cleanup (void);
+#define WINAPI
+
+typedef guint32 DWORD;
+typedef gboolean BOOL;
+typedef gint32 LONG;
+typedef guint32 ULONG;
+typedef guint UINT;
+
+typedef gpointer HANDLE;
+typedef gpointer HMODULE;
gboolean
CloseHandle (gpointer handle);
+++ /dev/null
-/* $OpenBSD: glob.c,v 1.26 2005/11/28 17:50:12 deraadt Exp $ */
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Guido van Rossum.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * _wapi_glob(3) -- a subset of the one defined in POSIX 1003.2.
- *
- * Optional extra services, controlled by flags not defined by POSIX:
- *
- * GLOB_MAGCHAR:
- * Set in gl_flags if pattern contained a globbing character.
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <glib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "wapi_glob.h"
-
-#define EOS '\0'
-#define NOT '!'
-#define QUESTION '?'
-#define QUOTE '\\'
-#define STAR '*'
-
-#ifndef DEBUG
-
-#define M_QUOTE 0x8000
-#define M_PROTECT 0x4000
-#define M_MASK 0xffff
-#define M_ASCII 0x00ff
-
-typedef unsigned short Char;
-
-#else
-
-#define M_QUOTE 0x80
-#define M_PROTECT 0x40
-#define M_MASK 0xff
-#define M_ASCII 0x7f
-
-typedef char Char;
-
-#endif
-
-
-#define CHAR(c) ((gchar)((c)&M_ASCII))
-#define META(c) ((gchar)((c)|M_QUOTE))
-#define M_ALL META('*')
-#define M_ONE META('?')
-#define ismeta(c) (((c)&M_QUOTE) != 0)
-
-
-static int g_Ctoc(const gchar *, char *, unsigned int);
-static int glob0(GDir *dir, const gchar *, wapi_glob_t *, gboolean,
- gboolean);
-static int glob1(GDir *dir, gchar *, gchar *, wapi_glob_t *, size_t *,
- gboolean, gboolean);
-static int glob3(GDir *dir, gchar *, gchar *, wapi_glob_t *, size_t *,
- gboolean, gboolean);
-static int globextend(const gchar *, wapi_glob_t *, size_t *);
-static int match(const gchar *, gchar *, gchar *, gboolean);
-#ifdef DEBUG_ENABLED
-static void qprintf(const char *, Char *);
-#endif
-
-int
-_wapi_glob(GDir *dir, const char *pattern, int flags, wapi_glob_t *pglob)
-{
- const unsigned char *patnext;
- int c;
- gchar *bufnext, *bufend, patbuf[PATH_MAX];
-
- patnext = (unsigned char *) pattern;
- if (!(flags & WAPI_GLOB_APPEND)) {
- pglob->gl_pathc = 0;
- pglob->gl_pathv = NULL;
- pglob->gl_offs = 0;
- }
- pglob->gl_flags = flags & ~WAPI_GLOB_MAGCHAR;
-
- bufnext = patbuf;
- bufend = bufnext + PATH_MAX - 1;
-
- /* Protect the quoted characters. */
- while (bufnext < bufend && (c = *patnext++) != EOS)
- if (c == QUOTE) {
- if ((c = *patnext++) == EOS) {
- c = QUOTE;
- --patnext;
- }
- *bufnext++ = c | M_PROTECT;
- } else
- *bufnext++ = c;
-
- *bufnext = EOS;
-
- return glob0(dir, patbuf, pglob, flags & WAPI_GLOB_IGNORECASE,
- flags & WAPI_GLOB_UNIQUE);
-}
-
-/*
- * The main glob() routine: compiles the pattern (optionally processing
- * quotes), calls glob1() to do the real pattern matching, and finally
- * sorts the list (unless unsorted operation is requested). Returns 0
- * if things went well, nonzero if errors occurred. It is not an error
- * to find no matches.
- */
-static int
-glob0(GDir *dir, const gchar *pattern, wapi_glob_t *pglob, gboolean ignorecase,
- gboolean unique)
-{
- const gchar *qpatnext;
- int c, err, oldpathc;
- gchar *bufnext, patbuf[PATH_MAX];
- size_t limit = 0;
-
- qpatnext = pattern;
- oldpathc = pglob->gl_pathc;
- bufnext = patbuf;
-
- /* We don't need to check for buffer overflow any more. */
- while ((c = *qpatnext++) != EOS) {
- switch (c) {
- case QUESTION:
- pglob->gl_flags |= WAPI_GLOB_MAGCHAR;
- *bufnext++ = M_ONE;
- break;
- case STAR:
- pglob->gl_flags |= WAPI_GLOB_MAGCHAR;
- /* collapse adjacent stars to one,
- * to avoid exponential behavior
- */
- if (bufnext == patbuf || bufnext[-1] != M_ALL)
- *bufnext++ = M_ALL;
- break;
- default:
- *bufnext++ = CHAR(c);
- break;
- }
- }
- *bufnext = EOS;
-#ifdef DEBUG_ENABLED
- qprintf("glob0:", patbuf);
-#endif
-
- if ((err = glob1(dir, patbuf, patbuf+PATH_MAX-1, pglob, &limit,
- ignorecase, unique)) != 0)
- return(err);
-
- if (pglob->gl_pathc == oldpathc) {
- return(WAPI_GLOB_NOMATCH);
- }
-
- return(0);
-}
-
-static int
-glob1(GDir *dir, gchar *pattern, gchar *pattern_last, wapi_glob_t *pglob,
- size_t *limitp, gboolean ignorecase, gboolean unique)
-{
- /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
- if (*pattern == EOS)
- return(0);
- return(glob3(dir, pattern, pattern_last, pglob, limitp, ignorecase,
- unique));
-}
-
-static gboolean contains (wapi_glob_t *pglob, const gchar *name)
-{
- int i;
- char **pp;
-
- if (pglob->gl_pathv != NULL) {
- pp = pglob->gl_pathv + pglob->gl_offs;
- for (i = pglob->gl_pathc; i--; ++pp) {
- if (*pp) {
- if (!strcmp (*pp, name)) {
- return(TRUE);
- }
- }
- }
- }
-
- return(FALSE);
-}
-
-static int
-glob3(GDir *dir, gchar *pattern, gchar *pattern_last, wapi_glob_t *pglob,
- size_t *limitp, gboolean ignorecase, gboolean unique)
-{
- const gchar *name;
-
- /* Search directory for matching names. */
- while ((name = g_dir_read_name(dir))) {
- if (!match(name, pattern, pattern + strlen (pattern),
- ignorecase)) {
- continue;
- }
- if (!unique ||
- !contains (pglob, name)) {
- globextend (name, pglob, limitp);
- }
- }
-
- return(0);
-}
-
-
-/*
- * Extend the gl_pathv member of a wapi_glob_t structure to accommodate a new item,
- * add the new item, and update gl_pathc.
- *
- * This assumes the BSD realloc, which only copies the block when its size
- * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
- * behavior.
- *
- * Return 0 if new item added, error code if memory couldn't be allocated.
- *
- * Invariant of the wapi_glob_t structure:
- * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
- * gl_pathv points to (gl_offs + gl_pathc + 1) items.
- */
-static int
-globextend(const gchar *path, wapi_glob_t *pglob, size_t *limitp)
-{
- char **pathv;
- int i;
- unsigned int newsize, len;
- char *copy;
- const gchar *p;
-
- newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
- /* FIXME: Can just use realloc(). */
- pathv = (char **)(pglob->gl_pathv ? g_realloc ((char *)pglob->gl_pathv, newsize) :
- g_malloc (newsize));
- if (pathv == NULL) {
- if (pglob->gl_pathv) {
- g_free (pglob->gl_pathv);
- pglob->gl_pathv = NULL;
- }
- return(WAPI_GLOB_NOSPACE);
- }
-
- if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
- /* first time around -- clear initial gl_offs items */
- pathv += pglob->gl_offs;
- for (i = pglob->gl_offs; --i >= 0; )
- *--pathv = NULL;
- }
- pglob->gl_pathv = pathv;
-
- for (p = path; *p++;)
- ;
- len = (size_t)(p - path);
- *limitp += len;
- if ((copy = (char *)malloc(len)) != NULL) {
- if (g_Ctoc(path, copy, len)) {
- g_free (copy);
- return(WAPI_GLOB_NOSPACE);
- }
- pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
- }
- pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
-
-#if 0
- /* Broken on opensuse 11 */
- if ((pglob->gl_flags & WAPI_GLOB_LIMIT) &&
- newsize + *limitp >= ARG_MAX) {
- errno = 0;
- return(WAPI_GLOB_NOSPACE);
- }
-#endif
-
- return(copy == NULL ? WAPI_GLOB_NOSPACE : 0);
-}
-
-
-/*
- * pattern matching function for filenames. Each occurrence of the *
- * pattern causes a recursion level.
- */
-static int
-match(const gchar *name, gchar *pat, gchar *patend, gboolean ignorecase)
-{
- gchar c;
-
- while (pat < patend) {
- c = *pat++;
- switch (c & M_MASK) {
- case M_ALL:
- if (pat == patend)
- return(1);
- do {
- if (match(name, pat, patend, ignorecase))
- return(1);
- } while (*name++ != EOS);
- return(0);
- case M_ONE:
- if (*name++ == EOS)
- return(0);
- break;
- default:
- if (ignorecase) {
- if (g_ascii_tolower (*name++) != g_ascii_tolower (c))
- return(0);
- } else {
- if (*name++ != c)
- return(0);
- }
-
- break;
- }
- }
- return(*name == EOS);
-}
-
-/* Free allocated data belonging to a wapi_glob_t structure. */
-void
-_wapi_globfree(wapi_glob_t *pglob)
-{
- int i;
- char **pp;
-
- if (pglob->gl_pathv != NULL) {
- pp = pglob->gl_pathv + pglob->gl_offs;
- for (i = pglob->gl_pathc; i--; ++pp)
- if (*pp)
- g_free (*pp);
- g_free (pglob->gl_pathv);
- pglob->gl_pathv = NULL;
- }
-}
-
-static int
-g_Ctoc(const gchar *str, char *buf, unsigned int len)
-{
-
- while (len--) {
- if ((*buf++ = *str++) == EOS)
- return (0);
- }
- return (1);
-}
-
-#ifdef DEBUG_ENABLED
-static void
-qprintf(const char *str, Char *s)
-{
- Char *p;
-
- (void)printf("%s:\n", str);
- for (p = s; *p; p++)
- (void)printf("%c", CHAR(*p));
- (void)printf("\n");
- for (p = s; *p; p++)
- (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
- (void)printf("\n");
- for (p = s; *p; p++)
- (void)printf("%c", ismeta(*p) ? '_' : ' ');
- (void)printf("\n");
-}
-#endif
+++ /dev/null
-/* $OpenBSD: glob.h,v 1.10 2005/12/13 00:35:22 millert Exp $ */
-/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */
-
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Guido van Rossum.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)glob.h 8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _WAPI_GLOB_H_
-#define _WAPI_GLOB_H_
-
-#include <glib.h>
-
-struct stat;
-typedef struct {
- int gl_pathc; /* Count of total paths so far. */
- int gl_offs; /* Reserved at beginning of gl_pathv. */
- int gl_flags; /* Copy of flags parameter to glob. */
- char **gl_pathv; /* List of paths matching pattern. */
-} wapi_glob_t;
-
-#define WAPI_GLOB_APPEND 0x0001 /* Append to output from previous call. */
-#define WAPI_GLOB_UNIQUE 0x0040 /* When appending only add items that aren't already in the list */
-#define WAPI_GLOB_NOSPACE (-1) /* Malloc call failed. */
-#define WAPI_GLOB_ABORTED (-2) /* Unignored error. */
-#define WAPI_GLOB_NOMATCH (-3) /* No match and WAPI_GLOB_NOCHECK not set. */
-#define WAPI_GLOB_NOSYS (-4) /* Function not supported. */
-
-#define WAPI_GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
-#define WAPI_GLOB_LIMIT 0x2000 /* Limit pattern match output to ARG_MAX */
-#define WAPI_GLOB_IGNORECASE 0x4000 /* Ignore case when matching */
-#define WAPI_GLOB_ABEND WAPI_GLOB_ABORTED /* backward compatibility */
-
-G_BEGIN_DECLS
-int _wapi_glob(GDir *dir, const char *, int, wapi_glob_t *);
-void _wapi_globfree(wapi_glob_t *);
-G_END_DECLS
-
-#endif /* !_WAPI_GLOB_H_ */
console-win32.c \
console-win32-internals.h \
cominterop-win32-internals.h \
- file-io-windows.c \
- file-io-windows-internals.h \
+ w32file-win32.c \
+ w32file-win32-internals.h \
icall-windows.c \
icall-windows-internals.h \
marshal-windows.c \
w32process-unix-bsd.c \
w32process-unix-haiku.c \
w32process-unix-default.c \
- w32socket-unix.c
+ w32socket-unix.c \
+ w32file-unix.c \
+ w32file-unix-glob.c \
+ w32file-unix-glob.h
platform_sources = $(unix_sources)
endif
exception.c \
exception.h \
exception-internals.h \
- file-io.c \
- file-io.h \
- file-io-internals.h \
+ w32file.c \
+ w32file.h \
+ w32file-internals.h \
filewatcher.c \
filewatcher.h \
gc-internals.h \
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug-debugger.h>
#include <mono/metadata/attach.h>
-#include <mono/metadata/file-io.h>
+#include <mono/metadata/w32file.h>
#include <mono/metadata/lock-tracer.h>
#include <mono/metadata/console-io.h>
#include <mono/metadata/threads-types.h>
{
guint16 *orig, *dest;
gboolean copy_result;
+ gint32 copy_error;
strcpy (src + srclen - tail_len, extension);
strcpy (target + targetlen - tail_len, extension);
dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
- DeleteFile (dest);
+ mono_w32file_delete (dest);
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
- copy_result = CopyFile (orig, dest, FALSE);
-#else
- copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
-#endif
+ copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
/* Fix for bug #556884 - make sure the files have the correct mode so that they can be
* overwritten when updated in their original locations. */
if (copy_result)
- copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
+ copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
g_free (orig);
g_free (dest);
if (!u16_ini) {
return FALSE;
}
- handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
- NULL, CREATE_NEW, FileAttributes_Normal, NULL);
+ handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
g_free (u16_ini);
if (handle == INVALID_HANDLE_VALUE) {
return FALSE;
}
full_path = mono_path_resolve_symlinks (filename);
- result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
+ result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
g_free (full_path);
CloseHandle (handle);
return result;
char *dir_name = g_path_get_dirname (filename);
MonoDomain *domain = mono_domain_get ();
char *shadow_dir;
+ gint32 copy_error;
mono_error_init (oerror);
orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
- DeleteFile (dest);
+ mono_w32file_delete (dest);
/* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
* let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
* and not have it runtime error" */
- attrs = GetFileAttributes (orig);
+ attrs = mono_w32file_get_attributes (orig);
if (attrs == INVALID_FILE_ATTRIBUTES) {
g_free (shadow);
return (char *)filename;
}
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
- copy_result = CopyFile (orig, dest, FALSE);
-#else
- copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
-#endif
+ copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
/* Fix for bug #556884 - make sure the files have the correct mode so that they can be
* overwritten when updated in their original locations. */
if (copy_result)
- copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
+ copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
g_free (dest);
g_free (orig);
if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
return NULL; /* file not found, shadow copy failed */
- mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
+ mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
return NULL;
}
if (!copy_result) {
g_free (shadow);
- mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
+ mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
return NULL;
}
MonoBoolean
ves_icall_System_ConsoleDriver_Isatty (HANDLE handle)
{
- return (GetFileType (handle) == FILE_TYPE_CHAR);
+ return mono_w32file_get_type (handle) == FILE_TYPE_CHAR;
}
MonoBoolean
#include <mono/metadata/w32semaphore.h>
#include <mono/metadata/w32event.h>
#include <mono/metadata/w32process.h>
+#include <mono/metadata/w32file.h>
#include <metadata/threads.h>
#include <metadata/profiler-private.h>
#include <mono/metadata/coree.h>
#ifndef HOST_WIN32
mono_w32handle_init ();
mono_w32handle_namespace_init ();
- wapi_init ();
#endif
mono_w32mutex_init ();
mono_w32semaphore_init ();
mono_w32event_init ();
mono_w32process_init ();
+ mono_w32file_init ();
#ifndef DISABLE_PERFCOUNTERS
mono_perfcounters_init ();
mono_coop_mutex_destroy (&appdomains_mutex);
mono_w32process_cleanup ();
-
-#ifndef HOST_WIN32
- wapi_cleanup ();
-#endif
+ mono_w32file_cleanup ();
}
void
+++ /dev/null
-/*
- * Copyright 2016 Microsoft
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-#ifndef __MONO_FILE_IO_INTERNALS_H__
-#define __MONO_FILE_IO_INTERNALS_H__
-
-#include <config.h>
-#include <glib.h>
-#include "mono/metadata/object.h"
-#include "mono/metadata/object-internals.h"
-
-gboolean
-mono_file_io_move_file (gunichar2 *path, gunichar2 *dest, gint32 *error);
-
-gboolean
-mono_file_io_copy_file (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32 *error);
-
-gint64
-mono_file_io_get_file_size (HANDLE handle, gint32 *error);
-
-gboolean
-mono_file_io_lock_file (HANDLE handle, gint64 position, gint64 length, gint32 *error);
-
-gboolean
-mono_file_io_replace_file (gunichar2 *destinationFileName, gunichar2 *sourceFileName,
- gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error);
-
-gboolean
-mono_file_io_unlock_file (HANDLE handle, gint64 position, gint64 length, gint32 *error);
-
-HANDLE
-mono_file_io_get_console_output (void);
-
-HANDLE
-mono_file_io_get_console_error (void);
-
-HANDLE
-mono_file_io_get_console_input (void);
-
-#endif /* __MONO_FILE_IO_INTERNALS_H__ */
+++ /dev/null
-/*
- * Copyright 2016 Microsoft
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-#ifndef _MONO_METADATA_FILEIO_WINDOWS_H_
-#define _MONO_METADATA_FILEIO_WINDOWS_H_
-
-#include <config.h>
-#include <glib.h>
-
-#ifdef HOST_WIN32
-#include "mono/metadata/file-io.h"
-#include "mono/metadata/file-io-internals.h"
-#endif /* HOST_WIN32 */
-#endif /* _MONO_METADATA_FILEIO_WINDOWS_H_ */
+++ /dev/null
-/*
- * file-io-windows-uwp.c: UWP file-io support for Mono.
- *
- * Copyright 2016 Microsoft
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
-*/
-#include <config.h>
-#include <glib.h>
-#include "mono/utils/mono-compiler.h"
-
-#if G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT)
-#include <windows.h>
-#include "mono/metadata/file-io-windows-internals.h"
-
-gboolean
-mono_file_io_move_file (gunichar2 *path, gunichar2 *dest, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = MoveFileEx (path, dest, MOVEFILE_COPY_ALLOWED);
- if (result == FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-
-gboolean
-mono_file_io_replace_file (gunichar2 *destinationFileName, gunichar2 *sourceFileName,
- gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = ReplaceFile (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
- if (result == FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-
-gboolean
-mono_file_io_copy_file (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32 *error)
-{
- gboolean result = FALSE;
- COPYFILE2_EXTENDED_PARAMETERS copy_param = {0};
-
- copy_param.dwSize = sizeof (COPYFILE2_EXTENDED_PARAMETERS);
- copy_param.dwCopyFlags = (!overwrite) ? COPY_FILE_FAIL_IF_EXISTS : 0;
-
- MONO_ENTER_GC_SAFE;
-
- result = SUCCEEDED (CopyFile2 (path, dest, ©_param));
- if (result == FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-
-gint64
-mono_file_io_get_file_size (HANDLE handle, gint32 *error)
-{
- LARGE_INTEGER length;
-
- MONO_ENTER_GC_SAFE;
-
- if (!GetFileSizeEx (handle, &length)) {
- *error=GetLastError ();
- length.QuadPart = INVALID_FILE_SIZE;
- }
-
- MONO_EXIT_GC_SAFE;
- return length.QuadPart;
-}
-
-gboolean
-mono_file_io_lock_file (HANDLE handle, gint64 position, gint64 length, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = LockFile (handle, position & 0xFFFFFFFF, position >> 32,
- length & 0xFFFFFFFF, length >> 32);
-
- if (result == FALSE) {
- *error = GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-
-gboolean
-mono_file_io_unlock_file (HANDLE handle, gint64 position, gint64 length, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
- length & 0xFFFFFFFF, length >> 32);
-
- if (result == FALSE) {
- *error = GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-
-HANDLE
-mono_file_io_get_console_output (void)
-{
- MonoError mono_error;
- mono_error_init (&mono_error);
-
- g_unsupported_api ("GetStdHandle (STD_OUTPUT_HANDLE)");
-
- mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "GetStdHandle (STD_OUTPUT_HANDLE)");
- mono_error_set_pending_exception (&mono_error);
-
- SetLastError (ERROR_NOT_SUPPORTED);
-
- return INVALID_HANDLE_VALUE;
-}
-
-HANDLE
-mono_file_io_get_console_input (void)
-{
- MonoError mono_error;
- mono_error_init (&mono_error);
-
- g_unsupported_api ("GetStdHandle (STD_INPUT_HANDLE)");
-
- mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "GetStdHandle (STD_INPUT_HANDLE)");
- mono_error_set_pending_exception (&mono_error);
-
- SetLastError (ERROR_NOT_SUPPORTED);
-
- return INVALID_HANDLE_VALUE;
-}
-
-HANDLE
-mono_file_io_get_console_error (void)
-{
- MonoError mono_error;
- mono_error_init (&mono_error);
-
- g_unsupported_api ("GetStdHandle (STD_ERROR_HANDLE)");
-
- mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "GetStdHandle (STD_ERROR_HANDLE)");
- mono_error_set_pending_exception (&mono_error);
-
- SetLastError (ERROR_NOT_SUPPORTED);
-
- return INVALID_HANDLE_VALUE;
-}
-
-#else /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */
-
-MONO_EMPTY_SOURCE_FILE (file_io_windows_uwp);
-#endif /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */
+++ /dev/null
-/*
- * file-io-windows.c: Windows File IO internal calls.
- *
- * Copyright 2016 Microsoft
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-#include <config.h>
-#include <glib.h>
-
-#if defined(HOST_WIN32)
-#include <winsock2.h>
-#include <windows.h>
-#include "mono/metadata/file-io-windows-internals.h"
-
-gunichar2
-ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
-{
- return (gunichar2) ':'; /* colon */
-}
-
-gunichar2
-ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
-{
- return (gunichar2) '\\'; /* backslash */
-}
-
-gunichar2
-ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
-{
- return (gunichar2) '/'; /* forward slash */
-}
-
-gunichar2
-ves_icall_System_IO_MonoIO_get_PathSeparator ()
-{
- return (gunichar2) ';'; /* semicolon */
-}
-
-void ves_icall_System_IO_MonoIO_DumpHandles (void)
-{
- return;
-}
-#endif /* HOST_WIN32 */
+++ /dev/null
-/*
- * file-io.c: File IO internal calls
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- * Gonzalo Paniagua Javier (gonzalo@ximian.com)
- *
- * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
- * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
- * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#include <config.h>
-
-#include <glib.h>
-#include <string.h>
-#include <errno.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#include <mono/metadata/object.h>
-#include <mono/io-layer/io-layer.h>
-#include <mono/metadata/file-io.h>
-#include <mono/metadata/file-io-internals.h>
-#include <mono/metadata/exception.h>
-#include <mono/metadata/appdomain.h>
-#include <mono/metadata/marshal.h>
-#include <mono/utils/strenc.h>
-#include <utils/mono-io-portability.h>
-#include <mono/metadata/w32handle.h>
-
-#undef DEBUG
-
-/* conversion functions */
-
-static guint32 convert_mode(MonoFileMode mono_mode)
-{
- guint32 mode;
-
- switch(mono_mode) {
- case FileMode_CreateNew:
- mode=CREATE_NEW;
- break;
- case FileMode_Create:
- mode=CREATE_ALWAYS;
- break;
- case FileMode_Open:
- mode=OPEN_EXISTING;
- break;
- case FileMode_OpenOrCreate:
- mode=OPEN_ALWAYS;
- break;
- case FileMode_Truncate:
- mode=TRUNCATE_EXISTING;
- break;
- case FileMode_Append:
- mode=OPEN_ALWAYS;
- break;
- default:
- g_warning("System.IO.FileMode has unknown value 0x%x",
- mono_mode);
- /* Safe fallback */
- mode=OPEN_EXISTING;
- }
-
- return(mode);
-}
-
-static guint32 convert_access(MonoFileAccess mono_access)
-{
- guint32 access;
-
- switch(mono_access) {
- case FileAccess_Read:
- access=GENERIC_READ;
- break;
- case FileAccess_Write:
- access=GENERIC_WRITE;
- break;
- case FileAccess_ReadWrite:
- access=GENERIC_READ|GENERIC_WRITE;
- break;
- default:
- g_warning("System.IO.FileAccess has unknown value 0x%x",
- mono_access);
- /* Safe fallback */
- access=GENERIC_READ;
- }
-
- return(access);
-}
-
-static guint32 convert_share(MonoFileShare mono_share)
-{
- guint32 share = 0;
-
- if (mono_share & FileShare_Read) {
- share |= FILE_SHARE_READ;
- }
- if (mono_share & FileShare_Write) {
- share |= FILE_SHARE_WRITE;
- }
- if (mono_share & FileShare_Delete) {
- share |= FILE_SHARE_DELETE;
- }
-
- if (mono_share & ~(FileShare_Read|FileShare_Write|FileShare_Delete)) {
- g_warning("System.IO.FileShare has unknown value 0x%x",
- mono_share);
- /* Safe fallback */
- share=0;
- }
-
- return(share);
-}
-
-#if 0
-static guint32 convert_stdhandle(guint32 fd)
-{
- guint32 stdhandle;
-
- switch(fd) {
- case 0:
- stdhandle=STD_INPUT_HANDLE;
- break;
- case 1:
- stdhandle=STD_OUTPUT_HANDLE;
- break;
- case 2:
- stdhandle=STD_ERROR_HANDLE;
- break;
- default:
- g_warning("unknown standard file descriptor %d", fd);
- stdhandle=STD_INPUT_HANDLE;
- }
-
- return(stdhandle);
-}
-#endif
-
-static guint32 convert_seekorigin(MonoSeekOrigin origin)
-{
- guint32 w32origin;
-
- switch(origin) {
- case SeekOrigin_Begin:
- w32origin=FILE_BEGIN;
- break;
- case SeekOrigin_Current:
- w32origin=FILE_CURRENT;
- break;
- case SeekOrigin_End:
- w32origin=FILE_END;
- break;
- default:
- g_warning("System.IO.SeekOrigin has unknown value 0x%x",
- origin);
- /* Safe fallback */
- w32origin=FILE_CURRENT;
- }
-
- return(w32origin);
-}
-
-static gint64 convert_filetime (const FILETIME *filetime)
-{
- guint64 ticks = filetime->dwHighDateTime;
- ticks <<= 32;
- ticks += filetime->dwLowDateTime;
- return (gint64)ticks;
-}
-
-static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, MonoIOStat *stat)
-{
- stat->attributes = data->dwFileAttributes;
- stat->creation_time = convert_filetime (&data->ftCreationTime);
- stat->last_access_time = convert_filetime (&data->ftLastAccessTime);
- stat->last_write_time = convert_filetime (&data->ftLastWriteTime);
- stat->length = ((gint64)data->nFileSizeHigh << 32) | data->nFileSizeLow;
-}
-
-/* Managed file attributes have nearly but not quite the same values
- * as the w32 equivalents.
- */
-static guint32 convert_attrs(MonoFileAttributes attrs)
-{
- if(attrs & FileAttributes_Encrypted) {
- attrs = (MonoFileAttributes)(attrs | FILE_ATTRIBUTE_ENCRYPTED);
- }
-
- return(attrs);
-}
-
-/*
- * On Win32, GetFileAttributes|Ex () seems to try opening the file,
- * which might lead to sharing violation errors, whereas FindFirstFile
- * always succeeds. These 2 wrappers resort to FindFirstFile if
- * GetFileAttributes|Ex () has failed.
- */
-static guint32
-get_file_attributes (const gunichar2 *path)
-{
- guint32 res;
- WIN32_FIND_DATA find_data;
- HANDLE find_handle;
- gint32 error;
-
- res = GetFileAttributes (path);
- if (res != -1)
- return res;
-
- error = GetLastError ();
-
- if (error != ERROR_SHARING_VIOLATION)
- return res;
-
- find_handle = FindFirstFile (path, &find_data);
-
- if (find_handle == INVALID_HANDLE_VALUE)
- return res;
-
- FindClose (find_handle);
-
- return find_data.dwFileAttributes;
-}
-
-static gboolean
-get_file_attributes_ex (const gunichar2 *path, WIN32_FILE_ATTRIBUTE_DATA *data)
-{
- gboolean res;
- WIN32_FIND_DATA find_data;
- HANDLE find_handle;
- gint32 error;
-
- res = GetFileAttributesEx (path, GetFileExInfoStandard, data);
- if (res)
- return TRUE;
-
- error = GetLastError ();
-
- if (error != ERROR_SHARING_VIOLATION)
- return FALSE;
-
- find_handle = FindFirstFile (path, &find_data);
-
- if (find_handle == INVALID_HANDLE_VALUE)
- return FALSE;
-
- FindClose (find_handle);
-
- data->dwFileAttributes = find_data.dwFileAttributes;
- data->ftCreationTime = find_data.ftCreationTime;
- data->ftLastAccessTime = find_data.ftLastAccessTime;
- data->ftLastWriteTime = find_data.ftLastWriteTime;
- data->nFileSizeHigh = find_data.nFileSizeHigh;
- data->nFileSizeLow = find_data.nFileSizeLow;
-
- return TRUE;
-}
-
-/* System.IO.MonoIO internal calls */
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
-{
- gboolean ret;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- ret=CreateDirectory (mono_string_chars (path), NULL);
- if(ret==FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
-{
- gboolean ret;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- ret=RemoveDirectory (mono_string_chars (path));
- if(ret==FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-static gchar *
-get_search_dir (const gunichar2 *pattern)
-{
- gchar *p;
- gchar *result;
-
- p = g_utf16_to_utf8 (pattern, -1, NULL, NULL, NULL);
- result = g_path_get_dirname (p);
- g_free (p);
- return result;
-}
-
-static GPtrArray *
-get_filesystem_entries (const gunichar2 *path,
- const gunichar2 *path_with_pattern,
- gint attrs, gint mask,
- gint32 *error)
-{
- int i;
- WIN32_FIND_DATA data;
- HANDLE find_handle;
- GPtrArray *names = NULL;
- gchar *utf8_path = NULL, *utf8_result, *full_name;
- gint32 attributes;
-
- mask = convert_attrs ((MonoFileAttributes)mask);
- attributes = get_file_attributes (path);
- if (attributes != -1) {
- if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
- *error = ERROR_INVALID_NAME;
- goto fail;
- }
- } else {
- *error = GetLastError ();
- goto fail;
- }
-
- find_handle = FindFirstFile (path_with_pattern, &data);
- if (find_handle == INVALID_HANDLE_VALUE) {
- gint32 find_error = GetLastError ();
-
- if (find_error == ERROR_FILE_NOT_FOUND || find_error == ERROR_NO_MORE_FILES) {
- /* No files, so just return an empty array */
- goto fail;
- }
-
- *error = find_error;
- goto fail;
- }
-
- utf8_path = get_search_dir (path_with_pattern);
- names = g_ptr_array_new ();
-
- do {
- if ((data.cFileName[0] == '.' && data.cFileName[1] == 0) ||
- (data.cFileName[0] == '.' && data.cFileName[1] == '.' && data.cFileName[2] == 0)) {
- continue;
- }
-
- if ((data.dwFileAttributes & mask) == attrs) {
- utf8_result = g_utf16_to_utf8 (data.cFileName, -1, NULL, NULL, NULL);
- if (utf8_result == NULL) {
- continue;
- }
-
- full_name = g_build_filename (utf8_path, utf8_result, NULL);
- g_ptr_array_add (names, full_name);
-
- g_free (utf8_result);
- }
- } while(FindNextFile (find_handle, &data));
-
- if (FindClose (find_handle) == FALSE) {
- *error = GetLastError ();
- goto fail;
- }
-
- g_free (utf8_path);
- return names;
-fail:
- if (names) {
- for (i = 0; i < names->len; i++)
- g_free (g_ptr_array_index (names, i));
- g_ptr_array_free (names, TRUE);
- }
- g_free (utf8_path);
- return FALSE;
-}
-
-
-MonoArray *
-ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
- MonoString *path_with_pattern,
- gint attrs, gint mask,
- gint32 *ioerror)
-{
- MonoError error;
- MonoDomain *domain = mono_domain_get ();
- MonoArray *result;
- int i;
- GPtrArray *names;
-
- *ioerror = ERROR_SUCCESS;
-
- MONO_ENTER_GC_SAFE;
- names = get_filesystem_entries (mono_string_chars (path), mono_string_chars (path_with_pattern), attrs, mask, ioerror);
- MONO_EXIT_GC_SAFE;
-
- if (!names) {
- // If there's no array and no error, then return an empty array.
- if (*ioerror == ERROR_SUCCESS) {
- MonoArray *arr = mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
- mono_error_set_pending_exception (&error);
- return arr;
- }
- return NULL;
- }
-
- result = mono_array_new_checked (domain, mono_defaults.string_class, names->len, &error);
- if (mono_error_set_pending_exception (&error))
- goto leave;
- for (i = 0; i < names->len; i++) {
- mono_array_setref (result, i, mono_string_new (domain, (const char *)g_ptr_array_index (names, i)));
- g_free (g_ptr_array_index (names, i));
- }
-leave:
- g_ptr_array_free (names, TRUE);
- return result;
-}
-
-typedef struct {
- MonoDomain *domain;
- gchar *utf8_path;
- HANDLE find_handle;
-} IncrementalFind;
-
-static gboolean
-incremental_find_check_match (IncrementalFind *handle, WIN32_FIND_DATA *data, MonoString **result)
-{
- gchar *utf8_result;
- gchar *full_name;
-
- if ((data->cFileName[0] == '.' && data->cFileName[1] == 0) || (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0))
- return FALSE;
-
- utf8_result = g_utf16_to_utf8 (data->cFileName, -1, NULL, NULL, NULL);
- if (utf8_result == NULL)
- return FALSE;
-
- full_name = g_build_filename (handle->utf8_path, utf8_result, NULL);
- g_free (utf8_result);
- *result = mono_string_new (mono_domain_get (), full_name);
- g_free (full_name);
-
- return TRUE;
-}
-
-HANDLE
-ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path_with_pattern, MonoString **file_name, gint32 *file_attr, gint32 *ioerror)
-{
- HANDLE hnd;
- WIN32_FIND_DATA data;
- MonoError error;
-
- hnd = FindFirstFile (mono_string_chars (path_with_pattern), &data);
-
- if (hnd == INVALID_HANDLE_VALUE) {
- *file_name = NULL;
- *file_attr = 0;
- *ioerror = GetLastError ();
- return hnd;
- }
-
- mono_gc_wbarrier_generic_store (file_name, (MonoObject*) mono_string_from_utf16_checked (data.cFileName, &error));
- mono_error_set_pending_exception (&error);
-
- *file_attr = data.dwFileAttributes;
- *ioerror = ERROR_SUCCESS;
-
- return hnd;
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_FindNextFile (HANDLE hnd, MonoString **file_name, gint32 *file_attr, gint32 *ioerror)
-{
- MonoBoolean res;
- WIN32_FIND_DATA data;
- MonoError error;
-
- res = FindNextFile (hnd, &data);
-
- if (res == FALSE) {
- *file_name = NULL;
- *file_attr = 0;
- *ioerror = GetLastError ();
- return res;
- }
-
- mono_gc_wbarrier_generic_store (file_name, (MonoObject*) mono_string_from_utf16_checked (data.cFileName, &error));
- mono_error_set_pending_exception (&error);
-
- *file_attr = data.dwFileAttributes;
- *ioerror = ERROR_SUCCESS;
-
- return res;
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_FindCloseFile (HANDLE hnd)
-{
- return FindClose (hnd);
-}
-
-/* FIXME make gc suspendable */
-MonoString *
-ves_icall_System_IO_MonoIO_FindFirst (MonoString *path,
- MonoString *path_with_pattern,
- gint32 *result_attr, gint32 *ioerror,
- gpointer *handle)
-{
- MonoError error;
- WIN32_FIND_DATA data;
- HANDLE find_handle;
- IncrementalFind *ifh;
- MonoString *result;
-
- *ioerror = ERROR_SUCCESS;
-
- find_handle = FindFirstFile (mono_string_chars (path_with_pattern), &data);
-
- if (find_handle == INVALID_HANDLE_VALUE) {
- gint32 find_error = GetLastError ();
- *handle = NULL;
-
- if (find_error == ERROR_FILE_NOT_FOUND)
- return NULL;
-
- *ioerror = find_error;
- return NULL;
- }
-
- ifh = g_new (IncrementalFind, 1);
- ifh->find_handle = find_handle;
- ifh->utf8_path = mono_string_to_utf8_checked (path, &error);
- if (mono_error_set_pending_exception (&error)) {
- MONO_ENTER_GC_SAFE;
- FindClose (find_handle);
- MONO_EXIT_GC_SAFE;
- g_free (ifh);
- return NULL;
- }
- ifh->domain = mono_domain_get ();
- *handle = ifh;
-
- while (incremental_find_check_match (ifh, &data, &result) == 0){
- if (FindNextFile (find_handle, &data) == FALSE){
- int e = GetLastError ();
- if (e != ERROR_NO_MORE_FILES)
- *ioerror = e;
- return NULL;
- }
- }
- *result_attr = data.dwFileAttributes;
-
- return result;
-}
-
-/* FIXME make gc suspendable */
-MonoString *
-ves_icall_System_IO_MonoIO_FindNext (gpointer handle, gint32 *result_attr, gint32 *error)
-{
- IncrementalFind *ifh = (IncrementalFind *)handle;
- WIN32_FIND_DATA data;
- MonoString *result;
-
- *error = ERROR_SUCCESS;
- do {
- if (FindNextFile (ifh->find_handle, &data) == FALSE){
- int e = GetLastError ();
- if (e != ERROR_NO_MORE_FILES)
- *error = e;
- return NULL;
- }
- } while (incremental_find_check_match (ifh, &data, &result) == 0);
-
- *result_attr = data.dwFileAttributes;
- return result;
-}
-
-int
-ves_icall_System_IO_MonoIO_FindClose (gpointer handle)
-{
- IncrementalFind *ifh = (IncrementalFind *)handle;
- gint32 error;
-
- MONO_ENTER_GC_SAFE;
- if (FindClose (ifh->find_handle) == FALSE){
- error = GetLastError ();
- } else
- error = ERROR_SUCCESS;
- g_free (ifh->utf8_path);
- g_free (ifh);
- MONO_EXIT_GC_SAFE;
-
- return error;
-}
-
-MonoString *
-ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *io_error)
-{
- MonoError error;
- MonoString *result;
- gunichar2 *buf;
- int len, res_len;
-
- len = MAX_PATH + 1; /*FIXME this is too smal under most unix systems.*/
- buf = g_new (gunichar2, len);
-
- mono_error_init (&error);
- *io_error=ERROR_SUCCESS;
- result = NULL;
-
- res_len = GetCurrentDirectory (len, buf);
- if (res_len > len) { /*buf is too small.*/
- int old_res_len = res_len;
- g_free (buf);
- buf = g_new (gunichar2, res_len);
- res_len = GetCurrentDirectory (res_len, buf) == old_res_len;
- }
-
- if (res_len) {
- len = 0;
- while (buf [len])
- ++ len;
-
- result = mono_string_new_utf16_checked (mono_domain_get (), buf, len, &error);
- } else {
- *io_error=GetLastError ();
- }
-
- g_free (buf);
- mono_error_set_pending_exception (&error);
- return result;
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
- gint32 *error)
-{
- gboolean ret;
-
- *error=ERROR_SUCCESS;
-
- ret=SetCurrentDirectory (mono_string_chars (path));
- if(ret==FALSE) {
- *error=GetLastError ();
- }
-
- return(ret);
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-gboolean
-mono_file_io_move_file (gunichar2 *path, gunichar2 *dest, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = MoveFile (path, dest);
- if (result == FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-#endif /* HAVE_CLASSIC_WINAPI_SUPPORT */
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest, gint32 *error)
-{
- *error=ERROR_SUCCESS;
- return mono_file_io_move_file (mono_string_chars (path), mono_string_chars (dest), error);
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-gboolean
-mono_file_io_replace_file (gunichar2 *destinationFileName, gunichar2 *sourceFileName,
- gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = ReplaceFile (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
- if (result == FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-#endif /* HAVE_CLASSIC_WINAPI_SUPPORT */
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
- MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
- gint32 *error)
-{
- gunichar2 *utf16_sourceFileName = NULL, *utf16_destinationFileName = NULL, *utf16_destinationBackupFileName = NULL;
- guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
-
- if (sourceFileName)
- utf16_sourceFileName = mono_string_chars (sourceFileName);
- if (destinationFileName)
- utf16_destinationFileName = mono_string_chars (destinationFileName);
- if (destinationBackupFileName)
- utf16_destinationBackupFileName = mono_string_chars (destinationBackupFileName);
-
- *error = ERROR_SUCCESS;
- if (ignoreMetadataErrors)
- replaceFlags |= REPLACEFILE_IGNORE_MERGE_ERRORS;
-
- /* FIXME: source and destination file names must not be NULL, but apparently they might be! */
- return mono_file_io_replace_file (utf16_destinationFileName, utf16_sourceFileName,
- utf16_destinationBackupFileName, replaceFlags, error);
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-gboolean
-mono_file_io_copy_file (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = CopyFile (path, dest, !overwrite);
- if (result == FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-#endif /* HAVE_CLASSIC_WINAPI_SUPPORT */
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
- MonoBoolean overwrite, gint32 *error)
-{
- *error=ERROR_SUCCESS;
- return mono_file_io_copy_file (mono_string_chars (path), mono_string_chars (dest), overwrite, error);
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
-{
- gboolean ret;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- ret=DeleteFile (mono_string_chars (path));
- if(ret==FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-gint32
-ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
-{
- gint32 ret;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- ret=get_file_attributes (mono_string_chars (path));
-
- /*
- * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
- * headers is wrong, hence this temporary workaround.
- * See
- * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
- */
- if (ret==-1) {
- /* if(ret==INVALID_FILE_ATTRIBUTES) { */
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
- gint32 *error)
-{
- gboolean ret;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- ret=SetFileAttributes (mono_string_chars (path),
- convert_attrs ((MonoFileAttributes)attrs));
- if(ret==FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-gint32
-ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
-{
- gboolean ret;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- ret=GetFileType (handle);
- if(ret==FILE_TYPE_UNKNOWN) {
- /* Not necessarily an error, but the caller will have
- * to decide based on the error value.
- */
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
- gint32 *error)
-{
- gboolean result;
- WIN32_FILE_ATTRIBUTE_DATA data;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- result = get_file_attributes_ex (mono_string_chars (path), &data);
-
- if (result) {
- convert_win32_file_attribute_data (&data, stat);
- } else {
- *error=GetLastError ();
- memset (stat, 0, sizeof (MonoIOStat));
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-
-HANDLE
-ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
- gint32 access_mode, gint32 share, gint32 options,
- gint32 *error)
-{
- HANDLE ret;
- int attributes, attrs;
- gunichar2 *chars;
- MONO_ENTER_GC_SAFE;
-
- chars = mono_string_chars (filename);
- *error=ERROR_SUCCESS;
-
- if (options != 0){
- if (options & FileOptions_Encrypted)
- attributes = FILE_ATTRIBUTE_ENCRYPTED;
- else
- attributes = FILE_ATTRIBUTE_NORMAL;
- if (options & FileOptions_DeleteOnClose)
- attributes |= FILE_FLAG_DELETE_ON_CLOSE;
- if (options & FileOptions_SequentialScan)
- attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
- if (options & FileOptions_RandomAccess)
- attributes |= FILE_FLAG_RANDOM_ACCESS;
-
- if (options & FileOptions_Temporary)
- attributes |= FILE_ATTRIBUTE_TEMPORARY;
-
- if (options & FileOptions_WriteThrough)
- attributes |= FILE_FLAG_WRITE_THROUGH;
- } else
- attributes = FILE_ATTRIBUTE_NORMAL;
-
- /* If we're opening a directory we need to set the extra flag
- */
- attrs = get_file_attributes (chars);
- if (attrs != INVALID_FILE_ATTRIBUTES) {
- if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
- attributes |= FILE_FLAG_BACKUP_SEMANTICS;
- }
- }
-
- ret=CreateFile (chars, convert_access ((MonoFileAccess)access_mode),
- convert_share ((MonoFileShare)share), NULL, convert_mode ((MonoFileMode)mode),
- attributes, NULL);
- if(ret==INVALID_HANDLE_VALUE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
-{
- gboolean ret;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- ret=CloseHandle (handle);
- if(ret==FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-gint32
-ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
- gint32 dest_offset, gint32 count,
- gint32 *error)
-{
- guchar *buffer;
- gboolean result;
- guint32 n;
-
- *error=ERROR_SUCCESS;
-
- MONO_CHECK_ARG_NULL (dest, 0);
-
- if (dest_offset > mono_array_length (dest) - count) {
- mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
- return 0;
- }
-
- buffer = mono_array_addr (dest, guchar, dest_offset);
-
- MONO_ENTER_GC_SAFE;
- result = ReadFile (handle, buffer, count, &n, NULL);
- MONO_EXIT_GC_SAFE;
-
- if (!result) {
- *error=GetLastError ();
- return -1;
- }
-
- return (gint32)n;
-}
-
-gint32
-ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
- gint32 src_offset, gint32 count,
- gint32 *error)
-{
- guchar *buffer;
- gboolean result;
- guint32 n;
-
- *error=ERROR_SUCCESS;
-
- MONO_CHECK_ARG_NULL (src, 0);
-
- if (src_offset > mono_array_length (src) - count) {
- mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
- return 0;
- }
-
- buffer = mono_array_addr (src, guchar, src_offset);
- MONO_ENTER_GC_SAFE;
- result = WriteFile (handle, buffer, count, &n, NULL);
- MONO_EXIT_GC_SAFE;
-
- if (!result) {
- *error=GetLastError ();
- return -1;
- }
-
- return (gint32)n;
-}
-
-gint64
-ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
- gint32 *error)
-{
- gint32 offset_hi;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- offset_hi = offset >> 32;
- offset = SetFilePointer (handle, (gint32) (offset & 0xFFFFFFFF), &offset_hi,
- convert_seekorigin ((MonoSeekOrigin)origin));
-
- if(offset==INVALID_SET_FILE_POINTER) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return offset | ((gint64)offset_hi << 32);
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
-{
- gboolean ret;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- ret=FlushFileBuffers (handle);
- if(ret==FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-gint64
-mono_file_io_get_file_size (HANDLE handle, gint32 *error)
-{
- gint64 length;
- guint32 length_hi;
-
- MONO_ENTER_GC_SAFE;
-
- length = GetFileSize (handle, &length_hi);
- if(length==INVALID_FILE_SIZE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return length | ((gint64)length_hi << 32);
-}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
-
-gint64
-ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
-{
- *error=ERROR_SUCCESS;
- return mono_file_io_get_file_size (handle, error);
-}
-
-/* FIXME make gc suspendable */
-MonoBoolean
-ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
- gint32 *error)
-{
- gint64 offset, offset_set;
- gint32 offset_hi;
- gint32 length_hi;
- gboolean result;
-
- *error=ERROR_SUCCESS;
-
- /* save file pointer */
-
- offset_hi = 0;
- offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
- if(offset==INVALID_SET_FILE_POINTER) {
- *error=GetLastError ();
- return(FALSE);
- }
-
- /* extend or truncate */
-
- length_hi = length >> 32;
- offset_set=SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi,
- FILE_BEGIN);
- if(offset_set==INVALID_SET_FILE_POINTER) {
- *error=GetLastError ();
- return(FALSE);
- }
-
- result = SetEndOfFile (handle);
- if(result==FALSE) {
- *error=GetLastError ();
- return(FALSE);
- }
-
- /* restore file pointer */
-
- offset_set=SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
- FILE_BEGIN);
- if(offset_set==INVALID_SET_FILE_POINTER) {
- *error=GetLastError ();
- return(FALSE);
- }
-
- return result;
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
- gint64 last_access_time,
- gint64 last_write_time, gint32 *error)
-{
- gboolean ret;
- const FILETIME *creation_filetime;
- const FILETIME *last_access_filetime;
- const FILETIME *last_write_filetime;
- MONO_ENTER_GC_SAFE;
-
- *error=ERROR_SUCCESS;
-
- if (creation_time < 0)
- creation_filetime = NULL;
- else
- creation_filetime = (FILETIME *)&creation_time;
-
- if (last_access_time < 0)
- last_access_filetime = NULL;
- else
- last_access_filetime = (FILETIME *)&last_access_time;
-
- if (last_write_time < 0)
- last_write_filetime = NULL;
- else
- last_write_filetime = (FILETIME *)&last_write_time;
-
- ret=SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
- if(ret==FALSE) {
- *error=GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return(ret);
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-HANDLE
-mono_file_io_get_console_output (void)
-{
- return GetStdHandle (STD_OUTPUT_HANDLE);
-}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
-
-HANDLE
-ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
-{
- return mono_file_io_get_console_output ();
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-HANDLE
-mono_file_io_get_console_input (void)
-{
- return GetStdHandle (STD_INPUT_HANDLE);
-}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
-
-HANDLE
-ves_icall_System_IO_MonoIO_get_ConsoleInput ()
-{
- return mono_file_io_get_console_input ();
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-HANDLE
-mono_file_io_get_console_error (void)
-{
- return GetStdHandle (STD_ERROR_HANDLE);
-}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
-
-HANDLE
-ves_icall_System_IO_MonoIO_get_ConsoleError ()
-{
- return mono_file_io_get_console_error ();
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle, HANDLE *write_handle, gint32 *error)
-{
- SECURITY_ATTRIBUTES attr;
- gboolean ret;
-
- attr.nLength=sizeof(SECURITY_ATTRIBUTES);
- attr.bInheritHandle=TRUE;
- attr.lpSecurityDescriptor=NULL;
-
- MONO_ENTER_GC_SAFE;
- ret=CreatePipe (read_handle, write_handle, &attr, 0);
- MONO_EXIT_GC_SAFE;
-
- if(ret==FALSE) {
- *error = GetLastError ();
- /* FIXME: throw an exception? */
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_DuplicateHandle (HANDLE source_process_handle, HANDLE source_handle,
- HANDLE target_process_handle, HANDLE *target_handle, gint32 access, gint32 inherit, gint32 options, gint32 *error)
-{
- /* This is only used on Windows */
- gboolean ret;
-
- MONO_ENTER_GC_SAFE;
-#ifdef HOST_WIN32
- ret=DuplicateHandle (source_process_handle, source_handle, target_process_handle, target_handle, access, inherit, options);
-#else
- mono_w32handle_ref (source_handle);
- *target_handle = source_handle;
- ret = TRUE;
-#endif
- MONO_EXIT_GC_SAFE;
-
- if(ret==FALSE) {
- *error = GetLastError ();
- /* FIXME: throw an exception? */
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-#ifndef HOST_WIN32
-gunichar2
-ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
-{
- return (gunichar2) '/'; /* forward slash */
-}
-
-gunichar2
-ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
-{
- return (gunichar2) '/'; /* forward slash */
-}
-
-gunichar2
-ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
-{
- if (IS_PORTABILITY_SET)
- return (gunichar2) '\\'; /* backslash */
- else
- return (gunichar2) '/'; /* forward slash */
-}
-
-gunichar2
-ves_icall_System_IO_MonoIO_get_PathSeparator ()
-{
- return (gunichar2) ':'; /* colon */
-}
-#endif /* !HOST_WIN32 */
-
-static const gunichar2
-invalid_path_chars [] = {
-#if defined (TARGET_WIN32)
- 0x0022, /* double quote, which seems allowed in MS.NET but should be rejected */
- 0x003c, /* less than */
- 0x003e, /* greater than */
- 0x007c, /* pipe */
- 0x0008,
- 0x0010,
- 0x0011,
- 0x0012,
- 0x0014,
- 0x0015,
- 0x0016,
- 0x0017,
- 0x0018,
- 0x0019,
-#endif
- 0x0000 /* null */
-};
-
-MonoArray *
-ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
-{
- MonoError error;
- MonoArray *chars;
- MonoDomain *domain;
- int i, n;
-
- domain = mono_domain_get ();
- n = sizeof (invalid_path_chars) / sizeof (gunichar2);
- chars = mono_array_new_checked (domain, mono_defaults.char_class, n, &error);
- if (mono_error_set_pending_exception (&error))
- return NULL;
-
- for (i = 0; i < n; ++ i)
- mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
-
- return chars;
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-gboolean
-mono_file_io_lock_file (HANDLE handle, gint64 position, gint64 length, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = LockFile (handle, position & 0xFFFFFFFF, position >> 32,
- length & 0xFFFFFFFF, length >> 32);
-
- if (result == FALSE) {
- *error = GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
-
-void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
- gint64 length, gint32 *error)
-{
- *error=ERROR_SUCCESS;
- mono_file_io_lock_file (handle, position, length, error);
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
-gboolean
-mono_file_io_unlock_file (HANDLE handle, gint64 position, gint64 length, gint32 *error)
-{
- gboolean result = FALSE;
- MONO_ENTER_GC_SAFE;
-
- result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
- length & 0xFFFFFFFF, length >> 32);
-
- if (result == FALSE) {
- *error = GetLastError ();
- }
-
- MONO_EXIT_GC_SAFE;
- return result;
-}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
-
-void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
- gint64 length, gint32 *error)
-{
- *error=ERROR_SUCCESS;
- mono_file_io_unlock_file (handle, position, length, error);
-}
-
-//Support for io-layer free mmap'd files.
-
-#if defined (TARGET_IOS) || defined (TARGET_ANDROID)
-
-gint64
-mono_filesize_from_path (MonoString *string)
-{
- MonoError error;
- struct stat buf;
- gint64 res;
- char *path = mono_string_to_utf8_checked (string, &error);
- mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
-
- MONO_ENTER_GC_SAFE;
- if (stat (path, &buf) == -1)
- res = -1;
- else
- res = (gint64)buf.st_size;
-
- g_free (path);
-
- MONO_EXIT_GC_SAFE;
- return res;
-}
-
-gint64
-mono_filesize_from_fd (int fd)
-{
- struct stat buf;
- int res;
-
- MONO_ENTER_GC_SAFE;
- res = fstat (fd, &buf);
- MONO_EXIT_GC_SAFE;
-
- if (res == -1)
- return (gint64)-1;
-
- return (gint64)buf.st_size;
-}
-
-#endif
-
-#ifndef HOST_WIN32
-void mono_w32handle_dump (void);
-
-void ves_icall_System_IO_MonoIO_DumpHandles (void)
-{
-
- mono_w32handle_dump ();
-}
-#endif /* !HOST_WIN32 */
+++ /dev/null
-/*
- * file-io.h: File IO internal calls
- *
- * Authors:
- * Dick Porter (dick@ximian.com)
- * Dan Lewis (dihlewis@yahoo.co.uk)
- *
- * (C) 2001 Ximian, Inc.
- * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#ifndef _MONO_METADATA_FILEIO_H_
-#define _MONO_METADATA_FILEIO_H_
-
-#include <config.h>
-#include <glib.h>
-
-#include <mono/metadata/object-internals.h>
-#include <mono/utils/mono-compiler.h>
-
-G_BEGIN_DECLS
-
-/* This is a copy of System.IO.FileAccess */
-typedef enum {
- FileAccess_Read=0x01,
- FileAccess_Write=0x02,
- FileAccess_ReadWrite=FileAccess_Read|FileAccess_Write
-} MonoFileAccess;
-
-/* This is a copy of System.IO.FileMode */
-typedef enum {
- FileMode_CreateNew=1,
- FileMode_Create=2,
- FileMode_Open=3,
- FileMode_OpenOrCreate=4,
- FileMode_Truncate=5,
- FileMode_Append=6
-} MonoFileMode;
-
-/* This is a copy of System.IO.FileShare */
-typedef enum {
- FileShare_None=0x0,
- FileShare_Read=0x01,
- FileShare_Write=0x02,
- FileShare_ReadWrite=FileShare_Read|FileShare_Write,
- FileShare_Delete=0x04
-} MonoFileShare;
-
-/* This is a copy of System.IO.FileOptions */
-typedef enum {
- FileOptions_None = 0,
- FileOptions_Temporary = 1, // Internal. See note in System.IO.FileOptions
- FileOptions_Encrypted = 0x4000,
- FileOptions_DeleteOnClose = 0x4000000,
- FileOptions_SequentialScan = 0x8000000,
- FileOptions_RandomAccess = 0x10000000,
- FileOptions_Asynchronous = 0x40000000,
- FileOptions_WriteThrough = 0x80000000
-} MonoFileOptions;
-
-/* This is a copy of System.IO.SeekOrigin */
-typedef enum {
- SeekOrigin_Begin=0,
- SeekOrigin_Current=1,
- SeekOrigin_End=2
-} MonoSeekOrigin;
-
-/* This is a copy of System.IO.MonoIOStat */
-typedef struct _MonoIOStat {
- gint32 attributes;
- gint64 length;
- gint64 creation_time;
- gint64 last_access_time;
- gint64 last_write_time;
-} MonoIOStat;
-
-/* This is a copy of System.IO.FileAttributes */
-typedef enum {
- FileAttributes_ReadOnly=0x00001,
- FileAttributes_Hidden=0x00002,
- FileAttributes_System=0x00004,
- FileAttributes_Directory=0x00010,
- FileAttributes_Archive=0x00020,
- FileAttributes_Device=0x00040,
- FileAttributes_Normal=0x00080,
- FileAttributes_Temporary=0x00100,
- FileAttributes_SparseFile=0x00200,
- FileAttributes_ReparsePoint=0x00400,
- FileAttributes_Compressed=0x00800,
- FileAttributes_Offline=0x01000,
- FileAttributes_NotContentIndexed=0x02000,
- FileAttributes_Encrypted=0x04000,
- FileAttributes_MonoExecutable= (int) 0x80000000
-} MonoFileAttributes;
-/* This is not used anymore
-typedef struct _MonoFSAsyncResult {
- MonoObject obj;
- MonoObject *state;
- MonoBoolean completed;
- MonoBoolean done;
- MonoException *exc;
- MonoWaitHandle *wait_handle;
- MonoDelegate *async_callback;
- MonoBoolean completed_synch;
- MonoArray *buffer;
- gint offset;
- gint count;
- gint original_count;
- gint bytes_read;
- MonoDelegate *real_cb;
-} MonoFSAsyncResult;
-*/
-/* System.IO.MonoIO */
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error);
-
-MonoArray *
-ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
- MonoString *path_with_pattern,
- gint mask, gint attrs,
- gint32 *error);
-
-extern gpointer
-ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path_with_pattern,
- MonoString **file_name,
- gint32 *file_attr,
- gint32 *ioerror);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_FindNextFile (gpointer hnd,
- MonoString **file_name,
- gint32 *file_attr,
- gint32 *ioerror);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_FindCloseFile (gpointer hnd);
-
-extern MonoString *
-ves_icall_System_IO_MonoIO_FindFirst (MonoString *path,
- MonoString *path_with_pattern,
- gint32 *result_mask,
- gint32 *error,
- gpointer *handle);
-extern MonoString *
-ves_icall_System_IO_MonoIO_FindNext (gpointer handle, gint32 *result_mask, gint32 *error);
-
-extern int
-ves_icall_System_IO_MonoIO_FindClose (gpointer handle);
-
-extern MonoString *
-ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
- gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
- gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
- MonoBoolean overwrite, gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error);
-
-extern gint32
-ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
- gint32 *error);
-
-extern gint32
-ves_icall_System_IO_MonoIO_GetFileType (gpointer handle, gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
- gint32 *error);
-
-extern gpointer
-ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
- gint32 access_mode, gint32 share, gint32 options,
- gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_Close (gpointer handle, gint32 *error);
-
-extern gint32
-ves_icall_System_IO_MonoIO_Read (gpointer handle, MonoArray *dest,
- gint32 dest_offset, gint32 count,
- gint32 *error);
-
-extern gint32
-ves_icall_System_IO_MonoIO_Write (gpointer handle, MonoArray *src,
- gint32 src_offset, gint32 count,
- gint32 *error);
-
-extern gint64
-ves_icall_System_IO_MonoIO_Seek (gpointer handle, gint64 offset, gint32 origin,
- gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_Flush (gpointer handle, gint32 *error);
-
-extern gint64
-ves_icall_System_IO_MonoIO_GetLength (gpointer handle, gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_SetLength (gpointer handle, gint64 length,
- gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_SetFileTime (gpointer handle, gint64 creation_time,
- gint64 last_access_time,
- gint64 last_write_time, gint32 *error);
-
-extern gpointer
-ves_icall_System_IO_MonoIO_get_ConsoleOutput (void);
-
-extern gpointer
-ves_icall_System_IO_MonoIO_get_ConsoleInput (void);
-
-extern gpointer
-ves_icall_System_IO_MonoIO_get_ConsoleError (void);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_CreatePipe (gpointer *read_handle, gpointer *write_handle, gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_DuplicateHandle (gpointer source_process_handle, gpointer source_handle,
- gpointer target_process_handle, gpointer *target_handle, gint32 access, gint32 inherit, gint32 options, gint32 *error);
-
-extern gunichar2
-ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar (void);
-
-extern gunichar2
-ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar (void);
-
-extern gunichar2
-ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar (void);
-
-extern gunichar2
-ves_icall_System_IO_MonoIO_get_PathSeparator (void);
-
-extern MonoArray *
-ves_icall_System_IO_MonoIO_get_InvalidPathChars (void);
-
-extern void ves_icall_System_IO_MonoIO_Lock (gpointer handle, gint64 position,
- gint64 length, gint32 *error);
-extern void ves_icall_System_IO_MonoIO_Unlock (gpointer handle, gint64 position,
- gint64 length, gint32 *error);
-
-extern MonoBoolean
-ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
- MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
- gint32 *error);
-
-MONO_RT_EXTERNAL_ONLY
-extern gint64
-mono_filesize_from_path (MonoString *path);
-
-extern gint64
-mono_filesize_from_fd (int fd);
-
-void
-ves_icall_System_IO_MonoIO_DumpHandles (void);
-
-G_END_DECLS
-
-#endif /* _MONO_METADATA_FILEIO_H_ */
#include <mono/metadata/object.h>
-#include <mono/metadata/file-io.h>
+#include <mono/metadata/w32file.h>
#include <mono/metadata/file-mmap.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-memory-model.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/exception-internals.h>
-#include <mono/metadata/file-io.h>
+#include <mono/metadata/w32file.h>
#include <mono/metadata/console-io.h>
#include <mono/metadata/mono-route.h>
#include <mono/metadata/w32socket.h>
ptr = buf;
while (size > initial_size) {
- size = (guint) GetLogicalDriveStrings (initial_size, ptr);
+ size = (guint) mono_w32file_get_logical_drive (initial_size, ptr);
if (size > initial_size) {
if (ptr != buf)
g_free (ptr);
MonoError error;
gunichar2 volume_name [MAX_PATH + 1];
- if (GetVolumeInformation (mono_string_chars (path), NULL, 0, NULL, NULL, NULL, volume_name, MAX_PATH + 1) == FALSE)
+ if (mono_w32file_get_volume_information (mono_string_chars (path), NULL, 0, NULL, NULL, NULL, volume_name, MAX_PATH + 1) == FALSE)
return NULL;
MonoString *result = mono_string_from_utf16_checked (volume_name, &error);
mono_error_set_pending_exception (&error);
gint32 *error)
{
gboolean result;
- ULARGE_INTEGER wapi_free_bytes_avail;
- ULARGE_INTEGER wapi_total_number_of_bytes;
- ULARGE_INTEGER wapi_total_number_of_free_bytes;
*error = ERROR_SUCCESS;
- result = GetDiskFreeSpaceEx (mono_string_chars (path_name), &wapi_free_bytes_avail, &wapi_total_number_of_bytes,
- &wapi_total_number_of_free_bytes);
- if (result) {
- *free_bytes_avail = wapi_free_bytes_avail.QuadPart;
- *total_number_of_bytes = wapi_total_number_of_bytes.QuadPart;
- *total_number_of_free_bytes = wapi_total_number_of_free_bytes.QuadPart;
- } else {
- *free_bytes_avail = 0;
- *total_number_of_bytes = 0;
- *total_number_of_free_bytes = 0;
+ result = mono_w32file_get_disk_free_space (mono_string_chars (path_name), free_bytes_avail, total_number_of_bytes, total_number_of_free_bytes);
+ if (!result)
*error = GetLastError ();
- }
return result;
}
static inline guint32
mono_icall_drive_info_get_drive_type (MonoString *root_path_name)
{
- return GetDriveType (mono_string_chars (root_path_name));
+ return mono_w32file_get_drive_type (mono_string_chars (root_path_name));
}
#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
#include "mono/metadata/security-manager.h"
#include "mono/metadata/tabledefs.h"
#include "mono/metadata/tokentype.h"
+#include "mono/metadata/w32file.h"
#include "mono/utils/checked-build.h"
#include "mono/utils/mono-digest.h"
checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
{
guint32 dummy;
- if (!WriteFile (f, buffer, numbytes, &dummy, NULL))
- g_error ("WriteFile returned %d\n", GetLastError ());
+ if (!mono_w32file_write (f, buffer, numbytes, &dummy))
+ g_error ("mono_w32file_write returned %d\n", GetLastError ());
}
/*
if (!assembly->sections [i].size)
continue;
- if (SetFilePointer (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
- g_error ("SetFilePointer returned %d\n", GetLastError ());
+ if (mono_w32file_seek (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+ g_error ("mono_w32file_seek returned %d\n", GetLastError ());
switch (i) {
case MONO_SECTION_TEXT:
}
/* check that the file is properly padded */
- if (SetFilePointer (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
- g_error ("SetFilePointer returned %d\n", GetLastError ());
- if (! SetEndOfFile (file))
- g_error ("SetEndOfFile returned %d\n", GetLastError ());
+ if (mono_w32file_seek (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+ g_error ("mono_w32file_seek returned %d\n", GetLastError ());
+ if (! mono_w32file_truncate (file))
+ g_error ("mono_w32file_truncate returned %d\n", GetLastError ());
mono_dynamic_stream_reset (&assembly->code);
mono_dynamic_stream_reset (&assembly->us);
#define SPECIAL_STATIC_THREAD 1
#define SPECIAL_STATIC_CONTEXT 2
-#ifdef HOST_WIN32
-typedef SECURITY_ATTRIBUTES WapiSecurityAttributes;
-#endif
-
typedef struct _MonoInternalThread MonoInternalThread;
typedef void (*MonoThreadCleanupFunc) (MonoNativeThreadId tid);
#include "mono/utils/mono-logger-internals.h"
#include "mono/metadata/w32handle.h"
+#define MAX_PATH 260
+
typedef struct {
gboolean manual;
guint32 set_count;
--- /dev/null
+/*
+ * Copyright 2016 Microsoft
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#ifndef _MONO_METADATA_W32FILE_INTERNALS_H_
+#define _MONO_METADATA_W32FILE_INTERNALS_H_
+
+#include <config.h>
+#include <glib.h>
+
+#endif /* _MONO_METADATA_W32FILE_INTERNALS_H_ */
--- /dev/null
+/* $OpenBSD: glob.c,v 1.26 2005/11/28 17:50:12 deraadt Exp $ */
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * mono_w32file_unix_glob(3) -- a subset of the one defined in POSIX 1003.2.
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_MAGCHAR:
+ * Set in gl_flags if pattern contained a globbing character.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "w32file-unix-glob.h"
+
+#define EOS '\0'
+#define NOT '!'
+#define QUESTION '?'
+#define QUOTE '\\'
+#define STAR '*'
+
+#ifndef DEBUG
+
+#define M_QUOTE 0x8000
+#define M_PROTECT 0x4000
+#define M_MASK 0xffff
+#define M_ASCII 0x00ff
+
+typedef unsigned short Char;
+
+#else
+
+#define M_QUOTE 0x80
+#define M_PROTECT 0x40
+#define M_MASK 0xff
+#define M_ASCII 0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define CHAR(c) ((gchar)((c)&M_ASCII))
+#define META(c) ((gchar)((c)|M_QUOTE))
+#define M_ALL META('*')
+#define M_ONE META('?')
+#define ismeta(c) (((c)&M_QUOTE) != 0)
+
+
+static int
+g_Ctoc(const gchar *, char *, unsigned int);
+
+static int
+glob0(GDir *dir, const gchar *, mono_w32file_unix_glob_t *, gboolean, gboolean);
+static int
+glob1(GDir *dir, gchar *, gchar *, mono_w32file_unix_glob_t *, size_t *, gboolean, gboolean);
+
+static int
+glob3(GDir *dir, gchar *, gchar *, mono_w32file_unix_glob_t *, size_t *, gboolean, gboolean);
+
+static int
+globextend(const gchar *, mono_w32file_unix_glob_t *, size_t *);
+
+static int
+match(const gchar *, gchar *, gchar *, gboolean);
+
+#ifdef DEBUG_ENABLED
+static void qprintf(const char *, Char *);
+#endif
+
+int
+mono_w32file_unix_glob(GDir *dir, const char *pattern, int flags, mono_w32file_unix_glob_t *pglob)
+{
+ const unsigned char *patnext;
+ int c;
+ gchar *bufnext, *bufend, patbuf[PATH_MAX];
+
+ patnext = (unsigned char *) pattern;
+ if (!(flags & W32FILE_UNIX_GLOB_APPEND)) {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ pglob->gl_offs = 0;
+ }
+ pglob->gl_flags = flags & ~W32FILE_UNIX_GLOB_MAGCHAR;
+
+ bufnext = patbuf;
+ bufend = bufnext + PATH_MAX - 1;
+
+ /* Protect the quoted characters. */
+ while (bufnext < bufend && (c = *patnext++) != EOS)
+ if (c == QUOTE) {
+ if ((c = *patnext++) == EOS) {
+ c = QUOTE;
+ --patnext;
+ }
+ *bufnext++ = c | M_PROTECT;
+ } else
+ *bufnext++ = c;
+
+ *bufnext = EOS;
+
+ return glob0(dir, patbuf, pglob, flags & W32FILE_UNIX_GLOB_IGNORECASE,
+ flags & W32FILE_UNIX_GLOB_UNIQUE);
+}
+
+/*
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested). Returns 0
+ * if things went well, nonzero if errors occurred. It is not an error
+ * to find no matches.
+ */
+static int
+glob0(GDir *dir, const gchar *pattern, mono_w32file_unix_glob_t *pglob, gboolean ignorecase,
+ gboolean unique)
+{
+ const gchar *qpatnext;
+ int c, err, oldpathc;
+ gchar *bufnext, patbuf[PATH_MAX];
+ size_t limit = 0;
+
+ qpatnext = pattern;
+ oldpathc = pglob->gl_pathc;
+ bufnext = patbuf;
+
+ /* We don't need to check for buffer overflow any more. */
+ while ((c = *qpatnext++) != EOS) {
+ switch (c) {
+ case QUESTION:
+ pglob->gl_flags |= W32FILE_UNIX_GLOB_MAGCHAR;
+ *bufnext++ = M_ONE;
+ break;
+ case STAR:
+ pglob->gl_flags |= W32FILE_UNIX_GLOB_MAGCHAR;
+ /* collapse adjacent stars to one,
+ * to avoid exponential behavior
+ */
+ if (bufnext == patbuf || bufnext[-1] != M_ALL)
+ *bufnext++ = M_ALL;
+ break;
+ default:
+ *bufnext++ = CHAR(c);
+ break;
+ }
+ }
+ *bufnext = EOS;
+#ifdef DEBUG_ENABLED
+ qprintf("glob0:", patbuf);
+#endif
+
+ if ((err = glob1(dir, patbuf, patbuf+PATH_MAX-1, pglob, &limit,
+ ignorecase, unique)) != 0)
+ return(err);
+
+ if (pglob->gl_pathc == oldpathc) {
+ return(W32FILE_UNIX_GLOB_NOMATCH);
+ }
+
+ return(0);
+}
+
+static int
+glob1(GDir *dir, gchar *pattern, gchar *pattern_last, mono_w32file_unix_glob_t *pglob,
+ size_t *limitp, gboolean ignorecase, gboolean unique)
+{
+ /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+ if (*pattern == EOS)
+ return(0);
+ return(glob3(dir, pattern, pattern_last, pglob, limitp, ignorecase,
+ unique));
+}
+
+static gboolean contains (mono_w32file_unix_glob_t *pglob, const gchar *name)
+{
+ int i;
+ char **pp;
+
+ if (pglob->gl_pathv != NULL) {
+ pp = pglob->gl_pathv + pglob->gl_offs;
+ for (i = pglob->gl_pathc; i--; ++pp) {
+ if (*pp) {
+ if (!strcmp (*pp, name)) {
+ return(TRUE);
+ }
+ }
+ }
+ }
+
+ return(FALSE);
+}
+
+static int
+glob3(GDir *dir, gchar *pattern, gchar *pattern_last, mono_w32file_unix_glob_t *pglob,
+ size_t *limitp, gboolean ignorecase, gboolean unique)
+{
+ const gchar *name;
+
+ /* Search directory for matching names. */
+ while ((name = g_dir_read_name(dir))) {
+ if (!match(name, pattern, pattern + strlen (pattern),
+ ignorecase)) {
+ continue;
+ }
+ if (!unique ||
+ !contains (pglob, name)) {
+ globextend (name, pglob, limitp);
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * Extend the gl_pathv member of a mono_w32file_unix_glob_t structure to accommodate a new item,
+ * add the new item, and update gl_pathc.
+ *
+ * This assumes the BSD realloc, which only copies the block when its size
+ * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
+ * behavior.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the mono_w32file_unix_glob_t structure:
+ * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ * gl_pathv points to (gl_offs + gl_pathc + 1) items.
+ */
+static int
+globextend(const gchar *path, mono_w32file_unix_glob_t *pglob, size_t *limitp)
+{
+ char **pathv;
+ int i;
+ unsigned int newsize, len;
+ char *copy;
+ const gchar *p;
+
+ newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+ /* FIXME: Can just use realloc(). */
+ pathv = (char **)(pglob->gl_pathv ? g_realloc ((char *)pglob->gl_pathv, newsize) :
+ g_malloc (newsize));
+ if (pathv == NULL) {
+ if (pglob->gl_pathv) {
+ g_free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+ return(W32FILE_UNIX_GLOB_NOSPACE);
+ }
+
+ if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+ /* first time around -- clear initial gl_offs items */
+ pathv += pglob->gl_offs;
+ for (i = pglob->gl_offs; --i >= 0; )
+ *--pathv = NULL;
+ }
+ pglob->gl_pathv = pathv;
+
+ for (p = path; *p++;)
+ ;
+ len = (size_t)(p - path);
+ *limitp += len;
+ if ((copy = (char *)malloc(len)) != NULL) {
+ if (g_Ctoc(path, copy, len)) {
+ g_free (copy);
+ return(W32FILE_UNIX_GLOB_NOSPACE);
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+#if 0
+ /* Broken on opensuse 11 */
+ if ((pglob->gl_flags & W32FILE_UNIX_GLOB_LIMIT) &&
+ newsize + *limitp >= ARG_MAX) {
+ errno = 0;
+ return(W32FILE_UNIX_GLOB_NOSPACE);
+ }
+#endif
+
+ return(copy == NULL ? W32FILE_UNIX_GLOB_NOSPACE : 0);
+}
+
+
+/*
+ * pattern matching function for filenames. Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(const gchar *name, gchar *pat, gchar *patend, gboolean ignorecase)
+{
+ gchar c;
+
+ while (pat < patend) {
+ c = *pat++;
+ switch (c & M_MASK) {
+ case M_ALL:
+ if (pat == patend)
+ return(1);
+ do {
+ if (match(name, pat, patend, ignorecase))
+ return(1);
+ } while (*name++ != EOS);
+ return(0);
+ case M_ONE:
+ if (*name++ == EOS)
+ return(0);
+ break;
+ default:
+ if (ignorecase) {
+ if (g_ascii_tolower (*name++) != g_ascii_tolower (c))
+ return(0);
+ } else {
+ if (*name++ != c)
+ return(0);
+ }
+
+ break;
+ }
+ }
+ return(*name == EOS);
+}
+
+/* Free allocated data belonging to a mono_w32file_unix_glob_t structure. */
+void
+mono_w32file_unix_globfree(mono_w32file_unix_glob_t *pglob)
+{
+ int i;
+ char **pp;
+
+ if (pglob->gl_pathv != NULL) {
+ pp = pglob->gl_pathv + pglob->gl_offs;
+ for (i = pglob->gl_pathc; i--; ++pp)
+ if (*pp)
+ g_free (*pp);
+ g_free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+}
+
+static int
+g_Ctoc(const gchar *str, char *buf, unsigned int len)
+{
+
+ while (len--) {
+ if ((*buf++ = *str++) == EOS)
+ return (0);
+ }
+ return (1);
+}
+
+#ifdef DEBUG_ENABLED
+static void
+qprintf(const char *str, Char *s)
+{
+ Char *p;
+
+ (void)printf("%s:\n", str);
+ for (p = s; *p; p++)
+ (void)printf("%c", CHAR(*p));
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", ismeta(*p) ? '_' : ' ');
+ (void)printf("\n");
+}
+#endif
--- /dev/null
+/* $OpenBSD: glob.h,v 1.10 2005/12/13 00:35:22 millert Exp $ */
+/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)glob.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef __MONO_METADATA_W32FILE_UNIX_GLOB_H__
+#define __MONO_METADATA_W32FILE_UNIX_GLOB_H__
+
+#include <glib.h>
+
+struct stat;
+typedef struct {
+ int gl_pathc; /* Count of total paths so far. */
+ int gl_offs; /* Reserved at beginning of gl_pathv. */
+ int gl_flags; /* Copy of flags parameter to glob. */
+ char **gl_pathv; /* List of paths matching pattern. */
+} mono_w32file_unix_glob_t;
+
+#define W32FILE_UNIX_GLOB_APPEND 0x0001 /* Append to output from previous call. */
+#define W32FILE_UNIX_GLOB_UNIQUE 0x0040 /* When appending only add items that aren't already in the list */
+#define W32FILE_UNIX_GLOB_NOSPACE (-1) /* Malloc call failed. */
+#define W32FILE_UNIX_GLOB_ABORTED (-2) /* Unignored error. */
+#define W32FILE_UNIX_GLOB_NOMATCH (-3) /* No match and W32FILE_UNIX_GLOB_NOCHECK not set. */
+#define W32FILE_UNIX_GLOB_NOSYS (-4) /* Function not supported. */
+
+#define W32FILE_UNIX_GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
+#define W32FILE_UNIX_GLOB_LIMIT 0x2000 /* Limit pattern match output to ARG_MAX */
+#define W32FILE_UNIX_GLOB_IGNORECASE 0x4000 /* Ignore case when matching */
+#define W32FILE_UNIX_GLOB_ABEND W32FILE_UNIX_GLOB_ABORTED /* backward compatibility */
+
+G_BEGIN_DECLS
+
+int
+mono_w32file_unix_glob (GDir *dir, const char *, int, mono_w32file_unix_glob_t *);
+
+void
+mono_w32file_unix_globfree (mono_w32file_unix_glob_t *);
+
+G_END_DECLS
+
+#endif /* !__MONO_METADATA_W32FILE_UNIX_GLOB_H__ */
--- /dev/null
+
+#include <config.h>
+#include <glib.h>
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+#if defined(HAVE_SYS_STATFS_H)
+#include <sys/statfs.h>
+#endif
+#if defined(HAVE_SYS_PARAM_H) && defined(HAVE_SYS_MOUNT_H)
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+#include <sys/types.h>
+#include <stdio.h>
+#include <utime.h>
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <mono/utils/linux_magic.h>
+#endif
+#include <sys/time.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif
+
+#include "w32file.h"
+#include "w32file-internals.h"
+
+#include "w32file-unix-glob.h"
+#include "w32handle.h"
+#include "utils/mono-io-portability.h"
+#include "utils/mono-logger-internals.h"
+#include "utils/mono-os-mutex.h"
+#include "utils/mono-threads.h"
+#include "utils/mono-threads-api.h"
+#include "utils/strenc.h"
+
+typedef struct {
+ guint64 device;
+ guint64 inode;
+ pid_t opened_by_pid;
+ guint32 sharemode;
+ guint32 access;
+ guint32 handle_refs;
+ guint32 timestamp;
+} FileShare;
+
+/* Currently used for both FILE, CONSOLE and PIPE handle types.
+ * This may have to change in future. */
+typedef struct {
+ gchar *filename;
+ FileShare *share_info; /* Pointer into shared mem */
+ gint fd;
+ guint32 security_attributes;
+ guint32 fileaccess;
+ guint32 sharemode;
+ guint32 attrs;
+} MonoW32HandleFile;
+
+typedef struct {
+ gchar **namelist;
+ gchar *dir_part;
+ gint num;
+ gsize count;
+} MonoW32HandleFind;
+
+/*
+ * If SHM is disabled, this will point to a hash of FileShare structures, otherwise
+ * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
+ * 4MB array.
+ */
+static GHashTable *file_share_table;
+static mono_mutex_t file_share_mutex;
+
+static void
+time_t_to_filetime (time_t timeval, FILETIME *filetime)
+{
+ guint64 ticks;
+
+ ticks = ((guint64)timeval * 10000000) + 116444736000000000ULL;
+ filetime->dwLowDateTime = ticks & 0xFFFFFFFF;
+ filetime->dwHighDateTime = ticks >> 32;
+}
+
+static void
+file_share_release (FileShare *share_info)
+{
+ /* Prevent new entries racing with us */
+ mono_os_mutex_lock (&file_share_mutex);
+
+ g_assert (share_info->handle_refs > 0);
+ share_info->handle_refs -= 1;
+
+ if (share_info->handle_refs == 0)
+ g_hash_table_remove (file_share_table, share_info);
+
+ mono_os_mutex_unlock (&file_share_mutex);
+}
+
+static gint
+file_share_equal (gconstpointer ka, gconstpointer kb)
+{
+ const FileShare *s1 = (const FileShare *)ka;
+ const FileShare *s2 = (const FileShare *)kb;
+
+ return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
+}
+
+static guint
+file_share_hash (gconstpointer data)
+{
+ const FileShare *s = (const FileShare *)data;
+
+ return s->inode;
+}
+
+static gboolean
+file_share_get (guint64 device, guint64 inode, guint32 new_sharemode, guint32 new_access,
+ guint32 *old_sharemode, guint32 *old_access, FileShare **share_info)
+{
+ FileShare *file_share;
+ gboolean exists = FALSE;
+
+ /* Prevent new entries racing with us */
+ mono_os_mutex_lock (&file_share_mutex);
+
+ FileShare tmp;
+
+ /*
+ * Instead of allocating a 4MB array, we use a hash table to keep track of this
+ * info. This is needed even if SHM is disabled, to track sharing inside
+ * the current process.
+ */
+ if (!file_share_table)
+ file_share_table = g_hash_table_new_full (file_share_hash, file_share_equal, NULL, g_free);
+
+ tmp.device = device;
+ tmp.inode = inode;
+
+ file_share = (FileShare *)g_hash_table_lookup (file_share_table, &tmp);
+ if (file_share) {
+ *old_sharemode = file_share->sharemode;
+ *old_access = file_share->access;
+ *share_info = file_share;
+
+ g_assert (file_share->handle_refs > 0);
+ file_share->handle_refs += 1;
+
+ exists = TRUE;
+ } else {
+ file_share = g_new0 (FileShare, 1);
+
+ file_share->device = device;
+ file_share->inode = inode;
+ file_share->opened_by_pid = wapi_getpid ();
+ file_share->sharemode = new_sharemode;
+ file_share->access = new_access;
+ file_share->handle_refs = 1;
+ *share_info = file_share;
+
+ g_hash_table_insert (file_share_table, file_share, file_share);
+ }
+
+ mono_os_mutex_unlock (&file_share_mutex);
+
+ return(exists);
+}
+
+static gint
+_wapi_open (const gchar *pathname, gint flags, mode_t mode)
+{
+ gint fd;
+ gchar *located_filename;
+
+ if (flags & O_CREAT) {
+ located_filename = mono_portability_find_file (pathname, FALSE);
+ if (located_filename == NULL) {
+ fd = open (pathname, flags, mode);
+ } else {
+ fd = open (located_filename, flags, mode);
+ g_free (located_filename);
+ }
+ } else {
+ fd = open (pathname, flags, mode);
+ if (fd == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ located_filename = mono_portability_find_file (pathname, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ fd = open (located_filename, flags, mode);
+ g_free (located_filename);
+ }
+ }
+
+ return(fd);
+}
+
+static gint
+_wapi_access (const gchar *pathname, gint mode)
+{
+ gint ret;
+
+ ret = access (pathname, mode);
+ if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_filename = mono_portability_find_file (pathname, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = access (located_filename, mode);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_chmod (const gchar *pathname, mode_t mode)
+{
+ gint ret;
+
+ ret = chmod (pathname, mode);
+ if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_filename = mono_portability_find_file (pathname, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = chmod (located_filename, mode);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_utime (const gchar *filename, const struct utimbuf *buf)
+{
+ gint ret;
+
+ ret = utime (filename, buf);
+ if (ret == -1 && errno == ENOENT && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_filename = mono_portability_find_file (filename, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = utime (located_filename, buf);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_unlink (const gchar *pathname)
+{
+ gint ret;
+
+ ret = unlink (pathname);
+ if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_filename = mono_portability_find_file (pathname, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = unlink (located_filename);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_rename (const gchar *oldpath, const gchar *newpath)
+{
+ gint ret;
+ gchar *located_newpath = mono_portability_find_file (newpath, FALSE);
+
+ if (located_newpath == NULL) {
+ ret = rename (oldpath, newpath);
+ } else {
+ ret = rename (oldpath, located_newpath);
+
+ if (ret == -1 && (errno == EISDIR || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EXDEV) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_oldpath = mono_portability_find_file (oldpath, TRUE);
+
+ if (located_oldpath == NULL) {
+ g_free (located_oldpath);
+ g_free (located_newpath);
+
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = rename (located_oldpath, located_newpath);
+ g_free (located_oldpath);
+ }
+ g_free (located_newpath);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_stat (const gchar *path, struct stat *buf)
+{
+ gint ret;
+
+ ret = stat (path, buf);
+ if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_filename = mono_portability_find_file (path, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = stat (located_filename, buf);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_lstat (const gchar *path, struct stat *buf)
+{
+ gint ret;
+
+ ret = lstat (path, buf);
+ if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_filename = mono_portability_find_file (path, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = lstat (located_filename, buf);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_mkdir (const gchar *pathname, mode_t mode)
+{
+ gint ret;
+ gchar *located_filename = mono_portability_find_file (pathname, FALSE);
+
+ if (located_filename == NULL) {
+ ret = mkdir (pathname, mode);
+ } else {
+ ret = mkdir (located_filename, mode);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_rmdir (const gchar *pathname)
+{
+ gint ret;
+
+ ret = rmdir (pathname);
+ if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_filename = mono_portability_find_file (pathname, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = rmdir (located_filename);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gint
+_wapi_chdir (const gchar *path)
+{
+ gint ret;
+
+ ret = chdir (path);
+ if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) && IS_PORTABILITY_SET) {
+ gint saved_errno = errno;
+ gchar *located_filename = mono_portability_find_file (path, TRUE);
+
+ if (located_filename == NULL) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ ret = chdir (located_filename);
+ g_free (located_filename);
+ }
+
+ return ret;
+}
+
+static gchar*
+_wapi_basename (const gchar *filename)
+{
+ gchar *new_filename = g_strdup (filename), *ret;
+
+ if (IS_PORTABILITY_SET) {
+ g_strdelimit (new_filename, "\\", '/');
+ }
+
+ if (IS_PORTABILITY_DRIVE && g_ascii_isalpha (new_filename[0]) && (new_filename[1] == ':')) {
+ gint len = strlen (new_filename);
+
+ g_memmove (new_filename, new_filename + 2, len - 2);
+ new_filename[len - 2] = '\0';
+ }
+
+ ret = g_path_get_basename (new_filename);
+ g_free (new_filename);
+
+ return ret;
+}
+
+static gchar*
+_wapi_dirname (const gchar *filename)
+{
+ gchar *new_filename = g_strdup (filename), *ret;
+
+ if (IS_PORTABILITY_SET) {
+ g_strdelimit (new_filename, "\\", '/');
+ }
+
+ if (IS_PORTABILITY_DRIVE && g_ascii_isalpha (new_filename[0]) && (new_filename[1] == ':')) {
+ gint len = strlen (new_filename);
+
+ g_memmove (new_filename, new_filename + 2, len - 2);
+ new_filename[len - 2] = '\0';
+ }
+
+ ret = g_path_get_dirname (new_filename);
+ g_free (new_filename);
+
+ return ret;
+}
+
+static GDir*
+_wapi_g_dir_open (const gchar *path, guint flags, GError **error)
+{
+ GDir *ret;
+
+ ret = g_dir_open (path, flags, error);
+ if (ret == NULL && ((*error)->code == G_FILE_ERROR_NOENT || (*error)->code == G_FILE_ERROR_NOTDIR || (*error)->code == G_FILE_ERROR_NAMETOOLONG) && IS_PORTABILITY_SET) {
+ gchar *located_filename = mono_portability_find_file (path, TRUE);
+ GError *tmp_error = NULL;
+
+ if (located_filename == NULL) {
+ return(NULL);
+ }
+
+ ret = g_dir_open (located_filename, flags, &tmp_error);
+ g_free (located_filename);
+ if (tmp_error == NULL) {
+ g_clear_error (error);
+ }
+ }
+
+ return ret;
+}
+
+static gint
+get_errno_from_g_file_error (gint error)
+{
+ switch (error) {
+#ifdef EACCESS
+ case G_FILE_ERROR_ACCES: return EACCES;
+#endif
+#ifdef ENAMETOOLONG
+ case G_FILE_ERROR_NAMETOOLONG: return ENAMETOOLONG;
+#endif
+#ifdef ENOENT
+ case G_FILE_ERROR_NOENT: return ENOENT;
+#endif
+#ifdef ENOTDIR
+ case G_FILE_ERROR_NOTDIR: return ENOTDIR;
+#endif
+#ifdef ENXIO
+ case G_FILE_ERROR_NXIO: return ENXIO;
+#endif
+#ifdef ENODEV
+ case G_FILE_ERROR_NODEV: return ENODEV;
+#endif
+#ifdef EROFS
+ case G_FILE_ERROR_ROFS: return EROFS;
+#endif
+#ifdef ETXTBSY
+ case G_FILE_ERROR_TXTBSY: return ETXTBSY;
+#endif
+#ifdef EFAULT
+ case G_FILE_ERROR_FAULT: return EFAULT;
+#endif
+#ifdef ELOOP
+ case G_FILE_ERROR_LOOP: return ELOOP;
+#endif
+#ifdef ENOSPC
+ case G_FILE_ERROR_NOSPC: return ENOSPC;
+#endif
+#ifdef ENOMEM
+ case G_FILE_ERROR_NOMEM: return ENOMEM;
+#endif
+#ifdef EMFILE
+ case G_FILE_ERROR_MFILE: return EMFILE;
+#endif
+#ifdef ENFILE
+ case G_FILE_ERROR_NFILE: return ENFILE;
+#endif
+#ifdef EBADF
+ case G_FILE_ERROR_BADF: return EBADF;
+#endif
+#ifdef EINVAL
+ case G_FILE_ERROR_INVAL: return EINVAL;
+#endif
+#ifdef EPIPE
+ case G_FILE_ERROR_PIPE: return EPIPE;
+#endif
+#ifdef EAGAIN
+ case G_FILE_ERROR_AGAIN: return EAGAIN;
+#endif
+#ifdef EINTR
+ case G_FILE_ERROR_INTR: return EINTR;
+#endif
+#ifdef EWIO
+ case G_FILE_ERROR_IO: return EIO;
+#endif
+#ifdef EPERM
+ case G_FILE_ERROR_PERM: return EPERM;
+#endif
+ case G_FILE_ERROR_FAILED: return ERROR_INVALID_PARAMETER;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gint
+file_compare (gconstpointer a, gconstpointer b)
+{
+ gchar *astr = *(gchar **) a;
+ gchar *bstr = *(gchar **) b;
+
+ return strcmp (astr, bstr);
+}
+
+/* scandir using glib */
+static gint
+_wapi_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist)
+{
+ GError *error = NULL;
+ GDir *dir;
+ GPtrArray *names;
+ gint result;
+ mono_w32file_unix_glob_t glob_buf;
+ gint flags = 0, i;
+
+ dir = _wapi_g_dir_open (dirname, 0, &error);
+ if (dir == NULL) {
+ /* g_dir_open returns ENOENT on directories on which we don't
+ * have read/x permission */
+ gint errnum = get_errno_from_g_file_error (error->code);
+ g_error_free (error);
+ if (errnum == ENOENT &&
+ !_wapi_access (dirname, F_OK) &&
+ _wapi_access (dirname, R_OK|X_OK)) {
+ errnum = EACCES;
+ }
+
+ errno = errnum;
+ return -1;
+ }
+
+ if (IS_PORTABILITY_CASE) {
+ flags = W32FILE_UNIX_GLOB_IGNORECASE;
+ }
+
+ result = mono_w32file_unix_glob (dir, pattern, flags, &glob_buf);
+ if (g_str_has_suffix (pattern, ".*")) {
+ /* Special-case the patterns ending in '.*', as
+ * windows also matches entries with no extension with
+ * this pattern.
+ *
+ * TODO: should this be a MONO_IOMAP option?
+ */
+ gchar *pattern2 = g_strndup (pattern, strlen (pattern) - 2);
+ gint result2;
+
+ g_dir_rewind (dir);
+ result2 = mono_w32file_unix_glob (dir, pattern2, flags | W32FILE_UNIX_GLOB_APPEND | W32FILE_UNIX_GLOB_UNIQUE, &glob_buf);
+
+ g_free (pattern2);
+
+ if (result != 0) {
+ result = result2;
+ }
+ }
+
+ g_dir_close (dir);
+ if (glob_buf.gl_pathc == 0) {
+ return(0);
+ } else if (result != 0) {
+ return -1;
+ }
+
+ names = g_ptr_array_new ();
+ for (i = 0; i < glob_buf.gl_pathc; i++) {
+ g_ptr_array_add (names, g_strdup (glob_buf.gl_pathv[i]));
+ }
+
+ mono_w32file_unix_globfree (&glob_buf);
+
+ result = names->len;
+ if (result > 0) {
+ g_ptr_array_sort (names, file_compare);
+ g_ptr_array_set_size (names, result + 1);
+
+ *namelist = (gchar **) g_ptr_array_free (names, FALSE);
+ } else {
+ g_ptr_array_free (names, TRUE);
+ }
+
+ return result;
+}
+
+static gboolean
+_wapi_lock_file_region (gint fd, off_t offset, off_t length)
+{
+#if defined(__native_client__)
+ printf("WARNING: %s: fcntl() not available on Native Client!\n", __func__);
+ // behave as below -- locks are not available
+ return TRUE;
+#else
+ struct flock lock_data;
+ gint ret;
+
+ if (offset < 0 || length < 0) {
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ lock_data.l_type = F_WRLCK;
+ lock_data.l_whence = SEEK_SET;
+ lock_data.l_start = offset;
+ lock_data.l_len = length;
+
+ do {
+ ret = fcntl (fd, F_SETLK, &lock_data);
+ } while(ret == -1 && errno == EINTR);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl returns %d", __func__, ret);
+
+ if (ret == -1) {
+ /*
+ * if locks are not available (NFS for example),
+ * ignore the error
+ */
+ if (errno == ENOLCK
+#ifdef EOPNOTSUPP
+ || errno == EOPNOTSUPP
+#endif
+#ifdef ENOTSUP
+ || errno == ENOTSUP
+#endif
+ ) {
+ return TRUE;
+ }
+
+ SetLastError (ERROR_LOCK_VIOLATION);
+ return FALSE;
+ }
+
+ return TRUE;
+#endif /* __native_client__ */
+}
+
+static gboolean
+_wapi_unlock_file_region (gint fd, off_t offset, off_t length)
+{
+#if defined(__native_client__)
+ printf("WARNING: %s: fcntl() not available on Native Client!\n", __func__);
+ return TRUE;
+#else
+ struct flock lock_data;
+ gint ret;
+
+ lock_data.l_type = F_UNLCK;
+ lock_data.l_whence = SEEK_SET;
+ lock_data.l_start = offset;
+ lock_data.l_len = length;
+
+ do {
+ ret = fcntl (fd, F_SETLK, &lock_data);
+ } while(ret == -1 && errno == EINTR);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl returns %d", __func__, ret);
+
+ if (ret == -1) {
+ /*
+ * if locks are not available (NFS for example),
+ * ignore the error
+ */
+ if (errno == ENOLCK
+#ifdef EOPNOTSUPP
+ || errno == EOPNOTSUPP
+#endif
+#ifdef ENOTSUP
+ || errno == ENOTSUP
+#endif
+ ) {
+ return TRUE;
+ }
+
+ SetLastError (ERROR_LOCK_VIOLATION);
+ return FALSE;
+ }
+
+ return TRUE;
+#endif /* __native_client__ */
+}
+
+static void file_close (gpointer handle, gpointer data);
+static void file_details (gpointer data);
+static const gchar* file_typename (void);
+static gsize file_typesize (void);
+static gint file_getfiletype(void);
+static gboolean file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread);
+static gboolean file_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten);
+static gboolean file_flush(gpointer handle);
+static guint32 file_seek(gpointer handle, gint32 movedistance,
+ gint32 *highmovedistance, gint method);
+static gboolean file_setendoffile(gpointer handle);
+static guint32 file_getfilesize(gpointer handle, guint32 *highsize);
+static gboolean file_getfiletime(gpointer handle, FILETIME *create_time,
+ FILETIME *access_time,
+ FILETIME *write_time);
+static gboolean file_setfiletime(gpointer handle,
+ const FILETIME *create_time,
+ const FILETIME *access_time,
+ const FILETIME *write_time);
+static guint32 GetDriveTypeFromPath (const gchar *utf8_root_path_name);
+
+/* File handle is only signalled for overlapped IO */
+static MonoW32HandleOps _wapi_file_ops = {
+ file_close, /* close */
+ NULL, /* signal */
+ NULL, /* own */
+ NULL, /* is_owned */
+ NULL, /* special_wait */
+ NULL, /* prewait */
+ file_details, /* details */
+ file_typename, /* typename */
+ file_typesize, /* typesize */
+};
+
+static void console_close (gpointer handle, gpointer data);
+static void console_details (gpointer data);
+static const gchar* console_typename (void);
+static gsize console_typesize (void);
+static gint console_getfiletype(void);
+static gboolean console_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread);
+static gboolean console_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten);
+
+/* Console is mostly the same as file, except it can block waiting for
+ * input or output
+ */
+static MonoW32HandleOps _wapi_console_ops = {
+ console_close, /* close */
+ NULL, /* signal */
+ NULL, /* own */
+ NULL, /* is_owned */
+ NULL, /* special_wait */
+ NULL, /* prewait */
+ console_details, /* details */
+ console_typename, /* typename */
+ console_typesize, /* typesize */
+};
+
+static const gchar* find_typename (void);
+static gsize find_typesize (void);
+
+static MonoW32HandleOps _wapi_find_ops = {
+ NULL, /* close */
+ NULL, /* signal */
+ NULL, /* own */
+ NULL, /* is_owned */
+ NULL, /* special_wait */
+ NULL, /* prewait */
+ NULL, /* details */
+ find_typename, /* typename */
+ find_typesize, /* typesize */
+};
+
+static void pipe_close (gpointer handle, gpointer data);
+static void pipe_details (gpointer data);
+static const gchar* pipe_typename (void);
+static gsize pipe_typesize (void);
+static gint pipe_getfiletype (void);
+static gboolean pipe_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread);
+static gboolean pipe_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten);
+
+/* Pipe handles
+ */
+static MonoW32HandleOps _wapi_pipe_ops = {
+ pipe_close, /* close */
+ NULL, /* signal */
+ NULL, /* own */
+ NULL, /* is_owned */
+ NULL, /* special_wait */
+ NULL, /* prewait */
+ pipe_details, /* details */
+ pipe_typename, /* typename */
+ pipe_typesize, /* typesize */
+};
+
+static const struct {
+ /* File, console and pipe handles */
+ gint (*getfiletype)(void);
+
+ /* File, console and pipe handles */
+ gboolean (*readfile)(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread);
+ gboolean (*writefile)(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten);
+ gboolean (*flushfile)(gpointer handle);
+
+ /* File handles */
+ guint32 (*seek)(gpointer handle, gint32 movedistance,
+ gint32 *highmovedistance, gint method);
+ gboolean (*setendoffile)(gpointer handle);
+ guint32 (*getfilesize)(gpointer handle, guint32 *highsize);
+ gboolean (*getfiletime)(gpointer handle, FILETIME *create_time,
+ FILETIME *access_time,
+ FILETIME *write_time);
+ gboolean (*setfiletime)(gpointer handle,
+ const FILETIME *create_time,
+ const FILETIME *access_time,
+ const FILETIME *write_time);
+} io_ops[MONO_W32HANDLE_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,
+ NULL, 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},
+ /* pipe */
+ {pipe_getfiletype,
+ pipe_read,
+ pipe_write,
+ NULL, NULL, NULL, NULL, NULL, NULL},
+};
+
+static gboolean lock_while_writing = FALSE;
+
+/* Some utility functions.
+ */
+
+/*
+ * Check if a file is writable by the current user.
+ *
+ * This is is a best effort kind of thing. It assumes a reasonable sane set
+ * of permissions by the underlying OS.
+ *
+ * We generally assume that basic unix permission bits are authoritative. Which might not
+ * be the case under systems with extended permissions systems (posix ACLs, SELinux, OSX/iOS sandboxing, etc)
+ *
+ * The choice of access as the fallback is due to the expected lower overhead compared to trying to open the file.
+ *
+ * The only expected problem with using access are for root, setuid or setgid programs as access is not consistent
+ * under those situations. It's to be expected that this should not happen in practice as those bits are very dangerous
+ * and should not be used with a dynamic runtime.
+ */
+static gboolean
+is_file_writable (struct stat *st, const gchar *path)
+{
+#if __APPLE__
+ // OS X Finder "locked" or `ls -lO` "uchg".
+ // This only covers one of several cases where an OS X file could be unwritable through special flags.
+ if (st->st_flags & (UF_IMMUTABLE|SF_IMMUTABLE))
+ return 0;
+#endif
+
+ /* Is it globally writable? */
+ if (st->st_mode & S_IWOTH)
+ return 1;
+
+ /* Am I the owner? */
+ if ((st->st_uid == geteuid ()) && (st->st_mode & S_IWUSR))
+ return 1;
+
+ /* Am I in the same group? */
+ if ((st->st_gid == getegid ()) && (st->st_mode & S_IWGRP))
+ return 1;
+
+ /* Fallback to using access(2). It's not ideal as it might not take into consideration euid/egid
+ * but it's the only sane option we have on unix.
+ */
+ return access (path, W_OK) == 0;
+}
+
+
+static guint32 _wapi_stat_to_file_attributes (const gchar *pathname,
+ struct stat *buf,
+ struct stat *lbuf)
+{
+ guint32 attrs = 0;
+ gchar *filename;
+
+ /* FIXME: this could definitely be better, but there seems to
+ * be no pattern to the attributes that are set
+ */
+
+ /* Sockets (0140000) != Directory (040000) + Regular file (0100000) */
+ if (S_ISSOCK (buf->st_mode))
+ buf->st_mode &= ~S_IFSOCK; /* don't consider socket protection */
+
+ filename = _wapi_basename (pathname);
+
+ if (S_ISDIR (buf->st_mode)) {
+ attrs = FILE_ATTRIBUTE_DIRECTORY;
+ if (!is_file_writable (buf, pathname)) {
+ attrs |= FILE_ATTRIBUTE_READONLY;
+ }
+ if (filename[0] == '.') {
+ attrs |= FILE_ATTRIBUTE_HIDDEN;
+ }
+ } else {
+ if (!is_file_writable (buf, pathname)) {
+ attrs = FILE_ATTRIBUTE_READONLY;
+
+ if (filename[0] == '.') {
+ attrs |= FILE_ATTRIBUTE_HIDDEN;
+ }
+ } else if (filename[0] == '.') {
+ attrs = FILE_ATTRIBUTE_HIDDEN;
+ } else {
+ attrs = FILE_ATTRIBUTE_NORMAL;
+ }
+ }
+
+ if (lbuf != NULL) {
+ if (S_ISLNK (lbuf->st_mode)) {
+ attrs |= FILE_ATTRIBUTE_REPARSE_POINT;
+ }
+ }
+
+ g_free (filename);
+
+ return attrs;
+}
+
+static void
+_wapi_set_last_error_from_errno (void)
+{
+ SetLastError (_wapi_get_win32_file_error (errno));
+}
+
+static void _wapi_set_last_path_error_from_errno (const gchar *dir,
+ const gchar *path)
+{
+ if (errno == ENOENT) {
+ /* Check the path - if it's a missing directory then
+ * we need to set PATH_NOT_FOUND not FILE_NOT_FOUND
+ */
+ gchar *dirname;
+
+
+ if (dir == NULL) {
+ dirname = _wapi_dirname (path);
+ } else {
+ dirname = g_strdup (dir);
+ }
+
+ if (_wapi_access (dirname, F_OK) == 0) {
+ SetLastError (ERROR_FILE_NOT_FOUND);
+ } else {
+ SetLastError (ERROR_PATH_NOT_FOUND);
+ }
+
+ g_free (dirname);
+ } else {
+ _wapi_set_last_error_from_errno ();
+ }
+}
+
+/* Handle ops.
+ */
+static void file_close (gpointer handle, gpointer data)
+{
+ MonoW32HandleFile *file_handle = (MonoW32HandleFile *)data;
+ gint fd = file_handle->fd;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing file handle %p [%s]", __func__, handle,
+ file_handle->filename);
+
+ if (file_handle->attrs & FILE_FLAG_DELETE_ON_CLOSE)
+ _wapi_unlink (file_handle->filename);
+
+ g_free (file_handle->filename);
+
+ if (file_handle->share_info)
+ file_share_release (file_handle->share_info);
+
+ close (fd);
+}
+
+static void file_details (gpointer data)
+{
+ MonoW32HandleFile *file = (MonoW32HandleFile *)data;
+
+ g_print ("[%20s] acc: %c%c%c, shr: %c%c%c, attrs: %5u",
+ file->filename,
+ file->fileaccess&GENERIC_READ?'R':'.',
+ file->fileaccess&GENERIC_WRITE?'W':'.',
+ file->fileaccess&GENERIC_EXECUTE?'X':'.',
+ file->sharemode&FILE_SHARE_READ?'R':'.',
+ file->sharemode&FILE_SHARE_WRITE?'W':'.',
+ file->sharemode&FILE_SHARE_DELETE?'D':'.',
+ file->attrs);
+}
+
+static const gchar* file_typename (void)
+{
+ return "File";
+}
+
+static gsize file_typesize (void)
+{
+ return sizeof (MonoW32HandleFile);
+}
+
+static gint file_getfiletype(void)
+{
+ return(FILE_TYPE_DISK);
+}
+
+static gboolean
+file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread)
+{
+ MonoW32HandleFile *file_handle;
+ gboolean ok;
+ gint fd, ret;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
+ (gpointer *)&file_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up file handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ fd = file_handle->fd;
+ if(bytesread!=NULL) {
+ *bytesread=0;
+ }
+
+ if(!(file_handle->fileaccess & GENERIC_READ) &&
+ !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
+ __func__, handle, file_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ do {
+ ret = read (fd, buffer, numbytes);
+ } while (ret == -1 && errno == EINTR &&
+ !mono_thread_info_is_interrupt_state (info));
+
+ if(ret==-1) {
+ gint err = errno;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of handle %p error: %s", __func__,
+ handle, strerror(err));
+ SetLastError (_wapi_get_win32_file_error (err));
+ return(FALSE);
+ }
+
+ if (bytesread != NULL) {
+ *bytesread = ret;
+ }
+
+ return(TRUE);
+}
+
+static gboolean
+file_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten)
+{
+ MonoW32HandleFile *file_handle;
+ gboolean ok;
+ gint ret, fd;
+ off_t current_pos = 0;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
+ (gpointer *)&file_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up file handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ fd = file_handle->fd;
+
+ if(byteswritten!=NULL) {
+ *byteswritten=0;
+ }
+
+ if(!(file_handle->fileaccess & GENERIC_WRITE) &&
+ !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ if (lock_while_writing) {
+ /* Need to lock the region we're about to write to,
+ * because we only do advisory locking on POSIX
+ * systems
+ */
+ current_pos = lseek (fd, (off_t)0, SEEK_CUR);
+ if (current_pos == -1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p lseek failed: %s", __func__,
+ handle, strerror (errno));
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+
+ if (_wapi_lock_file_region (fd, current_pos,
+ numbytes) == FALSE) {
+ /* The error has already been set */
+ return(FALSE);
+ }
+ }
+
+ do {
+ ret = write (fd, buffer, numbytes);
+ } while (ret == -1 && errno == EINTR &&
+ !mono_thread_info_is_interrupt_state (info));
+
+ if (lock_while_writing) {
+ _wapi_unlock_file_region (fd, current_pos, numbytes);
+ }
+
+ if (ret == -1) {
+ if (errno == EINTR) {
+ ret = 0;
+ } else {
+ _wapi_set_last_error_from_errno ();
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of handle %p error: %s",
+ __func__, handle, strerror(errno));
+
+ return(FALSE);
+ }
+ }
+ if (byteswritten != NULL) {
+ *byteswritten = ret;
+ }
+ return(TRUE);
+}
+
+static gboolean file_flush(gpointer handle)
+{
+ MonoW32HandleFile *file_handle;
+ gboolean ok;
+ gint ret, fd;
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
+ (gpointer *)&file_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up file handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ fd = file_handle->fd;
+
+ if(!(file_handle->fileaccess & GENERIC_WRITE) &&
+ !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ ret=fsync(fd);
+ if (ret==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fsync of handle %p error: %s", __func__, handle,
+ strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+static guint32 file_seek(gpointer handle, gint32 movedistance,
+ gint32 *highmovedistance, gint method)
+{
+ MonoW32HandleFile *file_handle;
+ gboolean ok;
+ gint64 offset, newpos;
+ gint whence, fd;
+ guint32 ret;
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
+ (gpointer *)&file_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up file handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(INVALID_SET_FILE_POINTER);
+ }
+
+ fd = file_handle->fd;
+
+ if(!(file_handle->fileaccess & GENERIC_READ) &&
+ !(file_handle->fileaccess & GENERIC_WRITE) &&
+ !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(INVALID_SET_FILE_POINTER);
+ }
+
+ switch(method) {
+ case FILE_BEGIN:
+ whence=SEEK_SET;
+ break;
+ case FILE_CURRENT:
+ whence=SEEK_CUR;
+ break;
+ case FILE_END:
+ whence=SEEK_END;
+ break;
+ default:
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: invalid seek type %d", __func__, method);
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(INVALID_SET_FILE_POINTER);
+ }
+
+#ifdef HAVE_LARGE_FILE_SUPPORT
+ if(highmovedistance==NULL) {
+ offset=movedistance;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting offset to %lld (low %d)", __func__,
+ offset, movedistance);
+ } else {
+ offset=((gint64) *highmovedistance << 32) | (guint32)movedistance;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting offset to %lld 0x%llx (high %d 0x%x, low %d 0x%x)", __func__, offset, offset, *highmovedistance, *highmovedistance, movedistance, movedistance);
+ }
+#else
+ offset=movedistance;
+#endif
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: moving handle %p by %lld bytes from %d", __func__,
+ handle, (long long)offset, whence);
+
+#ifdef PLATFORM_ANDROID
+ /* bionic doesn't support -D_FILE_OFFSET_BITS=64 */
+ newpos=lseek64(fd, offset, whence);
+#else
+ newpos=lseek(fd, offset, whence);
+#endif
+ if(newpos==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lseek on handle %p returned error %s",
+ __func__, handle, strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(INVALID_SET_FILE_POINTER);
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lseek returns %lld", __func__, newpos);
+
+#ifdef HAVE_LARGE_FILE_SUPPORT
+ ret=newpos & 0xFFFFFFFF;
+ if(highmovedistance!=NULL) {
+ *highmovedistance=newpos>>32;
+ }
+#else
+ ret=newpos;
+ if(highmovedistance!=NULL) {
+ /* Accurate, but potentially dodgy :-) */
+ *highmovedistance=0;
+ }
+#endif
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: move of handle %p returning %d/%d", __func__,
+ handle, ret, highmovedistance==NULL?0:*highmovedistance);
+
+ return(ret);
+}
+
+static gboolean file_setendoffile(gpointer handle)
+{
+ MonoW32HandleFile *file_handle;
+ gboolean ok;
+ struct stat statbuf;
+ off_t pos;
+ gint ret, fd;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
+ (gpointer *)&file_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up file handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+ fd = file_handle->fd;
+
+ if(!(file_handle->fileaccess & GENERIC_WRITE) &&
+ !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ /* Find the current file position, and the file length. If
+ * the file position is greater than the length, write to
+ * extend the file with a hole. If the file position is less
+ * than the length, truncate the file.
+ */
+
+ ret=fstat(fd, &statbuf);
+ if(ret==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__,
+ handle, strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+
+ pos=lseek(fd, (off_t)0, SEEK_CUR);
+ if(pos==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p lseek failed: %s", __func__,
+ handle, strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+
+#ifdef FTRUNCATE_DOESNT_EXTEND
+ off_t size = statbuf.st_size;
+ /* I haven't bothered to write the configure.ac stuff for this
+ * because I don't know if any platform needs it. I'm leaving
+ * this code just in case though
+ */
+ if(pos>size) {
+ /* Extend the file. Use write() here, because some
+ * manuals say that ftruncate() behaviour is undefined
+ * when the file needs extending. The POSIX spec says
+ * that on XSI-conformant systems it extends, so if
+ * every system we care about conforms, then we can
+ * drop this write.
+ */
+ do {
+ ret = write (fd, "", 1);
+ } while (ret == -1 && errno == EINTR &&
+ !mono_thread_info_is_interrupt_state (info));
+
+ if(ret==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p extend write failed: %s", __func__, handle, strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+
+ /* And put the file position back after the write */
+ ret = lseek (fd, pos, SEEK_SET);
+ if (ret == -1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p second lseek failed: %s",
+ __func__, handle, strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+ }
+#endif
+
+/* Native Client has no ftruncate function, even in standalone sel_ldr. */
+#ifndef __native_client__
+ /* always truncate, because the extend write() adds an extra
+ * byte to the end of the file
+ */
+ do {
+ ret=ftruncate(fd, pos);
+ }
+ while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
+ if(ret==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p ftruncate failed: %s", __func__,
+ handle, strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+#endif
+
+ return(TRUE);
+}
+
+static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
+{
+ MonoW32HandleFile *file_handle;
+ gboolean ok;
+ struct stat statbuf;
+ guint32 size;
+ gint ret;
+ gint fd;
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
+ (gpointer *)&file_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up file handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(INVALID_FILE_SIZE);
+ }
+ fd = file_handle->fd;
+
+ if(!(file_handle->fileaccess & GENERIC_READ) &&
+ !(file_handle->fileaccess & GENERIC_WRITE) &&
+ !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(INVALID_FILE_SIZE);
+ }
+
+ /* If the file has a size with the low bits 0xFFFFFFFF the
+ * caller can't tell if this is an error, so clear the error
+ * value
+ */
+ SetLastError (ERROR_SUCCESS);
+
+ ret = fstat(fd, &statbuf);
+ if (ret == -1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__,
+ handle, strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(INVALID_FILE_SIZE);
+ }
+
+ /* fstat indicates block devices as zero-length, so go a different path */
+#ifdef BLKGETSIZE64
+ if (S_ISBLK(statbuf.st_mode)) {
+ guint64 bigsize;
+ if (ioctl(fd, BLKGETSIZE64, &bigsize) < 0) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p ioctl BLKGETSIZE64 failed: %s",
+ __func__, handle, strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(INVALID_FILE_SIZE);
+ }
+
+ size = bigsize & 0xFFFFFFFF;
+ if (highsize != NULL) {
+ *highsize = bigsize>>32;
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning block device size %d/%d",
+ __func__, size, *highsize);
+
+ return(size);
+ }
+#endif
+
+#ifdef HAVE_LARGE_FILE_SUPPORT
+ size = statbuf.st_size & 0xFFFFFFFF;
+ if (highsize != NULL) {
+ *highsize = statbuf.st_size>>32;
+ }
+#else
+ if (highsize != NULL) {
+ /* Accurate, but potentially dodgy :-) */
+ *highsize = 0;
+ }
+ size = statbuf.st_size;
+#endif
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning size %d/%d", __func__, size, *highsize);
+
+ return(size);
+}
+
+static gboolean file_getfiletime(gpointer handle, FILETIME *create_time,
+ FILETIME *access_time,
+ FILETIME *write_time)
+{
+ MonoW32HandleFile *file_handle;
+ gboolean ok;
+ struct stat statbuf;
+ guint64 create_ticks, access_ticks, write_ticks;
+ gint ret, fd;
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
+ (gpointer *)&file_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up file handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+ fd = file_handle->fd;
+
+ if(!(file_handle->fileaccess & GENERIC_READ) &&
+ !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
+ __func__, handle, file_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ ret=fstat(fd, &statbuf);
+ if(ret==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__, handle,
+ strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: atime: %ld ctime: %ld mtime: %ld", __func__,
+ statbuf.st_atime, statbuf.st_ctime,
+ statbuf.st_mtime);
+
+ /* Try and guess a meaningful create time by using the older
+ * of atime or ctime
+ */
+ /* The magic constant comes from msdn documentation
+ * "Converting a time_t Value to a File Time"
+ */
+ if(statbuf.st_atime < statbuf.st_ctime) {
+ create_ticks=((guint64)statbuf.st_atime*10000000)
+ + 116444736000000000ULL;
+ } else {
+ create_ticks=((guint64)statbuf.st_ctime*10000000)
+ + 116444736000000000ULL;
+ }
+
+ access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000ULL;
+ write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000ULL;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: aticks: %llu cticks: %llu wticks: %llu", __func__,
+ access_ticks, create_ticks, write_ticks);
+
+ if(create_time!=NULL) {
+ create_time->dwLowDateTime = create_ticks & 0xFFFFFFFF;
+ create_time->dwHighDateTime = create_ticks >> 32;
+ }
+
+ if(access_time!=NULL) {
+ access_time->dwLowDateTime = access_ticks & 0xFFFFFFFF;
+ access_time->dwHighDateTime = access_ticks >> 32;
+ }
+
+ if(write_time!=NULL) {
+ write_time->dwLowDateTime = write_ticks & 0xFFFFFFFF;
+ write_time->dwHighDateTime = write_ticks >> 32;
+ }
+
+ return(TRUE);
+}
+
+static gboolean file_setfiletime(gpointer handle,
+ const FILETIME *create_time G_GNUC_UNUSED,
+ const FILETIME *access_time,
+ const FILETIME *write_time)
+{
+ MonoW32HandleFile *file_handle;
+ gboolean ok;
+ struct utimbuf utbuf;
+ struct stat statbuf;
+ guint64 access_ticks, write_ticks;
+ gint ret, fd;
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
+ (gpointer *)&file_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up file handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+ fd = file_handle->fd;
+
+ if(!(file_handle->fileaccess & GENERIC_WRITE) &&
+ !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ if(file_handle->filename == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p unknown filename", __func__, handle);
+
+ SetLastError (ERROR_INVALID_HANDLE);
+ 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 (fd, &statbuf);
+ if(ret==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__, handle,
+ strerror(errno));
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ if(access_time!=NULL) {
+ access_ticks=((guint64)access_time->dwHighDateTime << 32) +
+ access_time->dwLowDateTime;
+ /* This is (time_t)0. We can actually go to INT_MIN,
+ * but this will do for now.
+ */
+ if (access_ticks < 116444736000000000ULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set access time too early",
+ __func__);
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ if (sizeof (utbuf.actime) == 4 && ((access_ticks - 116444736000000000ULL) / 10000000) > INT_MAX) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time that is too big for a 32bits time_t",
+ __func__);
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ utbuf.actime=(access_ticks - 116444736000000000ULL) / 10000000;
+ } else {
+ utbuf.actime=statbuf.st_atime;
+ }
+
+ if(write_time!=NULL) {
+ write_ticks=((guint64)write_time->dwHighDateTime << 32) +
+ write_time->dwLowDateTime;
+ /* This is (time_t)0. We can actually go to INT_MIN,
+ * but this will do for now.
+ */
+ if (write_ticks < 116444736000000000ULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time too early",
+ __func__);
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+ if (sizeof (utbuf.modtime) == 4 && ((write_ticks - 116444736000000000ULL) / 10000000) > INT_MAX) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time that is too big for a 32bits time_t",
+ __func__);
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ utbuf.modtime=(write_ticks - 116444736000000000ULL) / 10000000;
+ } else {
+ utbuf.modtime=statbuf.st_mtime;
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting handle %p access %ld write %ld", __func__,
+ handle, utbuf.actime, utbuf.modtime);
+
+ ret = _wapi_utime (file_handle->filename, &utbuf);
+ if (ret == -1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p [%s] utime failed: %s", __func__,
+ handle, file_handle->filename, strerror(errno));
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+static void console_close (gpointer handle, gpointer data)
+{
+ MonoW32HandleFile *console_handle = (MonoW32HandleFile *)data;
+ gint fd = console_handle->fd;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing console handle %p", __func__, handle);
+
+ g_free (console_handle->filename);
+
+ if (fd > 2) {
+ if (console_handle->share_info)
+ file_share_release (console_handle->share_info);
+ close (fd);
+ }
+}
+
+static void console_details (gpointer data)
+{
+ file_details (data);
+}
+
+static const gchar* console_typename (void)
+{
+ return "Console";
+}
+
+static gsize console_typesize (void)
+{
+ return sizeof (MonoW32HandleFile);
+}
+
+static gint console_getfiletype(void)
+{
+ return(FILE_TYPE_CHAR);
+}
+
+static gboolean
+console_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread)
+{
+ MonoW32HandleFile *console_handle;
+ gboolean ok;
+ gint ret, fd;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
+ (gpointer *)&console_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up console handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+ fd = console_handle->fd;
+
+ if(bytesread!=NULL) {
+ *bytesread=0;
+ }
+
+ if(!(console_handle->fileaccess & GENERIC_READ) &&
+ !(console_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
+ __func__, handle, console_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ do {
+ ret=read(fd, buffer, numbytes);
+ } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
+
+ if(ret==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of handle %p error: %s", __func__, handle,
+ strerror(errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+
+ if(bytesread!=NULL) {
+ *bytesread=ret;
+ }
+
+ return(TRUE);
+}
+
+static gboolean
+console_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten)
+{
+ MonoW32HandleFile *console_handle;
+ gboolean ok;
+ gint ret, fd;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
+ (gpointer *)&console_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up console handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+ fd = console_handle->fd;
+
+ if(byteswritten!=NULL) {
+ *byteswritten=0;
+ }
+
+ if(!(console_handle->fileaccess & GENERIC_WRITE) &&
+ !(console_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, console_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ do {
+ ret = write(fd, buffer, numbytes);
+ } while (ret == -1 && errno == EINTR &&
+ !mono_thread_info_is_interrupt_state (info));
+
+ if (ret == -1) {
+ if (errno == EINTR) {
+ ret = 0;
+ } else {
+ _wapi_set_last_error_from_errno ();
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of handle %p error: %s",
+ __func__, handle, strerror(errno));
+
+ return(FALSE);
+ }
+ }
+ if(byteswritten!=NULL) {
+ *byteswritten=ret;
+ }
+
+ return(TRUE);
+}
+
+static const gchar* find_typename (void)
+{
+ return "Find";
+}
+
+static gsize find_typesize (void)
+{
+ return sizeof (MonoW32HandleFind);
+}
+
+static void pipe_close (gpointer handle, gpointer data)
+{
+ MonoW32HandleFile *pipe_handle = (MonoW32HandleFile*)data;
+ gint fd = pipe_handle->fd;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing pipe handle %p fd %d", __func__, handle, fd);
+
+ /* No filename with pipe handles */
+
+ if (pipe_handle->share_info)
+ file_share_release (pipe_handle->share_info);
+
+ close (fd);
+}
+
+static void pipe_details (gpointer data)
+{
+ file_details (data);
+}
+
+static const gchar* pipe_typename (void)
+{
+ return "Pipe";
+}
+
+static gsize pipe_typesize (void)
+{
+ return sizeof (MonoW32HandleFile);
+}
+
+static gint pipe_getfiletype(void)
+{
+ return(FILE_TYPE_PIPE);
+}
+
+static gboolean
+pipe_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread)
+{
+ MonoW32HandleFile *pipe_handle;
+ gboolean ok;
+ gint ret, fd;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_PIPE,
+ (gpointer *)&pipe_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up pipe handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+ fd = pipe_handle->fd;
+
+ if(bytesread!=NULL) {
+ *bytesread=0;
+ }
+
+ if(!(pipe_handle->fileaccess & GENERIC_READ) &&
+ !(pipe_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
+ __func__, handle, pipe_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: reading up to %d bytes from pipe %p", __func__,
+ numbytes, handle);
+
+ do {
+ ret=read(fd, buffer, numbytes);
+ } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
+
+ if (ret == -1) {
+ if (errno == EINTR) {
+ ret = 0;
+ } else {
+ _wapi_set_last_error_from_errno ();
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of handle %p error: %s", __func__,
+ handle, strerror(errno));
+
+ return(FALSE);
+ }
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read %d bytes from pipe %p", __func__, ret, handle);
+
+ if(bytesread!=NULL) {
+ *bytesread=ret;
+ }
+
+ return(TRUE);
+}
+
+static gboolean
+pipe_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten)
+{
+ MonoW32HandleFile *pipe_handle;
+ gboolean ok;
+ gint ret, fd;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_PIPE,
+ (gpointer *)&pipe_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up pipe handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+ fd = pipe_handle->fd;
+
+ if(byteswritten!=NULL) {
+ *byteswritten=0;
+ }
+
+ if(!(pipe_handle->fileaccess & GENERIC_WRITE) &&
+ !(pipe_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, pipe_handle->fileaccess);
+
+ SetLastError (ERROR_ACCESS_DENIED);
+ return(FALSE);
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: writing up to %d bytes to pipe %p", __func__, numbytes,
+ handle);
+
+ do {
+ ret = write (fd, buffer, numbytes);
+ } while (ret == -1 && errno == EINTR &&
+ !mono_thread_info_is_interrupt_state (info));
+
+ if (ret == -1) {
+ if (errno == EINTR) {
+ ret = 0;
+ } else {
+ _wapi_set_last_error_from_errno ();
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of handle %p error: %s", __func__,
+ handle, strerror(errno));
+
+ return(FALSE);
+ }
+ }
+ if(byteswritten!=NULL) {
+ *byteswritten=ret;
+ }
+
+ return(TRUE);
+}
+
+static gint convert_flags(guint32 fileaccess, guint32 createmode)
+{
+ gint flags=0;
+
+ switch(fileaccess) {
+ case GENERIC_READ:
+ flags=O_RDONLY;
+ break;
+ case GENERIC_WRITE:
+ flags=O_WRONLY;
+ break;
+ case GENERIC_READ|GENERIC_WRITE:
+ flags=O_RDWR;
+ break;
+ default:
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unknown access type 0x%x", __func__,
+ fileaccess);
+ break;
+ }
+
+ switch(createmode) {
+ case CREATE_NEW:
+ flags|=O_CREAT|O_EXCL;
+ break;
+ case CREATE_ALWAYS:
+ flags|=O_CREAT|O_TRUNC;
+ break;
+ case OPEN_EXISTING:
+ break;
+ case OPEN_ALWAYS:
+ flags|=O_CREAT;
+ break;
+ case TRUNCATE_EXISTING:
+ flags|=O_TRUNC;
+ break;
+ default:
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unknown create mode 0x%x", __func__,
+ createmode);
+ break;
+ }
+
+ return(flags);
+}
+
+#if 0 /* unused */
+static mode_t convert_perms(guint32 sharemode)
+{
+ mode_t perms=0600;
+
+ if(sharemode&FILE_SHARE_READ) {
+ perms|=044;
+ }
+ if(sharemode&FILE_SHARE_WRITE) {
+ perms|=022;
+ }
+
+ return(perms);
+}
+#endif
+
+static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode,
+ guint32 fileaccess,
+ FileShare **share_info)
+{
+ gboolean file_already_shared;
+ guint32 file_existing_share, file_existing_access;
+
+ file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, sharemode, fileaccess, &file_existing_share, &file_existing_access, share_info);
+
+ if (file_already_shared) {
+ /* The reference to this share info was incremented
+ * when we looked it up, so be careful to put it back
+ * if we conclude we can't use this file.
+ */
+ if (file_existing_share == 0) {
+ /* Quick and easy, no possibility to share */
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%x, file has sharing = NONE", __func__, fileaccess);
+
+ file_share_release (*share_info);
+
+ return(FALSE);
+ }
+
+ if (((file_existing_share == FILE_SHARE_READ) &&
+ (fileaccess != GENERIC_READ)) ||
+ ((file_existing_share == FILE_SHARE_WRITE) &&
+ (fileaccess != GENERIC_WRITE))) {
+ /* New access mode doesn't match up */
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%x, file has sharing: 0x%x", __func__, fileaccess, file_existing_share);
+
+ file_share_release (*share_info);
+
+ return(FALSE);
+ }
+
+ if (((file_existing_access & GENERIC_READ) &&
+ !(sharemode & FILE_SHARE_READ)) ||
+ ((file_existing_access & GENERIC_WRITE) &&
+ !(sharemode & FILE_SHARE_WRITE))) {
+ /* New share mode doesn't match up */
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Access mode prevents open: requested share: 0x%x, file has access: 0x%x", __func__, sharemode, file_existing_access);
+
+ file_share_release (*share_info);
+
+ return(FALSE);
+ }
+ } else {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: New file!", __func__);
+ }
+
+ return(TRUE);
+}
+
+
+static gboolean
+share_allows_delete (struct stat *statbuf, FileShare **share_info)
+{
+ gboolean file_already_shared;
+ guint32 file_existing_share, file_existing_access;
+
+ file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, FILE_SHARE_DELETE, GENERIC_READ, &file_existing_share, &file_existing_access, share_info);
+
+ if (file_already_shared) {
+ /* The reference to this share info was incremented
+ * when we looked it up, so be careful to put it back
+ * if we conclude we can't use this file.
+ */
+ if (file_existing_share == 0) {
+ /* Quick and easy, no possibility to share */
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%x, file has sharing = NONE", __func__, (*share_info)->access);
+
+ file_share_release (*share_info);
+
+ return(FALSE);
+ }
+
+ if (!(file_existing_share & FILE_SHARE_DELETE)) {
+ /* New access mode doesn't match up */
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%x, file has sharing: 0x%x", __func__, (*share_info)->access, file_existing_share);
+
+ file_share_release (*share_info);
+
+ return(FALSE);
+ }
+ } else {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: New file!", __func__);
+ }
+
+ return(TRUE);
+}
+
+gpointer
+mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs)
+{
+ MonoW32HandleFile file_handle = {0};
+ gpointer handle;
+ gint flags=convert_flags(fileaccess, createmode);
+ /*mode_t perms=convert_perms(sharemode);*/
+ /* we don't use sharemode, because that relates to sharing of
+ * the file when the file is open and is already handled by
+ * other code, perms instead are the on-disk permissions and
+ * this is a sane default.
+ */
+ mode_t perms=0666;
+ gchar *filename;
+ gint fd, ret;
+ MonoW32HandleType handle_type;
+ struct stat statbuf;
+
+ if (attrs & FILE_ATTRIBUTE_TEMPORARY)
+ perms = 0600;
+
+ if (attrs & FILE_ATTRIBUTE_ENCRYPTED){
+ SetLastError (ERROR_ENCRYPTION_FAILED);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ filename = mono_unicode_to_external (name);
+ if (filename == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening %s with share 0x%x and access 0x%x", __func__,
+ filename, sharemode, fileaccess);
+
+ fd = _wapi_open (filename, flags, perms);
+
+ /* If we were trying to open a directory with write permissions
+ * (e.g. O_WRONLY or O_RDWR), this call will fail with
+ * EISDIR. However, this is a bit bogus because calls to
+ * manipulate the directory (e.g. mono_w32file_set_times) will still work on
+ * the directory because they use other API calls
+ * (e.g. utime()). Hence, if we failed with the EISDIR error, try
+ * to open the directory again without write permission.
+ */
+ if (fd == -1 && errno == EISDIR)
+ {
+ /* Try again but don't try to make it writable */
+ fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms);
+ }
+
+ if (fd == -1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s: %s", __func__, filename,
+ strerror(errno));
+ _wapi_set_last_path_error_from_errno (NULL, filename);
+ g_free (filename);
+
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ if (fd >= mono_w32handle_fd_reserve) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
+
+ SetLastError (ERROR_TOO_MANY_OPEN_FILES);
+
+ close (fd);
+ g_free (filename);
+
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ ret = fstat (fd, &statbuf);
+ if (ret == -1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fstat error of file %s: %s", __func__,
+ filename, strerror (errno));
+ _wapi_set_last_error_from_errno ();
+ g_free (filename);
+ close (fd);
+
+ return(INVALID_HANDLE_VALUE);
+ }
+#ifdef __native_client__
+ /* Workaround: Native Client currently returns the same fake inode
+ * for all files, so do a simple hash on the filename so we don't
+ * use the same share info for each file.
+ */
+ statbuf.st_ino = g_str_hash(filename);
+#endif
+
+ if (share_allows_open (&statbuf, sharemode, fileaccess,
+ &file_handle.share_info) == FALSE) {
+ SetLastError (ERROR_SHARING_VIOLATION);
+ g_free (filename);
+ close (fd);
+
+ return (INVALID_HANDLE_VALUE);
+ }
+ if (file_handle.share_info == NULL) {
+ /* No space, so no more files can be opened */
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No space in the share table", __func__);
+
+ SetLastError (ERROR_TOO_MANY_OPEN_FILES);
+ close (fd);
+ g_free (filename);
+
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ file_handle.filename = filename;
+
+ file_handle.fd = fd;
+ file_handle.fileaccess=fileaccess;
+ file_handle.sharemode=sharemode;
+ file_handle.attrs=attrs;
+
+#ifdef HAVE_POSIX_FADVISE
+ if (attrs & FILE_FLAG_SEQUENTIAL_SCAN)
+ posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+ if (attrs & FILE_FLAG_RANDOM_ACCESS)
+ posix_fadvise (fd, 0, 0, POSIX_FADV_RANDOM);
+#endif
+
+#ifdef F_RDAHEAD
+ if (attrs & FILE_FLAG_SEQUENTIAL_SCAN)
+ fcntl(fd, F_RDAHEAD, 1);
+#endif
+
+#ifndef S_ISFIFO
+#define S_ISFIFO(m) ((m & S_IFIFO) != 0)
+#endif
+ if (S_ISFIFO (statbuf.st_mode)) {
+ handle_type = MONO_W32HANDLE_PIPE;
+ /* maintain invariant that pipes have no filename */
+ file_handle.filename = NULL;
+ g_free (filename);
+ filename = NULL;
+ } else if (S_ISCHR (statbuf.st_mode)) {
+ handle_type = MONO_W32HANDLE_CONSOLE;
+ } else {
+ handle_type = MONO_W32HANDLE_FILE;
+ }
+
+ handle = mono_w32handle_new_fd (handle_type, fd, &file_handle);
+ if (handle == INVALID_HANDLE_VALUE) {
+ g_warning ("%s: error creating file handle", __func__);
+ g_free (filename);
+ close (fd);
+
+ SetLastError (ERROR_GEN_FAILURE);
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p", __func__, handle);
+
+ return(handle);
+}
+
+gboolean mono_w32file_delete(const gunichar2 *name)
+{
+ gchar *filename;
+ gint retval;
+ gboolean ret = FALSE;
+ guint32 attrs;
+#if 0
+ struct stat statbuf;
+ FileShare *shareinfo;
+#endif
+
+ if(name==NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ filename=mono_unicode_to_external(name);
+ if(filename==NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ attrs = mono_w32file_get_attributes (name);
+ if (attrs == INVALID_FILE_ATTRIBUTES) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file attributes error", __func__);
+ /* Error set by mono_w32file_get_attributes() */
+ g_free (filename);
+ return(FALSE);
+ }
+
+#if 0
+ /* Check to make sure sharing allows us to open the file for
+ * writing. See bug 323389.
+ *
+ * Do the checks that don't need an open file descriptor, for
+ * simplicity's sake. If we really have to do the full checks
+ * then we can implement that later.
+ */
+ if (_wapi_stat (filename, &statbuf) < 0) {
+ _wapi_set_last_path_error_from_errno (NULL, filename);
+ g_free (filename);
+ return(FALSE);
+ }
+
+ if (share_allows_open (&statbuf, 0, GENERIC_WRITE,
+ &shareinfo) == FALSE) {
+ SetLastError (ERROR_SHARING_VIOLATION);
+ g_free (filename);
+ return FALSE;
+ }
+ if (shareinfo)
+ file_share_release (shareinfo);
+#endif
+
+ retval = _wapi_unlink (filename);
+
+ if (retval == -1) {
+ _wapi_set_last_path_error_from_errno (NULL, filename);
+ } else {
+ ret = TRUE;
+ }
+
+ g_free(filename);
+
+ return(ret);
+}
+
+static gboolean
+MoveFile (gunichar2 *name, gunichar2 *dest_name)
+{
+ gchar *utf8_name, *utf8_dest_name;
+ gint result, errno_copy;
+ struct stat stat_src, stat_dest;
+ gboolean ret = FALSE;
+ FileShare *shareinfo;
+
+ if(name==NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_name = mono_unicode_to_external (name);
+ if (utf8_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return FALSE;
+ }
+
+ if(dest_name==NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ g_free (utf8_name);
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_dest_name = mono_unicode_to_external (dest_name);
+ if (utf8_dest_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ g_free (utf8_name);
+ SetLastError (ERROR_INVALID_NAME);
+ return FALSE;
+ }
+
+ /*
+ * In C# land we check for the existence of src, but not for dest.
+ * We check it here and return the failure if dest exists and is not
+ * the same file as src.
+ */
+ if (_wapi_stat (utf8_name, &stat_src) < 0) {
+ if (errno != ENOENT || _wapi_lstat (utf8_name, &stat_src) < 0) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+ g_free (utf8_name);
+ g_free (utf8_dest_name);
+ return FALSE;
+ }
+ }
+
+ if (!_wapi_stat (utf8_dest_name, &stat_dest)) {
+ if (stat_dest.st_dev != stat_src.st_dev ||
+ stat_dest.st_ino != stat_src.st_ino) {
+ g_free (utf8_name);
+ g_free (utf8_dest_name);
+ SetLastError (ERROR_ALREADY_EXISTS);
+ return FALSE;
+ }
+ }
+
+ /* Check to make that we have delete sharing permission.
+ * See https://bugzilla.xamarin.com/show_bug.cgi?id=17009
+ *
+ * Do the checks that don't need an open file descriptor, for
+ * simplicity's sake. If we really have to do the full checks
+ * then we can implement that later.
+ */
+ if (share_allows_delete (&stat_src, &shareinfo) == FALSE) {
+ SetLastError (ERROR_SHARING_VIOLATION);
+ return FALSE;
+ }
+ if (shareinfo)
+ file_share_release (shareinfo);
+
+ result = _wapi_rename (utf8_name, utf8_dest_name);
+ errno_copy = errno;
+
+ if (result == -1) {
+ switch(errno_copy) {
+ case EEXIST:
+ SetLastError (ERROR_ALREADY_EXISTS);
+ break;
+
+ case EXDEV:
+ /* Ignore here, it is dealt with below */
+ break;
+
+ case ENOENT:
+ /* We already know src exists. Must be dest that doesn't exist. */
+ _wapi_set_last_path_error_from_errno (NULL, utf8_dest_name);
+ break;
+
+ default:
+ _wapi_set_last_error_from_errno ();
+ }
+ }
+
+ g_free (utf8_name);
+ g_free (utf8_dest_name);
+
+ if (result != 0 && errno_copy == EXDEV) {
+ gint32 copy_error;
+
+ if (S_ISDIR (stat_src.st_mode)) {
+ SetLastError (ERROR_NOT_SAME_DEVICE);
+ return FALSE;
+ }
+ /* Try a copy to the new location, and delete the source */
+ if (!mono_w32file_copy (name, dest_name, FALSE, ©_error)) {
+ /* mono_w32file_copy will set the error */
+ return(FALSE);
+ }
+
+ return(mono_w32file_delete (name));
+ }
+
+ if (result == 0) {
+ ret = TRUE;
+ }
+
+ return(ret);
+}
+
+static gboolean
+write_file (gint src_fd, gint dest_fd, struct stat *st_src, gboolean report_errors)
+{
+ gint remain, n;
+ gchar *buf, *wbuf;
+ gint buf_size = st_src->st_blksize;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : buf_size);
+ buf = (gchar *) g_malloc (buf_size);
+
+ for (;;) {
+ remain = read (src_fd, buf, buf_size);
+ if (remain < 0) {
+ if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
+ continue;
+
+ if (report_errors)
+ _wapi_set_last_error_from_errno ();
+
+ g_free (buf);
+ return FALSE;
+ }
+ if (remain == 0) {
+ break;
+ }
+
+ wbuf = buf;
+ while (remain > 0) {
+ if ((n = write (dest_fd, wbuf, remain)) < 0) {
+ if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
+ continue;
+
+ if (report_errors)
+ _wapi_set_last_error_from_errno ();
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write failed.", __func__);
+ g_free (buf);
+ return FALSE;
+ }
+
+ remain -= n;
+ wbuf += n;
+ }
+ }
+
+ g_free (buf);
+ return TRUE ;
+}
+
+static gboolean
+CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_exists)
+{
+ gchar *utf8_src, *utf8_dest;
+ gint src_fd, dest_fd;
+ struct stat st, dest_st;
+ struct utimbuf dest_time;
+ gboolean ret = TRUE;
+ gint ret_utime;
+
+ if(name==NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_src = mono_unicode_to_external (name);
+ if (utf8_src == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of source returned NULL",
+ __func__);
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ if(dest_name==NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dest is NULL", __func__);
+
+ g_free (utf8_src);
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_dest = mono_unicode_to_external (dest_name);
+ if (utf8_dest == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of dest returned NULL",
+ __func__);
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+
+ g_free (utf8_src);
+
+ return(FALSE);
+ }
+
+ src_fd = _wapi_open (utf8_src, O_RDONLY, 0);
+ if (src_fd < 0) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_src);
+
+ g_free (utf8_src);
+ g_free (utf8_dest);
+
+ return(FALSE);
+ }
+
+ if (fstat (src_fd, &st) < 0) {
+ _wapi_set_last_error_from_errno ();
+
+ g_free (utf8_src);
+ g_free (utf8_dest);
+ close (src_fd);
+
+ return(FALSE);
+ }
+
+ /* Before trying to open/create the dest, we need to report a 'file busy'
+ * error if src and dest are actually the same file. We do the check here to take
+ * advantage of the IOMAP capability */
+ if (!_wapi_stat (utf8_dest, &dest_st) && st.st_dev == dest_st.st_dev &&
+ st.st_ino == dest_st.st_ino) {
+
+ g_free (utf8_src);
+ g_free (utf8_dest);
+ close (src_fd);
+
+ SetLastError (ERROR_SHARING_VIOLATION);
+ return (FALSE);
+ }
+
+ if (fail_if_exists) {
+ dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL, st.st_mode);
+ } else {
+ /* FIXME: it kinda sucks that this code path potentially scans
+ * the directory twice due to the weird SetLastError()
+ * behavior. */
+ dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode);
+ if (dest_fd < 0) {
+ /* The file does not exist, try creating it */
+ dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode);
+ } else {
+ /* Apparently this error is set if we
+ * overwrite the dest file
+ */
+ SetLastError (ERROR_ALREADY_EXISTS);
+ }
+ }
+ if (dest_fd < 0) {
+ _wapi_set_last_error_from_errno ();
+
+ g_free (utf8_src);
+ g_free (utf8_dest);
+ close (src_fd);
+
+ return(FALSE);
+ }
+
+ if (!write_file (src_fd, dest_fd, &st, TRUE))
+ ret = FALSE;
+
+ close (src_fd);
+ close (dest_fd);
+
+ dest_time.modtime = st.st_mtime;
+ dest_time.actime = st.st_atime;
+ ret_utime = utime (utf8_dest, &dest_time);
+ if (ret_utime == -1)
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file [%s] utime failed: %s", __func__, utf8_dest, strerror(errno));
+
+ g_free (utf8_src);
+ g_free (utf8_dest);
+
+ return ret;
+}
+
+static gchar*
+convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name)
+{
+ gchar *utf8_ret;
+
+ if (arg == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s is NULL", __func__, arg_name);
+ SetLastError (ERROR_INVALID_NAME);
+ return NULL;
+ }
+
+ utf8_ret = mono_unicode_to_external (arg);
+ if (utf8_ret == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of %s returned NULL",
+ __func__, arg_name);
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ return utf8_ret;
+}
+
+static gboolean
+ReplaceFile (const gunichar2 *replacedFileName, const gunichar2 *replacementFileName, const gunichar2 *backupFileName, guint32 replaceFlags, gpointer exclude, gpointer reserved)
+{
+ gint result, backup_fd = -1,replaced_fd = -1;
+ gchar *utf8_replacedFileName, *utf8_replacementFileName = NULL, *utf8_backupFileName = NULL;
+ struct stat stBackup;
+ gboolean ret = FALSE;
+
+ if (!(utf8_replacedFileName = convert_arg_to_utf8 (replacedFileName, "replacedFileName")))
+ return FALSE;
+ if (!(utf8_replacementFileName = convert_arg_to_utf8 (replacementFileName, "replacementFileName")))
+ goto replace_cleanup;
+ if (backupFileName != NULL) {
+ if (!(utf8_backupFileName = convert_arg_to_utf8 (backupFileName, "backupFileName")))
+ goto replace_cleanup;
+ }
+
+ if (utf8_backupFileName) {
+ // Open the backup file for read so we can restore the file if an error occurs.
+ backup_fd = _wapi_open (utf8_backupFileName, O_RDONLY, 0);
+ result = _wapi_rename (utf8_replacedFileName, utf8_backupFileName);
+ if (result == -1)
+ goto replace_cleanup;
+ }
+
+ result = _wapi_rename (utf8_replacementFileName, utf8_replacedFileName);
+ if (result == -1) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_replacementFileName);
+ _wapi_rename (utf8_backupFileName, utf8_replacedFileName);
+ if (backup_fd != -1 && !fstat (backup_fd, &stBackup)) {
+ replaced_fd = _wapi_open (utf8_backupFileName, O_WRONLY | O_CREAT | O_TRUNC,
+ stBackup.st_mode);
+
+ if (replaced_fd == -1)
+ goto replace_cleanup;
+
+ write_file (backup_fd, replaced_fd, &stBackup, FALSE);
+ }
+
+ goto replace_cleanup;
+ }
+
+ ret = TRUE;
+
+replace_cleanup:
+ g_free (utf8_replacedFileName);
+ g_free (utf8_replacementFileName);
+ g_free (utf8_backupFileName);
+ if (backup_fd != -1)
+ close (backup_fd);
+ if (replaced_fd != -1)
+ close (replaced_fd);
+ return ret;
+}
+
+static mono_mutex_t stdhandle_mutex;
+
+static gpointer
+_wapi_stdhandle_create (gint fd, const gchar *name)
+{
+ gpointer handle;
+ gint flags;
+ MonoW32HandleFile file_handle = {0};
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating standard handle type %s, fd %d", __func__, name, fd);
+
+#if !defined(__native_client__)
+ /* Check if fd is valid */
+ do {
+ flags = fcntl(fd, F_GETFL);
+ } while (flags == -1 && errno == EINTR);
+
+ if (flags == -1) {
+ /* Invalid fd. Not really much point checking for EBADF
+ * specifically
+ */
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl error on fd %d: %s", __func__, fd, strerror(errno));
+
+ SetLastError (_wapi_get_win32_file_error (errno));
+ return INVALID_HANDLE_VALUE;
+ }
+
+ switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
+ case O_RDONLY:
+ file_handle.fileaccess = GENERIC_READ;
+ break;
+ case O_WRONLY:
+ file_handle.fileaccess = GENERIC_WRITE;
+ break;
+ case O_RDWR:
+ file_handle.fileaccess = GENERIC_READ | GENERIC_WRITE;
+ break;
+ default:
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't figure out flags 0x%x", __func__, flags);
+ file_handle.fileaccess = 0;
+ break;
+ }
+#else
+ /*
+ * fcntl will return -1 in nacl, as there is no real file system API.
+ * Yet, standard streams are available.
+ */
+ file_handle.fileaccess = (fd == STDIN_FILENO) ? GENERIC_READ : GENERIC_WRITE;
+#endif
+
+ file_handle.fd = fd;
+ file_handle.filename = g_strdup(name);
+ /* some default security attributes might be needed */
+ file_handle.security_attributes = 0;
+
+ /* Apparently input handles can't be written to. (I don't
+ * know if output or error handles can't be read from.)
+ */
+ if (fd == 0)
+ file_handle.fileaccess &= ~GENERIC_WRITE;
+
+ file_handle.sharemode = 0;
+ file_handle.attrs = 0;
+
+ handle = mono_w32handle_new_fd (MONO_W32HANDLE_CONSOLE, fd, &file_handle);
+ if (handle == INVALID_HANDLE_VALUE) {
+ g_warning ("%s: error creating file handle", __func__);
+ SetLastError (ERROR_GEN_FAILURE);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p", __func__, handle);
+
+ return handle;
+}
+
+enum {
+ STD_INPUT_HANDLE = -10,
+ STD_OUTPUT_HANDLE = -11,
+ STD_ERROR_HANDLE = -12,
+};
+
+static gpointer
+mono_w32file_get_std_handle (gint stdhandle)
+{
+ MonoW32HandleFile *file_handle;
+ gpointer handle;
+ gint fd;
+ const gchar *name;
+ gboolean ok;
+
+ 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:
+ g_assert_not_reached ();
+ }
+
+ handle = GINT_TO_POINTER (fd);
+
+ mono_os_mutex_lock (&stdhandle_mutex);
+
+ ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
+ (gpointer *)&file_handle);
+ if (ok == FALSE) {
+ /* Need to create this console handle */
+ handle = _wapi_stdhandle_create (fd, name);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SetLastError (ERROR_NO_MORE_FILES);
+ goto done;
+ }
+ } else {
+ /* Add a reference to this handle */
+ mono_w32handle_ref (handle);
+ }
+
+ done:
+ mono_os_mutex_unlock (&stdhandle_mutex);
+
+ return(handle);
+}
+
+gboolean
+mono_w32file_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if(io_ops[type].readfile==NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(io_ops[type].readfile (handle, buffer, numbytes, bytesread));
+}
+
+gboolean
+mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if(io_ops[type].writefile==NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(io_ops[type].writefile (handle, buffer, numbytes, byteswritten));
+}
+
+gboolean
+mono_w32file_flush (gpointer handle)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if(io_ops[type].flushfile==NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(io_ops[type].flushfile (handle));
+}
+
+gboolean
+mono_w32file_truncate (gpointer handle)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if (io_ops[type].setendoffile == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(io_ops[type].setendoffile (handle));
+}
+
+guint32
+mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if (io_ops[type].seek == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(INVALID_SET_FILE_POINTER);
+ }
+
+ return(io_ops[type].seek (handle, movedistance, highmovedistance,
+ method));
+}
+
+gint
+mono_w32file_get_type(gpointer handle)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if (io_ops[type].getfiletype == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FILE_TYPE_UNKNOWN);
+ }
+
+ return(io_ops[type].getfiletype ());
+}
+
+static guint32
+GetFileSize(gpointer handle, guint32 *highsize)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if (io_ops[type].getfilesize == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(INVALID_FILE_SIZE);
+ }
+
+ return(io_ops[type].getfilesize (handle, highsize));
+}
+
+gboolean
+mono_w32file_get_times(gpointer handle, FILETIME *create_time, FILETIME *access_time, FILETIME *write_time)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if (io_ops[type].getfiletime == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(io_ops[type].getfiletime (handle, create_time, access_time,
+ write_time));
+}
+
+gboolean
+mono_w32file_set_times(gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time)
+{
+ MonoW32HandleType type;
+
+ type = mono_w32handle_get_type (handle);
+
+ if (io_ops[type].setfiletime == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(io_ops[type].setfiletime (handle, create_time, access_time,
+ write_time));
+}
+
+/* A tick is a 100-nanosecond interval. File time epoch is Midnight,
+ * January 1 1601 GMT
+ */
+
+#define TICKS_PER_MILLISECOND 10000L
+#define TICKS_PER_SECOND 10000000L
+#define TICKS_PER_MINUTE 600000000L
+#define TICKS_PER_HOUR 36000000000LL
+#define TICKS_PER_DAY 864000000000LL
+
+#define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
+
+static const guint16 mon_yday[2][13]={
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
+};
+
+gboolean
+mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *system_time)
+{
+ gint64 file_ticks, totaldays, rem, y;
+ const guint16 *ip;
+
+ if(system_time==NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: system_time NULL", __func__);
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ file_ticks=((gint64)file_time->dwHighDateTime << 32) +
+ file_time->dwLowDateTime;
+
+ /* Really compares if file_ticks>=0x8000000000000000
+ * (LLONG_MAX+1) but we're working with a signed value for the
+ * year and day calculation to work later
+ */
+ if(file_ticks<0) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file_time too big", __func__);
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ totaldays=(file_ticks / TICKS_PER_DAY);
+ rem = file_ticks % TICKS_PER_DAY;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %lld rem: %lld", __func__, totaldays, rem);
+
+ system_time->wHour=rem/TICKS_PER_HOUR;
+ rem %= TICKS_PER_HOUR;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hour: %d rem: %lld", __func__, system_time->wHour, rem);
+
+ system_time->wMinute = rem / TICKS_PER_MINUTE;
+ rem %= TICKS_PER_MINUTE;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Minute: %d rem: %lld", __func__, system_time->wMinute,
+ rem);
+
+ system_time->wSecond = rem / TICKS_PER_SECOND;
+ rem %= TICKS_PER_SECOND;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Second: %d rem: %lld", __func__, system_time->wSecond,
+ rem);
+
+ system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Milliseconds: %d", __func__,
+ system_time->wMilliseconds);
+
+ /* January 1, 1601 was a Monday, according to Emacs calendar */
+ system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Day of week: %d", __func__, system_time->wDayOfWeek);
+
+ /* This algorithm to find year and month given days from epoch
+ * from glibc
+ */
+ y=1601;
+
+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400))
+
+ while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
+ /* Guess a corrected year, assuming 365 days per year */
+ gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %lld yg: %lld y: %lld", __func__,
+ totaldays, yg,
+ y);
+ g_message("%s: LEAPS(yg): %lld LEAPS(y): %lld", __func__,
+ LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
+
+ /* Adjust days and y to match the guessed year. */
+ totaldays -= ((yg - y) * 365
+ + LEAPS_THRU_END_OF (yg - 1)
+ - LEAPS_THRU_END_OF (y - 1));
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %lld", __func__, totaldays);
+ y = yg;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: y: %lld", __func__, y);
+ }
+
+ system_time->wYear = y;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Year: %d", __func__, system_time->wYear);
+
+ ip = mon_yday[isleap(y)];
+
+ for(y=11; totaldays < ip[y]; --y) {
+ continue;
+ }
+ totaldays-=ip[y];
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %lld", __func__, totaldays);
+
+ system_time->wMonth = y + 1;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Month: %d", __func__, system_time->wMonth);
+
+ system_time->wDay = totaldays + 1;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Day: %d", __func__, system_time->wDay);
+
+ return(TRUE);
+}
+
+gpointer
+mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
+{
+ MonoW32HandleFind find_handle = {0};
+ gpointer handle;
+ gchar *utf8_pattern = NULL, *dir_part, *entry_part;
+ gint result;
+
+ if (pattern == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pattern is NULL", __func__);
+
+ SetLastError (ERROR_PATH_NOT_FOUND);
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ utf8_pattern = mono_unicode_to_external (pattern);
+ if (utf8_pattern == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking for [%s]", __func__, utf8_pattern);
+
+ /* Figure out which bit of the pattern is the directory */
+ dir_part = _wapi_dirname (utf8_pattern);
+ entry_part = _wapi_basename (utf8_pattern);
+
+#if 0
+ /* Don't do this check for now, it breaks if directories
+ * really do have metachars in their names (see bug 58116).
+ * FIXME: Figure out a better solution to keep some checks...
+ */
+ if (strchr (dir_part, '*') || strchr (dir_part, '?')) {
+ SetLastError (ERROR_INVALID_NAME);
+ g_free (dir_part);
+ g_free (entry_part);
+ g_free (utf8_pattern);
+ return(INVALID_HANDLE_VALUE);
+ }
+#endif
+
+ /* The pattern can specify a directory or a set of files.
+ *
+ * The pattern can have wildcard characters ? and *, but only
+ * in the section after the last directory delimiter. (Return
+ * ERROR_INVALID_NAME if there are wildcards in earlier path
+ * sections.) "*" has the usual 0-or-more chars meaning. "?"
+ * means "match one character", "??" seems to mean "match one
+ * or two characters", "???" seems to mean "match one, two or
+ * three characters", etc. Windows will also try and match
+ * the mangled "short name" of files, so 8 character patterns
+ * with wildcards will show some surprising results.
+ *
+ * All the written documentation I can find says that '?'
+ * should only match one character, and doesn't mention '??',
+ * '???' etc. I'm going to assume that the strict behaviour
+ * (ie '???' means three and only three characters) is the
+ * correct one, because that lets me use fnmatch(3) rather
+ * than mess around with regexes.
+ */
+
+ find_handle.namelist = NULL;
+ result = _wapi_io_scandir (dir_part, entry_part,
+ &find_handle.namelist);
+
+ if (result == 0) {
+ /* No files, which windows seems to call
+ * FILE_NOT_FOUND
+ */
+ SetLastError (ERROR_FILE_NOT_FOUND);
+ g_free (utf8_pattern);
+ g_free (entry_part);
+ g_free (dir_part);
+ return (INVALID_HANDLE_VALUE);
+ }
+
+ if (result < 0) {
+ _wapi_set_last_path_error_from_errno (dir_part, NULL);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: scandir error: %s", __func__, g_strerror (errno));
+ g_free (utf8_pattern);
+ g_free (entry_part);
+ g_free (dir_part);
+ return (INVALID_HANDLE_VALUE);
+ }
+
+ g_free (utf8_pattern);
+ g_free (entry_part);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Got %d matches", __func__, result);
+
+ find_handle.dir_part = dir_part;
+ find_handle.num = result;
+ find_handle.count = 0;
+
+ handle = mono_w32handle_new (MONO_W32HANDLE_FIND, &find_handle);
+ if (handle == INVALID_HANDLE_VALUE) {
+ g_warning ("%s: error creating find handle", __func__);
+ g_free (dir_part);
+ g_free (entry_part);
+ g_free (utf8_pattern);
+ SetLastError (ERROR_GEN_FAILURE);
+
+ return(INVALID_HANDLE_VALUE);
+ }
+
+ if (handle != INVALID_HANDLE_VALUE &&
+ !mono_w32file_find_next (handle, find_data)) {
+ mono_w32file_find_close (handle);
+ SetLastError (ERROR_NO_MORE_FILES);
+ handle = INVALID_HANDLE_VALUE;
+ }
+
+ return (handle);
+}
+
+gboolean
+mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data)
+{
+ MonoW32HandleFind *find_handle;
+ gboolean ok;
+ struct stat buf, linkbuf;
+ gint result;
+ gchar *filename;
+ gchar *utf8_filename, *utf8_basename;
+ gunichar2 *utf16_basename;
+ time_t create_time;
+ glong bytes;
+ gboolean ret = FALSE;
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FIND,
+ (gpointer *)&find_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up find handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ mono_w32handle_lock_handle (handle);
+
+retry:
+ if (find_handle->count >= find_handle->num) {
+ SetLastError (ERROR_NO_MORE_FILES);
+ goto cleanup;
+ }
+
+ /* stat next match */
+
+ filename = g_build_filename (find_handle->dir_part, find_handle->namelist[find_handle->count ++], NULL);
+
+ result = _wapi_stat (filename, &buf);
+ if (result == -1 && errno == ENOENT) {
+ /* Might be a dangling symlink */
+ result = _wapi_lstat (filename, &buf);
+ }
+
+ if (result != 0) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: stat failed: %s", __func__, filename);
+
+ g_free (filename);
+ goto retry;
+ }
+
+#ifndef __native_client__
+ result = _wapi_lstat (filename, &linkbuf);
+ if (result != 0) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lstat failed: %s", __func__, filename);
+
+ g_free (filename);
+ goto retry;
+ }
+#endif
+
+ utf8_filename = mono_utf8_from_external (filename);
+ if (utf8_filename == NULL) {
+ /* We couldn't turn this filename into utf8 (eg the
+ * encoding of the name wasn't convertible), so just
+ * ignore it.
+ */
+ g_warning ("%s: Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODINGS\n", __func__, filename);
+
+ g_free (filename);
+ goto retry;
+ }
+ g_free (filename);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Found [%s]", __func__, utf8_filename);
+
+ /* fill data block */
+
+ if (buf.st_mtime < buf.st_ctime)
+ create_time = buf.st_mtime;
+ else
+ create_time = buf.st_ctime;
+
+#ifdef __native_client__
+ find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, NULL);
+#else
+ find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, &linkbuf);
+#endif
+
+ time_t_to_filetime (create_time, &find_data->ftCreationTime);
+ time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
+ 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;
+
+ utf8_basename = _wapi_basename (utf8_filename);
+ utf16_basename = g_utf8_to_utf16 (utf8_basename, -1, NULL, &bytes,
+ NULL);
+ if(utf16_basename==NULL) {
+ g_free (utf8_basename);
+ g_free (utf8_filename);
+ goto retry;
+ }
+ ret = TRUE;
+
+ /* utf16 is 2 * utf8 */
+ bytes *= 2;
+
+ memset (find_data->cFileName, '\0', (MAX_PATH*2));
+
+ /* Truncating a utf16 string like this might leave the last
+ * gchar incomplete
+ */
+ memcpy (find_data->cFileName, utf16_basename,
+ bytes<(MAX_PATH*2)-2?bytes:(MAX_PATH*2)-2);
+
+ find_data->cAlternateFileName [0] = 0; /* not used */
+
+ g_free (utf8_basename);
+ g_free (utf8_filename);
+ g_free (utf16_basename);
+
+cleanup:
+ mono_w32handle_unlock_handle (handle);
+
+ return(ret);
+}
+
+gboolean
+mono_w32file_find_close (gpointer handle)
+{
+ MonoW32HandleFind *find_handle;
+ gboolean ok;
+
+ if (handle == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FIND,
+ (gpointer *)&find_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up find handle %p", __func__,
+ handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ mono_w32handle_lock_handle (handle);
+
+ g_strfreev (find_handle->namelist);
+ g_free (find_handle->dir_part);
+
+ mono_w32handle_unlock_handle (handle);
+
+ mono_w32handle_unref (handle);
+
+ return(TRUE);
+}
+
+gboolean
+mono_w32file_create_directory (const gunichar2 *name)
+{
+ gchar *utf8_name;
+ gint result;
+
+ if (name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_name = mono_unicode_to_external (name);
+ if (utf8_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return FALSE;
+ }
+
+ result = _wapi_mkdir (utf8_name, 0777);
+
+ if (result == 0) {
+ g_free (utf8_name);
+ return TRUE;
+ }
+
+ _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+ g_free (utf8_name);
+ return FALSE;
+}
+
+gboolean
+mono_w32file_remove_directory (const gunichar2 *name)
+{
+ gchar *utf8_name;
+ gint result;
+
+ if (name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_name = mono_unicode_to_external (name);
+ if (utf8_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return FALSE;
+ }
+
+ result = _wapi_rmdir (utf8_name);
+ if (result == -1) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+ g_free (utf8_name);
+
+ return(FALSE);
+ }
+ g_free (utf8_name);
+
+ return(TRUE);
+}
+
+guint32
+mono_w32file_get_attributes (const gunichar2 *name)
+{
+ gchar *utf8_name;
+ struct stat buf, linkbuf;
+ gint result;
+ guint32 ret;
+
+ if (name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_name = mono_unicode_to_external (name);
+ if (utf8_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return (INVALID_FILE_ATTRIBUTES);
+ }
+
+ result = _wapi_stat (utf8_name, &buf);
+ if (result == -1 && errno == ENOENT) {
+ /* Might be a dangling symlink... */
+ result = _wapi_lstat (utf8_name, &buf);
+ }
+
+ if (result != 0) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+ g_free (utf8_name);
+ return (INVALID_FILE_ATTRIBUTES);
+ }
+
+#ifndef __native_client__
+ result = _wapi_lstat (utf8_name, &linkbuf);
+ if (result != 0) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+ g_free (utf8_name);
+ return (INVALID_FILE_ATTRIBUTES);
+ }
+#endif
+
+#ifdef __native_client__
+ ret = _wapi_stat_to_file_attributes (utf8_name, &buf, NULL);
+#else
+ ret = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf);
+#endif
+
+ g_free (utf8_name);
+
+ return(ret);
+}
+
+gboolean
+mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat)
+{
+ gchar *utf8_name;
+
+ struct stat buf, linkbuf;
+ gint result;
+
+ if (name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_name = mono_unicode_to_external (name);
+ if (utf8_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ result = _wapi_stat (utf8_name, &buf);
+ if (result == -1 && errno == ENOENT) {
+ /* Might be a dangling symlink... */
+ result = _wapi_lstat (utf8_name, &buf);
+ }
+
+ if (result != 0) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+ g_free (utf8_name);
+ return FALSE;
+ }
+
+ result = _wapi_lstat (utf8_name, &linkbuf);
+ if (result != 0) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+ g_free (utf8_name);
+ return(FALSE);
+ }
+
+ /* fill stat block */
+
+ stat->attributes = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf);
+ stat->creation_time = (((guint64) (buf.st_mtime < buf.st_ctime ? buf.st_mtime : buf.st_ctime)) * 10 * 1000 * 1000) + 116444736000000000ULL;
+ stat->last_access_time = (((guint64) (buf.st_atime)) * 10 * 1000 * 1000) + 116444736000000000ULL;
+ stat->last_write_time = (((guint64) (buf.st_mtime)) * 10 * 1000 * 1000) + 116444736000000000ULL;
+ stat->length = (stat->attributes & FILE_ATTRIBUTE_DIRECTORY) ? 0 : buf.st_size;
+
+ g_free (utf8_name);
+ return TRUE;
+}
+
+gboolean
+mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
+{
+ /* FIXME: think of something clever to do on unix */
+ gchar *utf8_name;
+ struct stat buf;
+ gint result;
+
+ /*
+ * Currently we only handle one *internal* case, with a value that is
+ * not standard: 0x80000000, which means `set executable bit'
+ */
+
+ if (name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+
+ utf8_name = mono_unicode_to_external (name);
+ if (utf8_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return FALSE;
+ }
+
+ result = _wapi_stat (utf8_name, &buf);
+ if (result == -1 && errno == ENOENT) {
+ /* Might be a dangling symlink... */
+ result = _wapi_lstat (utf8_name, &buf);
+ }
+
+ if (result != 0) {
+ _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+ g_free (utf8_name);
+ return FALSE;
+ }
+
+ /* Contrary to the documentation, ms allows NORMAL to be
+ * specified along with other attributes, so dont bother to
+ * catch that case here.
+ */
+ if (attrs & FILE_ATTRIBUTE_READONLY) {
+ result = _wapi_chmod (utf8_name, buf.st_mode & ~(S_IWUSR | S_IWOTH | S_IWGRP));
+ } else {
+ result = _wapi_chmod (utf8_name, buf.st_mode | S_IWUSR);
+ }
+
+ /* Ignore the other attributes for now */
+
+ if (attrs & 0x80000000){
+ mode_t exec_mask = 0;
+
+ if ((buf.st_mode & S_IRUSR) != 0)
+ exec_mask |= S_IXUSR;
+
+ if ((buf.st_mode & S_IRGRP) != 0)
+ exec_mask |= S_IXGRP;
+
+ if ((buf.st_mode & S_IROTH) != 0)
+ exec_mask |= S_IXOTH;
+
+ result = chmod (utf8_name, buf.st_mode | exec_mask);
+ }
+ /* Don't bother to reset executable (might need to change this
+ * policy)
+ */
+
+ g_free (utf8_name);
+
+ return(TRUE);
+}
+
+guint32
+mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
+{
+ gunichar2 *utf16_path;
+ glong count;
+ gsize bytes;
+
+#ifdef __native_client__
+ gchar *path = g_get_current_dir ();
+ if (length < strlen(path) + 1 || path == NULL)
+ return 0;
+ memcpy (buffer, path, strlen(path) + 1);
+#else
+ if (getcwd ((gchar*)buffer, length) == NULL) {
+ if (errno == ERANGE) { /*buffer length is not big enough */
+ gchar *path = g_get_current_dir (); /*FIXME g_get_current_dir doesn't work with broken paths and calling it just to know the path length is silly*/
+ if (path == NULL)
+ return 0;
+ utf16_path = mono_unicode_from_external (path, &bytes);
+ g_free (utf16_path);
+ g_free (path);
+ return (bytes/2)+1;
+ }
+ _wapi_set_last_error_from_errno ();
+ return 0;
+ }
+#endif
+
+ utf16_path = mono_unicode_from_external ((gchar*)buffer, &bytes);
+ count = (bytes/2)+1;
+ g_assert (count <= length); /*getcwd must have failed before with ERANGE*/
+
+ /* Add the terminator */
+ memset (buffer, '\0', bytes+2);
+ memcpy (buffer, utf16_path, bytes);
+
+ g_free (utf16_path);
+
+ return count;
+}
+
+gboolean
+mono_w32file_set_cwd (const gunichar2 *path)
+{
+ gchar *utf8_path;
+ gboolean result;
+
+ if (path == NULL) {
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
+ utf8_path = mono_unicode_to_external (path);
+ if (_wapi_chdir (utf8_path) != 0) {
+ _wapi_set_last_error_from_errno ();
+ result = FALSE;
+ }
+ else
+ result = TRUE;
+
+ g_free (utf8_path);
+ return result;
+}
+
+gboolean
+mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
+{
+ MonoW32HandleFile pipe_read_handle = {0};
+ MonoW32HandleFile pipe_write_handle = {0};
+ gpointer read_handle;
+ gpointer write_handle;
+ gint filedes[2];
+ gint ret;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating pipe", __func__);
+
+ ret=pipe (filedes);
+ if(ret==-1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error creating pipe: %s", __func__,
+ strerror (errno));
+
+ _wapi_set_last_error_from_errno ();
+ return(FALSE);
+ }
+
+ if (filedes[0] >= mono_w32handle_fd_reserve ||
+ filedes[1] >= mono_w32handle_fd_reserve) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
+
+ SetLastError (ERROR_TOO_MANY_OPEN_FILES);
+
+ close (filedes[0]);
+ close (filedes[1]);
+
+ return(FALSE);
+ }
+
+ /* filedes[0] is open for reading, filedes[1] for writing */
+
+ pipe_read_handle.fd = filedes [0];
+ pipe_read_handle.fileaccess = GENERIC_READ;
+ read_handle = mono_w32handle_new_fd (MONO_W32HANDLE_PIPE, filedes[0],
+ &pipe_read_handle);
+ if (read_handle == INVALID_HANDLE_VALUE) {
+ g_warning ("%s: error creating pipe read handle", __func__);
+ close (filedes[0]);
+ close (filedes[1]);
+ SetLastError (ERROR_GEN_FAILURE);
+
+ return(FALSE);
+ }
+
+ pipe_write_handle.fd = filedes [1];
+ pipe_write_handle.fileaccess = GENERIC_WRITE;
+ write_handle = mono_w32handle_new_fd (MONO_W32HANDLE_PIPE, filedes[1],
+ &pipe_write_handle);
+ if (write_handle == INVALID_HANDLE_VALUE) {
+ g_warning ("%s: error creating pipe write handle", __func__);
+ mono_w32handle_unref (read_handle);
+
+ close (filedes[0]);
+ close (filedes[1]);
+ SetLastError (ERROR_GEN_FAILURE);
+
+ return(FALSE);
+ }
+
+ *readpipe = read_handle;
+ *writepipe = write_handle;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning pipe: read handle %p, write handle %p",
+ __func__, read_handle, write_handle);
+
+ return(TRUE);
+}
+
+#ifdef HAVE_GETFSSTAT
+/* Darwin has getfsstat */
+gint32
+mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
+{
+ struct statfs *stats;
+ gint size, n, i;
+ gunichar2 *dir;
+ glong length, total = 0;
+
+ n = getfsstat (NULL, 0, MNT_NOWAIT);
+ if (n == -1)
+ return 0;
+ size = n * sizeof (struct statfs);
+ stats = (struct statfs *) g_malloc (size);
+ if (stats == NULL)
+ return 0;
+ if (getfsstat (stats, size, MNT_NOWAIT) == -1){
+ g_free (stats);
+ return 0;
+ }
+ for (i = 0; i < n; i++){
+ dir = g_utf8_to_utf16 (stats [i].f_mntonname, -1, NULL, &length, NULL);
+ if (total + length < len){
+ memcpy (buf + total, dir, sizeof (gunichar2) * length);
+ buf [total+length] = 0;
+ }
+ g_free (dir);
+ total += length + 1;
+ }
+ if (total < len)
+ buf [total] = 0;
+ total++;
+ g_free (stats);
+ return total;
+}
+#else
+/* In-place octal sequence replacement */
+static void
+unescape_octal (gchar *str)
+{
+ gchar *rptr;
+ gchar *wptr;
+
+ if (str == NULL)
+ return;
+
+ rptr = wptr = str;
+ while (*rptr != '\0') {
+ if (*rptr == '\\') {
+ gchar c;
+ rptr++;
+ c = (*(rptr++) - '0') << 6;
+ c += (*(rptr++) - '0') << 3;
+ c += *(rptr++) - '0';
+ *wptr++ = c;
+ } else if (wptr != rptr) {
+ *wptr++ = *rptr++;
+ } else {
+ rptr++; wptr++;
+ }
+ }
+ *wptr = '\0';
+}
+static gint32 GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf);
+
+#if __linux__
+#define GET_LOGICAL_DRIVE_STRINGS_BUFFER 512
+#define GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER 512
+#define GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER 64
+
+typedef struct
+{
+ glong total;
+ guint32 buffer_index;
+ guint32 mountpoint_index;
+ guint32 field_number;
+ guint32 allocated_size;
+ guint32 fsname_index;
+ guint32 fstype_index;
+ gchar mountpoint [GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER + 1];
+ gchar *mountpoint_allocated;
+ gchar buffer [GET_LOGICAL_DRIVE_STRINGS_BUFFER];
+ gchar fsname [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1];
+ gchar fstype [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1];
+ ssize_t nbytes;
+ gchar delimiter;
+ gboolean check_mount_source;
+} LinuxMountInfoParseState;
+
+static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+static void append_to_mountpoint (LinuxMountInfoParseState *state);
+static gboolean add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+
+gint32
+mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
+{
+ gint fd;
+ gint32 ret = 0;
+ LinuxMountInfoParseState state;
+ gboolean (*parser)(guint32, gunichar2*, LinuxMountInfoParseState*) = NULL;
+
+ memset (buf, 0, len * sizeof (gunichar2));
+ fd = open ("/proc/self/mountinfo", O_RDONLY);
+ if (fd != -1)
+ parser = GetLogicalDriveStrings_MountInfo;
+ else {
+ fd = open ("/proc/mounts", O_RDONLY);
+ if (fd != -1)
+ parser = GetLogicalDriveStrings_Mounts;
+ }
+
+ if (!parser) {
+ ret = GetLogicalDriveStrings_Mtab (len, buf);
+ goto done_and_out;
+ }
+
+ memset (&state, 0, sizeof (LinuxMountInfoParseState));
+ state.field_number = 1;
+ state.delimiter = ' ';
+
+ while ((state.nbytes = read (fd, state.buffer, GET_LOGICAL_DRIVE_STRINGS_BUFFER)) > 0) {
+ state.buffer_index = 0;
+
+ while ((*parser)(len, buf, &state)) {
+ if (state.buffer [state.buffer_index] == '\n') {
+ gboolean quit = add_drive_string (len, buf, &state);
+ state.field_number = 1;
+ state.buffer_index++;
+ if (state.mountpoint_allocated) {
+ g_free (state.mountpoint_allocated);
+ state.mountpoint_allocated = NULL;
+ }
+ if (quit) {
+ ret = state.total;
+ goto done_and_out;
+ }
+ }
+ }
+ };
+ ret = state.total;
+
+ done_and_out:
+ if (fd != -1)
+ close (fd);
+ return ret;
+}
+
+static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+ gchar *ptr;
+
+ if (state->field_number == 1)
+ state->check_mount_source = TRUE;
+
+ while (state->buffer_index < (guint32)state->nbytes) {
+ if (state->buffer [state->buffer_index] == state->delimiter) {
+ state->field_number++;
+ switch (state->field_number) {
+ case 2:
+ state->mountpoint_index = 0;
+ break;
+
+ case 3:
+ if (state->mountpoint_allocated)
+ state->mountpoint_allocated [state->mountpoint_index] = 0;
+ else
+ state->mountpoint [state->mountpoint_index] = 0;
+ break;
+
+ default:
+ ptr = (gchar*)memchr (state->buffer + state->buffer_index, '\n', GET_LOGICAL_DRIVE_STRINGS_BUFFER - state->buffer_index);
+ if (ptr)
+ state->buffer_index = (ptr - (gchar*)state->buffer) - 1;
+ else
+ state->buffer_index = state->nbytes;
+ return TRUE;
+ }
+ state->buffer_index++;
+ continue;
+ } else if (state->buffer [state->buffer_index] == '\n')
+ return TRUE;
+
+ switch (state->field_number) {
+ case 1:
+ if (state->check_mount_source) {
+ if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') {
+ /* We can ignore the rest, it's a device
+ * path */
+ state->check_mount_source = FALSE;
+ state->fsname [state->fsname_index++] = '/';
+ break;
+ }
+ if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+ state->fsname [state->fsname_index++] = state->buffer [state->buffer_index];
+ }
+ break;
+
+ case 2:
+ append_to_mountpoint (state);
+ break;
+
+ case 3:
+ if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+ state->fstype [state->fstype_index++] = state->buffer [state->buffer_index];
+ break;
+ }
+
+ state->buffer_index++;
+ }
+
+ return FALSE;
+}
+
+static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+ while (state->buffer_index < (guint32)state->nbytes) {
+ if (state->buffer [state->buffer_index] == state->delimiter) {
+ state->field_number++;
+ switch (state->field_number) {
+ case 5:
+ state->mountpoint_index = 0;
+ break;
+
+ case 6:
+ if (state->mountpoint_allocated)
+ state->mountpoint_allocated [state->mountpoint_index] = 0;
+ else
+ state->mountpoint [state->mountpoint_index] = 0;
+ break;
+
+ case 7:
+ state->delimiter = '-';
+ break;
+
+ case 8:
+ state->delimiter = ' ';
+ break;
+
+ case 10:
+ state->check_mount_source = TRUE;
+ break;
+ }
+ state->buffer_index++;
+ continue;
+ } else if (state->buffer [state->buffer_index] == '\n')
+ return TRUE;
+
+ switch (state->field_number) {
+ case 5:
+ append_to_mountpoint (state);
+ break;
+
+ case 9:
+ if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+ state->fstype [state->fstype_index++] = state->buffer [state->buffer_index];
+ break;
+
+ case 10:
+ if (state->check_mount_source) {
+ if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') {
+ /* We can ignore the rest, it's a device
+ * path */
+ state->check_mount_source = FALSE;
+ state->fsname [state->fsname_index++] = '/';
+ break;
+ }
+ if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+ state->fsname [state->fsname_index++] = state->buffer [state->buffer_index];
+ }
+ break;
+ }
+
+ state->buffer_index++;
+ }
+
+ return FALSE;
+}
+
+static void
+append_to_mountpoint (LinuxMountInfoParseState *state)
+{
+ gchar ch = state->buffer [state->buffer_index];
+ if (state->mountpoint_allocated) {
+ if (state->mountpoint_index >= state->allocated_size) {
+ guint32 newsize = (state->allocated_size << 1) + 1;
+ gchar *newbuf = (gchar *)g_malloc0 (newsize * sizeof (gchar));
+
+ memcpy (newbuf, state->mountpoint_allocated, state->mountpoint_index);
+ g_free (state->mountpoint_allocated);
+ state->mountpoint_allocated = newbuf;
+ state->allocated_size = newsize;
+ }
+ state->mountpoint_allocated [state->mountpoint_index++] = ch;
+ } else {
+ if (state->mountpoint_index >= GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER) {
+ state->allocated_size = (state->mountpoint_index << 1) + 1;
+ state->mountpoint_allocated = (gchar *)g_malloc0 (state->allocated_size * sizeof (gchar));
+ memcpy (state->mountpoint_allocated, state->mountpoint, state->mountpoint_index);
+ state->mountpoint_allocated [state->mountpoint_index++] = ch;
+ } else
+ state->mountpoint [state->mountpoint_index++] = ch;
+ }
+}
+
+static gboolean
+add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+ gboolean quit = FALSE;
+ gboolean ignore_entry;
+
+ if (state->fsname_index == 1 && state->fsname [0] == '/')
+ ignore_entry = FALSE;
+ else if (memcmp ("overlay", state->fsname, state->fsname_index) == 0 ||
+ memcmp ("aufs", state->fstype, state->fstype_index) == 0) {
+ /* Don't ignore overlayfs and aufs - these might be used on Docker
+ * (https://bugzilla.xamarin.com/show_bug.cgi?id=31021) */
+ ignore_entry = FALSE;
+ } else if (state->fsname_index == 0 || memcmp ("none", state->fsname, state->fsname_index) == 0) {
+ ignore_entry = TRUE;
+ } else if (state->fstype_index >= 5 && memcmp ("fuse.", state->fstype, 5) == 0) {
+ /* Ignore GNOME's gvfs */
+ if (state->fstype_index == 21 && memcmp ("fuse.gvfs-fuse-daemon", state->fstype, state->fstype_index) == 0)
+ ignore_entry = TRUE;
+ else
+ ignore_entry = FALSE;
+ } else if (state->fstype_index == 3 && memcmp ("nfs", state->fstype, state->fstype_index) == 0)
+ ignore_entry = FALSE;
+ else
+ ignore_entry = TRUE;
+
+ if (!ignore_entry) {
+ gunichar2 *dir;
+ glong length;
+ gchar *mountpoint = state->mountpoint_allocated ? state->mountpoint_allocated : state->mountpoint;
+
+ unescape_octal (mountpoint);
+ dir = g_utf8_to_utf16 (mountpoint, -1, NULL, &length, NULL);
+ if (state->total + length + 1 > len) {
+ quit = TRUE;
+ state->total = len * 2;
+ } else {
+ length++;
+ memcpy (buf + state->total, dir, sizeof (gunichar2) * length);
+ state->total += length;
+ }
+ g_free (dir);
+ }
+ state->fsname_index = 0;
+ state->fstype_index = 0;
+
+ return quit;
+}
+#else
+gint32
+mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
+{
+ return GetLogicalDriveStrings_Mtab (len, buf);
+}
+#endif
+static gint32
+GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
+{
+ FILE *fp;
+ gunichar2 *ptr, *dir;
+ glong length, total = 0;
+ gchar buffer [512];
+ gchar **splitted;
+
+ memset (buf, 0, sizeof (gunichar2) * (len + 1));
+ buf [0] = '/';
+ buf [1] = 0;
+ buf [2] = 0;
+
+ /* Sigh, mntent and friends don't work well.
+ * It stops on the first line that doesn't begin with a '/'.
+ * (linux 2.6.5, libc 2.3.2.ds1-12) - Gonz */
+ fp = fopen ("/etc/mtab", "rt");
+ if (fp == NULL) {
+ fp = fopen ("/etc/mnttab", "rt");
+ if (fp == NULL)
+ return 1;
+ }
+
+ ptr = buf;
+ while (fgets (buffer, 512, fp) != NULL) {
+ if (*buffer != '/')
+ continue;
+
+ splitted = g_strsplit (buffer, " ", 0);
+ if (!*splitted || !*(splitted + 1)) {
+ g_strfreev (splitted);
+ continue;
+ }
+
+ unescape_octal (*(splitted + 1));
+ dir = g_utf8_to_utf16 (*(splitted + 1), -1, NULL, &length, NULL);
+ g_strfreev (splitted);
+ if (total + length + 1 > len) {
+ fclose (fp);
+ g_free (dir);
+ return len * 2; /* guess */
+ }
+
+ memcpy (ptr + total, dir, sizeof (gunichar2) * length);
+ g_free (dir);
+ total += length + 1;
+ }
+
+ fclose (fp);
+ return total;
+/* Commented out, does not work with my mtab!!! - Gonz */
+#ifdef NOTENABLED /* HAVE_MNTENT_H */
+{
+ FILE *fp;
+ struct mntent *mnt;
+ gunichar2 *ptr, *dir;
+ glong len, total = 0;
+
+
+ fp = setmntent ("/etc/mtab", "rt");
+ if (fp == NULL) {
+ fp = setmntent ("/etc/mnttab", "rt");
+ if (fp == NULL)
+ return;
+ }
+
+ ptr = buf;
+ while ((mnt = getmntent (fp)) != NULL) {
+ g_print ("GOT %s\n", mnt->mnt_dir);
+ dir = g_utf8_to_utf16 (mnt->mnt_dir, &len, NULL, NULL, NULL);
+ if (total + len + 1 > len) {
+ return len * 2; /* guess */
+ }
+
+ memcpy (ptr + total, dir, sizeof (gunichar2) * len);
+ g_free (dir);
+ total += len + 1;
+ }
+
+ endmntent (fp);
+ return total;
+}
+#endif
+}
+#endif
+
+#if defined(HAVE_STATVFS) || defined(HAVE_STATFS)
+gboolean
+mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes)
+{
+#ifdef HAVE_STATVFS
+ struct statvfs fsstat;
+#elif defined(HAVE_STATFS)
+ struct statfs fsstat;
+#endif
+ gboolean isreadonly;
+ gchar *utf8_path_name;
+ gint ret;
+ unsigned long block_size;
+
+ if (path_name == NULL) {
+ utf8_path_name = g_strdup (g_get_current_dir());
+ if (utf8_path_name == NULL) {
+ SetLastError (ERROR_DIRECTORY);
+ return(FALSE);
+ }
+ }
+ else {
+ utf8_path_name = mono_unicode_to_external (path_name);
+ if (utf8_path_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+
+ SetLastError (ERROR_INVALID_NAME);
+ return(FALSE);
+ }
+ }
+
+ do {
+#ifdef HAVE_STATVFS
+ ret = statvfs (utf8_path_name, &fsstat);
+ isreadonly = ((fsstat.f_flag & ST_RDONLY) == ST_RDONLY);
+ block_size = fsstat.f_frsize;
+#elif defined(HAVE_STATFS)
+ ret = statfs (utf8_path_name, &fsstat);
+#if defined (MNT_RDONLY)
+ isreadonly = ((fsstat.f_flags & MNT_RDONLY) == MNT_RDONLY);
+#elif defined (MS_RDONLY)
+ isreadonly = ((fsstat.f_flags & MS_RDONLY) == MS_RDONLY);
+#endif
+ block_size = fsstat.f_bsize;
+#endif
+ } while(ret == -1 && errno == EINTR);
+
+ g_free(utf8_path_name);
+
+ if (ret == -1) {
+ _wapi_set_last_error_from_errno ();
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: statvfs failed: %s", __func__, strerror (errno));
+ return(FALSE);
+ }
+
+ /* total number of free bytes for non-root */
+ if (free_bytes_avail != NULL) {
+ if (isreadonly) {
+ *free_bytes_avail = 0;
+ }
+ else {
+ *free_bytes_avail = block_size * (guint64)fsstat.f_bavail;
+ }
+ }
+
+ /* total number of bytes available for non-root */
+ if (total_number_of_bytes != NULL) {
+ *total_number_of_bytes = block_size * (guint64)fsstat.f_blocks;
+ }
+
+ /* total number of bytes available for root */
+ if (total_number_of_free_bytes != NULL) {
+ if (isreadonly) {
+ *total_number_of_free_bytes = 0;
+ }
+ else {
+ *total_number_of_free_bytes = block_size * (guint64)fsstat.f_bfree;
+ }
+ }
+
+ return(TRUE);
+}
+#else
+gboolean
+mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes)
+{
+ if (free_bytes_avail != NULL) {
+ *free_bytes_avail = (guint64) -1;
+ }
+
+ if (total_number_of_bytes != NULL) {
+ *total_number_of_bytes = (guint64) -1;
+ }
+
+ if (total_number_of_free_bytes != NULL) {
+ *total_number_of_free_bytes = (guint64) -1;
+ }
+
+ return(TRUE);
+}
+#endif
+
+/*
+ * General Unix support
+ */
+typedef struct {
+ guint32 drive_type;
+#if __linux__
+ const long fstypeid;
+#endif
+ const gchar* fstype;
+} _wapi_drive_type;
+
+static _wapi_drive_type _wapi_drive_types[] = {
+#if PLATFORM_MACOSX
+ { DRIVE_REMOTE, "afp" },
+ { DRIVE_REMOTE, "autofs" },
+ { DRIVE_CDROM, "cddafs" },
+ { DRIVE_CDROM, "cd9660" },
+ { DRIVE_RAMDISK, "devfs" },
+ { DRIVE_FIXED, "exfat" },
+ { DRIVE_RAMDISK, "fdesc" },
+ { DRIVE_REMOTE, "ftp" },
+ { DRIVE_FIXED, "hfs" },
+ { DRIVE_FIXED, "msdos" },
+ { DRIVE_REMOTE, "nfs" },
+ { DRIVE_FIXED, "ntfs" },
+ { DRIVE_REMOTE, "smbfs" },
+ { DRIVE_FIXED, "udf" },
+ { DRIVE_REMOTE, "webdav" },
+ { DRIVE_UNKNOWN, NULL }
+#elif __linux__
+ { DRIVE_FIXED, ADFS_SUPER_MAGIC, "adfs"},
+ { DRIVE_FIXED, AFFS_SUPER_MAGIC, "affs"},
+ { DRIVE_REMOTE, AFS_SUPER_MAGIC, "afs"},
+ { DRIVE_RAMDISK, AUTOFS_SUPER_MAGIC, "autofs"},
+ { DRIVE_RAMDISK, AUTOFS_SBI_MAGIC, "autofs4"},
+ { DRIVE_REMOTE, CODA_SUPER_MAGIC, "coda" },
+ { DRIVE_RAMDISK, CRAMFS_MAGIC, "cramfs"},
+ { DRIVE_RAMDISK, CRAMFS_MAGIC_WEND, "cramfs"},
+ { DRIVE_REMOTE, CIFS_MAGIC_NUMBER, "cifs"},
+ { DRIVE_RAMDISK, DEBUGFS_MAGIC, "debugfs"},
+ { DRIVE_RAMDISK, SYSFS_MAGIC, "sysfs"},
+ { DRIVE_RAMDISK, SECURITYFS_MAGIC, "securityfs"},
+ { DRIVE_RAMDISK, SELINUX_MAGIC, "selinuxfs"},
+ { DRIVE_RAMDISK, RAMFS_MAGIC, "ramfs"},
+ { DRIVE_FIXED, SQUASHFS_MAGIC, "squashfs"},
+ { DRIVE_FIXED, EFS_SUPER_MAGIC, "efs"},
+ { DRIVE_FIXED, EXT2_SUPER_MAGIC, "ext"},
+ { DRIVE_FIXED, EXT3_SUPER_MAGIC, "ext"},
+ { DRIVE_FIXED, EXT4_SUPER_MAGIC, "ext"},
+ { DRIVE_REMOTE, XENFS_SUPER_MAGIC, "xenfs"},
+ { DRIVE_FIXED, BTRFS_SUPER_MAGIC, "btrfs"},
+ { DRIVE_FIXED, HFS_SUPER_MAGIC, "hfs"},
+ { DRIVE_FIXED, HFSPLUS_SUPER_MAGIC, "hfsplus"},
+ { DRIVE_FIXED, HPFS_SUPER_MAGIC, "hpfs"},
+ { DRIVE_RAMDISK, HUGETLBFS_MAGIC, "hugetlbfs"},
+ { DRIVE_CDROM, ISOFS_SUPER_MAGIC, "iso"},
+ { DRIVE_FIXED, JFFS2_SUPER_MAGIC, "jffs2"},
+ { DRIVE_RAMDISK, ANON_INODE_FS_MAGIC, "anon_inode"},
+ { DRIVE_FIXED, JFS_SUPER_MAGIC, "jfs"},
+ { DRIVE_FIXED, MINIX_SUPER_MAGIC, "minix"},
+ { DRIVE_FIXED, MINIX_SUPER_MAGIC2, "minix v2"},
+ { DRIVE_FIXED, MINIX2_SUPER_MAGIC, "minix2"},
+ { DRIVE_FIXED, MINIX2_SUPER_MAGIC2, "minix2 v2"},
+ { DRIVE_FIXED, MINIX3_SUPER_MAGIC, "minix3"},
+ { DRIVE_FIXED, MSDOS_SUPER_MAGIC, "msdos"},
+ { DRIVE_REMOTE, NCP_SUPER_MAGIC, "ncp"},
+ { DRIVE_REMOTE, NFS_SUPER_MAGIC, "nfs"},
+ { DRIVE_FIXED, NTFS_SB_MAGIC, "ntfs"},
+ { DRIVE_RAMDISK, OPENPROM_SUPER_MAGIC, "openpromfs"},
+ { DRIVE_RAMDISK, PROC_SUPER_MAGIC, "proc"},
+ { DRIVE_FIXED, QNX4_SUPER_MAGIC, "qnx4"},
+ { DRIVE_FIXED, REISERFS_SUPER_MAGIC, "reiserfs"},
+ { DRIVE_RAMDISK, ROMFS_MAGIC, "romfs"},
+ { DRIVE_REMOTE, SMB_SUPER_MAGIC, "samba"},
+ { DRIVE_RAMDISK, CGROUP_SUPER_MAGIC, "cgroupfs"},
+ { DRIVE_RAMDISK, FUTEXFS_SUPER_MAGIC, "futexfs"},
+ { DRIVE_FIXED, SYSV2_SUPER_MAGIC, "sysv2"},
+ { DRIVE_FIXED, SYSV4_SUPER_MAGIC, "sysv4"},
+ { DRIVE_RAMDISK, TMPFS_MAGIC, "tmpfs"},
+ { DRIVE_RAMDISK, DEVPTS_SUPER_MAGIC, "devpts"},
+ { DRIVE_CDROM, UDF_SUPER_MAGIC, "udf"},
+ { DRIVE_FIXED, UFS_MAGIC, "ufs"},
+ { DRIVE_FIXED, UFS_MAGIC_BW, "ufs"},
+ { DRIVE_FIXED, UFS2_MAGIC, "ufs2"},
+ { DRIVE_FIXED, UFS_CIGAM, "ufs"},
+ { DRIVE_RAMDISK, USBDEVICE_SUPER_MAGIC, "usbdev"},
+ { DRIVE_FIXED, XENIX_SUPER_MAGIC, "xenix"},
+ { DRIVE_FIXED, XFS_SB_MAGIC, "xfs"},
+ { DRIVE_RAMDISK, FUSE_SUPER_MAGIC, "fuse"},
+ { DRIVE_FIXED, V9FS_MAGIC, "9p"},
+ { DRIVE_REMOTE, CEPH_SUPER_MAGIC, "ceph"},
+ { DRIVE_RAMDISK, CONFIGFS_MAGIC, "configfs"},
+ { DRIVE_RAMDISK, ECRYPTFS_SUPER_MAGIC, "eCryptfs"},
+ { DRIVE_FIXED, EXOFS_SUPER_MAGIC, "exofs"},
+ { DRIVE_FIXED, VXFS_SUPER_MAGIC, "vxfs"},
+ { DRIVE_FIXED, VXFS_OLT_MAGIC, "vxfs_olt"},
+ { DRIVE_REMOTE, GFS2_MAGIC, "gfs2"},
+ { DRIVE_FIXED, LOGFS_MAGIC_U32, "logfs"},
+ { DRIVE_FIXED, OCFS2_SUPER_MAGIC, "ocfs2"},
+ { DRIVE_FIXED, OMFS_MAGIC, "omfs"},
+ { DRIVE_FIXED, UBIFS_SUPER_MAGIC, "ubifs"},
+ { DRIVE_UNKNOWN, 0, NULL}
+#else
+ { DRIVE_RAMDISK, "ramfs" },
+ { DRIVE_RAMDISK, "tmpfs" },
+ { DRIVE_RAMDISK, "proc" },
+ { DRIVE_RAMDISK, "sysfs" },
+ { DRIVE_RAMDISK, "debugfs" },
+ { DRIVE_RAMDISK, "devpts" },
+ { DRIVE_RAMDISK, "securityfs" },
+ { DRIVE_CDROM, "iso9660" },
+ { DRIVE_FIXED, "ext2" },
+ { DRIVE_FIXED, "ext3" },
+ { DRIVE_FIXED, "ext4" },
+ { DRIVE_FIXED, "sysv" },
+ { DRIVE_FIXED, "reiserfs" },
+ { DRIVE_FIXED, "ufs" },
+ { DRIVE_FIXED, "vfat" },
+ { DRIVE_FIXED, "msdos" },
+ { DRIVE_FIXED, "udf" },
+ { DRIVE_FIXED, "hfs" },
+ { DRIVE_FIXED, "hpfs" },
+ { DRIVE_FIXED, "qnx4" },
+ { DRIVE_FIXED, "ntfs" },
+ { DRIVE_FIXED, "ntfs-3g" },
+ { DRIVE_REMOTE, "smbfs" },
+ { DRIVE_REMOTE, "fuse" },
+ { DRIVE_REMOTE, "nfs" },
+ { DRIVE_REMOTE, "nfs4" },
+ { DRIVE_REMOTE, "cifs" },
+ { DRIVE_REMOTE, "ncpfs" },
+ { DRIVE_REMOTE, "coda" },
+ { DRIVE_REMOTE, "afs" },
+ { DRIVE_UNKNOWN, NULL }
+#endif
+};
+
+#if __linux__
+static guint32 _wapi_get_drive_type(long f_type)
+{
+ _wapi_drive_type *current;
+
+ current = &_wapi_drive_types[0];
+ while (current->drive_type != DRIVE_UNKNOWN) {
+ if (current->fstypeid == f_type)
+ return current->drive_type;
+ current++;
+ }
+
+ return DRIVE_UNKNOWN;
+}
+#else
+static guint32 _wapi_get_drive_type(const gchar* fstype)
+{
+ _wapi_drive_type *current;
+
+ current = &_wapi_drive_types[0];
+ while (current->drive_type != DRIVE_UNKNOWN) {
+ if (strcmp (current->fstype, fstype) == 0)
+ break;
+
+ current++;
+ }
+
+ return current->drive_type;
+}
+#endif
+
+#if defined (PLATFORM_MACOSX) || defined (__linux__)
+static guint32
+GetDriveTypeFromPath (const gchar *utf8_root_path_name)
+{
+ struct statfs buf;
+
+ if (statfs (utf8_root_path_name, &buf) == -1)
+ return DRIVE_UNKNOWN;
+#if PLATFORM_MACOSX
+ return _wapi_get_drive_type (buf.f_fstypename);
+#else
+ return _wapi_get_drive_type (buf.f_type);
+#endif
+}
+#else
+static guint32
+GetDriveTypeFromPath (const gchar *utf8_root_path_name)
+{
+ guint32 drive_type;
+ FILE *fp;
+ gchar buffer [512];
+ gchar **splitted;
+
+ fp = fopen ("/etc/mtab", "rt");
+ if (fp == NULL) {
+ fp = fopen ("/etc/mnttab", "rt");
+ if (fp == NULL)
+ return(DRIVE_UNKNOWN);
+ }
+
+ drive_type = DRIVE_NO_ROOT_DIR;
+ while (fgets (buffer, 512, fp) != NULL) {
+ splitted = g_strsplit (buffer, " ", 0);
+ if (!*splitted || !*(splitted + 1) || !*(splitted + 2)) {
+ g_strfreev (splitted);
+ continue;
+ }
+
+ /* compare given root_path_name with the one from mtab,
+ if length of utf8_root_path_name is zero it must be the root dir */
+ if (strcmp (*(splitted + 1), utf8_root_path_name) == 0 ||
+ (strcmp (*(splitted + 1), "/") == 0 && strlen (utf8_root_path_name) == 0)) {
+ drive_type = _wapi_get_drive_type (*(splitted + 2));
+ /* it is possible this path might be mounted again with
+ a known type...keep looking */
+ if (drive_type != DRIVE_UNKNOWN) {
+ g_strfreev (splitted);
+ break;
+ }
+ }
+
+ g_strfreev (splitted);
+ }
+
+ fclose (fp);
+ return drive_type;
+}
+#endif
+
+guint32
+mono_w32file_get_drive_type(const gunichar2 *root_path_name)
+{
+ gchar *utf8_root_path_name;
+ guint32 drive_type;
+
+ if (root_path_name == NULL) {
+ utf8_root_path_name = g_strdup (g_get_current_dir());
+ if (utf8_root_path_name == NULL) {
+ return(DRIVE_NO_ROOT_DIR);
+ }
+ }
+ else {
+ utf8_root_path_name = mono_unicode_to_external (root_path_name);
+ if (utf8_root_path_name == NULL) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
+ return(DRIVE_NO_ROOT_DIR);
+ }
+
+ /* strip trailing slash for compare below */
+ if (g_str_has_suffix(utf8_root_path_name, "/") && utf8_root_path_name [1] != 0) {
+ utf8_root_path_name[strlen(utf8_root_path_name) - 1] = 0;
+ }
+ }
+ drive_type = GetDriveTypeFromPath (utf8_root_path_name);
+ g_free (utf8_root_path_name);
+
+ return (drive_type);
+}
+
+#if defined (PLATFORM_MACOSX) || defined (__linux__) || defined(PLATFORM_BSD) || defined(__native_client__) || defined(__FreeBSD_kernel__)
+static gchar*
+get_fstypename (gchar *utfpath)
+{
+#if defined (PLATFORM_MACOSX) || defined (__linux__)
+ struct statfs stat;
+#if __linux__
+ _wapi_drive_type *current;
+#endif
+ if (statfs (utfpath, &stat) == -1)
+ return NULL;
+#if PLATFORM_MACOSX
+ return g_strdup (stat.f_fstypename);
+#else
+ current = &_wapi_drive_types[0];
+ while (current->drive_type != DRIVE_UNKNOWN) {
+ if (stat.f_type == current->fstypeid)
+ return g_strdup (current->fstype);
+ current++;
+ }
+ return NULL;
+#endif
+#else
+ return NULL;
+#endif
+}
+
+/* Linux has struct statfs which has a different layout */
+gboolean
+mono_w32file_get_volume_information (const gunichar2 *path, gunichar2 *volumename, gint volumesize, gint *outserial, gint *maxcomp, gint *fsflags, gunichar2 *fsbuffer, gint fsbuffersize)
+{
+ gchar *utfpath;
+ gchar *fstypename;
+ gboolean status = FALSE;
+ glong len;
+
+ // We only support getting the file system type
+ if (fsbuffer == NULL)
+ return 0;
+
+ utfpath = mono_unicode_to_external (path);
+ if ((fstypename = get_fstypename (utfpath)) != NULL){
+ gunichar2 *ret = g_utf8_to_utf16 (fstypename, -1, NULL, &len, NULL);
+ if (ret != NULL && len < fsbuffersize){
+ memcpy (fsbuffer, ret, len * sizeof (gunichar2));
+ fsbuffer [len] = 0;
+ status = TRUE;
+ }
+ if (ret != NULL)
+ g_free (ret);
+ g_free (fstypename);
+ }
+ g_free (utfpath);
+ return status;
+}
+#endif
+
+static gboolean
+LockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 length_low, guint32 length_high)
+{
+ MonoW32HandleFile *file_handle;
+ off_t offset, length;
+
+ if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE, (gpointer *)&file_handle)) {
+ g_warning ("%s: error looking up file handle %p", __func__, handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ if (!(file_handle->fileaccess & GENERIC_READ) && !(file_handle->fileaccess & GENERIC_WRITE) && !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
+ SetLastError (ERROR_ACCESS_DENIED);
+ return FALSE;
+ }
+
+#ifdef HAVE_LARGE_FILE_SUPPORT
+ offset = ((gint64)offset_high << 32) | offset_low;
+ length = ((gint64)length_high << 32) | length_low;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking handle %p, offset %lld, length %lld", __func__, handle, offset, length);
+#else
+ if (offset_high > 0 || length_high > 0) {
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ offset = offset_low;
+ length = length_low;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking handle %p, offset %ld, length %ld", __func__, handle, offset, length);
+#endif
+
+ return _wapi_lock_file_region (GPOINTER_TO_UINT(handle), offset, length);
+}
+
+static gboolean
+UnlockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 length_low, guint32 length_high)
+{
+ MonoW32HandleFile *file_handle;
+ off_t offset, length;
+
+ if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE, (gpointer *)&file_handle)) {
+ g_warning ("%s: error looking up file handle %p", __func__, handle);
+ SetLastError (ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ if (!(file_handle->fileaccess & GENERIC_READ) && !(file_handle->fileaccess & GENERIC_WRITE) && !(file_handle->fileaccess & GENERIC_ALL)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
+ SetLastError (ERROR_ACCESS_DENIED);
+ return FALSE;
+ }
+
+#ifdef HAVE_LARGE_FILE_SUPPORT
+ offset = ((gint64)offset_high << 32) | offset_low;
+ length = ((gint64)length_high << 32) | length_low;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking handle %p, offset %lld, length %lld", __func__, handle, offset, length);
+#else
+ offset = offset_low;
+ length = length_low;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking handle %p, offset %ld, length %ld", __func__, handle, offset, length);
+#endif
+
+ return _wapi_unlock_file_region (GPOINTER_TO_UINT(handle), offset, length);
+}
+
+void
+mono_w32file_init (void)
+{
+ mono_os_mutex_init (&stdhandle_mutex);
+ mono_os_mutex_init (&file_share_mutex);
+
+ mono_w32handle_register_ops (MONO_W32HANDLE_FILE, &_wapi_file_ops);
+ mono_w32handle_register_ops (MONO_W32HANDLE_CONSOLE, &_wapi_console_ops);
+ mono_w32handle_register_ops (MONO_W32HANDLE_FIND, &_wapi_find_ops);
+ mono_w32handle_register_ops (MONO_W32HANDLE_PIPE, &_wapi_pipe_ops);
+
+/* mono_w32handle_register_capabilities (MONO_W32HANDLE_FILE, */
+/* MONO_W32HANDLE_CAP_WAIT); */
+/* mono_w32handle_register_capabilities (MONO_W32HANDLE_CONSOLE, */
+/* MONO_W32HANDLE_CAP_WAIT); */
+
+ if (g_getenv ("MONO_STRICT_IO_EMULATION"))
+ lock_while_writing = TRUE;
+}
+
+void
+mono_w32file_cleanup (void)
+{
+ mono_os_mutex_destroy (&file_share_mutex);
+
+ if (file_share_table)
+ g_hash_table_destroy (file_share_table);
+}
+
+gboolean
+mono_w32file_move (gunichar2 *path, gunichar2 *dest, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = MoveFile (path, dest);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gboolean
+mono_w32file_copy (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = CopyFile (path, dest, !overwrite);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gboolean
+mono_w32file_replace (gunichar2 *destinationFileName, gunichar2 *sourceFileName, gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = ReplaceFile (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gint64
+mono_w32file_get_file_size (gpointer handle, gint32 *error)
+{
+ gint64 length;
+ guint32 length_hi;
+
+ MONO_ENTER_GC_SAFE;
+
+ length = GetFileSize (handle, &length_hi);
+ if(length==INVALID_FILE_SIZE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+
+ return length | ((gint64)length_hi << 32);
+}
+
+gboolean
+mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gboolean
+mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gpointer
+mono_w32file_get_console_input (void)
+{
+ gpointer handle;
+
+ MONO_ENTER_GC_SAFE;
+ handle = mono_w32file_get_std_handle (STD_INPUT_HANDLE);
+ MONO_EXIT_GC_SAFE;
+
+ return handle;
+}
+
+gpointer
+mono_w32file_get_console_output (void)
+{
+ gpointer handle;
+
+ MONO_ENTER_GC_SAFE;
+ handle = mono_w32file_get_std_handle (STD_OUTPUT_HANDLE);
+ MONO_EXIT_GC_SAFE;
+
+ return handle;
+}
+
+gpointer
+mono_w32file_get_console_error (void)
+{
+ gpointer handle;
+
+ MONO_ENTER_GC_SAFE;
+ handle = mono_w32file_get_std_handle (STD_ERROR_HANDLE);
+ MONO_EXIT_GC_SAFE;
+
+ return handle;
+}
--- /dev/null
+/*
+ * Copyright 2016 Microsoft
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#ifndef _MONO_METADATA_W32FILE_WIN32_INTERNALS_H_
+#define _MONO_METADATA_W32FILE_WIN32_INTERNALS_H_
+
+#include <config.h>
+#include <glib.h>
+
+#ifdef HOST_WIN32
+#include "mono/metadata/w32file.h"
+#include "mono/metadata/w32file-internals.h"
+#endif /* HOST_WIN32 */
+#endif /* _MONO_METADATA_W32FILE_WIN32_INTERNALS_H_ */
--- /dev/null
+/*
+ * w32file-win32-uwp.c: UWP w32file support for Mono.
+ *
+ * Copyright 2016 Microsoft
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+*/
+#include <config.h>
+#include <glib.h>
+#include "mono/utils/mono-compiler.h"
+
+#if G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT)
+#include <windows.h>
+#include "mono/metadata/w32file-win32-internals.h"
+
+gboolean
+mono_w32file_move (gunichar2 *path, gunichar2 *dest, gint32 *error)
+{
+ gboolean result = FALSE;
+ MONO_ENTER_GC_SAFE;
+
+ result = MoveFileEx (path, dest, MOVEFILE_COPY_ALLOWED);
+ if (result == FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return result;
+}
+
+gboolean
+mono_w32file_replace (gunichar2 *destinationFileName, gunichar2 *sourceFileName,
+ gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error)
+{
+ gboolean result = FALSE;
+ MONO_ENTER_GC_SAFE;
+
+ result = ReplaceFile (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
+ if (result == FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return result;
+}
+
+gboolean
+mono_w32file_copy (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32 *error)
+{
+ gboolean result = FALSE;
+ COPYFILE2_EXTENDED_PARAMETERS copy_param = {0};
+
+ copy_param.dwSize = sizeof (COPYFILE2_EXTENDED_PARAMETERS);
+ copy_param.dwCopyFlags = (!overwrite) ? COPY_FILE_FAIL_IF_EXISTS : 0;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = SUCCEEDED (CopyFile2 (path, dest, ©_param));
+ if (result == FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return result;
+}
+
+gint64
+mono_w32file_get_file_size (HANDLE handle, gint32 *error)
+{
+ LARGE_INTEGER length;
+
+ MONO_ENTER_GC_SAFE;
+
+ if (!GetFileSizeEx (handle, &length)) {
+ *error=GetLastError ();
+ length.QuadPart = INVALID_FILE_SIZE;
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return length.QuadPart;
+}
+
+gboolean
+mono_w32file_lock (HANDLE handle, gint64 position, gint64 length, gint32 *error)
+{
+ gboolean result = FALSE;
+ MONO_ENTER_GC_SAFE;
+
+ result = LockFile (handle, position & 0xFFFFFFFF, position >> 32,
+ length & 0xFFFFFFFF, length >> 32);
+
+ if (result == FALSE) {
+ *error = GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return result;
+}
+
+gboolean
+mono_w32file_unlock (HANDLE handle, gint64 position, gint64 length, gint32 *error)
+{
+ gboolean result = FALSE;
+ MONO_ENTER_GC_SAFE;
+
+ result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
+ length & 0xFFFFFFFF, length >> 32);
+
+ if (result == FALSE) {
+ *error = GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return result;
+}
+
+HANDLE
+mono_w32file_get_console_output (void)
+{
+ MonoError mono_error;
+ mono_error_init (&mono_error);
+
+ g_unsupported_api ("GetStdHandle (STD_OUTPUT_HANDLE)");
+
+ mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "GetStdHandle (STD_OUTPUT_HANDLE)");
+ mono_error_set_pending_exception (&mono_error);
+
+ SetLastError (ERROR_NOT_SUPPORTED);
+
+ return INVALID_HANDLE_VALUE;
+}
+
+HANDLE
+mono_w32file_get_console_input (void)
+{
+ MonoError mono_error;
+ mono_error_init (&mono_error);
+
+ g_unsupported_api ("GetStdHandle (STD_INPUT_HANDLE)");
+
+ mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "GetStdHandle (STD_INPUT_HANDLE)");
+ mono_error_set_pending_exception (&mono_error);
+
+ SetLastError (ERROR_NOT_SUPPORTED);
+
+ return INVALID_HANDLE_VALUE;
+}
+
+HANDLE
+mono_w32file_get_console_error (void)
+{
+ MonoError mono_error;
+ mono_error_init (&mono_error);
+
+ g_unsupported_api ("GetStdHandle (STD_ERROR_HANDLE)");
+
+ mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "GetStdHandle (STD_ERROR_HANDLE)");
+ mono_error_set_pending_exception (&mono_error);
+
+ SetLastError (ERROR_NOT_SUPPORTED);
+
+ return INVALID_HANDLE_VALUE;
+}
+
+#else /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */
+
+MONO_EMPTY_SOURCE_FILE (file_io_windows_uwp);
+#endif /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */
--- /dev/null
+/*
+ * w32file-win32.c: Windows File IO internal calls.
+ *
+ * Copyright 2016 Microsoft
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include <config.h>
+#include <glib.h>
+
+#include <winsock2.h>
+#include <windows.h>
+#include "mono/metadata/w32file-win32-internals.h"
+
+void
+mono_w32file_init (void)
+{
+}
+
+void
+mono_w32file_cleanup (void)
+{
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
+{
+ return (gunichar2) ':'; /* colon */
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
+{
+ return (gunichar2) '\\'; /* backslash */
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
+{
+ return (gunichar2) '/'; /* forward slash */
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_PathSeparator ()
+{
+ return (gunichar2) ';'; /* semicolon */
+}
+
+void ves_icall_System_IO_MonoIO_DumpHandles (void)
+{
+ return;
+}
+
+gpointer
+mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs)
+{
+ return CreateFile (name, fileaccess, sharemode, NULL, createmode, attrs, NULL);
+}
+
+gboolean
+mono_w32file_delete (const gunichar2 *name)
+{
+ return DeleteFile (name);
+}
+
+gboolean
+mono_w32file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread)
+{
+ return ReadFile (handle, buffer, numbytes, bytesread, NULL);
+}
+
+gboolean
+mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten)
+{
+ return WriteFile (handle, buffer, numbytes, byteswritten, NULL);
+}
+
+gboolean
+mono_w32file_flush (gpointer handle)
+{
+ return FlushFileBuffers (handle);
+}
+
+gboolean
+mono_w32file_truncate (gpointer handle)
+{
+ return SetEndOfFile (handle);
+}
+
+guint32
+mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method)
+{
+ return SetFilePointer (handle, movedistance, highmovedistance, method);
+}
+
+gint
+mono_w32file_get_type (gpointer handle)
+{
+ return GetFileType (handle);
+}
+
+gboolean
+mono_w32file_get_times (gpointer handle, FILETIME *create_time, FILETIME *access_time, FILETIME *write_time)
+{
+ return GetFileTime (handle, create_time, access_time, write_time);
+}
+
+gboolean
+mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time)
+{
+ return SetFileTime (handle, create_time, access_time, write_time);
+}
+
+gboolean
+mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time)
+{
+ return FileTimeToSystemTime (file_time, system_time);
+}
+
+gpointer
+mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
+{
+ return FindFirstFile (pattern, find_data);
+}
+
+gboolean
+mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data)
+{
+ return FindNextFile (handle, find_data);
+}
+
+gboolean
+mono_w32file_find_close (gpointer handle)
+{
+ return FindClose (handle);
+}
+
+gboolean
+mono_w32file_create_directory (const gunichar2 *name)
+{
+ return CreateDirectory (name, NULL);
+}
+
+gboolean
+mono_w32file_remove_directory (const gunichar2 *name)
+{
+ return RemoveDirectory (name);
+}
+
+guint32
+mono_w32file_get_attributes (const gunichar2 *name)
+{
+ return GetFileAttributes (name);
+}
+
+gboolean
+mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat)
+{
+ gboolean result;
+ WIN32_FILE_ATTRIBUTE_DATA data;
+
+ result = GetFileAttributesEx (name, GetFileExInfoStandard, &data);
+ if (result) {
+ stat->attributes = data.dwFileAttributes;
+ stat->creation_time = (gint64) ((((guint64) data.ftCreationTime.dwHighDateTime) << 32) + data.ftCreationTime.dwLowDateTime);
+ stat->last_access_time = (gint64) ((((guint64) data.ftLastAccessTime.dwHighDateTime) << 32) + data.ftLastAccessTime.dwLowDateTime);
+ stat->last_write_time = (gint64) ((((guint64) data.ftLastWriteTime.dwHighDateTime) << 32) + data.ftLastWriteTime.dwLowDateTime);
+ stat->length = ((gint64)data.nFileSizeHigh << 32) | data.nFileSizeLow;
+ }
+
+ return result;
+}
+
+gboolean
+mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
+{
+ return SetFileAttributes (name, attrs);
+}
+
+guint32
+mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
+{
+ return GetCurrentDirectory (length, buffer);
+}
+
+gboolean
+mono_w32file_set_cwd (const gunichar2 *path)
+{
+ return SetCurrentDirectory (path);
+}
+
+gboolean
+mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
+{
+ SECURITY_ATTRIBUTES attr;
+ attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ attr.bInheritHandle = TRUE;
+ attr.lpSecurityDescriptor = NULL;
+ return CreatePipe (readpipe, writepipe, &attr, size);
+}
+
+gboolean
+mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes)
+{
+ gboolean result;
+ ULARGE_INTEGER *wapi_free_bytes_avail;
+ ULARGE_INTEGER *wapi_total_number_of_bytes;
+ ULARGE_INTEGER *wapi_total_number_of_free_bytes;
+
+ result = GetDiskFreeSpaceEx (path_name, wapi_free_bytes_avail, wapi_total_number_of_bytes, wapi_total_number_of_free_bytes);
+ if (result) {
+ if (free_bytes_avail)
+ *free_bytes_avail = wapi_free_bytes_avail->QuadPart;
+ if (total_number_of_bytes)
+ *total_number_of_bytes = wapi_total_number_of_bytes->QuadPart;
+ if (total_number_of_free_bytes)
+ *total_number_of_free_bytes = wapi_total_number_of_free_bytes->QuadPart;
+ }
+
+ return result;
+}
+
+gboolean
+mono_w32file_get_volume_information (const gunichar2 *path, gunichar2 *volumename, gint volumesize, gint *outserial, gint *maxcomp, gint *fsflags, gunichar2 *fsbuffer, gint fsbuffersize)
+{
+ return GetVolumeInformation (path, volumename, volumesize, outserial, maxcomp, fsflags, fsbuffer, fsbuffersize);
+}
+
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
+
+gboolean
+mono_w32file_move (gunichar2 *path, gunichar2 *dest, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = MoveFile (path, dest);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gboolean
+mono_w32file_replace (gunichar2 *destinationFileName, gunichar2 *sourceFileName, gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = ReplaceFile (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gboolean
+mono_w32file_copy (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = CopyFile (path, dest, !overwrite);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gboolean
+mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+gboolean
+mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error)
+{
+ gboolean result;
+
+ MONO_ENTER_GC_SAFE;
+
+ result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
+ if (!result)
+ *error = GetLastError ();
+
+ MONO_EXIT_GC_SAFE;
+
+ return result;
+}
+
+HANDLE
+mono_w32file_get_console_input (void)
+{
+ return GetStdHandle (STD_INPUT_HANDLE);
+}
+
+HANDLE
+mono_w32file_get_console_output (void)
+{
+ return GetStdHandle (STD_OUTPUT_HANDLE);
+}
+
+HANDLE
+mono_w32file_get_console_error (void)
+{
+ return GetStdHandle (STD_ERROR_HANDLE);
+}
+
+gint64
+mono_w32file_get_file_size (gpointer handle, gint32 *error)
+{
+ gint64 length;
+ guint32 length_hi;
+
+ MONO_ENTER_GC_SAFE;
+
+ length = GetFileSize (handle, &length_hi);
+ if(length==INVALID_FILE_SIZE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+
+ return length | ((gint64)length_hi << 32);
+}
+
+guint32
+mono_w32file_get_drive_type (const gunichar2 *root_path_name)
+{
+ return GetDriveType (root_path_name);
+}
+
+gint32
+mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
+{
+ return GetLogicalDriveStrings (len, buf);
+}
+
+#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
--- /dev/null
+/*
+ * w32file.c: File IO internal calls
+ *
+ * Author:
+ * Dick Porter (dick@ximian.com)
+ * Gonzalo Paniagua Javier (gonzalo@ximian.com)
+ *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <mono/metadata/object.h>
+#include <mono/io-layer/io-layer.h>
+#include <mono/metadata/w32file.h>
+#include <mono/metadata/w32file-internals.h>
+#include <mono/metadata/exception.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
+#include <mono/utils/strenc.h>
+#include <utils/mono-io-portability.h>
+#include <mono/metadata/w32handle.h>
+
+#undef DEBUG
+
+/* conversion functions */
+
+static guint32 convert_mode(MonoFileMode mono_mode)
+{
+ guint32 mode;
+
+ switch(mono_mode) {
+ case FileMode_CreateNew:
+ mode=CREATE_NEW;
+ break;
+ case FileMode_Create:
+ mode=CREATE_ALWAYS;
+ break;
+ case FileMode_Open:
+ mode=OPEN_EXISTING;
+ break;
+ case FileMode_OpenOrCreate:
+ mode=OPEN_ALWAYS;
+ break;
+ case FileMode_Truncate:
+ mode=TRUNCATE_EXISTING;
+ break;
+ case FileMode_Append:
+ mode=OPEN_ALWAYS;
+ break;
+ default:
+ g_warning("System.IO.FileMode has unknown value 0x%x",
+ mono_mode);
+ /* Safe fallback */
+ mode=OPEN_EXISTING;
+ }
+
+ return(mode);
+}
+
+static guint32 convert_access(MonoFileAccess mono_access)
+{
+ guint32 access;
+
+ switch(mono_access) {
+ case FileAccess_Read:
+ access=GENERIC_READ;
+ break;
+ case FileAccess_Write:
+ access=GENERIC_WRITE;
+ break;
+ case FileAccess_ReadWrite:
+ access=GENERIC_READ|GENERIC_WRITE;
+ break;
+ default:
+ g_warning("System.IO.FileAccess has unknown value 0x%x",
+ mono_access);
+ /* Safe fallback */
+ access=GENERIC_READ;
+ }
+
+ return(access);
+}
+
+static guint32 convert_share(MonoFileShare mono_share)
+{
+ guint32 share = 0;
+
+ if (mono_share & FileShare_Read) {
+ share |= FILE_SHARE_READ;
+ }
+ if (mono_share & FileShare_Write) {
+ share |= FILE_SHARE_WRITE;
+ }
+ if (mono_share & FileShare_Delete) {
+ share |= FILE_SHARE_DELETE;
+ }
+
+ if (mono_share & ~(FileShare_Read|FileShare_Write|FileShare_Delete)) {
+ g_warning("System.IO.FileShare has unknown value 0x%x",
+ mono_share);
+ /* Safe fallback */
+ share=0;
+ }
+
+ return(share);
+}
+
+#if 0
+static guint32 convert_stdhandle(guint32 fd)
+{
+ guint32 stdhandle;
+
+ switch(fd) {
+ case 0:
+ stdhandle=STD_INPUT_HANDLE;
+ break;
+ case 1:
+ stdhandle=STD_OUTPUT_HANDLE;
+ break;
+ case 2:
+ stdhandle=STD_ERROR_HANDLE;
+ break;
+ default:
+ g_warning("unknown standard file descriptor %d", fd);
+ stdhandle=STD_INPUT_HANDLE;
+ }
+
+ return(stdhandle);
+}
+#endif
+
+static guint32 convert_seekorigin(MonoSeekOrigin origin)
+{
+ guint32 w32origin;
+
+ switch(origin) {
+ case SeekOrigin_Begin:
+ w32origin=FILE_BEGIN;
+ break;
+ case SeekOrigin_Current:
+ w32origin=FILE_CURRENT;
+ break;
+ case SeekOrigin_End:
+ w32origin=FILE_END;
+ break;
+ default:
+ g_warning("System.IO.SeekOrigin has unknown value 0x%x",
+ origin);
+ /* Safe fallback */
+ w32origin=FILE_CURRENT;
+ }
+
+ return(w32origin);
+}
+
+static gint64 convert_filetime (const FILETIME *filetime)
+{
+ return (gint64) ((((guint64) filetime->dwHighDateTime) << 32) + filetime->dwLowDateTime);
+}
+
+/* Managed file attributes have nearly but not quite the same values
+ * as the w32 equivalents.
+ */
+static guint32 convert_attrs(MonoFileAttributes attrs)
+{
+ if(attrs & FileAttributes_Encrypted) {
+ attrs = (MonoFileAttributes)(attrs | FILE_ATTRIBUTE_ENCRYPTED);
+ }
+
+ return(attrs);
+}
+
+/*
+ * On Win32, mono_w32file_get_attributes|_ex () seems to try opening the file,
+ * which might lead to sharing violation errors, whereas mono_w32file_find_first
+ * always succeeds. These 2 wrappers resort to mono_w32file_find_first if
+ * mono_w32file_get_attributes|_ex () has failed.
+ */
+static guint32
+get_file_attributes (const gunichar2 *path)
+{
+ guint32 res;
+ WIN32_FIND_DATA find_data;
+ HANDLE find_handle;
+ gint32 error;
+
+ res = mono_w32file_get_attributes (path);
+ if (res != -1)
+ return res;
+
+ error = GetLastError ();
+
+ if (error != ERROR_SHARING_VIOLATION)
+ return res;
+
+ find_handle = mono_w32file_find_first (path, &find_data);
+
+ if (find_handle == INVALID_HANDLE_VALUE)
+ return res;
+
+ mono_w32file_find_close (find_handle);
+
+ return find_data.dwFileAttributes;
+}
+
+static gboolean
+get_file_attributes_ex (const gunichar2 *path, MonoIOStat *stat)
+{
+ gboolean res;
+ WIN32_FIND_DATA find_data;
+ HANDLE find_handle;
+ gint32 error;
+
+ res = mono_w32file_get_attributes_ex (path, stat);
+ if (res)
+ return TRUE;
+
+ error = GetLastError ();
+ if (error != ERROR_SHARING_VIOLATION)
+ return FALSE;
+
+ find_handle = mono_w32file_find_first (path, &find_data);
+
+ if (find_handle == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ mono_w32file_find_close (find_handle);
+
+ stat->attributes = find_data.dwFileAttributes;
+ stat->creation_time = convert_filetime (&find_data.ftCreationTime);
+ stat->last_access_time = convert_filetime (&find_data.ftLastAccessTime);
+ stat->last_write_time = convert_filetime (&find_data.ftLastWriteTime);
+ stat->length = ((gint64)find_data.nFileSizeHigh << 32) | find_data.nFileSizeLow;
+ return TRUE;
+}
+
+/* System.IO.MonoIO internal calls */
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
+{
+ gboolean ret;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ ret=mono_w32file_create_directory (mono_string_chars (path));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
+{
+ gboolean ret;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ ret=mono_w32file_remove_directory (mono_string_chars (path));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+static gchar *
+get_search_dir (const gunichar2 *pattern)
+{
+ gchar *p;
+ gchar *result;
+
+ p = g_utf16_to_utf8 (pattern, -1, NULL, NULL, NULL);
+ result = g_path_get_dirname (p);
+ g_free (p);
+ return result;
+}
+
+static GPtrArray *
+get_filesystem_entries (const gunichar2 *path,
+ const gunichar2 *path_with_pattern,
+ gint attrs, gint mask,
+ gint32 *error)
+{
+ int i;
+ WIN32_FIND_DATA data;
+ HANDLE find_handle;
+ GPtrArray *names = NULL;
+ gchar *utf8_path = NULL, *utf8_result, *full_name;
+ gint32 attributes;
+
+ mask = convert_attrs ((MonoFileAttributes)mask);
+ attributes = get_file_attributes (path);
+ if (attributes != -1) {
+ if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+ *error = ERROR_INVALID_NAME;
+ goto fail;
+ }
+ } else {
+ *error = GetLastError ();
+ goto fail;
+ }
+
+ find_handle = mono_w32file_find_first (path_with_pattern, &data);
+ if (find_handle == INVALID_HANDLE_VALUE) {
+ gint32 find_error = GetLastError ();
+
+ if (find_error == ERROR_FILE_NOT_FOUND || find_error == ERROR_NO_MORE_FILES) {
+ /* No files, so just return an empty array */
+ goto fail;
+ }
+
+ *error = find_error;
+ goto fail;
+ }
+
+ utf8_path = get_search_dir (path_with_pattern);
+ names = g_ptr_array_new ();
+
+ do {
+ if ((data.cFileName[0] == '.' && data.cFileName[1] == 0) ||
+ (data.cFileName[0] == '.' && data.cFileName[1] == '.' && data.cFileName[2] == 0)) {
+ continue;
+ }
+
+ if ((data.dwFileAttributes & mask) == attrs) {
+ utf8_result = g_utf16_to_utf8 (data.cFileName, -1, NULL, NULL, NULL);
+ if (utf8_result == NULL) {
+ continue;
+ }
+
+ full_name = g_build_filename (utf8_path, utf8_result, NULL);
+ g_ptr_array_add (names, full_name);
+
+ g_free (utf8_result);
+ }
+ } while(mono_w32file_find_next (find_handle, &data));
+
+ if (mono_w32file_find_close (find_handle) == FALSE) {
+ *error = GetLastError ();
+ goto fail;
+ }
+
+ g_free (utf8_path);
+ return names;
+fail:
+ if (names) {
+ for (i = 0; i < names->len; i++)
+ g_free (g_ptr_array_index (names, i));
+ g_ptr_array_free (names, TRUE);
+ }
+ g_free (utf8_path);
+ return FALSE;
+}
+
+
+MonoArray *
+ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
+ MonoString *path_with_pattern,
+ gint attrs, gint mask,
+ gint32 *ioerror)
+{
+ MonoError error;
+ MonoDomain *domain = mono_domain_get ();
+ MonoArray *result;
+ int i;
+ GPtrArray *names;
+
+ *ioerror = ERROR_SUCCESS;
+
+ MONO_ENTER_GC_SAFE;
+ names = get_filesystem_entries (mono_string_chars (path), mono_string_chars (path_with_pattern), attrs, mask, ioerror);
+ MONO_EXIT_GC_SAFE;
+
+ if (!names) {
+ // If there's no array and no error, then return an empty array.
+ if (*ioerror == ERROR_SUCCESS) {
+ MonoArray *arr = mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
+ mono_error_set_pending_exception (&error);
+ return arr;
+ }
+ return NULL;
+ }
+
+ result = mono_array_new_checked (domain, mono_defaults.string_class, names->len, &error);
+ if (mono_error_set_pending_exception (&error))
+ goto leave;
+ for (i = 0; i < names->len; i++) {
+ mono_array_setref (result, i, mono_string_new (domain, (const char *)g_ptr_array_index (names, i)));
+ g_free (g_ptr_array_index (names, i));
+ }
+leave:
+ g_ptr_array_free (names, TRUE);
+ return result;
+}
+
+typedef struct {
+ MonoDomain *domain;
+ gchar *utf8_path;
+ HANDLE find_handle;
+} IncrementalFind;
+
+static gboolean
+incremental_find_check_match (IncrementalFind *handle, WIN32_FIND_DATA *data, MonoString **result)
+{
+ gchar *utf8_result;
+ gchar *full_name;
+
+ if ((data->cFileName[0] == '.' && data->cFileName[1] == 0) || (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0))
+ return FALSE;
+
+ utf8_result = g_utf16_to_utf8 (data->cFileName, -1, NULL, NULL, NULL);
+ if (utf8_result == NULL)
+ return FALSE;
+
+ full_name = g_build_filename (handle->utf8_path, utf8_result, NULL);
+ g_free (utf8_result);
+ *result = mono_string_new (mono_domain_get (), full_name);
+ g_free (full_name);
+
+ return TRUE;
+}
+
+HANDLE
+ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path_with_pattern, MonoString **file_name, gint32 *file_attr, gint32 *ioerror)
+{
+ HANDLE hnd;
+ WIN32_FIND_DATA data;
+ MonoError error;
+
+ hnd = mono_w32file_find_first (mono_string_chars (path_with_pattern), &data);
+
+ if (hnd == INVALID_HANDLE_VALUE) {
+ *file_name = NULL;
+ *file_attr = 0;
+ *ioerror = GetLastError ();
+ return hnd;
+ }
+
+ mono_gc_wbarrier_generic_store (file_name, (MonoObject*) mono_string_from_utf16_checked (data.cFileName, &error));
+ mono_error_set_pending_exception (&error);
+
+ *file_attr = data.dwFileAttributes;
+ *ioerror = ERROR_SUCCESS;
+
+ return hnd;
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_FindNextFile (HANDLE hnd, MonoString **file_name, gint32 *file_attr, gint32 *ioerror)
+{
+ MonoBoolean res;
+ WIN32_FIND_DATA data;
+ MonoError error;
+
+ res = mono_w32file_find_next (hnd, &data);
+
+ if (res == FALSE) {
+ *file_name = NULL;
+ *file_attr = 0;
+ *ioerror = GetLastError ();
+ return res;
+ }
+
+ mono_gc_wbarrier_generic_store (file_name, (MonoObject*) mono_string_from_utf16_checked (data.cFileName, &error));
+ mono_error_set_pending_exception (&error);
+
+ *file_attr = data.dwFileAttributes;
+ *ioerror = ERROR_SUCCESS;
+
+ return res;
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_FindCloseFile (HANDLE hnd)
+{
+ return mono_w32file_find_close (hnd);
+}
+
+/* FIXME make gc suspendable */
+MonoString *
+ves_icall_System_IO_MonoIO_FindFirst (MonoString *path,
+ MonoString *path_with_pattern,
+ gint32 *result_attr, gint32 *ioerror,
+ gpointer *handle)
+{
+ MonoError error;
+ WIN32_FIND_DATA data;
+ HANDLE find_handle;
+ IncrementalFind *ifh;
+ MonoString *result;
+
+ *ioerror = ERROR_SUCCESS;
+
+ find_handle = mono_w32file_find_first (mono_string_chars (path_with_pattern), &data);
+
+ if (find_handle == INVALID_HANDLE_VALUE) {
+ gint32 find_error = GetLastError ();
+ *handle = NULL;
+
+ if (find_error == ERROR_FILE_NOT_FOUND)
+ return NULL;
+
+ *ioerror = find_error;
+ return NULL;
+ }
+
+ ifh = g_new (IncrementalFind, 1);
+ ifh->find_handle = find_handle;
+ ifh->utf8_path = mono_string_to_utf8_checked (path, &error);
+ if (mono_error_set_pending_exception (&error)) {
+ MONO_ENTER_GC_SAFE;
+ mono_w32file_find_close (find_handle);
+ MONO_EXIT_GC_SAFE;
+ g_free (ifh);
+ return NULL;
+ }
+ ifh->domain = mono_domain_get ();
+ *handle = ifh;
+
+ while (incremental_find_check_match (ifh, &data, &result) == 0){
+ if (mono_w32file_find_next (find_handle, &data) == FALSE){
+ int e = GetLastError ();
+ if (e != ERROR_NO_MORE_FILES)
+ *ioerror = e;
+ return NULL;
+ }
+ }
+ *result_attr = data.dwFileAttributes;
+
+ return result;
+}
+
+/* FIXME make gc suspendable */
+MonoString *
+ves_icall_System_IO_MonoIO_FindNext (gpointer handle, gint32 *result_attr, gint32 *error)
+{
+ IncrementalFind *ifh = (IncrementalFind *)handle;
+ WIN32_FIND_DATA data;
+ MonoString *result;
+
+ *error = ERROR_SUCCESS;
+ do {
+ if (mono_w32file_find_next (ifh->find_handle, &data) == FALSE){
+ int e = GetLastError ();
+ if (e != ERROR_NO_MORE_FILES)
+ *error = e;
+ return NULL;
+ }
+ } while (incremental_find_check_match (ifh, &data, &result) == 0);
+
+ *result_attr = data.dwFileAttributes;
+ return result;
+}
+
+int
+ves_icall_System_IO_MonoIO_FindClose (gpointer handle)
+{
+ IncrementalFind *ifh = (IncrementalFind *)handle;
+ gint32 error;
+
+ MONO_ENTER_GC_SAFE;
+ if (mono_w32file_find_close (ifh->find_handle) == FALSE){
+ error = GetLastError ();
+ } else
+ error = ERROR_SUCCESS;
+ g_free (ifh->utf8_path);
+ g_free (ifh);
+ MONO_EXIT_GC_SAFE;
+
+ return error;
+}
+
+MonoString *
+ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *io_error)
+{
+ MonoError error;
+ MonoString *result;
+ gunichar2 *buf;
+ int len, res_len;
+
+ len = MAX_PATH + 1; /*FIXME this is too smal under most unix systems.*/
+ buf = g_new (gunichar2, len);
+
+ mono_error_init (&error);
+ *io_error=ERROR_SUCCESS;
+ result = NULL;
+
+ res_len = mono_w32file_get_cwd (len, buf);
+ if (res_len > len) { /*buf is too small.*/
+ int old_res_len = res_len;
+ g_free (buf);
+ buf = g_new (gunichar2, res_len);
+ res_len = mono_w32file_get_cwd (res_len, buf) == old_res_len;
+ }
+
+ if (res_len) {
+ len = 0;
+ while (buf [len])
+ ++ len;
+
+ result = mono_string_new_utf16_checked (mono_domain_get (), buf, len, &error);
+ } else {
+ *io_error=GetLastError ();
+ }
+
+ g_free (buf);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
+ gint32 *error)
+{
+ gboolean ret;
+
+ *error=ERROR_SUCCESS;
+
+ ret=mono_w32file_set_cwd (mono_string_chars (path));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ return(ret);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest, gint32 *error)
+{
+ *error=ERROR_SUCCESS;
+ return mono_w32file_move (mono_string_chars (path), mono_string_chars (dest), error);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
+ MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
+ gint32 *error)
+{
+ gunichar2 *utf16_sourceFileName = NULL, *utf16_destinationFileName = NULL, *utf16_destinationBackupFileName = NULL;
+ guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
+
+ if (sourceFileName)
+ utf16_sourceFileName = mono_string_chars (sourceFileName);
+ if (destinationFileName)
+ utf16_destinationFileName = mono_string_chars (destinationFileName);
+ if (destinationBackupFileName)
+ utf16_destinationBackupFileName = mono_string_chars (destinationBackupFileName);
+
+ *error = ERROR_SUCCESS;
+ if (ignoreMetadataErrors)
+ replaceFlags |= REPLACEFILE_IGNORE_MERGE_ERRORS;
+
+ /* FIXME: source and destination file names must not be NULL, but apparently they might be! */
+ return mono_w32file_replace (utf16_destinationFileName, utf16_sourceFileName,
+ utf16_destinationBackupFileName, replaceFlags, error);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
+ MonoBoolean overwrite, gint32 *error)
+{
+ *error=ERROR_SUCCESS;
+ return mono_w32file_copy (mono_string_chars (path), mono_string_chars (dest), overwrite, error);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
+{
+ gboolean ret;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ ret=mono_w32file_delete (mono_string_chars (path));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+gint32
+ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
+{
+ gint32 ret;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ ret=get_file_attributes (mono_string_chars (path));
+
+ /*
+ * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
+ * headers is wrong, hence this temporary workaround.
+ * See
+ * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
+ */
+ if (ret==-1) {
+ /* if(ret==INVALID_FILE_ATTRIBUTES) { */
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
+ gint32 *error)
+{
+ gboolean ret;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ ret=mono_w32file_set_attributes (mono_string_chars (path),
+ convert_attrs ((MonoFileAttributes)attrs));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+gint32
+ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
+{
+ gboolean ret;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ ret=mono_w32file_get_type (handle);
+ if(ret==FILE_TYPE_UNKNOWN) {
+ /* Not necessarily an error, but the caller will have
+ * to decide based on the error value.
+ */
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat, gint32 *error)
+{
+ gboolean result;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ result = get_file_attributes_ex (mono_string_chars (path), stat);
+
+ if (!result) {
+ *error=GetLastError ();
+ memset (stat, 0, sizeof (MonoIOStat));
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return result;
+}
+
+HANDLE
+ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
+ gint32 access_mode, gint32 share, gint32 options,
+ gint32 *error)
+{
+ HANDLE ret;
+ int attributes, attrs;
+ gunichar2 *chars;
+ MONO_ENTER_GC_SAFE;
+
+ chars = mono_string_chars (filename);
+ *error=ERROR_SUCCESS;
+
+ if (options != 0){
+ if (options & FileOptions_Encrypted)
+ attributes = FILE_ATTRIBUTE_ENCRYPTED;
+ else
+ attributes = FILE_ATTRIBUTE_NORMAL;
+ if (options & FileOptions_DeleteOnClose)
+ attributes |= FILE_FLAG_DELETE_ON_CLOSE;
+ if (options & FileOptions_SequentialScan)
+ attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
+ if (options & FileOptions_RandomAccess)
+ attributes |= FILE_FLAG_RANDOM_ACCESS;
+
+ if (options & FileOptions_Temporary)
+ attributes |= FILE_ATTRIBUTE_TEMPORARY;
+
+ if (options & FileOptions_WriteThrough)
+ attributes |= FILE_FLAG_WRITE_THROUGH;
+ } else
+ attributes = FILE_ATTRIBUTE_NORMAL;
+
+ /* If we're opening a directory we need to set the extra flag
+ */
+ attrs = get_file_attributes (chars);
+ if (attrs != INVALID_FILE_ATTRIBUTES) {
+ if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
+ }
+ }
+
+ ret=mono_w32file_create (chars, convert_access ((MonoFileAccess)access_mode), convert_share ((MonoFileShare)share), convert_mode ((MonoFileMode)mode), attributes);
+ if(ret==INVALID_HANDLE_VALUE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
+{
+ gboolean ret;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ ret=CloseHandle (handle);
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+gint32
+ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
+ gint32 dest_offset, gint32 count,
+ gint32 *error)
+{
+ guchar *buffer;
+ gboolean result;
+ guint32 n;
+
+ *error=ERROR_SUCCESS;
+
+ MONO_CHECK_ARG_NULL (dest, 0);
+
+ if (dest_offset > mono_array_length (dest) - count) {
+ mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
+ return 0;
+ }
+
+ buffer = mono_array_addr (dest, guchar, dest_offset);
+
+ MONO_ENTER_GC_SAFE;
+ result = mono_w32file_read (handle, buffer, count, &n);
+ MONO_EXIT_GC_SAFE;
+
+ if (!result) {
+ *error=GetLastError ();
+ return -1;
+ }
+
+ return (gint32)n;
+}
+
+gint32
+ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
+ gint32 src_offset, gint32 count,
+ gint32 *error)
+{
+ guchar *buffer;
+ gboolean result;
+ guint32 n;
+
+ *error=ERROR_SUCCESS;
+
+ MONO_CHECK_ARG_NULL (src, 0);
+
+ if (src_offset > mono_array_length (src) - count) {
+ mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
+ return 0;
+ }
+
+ buffer = mono_array_addr (src, guchar, src_offset);
+ MONO_ENTER_GC_SAFE;
+ result = mono_w32file_write (handle, buffer, count, &n);
+ MONO_EXIT_GC_SAFE;
+
+ if (!result) {
+ *error=GetLastError ();
+ return -1;
+ }
+
+ return (gint32)n;
+}
+
+gint64
+ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
+ gint32 *error)
+{
+ gint32 offset_hi;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ offset_hi = offset >> 32;
+ offset = mono_w32file_seek (handle, (gint32) (offset & 0xFFFFFFFF), &offset_hi,
+ convert_seekorigin ((MonoSeekOrigin)origin));
+
+ if(offset==INVALID_SET_FILE_POINTER) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return offset | ((gint64)offset_hi << 32);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
+{
+ gboolean ret;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ ret=mono_w32file_flush (handle);
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+gint64
+ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
+{
+ *error=ERROR_SUCCESS;
+ return mono_w32file_get_file_size (handle, error);
+}
+
+/* FIXME make gc suspendable */
+MonoBoolean
+ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
+ gint32 *error)
+{
+ gint64 offset, offset_set;
+ gint32 offset_hi;
+ gint32 length_hi;
+ gboolean result;
+
+ *error=ERROR_SUCCESS;
+
+ /* save file pointer */
+
+ offset_hi = 0;
+ offset = mono_w32file_seek (handle, 0, &offset_hi, FILE_CURRENT);
+ if(offset==INVALID_SET_FILE_POINTER) {
+ *error=GetLastError ();
+ return(FALSE);
+ }
+
+ /* extend or truncate */
+
+ length_hi = length >> 32;
+ offset_set=mono_w32file_seek (handle, length & 0xFFFFFFFF, &length_hi,
+ FILE_BEGIN);
+ if(offset_set==INVALID_SET_FILE_POINTER) {
+ *error=GetLastError ();
+ return(FALSE);
+ }
+
+ result = mono_w32file_truncate (handle);
+ if(result==FALSE) {
+ *error=GetLastError ();
+ return(FALSE);
+ }
+
+ /* restore file pointer */
+
+ offset_set=mono_w32file_seek (handle, offset & 0xFFFFFFFF, &offset_hi,
+ FILE_BEGIN);
+ if(offset_set==INVALID_SET_FILE_POINTER) {
+ *error=GetLastError ();
+ return(FALSE);
+ }
+
+ return result;
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
+ gint64 last_access_time,
+ gint64 last_write_time, gint32 *error)
+{
+ gboolean ret;
+ const FILETIME *creation_filetime;
+ const FILETIME *access_filetime;
+ const FILETIME *write_filetime;
+ MONO_ENTER_GC_SAFE;
+
+ *error=ERROR_SUCCESS;
+
+ if (creation_time < 0)
+ creation_filetime = NULL;
+ else
+ creation_filetime = (FILETIME *)&creation_time;
+
+ if (last_access_time < 0)
+ access_filetime = NULL;
+ else
+ access_filetime = (FILETIME *)&last_access_time;
+
+ if (last_write_time < 0)
+ write_filetime = NULL;
+ else
+ write_filetime = (FILETIME *)&last_write_time;
+
+ ret=mono_w32file_set_times (handle, creation_filetime, access_filetime, write_filetime);
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+ return(ret);
+}
+
+HANDLE
+ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
+{
+ return mono_w32file_get_console_output ();
+}
+
+HANDLE
+ves_icall_System_IO_MonoIO_get_ConsoleInput ()
+{
+ return mono_w32file_get_console_input ();
+}
+
+HANDLE
+ves_icall_System_IO_MonoIO_get_ConsoleError ()
+{
+ return mono_w32file_get_console_error ();
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle, HANDLE *write_handle, gint32 *error)
+{
+ gboolean ret;
+
+ MONO_ENTER_GC_SAFE;
+ ret=mono_w32file_create_pipe (read_handle, write_handle, 0);
+ MONO_EXIT_GC_SAFE;
+
+ if(ret==FALSE) {
+ *error = GetLastError ();
+ /* FIXME: throw an exception? */
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_DuplicateHandle (HANDLE source_process_handle, HANDLE source_handle,
+ HANDLE target_process_handle, HANDLE *target_handle, gint32 access, gint32 inherit, gint32 options, gint32 *error)
+{
+ /* This is only used on Windows */
+ gboolean ret;
+
+ MONO_ENTER_GC_SAFE;
+#ifdef HOST_WIN32
+ ret=DuplicateHandle (source_process_handle, source_handle, target_process_handle, target_handle, access, inherit, options);
+#else
+ mono_w32handle_ref (source_handle);
+ *target_handle = source_handle;
+ ret = TRUE;
+#endif
+ MONO_EXIT_GC_SAFE;
+
+ if(ret==FALSE) {
+ *error = GetLastError ();
+ /* FIXME: throw an exception? */
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+#ifndef HOST_WIN32
+gunichar2
+ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
+{
+ return (gunichar2) '/'; /* forward slash */
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
+{
+ return (gunichar2) '/'; /* forward slash */
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
+{
+ if (IS_PORTABILITY_SET)
+ return (gunichar2) '\\'; /* backslash */
+ else
+ return (gunichar2) '/'; /* forward slash */
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_PathSeparator ()
+{
+ return (gunichar2) ':'; /* colon */
+}
+#endif /* !HOST_WIN32 */
+
+static const gunichar2
+invalid_path_chars [] = {
+#if defined (TARGET_WIN32)
+ 0x0022, /* double quote, which seems allowed in MS.NET but should be rejected */
+ 0x003c, /* less than */
+ 0x003e, /* greater than */
+ 0x007c, /* pipe */
+ 0x0008,
+ 0x0010,
+ 0x0011,
+ 0x0012,
+ 0x0014,
+ 0x0015,
+ 0x0016,
+ 0x0017,
+ 0x0018,
+ 0x0019,
+#endif
+ 0x0000 /* null */
+};
+
+MonoArray *
+ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
+{
+ MonoError error;
+ MonoArray *chars;
+ MonoDomain *domain;
+ int i, n;
+
+ domain = mono_domain_get ();
+ n = sizeof (invalid_path_chars) / sizeof (gunichar2);
+ chars = mono_array_new_checked (domain, mono_defaults.char_class, n, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
+
+ for (i = 0; i < n; ++ i)
+ mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
+
+ return chars;
+}
+
+void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
+ gint64 length, gint32 *error)
+{
+ *error=ERROR_SUCCESS;
+ mono_w32file_lock (handle, position, length, error);
+}
+
+void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
+ gint64 length, gint32 *error)
+{
+ *error=ERROR_SUCCESS;
+ mono_w32file_unlock (handle, position, length, error);
+}
+
+//Support for io-layer free mmap'd files.
+
+#if defined (TARGET_IOS) || defined (TARGET_ANDROID)
+
+gint64
+mono_filesize_from_path (MonoString *string)
+{
+ MonoError error;
+ struct stat buf;
+ gint64 res;
+ char *path = mono_string_to_utf8_checked (string, &error);
+ mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
+
+ MONO_ENTER_GC_SAFE;
+ if (stat (path, &buf) == -1)
+ res = -1;
+ else
+ res = (gint64)buf.st_size;
+
+ g_free (path);
+
+ MONO_EXIT_GC_SAFE;
+ return res;
+}
+
+gint64
+mono_filesize_from_fd (int fd)
+{
+ struct stat buf;
+ int res;
+
+ MONO_ENTER_GC_SAFE;
+ res = fstat (fd, &buf);
+ MONO_EXIT_GC_SAFE;
+
+ if (res == -1)
+ return (gint64)-1;
+
+ return (gint64)buf.st_size;
+}
+
+#endif
+
+#ifndef HOST_WIN32
+void mono_w32handle_dump (void);
+
+void ves_icall_System_IO_MonoIO_DumpHandles (void)
+{
+ mono_w32handle_dump ();
+}
+#endif /* !HOST_WIN32 */
--- /dev/null
+/*
+ * w32file.h: File IO internal calls
+ *
+ * Authors:
+ * Dick Porter (dick@ximian.com)
+ * Dan Lewis (dihlewis@yahoo.co.uk)
+ *
+ * (C) 2001 Ximian, Inc.
+ * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#ifndef _MONO_METADATA_W32FILE_H_
+#define _MONO_METADATA_W32FILE_H_
+
+#include <config.h>
+#include <glib.h>
+
+#include "io-layer/io-layer.h"
+#include <mono/metadata/object-internals.h>
+#include <mono/utils/mono-compiler.h>
+
+G_BEGIN_DECLS
+
+/* This is a copy of System.IO.FileAccess */
+typedef enum {
+ FileAccess_Read=0x01,
+ FileAccess_Write=0x02,
+ FileAccess_ReadWrite=FileAccess_Read|FileAccess_Write
+} MonoFileAccess;
+
+/* This is a copy of System.IO.FileMode */
+typedef enum {
+ FileMode_CreateNew=1,
+ FileMode_Create=2,
+ FileMode_Open=3,
+ FileMode_OpenOrCreate=4,
+ FileMode_Truncate=5,
+ FileMode_Append=6
+} MonoFileMode;
+
+/* This is a copy of System.IO.FileShare */
+typedef enum {
+ FileShare_None=0x0,
+ FileShare_Read=0x01,
+ FileShare_Write=0x02,
+ FileShare_ReadWrite=FileShare_Read|FileShare_Write,
+ FileShare_Delete=0x04
+} MonoFileShare;
+
+/* This is a copy of System.IO.FileOptions */
+typedef enum {
+ FileOptions_None = 0,
+ FileOptions_Temporary = 1, // Internal. See note in System.IO.FileOptions
+ FileOptions_Encrypted = 0x4000,
+ FileOptions_DeleteOnClose = 0x4000000,
+ FileOptions_SequentialScan = 0x8000000,
+ FileOptions_RandomAccess = 0x10000000,
+ FileOptions_Asynchronous = 0x40000000,
+ FileOptions_WriteThrough = 0x80000000
+} MonoFileOptions;
+
+/* This is a copy of System.IO.SeekOrigin */
+typedef enum {
+ SeekOrigin_Begin=0,
+ SeekOrigin_Current=1,
+ SeekOrigin_End=2
+} MonoSeekOrigin;
+
+/* This is a copy of System.IO.MonoIOStat */
+typedef struct _MonoIOStat {
+ gint32 attributes;
+ gint64 length;
+ gint64 creation_time;
+ gint64 last_access_time;
+ gint64 last_write_time;
+} MonoIOStat;
+
+/* This is a copy of System.IO.FileAttributes */
+typedef enum {
+ FileAttributes_ReadOnly=0x00001,
+ FileAttributes_Hidden=0x00002,
+ FileAttributes_System=0x00004,
+ FileAttributes_Directory=0x00010,
+ FileAttributes_Archive=0x00020,
+ FileAttributes_Device=0x00040,
+ FileAttributes_Normal=0x00080,
+ FileAttributes_Temporary=0x00100,
+ FileAttributes_SparseFile=0x00200,
+ FileAttributes_ReparsePoint=0x00400,
+ FileAttributes_Compressed=0x00800,
+ FileAttributes_Offline=0x01000,
+ FileAttributes_NotContentIndexed=0x02000,
+ FileAttributes_Encrypted=0x04000,
+ FileAttributes_MonoExecutable= (int) 0x80000000
+} MonoFileAttributes;
+/* This is not used anymore
+typedef struct _MonoFSAsyncResult {
+ MonoObject obj;
+ MonoObject *state;
+ MonoBoolean completed;
+ MonoBoolean done;
+ MonoException *exc;
+ MonoWaitHandle *wait_handle;
+ MonoDelegate *async_callback;
+ MonoBoolean completed_synch;
+ MonoArray *buffer;
+ gint offset;
+ gint count;
+ gint original_count;
+ gint bytes_read;
+ MonoDelegate *real_cb;
+} MonoFSAsyncResult;
+*/
+/* System.IO.MonoIO */
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error);
+
+MonoArray *
+ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
+ MonoString *path_with_pattern,
+ gint mask, gint attrs,
+ gint32 *error);
+
+extern gpointer
+ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path_with_pattern,
+ MonoString **file_name,
+ gint32 *file_attr,
+ gint32 *ioerror);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_FindNextFile (gpointer hnd,
+ MonoString **file_name,
+ gint32 *file_attr,
+ gint32 *ioerror);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_FindCloseFile (gpointer hnd);
+
+extern MonoString *
+ves_icall_System_IO_MonoIO_FindFirst (MonoString *path,
+ MonoString *path_with_pattern,
+ gint32 *result_mask,
+ gint32 *error,
+ gpointer *handle);
+extern MonoString *
+ves_icall_System_IO_MonoIO_FindNext (gpointer handle, gint32 *result_mask, gint32 *error);
+
+extern int
+ves_icall_System_IO_MonoIO_FindClose (gpointer handle);
+
+extern MonoString *
+ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
+ gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
+ gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
+ MonoBoolean overwrite, gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error);
+
+extern gint32
+ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
+ gint32 *error);
+
+extern gint32
+ves_icall_System_IO_MonoIO_GetFileType (gpointer handle, gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
+ gint32 *error);
+
+extern gpointer
+ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
+ gint32 access_mode, gint32 share, gint32 options,
+ gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_Close (gpointer handle, gint32 *error);
+
+extern gint32
+ves_icall_System_IO_MonoIO_Read (gpointer handle, MonoArray *dest,
+ gint32 dest_offset, gint32 count,
+ gint32 *error);
+
+extern gint32
+ves_icall_System_IO_MonoIO_Write (gpointer handle, MonoArray *src,
+ gint32 src_offset, gint32 count,
+ gint32 *error);
+
+extern gint64
+ves_icall_System_IO_MonoIO_Seek (gpointer handle, gint64 offset, gint32 origin,
+ gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_Flush (gpointer handle, gint32 *error);
+
+extern gint64
+ves_icall_System_IO_MonoIO_GetLength (gpointer handle, gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_SetLength (gpointer handle, gint64 length,
+ gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_SetFileTime (gpointer handle, gint64 creation_time,
+ gint64 last_access_time,
+ gint64 last_write_time, gint32 *error);
+
+extern gpointer
+ves_icall_System_IO_MonoIO_get_ConsoleOutput (void);
+
+extern gpointer
+ves_icall_System_IO_MonoIO_get_ConsoleInput (void);
+
+extern gpointer
+ves_icall_System_IO_MonoIO_get_ConsoleError (void);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_CreatePipe (gpointer *read_handle, gpointer *write_handle, gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_DuplicateHandle (gpointer source_process_handle, gpointer source_handle,
+ gpointer target_process_handle, gpointer *target_handle, gint32 access, gint32 inherit, gint32 options, gint32 *error);
+
+extern gunichar2
+ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar (void);
+
+extern gunichar2
+ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar (void);
+
+extern gunichar2
+ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar (void);
+
+extern gunichar2
+ves_icall_System_IO_MonoIO_get_PathSeparator (void);
+
+extern MonoArray *
+ves_icall_System_IO_MonoIO_get_InvalidPathChars (void);
+
+extern void ves_icall_System_IO_MonoIO_Lock (gpointer handle, gint64 position,
+ gint64 length, gint32 *error);
+extern void ves_icall_System_IO_MonoIO_Unlock (gpointer handle, gint64 position,
+ gint64 length, gint32 *error);
+
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
+ MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
+ gint32 *error);
+
+#if defined (TARGET_IOS) || defined (TARGET_ANDROID)
+
+MONO_RT_EXTERNAL_ONLY
+extern gint64
+mono_filesize_from_path (MonoString *path);
+
+extern gint64
+mono_filesize_from_fd (int fd);
+
+#endif
+
+void
+ves_icall_System_IO_MonoIO_DumpHandles (void);
+
+#if !defined(HOST_WIN32)
+
+#define GENERIC_READ 0x80000000
+#define GENERIC_WRITE 0x40000000
+#define GENERIC_EXECUTE 0x20000000
+#define GENERIC_ALL 0x10000000
+
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+#define FILE_SHARE_DELETE 0x00000004
+
+#define CREATE_NEW 1
+#define CREATE_ALWAYS 2
+#define OPEN_EXISTING 3
+#define OPEN_ALWAYS 4
+#define TRUNCATE_EXISTING 5
+
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
+#define FILE_ATTRIBUTE_ENCRYPTED 0x00000040
+#define FILE_ATTRIBUTE_NORMAL 0x00000080
+#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
+#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
+#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
+#define FILE_ATTRIBUTE_OFFLINE 0x00001000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
+#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
+#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
+#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
+#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
+#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
+#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
+#define FILE_FLAG_RANDOM_ACCESS 0x10000000
+#define FILE_FLAG_NO_BUFFERING 0x20000000
+#define FILE_FLAG_OVERLAPPED 0x40000000
+#define FILE_FLAG_WRITE_THROUGH 0x80000000
+
+#define REPLACEFILE_WRITE_THROUGH 0x00000001
+#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x00000002
+
+#define MAX_PATH 260
+
+#define INVALID_SET_FILE_POINTER ((guint32) 0xFFFFFFFF)
+#define INVALID_FILE_SIZE ((guint32) 0xFFFFFFFF)
+#define INVALID_FILE_ATTRIBUTES ((guint32) 0xFFFFFFFF)
+
+#define FILE_TYPE_UNKNOWN 0x0000
+#define FILE_TYPE_DISK 0x0001
+#define FILE_TYPE_CHAR 0x0002
+#define FILE_TYPE_PIPE 0x0003
+#define FILE_TYPE_REMOTE 0x8000
+
+#define FILE_BEGIN 0
+#define FILE_CURRENT 1
+#define FILE_END 2
+
+#define DRIVE_UNKNOWN 0
+#define DRIVE_NO_ROOT_DIR 1
+#define DRIVE_REMOVABLE 2
+#define DRIVE_FIXED 3
+#define DRIVE_REMOTE 4
+#define DRIVE_CDROM 5
+#define DRIVE_RAMDISK 6
+
+typedef struct {
+ guint16 wYear;
+ guint16 wMonth;
+ guint16 wDayOfWeek;
+ guint16 wDay;
+ guint16 wHour;
+ guint16 wMinute;
+ guint16 wSecond;
+ guint16 wMilliseconds;
+} SYSTEMTIME;
+
+typedef struct {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint32 dwHighDateTime;
+ guint32 dwLowDateTime;
+#else
+ guint32 dwLowDateTime;
+ guint32 dwHighDateTime;
+#endif
+} FILETIME;
+
+typedef struct {
+ guint32 dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ guint32 nFileSizeHigh;
+ guint32 nFileSizeLow;
+ guint32 dwReserved0;
+ guint32 dwReserved1;
+ gunichar2 cFileName [MAX_PATH];
+ gunichar2 cAlternateFileName [14];
+} WIN32_FIND_DATA;
+
+#endif /* !defined(HOST_WIN32) */
+
+void
+mono_w32file_init (void);
+
+void
+mono_w32file_cleanup (void);
+
+gpointer
+mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs);
+
+gboolean
+mono_w32file_delete (const gunichar2 *name);
+
+gboolean
+mono_w32file_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread);
+
+gboolean
+mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten);
+
+gboolean
+mono_w32file_flush (gpointer handle);
+
+gboolean
+mono_w32file_truncate (gpointer handle);
+
+guint32
+mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method);
+
+gboolean
+mono_w32file_move (gunichar2 *path, gunichar2 *dest, gint32 *error);
+
+gboolean
+mono_w32file_copy (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32 *error);
+
+gboolean
+mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error);
+
+gboolean
+mono_w32file_replace (gunichar2 *destinationFileName, gunichar2 *sourceFileName, gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error);
+
+gboolean
+mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error);
+
+gpointer
+mono_w32file_get_console_output (void);
+
+gpointer
+mono_w32file_get_console_error (void);
+
+gpointer
+mono_w32file_get_console_input (void);
+
+gint64
+mono_w32file_get_file_size (gpointer handle, gint32 *error);
+
+gint
+mono_w32file_get_type (gpointer handle);
+
+gboolean
+mono_w32file_get_times (gpointer handle, FILETIME *create_time, FILETIME *access_time, FILETIME *write_time);
+
+gboolean
+mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time);
+
+gboolean
+mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time);
+
+gpointer
+mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data);
+
+gboolean
+mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data);
+
+gboolean
+mono_w32file_find_close (gpointer handle);
+
+gboolean
+mono_w32file_create_directory (const gunichar2 *name);
+
+gboolean
+mono_w32file_remove_directory (const gunichar2 *name);
+
+guint32
+mono_w32file_get_attributes (const gunichar2 *name);
+
+gboolean
+mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat);
+
+gboolean
+mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs);
+
+guint32
+mono_w32file_get_cwd (guint32 length, gunichar2 *buffer);
+
+gboolean
+mono_w32file_set_cwd (const gunichar2 *path);
+
+gboolean
+mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size);
+
+gint32
+mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf);
+
+gboolean
+mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes);
+
+guint32
+mono_w32file_get_drive_type (const gunichar2 *root_path_name);
+
+gboolean
+mono_w32file_get_volume_information (const gunichar2 *path, gunichar2 *volumename, gint volumesize, gint *outserial, gint *maxcomp, gint *fsflags, gunichar2 *fsbuffer, gint fsbuffersize);
+
+G_END_DECLS
+
+#endif /* _MONO_METADATA_W32FILE_H_ */
}
/*
- * wapi_init:
+ * mono_w32handle_init:
*
* Initialize the io-layer.
*/
#include "mono/utils/mono-threads.h"
#include "mono/metadata/w32handle.h"
+#define MAX_PATH 260
+
typedef struct {
MonoNativeThreadId tid;
guint32 recursion;
#include <mono/metadata/exception.h>
#include <mono/io-layer/io-layer.h>
#include <mono/metadata/w32handle.h>
+#include <mono/metadata/w32file.h>
#include <mono/utils/mono-membar.h>
#include <mono/utils/mono-logger-internals.h>
#include <mono/utils/strenc.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-mmap.h>
#include <mono/utils/strenc.h>
+#include <mono/utils/mono-io-portability.h>
#ifndef MAXPATHLEN
#define MAXPATHLEN 242
out_fd = GPOINTER_TO_UINT (startup_handles->output);
err_fd = GPOINTER_TO_UINT (startup_handles->error);
} else {
- in_fd = GPOINTER_TO_UINT (GetStdHandle (STD_INPUT_HANDLE));
- out_fd = GPOINTER_TO_UINT (GetStdHandle (STD_OUTPUT_HANDLE));
- err_fd = GPOINTER_TO_UINT (GetStdHandle (STD_ERROR_HANDLE));
+ in_fd = GPOINTER_TO_UINT (mono_w32file_get_console_input ());
+ out_fd = GPOINTER_TO_UINT (mono_w32file_get_console_output ());
+ err_fd = GPOINTER_TO_UINT (mono_w32file_get_console_error ());
}
/*
return(NULL);
}
- fd = _wapi_open (filename_ext, O_RDONLY, 0);
- if (fd == -1) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s: %s", __func__, filename_ext, strerror (errno));
+ fd = open (filename_ext, O_RDONLY, 0);
+ if (fd == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
+ gint saved_errno;
+ gchar *located_filename;
- SetLastError (_wapi_get_win32_file_error (errno));
- g_free (filename_ext);
+ saved_errno = errno;
- return(NULL);
+ located_filename = mono_portability_find_file (filename_ext, TRUE);
+ if (!located_filename) {
+ errno = saved_errno;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s (1): %s", __func__, filename_ext, strerror (errno));
+
+ g_free (filename_ext);
+
+ SetLastError (_wapi_get_win32_file_error (errno));
+ return NULL;
+ }
+
+ fd = open (located_filename, O_RDONLY, 0);
+ if (fd == -1) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s (2): %s", __func__, filename_ext, strerror (errno));
+
+ g_free (filename_ext);
+ g_free (located_filename);
+
+ SetLastError (_wapi_get_win32_file_error (errno));
+ return NULL;
+ }
+
+ g_free (located_filename);
}
if (fstat (fd, &statbuf) == -1) {
#include "w32process.h"
#include "w32process-internals.h"
#include "w32process-win32-internals.h"
+#include "w32file.h"
#include "object.h"
#include "object-internals.h"
#include "class.h"
#include "mono/utils/mono-logger-internals.h"
#include "mono/metadata/w32handle.h"
+#define MAX_PATH 260
+
typedef struct {
guint32 val;
gint32 max;
gpointer buf;
} WSABUF;
-typedef struct {
- guint32 Internal;
- guint32 InternalHigh;
- guint32 Offset;
- guint32 OffsetHigh;
- gpointer hEvent;
- gpointer handle1;
- gpointer handle2;
-} OVERLAPPED;
-
typedef struct {
gpointer Head;
guint32 HeadLength;
guint8 Data4[8];
} GUID;
+typedef struct {
+ guint32 Internal;
+ guint32 InternalHigh;
+ guint32 Offset;
+ guint32 OffsetHigh;
+ gpointer hEvent;
+ gpointer handle1;
+ gpointer handle2;
+} OVERLAPPED;
+
typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, OVERLAPPED*, guint32, guint32);
typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, guint32, guint32, OVERLAPPED*, TRANSMIT_FILE_BUFFERS*, guint32);
#include <mono/metadata/exception.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/appdomain.h>
-#include <mono/metadata/file-io.h>
+#include <mono/metadata/w32file.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/threadpool-io.h>
<ClCompile Include="..\mono\metadata\console-win32.c" />\r
<ClCompile Include="..\mono\metadata\property-bag.c" />\r
<ClCompile Include="..\mono\metadata\w32socket-win32.c" />\r
- <ClCompile Include="..\mono\metadata\file-io-windows.c" />\r
+ <ClCompile Include="..\mono\metadata\w32file-win32.c" />\r
<ClCompile Include="..\mono\metadata\icall-windows.c" />\r
<ClCompile Include="..\mono\metadata\marshal-windows.c" />\r
<ClCompile Include="..\mono\metadata\mono-security-windows.c" />\r
<ClCompile Include="..\mono\metadata\domain.c" />\r
<ClCompile Include="..\mono\metadata\environment.c" />\r
<ClCompile Include="..\mono\metadata\exception.c" />\r
- <ClCompile Include="..\mono\metadata\file-io.c" />\r
+ <ClCompile Include="..\mono\metadata\w32file.c" />\r
<ClCompile Include="..\mono\metadata\file-mmap-windows.c" />\r
<ClCompile Include="..\mono\metadata\filewatcher.c" />\r
<ClCompile Include="..\mono\metadata\gc-stats.c" />\r
<ClInclude Include="..\mono\metadata\dynamic-stream-internals.h" />\r
<ClInclude Include="..\mono\metadata\environment.h" />\r
<ClInclude Include="..\mono\metadata\exception.h" />\r
- <ClInclude Include="..\mono\metadata\file-io-internals.h" />\r
- <ClInclude Include="..\mono\metadata\file-io-windows-internals.h" />\r
- <ClInclude Include="..\mono\metadata\file-io.h" />\r
+ <ClInclude Include="..\mono\metadata\w32file-internals.h" />\r
+ <ClInclude Include="..\mono\metadata\w32file-win32-internals.h" />\r
+ <ClInclude Include="..\mono\metadata\w32file.h" />\r
<ClInclude Include="..\mono\metadata\filewatcher.h" />\r
<ClInclude Include="..\mono\metadata\gc-internals.h" />\r
<ClInclude Include="..\mono\metadata\handle.h" />\r
<ClCompile Include="..\mono\metadata\exception.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\mono\metadata\file-io.c">\r
+ <ClCompile Include="..\mono\metadata\w32file.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\mono\metadata\file-mmap-windows.c">\r
<ClCompile Include="..\mono\metadata\w32socket-win32.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\mono\metadata\file-io-windows.c">\r
+ <ClCompile Include="..\mono\metadata\w32file-win32.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\mono\metadata\icall-windows.c">\r
<ClInclude Include="..\mono\metadata\exception.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\mono\metadata\file-io.h">\r
+ <ClInclude Include="..\mono\metadata\w32file.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
<ClInclude Include="..\mono\metadata\filewatcher.h">\r
<ClInclude Include="..\mono\metadata\console-win32-internals.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\mono\metadata\file-io-windows-internals.h">\r
+ <ClInclude Include="..\mono\metadata\w32file-win32-internals.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\mono\metadata\file-io-internals.h">\r
+ <ClInclude Include="..\mono\metadata\w32file-internals.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
<ClInclude Include="..\mono\metadata\icall-internals.h">\r
<ClCompile Include="..\mono\metadata\console-win32.c" />\r
<ClCompile Include="..\mono\metadata\domain.c" />\r
<ClCompile Include="..\mono\metadata\environment.c" />\r
- <ClCompile Include="..\mono\metadata\file-io-windows.c" />\r
- <ClCompile Include="..\mono\metadata\file-io.c" />\r
+ <ClCompile Include="..\mono\metadata\w32file-win32.c" />\r
+ <ClCompile Include="..\mono\metadata\w32file.c" />\r
<ClCompile Include="..\mono\metadata\filewatcher.c" />\r
<ClCompile Include="..\mono\metadata\gc.c" />\r
<ClCompile Include="..\mono\metadata\icall-windows.c" />\r
<ClCompile Include="..\mono\metadata\environment.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\mono\metadata\file-io.c">\r
+ <ClCompile Include="..\mono\metadata\w32file.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\mono\metadata\filewatcher.c">\r
<ClCompile Include="..\mono\metadata\icall-windows.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\mono\metadata\file-io-windows.c">\r
+ <ClCompile Include="..\mono\metadata\w32file-win32.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
</ItemGroup>\r