[Mono-dev] [PATCH]System.IO.File.Replace

2007-08-15 Thread Bill Holmes
Attached is a patch that implements the 2.0 method File.IO.File.Replace.

http://msdn2.microsoft.com/en-us/library/9etk7xw2.aspx

Some implementation details are as follows.
-An internal call was added to perform this operation
-Most argument validation is performed in managed code.
-On windows we call ReplaceFile defined in Kernel32
-On !windows Replace file was implemented in io-layer/io.c

*file-io.c: Added ves_icall_System_IO_MonoIO_ReplaceFile to call
ReplaceFile Kernel32 on windows or in io-layer.
*file-io.h: Added deceleration for ves_icall_System_IO_MonoIO_ReplaceFile
*icall-def.h: Register ves_icall_System_IO_MonoIO_ReplaceFile as an
internal call.
*io.c: Added implementation for ReplaceFile.
*io.h: Added deceleration for ReplaceFile method.
*File.cs:  Add implementation for IO.File.Replace methods.
*MonoIO.cs: Declared an internal call for ReplaceFile
*FileTest.cs:  Added a test for IO.File.Replace.

This may be less of a patch request and more of a "Tell me what I did
wrong."  ;)

-bill


replaceFile.diff
Description: Binary data
___
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list


Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-15 Thread Rodrigo Kumpera
Hi Bill,

Below are some comments regarding your patch:

+
+return(ret);
+}

Don't use parentesis around the return value, it makes things harder to
read.

+int remain, n;
+int buf_size = st_src->st_blksize;
+char *buf = (char *) alloca (buf_size);
+

It's better to avoid alloca for quite a few reasons and on this case, it's
better to limit the maximum size of buf_size since it's value is outside
mono's control.

-
-g_free (utf8_src);
-g_free (utf8_dest);
-close (src_fd);
-close (dest_fd);
-
+
+g_free (utf8_replacedFileName);
+g_free (utf8_replacementFileName);
+g_free (utf8_backupFileName);
+close (backup_fd);
+

Notice here that you're introducing some redudant whitespaces in the empty
lines, this should be avoided as it make patches hard to read due to
increased noise.

Besides that, I have a question. Wouldn't be possible to use sendfile for
unix systems? Senfile skip copying data to user space and should be a lot
faster than using read/write.

Cheers!
Rodrigo


On 8/15/07, Bill Holmes <[EMAIL PROTECTED]> wrote:
>
> Attached is a patch that implements the 2.0 method File.IO.File.Replace.
>
> http://msdn2.microsoft.com/en-us/library/9etk7xw2.aspx
>
> Some implementation details are as follows.
> -An internal call was added to perform this operation
> -Most argument validation is performed in managed code.
> -On windows we call ReplaceFile defined in Kernel32
> -On !windows Replace file was implemented in io-layer/io.c
>
> *file-io.c: Added ves_icall_System_IO_MonoIO_ReplaceFile to call
> ReplaceFile Kernel32 on windows or in io-layer.
> *file-io.h: Added deceleration for ves_icall_System_IO_MonoIO_ReplaceFile
> *icall-def.h: Register ves_icall_System_IO_MonoIO_ReplaceFile as an
> internal call.
> *io.c: Added implementation for ReplaceFile.
> *io.h: Added deceleration for ReplaceFile method.
> *File.cs:  Add implementation for IO.File.Replace methods.
> *MonoIO.cs: Declared an internal call for ReplaceFile
> *FileTest.cs:  Added a test for IO.File.Replace.
>
> This may be less of a patch request and more of a "Tell me what I did
> wrong."  ;)
>
> -bill
>
> ___
> Mono-devel-list mailing list
> Mono-devel-list@lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-devel-list
>
>
>
___
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list


Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-15 Thread Leszek Ciesielski
> Besides that, I have a question. Wouldn't be possible to use sendfile for
> unix systems? Senfile skip copying data to user space and should be a lot
> faster than using read/write.

>From man:

" Other Unix systems implement sendfile() with different semantics and
prototypes.  It should not  be  used  in  portable  programs."

and

"In Linux 2.4 and earlier, out_fd could refer to a regular file" (in
2.6 it has to be a socket).
___
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list


Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-15 Thread Bill Holmes
Rodrigo,

I thought the ()'s around the return was a bit odd myself.  But since
I did not understand why they were in the existing code I kept the
pattern going.  I will remove them from my changes.

As for the alloca, that too is something I refactored out of the
CopyFile method.  I agree that can cause problems so I will look for
an alternative.

