These patches implement the win32 side of Ian's Compat.hs patches, with a
couple of additional fixes. Tested on Windows XP with both ghc-6.2.2 and 6.4.

The hsc2hs one is a bit ugly, the problem is that win32 hsc2hs doesn't handle
forward slashes for its output argument, for some reason. At least not my
version.



Sat Jul 30 02:48:29 CEST 2005  Ian Lynagh <[EMAIL PROTECTED]>
  * Start Compat.hs, and move stdout_is_a_pipe from compat.c

Sat Jul 30 03:01:18 CEST 2005  Ian Lynagh <[EMAIL PROTECTED]>
  * Remove unused function

Sat Jul 30 04:09:18 CEST 2005  Ian Lynagh <[EMAIL PROTECTED]>
  * Move mkstemp to Compat.hs

Sat Jul 30 14:22:55 CEST 2005  Ian Lynagh <[EMAIL PROTECTED]>
  * Remove is_symlink

Sat Jul 30 15:12:05 CEST 2005  Ian Lynagh <[EMAIL PROTECTED]>
  * Move maybe_relink out of compat.c

Sat Jul 30 15:40:30 CEST 2005  Ian Lynagh <[EMAIL PROTECTED]>
  * Split the raw mode stuff out into its own .hsc file. Windows needs some TLC

Sat Jul 30 16:17:03 CEST 2005  Ian Lynagh <[EMAIL PROTECTED]>
  * Move atomic_create/sloppy_atomic_create to Compat

Sun Jul 31 13:40:11 CEST 2005  [EMAIL PROTECTED]
  * Rename compat.c to c_compat.c to avoid object filename conflict with 
Compat.hs

Tue Aug  9 00:04:44 CEST 2005  [EMAIL PROTECTED]
  * call hsc2hs without output filename argument

Tue Aug  9 22:01:48 CEST 2005  [EMAIL PROTECTED]
  * implement RawMode with library functions instead of ffi

Tue Aug  9 22:04:33 CEST 2005  [EMAIL PROTECTED]
  * Implement parts of System.Posix.(IO|Files) for win32

Wed Aug 10 23:13:03 CEST 2005  Peter Strand <[EMAIL PROTECTED]>
  * fix mkstemp implementation for win32

New patches:

[Start Compat.hs, and move stdout_is_a_pipe from compat.c
Ian Lynagh <[EMAIL PROTECTED]>**20050730004829] {
addfile ./Compat.hs
hunk ./Compat.hs 1
+
+module Compat (stdout_is_a_pipe) where
+
+import System.Posix.Files ( getFdStatus, isNamedPipe )
+import System.Posix.IO ( stdOutput )
+
+stdout_is_a_pipe :: IO Bool
+stdout_is_a_pipe
+ = do stat <- getFdStatus stdOutput
+      return (isNamedPipe stat)
+
hunk ./GNUmakefile 21
-	CheckFileSystem.lhs ColourPrinter.lhs Curl.hs DarcsIO.lhs	\
+	CheckFileSystem.lhs ColourPrinter.lhs Compat.hs Curl.hs DarcsIO.lhs	\
hunk ./SignalHandler.lhs 32
-import Foreign.C ( CInt )
hunk ./SignalHandler.lhs 33
+import Compat ( stdout_is_a_pipe )
hunk ./SignalHandler.lhs 43
-foreign import ccall unsafe "static compat.h stdout_is_a_pipe"
-        stdout_is_a_pipe :: IO CInt
-
hunk ./SignalHandler.lhs 58
-                   when (is_pipe /= 0) $
+                   when is_pipe $
hunk ./compat.c 13
-int stdout_is_a_pipe() {
-    struct stat s;
-    int ret;
-    ret = fstat(STDOUT_FILENO, &s);
-    if (ret == 0)
-        return !S_ISFIFO(s.st_mode);
-    else
-        return 0;
-}
-
hunk ./compat.h 26
-int stdout_is_a_pipe();
-
}

[Remove unused function
Ian Lynagh <[EMAIL PROTECTED]>**20050730010118] {
hunk ./compat.c 183
-int pipe(int fildes[2]) {
-    return _pipe(fildes, 8 * (2<<10), O_BINARY);
-}
-
}

