hpath-0.7.2: Support for well-typed paths

Copyright© 2016 Julian Ospald
LicenseGPL-2
MaintainerJulian Ospald <hasufell@posteo.de>
Stabilityexperimental
Portabilityportable
Safe HaskellNone
LanguageHaskell2010

HPath.IO

Contents

Description

This module provides high-level IO related file operations like copy, delete, move and so on. It only operates on Path Abs which guarantees us well-typed paths which are absolute.

Some functions are just path-safe wrappers around unix functions, others have stricter exception handling and some implement functionality that doesn't have a unix counterpart (like copyDirRecursive).

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 not explicitly supported right now. Calling any of these functions on such a file may throw an exception or just do nothing.

Synopsis

Types

File copying

copyDirRecursive Source

Arguments

:: Path Abs

source dir

-> Path Abs

full destination

-> IO () 

Copies a directory recursively to the given destination. Does not follow symbolic links.

Safety/reliability concerns:

  • not atomic
  • examines filetypes explicitly
  • an explicit check throwDestinationInSource is 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:

  • NoSuchThing if source directory does not exist
  • PermissionDenied if output directory is not writable
  • PermissionDenied if source directory can't be opened
  • InvalidArgument if source directory is wrong type (symlink)
  • InvalidArgument if source directory is wrong type (regular file)
  • AlreadyExists if destination already exists
  • SameFile if source and destination are the same file (HPathIOException)
  • DestinationInSource if destination is contained in source (HPathIOException)

copyDirRecursiveOverwrite Source

Arguments

:: Path Abs

source dir

-> Path Abs

full destination

-> IO () 

Like copyDirRecursive except it overwrites contents of directories if any.

Throws:

  • NoSuchThing if source directory does not exist
  • PermissionDenied if output directory is not writable
  • PermissionDenied if source directory can't be opened
  • InvalidArgument if source directory is wrong type (symlink)
  • InvalidArgument if source directory is wrong type (regular file)
  • SameFile if source and destination are the same file (HPathIOException)
  • DestinationInSource if destination is contained in source (HPathIOException)

recreateSymlink Source

Arguments

:: Path Abs

the old symlink file

-> Path Abs

destination file

-> IO () 

Recreate a symlink.

Throws:

  • InvalidArgument if symlink file is wrong type (file)
  • InvalidArgument if symlink file is wrong type (directory)
  • PermissionDenied if output directory cannot be written to
  • PermissionDenied if source directory cannot be opened
  • AlreadyExists if destination file already exists
  • SameFile if source and destination are the same file (HPathIOException)

Note: calls symlink

copyFile Source

Arguments

:: Path Abs

source file

-> Path Abs

destination file

-> IO () 

Copies the given regular file to the given destination. Neither follows symbolic links, nor accepts them. For "copying" symbolic links, use recreateSymlink instead.

Throws:

  • NoSuchThing if source file does not exist
  • PermissionDenied if output directory is not writable
  • PermissionDenied if source directory can't be opened
  • InvalidArgument if source file is wrong type (symlink)
  • InvalidArgument if source file is wrong type (directory)
  • AlreadyExists if destination already exists
  • SameFile if source and destination are the same file (HPathIOException)

Note: calls sendfile and possibly read/write as fallback

copyFileOverwrite Source

Arguments

:: Path Abs

source file

-> Path Abs

destination file

-> IO () 

Like copyFile except it overwrites the destination if it already exists. This also works if source and destination are the same file.

Safety/reliability concerns:

  • not atomic, since it uses read/write

Throws:

  • NoSuchThing if source file does not exist
  • PermissionDenied if output directory is not writable
  • PermissionDenied if source directory can't be opened
  • InvalidArgument if source file is wrong type (symlink)
  • InvalidArgument if source file is wrong type (directory)
  • SameFile if source and destination are the same file (HPathIOException)

Note: calls sendfile and possibly read/write as fallback

easyCopy :: Path Abs -> Path Abs -> IO () Source

Copies anything. In case of a symlink, it is just recreated, even if it points to a directory.

Safety/reliability concerns:

easyCopyOverwrite :: Path Abs -> Path Abs -> IO () Source

Like easyCopy except it overwrites the destination if it already exists. For directories, this overwrites contents without pruning them, so the resulting directory may have more files than have been copied.

File deletion

deleteFile :: Path Abs -> IO () Source

Deletes the given file. Raises eISDIR if run on a directory. Does not follow symbolic links.

Throws:

  • InappropriateType for wrong file type (directory)
  • NoSuchThing if the file does not exist
  • PermissionDenied if the directory cannot be read

