[project @ 2003-07-10 19:25:58 by sof]
authorsof <unknown>
Thu, 10 Jul 2003 19:25:59 +0000 (19:25 +0000)
committersof <unknown>
Thu, 10 Jul 2003 19:25:59 +0000 (19:25 +0000)
For System.Directory.renameFile on Win32 platforms, implement the Haskell98
semantics of replacing the target file if it already exists (i.e.,
file/directory renaming is now done by dirUtils.c:__hscore_renameFile().)

Document that System.Directory.renameDirectory will fail on Win32 boxes should
the target directory exist.

Merge to STABLE, I suppose.

System/Directory.hs
System/Posix/Internals.hs
cbits/dirUtils.c
include/dirUtils.h

index d37a364..17672c5 100644 (file)
@@ -292,6 +292,9 @@ renaming directories in all situations (e.g. renaming to an existing
 directory, or across different physical devices), but the constraints
 must be documented.
 
+On Win32 platforms, @renameDirectory@ fails if the /new/ directory already
+exists.
+
 The operation may fail with:
 
 * 'HardwareFault'
index 47362ed..575ec66 100644 (file)
@@ -354,7 +354,7 @@ foreign import ccall unsafe "HsBase.h read"
 foreign import ccall unsafe "HsBase.h readdir" 
    c_readdir :: Ptr CDir -> IO (Ptr CDirent)
 
-foreign import ccall unsafe "HsBase.h rename"
+foreign import ccall unsafe "dirUtils.h __hscore_renameFile"
    c_rename :: CString -> CString -> IO CInt
                     
 foreign import ccall unsafe "HsBase.h rewinddir"
index 8d94a45..316a689 100644 (file)
@@ -65,3 +65,73 @@ __hscore_readdir( HsAddr dirPtr, HsAddr pDirEnt )
   }  
 #endif
 }
+
+/*
+ * Function: __hscore_renameFile()
+ *
+ * Provide Haskell98's semantics for renaming files and directories.
+ * It mirrors that of POSIX.1's behaviour for rename() by overwriting
+ * the target if it exists (the MS CRT implementation of rename() returns
+ * an error
+ *
+ */
+HsInt
+__hscore_renameFile( HsAddr src,
+                    HsAddr dest)
+{
+#if defined(_MSC_VER) || defined(_WIN32)
+    static int forNT = -1;
+    DWORD rc;
+    
+    /* ToDo: propagate error codes back */
+    if (MoveFileA(src, dest)) {
+       return 0;
+    } else {
+       rc = GetLastError();
+    }
+    
+    /* Failed...it could be because the target already existed. */
+    if ( !GetFileAttributes(dest) ) {
+       /* No, it's not there - just fail. */
+       errno = 0;
+       return (-1);
+    }
+
+    if (forNT == -1) {
+       OSVERSIONINFO ovi;
+       ovi.dwOSVersionInfoSize = sizeof(ovi);
+       if ( !GetVersionEx(&ovi) ) {
+           errno = 0; 
+           return (-1);
+       }
+       forNT = ((ovi.dwPlatformId & VER_PLATFORM_WIN32_NT) != 0);
+    }
+    
+    if (forNT) {
+       /* Easy, go for MoveFileEx() */
+       if ( MoveFileExA(src, dest, MOVEFILE_REPLACE_EXISTING) ) {
+           return 0;
+       } else {
+           errno = 0; 
+           return (-1);
+       }
+    }
+
+    /* No MoveFileEx() for Win9x, try deleting the target. */
+    /* Similarly, if the MoveFile*() ops didn't work out under NT */
+    if (DeleteFileA(dest)) {
+       if (MoveFileA(src,dest)) {
+           return 0;
+       } else {
+           errno = 0;
+           return (-1);
+       }
+    } else {
+       errno = 0;
+       return (-1);
+    }
+#else
+    return rename(src,dest);
+#endif
+}
+
index fb91ba1..ce11b08 100644 (file)
@@ -7,5 +7,6 @@
 #define __DIRUTILS_H__
 
 extern HsInt __hscore_readdir(HsAddr dirPtr, HsAddr pDirEnt);
+extern HsInt __hscore_renameFile(HsAddr src, HsAddr dest);
 
 #endif /* __DIRUTILS_H__ */