#include <fnmatch.h>
#include <stdio.h>
#include <utime.h>
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#endif
#include <mono/io-layer/wapi.h>
#include <mono/io-layer/wapi-private.h>
g_free (file_handle->filename);
- _wapi_handle_share_release (file_handle->share_info);
+ if (file_handle->share_info)
+ _wapi_handle_share_release (file_handle->share_info);
close (GPOINTER_TO_UINT(handle));
}
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) {
+#ifdef DEBUG
+ g_message ("%s: handle %p ioctl BLKGETSIZE64 failed: %s",
+ __func__, handle, strerror(errno));
+#endif
+
+ _wapi_set_last_error_from_errno ();
+ return(INVALID_FILE_SIZE);
+ }
+
+ size = bigsize & 0xFFFFFFFF;
+ if (highsize != NULL) {
+ *highsize = bigsize>>32;
+ }
+
+#ifdef DEBUG
+ g_message ("%s: Returning block device size %d/%d",
+ __func__, size, *highsize);
+#endif
+
+ return(size);
+ }
+#endif
+
#ifdef HAVE_LARGE_FILE_SUPPORT
size = statbuf.st_size & 0xFFFFFFFF;
if (highsize != NULL) {
return(flags);
}
-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 {
-#ifdef DEBUG
- g_message("%s: Can't figure out flags 0x%x", __func__, flags);
-#endif
- }
-
- /* Maybe sort out create mode too */
-
- return(fileaccess);
-}
-
#if 0 /* unused */
static mode_t convert_perms(guint32 sharemode)
{
if (fd == -1 && errno == EISDIR)
{
/* Try again but don't try to make it writable */
- fd = open(filename, flags & ~(O_RDWR|O_WRONLY), perms);
+ fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms);
}
if (fd == -1) {
g_free (filename);
return FALSE;
}
- _wapi_handle_share_release (shareinfo);
+ if (shareinfo)
+ _wapi_handle_share_release (shareinfo);
#endif
retval = _wapi_unlink (filename);
* the same file as src.
*/
if (_wapi_stat (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 (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)) {
SetLastError (ERROR_SHARING_VIOLATION);
return FALSE;
}
- _wapi_handle_share_release (shareinfo);
+ if (shareinfo)
+ _wapi_handle_share_release (shareinfo);
result = _wapi_rename (utf8_name, utf8_dest_name);
errno_copy = errno;
{
gchar *utf8_src, *utf8_dest;
int src_fd, dest_fd;
- struct stat st;
+ struct stat st, dest_st;
gboolean ret = TRUE;
if(name==NULL) {
if(dest_name==NULL) {
#ifdef DEBUG
- g_message("%s: name is NULL", __func__);
+ g_message("%s: dest is NULL", __func__);
#endif
g_free (utf8_src);
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 = open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL,
- st.st_mode);
+ dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL, st.st_mode);
} else {
- dest_fd = open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode);
+ /* 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) {
- /* O_TRUNC might cause a fail if the file
- * doesn't exist
- */
- dest_fd = open (utf8_dest, O_WRONLY | O_CREAT,
- st.st_mode);
+ /* 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
_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 = open (utf8_backupFileName, O_WRONLY | O_CREAT | O_TRUNC,
- stBackup.st_mode);
- if (replaced_fd == -1) {
- replaced_fd = open (utf8_backupFileName, O_WRONLY | O_CREAT,
- stBackup.st_mode);
- }
+ replaced_fd = _wapi_open (utf8_backupFileName, O_WRONLY | O_CREAT | O_TRUNC,
+ stBackup.st_mode);
+
if (replaced_fd == -1)
goto replace_cleanup;
return ret;
}
-static gpointer stdhandle_create (int fd, const gchar *name)
-{
- struct _WapiHandle_file file_handle = {0};
- gpointer handle;
- int flags;
-
-#ifdef DEBUG
- g_message("%s: creating standard handle type %s, fd %d", __func__,
- name, fd);
-#endif
-
- /* 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
- */
-#ifdef DEBUG
- g_message("%s: fcntl error on fd %d: %s", __func__, fd,
- strerror(errno));
-#endif
-
- _wapi_set_last_error_from_errno ();
- return(INVALID_HANDLE_VALUE);
- }
-
- file_handle.filename = g_strdup(name);
- /* some default security attributes might be needed */
- file_handle.security_attributes=0;
- file_handle.fileaccess=convert_from_flags(flags);
-
- /* 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 = _wapi_handle_new_fd (WAPI_HANDLE_CONSOLE, fd, &file_handle);
- if (handle == _WAPI_HANDLE_INVALID) {
- g_warning ("%s: error creating file handle", __func__);
- SetLastError (ERROR_GEN_FAILURE);
- return(INVALID_HANDLE_VALUE);
- }
-
-#ifdef DEBUG
- g_message("%s: returning handle %p", __func__, handle);
-#endif
-
- return(handle);
-}
-
/**
* GetStdHandle:
* @stdhandle: specifies the file descriptor
(gpointer *)&file_handle);
if (ok == FALSE) {
/* Need to create this console handle */
- handle = stdhandle_create (fd, name);
+ handle = _wapi_stdhandle_create (fd, name);
if (handle == INVALID_HANDLE_VALUE) {
SetLastError (ERROR_NO_MORE_FILES);
return(ret);
}
+/* 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';
+}
+
gint32
GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
{
continue;
}
- dir = g_utf8_to_utf16 (*(splitted + 1), -1, &length, NULL, NULL);
+ 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 */
}
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());
#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);
isreadonly = ((fsstat.f_flags & MNT_RDONLY) == MNT_RDONLY);
+ block_size = fsstat.f_bsize;
#endif
} while(ret == -1 && errno == EINTR);
free_bytes_avail->QuadPart = 0;
}
else {
- free_bytes_avail->QuadPart = fsstat.f_bsize * fsstat.f_bavail;
+ 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 = fsstat.f_bsize * fsstat.f_blocks;
+ total_number_of_bytes->QuadPart = block_size * (guint64)fsstat.f_blocks;
}
/* total number of bytes available for root */
total_number_of_free_bytes->QuadPart = 0;
}
else {
- total_number_of_free_bytes->QuadPart = fsstat.f_bsize * fsstat.f_bfree;
+ total_number_of_free_bytes->QuadPart = block_size * (guint64)fsstat.f_bfree;
}
}