do you think I could get away with
int buf_size = st_src->st_blksize;
if (buf_size > 1024)
buf_size = 1024;
 char *buf = (char *) alloca (buf_size);

Or should I switch to dynamic allocation (malloc)?  Or should I use
dynamic allocation and cap the max?

I'll see what I can do to cleanup my messy whitespace.

sendfile could be a good solution for this method but as Leszek points
out this is probably not a reliable cross platform solution.  What I
am actually doing here is opening the backup file for read.  Then in
the event of an error I need to simply restore that file.  If I had
something like linkFile (int in_fd, const char *path) I would be
better off.

Thanks so much for you comments.  I will make improvements and re-submit.

-bill
___
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list


Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-15 Thread Miguel de Icaza
Hello,

> I thought the ()'s around the return was a bit odd myself.  But since
> I did not understand why they were in the existing code I kept the
> pattern going.  I will remove them from my changes.

The io-layer is an exception to the coding guidelines of Mono.   Dick
Porter tends to use the return (value) pattern.   For the sake of
consistency with that code we should probably keep that.

Miguel
___
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list


Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-16 Thread Paolo Molaro
On 08/15/07 Bill Holmes wrote:
> I thought the ()'s around the return was a bit odd myself.  But since
> I did not understand why they were in the existing code I kept the
> pattern going.  I will remove them from my changes.

Thanks: new code also in the io-layer should follow the mono
conventions (we just don't usually go around and fix it to avoid losing
th history).

> As for the alloca, that too is something I refactored out of the
> CopyFile method.  I agree that can cause problems so I will look for
> an alternative.
> 
> do you think I could get away with
> int buf_size = st_src->st_blksize;
> if (buf_size > 1024)
> buf_size = 1024;
>  char *buf = (char *) alloca (buf_size);
> 
> Or should I switch to dynamic allocation (malloc)?  Or should I use
> dynamic allocation and cap the max?

Just use malloc: the amount of memory that we'd allow to be allocated
with alloca (100-200 bytes) would be useless for this usage.
The buffer size should also have a lower and upper limit (8-64 KB
is reasonable).

lupus

-- 
-
[EMAIL PROTECTED] debian/rules
[EMAIL PROTECTED] Monkeys do it better
___
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list


Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-16 Thread Paolo Molaro
On 08/15/07 Bill Holmes wrote:
> Attached is a patch that implements the 2.0 method File.IO.File.Replace.
> 
> http://msdn2.microsoft.com/en-us/library/9etk7xw2.aspx

Please mark your patch attachments as text files instead of as binary
blobs, thanks!

