Skip to content

Commit 3a77b83

Browse files
committed
Add replaceFile
1 parent f95c5ea commit 3a77b83

File tree

5 files changed

+77
-1
lines changed

5 files changed

+77
-1
lines changed

System/Directory.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ module System.Directory
5050
, copyFile
5151
, copyFileWithMetadata
5252
, getFileSize
53+
, replaceFile
5354

5455
, canonicalizePath
5556
, makeAbsolute

System/Directory/Internal/Posix.hsc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ removePathInternal False = Posix.removeLink . getOsString
8585
renamePathInternal :: OsPath -> OsPath -> IO ()
8686
renamePathInternal (OsString p1) (OsString p2) = Posix.rename p1 p2
8787

88+
replaceFileInternal :: OsPath -> OsPath -> Maybe OsPath -> IO ()
89+
replaceFileInternal (OsString p1) (OsString p2) _ = Posix.rename p1 p2
90+
8891
-- On POSIX, the removability of a file is only affected by the attributes of
8992
-- the containing directory.
9093
filesAlwaysRemovable :: Bool

System/Directory/Internal/Windows.hsc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ renamePathInternal opath npath =
9898
npath' <- furnishPath npath
9999
Win32.moveFileEx opath' (Just npath') Win32.mOVEFILE_REPLACE_EXISTING
100100

101+
replaceFileInternal :: OsPath -> OsPath -> Maybe OsPath -> IO ()
102+
replaceFileInternal replacedFile replacementFile mBackupFile =
103+
(`ioeSetOsPath` replacedFile) `modifyIOError` do
104+
replacedFile' <- furnishPath replacedFile
105+
replacementFile' <- furnishPath replacementFile
106+
mBackupFile' <- fmap furnishPath mBackupFile
107+
Win32.replaceFile replacedFile' replacementFile' mBackupFile' Win32.rEPLACEFILE_IGNORE_MERGE_ERRORS
108+
101109
-- On Windows, the removability of a file may be affected by the attributes of
102110
-- the file itself.
103111
filesAlwaysRemovable :: Bool

System/Directory/OsPath.hs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ module System.Directory.OsPath
5252
, copyFile
5353
, copyFileWithMetadata
5454
, getFileSize
55+
, replaceFile
5556

5657
, canonicalizePath
5758
, makeAbsolute
@@ -709,6 +710,69 @@ renamePath opath npath =
709710
(`ioeAddLocation` "renamePath") `modifyIOError` do
710711
renamePathInternal opath npath
711712

713+
-- | 'replaceFile' replaces one file with another file. The replacement file
714+
-- assumes the name of the replaced file and its identity.
715+
--
716+
-- This operation is atomic.
717+
--
718+
-- On the unix same as renamePath, on the Windows platform this is ReplaceFileW.
719+
--
720+
-- The operation on unix may fail with:
721+
--
722+
-- * @HardwareFault@
723+
-- A physical I\/O error has occurred.
724+
-- @[EIO]@
725+
--
726+
-- * @InvalidArgument@
727+
-- Either operand is not a valid file name.
728+
-- @[ENAMETOOLONG, ELOOP]@
729+
--
730+
-- * 'isDoesNotExistError'
731+
-- The original file does not exist, or there is no path to the target.
732+
-- @[ENOENT, ENOTDIR]@
733+
--
734+
-- * 'isPermissionError'
735+
-- The process has insufficient privileges to perform the operation.
736+
-- @[EROFS, EACCES, EPERM]@
737+
--
738+
-- * 'System.IO.isFullError'
739+
-- Insufficient resources are available to perform the operation.
740+
-- @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
741+
--
742+
-- * @UnsatisfiedConstraints@
743+
-- Implementation-dependent constraints are not satisfied.
744+
-- @[EBUSY]@
745+
--
746+
-- * @UnsupportedOperation@
747+
-- The implementation does not support renaming in this situation.
748+
-- @[EXDEV]@
749+
--
750+
-- * @InappropriateType@
751+
-- Either the destination path refers to an existing directory, or one of the
752+
-- parent segments in the destination path is not a directory.
753+
-- @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
754+
--
755+
-- The operation on Windows may fail with:
756+
--
757+
-- ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176 (0x498)
758+
-- The replacement file could not be renamed. The replaced file no longer exists
759+
-- and the replacement file exists under its original name.
760+
--
761+
-- ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177 (0x499)
762+
--
763+
-- The replacement file could not be moved. The replacement file still exists
764+
-- under its original name; however, it has inherited the file streams and
765+
-- attributes from the file it is replacing. The file to be replaced still
766+
-- exists with a different name.
767+
--
768+
-- ERROR_UNABLE_TO_REMOVE_REPLACED 1175 (0x497)
769+
-- The replaced file could not be deleted. The replaced and replacement files
770+
-- retain their original file names.
771+
replaceFile :: OsPath -> OsPath -> IO ()
772+
replaceFile opath npath =
773+
(`ioeAddLocation` "replaceFile") `modifyIOError` do
774+
replaceFileInternal opath npath Nothing
775+
712776
-- | Copy a file with its permissions. If the destination file already exists,
713777
-- it is replaced atomically. Neither path may refer to an existing
714778
-- directory. No exceptions are thrown if the permissions could not be

directory.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Library
6363
file-io >= 0.1.4 && < 0.2,
6464
time >= 1.8.0 && < 1.15,
6565
if os(windows)
66-
build-depends: Win32 >= 2.14.1.0 && < 2.15
66+
build-depends: Win32 >= 2.14.2.0 && < 2.15
6767
else
6868
build-depends: unix >= 2.8.0 && < 2.9
6969

0 commit comments

Comments
 (0)