[Move mkstemp to Compat.hs
Ian Lynagh <[EMAIL PROTECTED]>**20050730020918] {
hunk ./Compat.hs 2
-module Compat (stdout_is_a_pipe) where
+{-# OPTIONS -fffi #-}
hunk ./Compat.hs 4
+module Compat (stdout_is_a_pipe, mkstemp, mk_stdout_temp, canonFilename) where
+
+import DarcsUtils ( withCurrentDirectory )
+#ifdef WIN32
+import DarcsUtils ( showHexLen )
+#endif
+
+#ifdef WIN32
+import Control.Exception ( Exception(IOException), throwIO )
+#endif
+import Control.Monad ( liftM )
+#ifdef WIN32
+import Data.Bits ( (.&.) )
+#endif
+#ifndef WIN32
+import Foreign.C.Error ( throwErrno )
+import Foreign.C.String ( CString, withCString, peekCString )
+import Foreign.C.Types ( CInt )
+#endif
+import System.Directory ( getCurrentDirectory )
+import System.IO ( Handle, hFlush, stdout, stderr, hSetBuffering,
+                   BufferMode(NoBuffering), hSetBinaryMode )
+#ifdef WIN32
+import System.IO.Error ( mkIOError, illegalOperationErrorType )
+#endif
hunk ./Compat.hs 30
-import System.Posix.IO ( stdOutput )
+#ifdef WIN32
+import System.Posix.Files ( stdFileMode )
+#endif
+import System.Posix.IO ( stdOutput, stdError, fdToHandle, dupTo )
+#ifdef WIN32
+import System.Posix.IO ( defaultFileFlags, openFd,
+                         exclusive, OpenMode(WriteOnly) )
+#endif
+import System.Posix.Types ( Fd(..) )
+#ifdef WIN32
+import System.Random ( randomIO )
+#endif
hunk ./Compat.hs 47
+
+canonFilename :: FilePath -> IO FilePath
+canonFilename f@(_:':':_) = return f -- absolute windows paths
+canonFilename f@('/':_) = return f
+canonFilename ('.':'/':f) = do cd <- getCurrentDirectory
+                               return $ cd ++ "/" ++ f
+canonFilename f = case reverse $ dropWhile (/='/') $ reverse f of
+                  "" -> liftM (++('/':f)) getCurrentDirectory
+                  rd -> withCurrentDirectory rd $
+                          do fd <- getCurrentDirectory
+                             return $ fd ++ "/" ++ simplefilename
+    where
+    simplefilename = reverse $ takeWhile (/='/') $ reverse f
+
+#ifdef WIN32
+mkstemp_core :: FilePath -> IO (Fd, String)
+mkstemp_core fp
+ = do fp' <- case splitAt 6 fp of
+                 ("XXXXXX", rev_fp) -> return $ reverse rev_fp
+                 _ -> let e = mkIOError illegalOperationErrorType
+                                        "mkstemp" Nothing (Just fp)
+                      in throwIO (IOException e)
+      r <- randomIO
+      let fp'' = fp' ++ (showHexLen 6 (r .&. 0xFFFFFF :: Int))
+      fd <- openFd fp WriteOnly (Just stdFileMode) flags
+      return (fd, fp'')
+  where flags = defaultFileFlags { exclusive = True }
+#else
+mkstemp_core :: String -> IO (Fd, String)
+mkstemp_core str = withCString (str++"XXXXXX") $
+    \cstr -> do fd <- c_mkstemp cstr
+                if fd < 0
+                  then throwErrno $ "Failed to create temporary file "++str
+                  else do str' <- peekCString cstr
+                          fname <- canonFilename str'
+                          return (Fd fd, fname)
+
+foreign import ccall unsafe "static stdlib.h mkstemp"
+    c_mkstemp :: CString -> IO CInt
+#endif
+
+mkstemp :: String -> IO (Handle, String)
+mkstemp str = do (fd, fn) <- mkstemp_core str
+                 h <- fdToHandle fd
+                 hSetBinaryMode h True
+                 return (h, fn)
+
+mk_stdout_temp :: String -> IO String
+mk_stdout_temp str = do (fd, fn) <- mkstemp_core str
+                        hFlush stdout
+                        hFlush stderr
+                        dupTo fd stdOutput
+                        dupTo fd stdError
+                        hFlush stdout
+                        hFlush stderr
+                        hSetBuffering stdout NoBuffering
+                        hSetBuffering stderr NoBuffering
+                        return fn
hunk ./DarcsUtils.lhs 9
+                    showHexLen,
hunk ./DarcsUtils.lhs 12
+import Numeric ( showHex )
hunk ./DarcsUtils.lhs 25
+
+showHexLen :: (Integral a) => Int -> a -> String
+showHexLen n x = let s = showHex x ""
+                 in replicate (n - length s) ' ' ++ s
hunk ./Lock.lhs 37
-import GHC.Handle ( hSetBinaryMode )
hunk ./Lock.lhs 44
-import Foreign.C ( withCString, CString, peekCString,
+import Foreign.C ( withCString, CString,
hunk ./Lock.lhs 47
-import Workaround ( fileMode, getFileStatus, setFileMode, openFd, )
+import Workaround ( fileMode, getFileStatus, setFileMode )
hunk ./Lock.lhs 57
+import Compat ( mkstemp, mk_stdout_temp, canonFilename )
hunk ./Lock.lhs 111
-
-canonFilename :: FilePath -> IO FilePath
-canonFilename f@(_:':':_) = return f -- absolute windows paths
-canonFilename f@('/':_) = return f
-canonFilename ('.':'/':f) = do cd <- getCurrentDirectory
-                               return $ cd ++ "/" ++ f
-canonFilename f = case reverse $ dropWhile (/='/') $ reverse f of
-                  "" -> liftM (++('/':f)) getCurrentDirectory
-                  rd -> withCurrentDirectory rd $
-                          do fd <- getCurrentDirectory
-                             return $ fd ++ "/" ++ simplefilename
-    where
-    simplefilename = reverse $ takeWhile (/='/') $ reverse f
hunk ./Lock.lhs 137
-
-mk_stdout_temp :: String -> IO String
-mk_stdout_temp str = withCString (str++"XXXXXX") $
-    \cstr -> do fd <- c_mkstemp cstr
-                if fd < 0
-                  then throwErrno $ "Failed to create temporary file "++str
-                  else do str' <- peekCString cstr
-                          fname <- canonFilename str'
-                          hFlush stdout
-                          hFlush stderr
-                          c_dup2 fd 1
-                          c_dup2 fd 2
-                          hFlush stdout
-                          hFlush stderr
-                          hSetBuffering stdout NoBuffering
-                          hSetBuffering stderr NoBuffering
-                          return fname
-
-mkstemp :: String -> IO (Handle, String)
-mkstemp str = withCString (str++"XXXXXX") $
-    \cstr -> do fd <- c_mkstemp cstr
-                if fd < 0
-                  then throwErrno $ "Failed to create temporary file "++str
-                  else do str' <- peekCString cstr
-                          fname <- canonFilename str'
-                          h <- openFd (fromIntegral fd) Nothing fname ReadWriteMode True False
-                          hSetBinaryMode h True
-                          return (h, fname)
-
-foreign import ccall unsafe "static unistd.h dup2" c_dup2 :: CInt -> CInt -> IO CInt
-foreign import ccall unsafe "static stdlib.h mkstemp" c_mkstemp :: CString -> IO CInt
hunk ./compat.c 161
-int mkstemp(char *p)
-{
-    static int inited_rand = 0;
-    size_t len = strlen(p);
-    if (len < 6 || strcmp(p+len-6, "XXXXXX")) {
-        errno = EINVAL;
-        return -1;
-    }
-    if (!inited_rand) {
-        srand(time(NULL));
-        inited_rand = 1;
-    }
-    // WARNING! The following is written for the win32 version of snprintf,
-    // which differs from the POSIX snprintf in how it treats the second
-    // argument.  The win32 snprintf doesn't print a nul character on
-    // overflow, so the second argument had better be one less than the
-    // size of the buffer, and the last character of the buffer had better
-    // be preset to nul.
-    snprintf(p+len-6, 6, "%06x", rand()<<16 ^ rand());
-    return open(p, O_CREAT | O_EXCL | O_RDWR, 0666);
-}
-
hunk ./compat.h 10
-int mkstemp(char *p);
-int pipe( int fildes[2] );
}

[Remove is_symlink
Ian Lynagh <[EMAIL PROTECTED]>**20050730122255] {
hunk ./Lock.lhs 58
+import System.Posix.Files ( getSymbolicLinkStatus, isDirectory )
hunk ./Lock.lhs 206
-foreign import ccall unsafe "static compat.h is_symlink" is_symlink
-    :: CString -> IO CInt
-
hunk ./Lock.lhs 208
-    fe <- doesDirectoryExist f
-    if not fe then return False
-       else withCString f $ \cf-> (0==) `liftM` is_symlink cf
+    fs <- getSymbolicLinkStatus f
+    return (isDirectory fs)
hunk ./SlurpDirectory.lhs 59
-import Foreign.C.String
-import Foreign.C ( CInt )
hunk ./SlurpDirectory.lhs 286
-foreign import ccall unsafe "static compat.h is_symlink" is_symlink
-    :: CString -> IO CInt
-
hunk ./SlurpDirectory.lhs 287
-isFileReallySymlink f = do
-    withCString f $ \cf -> do sym <- is_symlink cf
-                              return $ sym /= 0
+isFileReallySymlink f = do fs <- getSymbolicLinkStatus f
+                           return (isSymbolicLink fs)
hunk ./SlurpDirectory.lhs 291
-doesFileReallyExist f = do
-    fe <- doesFileExist f
-    if not fe then return False
-       else do symlink <- isFileReallySymlink f
-               return $ not symlink
+doesFileReallyExist f = do fs <- getSymbolicLinkStatus f
+                           return (isRegularFile fs)
+
hunk ./SlurpDirectory.lhs 295
-doesDirectoryReallyExist f = do
-    fe <- doesDirectoryExist f
-    if not fe then return False
-       else do symlink <- isFileReallySymlink f
-               return $ not symlink
+doesDirectoryReallyExist f = do fs <- getSymbolicLinkStatus f
+                                return (isDirectory fs)
hunk ./compat.c 161
-int is_symlink(const char *file) {
-    return 0; /* FIXME: should ignore windows shortcuts */
-}
-
hunk ./compat.c 256
-
-int is_symlink(const char *file) {
-  struct stat buf;
-  if (lstat(file, &buf)) return 0; /* treat error as non-symlink */
-  return S_ISLNK(buf.st_mode);
-}
-
hunk ./compat.h 22
-int is_symlink(const char *file);
-
}

[Move maybe_relink out of compat.c
Ian Lynagh <[EMAIL PROTECTED]>**20050730131205] {
hunk ./Compat.hs 4
-module Compat (stdout_is_a_pipe, mkstemp, mk_stdout_temp, canonFilename) where
+module Compat (stdout_is_a_pipe, mkstemp, mk_stdout_temp, canonFilename,
+               maybe_relink) where
+
+import Prelude hiding ( catch )
hunk ./Compat.hs 10
-#ifdef WIN32
hunk ./Compat.hs 11
+#ifndef WIN32
+import DarcsUtils ( add_to_error_loc, isUnsupportedOperationError )
+import FastPackedString ( readFileLazily )
hunk ./Compat.hs 16
-#ifdef WIN32
hunk ./Compat.hs 17
+#ifndef WIN32
+import Control.Exception ( catch )
+import Control.Monad ( unless )
hunk ./Compat.hs 22
-#ifdef WIN32
hunk ./Compat.hs 23
-#endif
hunk ./Compat.hs 24
+import Data.Bits ( xor, shiftR )
hunk ./Compat.hs 28
+import System.Directory ( removeFile, renameFile )
hunk ./Compat.hs 33
+#ifndef WIN32
+import System.IO ( hPutStrLn )
+import System.IO.Error ( isDoesNotExistError, isPermissionError )
+#endif
hunk ./Compat.hs 41
+#ifndef WIN32
+import System.Posix.Files ( getFileStatus, isRegularFile, createLink,
+                            modificationTime, fileID, fileSize, deviceID )
+#endif
hunk ./Compat.hs 56
+#endif
+#ifndef WIN32
+import System.Time ( getClockTime, ClockTime(TOD) )
hunk ./Compat.hs 123
+
+#ifdef WIN32
+
+maybe_relink :: Bool -> FilePath -> FilePath -> IO Bool
+maybe_relink _ _ _ = return False
+
+#else
+
+{-
+Tries to link src to dst if both files exist and have the same
+contents.  If careful is false only the file sizes are compared; if
+it is true, the full contents are compared.
+
+This code assumes that dst cannot change behind our back -- the
+caller is supposed to protect it by a lock.  On the other hand, it
+does handle simultaneous access to src, but only if src is never
+modified in place.  It should also be safe over NFS.
+
+Assumes that rename cannot fail mid-way on a single filesystem.
+-}
+
+maybe_relink :: Bool -> FilePath -> FilePath -> IO Bool
+maybe_relink careful src dst = do
+    m_src_stat <- (liftM Just $ getFileStatus src) `catch` \e ->
+                  case e of
+                      IOException e'
+                       | isDoesNotExistError e'
+                         -> return Nothing
+                      _ -> throwIO (add_to_error_loc e ("Relinking " ++ dst))
+    case m_src_stat of
+        Nothing -> return False
+        Just src_stat -> do
+            dst_stat <- getFileStatus dst
+
+            unless (isRegularFile src_stat)
+                   (fail (src ++ " is not a regular file"))
+            unless (isRegularFile dst_stat)
+                   (fail (dst ++ " is not a regular file"))
+
+            if deviceID src_stat /= deviceID dst_stat then return False
+              else if fileID src_stat == fileID dst_stat then return True
+              else if fileSize src_stat /= fileSize dst_stat then return False
+              else do TOD _ usec <- getClockTime
+                      let x = (shiftR usec 16 `xor` usec) .&. 0xFFFF
+                          tempname = dst ++ showHexLen 4 x
+                      {- link is atomic even on NFS, we will fail
+                         gracefully if the name is not unique. -}
+                      do createLink src tempname
+                         temp_stat <- getFileStatus tempname
+                         {- Check for a race condition. The size and
+                            mtime checks are gratuitious, but they don't
+                            cost much, and might save your data if
+                            you're on a filesystem without i-nodes. -}
+                         if fileID temp_stat /= fileID src_stat ||
+                            fileSize temp_stat /= fileSize src_stat ||
+                            modificationTime temp_stat /=
+                                modificationTime src_stat
+                           then do hPutStrLn stderr "race condition avoided"
+                                   removeFile tempname
+                                   return False
+                           else if careful
+                                then do lf1 <- readFileLazily tempname
+                                        lf2 <- readFileLazily dst
+                                        {- This == test is technically too
+                                           strong, but will pretty much
+                                           always br right in practice -}
+                                        if lf1 == lf2
+                                          then do renameFile tempname dst
+                                                  return True
+                                          else do removeFile tempname
+                                                  return False
+                                else do renameFile tempname dst
+                                        return True
+                       `catch` \e -> do removeFile tempname `catch`
+                                                             \_ -> return ()
+                                        throwIO e
+ `catch` \e -> case e of
+                   IOException e'
+                    | isPermissionError e' || isUnsupportedOperationError e' ->
+                       return False
+                   _ -> throwIO (add_to_error_loc e ("Relinking " ++ dst))
+
+#endif
hunk ./DarcsUtils.lhs 9
-                    showHexLen,
+                    showHexLen, add_to_error_loc, isUnsupportedOperationError,
hunk ./DarcsUtils.lhs 12
+import Control.Exception ( Exception(IOException) )
+import GHC.IOBase ( IOException(ioe_location),
+                    IOErrorType(UnsupportedOperation) )
+import System.IO.Error ( ioeGetErrorType )
hunk ./DarcsUtils.lhs 33
+
+add_to_error_loc :: Exception -> String -> Exception
+add_to_error_loc (IOException ioe) s
+    = IOException $ ioe { ioe_location = s ++ ": " ++ ioe_location ioe }
+add_to_error_loc e _ = e
+
+isUnsupportedOperationError :: IOError -> Bool
+isUnsupportedOperationError = isUnsupportedOperationErrorType . ioeGetErrorType
+
+isUnsupportedOperationErrorType :: IOErrorType -> Bool
+isUnsupportedOperationErrorType UnsupportedOperation = True
+isUnsupportedOperationErrorType _ = False
hunk ./FastPackedString.hs 45
+        readFileLazily,  -- :: FilePath -> IO LazyFile
hunk ./FastPackedString.hs 819
+    deriving Eq
hunk ./FastPackedString.hs 848
-        else do let read_rest = do
-                        -- We might be making too big a fp here
-                        fp <- mallocForeignPtr blocksize
-                        debugForeignPtr fp $ "gzReadFileLazily "++f
-                        lread <- withForeignPtr fp
-                               $ \p -> hGetBuf h p blocksize
-                        case lread of
-                            0 -> return []
-                            l -> do rest <- unsafeInterleaveIO read_rest
-                                    return (PS fp 0 l:rest)
-                rest <- unsafeInterleaveIO read_rest
-                return $ LazyPackedStrings (header:rest)
+        else liftM (LazyPackedStrings . (header:)) $ readHandleLazily h
+    where blocksize = 1024
+
+readFileLazily :: FilePath -> IO LazyFile
+readFileLazily f =
+#if defined(__GLASGOW_HASKELL__)
+    if use_mmap
+      then liftM MMappedPackedString (mmapFilePS f)
+      else
+#endif
+           do h <- openBinaryFile f ReadMode
+              liftM LazyPackedStrings $ readHandleLazily h
+
+readHandleLazily :: Handle -> IO [PackedString]
+readHandleLazily h
+ = do let read_rest = do
+              -- We might be making too big a fp here
+              fp <- mallocForeignPtr blocksize
+              debugForeignPtr fp ("readHandleLazily " ++ show h)
+              lread <- withForeignPtr fp
+                     $ \p -> hGetBuf h p blocksize
+              case lread of
+                  0 -> return []
+                  l -> do rest <- unsafeInterleaveIO read_rest
+                          return (PS fp 0 l:rest)
+      unsafeInterleaveIO read_rest
hunk ./Lock.lhs 57
-import Compat ( mkstemp, mk_stdout_temp, canonFilename )
+import Compat ( mkstemp, mk_stdout_temp, canonFilename, maybe_relink )
hunk ./Lock.lhs 296
-foreign import ccall unsafe "compat.h maybe_relink" c_maybe_relink
-    :: CString -> CString -> CInt -> IO CInt
-
hunk ./Lock.lhs 301
-maybeRelink src dst =
-    withCString src $ \csrc ->
-    withCString dst $ \cdst ->
-    do rc <- c_maybe_relink csrc cdst 1
-       (case rc of
-        0 -> return True
-        1 -> return True
-        -1 -> throwErrno ("Relinking " ++ dst)
-        -2 -> return False
-        -3 -> do putStrLn ("Relinking: race condition avoided on file " ++
-                            dst)
-                 return False
-        _ -> fail ("Unexpected situation when relinking " ++ dst))
+maybeRelink src dst = maybe_relink True src dst
hunk ./compat.c 258
-#ifdef _WIN32
-int
-maybe_relink(const char *src, const char *dst, int careful)
-{
-    return 0;
-}
-
-#else
-
-/* Tries to link src to dst if both files exist and have the same
-   contents.  If careful is false only the file sizes are compared; if
-   it is true, the full contents are compared.
-
-   This code assumes that dst cannot change behind our back -- the
-   caller is supposed to protect it by a lock.  On the other hand, it
-   does handle simultaneous access to src, but only if src is never
-   modified in place.  It should also be safe over NFS.
-
-   Assumes that rename cannot fail mid-way on a single filesystem.
-
-   Returns 1 on success, 0 if the files are already linked, -1 for an
-   error in errno, -2 if the files cannot be linked because they are not
-   the same, on different devices, or on a filesystem with no support for
-   hard links, -3 if there was a race condition, -4 if something unexpected
-   happened. */
-
-int
-maybe_relink(char *src, char *dst, int careful)
-{
-#define RELINK_BUFFER_SIZE 8192
-
-    int len, rc, saved_errno;
-    char *tempname;
-    struct stat srcstat, dststat, tempstat;
-    struct timeval now;
-
-    rc = stat(src, &srcstat);
-    if(rc < 0) {
-        if(errno == ENOENT)
-            return -2;
-        else
-            return -1;
-    }
-
-    rc = stat(dst, &dststat);
-    if(rc < 0) return -1;
-
-    if(!S_ISREG(srcstat.st_mode) || !S_ISREG(dststat.st_mode)) {
-        return -4;
-    }
-
-    if(srcstat.st_dev != dststat.st_dev) {
-        return -2;
-    }
-
-    if(srcstat.st_ino == dststat.st_ino)
-        /* Files are already linked */
-        return 0;
-
-    if(srcstat.st_size != dststat.st_size)
-        return -2;
-
-    /* link is atomic even on NFS, we will fail gracefully if the name
-       is not unique. */
-    gettimeofday(&now, NULL);
-    rc = strlen(dst) + 6;
-    tempname = malloc(rc);
-    if(tempname == NULL) return -1;
-    len = snprintf(tempname, rc, "%s-%04x", dst,
-                   ((unsigned)(now.tv_usec ^ (now.tv_usec >> 16))) & 0xFFFF);
-    if(len < 0 || len >= rc) {
-        free(tempname);
-        return -4;
-    }
-
-    rc = link(src, tempname);
-    if(rc < 0) {
-        /* We need to try to remove the link in case this was a
-           problem with NFS over an unreliable transport. */
-        goto fail;
-    }
-
-    rc = stat(tempname, &tempstat);
-    if(rc < 0) goto fail;
-
-    /* Check for a race condition.  The size and mtime checks are
-       gratuitious, but they don't cost much, and might save your data
-       if you're on a filesystem without i-nodes. */
-    if(tempstat.st_ino != srcstat.st_ino ||
-       tempstat.st_size != srcstat.st_size ||
-       tempstat.st_mtime != srcstat.st_mtime) {
-        unlink(tempname);
-        free(tempname);
-        return -3;
-    }
-    if(careful) {
-        int fd1, fd2, i, rc1, rc2;
-        char buf1[RELINK_BUFFER_SIZE], buf2[RELINK_BUFFER_SIZE];
-
-        fd1 = open(tempname, O_RDONLY);
-        if(fd1 < 0) goto fail;
-        fd2 = open(dst, O_RDONLY);
-        if(fd2 < 0) { close(fd1); goto fail; }
-
-        i = 0;
-        /* This comparison is approximate: it doesn't deal with short
-           reads and EINTR.  It's okay, as these cases are rare and if
-           they happen, we're still safe. */
-        while(i < tempstat.st_size) {
-            rc1 = read(fd1, buf1, RELINK_BUFFER_SIZE);
-            if(rc1 < 0) { close(fd1); close(fd2); goto fail; }
-            rc2 = read(fd2, buf2, RELINK_BUFFER_SIZE);
-            if(rc2 < 0) { close(fd1); close(fd2); goto fail; }
-            if(rc1 == 0 || rc1 != rc2 || memcmp(buf1, buf2, rc1) != 0) {
-                close(fd1); close(fd2);
-                unlink(tempname);
-                free(tempname);
-                return -2;
-            }
-            i += rc1;
-        }
-        close(fd1); close(fd2);
-    }
-
-    rc = rename(tempname, dst);
-    if(rc < 0) goto fail;
-
-    free(tempname);
-    return 1;
-
- fail:
-    saved_errno = errno;
-    unlink(tempname);
-    free(tempname);
-    errno = saved_errno;
-    if(errno == EPERM || errno == EOPNOTSUPP)
-        return -2;
-    return -1;
-
-#undef RELINK_BUFFER_SIZE
-}
-
-#endif
hunk ./compat.h 22
-int maybe_relink(const char *src, const char *dst, int careful);
}

[Split the raw mode stuff out into its own .hsc file. Windows needs some TLC
Ian Lynagh <[EMAIL PROTECTED]>**20050730134030] {
hunk ./GNUmakefile 32
-	PrintPatch.lhs Printer.lhs RegChars.lhs \
+	PrintPatch.lhs Printer.lhs RawMode.hs RegChars.lhs \
hunk ./GNUmakefile 249
+	rm -f RawMode.hs
addfile ./RawMode.hsc
hunk ./RawMode.hsc 1
+
+module RawMode (get_raw_mode, set_raw_mode) where
+
+#ifdef _WIN32
+
+-- Various details are missing, unfinished and compilation etc not tested
+-- as I don't have Windows.
+
+#include <XXX.h>
+
+type DWORD = #type DWORD
+type HANDLE = #type HANDLE
+
+foreign import ccall unsafe "XXX.h GetStdHandle"
+    c_GetStdHandle :: Handle -> IO c_STD_INPUT_HANDLE
+
+foreign import ccall unsafe "XXX.h GetConsoleMode"
+    c_GetConsoleMode :: Handle -> Ptr DWORD -> IO ()
+
+get_mode :: IO DWORD
+get_mode = do stdin_handle <- c_GetStdHandle (#const STD_INPUT_HANDLE)
+              p <- malloc
+              c_GetConsoleMode stdin_handle p
+              console_mode <- peek p
+              free p
+              return console_mode
+
+int get_raw_mode()
+{
+    return (get_mode() & ENABLE_LINE_INPUT) == 0;
+}
+
+void set_raw_mode(int raw)
+{
+    HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
+    DWORD console_mode = get_mode();
+    if (raw)
+        console_mode &= ~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT);
+    else
+        console_mode |= ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT;
+    if (!SetConsoleMode(stdin_handle, console_mode))
+        fprintf(stderr, "SetConsoleMode error: %x\n", GetLastError());
+}
+
+#else
+
+get_raw_mode :: IO Bool
+get_raw_mode = return False
+
+set_raw_mode :: Bool -> IO ()
+set_raw_mode _ = return ()
+
+#endif
+
hunk ./SelectChanges.lhs 54
-import Foreign.C ( CInt )
hunk ./SelectChanges.lhs 78
+import RawMode ( get_raw_mode, set_raw_mode )
hunk ./SelectChanges.lhs 215
-foreign import ccall "compat.h get_raw_mode" get_raw_mode :: IO CInt
-foreign import ccall "compat.h set_raw_mode" set_raw_mode :: CInt -> IO ()
-
hunk ./SelectChanges.lhs 222
-                                       set_raw_mode 1
+                                       set_raw_mode True
hunk ./autoconf.mk.in 91
+%.hs : %.hsc
+	hsc2hs $< -o $@
+
hunk ./compat.c 160
-#ifdef _WIN32
-static DWORD get_mode()
-{
-    DWORD console_mode;
-    HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
-    GetConsoleMode(stdin_handle, &console_mode);
-    return console_mode;
-}
-
-int get_raw_mode()
-{
-    return (get_mode() & ENABLE_LINE_INPUT) == 0;
-}
-
-void set_raw_mode(int raw)
-{
-    HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
-    DWORD console_mode = get_mode();
-    if (raw)
-        console_mode &= ~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT);
-    else
-        console_mode |= ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT;
-    if (!SetConsoleMode(stdin_handle, console_mode))
-        fprintf(stderr, "SetConsoleMode error: %x\n", GetLastError());
-}
-
-
-#else
-
-int get_raw_mode()
-{
-    return 0;
-}
-
-void set_raw_mode(int raw)
-{
-}
+#ifndef _WIN32
hunk ./compat.h 13
-int get_raw_mode();
-void set_raw_mode(int raw);
-
}

[Move atomic_create/sloppy_atomic_create to Compat
Ian Lynagh <[EMAIL PROTECTED]>**20050730141703] {
hunk ./Compat.hs 5
-               maybe_relink) where
+               maybe_relink, atomic_create, sloppy_atomic_create) where
hunk ./Compat.hs 12
-import DarcsUtils ( add_to_error_loc, isUnsupportedOperationError )
+import DarcsUtils ( add_to_error_loc, isUnsupportedOperationError,
+                    isHardwareFaultError )
hunk ./Compat.hs 19
-import Control.Exception ( catch )
-import Control.Monad ( unless )
+import Control.Exception ( catch, finally )
+import Control.Monad ( when, unless )
hunk ./Compat.hs 26
+import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
+import Data.Maybe ( isJust )
hunk ./Compat.hs 31
+import Network.BSD ( getHostName )
hunk ./Compat.hs 39
-import System.IO.Error ( isDoesNotExistError, isPermissionError )
+import System.IO.Error ( isDoesNotExistError, isPermissionError,
+                         alreadyExistsErrorType, isAlreadyExistsError,
+                         ioeSetErrorType )
hunk ./Compat.hs 46
-import System.Posix.Files ( getFdStatus, isNamedPipe )
hunk ./Compat.hs 47
-import System.Posix.Files ( getFileStatus, isRegularFile, createLink,
-                            modificationTime, fileID, fileSize, deviceID )
+import System.IO.Unsafe ( unsafePerformIO )
+import System.Posix.Env ( getEnv )
hunk ./Compat.hs 50
+import System.Posix.Files ( getFdStatus, isNamedPipe )
hunk ./Compat.hs 53
+#else
+import System.Posix.Files ( getFileStatus, isRegularFile, createLink,
+                            modificationTime, fileID, fileSize, deviceID,
+                            linkCount, stdFileMode )
hunk ./Compat.hs 58
-import System.Posix.IO ( stdOutput, stdError, fdToHandle, dupTo )
+import System.Posix.IO ( openFd, closeFd, stdOutput, stdError, fdToHandle,
+                         dupTo, defaultFileFlags, exclusive,
+                         OpenMode(WriteOnly) )
hunk ./Compat.hs 65
+#ifndef WIN32
+import System.Posix.Process ( getProcessID )
+#endif
hunk ./Compat.hs 220
+#endif
+
+sloppy_atomic_create :: FilePath -> IO ()
+sloppy_atomic_create fp
+    = do fd <- openFd fp WriteOnly (Just stdFileMode) flags
+         closeFd fd
+  where flags = defaultFileFlags { exclusive = True }
+
+atomic_create :: FilePath -> IO ()
+
+#ifdef _WIN32
+
+atomic_create fp = sloppy_atomic_create fp
+
+#else
+
+{-# NOINLINE hostname_ref #-}
+hostname_ref :: IORef (Maybe String)
+hostname_ref = unsafePerformIO (newIORef Nothing)
+
+get_hostname :: IO String
+get_hostname
+ = getHostName `catch` \_ ->
+       do hPutStrLn stderr "Error reading hostname when locking."
+          return "kremvax"
+
+careful_atomic_create :: FilePath -> IO ()
+{-
+O_EXCL is not available over NFSv2, and even under NFSv3, it is
+broken on many systems.  The following protocol is provably
+safe assuming that:
+- creation of hard links is atomic;
+- stat hits the server rather than working from the cache.
+-}
+careful_atomic_create fp =
+    do m_hostname <- readIORef hostname_ref
+       hostname <- case m_hostname of
+                       Just hostname -> return hostname
+                       Nothing -> do
+                           hostname <- get_hostname
+                           let hostname' = take 15
+                                         $ takeWhile ('.' /=) hostname
+                           writeIORef hostname_ref (Just hostname')
+                           return hostname'
+       pid <- getProcessID
+       TOD _ usec <- getClockTime
+
+       let directory = case break ('/' ==) $ reverse fp of
+                           (_, xs) -> reverse xs
+           file = directory
+               ++ "darcs_lock_"
+               ++ hostname
+               ++ showHexLen 4 (pid .&. 0xFFFF)
+               ++ showHexLen 4 ((shiftR usec 16 `xor` usec) .&. 0xFFFF)
+
+       finally (do sloppy_atomic_create file
+                   createLink file fp `catch` \e ->
+                       case e of
+                           IOException e'
+                            {- Linux returns EPERM when making hard
+                               links on filesystems that don't support
+                               them.
+                               It seems that MacOS returns EOPNOTSUPP
+                               on filesystems that don't support hard
+                               links. -}
+                            | isPermissionError e' ||
+                              isUnsupportedOperationError e' ->
+                               sloppy_atomic_create fp
+                            {- The link may still have been successful
+                               if we're running over UDP and got EEXIST
+                               or EIO.  Check the file's link count. -}
+                            | isAlreadyExistsError e' ||
+                              isHardwareFaultError e' ->
+                               do fs <- getFileStatus file
+                                  let e'' = ioeSetErrorType e'
+                                                alreadyExistsErrorType
+                                  when (linkCount fs /= 2)
+                                       (throwIO (IOException e''))
+                           _ -> throwIO e
+               )
+               (removeFile file `catch` \e ->
+                    case e of
+                        IOException e' | isDoesNotExistError e' -> return ()
+                        _ -> throwIO e)
+
+atomic_create fp = do m <- getEnv "DARCS_SLOPPY_LOCKS"
+                      if isJust m
+                        then sloppy_atomic_create fp
+                        else careful_atomic_create fp
hunk ./DarcsUtils.lhs 9
-                    showHexLen, add_to_error_loc, isUnsupportedOperationError,
+                    showHexLen, add_to_error_loc,
+                    isUnsupportedOperationError, isHardwareFaultError,
hunk ./DarcsUtils.lhs 15
-                    IOErrorType(UnsupportedOperation) )
+                    IOErrorType(UnsupportedOperation, HardwareFault) )
hunk ./DarcsUtils.lhs 46
+
+isHardwareFaultError :: IOError -> Bool
+isHardwareFaultError = isHardwareFaultErrorType . ioeGetErrorType
+
+isHardwareFaultErrorType :: IOErrorType -> Bool
+isHardwareFaultErrorType HardwareFault = True
+isHardwareFaultErrorType _ = False
hunk ./GNUmakefile 14
-GHCFLAGS += -Wall -Werror -package util -I.
+GHCFLAGS += -Wall -Werror -package util -package network -I.
hunk ./Lock.lhs 34
-import IO hiding ( bracket )
-import System.IO ( openBinaryFile )
-import Control.Exception ( bracket, catchJust, ioErrors, finally )
+import System.IO ( openBinaryFile, hClose, hPutStr, Handle,
+                   IOMode(WriteMode, AppendMode) )
+import System.IO.Error ( isDoesNotExistError, isAlreadyExistsError )
+import Control.Exception ( bracket, catchJust, ioErrors, finally, throwIO,
+                           Exception(IOException), catch, try )
hunk ./Lock.lhs 45
-import Foreign
-import Foreign.C ( withCString, CString,
-                   throwErrno, getErrno, eEXIST, CInt, CUInt )
+import Foreign.C ( CUInt )
hunk ./Lock.lhs 50
-import DarcsUtils ( catchall )
+import DarcsUtils ( catchall, add_to_error_loc )
hunk ./Lock.lhs 57
-import Compat ( mkstemp, mk_stdout_temp, canonFilename, maybe_relink )
+import Compat ( mkstemp, mk_stdout_temp, canonFilename, maybe_relink,
+                atomic_create, sloppy_atomic_create )
hunk ./Lock.lhs 62
-takeLock :: String -> IO Bool
hunk ./Lock.lhs 88
-takeLock s = withCString s $ \cstr -> do
-    rc <- c_atomic_create cstr
-    if rc >= 0 then return True
-               else do errno <- getErrno
-                       if errno == eEXIST
-                          then return False
-                          else do pwd <- getCurrentDirectory
-                                  throwErrno $ "takeLock "++s++" in "++pwd
+takeLock :: FilePath -> IO Bool
+takeLock fp =
+    do atomic_create fp
+       return True
+  `catch` \e -> case e of
+                    IOException e'
+                     | isAlreadyExistsError e' ->
+                        return False
+                    _ -> do pwd <- getCurrentDirectory
+                            throwIO $ add_to_error_loc e
+                                            ("takeLock "++fp++" in "++pwd)
hunk ./Lock.lhs 100
-foreign import ccall unsafe "compat.h atomic_create" c_atomic_create
-    :: CString -> IO CInt
-
-takeFile :: String -> IO Bool
-takeFile s = withCString s $ \cstr -> do
-    rc <- c_sloppy_create cstr
-    if rc >= 0 then return True
-               else do errno <- getErrno
-                       if errno == eEXIST
-                          then return False
-                          else do pwd <- getCurrentDirectory
-                                  throwErrno $ "takeFile "++s++" in "++pwd
-
-foreign import ccall unsafe "compat.h sloppy_atomic_create" c_sloppy_create
-    :: CString -> IO CInt
+takeFile :: FilePath -> IO Bool
+takeFile fp =
+    do sloppy_atomic_create fp
+       return True
+  `catch` \e -> case e of
+                    IOException e'
+                     | isAlreadyExistsError e' ->
+                        return False
+                    _ -> do pwd <- getCurrentDirectory
+                            throwIO $ add_to_error_loc e
+                                            ("takeFile "++fp++" in "++pwd)
hunk ./Lock.lhs 187
-                `IO.catch` (\e -> if isAlreadyExistsError e
-                            then create_directory name (n+1)
-                            else ioError e)
+                `catch` (\e -> case e of
+                              IOException e'
+                               | isAlreadyExistsError e' ->
+                                  create_directory name (n+1)
+                              _ -> throwIO e)
hunk ./compat.c 18
-int sloppy_atomic_create(const char *p)
-{
-    int fd;
-    fd = open(p, O_WRONLY | O_EXCL | O_CREAT, 0666);
-    if(fd < 0)
-        return -1;
-    close(fd);
-    return 1;
-}
-
-#ifdef _WIN32
-
-int atomic_create(const char *p)
-{
-    return sloppy_atomic_create(p);
-}
-
-#else
-
-static int careful_atomic_create(const char *p)
-{
-    /* O_EXCL is not available over NFSv2, and even under NFSv3, it is
-       broken on many systems.  The following protocol is provably
-       safe assuming that:
-       - creation of hard links is atomic;
-       - stat hits the server rather than working from the cache.
-    */
-
-    static char hostname[65] = {'\0'};
-    int fd, rc, saved_errno;
-#define FILENAME_SIZE (11 + 15 + 8 + 1)
-    char *filename;
-    char *lastslash;
-    int dirlen;
-    struct timeval now;
-    struct stat sb;
-
-    if(hostname[0] == '\0') {
-        char *c;
-        /* POSIX guarantees 65 is enough. */
-        rc = gethostname(hostname, 65);
-        if(rc < 0 || rc >= 65) {
-            fprintf(stderr, "Error reading hostname when locking.\n");
-            strcpy(hostname, "kremvax");
-        }
-        c = strchr(hostname, '.');
-        if(c != NULL)
-            *c = '\0';
-        hostname[15] = '\0';
-    }
-
-    lastslash = strrchr(p, '/');
-    dirlen = lastslash ? lastslash - p + 1 : 0;
-
-    filename = malloc(dirlen + FILENAME_SIZE);
-    if(filename == NULL)
-        return -1;
-
-    if(dirlen > 0)
-        memcpy(filename, p, dirlen);
-    filename[dirlen] = '\0';
-
-    gettimeofday(&now, NULL);
-
-    rc = snprintf(filename + dirlen, FILENAME_SIZE, "darcs_lock_%s%04x%04x",
-                  hostname, ((unsigned)getpid()) & 0xFFFF,
-                  ((unsigned)(now.tv_usec ^ (now.tv_usec >> 16))) & 0xFFFF);
-    if(rc < 0 || rc >= FILENAME_SIZE) {
-        fprintf(stderr, "Error writing to lock filename (%d)\n", 
-                rc < 0 ? errno : 0);
-        goto fail2;
-    }
-
-    fd = open(filename, O_WRONLY | O_EXCL | O_CREAT, 0666);
-    if(fd < 0)
-        goto fail2;
-
-    /* Paranoia: should cause the client to flush its metadata cache. */
-    rc = close(fd);
-    if(rc < 0) {
-        fprintf(stderr, "Error closing file %s. (%d)\n", filename, errno);
-        goto fail;
-    }
-
-    rc = link(filename, p);
-    if(rc >= 0)
-        goto success;
-    else if(errno == EPERM || errno == EOPNOTSUPP) {
-        /* Linux returns EPERM when making hard links on filesystems
-           that don't support them. */
-        /* It seems that MacOS returns EOPNOTSUPP on filesystems that
-           don't support hard links. */
-        unlink(filename);
-        free(filename);
-        return sloppy_atomic_create(p);
-    } else if(errno != EEXIST && errno != EIO)
-        goto fail;
-
-    /* The link may still have been successful if we're running over
-       UDP and got EEXIST or EIO.  Check the file's link count. */
-
-    rc = stat(filename, &sb);
-    if(rc < 0) {
-        goto fail;
-    }
-
-    if(sb.st_nlink != 2) {
-        errno = EEXIST;
-        goto fail;
-    }
-
- success:
-    unlink(filename);
-    free(filename);
-    return 1;
-
- fail:
-    saved_errno = errno;
-    unlink(filename);
-    errno = saved_errno;
- fail2:
-    free(filename);
-    return -1;
-}
-
-int atomic_create(const char *p)
-{
-    static int sloppy = -1;
-
-    if(sloppy < 0) {
-        char *s = getenv("DARCS_SLOPPY_LOCKS");
-        sloppy = (s != NULL);
-    }
-
-    if(sloppy)
-        return sloppy_atomic_create(p);
-    else
-        return careful_atomic_create(p);
-}
-
-#endif
-
hunk ./compat.h 6
-int sloppy_atomic_create(const char *p);
-int atomic_create(const char *p);
-
-#ifdef _WIN32
-int renamefile(const char *from, const char *to);
-#endif
-
}

[Rename compat.c to c_compat.c to avoid object filename conflict with Compat.hs
[EMAIL PROTECTED] {
move ./compat.c ./c_compat.c
hunk ./Compat.hs 61
-#ifdef WIN32
-import System.Posix.IO ( defaultFileFlags, openFd,
-                         exclusive, OpenMode(WriteOnly) )
-#endif
hunk ./GNUmakefile 59
-C_OBJS := compat.o fpstring.o $(GIT_C_OBJS)
+C_OBJS := c_compat.o fpstring.o $(GIT_C_OBJS)
}

[call hsc2hs without output filename argument
[EMAIL PROTECTED] {
hunk ./autoconf.mk.in 92
-	hsc2hs $< -o $@
+	hsc2hs $<
}

[implement RawMode with library functions instead of ffi
[EMAIL PROTECTED] {
move ./RawMode.hsc ./RawMode.hs
hunk ./GNUmakefile 249
-	rm -f RawMode.hs
hunk ./RawMode.hs 4
-#ifdef _WIN32
+#ifdef WIN32
hunk ./RawMode.hs 6
--- Various details are missing, unfinished and compilation etc not tested
--- as I don't have Windows.
+import Monad ( liftM )
+import DarcsUtils ( catchall )
+import System.Posix.Internals ( getEcho, setCooked, setEcho )
hunk ./RawMode.hs 10
-#include <XXX.h>
+get_raw_mode :: IO Bool
+get_raw_mode = not `liftM` getEcho 0
+  `catchall` return False -- getEcho sometimes fails when called from scripts
hunk ./RawMode.hs 14
-type DWORD = #type DWORD
-type HANDLE = #type HANDLE
-
-foreign import ccall unsafe "XXX.h GetStdHandle"
-    c_GetStdHandle :: Handle -> IO c_STD_INPUT_HANDLE
-
-foreign import ccall unsafe "XXX.h GetConsoleMode"
-    c_GetConsoleMode :: Handle -> Ptr DWORD -> IO ()
-
-get_mode :: IO DWORD
-get_mode = do stdin_handle <- c_GetStdHandle (#const STD_INPUT_HANDLE)
-              p <- malloc
-              c_GetConsoleMode stdin_handle p
-              console_mode <- peek p
-              free p
-              return console_mode
-
-int get_raw_mode()
-{
-    return (get_mode() & ENABLE_LINE_INPUT) == 0;
-}
-
-void set_raw_mode(int raw)
-{
-    HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
-    DWORD console_mode = get_mode();
-    if (raw)
-        console_mode &= ~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT);
-    else
-        console_mode |= ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT;
-    if (!SetConsoleMode(stdin_handle, console_mode))
-        fprintf(stderr, "SetConsoleMode error: %x\n", GetLastError());
-}
+set_raw_mode :: Bool -> IO ()
+set_raw_mode raw = setCooked 0 normal >> setEcho 0 normal
+ where normal = not raw
}

[Implement parts of System.Posix.(IO|Files) for win32
[EMAIL PROTECTED] {
adddir ./win32/System/Posix
hunk ./Compat.hs 226
-#ifdef _WIN32
+#ifdef WIN32
hunk ./External.hs 20
-import System.Posix ( getSymbolicLinkStatus, isRegularFile, isDirectory )
+import System.Posix.Files ( getSymbolicLinkStatus, isRegularFile, isDirectory )
hunk ./GNUmakefile 63
-DARCS_FILES += win32/System/Posix.hs win32/CtrlC.hs
+DARCS_FILES += win32/System/Posix.hs win32/System/Posix/Files.hs \
+               win32/System/Posix/IO.hs win32/CtrlC.hs
hunk ./GNUmakefile 66
-UNIT_FILES += win32/System/Posix.hs
-CREATEREPO_FILES += win32/System/Posix.hs
+UNIT_FILES += win32/System/Posix.hs win32/System/Posix/Files.hs \
+              win32/System/Posix/IO.hs 
+CREATEREPO_FILES += win32/System/Posix.hs win32/System/Posix/Files.hs \
+                    win32/System/Posix/IO.hs 
hunk ./GNUmakefile 260
+	rm -f win32/System/Posix/IO.hs win32/System/Posix/Files.hs
hunk ./SlurpDirectory.lhs 54
-import System.Posix
-        ( EpochTime, getSymbolicLinkStatus, modificationTime,
-          sleep, FileOffset, fileSize,
+import System.Posix.Types ( EpochTime, FileOffset )
+import System.Posix.Files
+        ( getSymbolicLinkStatus, modificationTime,
+          fileSize,
hunk ./SlurpDirectory.lhs 60
+import System.Posix ( sleep )
hunk ./win32/System/Posix.hs 4
-import Foreign
-import Foreign.Ptr
-import Foreign.C.Error
-import Foreign.C.Types
-import Foreign.C.String
+import Foreign.Ptr ( Ptr, castPtr, plusPtr )
+import Foreign.Storable ( peek, poke, sizeOf )
+import Foreign.C.Types ( CInt, CULong, CTime )
+import Foreign.C.String ( CString, withCString )
+import Foreign.Marshal.Alloc ( allocaBytes )
hunk ./win32/System/Posix.hs 10
-import Monad
+import System.Posix.Types ( EpochTime )
+import System.IO ( Handle )
hunk ./win32/System/Posix.hs 13
-import IO
-
-foreign import ccall "_stat" c_stat :: CString -> Ptr () -> IO Int
-
-
-type FileOffset = CInt
- 
-data FileStatus = FileStatus {
-    accessTime :: EpochTime,
-    modificationTime :: EpochTime,
-    fileSize :: FileOffset,
-    isRegularFile :: Bool,
-    isDirectory :: Bool,
-    isSymbolicLink :: Bool
-  }
-
-s_ifdir, s_ifreg :: CShort
-s_ifdir = 0x4000 :: CShort
-s_ifreg = 0x8000 :: CShort
-
-getFileStatus     :: FilePath -> IO FileStatus
-getFileStatus path = do
-    p <- mallocBytes 36
-    r <- path `withCString` (`c_stat` p)
-    when (r /= 0) $ throwErrno path
-    md <- peek_short p 6
-    sz <- peek_int p 20
-    at <- peek_int p 24
-    mt <- peek_int p 28
-    free p
-    let isReg = md .&. s_ifreg == s_ifreg
-    let isDir = md .&. s_ifdir == s_ifdir
-    return (FileStatus (EpochTime (fromInteger at)) (EpochTime (fromInteger mt)) sz isReg isDir False)
-    where peek_int p o = do i <- peek (castPtr (plusPtr p o)) :: IO CInt
-                            return (fromIntegral i)
-          peek_short p o = do peek (castPtr (plusPtr p o)) :: IO CShort
-
-getSymbolicLinkStatus :: FilePath -> IO FileStatus
-getSymbolicLinkStatus = getFileStatus
hunk ./win32/System/Posix.hs 17
-setFileTimes path (EpochTime atime) (EpochTime mtime) = path `withCString` \s -> do
-    p <- mallocBytes 8
-    poke (castPtr p :: Ptr Int32) (fromIntegral atime)
-    poke (castPtr (plusPtr p 4) :: Ptr Int32) (fromIntegral mtime)
+setFileTimes path atime mtime = path `withCString` \s -> do
+  allocaBytes 8 $ \p -> do
+    poke (castPtr p :: Ptr CTime) (atime)
+    poke (castPtr (plusPtr p 4) :: Ptr CTime) (mtime)
hunk ./win32/System/Posix.hs 22
-    free p
hunk ./win32/System/Posix.hs 25
-
-foreign import ccall "time" c_ctime :: CInt -> IO CInt
+foreign import ccall "time" c_ctime :: Ptr CTime -> IO CInt
hunk ./win32/System/Posix.hs 29
-    t <- c_ctime 0
-    return (EpochTime (fromIntegral t))
-
-newtype EpochTime = EpochTime Int32
- deriving (Eq, Ord, Num, Real, Integral, Enum, Show)
+    allocaBytes (sizeOf (undefined :: CTime)) $ \p -> do
+      c_ctime p
+      t <- peek p :: IO CTime
+      return t
hunk ./win32/System/Posix.hs 42
+
addfile ./win32/System/Posix/Files.hsc
hunk ./win32/System/Posix/Files.hsc 1
+module System.Posix.Files where
+
+import Foreign.Marshal.Alloc ( allocaBytes )
+import Foreign.C.Error ( throwErrnoIfMinus1Retry )
+import Foreign.C.String ( withCString )
+import Foreign.C.Types ( CTime, CInt )
+import Foreign.Ptr ( Ptr )
+
+import System.Posix.Internals
+          ( FDType, CStat, c_fstat, lstat, 
+            sizeof_stat, statGetType, 
+            st_mode, st_size, st_mtime,
+            s_isreg, s_isdir, s_isfifo, )
+import System.Posix.Types ( Fd(..), CMode, COff, EpochTime, FileOffset, FileMode )
+
+import Data.Bits ( (.|.) )
+
+data FileStatus = FileStatus {
+    fst_type :: FDType,
+    fst_mode :: CMode,
+    fst_mtime :: CTime,
+    fst_size :: COff
+ }
+
+getFdStatus :: Fd -> IO FileStatus
+getFdStatus (Fd fd) = do
+  do_stat (c_fstat fd)
+
+do_stat :: (Ptr CStat -> IO CInt) -> IO FileStatus
+do_stat stat_func = do
+  allocaBytes sizeof_stat $ \p -> do
+    throwErrnoIfMinus1Retry "do_stat" $
+      stat_func p
+    tp <- statGetType p
+    mode <- st_mode p
+    mtime <- st_mtime p
+    size <- st_size p
+    return (FileStatus tp mode mtime size)
+
+isNamedPipe :: FileStatus -> Bool
+isNamedPipe = s_isfifo . fst_mode
+
+isDirectory :: FileStatus -> Bool
+isDirectory = s_isdir . fst_mode
+
+isRegularFile :: FileStatus -> Bool
+isRegularFile = s_isreg . fst_mode
+
+isSymbolicLink :: FileStatus -> Bool
+isSymbolicLink = const False
+
+modificationTime :: FileStatus -> EpochTime
+modificationTime = fst_mtime
+
+fileSize :: FileStatus -> FileOffset
+fileSize = fst_size
+
+#include <sys/stat.h>
+stdFileMode :: FileMode
+stdFileMode = (#const S_IRUSR) .|. (#const S_IWUSR)
+
+
+
+getSymbolicLinkStatus :: FilePath -> IO FileStatus
+getSymbolicLinkStatus fp = 
+  do_stat (\p -> (fp `withCString` (`lstat` p)))
+
addfile ./win32/System/Posix/IO.hsc
hunk ./win32/System/Posix/IO.hsc 1
+module System.Posix.IO where
+
+import Foreign.C.String ( withCString )
+import Foreign.C.Error ( throwErrnoIfMinus1, throwErrnoIfMinus1_ )
+
+import GHC.Handle ( fdToHandle )
+
+import System.Posix.Internals ( c_open, c_close, c_dup2 )
+import System.Posix.Types ( Fd(..), FileMode )
+import System.IO ( Handle )
+
+import Data.Bits ( (.|.) )
+
+
+stdOutput :: Fd
+stdOutput = Fd 1
+
+stdError :: Fd
+stdError = Fd 2
+
+data OpenFileFlags = 
+ OpenFileFlags {
+  append :: Bool,
+  exclusive :: Bool,
+  noctty :: Bool,
+  nonBlock :: Bool,
+  trunc :: Bool
+ }
+
+
+-- Adapted from System.Posix.IO in ghc
+#include <fcntl.h>
+
+openFd :: FilePath -> OpenMode -> Maybe FileMode -> OpenFileFlags -> IO Fd
+openFd name how maybe_mode off = do
+  withCString name $ \s -> do
+   fd <- throwErrnoIfMinus1 "openFd" (c_open s all_flags mode_w)
+   return (Fd fd)
+ where
+   all_flags = binary .|. creat .|. flags .|. open_mode
+   flags =
+    (if append off    then (#const O_APPEND)   else 0) .|.
+    (if exclusive off then (#const O_EXCL)     else 0) .|.
+    (if trunc off     then (#const O_TRUNC)    else 0)
+   binary = (#const O_BINARY)
+   (creat, mode_w) = maybe (0,0) (\x->((#const O_CREAT),x)) maybe_mode
+   open_mode = case how of
+                ReadOnly  -> (#const O_RDONLY)
+                WriteOnly -> (#const O_WRONLY)
+                ReadWrite -> (#const O_RDWR)
+
+closeFd :: Fd -> IO ()
+closeFd (Fd fd) = throwErrnoIfMinus1_ "closeFd" (c_close fd)
+
+
+fdToHandle :: Fd -> IO Handle
+fdToHandle fd = GHC.Handle.fdToHandle (fromIntegral fd)
+
+dupTo :: Fd -> Fd -> IO Fd
+dupTo (Fd fd1) (Fd fd2) = do
+  r <- throwErrnoIfMinus1 "dupTo" (c_dup2 fd1 fd2)
+  return (Fd r)
+
+data OpenMode = ReadOnly | WriteOnly | ReadWrite
+
+defaultFileFlags :: OpenFileFlags
+defaultFileFlags = OpenFileFlags False False False False False
+
+
}

[fix mkstemp implementation for win32
Peter Strand <[EMAIL PROTECTED]>**20050810211303] {
hunk ./Compat.hs 17
-import Control.Exception ( Exception(IOException), throwIO )
hunk ./Compat.hs 18
+import Control.Exception ( Exception(IOException), throwIO )
hunk ./Compat.hs 43
-#ifdef WIN32
-import System.IO.Error ( mkIOError, illegalOperationErrorType )
-#endif
hunk ./Compat.hs 55
-import System.Posix.IO ( openFd, closeFd, stdOutput, stdError, fdToHandle,
+import System.Posix.IO ( openFd, closeFd, stdOutput, stdError, 
hunk ./Compat.hs 68
+import qualified Workaround ( openFd )
+import System.IO ( IOMode(ReadWriteMode) )
hunk ./Compat.hs 92
- = do fp' <- case splitAt 6 fp of
-                 ("XXXXXX", rev_fp) -> return $ reverse rev_fp
-                 _ -> let e = mkIOError illegalOperationErrorType
-                                        "mkstemp" Nothing (Just fp)
-                      in throwIO (IOException e)
-      r <- randomIO
-      let fp'' = fp' ++ (showHexLen 6 (r .&. 0xFFFFFF :: Int))
-      fd <- openFd fp WriteOnly (Just stdFileMode) flags
-      return (fd, fp'')
+ = do r <- randomIO
+      let fp' = fp ++ (showHexLen 6 (r .&. 0xFFFFFF :: Int))
+      fd <- openFd fp' WriteOnly (Just stdFileMode) flags
+      return (fd, fp')
hunk ./Compat.hs 112
-mkstemp str = do (fd, fn) <- mkstemp_core str
-                 h <- fdToHandle fd
+mkstemp str = do (Fd fd, fn) <- mkstemp_core str
+                 h <- Workaround.openFd (fromIntegral fd) Nothing fn ReadWriteMode True False
}

Context:

[make repair work on partial repositories.
David Roundy <[EMAIL PROTECTED]>**20050805113001] 
[Cleanup --verbose handling in repair command
Matt Lavin <[EMAIL PROTECTED]>**20050805020630] 
[clean up Printer.wrap_text.
David Roundy <[EMAIL PROTECTED]>**20050808114844] 
[add several changelog entries.
David Roundy <[EMAIL PROTECTED]>**20050808114800] 
[improve EOD message a tad.
David Roundy <[EMAIL PROTECTED]>**20050807112644
 This change also introduces a "wrapped_text" function in Printer, so we
 won't have to worry so often about manually wrapping lines.
] 
[changed ***DARCS*** to ***END OF DESCRIPTION***
Jason Dagit <[EMAIL PROTECTED]>**20050729032543] 
[remove unused opts argument from apply_patches and apply_patches_with_feedback
Matt Lavin <[EMAIL PROTECTED]>**20050807031038] 
[Use apply_patch_with_feedback from check and repair commands
Matt Lavin <[EMAIL PROTECTED]>**20050805020830] 
[add code to read patch bundles with added CRs.
David Roundy <[EMAIL PROTECTED]>**20050806222631
 I think this'll address bug #291.
] 
[accept command-line flags in any order.
David Roundy <[EMAIL PROTECTED]>**20050806211828
 In particular, we no longer require that --flags precede filename and
 repository arguments.
] 
[show patch numbers instead of dots on get
Matt Lavin <[EMAIL PROTECTED]>**20050804013649] 
[add obliterate command as alias for unpull.
David Roundy <[EMAIL PROTECTED]>**20050804104929] 
[Do not ask confirmation for revert -a
[EMAIL PROTECTED]
 Giving -a as a parameter means the user expects all changes to be reverted.
 Just like for unrevert and record go ahead with it do not ask for confirmation.
] 
[clarify help text for 'd' in SelectPatches.
David Roundy <[EMAIL PROTECTED]>**20050806231117] 
[Add --with-static-libs configure flag for linking static versions of libraries.
[EMAIL PROTECTED] 
[add changelog entry for bug #477.
David Roundy <[EMAIL PROTECTED]>**20050806212148] 
[changelog entry for bug #189.
David Roundy <[EMAIL PROTECTED]>**20050731132624] 
[add description of how to add changelog entries to ChangeLog.README.
David Roundy <[EMAIL PROTECTED]>**20050806225901] 
[Explain the missing ChangeLog
Mark Stosberg <[EMAIL PROTECTED]>**20050526135421
 
 It should be easy for casual users and contributors to view and update the
 ChangeLog.
 
 Providing a README file in the place where people are most likely to look
 provides a very useful clue.
 
 However, it's still not clear to me exactly how the system works, so I have
 left a stub to complete that documentation.
 
     Mark
 
] 
[fix obsolete error explanation in get_extra bug.
David Roundy <[EMAIL PROTECTED]>**20050804130610] 
[simplify fix for bug 463; reuse /// from FilePathUtils
Matt Lavin <[EMAIL PROTECTED]>**20050804021130] 
[Make curl exit with error on failed downloads
[EMAIL PROTECTED] 
[Bump up AC_PREREQ version to 2.59.
[EMAIL PROTECTED] 
[fix for bug 463 (with new test)
Matt Lavin <[EMAIL PROTECTED]>**20050802002116] 
[bump version number, since I just made a release.
David Roundy <[EMAIL PROTECTED]>**20050731190756] 
[Use simpler curl_version() function to get version string.
Kannan Goundan <[EMAIL PROTECTED]>**20050322221027] 
[fix documentation on --reorder-patches.
David Roundy <[EMAIL PROTECTED]>**20050731185406] 
[add changelog entry for bug #224.
David Roundy <[EMAIL PROTECTED]>**20050731133942] 
[fix bug when editing long comment leaves empty file.
David Roundy <[EMAIL PROTECTED]>**20050731133612] 
[TAG 1.0.4pre2
David Roundy <[EMAIL PROTECTED]>**20050731121029] 
Patch bundle hash:
969d8f85fd7af3083ad81784d1e2a945cdcb07dc
_______________________________________________
darcs-devel mailing list
[email protected]
http://www.abridgegame.org/cgi-bin/mailman/listinfo/darcs-devel

Reply via email to