> Index: mono/mono/metadata/file-io.c
> ===
> --- mono/mono/metadata/file-io.c  (revision 84157)
> +++ mono/mono/metadata/file-io.c  (working copy)
> @@ -10,6 +10,11 @@
>   */
>  
>  #include 
> +
> +#ifdef PLATFORM_WIN32
> +#define _WIN32_WINNT 0x0500
> +#endif
> +
>  #include 
>  #include 
>  #include 
> @@ -384,6 +389,40 @@
>  }
>  
>  MonoBoolean
> +ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, 
> MonoString *destinationFileName,
> + MonoString *destinationBackupFileName, 
> MonoBoolean ignoreMetadataErrors,
> + gint32 *error)
> +{
> + gboolean ret;
> + gunichar2 *utf16_sourceFileName=NULL, *utf16_destinationFileName=NULL, 
> *utf16_destinationBackupFileName=NULL;
> + guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
> + 
> + MONO_ARCH_SAVE_REGS;
> +
> + 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;

Please make new code follow the mono coding conventions: space before
parens, spaces around operators like = etc.

>  #endif /* _MONO_METADATA_FILEIO_H_ */
> Index: mono/mono/metadata/icall-def.h
> ===
> --- mono/mono/metadata/icall-def.h(revision 84157)
> +++ mono/mono/metadata/icall-def.h(working copy)
> @@ -270,22 +270,25 @@
>  ICALL(MONOIO_16, 
> "Open(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.IO.FileOptions,System.IO.MonoIOError&)",
>  ves_icall_System_IO_MonoIO_Open)
>  ICALL(MONOIO_17, "Read(intptr,byte[],int,int,System.IO.MonoIOError&)", 
> ves_icall_System_IO_MonoIO_Read)
>  ICALL(MONOIO_18, "RemoveDirectory(string,System.IO.MonoIOError&)", 
> ves_icall_System_IO_MonoIO_RemoveDirectory)
> -ICALL(MONOIO_19, 
> "Seek(intptr,long,System.IO.SeekOrigin,System.IO.MonoIOError&)", 
> ves_icall_System_IO_MonoIO_Seek)

As written at the beginning of this file, do not rename all the entries,
just add the icall in the correctly sorted place. The sequential name is
meanlingless, you could use MONOIO_18M or MONOIO_185 in this case.

> +ICALL(MONOIO_31, "get_DirectorySeparatorChar", 
> ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar)
> +ICALL(MONOIO_32, "get_InvalidPathChars", 
> ves_icall_System_IO_MonoIO_get_InvalidPathChars)
> +ICALL(MONOIO_33, "get_PathSeparator", 
> ves_icall_System_IO_MonoIO_get_PathSeparator)
> +ICALL(MONOIO_34, "get_VolumeSeparatorChar", 
> ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar)
>  
> +
> +

Please don't add random withspace to the code.

> Index: mono/mono/io-layer/io.c
> ===
> --- mono/mono/io-layer/io.c   (revision 84157)
> +++ mono/mono/io-layer/io.c   (working copy)
> @@ -1835,6 +1835,51 @@
>   return(ret);
>  }
>  
> +gboolean write_file (int src_fd, int dest_fd, struct stat *st_src, gboolean 
> report_errors)
> +{
> + int remain, n;
> + int buf_size = st_src->st_blksize;
> + char *buf = (char *) alloca (buf_size);
> +
> + for (;;) {
> + remain = read (src_fd, buf, buf_size);
> + 
> + if (remain < 0) {
> + if (errno == EINTR && !_wapi_thread_cur_apc_pending ()) 
> {
> + continue;
> + }
> + 
> + if (report_errors)
> + _wapi_set_last_error_from_errno ();
> + 
> + return(FALSE);
> + }
> + 
> + if (remain == 0) {
> + break;
> + }
> +
> + while (remain > 0) {
> + if ((n = write (dest_fd, buf, remain)) < 0) {
> + if (errno == EINTR && 
> !_wapi_thread_cur_apc_pending ())
> + continue;
> +
> + if (report_errors)
> + _wapi_set_last_error_from_errno ();
> +#ifdef DEBUG
> + g_message ("%s: write failed.", __func__);
> +#endif
> +
> + return (FALSE);
> + }
> +
> + remain -= n;
> + }
> + }
> +
> + return (TRUE);
> +}
> +
>  /**
>   * CopyFile:
>   * @name: a pointer to 

Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-17 Thread Bill Holmes
All,

Here is an updated version of my patch.  I apologize in advance if my
attachment is a "binary blob" again.  I am not quite sure what that
meant or what I should do about it.  This time I am sending the mail
from SUSE so maybe that will help.

I have applied the changes mentioned by Rodrigo and Paolo including
-removed alloca.
-adding gotos to avoid duplicate cleanup code.
-fixed numbering oversight in icall-def
-formatted the code to follow the coding guidelines. (including the
return statements)
-cleaned up my white space mess.

Round 2.  What did I miss this time?  ;)

Thanks so much for you comments.

-bill
Index: mono/mono/metadata/file-io.c
===
--- mono/mono/metadata/file-io.c	(revision 84326)
+++ mono/mono/metadata/file-io.c	(working copy)
@@ -10,6 +10,11 @@
  */
 
 #include 
+
+#ifdef PLATFORM_WIN32
+#define _WIN32_WINNT 0x0500
+#endif
+
 #include 
 #include 
 #include 
@@ -384,6 +389,36 @@
 }
 
 MonoBoolean
+ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
+	MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
+	gint32 *error)
+{
+	gboolean ret;
+	gunichar2 *utf16_sourceFileName = NULL, *utf16_destinationFileName = NULL, *utf16_destinationBackupFileName = NULL;
+	guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
+
+	MONO_ARCH_SAVE_REGS;
+
+	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;
+
+	ret = ReplaceFile (utf16_destinationFileName, utf16_sourceFileName, utf16_destinationBackupFileName,
+			 replaceFlags, NULL, NULL);
+	if (ret == FALSE)
+		*error = GetLastError ();
+
+	return ret;
+}
+
+MonoBoolean
 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
  MonoBoolean overwrite, gint32 *error)
 {
Index: mono/mono/metadata/file-io.h
===
--- mono/mono/metadata/file-io.h	(revision 84326)
+++ mono/mono/metadata/file-io.h	(working copy)
@@ -230,6 +230,11 @@
 extern void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
 	   gint64 length, gint32 *error) MONO_INTERNAL;
 
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
+	MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
+	gint32 *error) MONO_INTERNAL;
+
 G_END_DECLS
 
 #endif /* _MONO_METADATA_FILEIO_H_ */