deleteDir :: Path Abs -> IO () Source

Deletes the given directory, which must be empty, never symlinks.

Throws:

  • InappropriateType for wrong file type (symlink to directory)
  • InappropriateType for wrong file type (regular file)
  • NoSuchThing if directory does not exist
  • UnsatisfiedConstraints if directory is not empty
  • PermissionDenied if we can't open or write to parent directory

Notes: calls rmdir

deleteDirRecursive :: Path Abs -> IO () Source

Deletes the given directory recursively. Does not follow symbolic links. Tries deleteDir first before attemtping a recursive deletion.

Safety/reliability concerns:

  • not atomic
  • examines filetypes explicitly

Throws:

  • InappropriateType for wrong file type (symlink to directory)
  • InappropriateType for wrong file type (regular file)
  • NoSuchThing if directory does not exist
  • PermissionDenied if we can't open or write to parent directory

easyDelete :: Path Abs -> IO () Source

Deletes a file, directory or symlink, whatever it may be. In case of directory, performs recursive deletion. In case of a symlink, the symlink file is deleted.

Safety/reliability concerns:

File opening

openFile :: Path Abs -> IO ProcessID Source

Opens a file appropriately by invoking xdg-open. The file type is not checked. This forks a process.

executeFile Source

Arguments

:: Path Abs

program

-> [ByteString]

arguments

-> IO ProcessID 

Executes a program with the given arguments. This forks a process.

File creation

createRegularFile :: Path Abs -> IO () Source

Create an empty regular file at the given directory with the given filename.

Throws:

  • PermissionDenied if output directory cannot be written to
  • AlreadyExists if destination file already exists

createDir :: Path Abs -> IO () Source

Create an empty directory at the given directory with the given filename.

Throws:

  • PermissionDenied if output directory cannot be written to
  • AlreadyExists if destination directory already exists

createSymlink Source

Arguments

:: Path Abs

destination file

-> ByteString

path the symlink points to

-> IO () 

Create a symlink.

Throws:

  • PermissionDenied if output directory cannot be written to
  • AlreadyExists if destination file already exists

Note: calls symlink

File renaming/moving

renameFile :: Path Abs -> Path Abs -> 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:

  • NoSuchThing if source file does not exist
  • PermissionDenied if output directory cannot be written to
  • PermissionDenied if source directory cannot be opened
  • UnsupportedOperation if source and destination are on different devices
  • FileDoesExist if destination file already exists (HPathIOException)
  • DirDoesExist if destination directory already exists (HPathIOException)
  • SameFile if destination and source are the same file (HPathIOException)

Note: calls rename (but does not allow to rename over existing files)

moveFile Source

Arguments

:: Path Abs

file to move

-> Path Abs

destination

-> 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:

  • copy-delete fallback is inherently non-atomic

Throws:

Note: calls rename (but does not allow to rename over existing files)

moveFileOverwrite Source

Arguments

:: Path Abs

file to move

-> Path Abs

destination

-> IO () 

Like moveFile, but overwrites the destination if it exists.

Does not follow symbolic links, but renames the symbolic link file.

Safety/reliability concerns:

  • copy-delete fallback is inherently non-atomic
  • checks for file types and destination file existence explicitly

Throws:

  • NoSuchThing if source file does not exist
  • PermissionDenied if output directory cannot be written to
  • PermissionDenied if source directory cannot be opened
  • SameFile if destination and source are the same file (HPathIOException)

Note: calls rename (but does not allow to rename over existing files)

File permissions

newFilePerms :: FileMode Source

Default permissions for a new file.

newDirPerms :: FileMode Source

Default permissions for a new directory.

Directory reading

getDirsFiles Source

Arguments

:: Path Abs

dir to read

-> IO [Path Abs] 

Gets all filenames of the given directory. This excludes "." and "..". This version does not follow symbolic links.

Throws:

  • NoSuchThing if directory does not exist
  • InappropriateType if file type is wrong (file)
  • InappropriateType if file type is wrong (symlink to file)
  • InappropriateType if file type is wrong (symlink to dir)
  • PermissionDenied if directory cannot be opened

Filetype operations

getFileType :: Path Abs -> IO FileType Source

Get the file type of the file located at the given path. Does not follow symbolic links.

Throws:

  • NoSuchThing if the file does not exist
  • PermissionDenied if any part of the path is not accessible

Others

canonicalizePath :: Path Abs -> IO (Path Abs) Source

Applies realpath on the given absolute path.

Throws:

  • NoSuchThing if the file at the given path does not exist
  • NoSuchThing if the symlink is broken