| Copyright | © 2020 Julian Ospald |
|---|---|
| License | BSD3 |
| Maintainer | Julian Ospald <hasufell@posteo.de> |
| Stability | experimental |
| Portability | portable |
| Safe Haskell | None |
| Language | Haskell2010 |
System.Posix.RawFilePath.Directory
Description
This module provides IO related file operations like
copy, delete, move and so on, similar to the directory package.
Some of these operations are due to their nature not atomic, which means they may do multiple syscalls which form one context. Some of them also have to examine the filetypes explicitly before the syscalls, so a reasonable decision can be made. That means the result is undefined if another process changes that context while the non-atomic operation is still happening. However, where possible, as few syscalls as possible are used and the underlying exception handling is kept.
Note: BlockDevice, CharacterDevice, NamedPipe and Socket
are ignored by some of the more high-level functions (like easyCopy).
For other functions (like copyFile), the behavior on these file types is
unreliable/unsafe. Check the documentation of those functions for details.
Import as: > import System.Posix.RawFilePath.Directory
Synopsis
- data FileType
- data RecursiveErrorMode
- data CopyMode
- copyDirRecursive :: RawFilePath -> RawFilePath -> CopyMode -> RecursiveErrorMode -> IO ()
- recreateSymlink :: RawFilePath -> RawFilePath -> CopyMode -> IO ()
- copyFile :: RawFilePath -> RawFilePath -> CopyMode -> IO ()
- easyCopy :: RawFilePath -> RawFilePath -> CopyMode -> RecursiveErrorMode -> IO ()
- deleteFile :: RawFilePath -> IO ()
- deleteDir :: RawFilePath -> IO ()
- deleteDirRecursive :: RawFilePath -> IO ()
- easyDelete :: RawFilePath -> IO ()
- openFile :: RawFilePath -> IO ProcessID
- executeFile :: RawFilePath -> [ByteString] -> IO ProcessID
- createRegularFile :: FileMode -> RawFilePath -> IO ()
- createDir :: FileMode -> RawFilePath -> IO ()
- createDirIfMissing :: FileMode -> RawFilePath -> IO ()
- createDirRecursive :: FileMode -> RawFilePath -> IO ()
- createSymlink :: RawFilePath -> RawFilePath -> IO ()
- renameFile :: RawFilePath -> RawFilePath -> IO ()
- moveFile :: RawFilePath -> RawFilePath -> CopyMode -> IO ()
- readFile :: RawFilePath -> IO ByteString
- readFileStrict :: RawFilePath -> IO ByteString
- readFileStream :: RawFilePath -> IO (SerialT IO (Array Word8))
- writeFile :: RawFilePath -> Maybe FileMode -> ByteString -> IO ()
- writeFileL :: RawFilePath -> Maybe FileMode -> ByteString -> IO ()
- appendFile :: RawFilePath -> ByteString -> IO ()
- newFilePerms :: FileMode
- newDirPerms :: FileMode
- doesExist :: RawFilePath -> IO Bool
- doesFileExist :: RawFilePath -> IO Bool
- doesDirectoryExist :: RawFilePath -> IO Bool
- isReadable :: RawFilePath -> IO Bool
- isWritable :: RawFilePath -> IO Bool
- isExecutable :: RawFilePath -> IO Bool
- canOpenDirectory :: RawFilePath -> IO Bool
- getModificationTime :: RawFilePath -> IO UTCTime
- setModificationTime :: RawFilePath -> EpochTime -> IO ()
- setModificationTimeHiRes :: RawFilePath -> POSIXTime -> IO ()
- getDirsFiles :: RawFilePath -> IO [RawFilePath]
- getDirsFiles' :: RawFilePath -> IO [RawFilePath]
- getDirsFilesStream :: (MonadCatch m, MonadAsync m, MonadMask m) => RawFilePath -> IO (SerialT m RawFilePath)
- getFileType :: RawFilePath -> IO FileType
- canonicalizePath :: RawFilePath -> IO RawFilePath
- toAbs :: RawFilePath -> IO RawFilePath
Types
data RecursiveErrorMode Source #
The error mode for recursive operations.
On FailEarly the whole operation fails immediately if any of the
recursive sub-operations fail, which is sort of the default
for IO operations.
On CollectFailures skips errors in the recursion and keeps on recursing.
However all errors are collected in the RecursiveFailure error type,
which is raised finally if there was any error. Also note that
RecursiveFailure does not give any guarantees on the ordering
of the collected exceptions.
Constructors
| FailEarly | |
| CollectFailures |
The mode for copy and file moves. Overwrite mode is usually not very well defined, but is a convenience shortcut.
File copying
Arguments
| :: RawFilePath | source dir |
| -> RawFilePath | destination (parent dirs are not automatically created) |
| -> CopyMode | |
| -> RecursiveErrorMode | |
| -> IO () |
Copies the contents of a directory recursively to the given destination, while preserving permissions. Does not follow symbolic links. This behaves more or less like the following, without descending into the destination if it already exists:
cp -a /source/dir /destination/somedir
For directory contents, this will ignore any file type that is not
RegularFile, SymbolicLink or Directory.
For Overwrite copy mode this does not prune destination directory
contents, so the destination might contain more files than the source after
the operation has completed. Permissions of existing directories are
fixed.
Safety/reliability concerns:
- not atomic
- examines filetypes explicitly
- an explicit check
throwDestinationInSourceis carried out for the top directory for basic sanity, because otherwise we might end up with an infinite copy loop... however, this operation is not carried out recursively (because it's slow)
Throws:
NoSuchThingif source directory does not existPermissionDeniedif source directory can't be openedSameFileif source and destination are the same file (HPathIOException)DestinationInSourceif destination is contained in source (HPathIOException)
Throws in FailEarly RecursiveErrorMode only:
PermissionDeniedif output directory is not writableInvalidArgumentif source directory is wrong type (symlink)InappropriateTypeif source directory is wrong type (regular file)
Throws in CollectFailures RecursiveErrorMode only:
RecursiveFailureif any of the recursive operations that are not part of the top-directory sanity-checks fail (HPathIOException)
Throws in Strict CopyMode only:
AlreadyExistsif destination already exists
Arguments
| :: RawFilePath | the old symlink file |
| -> RawFilePath | destination file |
| -> CopyMode | |
| -> IO () |
Recreate a symlink.
In Overwrite copy mode only files and empty directories are deleted.
Safety/reliability concerns:
Overwritemode is inherently non-atomic
Throws:
InvalidArgumentif source file is wrong type (not a symlink)PermissionDeniedif output directory cannot be written toPermissionDeniedif source directory cannot be openedSameFileif source and destination are the same file (HPathIOException)
Throws in Strict mode only:
AlreadyExistsif destination already exists
Throws in Overwrite mode only:
UnsatisfiedConstraintsif destination file is non-empty directory
Notes:
- calls
symlink
Arguments
| :: RawFilePath | source file |
| -> RawFilePath | destination file |
| -> CopyMode | |
| -> IO () |
Copies the given regular file to the given destination.
Neither follows symbolic links, nor accepts them.
For "copying" symbolic links, use recreateSymlink instead.
Note that this is still sort of a low-level function and doesn't
examine file types. For a more high-level version, use easyCopy
instead.
In Overwrite copy mode only overwrites actual files, not directories.
In Strict mode the destination file must not exist.
Safety/reliability concerns:
Overwritemode is not atomic- when used on
CharacterDevice, reads the "contents" and copies them to a regular file, which might take indefinitely - when used on
BlockDevice, may either read the "contents" and copy them to a regular file (potentially hanging indefinitely) or may create a regular empty destination file - when used on
NamedPipe, will hang indefinitely
Throws:
NoSuchThingif source file does not existNoSuchThingif source file is a aSocketPermissionDeniedif output directory is not writablePermissionDeniedif source directory can't be openedInvalidArgumentif source file is wrong type (symlink or directory)SameFileif source and destination are the same file (HPathIOException)
Throws in Strict mode only:
AlreadyExistsif destination already exists
easyCopy :: RawFilePath -> RawFilePath -> CopyMode -> RecursiveErrorMode -> IO () Source #
Copies a regular file, directory or symbolic link. In case of a symbolic link it is just recreated, even if it points to a directory. Any other file type is ignored.
Safety/reliability concerns:
- examines filetypes explicitly
- calls
copyDirRecursivefor directories
File deletion
deleteFile :: RawFilePath -> IO () Source #
Deletes the given file. Raises eISDIR
if run on a directory. Does not follow symbolic links.
Throws:
InappropriateTypefor wrong file type (directory)NoSuchThingif the file does not existPermissionDeniedif the directory cannot be read
Notes: calls unlink
deleteDir :: RawFilePath -> IO () Source #
Deletes the given directory, which must be empty, never symlinks.
Throws:
InappropriateTypefor wrong file type (symlink to directory)InappropriateTypefor wrong file type (regular file)NoSuchThingif directory does not existUnsatisfiedConstraintsif directory is not emptyPermissionDeniedif we can't open or write to parent directory
Notes: calls rmdir
deleteDirRecursive :: RawFilePath -> IO () Source #
Deletes the given directory recursively. Does not follow symbolic
links. Tries deleteDir first before attemtping a recursive
deletion.
On directory contents this behaves like easyDelete
and thus will ignore any file type that is not RegularFile,
SymbolicLink or Directory.
Safety/reliability concerns:
- not atomic
- examines filetypes explicitly
Throws:
InappropriateTypefor wrong file type (symlink to directory)InappropriateTypefor wrong file type (regular file)NoSuchThingif directory does not existPermissionDeniedif we can't open or write to parent directory
easyDelete :: RawFilePath -> IO () Source #
Deletes a file, directory or symlink. In case of directory, performs recursive deletion. In case of a symlink, the symlink file is deleted. Any other file type is ignored.
Safety/reliability concerns:
- examines filetypes explicitly
- calls
deleteDirRecursivefor directories
File opening
openFile :: RawFilePath -> IO ProcessID Source #
Opens a file appropriately by invoking xdg-open. The file type is not checked. This forks a process.
Arguments
| :: RawFilePath | program |
| -> [ByteString] | arguments |
| -> IO ProcessID |
Executes a program with the given arguments. This forks a process.
File creation
createRegularFile :: FileMode -> RawFilePath -> IO () Source #
Create an empty regular file at the given directory with the given filename.
Throws:
PermissionDeniedif output directory cannot be written toAlreadyExistsif destination already existsNoSuchThingif any of the parent components of the path do not exist
createDir :: FileMode -> RawFilePath -> IO () Source #
Create an empty directory at the given directory with the given filename.
Throws:
PermissionDeniedif output directory cannot be written toAlreadyExistsif destination already existsNoSuchThingif any of the parent components of the path do not exist
createDirIfMissing :: FileMode -> RawFilePath -> IO () Source #
Create an empty directory at the given directory with the given filename.
Throws:
PermissionDeniedif output directory cannot be written toNoSuchThingif any of the parent components of the path do not exist
createDirRecursive :: FileMode -> RawFilePath -> IO () Source #
Create an empty directory at the given directory with the given filename. All parent directories are created with the same filemode. This basically behaves like:
mkdir -p /some/dir
Safety/reliability concerns:
- not atomic
Throws:
PermissionDeniedif any part of the path components do not exist and cannot be written toAlreadyExistsif destination already exists and is *not* a directory
Arguments
| :: RawFilePath | destination file |
| -> RawFilePath | path the symlink points to |
| -> IO () |
Create a symlink.
Throws:
PermissionDeniedif output directory cannot be written toAlreadyExistsif destination file already existsNoSuchThingif any of the parent components of the path do not exist
Note: calls symlink
File renaming/moving
renameFile :: RawFilePath -> RawFilePath -> IO () Source #
Rename a given file with the provided filename. Destination and source
must be on the same device, otherwise eXDEV will be raised.
Does not follow symbolic links, but renames the symbolic link file.
Safety/reliability concerns:
- has a separate set of exception handling, apart from the syscall
Throws:
NoSuchThingif source file does not existPermissionDeniedif output directory cannot be written toPermissionDeniedif source directory cannot be openedUnsupportedOperationif source and destination are on different devicesAlreadyExistsif destination already existsSameFileif destination and source are the same file (HPathIOException)
Note: calls rename (but does not allow to rename over existing files)
Arguments
| :: RawFilePath | file to move |
| -> RawFilePath | destination |
| -> CopyMode | |
| -> IO () |
Move a file. This also works across devices by copy-delete fallback. And also works on directories.
Does not follow symbolic links, but renames the symbolic link file.
Safety/reliability concerns:
Overwritemode is not atomic- copy-delete fallback is inherently non-atomic
- since this function calls
easyCopyandeasyDeleteas a fallback torenameFile, file types that are notRegularFile,SymbolicLinkorDirectorymay be ignored - for
Overwritemode, the destination will be deleted (not recursively) before moving
Throws:
NoSuchThingif source file does not existPermissionDeniedif output directory cannot be written toPermissionDeniedif source directory cannot be openedSameFileif destination and source are the same file (HPathIOException)
Throws in Strict mode only:
AlreadyExistsif destination already exists
Notes:
- calls
rename(but does not allow to rename over existing files)
File reading
readFile :: RawFilePath -> IO ByteString Source #
Read the given file lazily.
Symbolic links are followed. File must exist.
Throws:
InappropriateTypeif file is not a regular file or a symlinkPermissionDeniedif we cannot read the file or the directory containting itNoSuchThingif the file does not exist
readFileStrict :: RawFilePath -> IO ByteString Source #
Read the given file strictly into memory.
Symbolic links are followed. File must exist.
Throws:
InappropriateTypeif file is not a regular file or a symlinkPermissionDeniedif we cannot read the file or the directory containting itNoSuchThingif the file does not exist
readFileStream :: RawFilePath -> IO (SerialT IO (Array Word8)) Source #
Open the given file as a filestream. Once the filestream exits, the filehandle is cleaned up.
Throws:
InappropriateTypeif file is not a regular file or a symlinkPermissionDeniedif we cannot read the file or the directory containting itNoSuchThingif the file does not exist
File writing
Arguments
| :: RawFilePath | |
| -> Maybe FileMode | if Nothing, file must exist |
| -> ByteString | |
| -> IO () |
Write a given ByteString to a file, truncating the file beforehand. Follows symlinks.
Throws:
InappropriateTypeif file is not a regular file or a symlinkPermissionDeniedif we cannot read the file or the directory containting itNoSuchThingif the file does not exist
Arguments
| :: RawFilePath | |
| -> Maybe FileMode | if Nothing, file must exist |
| -> ByteString | |
| -> IO () |
Write a given lazy ByteString to a file, truncating the file beforehand. Follows symlinks.
Throws:
InappropriateTypeif file is not a regular file or a symlinkPermissionDeniedif we cannot read the file or the directory containting itNoSuchThingif the file does not exist
Note: uses streamly under the hood
appendFile :: RawFilePath -> ByteString -> IO () Source #
Append a given ByteString to a file. The file must exist. Follows symlinks.
Throws:
InappropriateTypeif file is not a regular file or a symlinkPermissionDeniedif we cannot read the file or the directory containting itNoSuchThingif the file does not exist
File permissions
newFilePerms :: FileMode Source #
Default permissions for a new file.
newDirPerms :: FileMode Source #
Default permissions for a new directory.
File checks
doesExist :: RawFilePath -> IO Bool Source #
Checks if the given file exists. Does not follow symlinks.
Only eNOENT is catched (and returns False).
doesFileExist :: RawFilePath -> IO Bool Source #
Checks if the given file exists and is not a directory. Does not follow symlinks.
Only eNOENT is catched (and returns False).
doesDirectoryExist :: RawFilePath -> IO Bool Source #
Checks if the given file exists and is a directory. Does not follow symlinks.
Only eNOENT is catched (and returns False).
isReadable :: RawFilePath -> IO Bool Source #
Checks whether a file or folder is readable.
Only eACCES, eROFS, eTXTBSY, ePERM are catched (and return False).
Throws:
NoSuchThingif the file does not exist
isWritable :: RawFilePath -> IO Bool Source #
Checks whether a file or folder is writable.
Only eACCES, eROFS, eTXTBSY, ePERM are catched (and return False).
Throws:
NoSuchThingif the file does not exist
isExecutable :: RawFilePath -> IO Bool Source #
Checks whether a file or folder is executable.
Only eACCES, eROFS, eTXTBSY, ePERM are catched (and return False).
Throws:
NoSuchThingif the file does not exist
canOpenDirectory :: RawFilePath -> IO Bool Source #
Checks whether the directory at the given path exists and can be
opened. This invokes openDirStream which follows symlinks.
File times
setModificationTime :: RawFilePath -> EpochTime -> IO () Source #
setModificationTimeHiRes :: RawFilePath -> POSIXTime -> IO () Source #
Directory reading
Arguments
| :: RawFilePath | dir to read |
| -> IO [RawFilePath] |
Gets all filenames of the given directory. This excludes "." and "..". This version does not follow symbolic links.
The contents are not sorted and there is no guarantee on the ordering.
Throws:
NoSuchThingif directory does not existInappropriateTypeif file type is wrong (file)InappropriateTypeif file type is wrong (symlink to file)InappropriateTypeif file type is wrong (symlink to dir)PermissionDeniedif directory cannot be opened
Arguments
| :: RawFilePath | dir to read |
| -> IO [RawFilePath] |
Like getDirsFiles, but returns the filename only, instead
of prepending the base path.
getDirsFilesStream :: (MonadCatch m, MonadAsync m, MonadMask m) => RawFilePath -> IO (SerialT m RawFilePath) Source #
Like getDirsFiles', except returning a Stream.
Filetype operations
getFileType :: RawFilePath -> IO FileType Source #
Get the file type of the file located at the given path. Does not follow symbolic links.
Throws:
NoSuchThingif the file does not existPermissionDeniedif any part of the path is not accessible
Others
canonicalizePath :: RawFilePath -> IO RawFilePath Source #
Applies realpath on the given path.
Throws:
NoSuchThingif the file at the given path does not existNoSuchThingif the symlink is broken
toAbs :: RawFilePath -> IO RawFilePath Source #
Converts any path to an absolute path. This is done in the following way:
- if the path is already an absolute one, just return it
- if it's a relative path, prepend the current directory to it