Index: mono/mono/metadata/icall-def.h
===
--- mono/mono/metadata/icall-def.h	(revision 84326)
+++ mono/mono/metadata/icall-def.h	(working copy)
@@ -270,6 +270,7 @@
 ICALL(MONOIO_16, "Open(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.IO.FileOptions,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_Open)
 ICALL(MONOIO_17, "Read(intptr,byte[],int,int,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_Read)
 ICALL(MONOIO_18, "RemoveDirectory(string,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_RemoveDirectory)
+ICALL(MONOIO_18M, "ReplaceFile(string,string,string,bool,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_ReplaceFile)
 ICALL(MONOIO_19, "Seek(intptr,long,System.IO.SeekOrigin,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_Seek)
 ICALL(MONOIO_20, "SetCurrentDirectory(string,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_SetCurrentDirectory)
 ICALL(MONOIO_21, "SetFileAttributes(string,System.IO.FileAttributes,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_SetFileAttributes)
Index: mono/mono/io-layer/io.c
===
--- mono/mono/io-layer/io.c	(revision 84326)
+++ mono/mono/io-layer/io.c	(working copy)
@@ -1835,6 +1835,55 @@
 	return(ret);
 }
 
+gboolean write_file (int src_fd, int dest_fd, struct stat *st_src, gboolean report_errors)
+{
+	int remain, n;
+	char *buf;
+	int buf_size = st_src->st_blksize;
+	gboolean ret = FALSE;
+
+	buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : buf_size);
+	buf = (char *) malloc (buf_size);
+
+	for (;;) {
+		remain = read (src_fd, buf, buf_size);
+		if (remain < 0) {
+			if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
+continue;
+
+			if (report_errors)
+_wapi_set_last_error_from_errno ();
+
+			goto write_file_cleanup;
+		}
+		if (remain == 0) {
+			break;
+		}
+
+		while (remain > 0) {
+			if ((n = write (dest_fd, buf, remain)) < 0) {
+if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
+	continue;
+
+if (report_errors)
+	_wapi_set_last_error_from_errno ();
+#ifdef DE

Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-20 Thread Paolo Molaro
On 08/17/07 Bill Holmes wrote:
> Here is an updated version of my patch.  I apologize in advance if my
> attachment is a "binary blob" again.  I am not quite sure what that
> meant or what I should do about it.  This time I am sending the mail
> from SUSE so maybe that will help.

It looks good now:) Binary blob means that the patch you sent was marked
as an attachment of mime-type octect-stream (octect-stream is another
name for binary blob) instead of the text file it is.

> Index: mono/mono/io-layer/io.c
> ===
> --- mono/mono/io-layer/io.c   (revision 84326)
> +++ mono/mono/io-layer/io.c   (working copy)
> @@ -1835,6 +1835,55 @@
>   return(ret);
>  }
>  
> +gboolean write_file (int src_fd, int dest_fd, struct stat *st_src, gboolean 
> report_errors)
> +{
> + int remain, n;
> + char *buf;
> + int buf_size = st_src->st_blksize;
> + gboolean ret = FALSE;
> +
> + buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : 
> buf_size);
> + buf = (char *) malloc (buf_size);
> +
> + for (;;) {
> + remain = read (src_fd, buf, buf_size);
> + if (remain < 0) {
> + if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
> + continue;
> +
> + if (report_errors)
> + _wapi_set_last_error_from_errno ();
> +
> + goto write_file_cleanup;
> + }
> + if (remain == 0) {
> + break;
> + }
> +
> + while (remain > 0) {
> + if ((n = write (dest_fd, buf, remain)) < 0) {
> + if (errno == EINTR && 
> !_wapi_thread_cur_apc_pending ())
> + continue;
> +
> + if (report_errors)
> + _wapi_set_last_error_from_errno ();
> +#ifdef DEBUG
> + g_message ("%s: write failed.", __func__);
> +#endif
> + goto write_file_cleanup;
> + }
> +
> + remain -= n;
> + }
> + }
> +
> + ret = TRUE;
> +
> +write_file_cleanup:
> + free (buf);
> + return ret ;

In this function I wouldn't use goto (I don't think I asked for this
change): the cleanup code is very simple.
Anyway, this change made me incpect the code more and there seems to be
a bug: in the case of a short write, we try to repeatedly write always
from the start of the buffer, instead of advancing into it. This causes
corruption and needs fixing.

> +gchar* convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name)

Here and in the other places, put the function name at the start of a
line, with the return type and storage type in their own line.

Thanks!
lupus

-- 
-
[EMAIL PROTECTED] debian/rules
[EMAIL PROTECTED] Monkeys do it better
___
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list


Re: [Mono-dev] [PATCH]System.IO.File.Replace

2007-08-20 Thread Bill Holmes
goto removed
short write case fixed
function definition formatting fixed

thanks
-bill
Index: mono/mono/metadata/file-io.c
===
--- mono/mono/metadata/file-io.c	(revision 84466)
+++ mono/mono/metadata/file-io.c	(working copy)
@@ -10,6 +10,11 @@
  */
 
 #include 
+
+#ifdef PLATFORM_WIN32
+#define _WIN32_WINNT 0x0500
+#endif
+
 #include 
 #include 
 #include 
@@ -384,6 +389,36 @@
 }
 
 MonoBoolean
+ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
+	MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
+	gint32 *error)
+{
+	gboolean ret;
+	gunichar2 *utf16_sourceFileName = NULL, *utf16_destinationFileName = NULL, *utf16_destinationBackupFileName = NULL;
+	guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
+
+	MONO_ARCH_SAVE_REGS;
+
+	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;
+
+	ret = ReplaceFile (utf16_destinationFileName, utf16_sourceFileName, utf16_destinationBackupFileName,
+			 replaceFlags, NULL, NULL);
+	if (ret == FALSE)
+		*error = GetLastError ();
+
+	return ret;
+}
+
+MonoBoolean
 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
  MonoBoolean overwrite, gint32 *error)
 {
Index: mono/mono/metadata/file-io.h
===
--- mono/mono/metadata/file-io.h	(revision 84466)
+++ mono/mono/metadata/file-io.h	(working copy)
@@ -230,6 +230,11 @@
 extern void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
 	   gint64 length, gint32 *error) MONO_INTERNAL;
 
+extern MonoBoolean
+ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
+	MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
+	gint32 *error) MONO_INTERNAL;
+
 G_END_DECLS
 
 #endif /* _MONO_METADATA_FILEIO_H_ */
Index: mono/mono/metadata/icall-def.h
===
--- mono/mono/metadata/icall-def.h	(revision 84466)
+++ mono/mono/metadata/icall-def.h	(working copy)
@@ -271,6 +271,7 @@
 ICALL(MONOIO_16, "Open(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.IO.FileOptions,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_Open)
 ICALL(MONOIO_17, "Read(intptr,byte[],int,int,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_Read)
 ICALL(MONOIO_18, "RemoveDirectory(string,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_RemoveDirectory)
+ICALL(MONOIO_18M, "ReplaceFile(string,string,string,bool,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_ReplaceFile)
 ICALL(MONOIO_19, "Seek(intptr,long,System.IO.SeekOrigin,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_Seek)
 ICALL(MONOIO_20, "SetCurrentDirectory(string,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_SetCurrentDirectory)
 ICALL(MONOIO_21, "SetFileAttributes(string,System.IO.FileAttributes,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_SetFileAttributes)
Index: mono/mono/io-layer/io.c
===
--- mono/mono/io-layer/io.c	(revision 84466)
+++ mono/mono/io-layer/io.c	(working copy)
@@ -1835,6 +1835,56 @@
 	return(ret);
 }
 
+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;
+
+	buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : buf_size);
+	buf = (char *) malloc (buf_size);
+
+	for (;;) {
+		remain = read (src_fd, buf, buf_size);
+		if (remain < 0) {
+			if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
+continue;
+
+			if (report_errors)
+_wapi_set_last_error_from_errno ();
+
+			free (buf);
+			return FALSE;
+		}
+		if (remain == 0) {
+			break;
+		}
+
+		wbuf = buf;
+		while (remain > 0) {
+			if ((n = write (dest_fd, wbuf, remain)) < 0) {
+if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
+	continue;
+
+if (report_errors)
+	_wapi_set_last_error_from_errno ();
+#ifdef DEBUG
+g_message ("%s: write failed.", __func__);
+#endif
+free (buf);
+return FALSE;
+			}
+
+			remain -= n;
+			wbuf += n;
+		}
+	}
+
+	free (buf);
+	return TRUE ;
+}
+
 /**
  * CopyFile:
  * @name: a pointer to a NULL-terminated unicode string, that names
@@ -1852,10 +1902,8 @@
 {
 	gchar *utf8_src, *utf8_dest;
 	int src_fd, dest_fd;
-	int buf_size;
-	char *buf;
-	int remain, n;
 	struct stat st;
+	gboolean ret = TRUE;
 	
 	if(name==NULL) {
 #ifdef DEBUG
@@ -1945,63 +1993,107 @@
 		g_free (utf8_src);
 		g_free (u