packages feed

Z-IO 0.5.0.0 → 0.6.0.0

raw patch · 19 files changed

+1091/−887 lines, 19 filesdep ~Z-DataPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: Z-Data

API changes (from Hackage documentation)

- Z.IO.FileSystem: AccessOK :: AccessResult
- Z.IO.FileSystem: DirEntBlock :: DirEntType
- Z.IO.FileSystem: DirEntChar :: DirEntType
- Z.IO.FileSystem: DirEntDir :: DirEntType
- Z.IO.FileSystem: DirEntFIFO :: DirEntType
- Z.IO.FileSystem: DirEntFile :: DirEntType
- Z.IO.FileSystem: DirEntLink :: DirEntType
- Z.IO.FileSystem: DirEntSocket :: DirEntType
- Z.IO.FileSystem: DirEntUnknown :: DirEntType
- Z.IO.FileSystem: FStat :: {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !FileMode -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !UID -> {-# UNPACK #-} !GID -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !UVTimeSpec -> {-# UNPACK #-} !UVTimeSpec -> {-# UNPACK #-} !UVTimeSpec -> {-# UNPACK #-} !UVTimeSpec -> FStat
- Z.IO.FileSystem: NoExistence :: AccessResult
- Z.IO.FileSystem: NoPermission :: AccessResult
- Z.IO.FileSystem: UVTimeSpec :: {-# UNPACK #-} !CLong -> {-# UNPACK #-} !CLong -> UVTimeSpec
- Z.IO.FileSystem: [stAtim] :: FStat -> {-# UNPACK #-} !UVTimeSpec
- Z.IO.FileSystem: [stBirthtim] :: FStat -> {-# UNPACK #-} !UVTimeSpec
- Z.IO.FileSystem: [stBlksize] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stBlocks] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stCtim] :: FStat -> {-# UNPACK #-} !UVTimeSpec
- Z.IO.FileSystem: [stDev] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stFlags] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stGID] :: FStat -> {-# UNPACK #-} !GID
- Z.IO.FileSystem: [stGen] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stIno] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stMode] :: FStat -> {-# UNPACK #-} !FileMode
- Z.IO.FileSystem: [stMtim] :: FStat -> {-# UNPACK #-} !UVTimeSpec
- Z.IO.FileSystem: [stNlink] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stRdev] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stSize] :: FStat -> {-# UNPACK #-} !Word64
- Z.IO.FileSystem: [stUID] :: FStat -> {-# UNPACK #-} !UID
- Z.IO.FileSystem: [uvtNanoSecond] :: UVTimeSpec -> {-# UNPACK #-} !CLong
- Z.IO.FileSystem: [uvtSecond] :: UVTimeSpec -> {-# UNPACK #-} !CLong
- Z.IO.FileSystem: access :: HasCallStack => CBytes -> AccessMode -> IO AccessResult
- Z.IO.FileSystem: chmod :: HasCallStack => CBytes -> FileMode -> IO ()
- Z.IO.FileSystem: chown :: HasCallStack => CBytes -> UID -> GID -> IO ()
- Z.IO.FileSystem: copyfile :: HasCallStack => CBytes -> CBytes -> CopyFileFlag -> IO ()
- Z.IO.FileSystem: data AccessResult
- Z.IO.FileSystem: data DirEntType
- Z.IO.FileSystem: data FStat
- Z.IO.FileSystem: data File
- Z.IO.FileSystem: data FilePtr
- Z.IO.FileSystem: data UVTimeSpec
- Z.IO.FileSystem: fchmod :: HasCallStack => File -> FileMode -> IO ()
- Z.IO.FileSystem: fchown :: HasCallStack => File -> UID -> GID -> IO ()
- Z.IO.FileSystem: fdatasync :: HasCallStack => File -> IO ()
- Z.IO.FileSystem: fstat :: HasCallStack => File -> IO FStat
- Z.IO.FileSystem: fsync :: HasCallStack => File -> IO ()
- Z.IO.FileSystem: ftruncate :: HasCallStack => File -> Int64 -> IO ()
- Z.IO.FileSystem: futime :: HasCallStack => File -> Double -> Double -> IO ()
- Z.IO.FileSystem: getFileFD :: File -> IO FD
- Z.IO.FileSystem: getFilePtrOffset :: FilePtr -> IO Int64
- Z.IO.FileSystem: initFile :: HasCallStack => CBytes -> FileFlag -> FileMode -> Resource File
- Z.IO.FileSystem: instance GHC.Show.Show Z.IO.FileSystem.File
- Z.IO.FileSystem: instance Z.Data.Text.Print.Print Z.IO.FileSystem.File
- Z.IO.FileSystem: instance Z.IO.Buffered.Input Z.IO.FileSystem.File
- Z.IO.FileSystem: instance Z.IO.Buffered.Input Z.IO.FileSystem.FilePtr
- Z.IO.FileSystem: instance Z.IO.Buffered.Output Z.IO.FileSystem.File
- Z.IO.FileSystem: instance Z.IO.Buffered.Output Z.IO.FileSystem.FilePtr
- Z.IO.FileSystem: isDir :: HasCallStack => CBytes -> IO Bool
- Z.IO.FileSystem: isFile :: HasCallStack => CBytes -> IO Bool
- Z.IO.FileSystem: isLink :: HasCallStack => CBytes -> IO Bool
- Z.IO.FileSystem: lchown :: HasCallStack => CBytes -> UID -> GID -> IO ()
- Z.IO.FileSystem: link :: HasCallStack => CBytes -> CBytes -> IO ()
- Z.IO.FileSystem: lstat :: HasCallStack => CBytes -> IO FStat
- Z.IO.FileSystem: lutime :: HasCallStack => CBytes -> Double -> Double -> IO ()
- Z.IO.FileSystem: mkdir :: HasCallStack => CBytes -> FileMode -> IO ()
- Z.IO.FileSystem: mkdirp :: HasCallStack => CBytes -> FileMode -> IO ()
- Z.IO.FileSystem: mkdtemp :: HasCallStack => CBytes -> IO CBytes
- Z.IO.FileSystem: newFilePtr :: File -> Int64 -> IO FilePtr
- Z.IO.FileSystem: pattern COPYFILE_DEFAULT :: CopyFileFlag
- Z.IO.FileSystem: pattern COPYFILE_EXCL :: CopyFileFlag
- Z.IO.FileSystem: pattern COPYFILE_FICLONE :: CopyFileFlag
- Z.IO.FileSystem: pattern COPYFILE_FICLONE_FORCE :: CopyFileFlag
- Z.IO.FileSystem: pattern DEFAULT_MODE :: FileMode
- Z.IO.FileSystem: pattern F_OK :: AccessMode
- Z.IO.FileSystem: pattern O_APPEND :: FileFlag
- Z.IO.FileSystem: pattern O_CREAT :: FileFlag
- Z.IO.FileSystem: pattern O_DIRECT :: FileFlag
- Z.IO.FileSystem: pattern O_DSYNC :: FileFlag
- Z.IO.FileSystem: pattern O_EXCL :: FileFlag
- Z.IO.FileSystem: pattern O_EXLOCK :: FileFlag
- Z.IO.FileSystem: pattern O_NOATIME :: FileFlag
- Z.IO.FileSystem: pattern O_NOFOLLOW :: FileFlag
- Z.IO.FileSystem: pattern O_RANDOM :: FileFlag
- Z.IO.FileSystem: pattern O_RDONLY :: FileFlag
- Z.IO.FileSystem: pattern O_RDWR :: FileFlag
- Z.IO.FileSystem: pattern O_SEQUENTIAL :: FileFlag
- Z.IO.FileSystem: pattern O_SHORT_LIVED :: FileFlag
- Z.IO.FileSystem: pattern O_SYMLINK :: FileFlag
- Z.IO.FileSystem: pattern O_SYNC :: FileFlag
- Z.IO.FileSystem: pattern O_TEMPORARY :: FileFlag
- Z.IO.FileSystem: pattern O_TRUNC :: FileFlag
- Z.IO.FileSystem: pattern O_WRONLY :: FileFlag
- Z.IO.FileSystem: pattern R_OK :: AccessMode
- Z.IO.FileSystem: pattern SEEK_CUR :: Whence
- Z.IO.FileSystem: pattern SEEK_END :: Whence
- Z.IO.FileSystem: pattern SEEK_SET :: Whence
- Z.IO.FileSystem: pattern SYMLINK_DEFAULT :: SymlinkFlag
- Z.IO.FileSystem: pattern SYMLINK_DIR :: SymlinkFlag
- Z.IO.FileSystem: pattern SYMLINK_JUNCTION :: SymlinkFlag
- Z.IO.FileSystem: pattern S_IFDIR :: FileMode
- Z.IO.FileSystem: pattern S_IFLNK :: FileMode
- Z.IO.FileSystem: pattern S_IFMT :: FileMode
- Z.IO.FileSystem: pattern S_IFREG :: FileMode
- Z.IO.FileSystem: pattern S_IRGRP :: FileMode
- Z.IO.FileSystem: pattern S_IROTH :: FileMode
- Z.IO.FileSystem: pattern S_IRUSR :: FileMode
- Z.IO.FileSystem: pattern S_IRWXG :: FileMode
- Z.IO.FileSystem: pattern S_IRWXO :: FileMode
- Z.IO.FileSystem: pattern S_IRWXU :: FileMode
- Z.IO.FileSystem: pattern S_IWGRP :: FileMode
- Z.IO.FileSystem: pattern S_IWUSR :: FileMode
- Z.IO.FileSystem: pattern S_IXGRP :: FileMode
- Z.IO.FileSystem: pattern S_IXUSR :: FileMode
- Z.IO.FileSystem: pattern W_OK :: AccessMode
- Z.IO.FileSystem: pattern X_OK :: AccessMode
- Z.IO.FileSystem: readFile :: HasCallStack => CBytes -> IO Bytes
- Z.IO.FileSystem: readFileP :: HasCallStack => File -> Ptr Word8 -> Int -> Int64 -> IO Int
- Z.IO.FileSystem: readJSONFile :: (HasCallStack, JSON a) => CBytes -> IO a
- Z.IO.FileSystem: readTextFile :: HasCallStack => CBytes -> IO Text
- Z.IO.FileSystem: readlink :: HasCallStack => CBytes -> IO CBytes
- Z.IO.FileSystem: realpath :: HasCallStack => CBytes -> IO CBytes
- Z.IO.FileSystem: rename :: HasCallStack => CBytes -> CBytes -> IO ()
- Z.IO.FileSystem: rmdir :: HasCallStack => CBytes -> IO ()
- Z.IO.FileSystem: rmdirrf :: HasCallStack => CBytes -> IO ()
- Z.IO.FileSystem: scandir :: HasCallStack => CBytes -> IO [(CBytes, DirEntType)]
- Z.IO.FileSystem: scandirRecursively :: HasCallStack => CBytes -> (CBytes -> DirEntType -> IO Bool) -> IO [CBytes]
- Z.IO.FileSystem: seek :: HasCallStack => File -> Int64 -> Whence -> IO Int64
- Z.IO.FileSystem: setFilePtrOffset :: FilePtr -> Int64 -> IO ()
- Z.IO.FileSystem: stat :: HasCallStack => CBytes -> IO FStat
- Z.IO.FileSystem: symlink :: HasCallStack => CBytes -> CBytes -> SymlinkFlag -> IO ()
- Z.IO.FileSystem: type AccessMode = CInt
- Z.IO.FileSystem: type CopyFileFlag = CInt
- Z.IO.FileSystem: type FileFlag = CInt
- Z.IO.FileSystem: type FileMode = CInt
- Z.IO.FileSystem: type SymlinkFlag = CInt
- Z.IO.FileSystem: type Whence = CInt
- Z.IO.FileSystem: unlink :: HasCallStack => CBytes -> IO ()
- Z.IO.FileSystem: utime :: HasCallStack => CBytes -> Double -> Double -> IO ()
- Z.IO.FileSystem: writeFile :: HasCallStack => CBytes -> Bytes -> IO ()
- Z.IO.FileSystem: writeFileP :: HasCallStack => File -> Ptr Word8 -> Int -> Int64 -> IO ()
- Z.IO.FileSystem: writeJSONFile :: (HasCallStack, JSON a) => CBytes -> a -> IO ()
- Z.IO.FileSystem: writeTextFile :: HasCallStack => CBytes -> Text -> IO ()
- Z.IO.FileSystem.Threaded: data FilePtrT
- Z.IO.FileSystem.Threaded: instance Z.IO.Buffered.Input Z.IO.FileSystem.Threaded.FilePtrT
- Z.IO.FileSystem.Threaded: instance Z.IO.Buffered.Output Z.IO.FileSystem.Threaded.FilePtrT
- Z.IO.FileSystem.Threaded: newFilePtrT :: File -> Int64 -> IO FilePtrT
- Z.IO.FileSystem.Threaded: pattern DEFAULT_MODE :: FileMode
- Z.IO.FileSystem.Threaded: rmdirrf :: HasCallStack => CBytes -> IO ()
- Z.IO.UV.FFI: pattern DEFAULT_MODE :: FileMode
+ Z.IO.Exception: throwUV :: (Integral a, HasCallStack) => a -> IO b
+ Z.IO.Exception: throwUVIf :: (HasCallStack, Integral a) => IO a -> (a -> Bool) -> IO a
+ Z.IO.Exception: throwUVIf_ :: (HasCallStack, Integral a) => IO a -> (a -> Bool) -> IO ()
+ Z.IO.FileSystem.Base: AccessOK :: AccessResult
+ Z.IO.FileSystem.Base: DirEntBlock :: DirEntType
+ Z.IO.FileSystem.Base: DirEntChar :: DirEntType
+ Z.IO.FileSystem.Base: DirEntDir :: DirEntType
+ Z.IO.FileSystem.Base: DirEntFIFO :: DirEntType
+ Z.IO.FileSystem.Base: DirEntFile :: DirEntType
+ Z.IO.FileSystem.Base: DirEntLink :: DirEntType
+ Z.IO.FileSystem.Base: DirEntSocket :: DirEntType
+ Z.IO.FileSystem.Base: DirEntUnknown :: DirEntType
+ Z.IO.FileSystem.Base: FStat :: {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !FileMode -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !UID -> {-# UNPACK #-} !GID -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !UVTimeSpec -> {-# UNPACK #-} !UVTimeSpec -> {-# UNPACK #-} !UVTimeSpec -> {-# UNPACK #-} !UVTimeSpec -> FStat
+ Z.IO.FileSystem.Base: NoExistence :: AccessResult
+ Z.IO.FileSystem.Base: NoPermission :: AccessResult
+ Z.IO.FileSystem.Base: UVTimeSpec :: {-# UNPACK #-} !CLong -> {-# UNPACK #-} !CLong -> UVTimeSpec
+ Z.IO.FileSystem.Base: [stAtim] :: FStat -> {-# UNPACK #-} !UVTimeSpec
+ Z.IO.FileSystem.Base: [stBirthtim] :: FStat -> {-# UNPACK #-} !UVTimeSpec
+ Z.IO.FileSystem.Base: [stBlksize] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stBlocks] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stCtim] :: FStat -> {-# UNPACK #-} !UVTimeSpec
+ Z.IO.FileSystem.Base: [stDev] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stFlags] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stGID] :: FStat -> {-# UNPACK #-} !GID
+ Z.IO.FileSystem.Base: [stGen] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stIno] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stMode] :: FStat -> {-# UNPACK #-} !FileMode
+ Z.IO.FileSystem.Base: [stMtim] :: FStat -> {-# UNPACK #-} !UVTimeSpec
+ Z.IO.FileSystem.Base: [stNlink] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stRdev] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stSize] :: FStat -> {-# UNPACK #-} !Word64
+ Z.IO.FileSystem.Base: [stUID] :: FStat -> {-# UNPACK #-} !UID
+ Z.IO.FileSystem.Base: [uvtNanoSecond] :: UVTimeSpec -> {-# UNPACK #-} !CLong
+ Z.IO.FileSystem.Base: [uvtSecond] :: UVTimeSpec -> {-# UNPACK #-} !CLong
+ Z.IO.FileSystem.Base: access :: HasCallStack => CBytes -> AccessMode -> IO AccessResult
+ Z.IO.FileSystem.Base: chmod :: HasCallStack => CBytes -> FileMode -> IO ()
+ Z.IO.FileSystem.Base: chown :: HasCallStack => CBytes -> UID -> GID -> IO ()
+ Z.IO.FileSystem.Base: copyfile :: HasCallStack => CBytes -> CBytes -> CopyFileFlag -> IO ()
+ Z.IO.FileSystem.Base: data AccessResult
+ Z.IO.FileSystem.Base: data DirEntType
+ Z.IO.FileSystem.Base: data FStat
+ Z.IO.FileSystem.Base: data File
+ Z.IO.FileSystem.Base: data FilePtr
+ Z.IO.FileSystem.Base: data UVTimeSpec
+ Z.IO.FileSystem.Base: doesDirExist :: CBytes -> IO Bool
+ Z.IO.FileSystem.Base: doesFileExist :: CBytes -> IO Bool
+ Z.IO.FileSystem.Base: doesPathExist :: CBytes -> IO Bool
+ Z.IO.FileSystem.Base: fchmod :: HasCallStack => File -> FileMode -> IO ()
+ Z.IO.FileSystem.Base: fchown :: HasCallStack => File -> UID -> GID -> IO ()
+ Z.IO.FileSystem.Base: fdatasync :: HasCallStack => File -> IO ()
+ Z.IO.FileSystem.Base: fstat :: HasCallStack => File -> IO FStat
+ Z.IO.FileSystem.Base: fsync :: HasCallStack => File -> IO ()
+ Z.IO.FileSystem.Base: ftruncate :: HasCallStack => File -> Int64 -> IO ()
+ Z.IO.FileSystem.Base: futime :: HasCallStack => File -> Double -> Double -> IO ()
+ Z.IO.FileSystem.Base: getFileFD :: File -> IO FD
+ Z.IO.FileSystem.Base: getFilePtrOffset :: FilePtr -> IO Int64
+ Z.IO.FileSystem.Base: initFile :: HasCallStack => CBytes -> FileFlag -> FileMode -> Resource File
+ Z.IO.FileSystem.Base: initTempDir :: CBytes -> Resource CBytes
+ Z.IO.FileSystem.Base: initTempFile :: CBytes -> Resource File
+ Z.IO.FileSystem.Base: instance GHC.Show.Show Z.IO.FileSystem.Base.File
+ Z.IO.FileSystem.Base: instance Z.Data.Text.Print.Print Z.IO.FileSystem.Base.File
+ Z.IO.FileSystem.Base: instance Z.IO.Buffered.Input Z.IO.FileSystem.Base.File
+ Z.IO.FileSystem.Base: instance Z.IO.Buffered.Input Z.IO.FileSystem.Base.FilePtr
+ Z.IO.FileSystem.Base: instance Z.IO.Buffered.Output Z.IO.FileSystem.Base.File
+ Z.IO.FileSystem.Base: instance Z.IO.Buffered.Output Z.IO.FileSystem.Base.FilePtr
+ Z.IO.FileSystem.Base: isDir :: HasCallStack => CBytes -> IO Bool
+ Z.IO.FileSystem.Base: isDirSt :: FStat -> Bool
+ Z.IO.FileSystem.Base: isFile :: HasCallStack => CBytes -> IO Bool
+ Z.IO.FileSystem.Base: isFileSt :: FStat -> Bool
+ Z.IO.FileSystem.Base: isLink :: HasCallStack => CBytes -> IO Bool
+ Z.IO.FileSystem.Base: isLinkSt :: FStat -> Bool
+ Z.IO.FileSystem.Base: lchown :: HasCallStack => CBytes -> UID -> GID -> IO ()
+ Z.IO.FileSystem.Base: link :: HasCallStack => CBytes -> CBytes -> IO ()
+ Z.IO.FileSystem.Base: lstat :: HasCallStack => CBytes -> IO FStat
+ Z.IO.FileSystem.Base: lstat' :: HasCallStack => CBytes -> IO (Maybe FStat)
+ Z.IO.FileSystem.Base: lutime :: HasCallStack => CBytes -> Double -> Double -> IO ()
+ Z.IO.FileSystem.Base: mkdir :: HasCallStack => CBytes -> FileMode -> IO ()
+ Z.IO.FileSystem.Base: mkdirp :: HasCallStack => CBytes -> FileMode -> IO ()
+ Z.IO.FileSystem.Base: mkdtemp :: HasCallStack => CBytes -> IO CBytes
+ Z.IO.FileSystem.Base: mkstemp :: HasCallStack => CBytes -> IO CBytes
+ Z.IO.FileSystem.Base: newFilePtr :: File -> Int64 -> IO FilePtr
+ Z.IO.FileSystem.Base: pattern COPYFILE_DEFAULT :: CopyFileFlag
+ Z.IO.FileSystem.Base: pattern COPYFILE_EXCL :: CopyFileFlag
+ Z.IO.FileSystem.Base: pattern COPYFILE_FICLONE :: CopyFileFlag
+ Z.IO.FileSystem.Base: pattern COPYFILE_FICLONE_FORCE :: CopyFileFlag
+ Z.IO.FileSystem.Base: pattern DEFAULT_DIR_MODE :: FileMode
+ Z.IO.FileSystem.Base: pattern DEFAULT_FILE_MODE :: FileMode
+ Z.IO.FileSystem.Base: pattern F_OK :: AccessMode
+ Z.IO.FileSystem.Base: pattern O_APPEND :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_CREAT :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_DIRECT :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_DSYNC :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_EXCL :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_EXLOCK :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_NOATIME :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_NOFOLLOW :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_RANDOM :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_RDONLY :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_RDWR :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_SEQUENTIAL :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_SHORT_LIVED :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_SYMLINK :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_SYNC :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_TEMPORARY :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_TRUNC :: FileFlag
+ Z.IO.FileSystem.Base: pattern O_WRONLY :: FileFlag
+ Z.IO.FileSystem.Base: pattern R_OK :: AccessMode
+ Z.IO.FileSystem.Base: pattern SEEK_CUR :: Whence
+ Z.IO.FileSystem.Base: pattern SEEK_END :: Whence
+ Z.IO.FileSystem.Base: pattern SEEK_SET :: Whence
+ Z.IO.FileSystem.Base: pattern SYMLINK_DEFAULT :: SymlinkFlag
+ Z.IO.FileSystem.Base: pattern SYMLINK_DIR :: SymlinkFlag
+ Z.IO.FileSystem.Base: pattern SYMLINK_JUNCTION :: SymlinkFlag
+ Z.IO.FileSystem.Base: pattern S_IFDIR :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IFLNK :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IFMT :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IFREG :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IRGRP :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IROTH :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IRUSR :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IRWXG :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IRWXO :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IRWXU :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IWGRP :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IWUSR :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IXGRP :: FileMode
+ Z.IO.FileSystem.Base: pattern S_IXUSR :: FileMode
+ Z.IO.FileSystem.Base: pattern W_OK :: AccessMode
+ Z.IO.FileSystem.Base: pattern X_OK :: AccessMode
+ Z.IO.FileSystem.Base: readFile :: HasCallStack => CBytes -> IO Bytes
+ Z.IO.FileSystem.Base: readFileP :: HasCallStack => File -> Ptr Word8 -> Int -> Int64 -> IO Int
+ Z.IO.FileSystem.Base: readJSONFile :: (HasCallStack, JSON a) => CBytes -> IO a
+ Z.IO.FileSystem.Base: readTextFile :: HasCallStack => CBytes -> IO Text
+ Z.IO.FileSystem.Base: readlink :: HasCallStack => CBytes -> IO CBytes
+ Z.IO.FileSystem.Base: realpath :: HasCallStack => CBytes -> IO CBytes
+ Z.IO.FileSystem.Base: rename :: HasCallStack => CBytes -> CBytes -> IO ()
+ Z.IO.FileSystem.Base: rmdir :: HasCallStack => CBytes -> IO ()
+ Z.IO.FileSystem.Base: rmrf :: HasCallStack => CBytes -> IO ()
+ Z.IO.FileSystem.Base: scandir :: HasCallStack => CBytes -> IO [(CBytes, DirEntType)]
+ Z.IO.FileSystem.Base: scandirRecursively :: HasCallStack => CBytes -> (CBytes -> DirEntType -> IO Bool) -> IO [CBytes]
+ Z.IO.FileSystem.Base: seek :: HasCallStack => File -> Int64 -> Whence -> IO Int64
+ Z.IO.FileSystem.Base: setFilePtrOffset :: FilePtr -> Int64 -> IO ()
+ Z.IO.FileSystem.Base: stat :: HasCallStack => CBytes -> IO FStat
+ Z.IO.FileSystem.Base: stat' :: HasCallStack => CBytes -> IO (Maybe FStat)
+ Z.IO.FileSystem.Base: symlink :: HasCallStack => CBytes -> CBytes -> SymlinkFlag -> IO ()
+ Z.IO.FileSystem.Base: type AccessMode = CInt
+ Z.IO.FileSystem.Base: type CopyFileFlag = CInt
+ Z.IO.FileSystem.Base: type FileFlag = CInt
+ Z.IO.FileSystem.Base: type FileMode = CInt
+ Z.IO.FileSystem.Base: type SymlinkFlag = CInt
+ Z.IO.FileSystem.Base: type Whence = CInt
+ Z.IO.FileSystem.Base: unlink :: HasCallStack => CBytes -> IO ()
+ Z.IO.FileSystem.Base: utime :: HasCallStack => CBytes -> Double -> Double -> IO ()
+ Z.IO.FileSystem.Base: writeFile :: HasCallStack => CBytes -> Bytes -> IO ()
+ Z.IO.FileSystem.Base: writeFileP :: HasCallStack => File -> Ptr Word8 -> Int -> Int64 -> IO ()
+ Z.IO.FileSystem.Base: writeJSONFile :: (HasCallStack, JSON a) => CBytes -> a -> IO ()
+ Z.IO.FileSystem.Base: writeTextFile :: HasCallStack => CBytes -> Text -> IO ()
+ Z.IO.FileSystem.Threaded: data FilePtr
+ Z.IO.FileSystem.Threaded: doesDirExist :: CBytes -> IO Bool
+ Z.IO.FileSystem.Threaded: doesFileExist :: CBytes -> IO Bool
+ Z.IO.FileSystem.Threaded: doesPathExist :: CBytes -> IO Bool
+ Z.IO.FileSystem.Threaded: initTempDir :: CBytes -> Resource CBytes
+ Z.IO.FileSystem.Threaded: initTempFile :: CBytes -> Resource File
+ Z.IO.FileSystem.Threaded: instance Z.IO.Buffered.Input Z.IO.FileSystem.Threaded.FilePtr
+ Z.IO.FileSystem.Threaded: instance Z.IO.Buffered.Output Z.IO.FileSystem.Threaded.FilePtr
+ Z.IO.FileSystem.Threaded: isDirSt :: FStat -> Bool
+ Z.IO.FileSystem.Threaded: isFileSt :: FStat -> Bool
+ Z.IO.FileSystem.Threaded: isLinkSt :: FStat -> Bool
+ Z.IO.FileSystem.Threaded: lstat' :: HasCallStack => CBytes -> IO (Maybe FStat)
+ Z.IO.FileSystem.Threaded: mkstemp :: HasCallStack => CBytes -> IO CBytes
+ Z.IO.FileSystem.Threaded: newFilePtr :: File -> Int64 -> IO FilePtr
+ Z.IO.FileSystem.Threaded: pattern DEFAULT_DIR_MODE :: FileMode
+ Z.IO.FileSystem.Threaded: pattern DEFAULT_FILE_MODE :: FileMode
+ Z.IO.FileSystem.Threaded: rmrf :: HasCallStack => CBytes -> IO ()
+ Z.IO.FileSystem.Threaded: stat' :: HasCallStack => CBytes -> IO (Maybe FStat)
+ Z.IO.UV.FFI: hs_uv_fs_mkstemp :: BA# Word8 -> Int -> MBA# Word8 -> IO Int
+ Z.IO.UV.FFI: hs_uv_fs_mkstemp_threaded :: BA# Word8 -> Int -> MBA# Word8 -> Ptr UVLoop -> IO UVSlotUnsafe
+ Z.IO.UV.FFI: pattern DEFAULT_DIR_MODE :: FileMode
+ Z.IO.UV.FFI: pattern DEFAULT_FILE_MODE :: FileMode
- Z.IO.FileSystem.Threaded: getFilePtrOffset :: FilePtrT -> IO Int64
+ Z.IO.FileSystem.Threaded: getFilePtrOffset :: FilePtr -> IO Int64
- Z.IO.FileSystem.Threaded: setFilePtrOffset :: FilePtrT -> Int64 -> IO ()
+ Z.IO.FileSystem.Threaded: setFilePtrOffset :: FilePtr -> Int64 -> IO ()

Files

ChangeLog.md view
@@ -1,11 +1,20 @@ # Revision history for Z-IO +## 0.6.0.0  -- 2020-02-04++* FileSystem: replace `DEFAULT_MODE` with `DEFAULT_FILE_MODE` & `DEFAULT_DIR_MODE`.+* Ignore exception while `mkdirp` on an exist directory.+* Make `rmrf` more like `rm -rf`, which can be used on files.+* Add `doesPathExist/doesFileExist/doesDirExist` to file system module.+* Add `Z.IO.FileSystem` re-export `Z.IO.FileSystem.Watch` and `Z.IO.FileSystem.FilePath`.+* Add `mkstemp`, `initTempFile/initTempDir` to file system module.+ ## 0.5.0.0  -- 2020-01-28  * Add `unwrap/unwrap'` to `Z.IO.Exception`. * Add `readParseChunks` to `Z.IO.Buffered`, Change `readParser`'s type to match `readParseChunks`. * Add `sourceParseChunksBufferedInput`, `sourceParseChunksInput` to `Z.IO.BIO`.-* Add `newJSONLogger/defaultJSONFmt` to `Z.IO.Logger`, provide simple JSON structured logging. +* Add `newJSONLogger/defaultJSONFmt` to `Z.IO.Logger`, provide simple JSON structured logging.  ## 0.3.0.0  -- 2020-12-29 
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) Project Z Contributors, 2017-2020+Copyright (c) Z.Haskell Contributors, 2017-2020  All rights reserved. 
README.md view
@@ -1,12 +1,12 @@ ## Z-IO  [![Hackage](https://img.shields.io/hackage/v/Z-IO.svg?style=flat)](https://hackage.haskell.org/package/Z-IO)-[![Linux Build Status](https://github.com/haskell-Z/z-io/workflows/ubuntu-ci/badge.svg)](https://github.com/haskell-Z/z-io/actions)-[![MacOS Build Status](https://github.com/haskell-Z/z-io/workflows/osx-ci/badge.svg)](https://github.com/haskell-Z/z-io/actions)-[![Windows Build Status](https://github.com/haskell-Z/z-io/workflows/win-ci/badge.svg)](https://github.com/haskell-Z/z-io/actions)-[![Docker Build Status](https://github.com/haskell-Z/z-io/workflows/docker-ci/badge.svg)](https://github.com/haskell-Z/z-io/actions)+[![Linux Build Status](https://github.com/ZHaskell/z-io/workflows/ubuntu-ci/badge.svg)](https://github.com/ZHaskell/z-io/actions)+[![MacOS Build Status](https://github.com/ZHaskell/z-io/workflows/osx-ci/badge.svg)](https://github.com/ZHaskell/z-io/actions)+[![Windows Build Status](https://github.com/ZHaskell/z-io/workflows/win-ci/badge.svg)](https://github.com/ZHaskell/z-io/actions)+[![Docker Build Status](https://github.com/ZHaskell/z-io/workflows/docker-ci/badge.svg)](https://github.com/ZHaskell/z-io/actions) -This package is part of [Z](https://github.com/haskell-Z/Z) project, provides basic IO operations:+This package is part of [Z.Haskell](https://github.com/ZHaskell/Z) project, provides basic IO operations:  * IO resource management, resource pool * File system operations@@ -62,7 +62,7 @@  ```bash # get code-git clone --recursive git@github.com:haskell-Z/z-io.git+git clone --recursive git@github.com:ZHaskell/z-io.git cd z-io # build cabal build
Z-IO.cabal view
@@ -1,23 +1,26 @@ cabal-version:              2.4 name:                       Z-IO-version:                    0.5.0.0+version:                    0.6.0.0 synopsis:                   Simple and high performance IO toolkit for Haskell description:                Simple and high performance IO toolkit for Haskell, including                             file system, network, ipc and more! license:                    BSD-3-Clause license-file:               LICENSE-author:                     Dong Han, Tao He+author:                     Z.Haskell Contributors maintainer:                 winterland1989@gmail.com-copyright:                  (c) Project Z Contributors+copyright:                  (c) Z.Haskell Contributors category:                   Data build-type:                 Simple-homepage:                   https://github.com/haskell-Z/Z-IO-bug-reports:                https://github.com/haskell-Z/Z-IO/issues+homepage:                   https://github.com/ZHaskell/Z-IO+bug-reports:                https://github.com/ZHaskell/Z-IO/issues  extra-source-files:         ChangeLog.md                             README.md                             LICENSE +                            -- shared Haskell soruce+                            Z/IO/FileSystem/_Shared.hs+                             -- zlib C sources                             third_party/zlib/crc32.h                             third_party/zlib/inffast.h @@ -75,7 +78,7 @@  source-repository head     type:     git-    location: git://github.com/haskell-Z/Z-IO.git+    location: git://github.com/ZHaskell/Z-IO.git  flag no-pkg-config     description: Don't use pkg-config to check for library dependences(on platforms other than linux, win and osx)@@ -89,8 +92,9 @@                             Z.IO.BIO.Concurrent                              Z.IO.FileSystem-                            Z.IO.FileSystem.FilePath+                            Z.IO.FileSystem.Base                             Z.IO.FileSystem.Threaded+                            Z.IO.FileSystem.FilePath                             Z.IO.FileSystem.Watch                              Z.IO.Network.SocketAddr@@ -125,7 +129,7 @@                           , stm                     == 2.5.*                           , unordered-containers    == 0.2.*                           , containers              == 0.6.*-                          , Z-Data                  == 0.5.* +                          , Z-Data                  == 0.6.*                            , time                    >= 1.9 && <= 2.0                           , unix-time               >= 0.4.7 && <= 0.5 
Z/IO/BIO.hs view
@@ -108,7 +108,7 @@ import           Z.Data.Vector.Hex import           Z.IO.Buffered import           Z.IO.Exception-import qualified Z.IO.FileSystem        as FS+import qualified Z.IO.FileSystem.Base   as FS import           Z.IO.Resource  -- | A 'BIO'(blocked IO) node.@@ -496,7 +496,7 @@ initSourceFromFile :: HasCallStack => CBytes -> Resource (Source V.Bytes) {-# INLINABLE initSourceFromFile #-} initSourceFromFile p = do-    f <- FS.initFile p FS.O_RDONLY FS.DEFAULT_MODE+    f <- FS.initFile p FS.O_RDONLY FS.DEFAULT_FILE_MODE     liftIO (sourceFromInput f)  -- | Turn input device into a packet source.@@ -547,7 +547,7 @@ initSinkToFile :: HasCallStack => CBytes -> Resource (Sink V.Bytes) {-# INLINABLE initSinkToFile #-} initSinkToFile p = do-    f <- FS.initFile p (FS.O_APPEND .|. FS.O_CREAT .|. FS.O_WRONLY) FS.DEFAULT_MODE+    f <- FS.initFile p (FS.O_APPEND .|. FS.O_CREAT .|. FS.O_WRONLY) FS.DEFAULT_FILE_MODE     liftIO (sinkToOutput f)  -- | Turn an 'Output' into 'B.Builder' sink.
Z/IO/BIO/Concurrent.hs view
@@ -25,6 +25,9 @@ @ (sink, src) <- newTQueueNode 2  -- it's important to correctly set the numebr of producers +--------------------------------------------------------------------------------+-- producers+ forkIO $ do     ...     push x sink             -- producer using push@@ -35,6 +38,10 @@     ...     (runBIO $ ... >|> sink) -- producer using BIO         `onException` (pull sink)++--------------------------------------------------------------------------------+-- consumers+ forkIO $ do     ...     r <- pull src           -- consumer using pull
Z/IO/BIO/Zlib.hsc view
@@ -7,7 +7,14 @@ Stability   : experimental Portability : non-portable -This module provides <https://zlib.net zlib> bindings, with 'BIO' streaming interface.+This module provides <https://zlib.net zlib> bindings, with 'BIO' streaming interface, e.g.++@+-- add compressor to your BIO chain to compress streaming blocks of 'V.Bytes'.+(_, zlibCompressor) <- newCompress defaultCompressConfig{compressWindowBits = 31}+runBIO $ src >|> zlibCompressor >|> sink+@+ -}  module Z.IO.BIO.Zlib(
Z/IO/Exception.hs view
@@ -61,6 +61,9 @@   , throwOOMIfNull   , throwUVIfMinus   , throwUVIfMinus_+  , throwUVIf+  , throwUVIf_+  , throwUV   , throwECLOSED   , throwECLOSEDSTM   , throwUVError@@ -78,7 +81,7 @@ import           Control.Concurrent.STM import           Control.Exception      hiding (IOException) import           Control.Monad-import           Data.Typeable          (Typeable, cast)+import           Data.Typeable          (cast) import           Foreign.C.Types import           Foreign.Ptr import           GHC.Stack@@ -143,37 +146,35 @@         else return addr  -- | Throw appropriate IO exception if return value < 0 (libuv's convention).---+{-# INLINABLE throwUVIfMinus #-} throwUVIfMinus :: (HasCallStack, Integral a)                => IO a    -- ^ the IO action                -> IO a-{-# INLINABLE throwUVIfMinus #-}-throwUVIfMinus f = do-    errno <- f-    let errno' = fromIntegral errno-    if errno' < 0-        then do-            name <- uvErrName errno'-            desc <- uvStdError errno'-            throwUVError errno' (IOEInfo name desc callStack)-        else return errno+throwUVIfMinus f = throwUVIf f (< 0)  -- | Throw appropriate IO exception if return value < 0, otherwise ignore the result.---+{-# INLINABLE throwUVIfMinus_ #-} throwUVIfMinus_ :: (HasCallStack, Integral a)                 => IO a    -- ^ the IO action                 -> IO ()-{-# INLINABLE throwUVIfMinus_ #-}-throwUVIfMinus_ f = do+throwUVIfMinus_ f = throwUVIf_ f (< 0)++-- | Throw appropriate IO exception if condition is true.+throwUVIf :: (HasCallStack, Integral a) => IO a -> (a -> Bool) -> IO a+{-# INLINABLE throwUVIf #-}+throwUVIf f cond = do     errno <- f-    let errno' = fromIntegral errno-    when (errno' < 0) $ do-        name <- uvErrName errno'-        desc <- uvStdError errno'-        throwUVError errno' (IOEInfo name desc callStack)+    if cond errno+       then throwUV errno+       else return errno +-- | Throw appropriate IO exception if condition is true, otherwise ignore the+-- result.+throwUVIf_ :: (HasCallStack, Integral a) => IO a -> (a -> Bool) -> IO ()+{-# INLINABLE throwUVIf_ #-}+throwUVIf_ f cond = void $ throwUVIf f cond+ -- | Throw 'ResourceVanished' with name 'ECLOSED' and description 'resource is closed'.--- throwECLOSED :: HasCallStack => IO a {-# INLINABLE throwECLOSED #-} throwECLOSED = throwIO (ResourceVanished@@ -202,7 +203,7 @@ unwrap' :: HasCallStack => T.Text -> T.Text -> Maybe a -> IO a {-# INLINABLE unwrap' #-} unwrap' _ _ (Just x) = return x-unwrap' n d Nothing = throwOtherError n d+unwrap' n d Nothing  = throwOtherError n d  -------------------------------------------------------------------------------- @@ -226,7 +227,17 @@          T.stringUTF8 (prettyCallStack cstack)          "}" +-- | Throw a UV Exception with given libuv's errno.+throwUV :: (Integral a, HasCallStack) => a -> IO b+{-# INLINABLE throwUV #-}+throwUV e = do+    let e' = fromIntegral e+    name <- uvErrName e'+    desc <- uvStdError e'+    throwUVError e' (IOEInfo name desc callStack)+ throwUVError :: CInt -> IOEInfo -> IO a+{-# INLINABLE throwUVError #-} throwUVError e info = case e of     UV_EOF             -> throwIO (EOF                     info)     UV_E2BIG           -> throwIO (ResourceExhausted       info)
Z/IO/FileSystem.hs view
@@ -1,601 +1,27 @@ {-|-Module      : Z.IO.FileSystem-Description : Filesystem IO-Copyright   : (c) Dong Han, 2017-2020+Module      : Z.IO.Network+Description : FileSystem Umbrella module+Copyright   : (c) Song Xue, Dong Han, 2020 License     : BSD Maintainer  : winterland1989@gmail.com Stability   : experimental Portability : non-portable -This module provide IO operations related to filesystem, operations are implemented using unsafe FFIs, which should be prefered when the operations' estimated time is short(<1ms), which is much common on modern SSDs.+Umbrella module to export everything you need to start using file.  -}  module Z.IO.FileSystem-  ( -- * regular file devices-    File, initFile, readFileP, writeFileP, getFileFD, seek-  , readFile, readTextFile, writeFile, writeTextFile-  , readJSONFile, writeJSONFile-    -- * file offset bundle-  , FilePtr, newFilePtr, getFilePtrOffset, setFilePtrOffset-  -- * filesystem operations-  , mkdir, mkdirp-  , unlink-  , mkdtemp-  , rmdir, rmdirrf-  , DirEntType(..)-  , scandir-  , scandirRecursively-  , FStat(..), UVTimeSpec(..)-  , stat, lstat, fstat-  , isLink, isDir, isFile-  , rename-  , fsync, fdatasync-  , ftruncate-  , copyfile-  , AccessResult(..)-  , access-  , chmod, fchmod-  , utime, futime, lutime-  , link, symlink-  , readlink, realpath-  , chown, fchown, lchown-  -- * opening constant-  -- ** AccessMode-  , AccessMode-  , pattern F_OK-  , pattern R_OK-  , pattern W_OK-  , pattern X_OK-  -- ** FileMode-  , FileMode-  , pattern DEFAULT_MODE-  , pattern S_IRWXU-  , pattern S_IRUSR-  , pattern S_IWUSR-  , pattern S_IXUSR-  , pattern S_IRWXG-  , pattern S_IRGRP-  , pattern S_IWGRP-  , pattern S_IXGRP-  , pattern S_IRWXO-  , pattern S_IROTH-  -- ** file type constant-  , pattern S_IFMT-  , pattern S_IFLNK-  , pattern S_IFDIR-  , pattern S_IFREG-  -- ** FileFlag-  , FileFlag-  , pattern O_APPEND-  , pattern O_CREAT-  , pattern O_DIRECT-  , pattern O_DSYNC-  , pattern O_EXCL-  , pattern O_EXLOCK-  , pattern O_NOATIME-  , pattern O_NOFOLLOW-  , pattern O_RDONLY-  , pattern O_RDWR-  , pattern O_SYMLINK-  , pattern O_SYNC-  , pattern O_TRUNC-  , pattern O_WRONLY-  , pattern O_RANDOM-  , pattern O_SHORT_LIVED-  , pattern O_SEQUENTIAL-  , pattern O_TEMPORARY-  -- ** CopyFileFlag-  , CopyFileFlag-  , pattern COPYFILE_DEFAULT-  , pattern COPYFILE_EXCL-  , pattern COPYFILE_FICLONE-  , pattern COPYFILE_FICLONE_FORCE-  -- ** SymlinkFlag-  , SymlinkFlag-  , pattern SYMLINK_DEFAULT-  , pattern SYMLINK_DIR-  , pattern SYMLINK_JUNCTION-  -- ** Whence-  , Whence-  , pattern SEEK_SET-  , pattern SEEK_CUR-  , pattern SEEK_END-  ) where--import           Control.Monad-import           Data.Bits-import           Data.Int-import           Data.IORef-import           Data.Word-import           Foreign.Ptr-import           Foreign.Storable               (peekElemOff)-import           Foreign.Marshal.Alloc          (allocaBytes)-import           Z.Data.CBytes                  as CBytes-import           Z.Data.PrimRef.PrimIORef-import qualified Z.Data.Text                    as T-import qualified Z.Data.Text.Print              as T-import qualified Z.Data.Vector                  as V-import qualified Z.Data.JSON                    as JSON-import           Z.Foreign-import           Z.IO.Buffered-import           Z.IO.Exception-import qualified Z.IO.FileSystem.FilePath       as P-import           Z.IO.Resource-import           Z.IO.UV.FFI-import           Prelude hiding (writeFile, readFile)------------------------------------------------------------------------------------- File---- | 'File' and its operations are NOT thread safe, use 'MVar' 'File' in multiple threads------ libuv implements read and write method with both implict and explict offset capable.--- Implict offset interface is provided by 'Input' \/ 'Output' instances.--- Explict offset interface is provided by 'readFileP' \/ 'writeFileP'.----data File =  File  {-# UNPACK #-} !FD      -- ^ the file-                   {-# UNPACK #-} !(IORef Bool)  -- ^ closed flag--instance Show File where show = T.toString--instance T.Print File where-    toUTF8BuilderP _ (File fd _) = "File " >> T.int fd---- | Return File fd.-getFileFD :: File -> IO FD-getFileFD (File fd closedRef) = do-    closed <- readIORef closedRef-    if closed then throwECLOSED else return fd---- | If fd is -1 (closed), throw 'ResourceVanished' ECLOSED.-checkFileClosed :: HasCallStack => File -> (FD -> IO a) -> IO a-checkFileClosed (File fd closedRef) f = do-    closed <- readIORef closedRef-    if closed then throwECLOSED else f fd---- | Set file's system offset.------ Equivalent to <https://linux.die.net/man/3/lseek64 lseek64(3)>.-seek :: HasCallStack => File -> Int64 -> Whence -> IO Int64-seek uvf off w = checkFileClosed uvf $ \ fd -> throwUVIfMinus $ hs_seek fd off w--instance Input File where-    -- readInput :: HasCallStack => File -> Ptr Word8 -> Int -> IO Int-    -- use -1 offset to use fd's default offset-    readInput f buf bufSiz = readFileP f buf bufSiz (-1)---- | Read file with given offset------ Read length may be smaller than buffer size.-readFileP :: HasCallStack-           => File-           -> Ptr Word8 -- ^ buffer-           -> Int       -- ^ buffer size-           -> Int64     -- ^ file offset, pass -1 to use default(system) offset-           -> IO Int    -- ^ read length-readFileP uvf buf bufSiz off =-    checkFileClosed uvf $ \ fd -> throwUVIfMinus $ hs_uv_fs_read fd buf bufSiz off--instance Output File where-    writeOutput f buf bufSiz = writeFileP f buf bufSiz (-1)---- | Write buffer to file------ This function will loop until all bytes are written.------ Note on linux files opened with 'O_APPEND' behave differently since this function use @pwrite@:------ @--- POSIX requires that opening a file with the O_APPEND flag should have no effect--- on the location at which pwrite() writes data. However, on Linux,--- if a file is opened with O_APPEND, pwrite() appends data to the end of the file,--- regardless of the value of offset.--- @-writeFileP :: HasCallStack-            => File-            -> Ptr Word8 -- ^ buffer-            -> Int       -- ^ buffer size-            -> Int64     -- ^ file offset, pass -1 to use default(system) offset-            -> IO ()-writeFileP uvf buf0 bufSiz0 off0 =-    checkFileClosed uvf $ \fd ->  if off0 == -1 then go fd buf0 bufSiz0-                                                else go' fd buf0 bufSiz0 off0-  where-    go fd !buf !bufSiz = do-        written <- throwUVIfMinus (hs_uv_fs_write fd buf bufSiz (-1))-        when (written < bufSiz)-            (go fd (buf `plusPtr` written) (bufSiz-written))--    go' fd !buf !bufSiz !off = do-        written <- throwUVIfMinus (hs_uv_fs_write fd buf bufSiz off)-        when (written < bufSiz) $-            go' fd (buf `plusPtr` written)-                   (bufSiz-written)-                   (off+fromIntegral written)---- | File bundled with offset.------ Reading or writing using 'Input' \/ 'Output' instance will automatically increase offset.--- 'FilePtr' and its operations are NOT thread safe, use 'MVar' 'FilePtr' in multiple threads.------ The notes on linux 'writeFileP' applied to 'FilePtr' too.-data FilePtr = FilePtr {-# UNPACK #-} !File-                       {-# UNPACK #-} !(PrimIORef Int64)---- |  Create a file offset bundle from an 'File'.----newFilePtr :: File       -- ^ the file we're reading-           -> Int64      -- ^ initial offset-           -> IO FilePtr-newFilePtr uvf off = FilePtr uvf <$> newPrimIORef off---- | Get current offset.-getFilePtrOffset :: FilePtr -> IO Int64-getFilePtrOffset (FilePtr _ offsetRef) = readPrimIORef offsetRef---- | Change current offset.-setFilePtrOffset :: FilePtr -> Int64 -> IO ()-setFilePtrOffset (FilePtr _ offsetRef) = writePrimIORef offsetRef--instance Input FilePtr where-    readInput (FilePtr file offsetRef) buf bufSiz =-        readPrimIORef offsetRef >>= \ off -> do-            l <- readFileP file buf bufSiz off-            writePrimIORef offsetRef (off + fromIntegral l)-            return l--instance Output FilePtr where-    writeOutput (FilePtr file offsetRef) buf bufSiz =-        readPrimIORef offsetRef >>= \ off -> do-            writeFileP file buf bufSiz off-            writePrimIORef offsetRef (off + fromIntegral bufSiz)-------------------------------------------------------------------------------------- | init a file 'Resource', which open a file when used.------ Resource closing is thread safe, on some versions of OSX, repeatly open and close same file 'Resource' may--- result in shared memory object error, use 'O_CREAT' to avoid that.-initFile :: HasCallStack-         => CBytes-         -> FileFlag        -- ^ Opening flags, e.g. 'O_CREAT' @.|.@ 'O_RDWR'-         -> FileMode      -- ^ Sets the file mode (permission and sticky bits),-                            -- but only if the file was created, see 'DEFAULT_MODE'.-         -> Resource File-initFile path flags mode =-    initResource-        (do !fd <- withCBytesUnsafe path $ \ p ->-                throwUVIfMinus $ hs_uv_fs_open p flags mode-            File fd <$> newIORef False)-        (\ (File fd closedRef) -> do-            closed <- readIORef closedRef-            unless closed $ do-                throwUVIfMinus_ (hs_uv_fs_close fd)-                writeIORef closedRef True)---- | Quickly open a file and read its content.-readFile :: HasCallStack => CBytes -> IO V.Bytes-readFile filename = do-    withResource (initFile filename O_RDONLY DEFAULT_MODE) $ \ file -> do-        readAll' =<< newBufferedInput file---- | Quickly open a file and read its content as UTF8 text.-readTextFile :: HasCallStack => CBytes -> IO T.Text-readTextFile filename = T.validate <$> readFile filename---- | Quickly open a file and write some content.-writeFile :: HasCallStack => CBytes -> V.Bytes -> IO ()-writeFile filename content = do-    withResource (initFile filename (O_WRONLY .|. O_CREAT) DEFAULT_MODE) $ \ file -> do-        withPrimVectorSafe content (writeOutput file)---- | Quickly open a file and write some content as UTF8 text.-writeTextFile :: HasCallStack => CBytes -> T.Text -> IO ()-writeTextFile filename content = writeFile filename (T.getUTF8Bytes content)---- | Quickly open a file and read its content as a JSON value.--- Throw 'OtherError' with name @EPARSE@ if JSON value is not parsed.-readJSONFile :: (HasCallStack, JSON.JSON a) => CBytes -> IO a-readJSONFile filename = unwrap "EPARSE" . JSON.decode' =<< readFile filename---- | Quickly open a file and write a JSON Value.-writeJSONFile :: (HasCallStack, JSON.JSON a) => CBytes -> a -> IO ()-writeJSONFile filename x = writeFile filename (JSON.encode x)-------------------------------------------------------------------------------------- | Equivalent to <http://linux.die.net/man/2/mkdir mkdir(2)>.------ Note mode is currently not implemented on Windows. On unix you should set execute bit--- if you want the directory is accessable, e.g. 0o777.-mkdir :: HasCallStack => CBytes -> FileMode -> IO ()-mkdir path mode = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->-     hs_uv_fs_mkdir p mode---- | Equivalent to @mkdir -p@------ Note mode is currently not implemented on Windows. On unix you should set execute bit--- if you want the directory is accessable(so that child folder can be created), e.g. 0o777.-mkdirp :: HasCallStack => CBytes -> FileMode -> IO ()-mkdirp path mode = do-    r <- withCBytesUnsafe path $ \ p -> hs_uv_fs_mkdir p mode-    if fromIntegral r == UV_ENOENT-    then do-        (root, segs) <- P.splitSegments path-        case segs of-            seg:segs' -> loop segs' =<< P.join root seg-            _ -> throwUVIfMinus_ (return r)-    else throwUVIfMinus_ (return r)-  where-    loop segs p = do-        a <- access p F_OK-        case a of-            AccessOK     -> return ()-            NoExistence  -> mkdir p mode-            NoPermission -> throwUVIfMinus_ (return UV_EACCES)-        case segs of-            (nextp:ps) -> P.join p nextp >>= loop ps-            _  -> return ()---- | Equivalent to <http://linux.die.net/man/2/unlink unlink(2)>.-unlink :: HasCallStack => CBytes -> IO ()-unlink path = throwUVIfMinus_ (withCBytesUnsafe path hs_uv_fs_unlink)---- | Equivalent to <mkdtemp http://linux.die.net/man/3/mkdtemp>------ Creates a temporary directory in the most secure manner possible.--- There are no race conditions in the directory’s creation.--- The directory is readable, writable, and searchable only by the creating user ID.--- The user of mkdtemp() is responsible for deleting the temporary directory and--- its contents when done with it.------ Note: the argument is the prefix of the temporary directory,--- so no need to add XXXXXX ending.----mkdtemp :: HasCallStack => CBytes -> IO CBytes-mkdtemp path = do-    let size = CBytes.length path-    withCBytesUnsafe path $ \ p -> do-        (p',_) <- CBytes.allocCBytesUnsafe (size+7) $ \ p' -> do  -- we append "XXXXXX\NUL" in C-            throwUVIfMinus_ (hs_uv_fs_mkdtemp p size p')-        return p'---- | Equivalent to <http://linux.die.net/man/2/rmdir rmdir(2)>.------ Note this function may inherent OS limitations such as argument must be an empty folder.-rmdir :: HasCallStack => CBytes -> IO ()-rmdir path = throwUVIfMinus_ (withCBytesUnsafe path hs_uv_fs_rmdir)---- | Equivalent to @rmdir -rf@------ This function will try to remove folder and files contained by it.-rmdirrf :: HasCallStack => CBytes -> IO ()-rmdirrf path = do-    ds <- scandir path-    forM_ ds $ \ (d, t) -> do-        if t /= DirEntDir-        then unlink d-        else rmdirrf =<< path `P.join` d-    rmdir path---- | Equivalent to <http://linux.die.net/man/3/scandir scandir(3)>.------ Note Unlike scandir(3), this function does not return the “.” and “..” entries.------ Note On Linux, getting the type of an entry is only supported by some file systems (btrfs, ext2, ext3 and ext4 at the time of this writing), check the <http://linux.die.net/man/2/getdents getdents(2)> man page.-scandir :: HasCallStack => CBytes -> IO [(CBytes, DirEntType)]-scandir path = do-    bracket-        (withCBytesUnsafe path $ \ p ->-            allocPrimUnsafe $ \ dents ->-                throwUVIfMinus (hs_uv_fs_scandir p dents))-        (\ (dents, n) -> hs_uv_fs_scandir_cleanup dents n)-        (\ (dents, n) -> forM [0..n-1] $ \ i -> do-            dent <- peekElemOff dents i-            (p, typ) <- peekUVDirEnt dent-            let !typ' = fromUVDirEntType typ-            !p' <- fromCString p-            return (p', typ'))---- | Find all files and directories within a given directory with a predicator.------ @---  import Z.IO.FileSystem.FilePath (splitExtension)---  -- find all haskell source file within current dir---  scandirRecursively "."  (\\ p _ -> (== ".hs") . snd \<$\> splitExtension p)--- @-scandirRecursively :: HasCallStack => CBytes -> (CBytes -> DirEntType -> IO Bool) -> IO [CBytes]-scandirRecursively dir p = loop [] =<< P.normalize dir-  where-    loop acc0 pdir =-        foldM (\ acc (d,t) -> do-            d' <- pdir `P.join` d-            r <- p d' t-            let acc' = if r then (d':acc) else acc-            if (t == DirEntDir)-            then loop acc' d'-            else return acc'-        ) acc0 =<< scandir pdir-------------------------------------------------------------------------------------- | Equivalent to <http://linux.die.net/man/2/stat stat(2)>-stat :: HasCallStack => CBytes -> IO FStat-stat path = withCBytesUnsafe path $ \ p ->-     allocaBytes uvStatSize $ \ s -> do-        throwUVIfMinus_ (hs_uv_fs_stat p s)-        peekUVStat s---- | Equivalent to <http://linux.die.net/man/2/lstat lstat(2)>-lstat :: HasCallStack => CBytes -> IO FStat-lstat path = withCBytesUnsafe path $ \ p ->-     allocaBytes uvStatSize $ \ s -> do-        throwUVIfMinus_ (hs_uv_fs_lstat p s)-        peekUVStat s---- | Equivalent to <http://linux.die.net/man/2/fstat fstat(2)>-fstat :: HasCallStack => File -> IO FStat-fstat uvf = checkFileClosed uvf $ \ fd ->-    allocaBytes uvStatSize $ \ s -> do-        throwUVIfMinus_ (hs_uv_fs_fstat fd s)-        peekUVStat s---- | If given path is a symbolic link?-isLink :: HasCallStack => CBytes -> IO Bool-isLink p = lstat p >>= \ st -> return (stMode st .&. S_IFMT == S_IFLNK)---- | If given path is a directory or a symbolic link to a directory?-isDir :: HasCallStack => CBytes -> IO Bool-isDir p = stat p >>= \ st -> return (stMode st .&. S_IFMT == S_IFDIR)---- | If given path is a file or a symbolic link to a file?-isFile :: HasCallStack => CBytes -> IO Bool-isFile p = stat p >>= \ st -> return (stMode st .&. S_IFMT == S_IFREG)-------------------------------------------------------------------------------------- | Equivalent to <http://linux.die.net/man/2/rename rename(2)>.------ Note On Windows if this function fails with UV_EBUSY, UV_EPERM or UV_EACCES, it will retry to rename the file up to four times with 250ms wait between attempts before giving up. If both path and new_path are existing directories this function will work only if target directory is empty.-rename :: HasCallStack => CBytes -> CBytes -> IO ()-rename path path' = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->-    withCBytesUnsafe path' (hs_uv_fs_rename p)---- | Equivalent to <http://linux.die.net/man/2/fsync fsync(2)>.-fsync :: HasCallStack => File -> IO ()-fsync uvf = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_fsync fd---- | Equivalent to <http://linux.die.net/man/2/fdatasync fdatasync(2)>.-fdatasync :: HasCallStack => File -> IO ()-fdatasync uvf = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_fdatasync fd---- | Equivalent to <http://linux.die.net/man/2/ftruncate ftruncate(2)>.-ftruncate :: HasCallStack => File -> Int64 -> IO ()-ftruncate uvf off = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_ftruncate fd off---- | Copies a file from path to new_path.------ Warning: If the destination path is created, but an error occurs while copying the data, then the destination path is removed. There is a brief window of time between closing and removing the file where another process could access the file.-copyfile :: HasCallStack => CBytes -> CBytes -> CopyFileFlag -> IO ()-copyfile path path' flag = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->-    withCBytesUnsafe path' $ \ p' -> hs_uv_fs_copyfile p p' flag---- | Equivalent to <http://linux.die.net/man/2/access access(2)> on Unix.------ Windows uses GetFileAttributesW().-access :: HasCallStack => CBytes -> AccessMode -> IO AccessResult-access path mode = do-     r <- withCBytesUnsafe path $ \ p -> fromIntegral <$> hs_uv_fs_access p mode-     if | r == 0           -> return AccessOK-        | r == UV_ENOENT   -> return NoExistence-        | r == UV_EACCES   -> return NoPermission-        | otherwise        -> do-            name <- uvErrName r-            desc <- uvStdError r-            throwUVError r (IOEInfo name desc callStack)---- | Equivalent to <http://linux.die.net/man/2/chmod chmod(2)>.-chmod :: HasCallStack => CBytes -> FileMode -> IO ()-chmod path mode = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_chmod p mode---- | Equivalent to <http://linux.die.net/man/2/fchmod fchmod(2)>.-fchmod :: HasCallStack => File -> FileMode -> IO ()-fchmod uvf mode = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_fchmod fd mode---- | Equivalent to <http://linux.die.net/man/2/utime utime(2)>.------ libuv choose 'Double' type due to cross platform concerns, we only provide micro-second precision.-utime :: HasCallStack-      => CBytes-      -> Double     -- ^ atime, i.e. access time-      -> Double     -- ^ mtime, i.e. modify time-      -> IO ()-utime path atime mtime = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_utime p atime mtime---- | Equivalent to <https://man7.org/linux/man-pages/man3/futimes.3.html futime(3)>.------ Same precision notes with 'utime'.-futime :: HasCallStack => File -> Double -> Double -> IO ()-futime uvf atime mtime = checkFileClosed uvf $ \ fd ->-    throwUVIfMinus_ (hs_uv_fs_futime fd atime mtime)---- | Equivalent to <https://man7.org/linux/man-pages/man3/lutimes.3.html lutime(3)>.------ Same precision notes with 'utime'.-lutime :: HasCallStack-       => CBytes-       -> Double     -- ^ atime, i.e. access time-       -> Double     -- ^ mtime, i.e. modify time-       -> IO ()-lutime path atime mtime = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_lutime p atime mtime---- | Equivalent to <http://linux.die.net/man/2/link link(2)>.-link :: HasCallStack => CBytes -> CBytes -> IO ()-link path path' = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->-    withCBytesUnsafe path' $ hs_uv_fs_link p---- | Equivalent to <http://linux.die.net/man/2/symlink symlink(2)>.------ | Note On Windows the flags parameter can be specified to control how the symlink will be created.------   * 'SYMLINK_DIR': indicates that path points to a directory.---   * 'SYMLINK_JUNCTION': request that the symlink is created using junction points.------ On other platforms these flags are ignored.-symlink :: HasCallStack => CBytes -> CBytes -> SymlinkFlag -> IO ()-symlink path path' flag = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->-    withCBytesUnsafe path' $ \ p' -> hs_uv_fs_symlink p p' flag---- | Equivalent to <http://linux.die.net/man/2/readlink readlink(2)>.-readlink :: HasCallStack => CBytes -> IO CBytes-readlink path = do-    bracket-        (withCBytesUnsafe path $ \ p ->-            allocPrimUnsafe $ \ p' ->-                throwUVIfMinus (hs_uv_fs_readlink p p'))-        (hs_uv_fs_readlink_cleanup . fst)-        (fromCString . fst)----- | Equivalent to <http://linux.die.net/man/3/realpath realpath(3)> on Unix. Windows uses <https://msdn.microsoft.com/en-us/library/windows/desktop/aa364962(v=vs.85).aspx GetFinalPathNameByHandle>.------ Warning This function has certain platform-specific caveats that were discovered when used in Node.------  * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are found while---    resolving the given path. This limit is hardcoded and cannot be sidestepped.------  * Windows: while this function works in the common case, there are a number of corner cases where it doesn’t:------      * Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk) cannot be resolved.---      * Inconsistent casing when using drive letters.---      * Resolved path bypasses subst’d drives.------ While this function can still be used, it’s not recommended if scenarios such as the above need to be supported.--- The background story and some more details on these issues can be checked <https://github.com/nodejs/node/issues/7726 here>.------ Note This function is not implemented on Windows XP and Windows Server 2003. On these systems, UV_ENOSYS is returned.-realpath :: HasCallStack => CBytes -> IO CBytes-realpath path = do-    bracket-        (withCBytesUnsafe path $ \ p ->-            allocPrimUnsafe $ \ p' ->-                throwUVIfMinus (hs_uv_fs_realpath p p'))-        (hs_uv_fs_readlink_cleanup . fst)-        (fromCString . fst)---- | Equivalent to <http://linux.die.net/man/2/chown chown(2)>.-chown :: HasCallStack => CBytes -> UID -> GID -> IO ()-chown path uid gid = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_chown p uid gid---- | Equivalent to <http://linux.die.net/man/2/fchown fchown(2)>.-fchown :: HasCallStack => File -> UID -> GID -> IO ()-fchown uvf uid gid = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_fchown fd uid gid+  ( -- * Basic Operations+    module Z.IO.FileSystem.Base --- | Equivalent to <http://linux.die.net/man/2/lchown lchown(2)>.-lchown :: HasCallStack => CBytes -> UID -> GID -> IO ()-lchown path uid gid = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_lchown p uid gid+    -- * FilePath+  , module Z.IO.FileSystem.FilePath ------------------------------------------------------------------------------------ high level utilities+    -- * FileWatch+  , module Z.IO.FileSystem.Watch+  ) where +import           Z.IO.FileSystem.Base+import           Z.IO.FileSystem.FilePath+import           Z.IO.FileSystem.Watch
+ Z/IO/FileSystem/Base.hs view
@@ -0,0 +1,570 @@+{-|+Module      : Z.IO.FileSystem.Base+Description : Filesystem IO+Copyright   : (c) Dong Han, 2017-2020+License     : BSD+Maintainer  : winterland1989@gmail.com+Stability   : experimental+Portability : non-portable++This module provide IO operations related to filesystem, operations are+implemented using unsafe FFIs, which should be prefered when the operations'+estimated time is short(<1ms), which is much common on modern SSDs.+-}+module Z.IO.FileSystem.Base+  ( -- * Regular file devices+    File, initFile, readFileP, writeFileP, getFileFD, seek+  , readFile, readTextFile, writeFile, writeTextFile+  , readJSONFile, writeJSONFile+    -- * file offset bundle+  , FilePtr, newFilePtr, getFilePtrOffset, setFilePtrOffset+  -- * Filesystem operations+  , mkdir, mkdirp+  , unlink+  , mkdtemp, mkstemp , initTempFile, initTempDir+  , rmdir, rmrf+  , DirEntType(..)+  , scandir+  , scandirRecursively+    -- ** File stats+  , FStat(..), UVTimeSpec(..)+  , doesPathExist, doesFileExist, doesDirExist+  , isLink, isDir, isFile+  , isLinkSt, isDirSt, isFileSt+  , stat, lstat, fstat+  , stat', lstat'+  , rename+  , fsync, fdatasync+  , ftruncate+  , copyfile+  , AccessResult(..)+  , access+  , chmod, fchmod+  , utime, futime, lutime+  , link, symlink+  , readlink, realpath+  , chown, fchown, lchown+  -- * opening constant+  -- ** AccessMode+  , AccessMode+  , pattern F_OK+  , pattern R_OK+  , pattern W_OK+  , pattern X_OK+  -- ** FileMode+  , FileMode+  , pattern DEFAULT_FILE_MODE+  , pattern DEFAULT_DIR_MODE+  , pattern S_IRWXU+  , pattern S_IRUSR+  , pattern S_IWUSR+  , pattern S_IXUSR+  , pattern S_IRWXG+  , pattern S_IRGRP+  , pattern S_IWGRP+  , pattern S_IXGRP+  , pattern S_IRWXO+  , pattern S_IROTH+  -- ** file type constant+  , pattern S_IFMT+  , pattern S_IFLNK+  , pattern S_IFDIR+  , pattern S_IFREG+  -- ** FileFlag+  , FileFlag+  , pattern O_APPEND+  , pattern O_CREAT+  , pattern O_DIRECT+  , pattern O_DSYNC+  , pattern O_EXCL+  , pattern O_EXLOCK+  , pattern O_NOATIME+  , pattern O_NOFOLLOW+  , pattern O_RDONLY+  , pattern O_RDWR+  , pattern O_SYMLINK+  , pattern O_SYNC+  , pattern O_TRUNC+  , pattern O_WRONLY+  , pattern O_RANDOM+  , pattern O_SHORT_LIVED+  , pattern O_SEQUENTIAL+  , pattern O_TEMPORARY+  -- ** CopyFileFlag+  , CopyFileFlag+  , pattern COPYFILE_DEFAULT+  , pattern COPYFILE_EXCL+  , pattern COPYFILE_FICLONE+  , pattern COPYFILE_FICLONE_FORCE+  -- ** SymlinkFlag+  , SymlinkFlag+  , pattern SYMLINK_DEFAULT+  , pattern SYMLINK_DIR+  , pattern SYMLINK_JUNCTION+  -- ** Whence+  , Whence+  , pattern SEEK_SET+  , pattern SEEK_CUR+  , pattern SEEK_END+  ) where++import           Control.Monad+import           Data.Bits+import           Data.IORef+import           Data.Int+import           Data.Word+import           Foreign.Marshal.Alloc    (allocaBytes)+import           Foreign.Ptr+import           Foreign.Storable         (peekElemOff)+import           Prelude                  hiding (readFile, writeFile)+import qualified Z.Data.Builder           as B+import           Z.Data.CBytes            as CBytes+import qualified Z.Data.JSON              as JSON+import           Z.Data.PrimRef.PrimIORef+import qualified Z.Data.Text              as T+import qualified Z.Data.Text.Print        as T+import qualified Z.Data.Vector            as V+import           Z.Foreign+import           Z.IO.Buffered+import qualified Z.IO.Environment         as Env+import           Z.IO.Exception+import qualified Z.IO.FileSystem.FilePath as P+import           Z.IO.Resource+import           Z.IO.UV.FFI++#include "_Shared.hs"++--------------------------------------------------------------------------------+-- File++-- | 'File' and its operations are NOT thread safe, use 'MVar' 'File' in multiple threads+--+-- libuv implements read and write method with both implict and explict offset capable.+-- Implict offset interface is provided by 'Input' \/ 'Output' instances.+-- Explict offset interface is provided by 'readFileP' \/ 'writeFileP'.+--+data File =  File  {-# UNPACK #-} !FD      -- ^ the file+                   {-# UNPACK #-} !(IORef Bool)  -- ^ closed flag++instance Show File where show = T.toString++instance T.Print File where+    toUTF8BuilderP _ (File fd _) = "File " >> T.int fd++-- | Return File fd.+getFileFD :: File -> IO FD+getFileFD (File fd closedRef) = do+    closed <- readIORef closedRef+    if closed then throwECLOSED else return fd++-- | If fd is -1 (closed), throw 'ResourceVanished' ECLOSED.+checkFileClosed :: HasCallStack => File -> (FD -> IO a) -> IO a+checkFileClosed (File fd closedRef) f = do+    closed <- readIORef closedRef+    if closed then throwECLOSED else f fd++-- | Set file's system offset.+--+-- Equivalent to <https://linux.die.net/man/3/lseek64 lseek64(3)>.+seek :: HasCallStack => File -> Int64 -> Whence -> IO Int64+seek uvf off w = checkFileClosed uvf $ \ fd -> throwUVIfMinus $ hs_seek fd off w++instance Input File where+    -- readInput :: HasCallStack => File -> Ptr Word8 -> Int -> IO Int+    -- use -1 offset to use fd's default offset+    readInput f buf bufSiz = readFileP f buf bufSiz (-1)++-- | Read file with given offset+--+-- Read length may be smaller than buffer size.+readFileP :: HasCallStack+           => File+           -> Ptr Word8 -- ^ buffer+           -> Int       -- ^ buffer size+           -> Int64     -- ^ file offset, pass -1 to use default(system) offset+           -> IO Int    -- ^ read length+readFileP uvf buf bufSiz off =+    checkFileClosed uvf $ \ fd -> throwUVIfMinus $ hs_uv_fs_read fd buf bufSiz off++instance Output File where+    writeOutput f buf bufSiz = writeFileP f buf bufSiz (-1)++-- | Write buffer to file+--+-- This function will loop until all bytes are written.+--+-- Note on linux files opened with 'O_APPEND' behave differently since this function use @pwrite@:+--+-- @+-- POSIX requires that opening a file with the O_APPEND flag should have no effect+-- on the location at which pwrite() writes data. However, on Linux,+-- if a file is opened with O_APPEND, pwrite() appends data to the end of the file,+-- regardless of the value of offset.+-- @+writeFileP :: HasCallStack+            => File+            -> Ptr Word8 -- ^ buffer+            -> Int       -- ^ buffer size+            -> Int64     -- ^ file offset, pass -1 to use default(system) offset+            -> IO ()+writeFileP uvf buf0 bufSiz0 off0 =+    checkFileClosed uvf $ \fd ->  if off0 == -1 then go fd buf0 bufSiz0+                                                else go' fd buf0 bufSiz0 off0+  where+    go fd !buf !bufSiz = do+        written <- throwUVIfMinus (hs_uv_fs_write fd buf bufSiz (-1))+        when (written < bufSiz)+            (go fd (buf `plusPtr` written) (bufSiz-written))++    go' fd !buf !bufSiz !off = do+        written <- throwUVIfMinus (hs_uv_fs_write fd buf bufSiz off)+        when (written < bufSiz) $+            go' fd (buf `plusPtr` written)+                   (bufSiz-written)+                   (off+fromIntegral written)+++--------------------------------------------------------------------------------++-- | init a file 'Resource', which open a file when used.+--+-- Resource closing is thread safe, on some versions of OSX, repeatly open and close same file 'Resource' may+-- result in shared memory object error, use 'O_CREAT' to avoid that.+initFile :: HasCallStack+         => CBytes+         -> FileFlag        -- ^ Opening flags, e.g. 'O_CREAT' @.|.@ 'O_RDWR'+         -> FileMode      -- ^ Sets the file mode (permission and sticky bits),+                            -- but only if the file was created, see 'DEFAULT_FILE_MODE'.+         -> Resource File+initFile path flags mode =+    initResource+        (do !fd <- withCBytesUnsafe path $ \ p ->+                throwUVIfMinus $ hs_uv_fs_open p flags mode+            File fd <$> newIORef False)+        (\ (File fd closedRef) -> do+            closed <- readIORef closedRef+            unless closed $ do+                throwUVIfMinus_ (hs_uv_fs_close fd)+                writeIORef closedRef True)++--------------------------------------------------------------------------------++-- | Create a directory named path with numeric mode 'FileMode'.+--+-- Equivalent to <http://linux.die.net/man/2/mkdir mkdir(2)>.+--+-- Note mode is currently not implemented on Windows. On unix you should set execute bit+-- if you want the directory is accessable, e.g. 0o777.+mkdir :: HasCallStack => CBytes -> FileMode -> IO ()+mkdir path mode = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->+     hs_uv_fs_mkdir p mode++-- | Recursive directory creation function. Like 'mkdir', but makes all+-- intermediate-level directories needed to contain the leaf directory.+--+-- Equivalent to @mkdir -p@,+--+-- Note mode is currently not implemented on Windows. On unix you should set+-- execute bit if you want the directory is accessable(so that child folder+-- can be created), e.g. 'DEFAULT_DIR_MODE'.+--+mkdirp :: HasCallStack => CBytes -> FileMode -> IO ()+mkdirp path mode = do+    r <- withCBytesUnsafe path $ \ p -> hs_uv_fs_mkdir p mode+    case fromIntegral r of+        UV_ENOENT -> do+            (root, segs) <- P.splitSegments path+            case segs of+                seg:segs' -> loop segs' =<< P.join root seg+                _         -> throwUV r+        UV_EEXIST -> do+            canIgnore <- isDir path+            unless canIgnore $ throwUV r+        _ -> throwUV r+  where+    loop segs p = do+        a <- access p F_OK+        case a of+            AccessOK     -> return ()+            NoExistence  -> mkdir p mode+            NoPermission -> throwUV UV_EACCES+        case segs of+            (nextp:ps) -> P.join p nextp >>= loop ps+            _          -> return ()++-- | Equivalent to <http://linux.die.net/man/2/unlink unlink(2)>.+unlink :: HasCallStack => CBytes -> IO ()+unlink path = throwUVIfMinus_ (withCBytesUnsafe path hs_uv_fs_unlink)+++-- | Equivalent to <mkdtemp http://linux.die.net/man/3/mkdtemp>+--+-- Creates a temporary directory in the most secure manner possible.+-- There are no race conditions in the directory’s creation.+-- The directory is readable, writable, and searchable only by the creating user ID.+-- The user of mkdtemp() is responsible for deleting the temporary directory and+-- its contents when done with it.+--+-- Note: the argument is the prefix of the temporary directory,+-- so no need to add XXXXXX ending.+--+mkdtemp :: HasCallStack => CBytes -> IO CBytes+mkdtemp path = do+    let size = CBytes.length path+    withCBytesUnsafe path $ \ p -> do+        (p',_) <- CBytes.allocCBytesUnsafe (size+7) $ \ p' -> do  -- we append "XXXXXX\NUL" in C+            throwUVIfMinus_ (hs_uv_fs_mkdtemp p size p')+        return p'++-- | Equivalent to <mkstemp https://man7.org/linux/man-pages/man3/mkstemp.3.html>+mkstemp :: HasCallStack => CBytes -> IO CBytes+mkstemp template = do+    let size = CBytes.length template+    CBytes.withCBytesUnsafe template $ \p -> do+        (p', _) <- CBytes.allocCBytesUnsafe (size + 7) $ \ p' -> do  -- we append "XXXXXX\NUL" in C+            throwUVIfMinus_ (hs_uv_fs_mkstemp p size p')+        return p'++-------------------------------------------------------------------------------++-- | Equivalent to <http://linux.die.net/man/2/rmdir rmdir(2)>.+--+-- Note this function may inherent OS limitations such as argument must be an empty folder.+rmdir :: HasCallStack => CBytes -> IO ()+rmdir path = throwUVIfMinus_ (withCBytesUnsafe path hs_uv_fs_rmdir)++-- | Removes a file or directory at path together with its contents and+-- subdirectories. Symbolic links are removed without affecting their targets.+-- If the path does not exist, nothing happens.+rmrf :: HasCallStack => CBytes -> IO ()+rmrf path =+    withCBytesUnsafe path $ \path' ->+    allocaBytes uvStatSize $ \s -> do+        r <- fromIntegral <$> hs_uv_fs_stat path' s+        if  | r == UV_ENOENT -> pure ()   -- nothing if path does not exist.+            | r < 0     -> throwUV r+            | otherwise -> do+                st <- peekUVStat s+                case stMode st .&. S_IFMT of+                    S_IFREG -> unlink path+                    S_IFLNK -> unlink path+                    S_IFDIR -> do+                        ds <- scandir path+                        forM_ ds $ \ (d, t) ->+                            if t /= DirEntDir+                            then unlink d+                            else rmrf =<< path `P.join` d+                        rmdir path+                    mode    -> do+                        let desc = B.buildText $ "Unsupported file mode: " >> B.hex mode+                        throwIO $ UnsupportedOperation (IOEInfo "" desc callStack)++-- | Equivalent to <http://linux.die.net/man/3/scandir scandir(3)>.+--+-- Note Unlike scandir(3), this function does not return the “.” and “..” entries.+--+-- Note On Linux, getting the type of an entry is only supported by some file+-- systems (btrfs, ext2, ext3 and ext4 at the time of this writing), check the+-- <http://linux.die.net/man/2/getdents getdents(2)> man page.+scandir :: HasCallStack => CBytes -> IO [(CBytes, DirEntType)]+scandir path = do+    bracket+        (withCBytesUnsafe path $ \ p ->+            allocPrimUnsafe $ \ dents ->+                throwUVIfMinus (hs_uv_fs_scandir p dents))+        (\ (dents, n) -> hs_uv_fs_scandir_cleanup dents n)+        (\ (dents, n) -> forM [0..n-1] $ \ i -> do+            dent <- peekElemOff dents i+            (p, typ) <- peekUVDirEnt dent+            let !typ' = fromUVDirEntType typ+            !p' <- fromCString p+            return (p', typ'))++--------------------------------------------------------------------------------+-- File Status++-- | Equivalent to <http://linux.die.net/man/2/stat stat(2)>+stat :: HasCallStack => CBytes -> IO FStat+stat path = withCBytesUnsafe path $ \ p ->+     allocaBytes uvStatSize $ \ s -> do+        throwUVIfMinus_ (hs_uv_fs_stat p s)+        peekUVStat s++-- | Equivalent to <http://linux.die.net/man/2/lstat lstat(2)>+lstat :: HasCallStack => CBytes -> IO FStat+lstat path = withCBytesUnsafe path $ \ p ->+     allocaBytes uvStatSize $ \ s -> do+        throwUVIfMinus_ (hs_uv_fs_lstat p s)+        peekUVStat s++-- | Equivalent to <http://linux.die.net/man/2/stat stat(2)>+--+-- Return 'Nothing' instead of throwing 'NoSuchThing' if the file doesn't exist.+stat' :: HasCallStack => CBytes -> IO (Maybe FStat)+stat' path = withCBytesUnsafe path $ \ p ->+     allocaBytes uvStatSize $ \ s -> do+        r <- fromIntegral <$> hs_uv_fs_stat p s+        if  | r == UV_ENOENT -> return Nothing+            | r < 0 -> throwUV r+            | otherwise -> Just <$> peekUVStat s++-- | Equivalent to <http://linux.die.net/man/2/lstat lstat(2)>+--+-- Return 'Nothing' instead of throwing 'NoSuchThing' if the link doesn't exist.+lstat' :: HasCallStack => CBytes -> IO (Maybe FStat)+lstat' path = withCBytesUnsafe path $ \ p ->+     allocaBytes uvStatSize $ \ s -> do+        r <- fromIntegral <$> hs_uv_fs_lstat p s+        if  | r == UV_ENOENT -> return Nothing+            | r < 0 -> throwUV r+            | otherwise -> Just <$> peekUVStat s++-- | Equivalent to <http://linux.die.net/man/2/fstat fstat(2)>+fstat :: HasCallStack => File -> IO FStat+fstat uvf = checkFileClosed uvf $ \ fd ->+    allocaBytes uvStatSize $ \ s -> do+        throwUVIfMinus_ (hs_uv_fs_fstat fd s)+        peekUVStat s++--------------------------------------------------------------------------------++-- | Equivalent to <http://linux.die.net/man/2/rename rename(2)>.+--+-- Note On Windows if this function fails with UV_EBUSY, UV_EPERM or UV_EACCES, it will retry to rename the file up to four times with 250ms wait between attempts before giving up. If both path and new_path are existing directories this function will work only if target directory is empty.+rename :: HasCallStack => CBytes -> CBytes -> IO ()+rename path path' = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->+    withCBytesUnsafe path' (hs_uv_fs_rename p)++-- | Equivalent to <http://linux.die.net/man/2/fsync fsync(2)>.+fsync :: HasCallStack => File -> IO ()+fsync uvf = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_fsync fd++-- | Equivalent to <http://linux.die.net/man/2/fdatasync fdatasync(2)>.+fdatasync :: HasCallStack => File -> IO ()+fdatasync uvf = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_fdatasync fd++-- | Equivalent to <http://linux.die.net/man/2/ftruncate ftruncate(2)>.+ftruncate :: HasCallStack => File -> Int64 -> IO ()+ftruncate uvf off = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_ftruncate fd off++-- | Copies a file from path to new_path.+--+-- Warning: If the destination path is created, but an error occurs while copying the data, then the destination path is removed. There is a brief window of time between closing and removing the file where another process could access the file.+copyfile :: HasCallStack => CBytes -> CBytes -> CopyFileFlag -> IO ()+copyfile path path' flag = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->+    withCBytesUnsafe path' $ \ p' -> hs_uv_fs_copyfile p p' flag++-- | Equivalent to <http://linux.die.net/man/2/access access(2)> on Unix.+--+-- Windows uses GetFileAttributesW().+access :: HasCallStack => CBytes -> AccessMode -> IO AccessResult+access path mode = do+     r <- withCBytesUnsafe path $ \ p -> fromIntegral <$> hs_uv_fs_access p mode+     if | r == 0           -> return AccessOK+        | r == UV_ENOENT   -> return NoExistence+        | r == UV_EACCES   -> return NoPermission+        | otherwise        -> do+            name <- uvErrName r+            desc <- uvStdError r+            throwUVError r (IOEInfo name desc callStack)++-- | Equivalent to <http://linux.die.net/man/2/chmod chmod(2)>.+chmod :: HasCallStack => CBytes -> FileMode -> IO ()+chmod path mode = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_chmod p mode++-- | Equivalent to <http://linux.die.net/man/2/fchmod fchmod(2)>.+fchmod :: HasCallStack => File -> FileMode -> IO ()+fchmod uvf mode = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_fchmod fd mode++-- | Equivalent to <http://linux.die.net/man/2/utime utime(2)>.+--+-- libuv choose 'Double' type due to cross platform concerns, we only provide micro-second precision.+utime :: HasCallStack+      => CBytes+      -> Double     -- ^ atime, i.e. access time+      -> Double     -- ^ mtime, i.e. modify time+      -> IO ()+utime path atime mtime = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_utime p atime mtime++-- | Equivalent to <https://man7.org/linux/man-pages/man3/futimes.3.html futime(3)>.+--+-- Same precision notes with 'utime'.+futime :: HasCallStack => File -> Double -> Double -> IO ()+futime uvf atime mtime = checkFileClosed uvf $ \ fd ->+    throwUVIfMinus_ (hs_uv_fs_futime fd atime mtime)++-- | Equivalent to <https://man7.org/linux/man-pages/man3/lutimes.3.html lutime(3)>.+--+-- Same precision notes with 'utime'.+lutime :: HasCallStack+       => CBytes+       -> Double     -- ^ atime, i.e. access time+       -> Double     -- ^ mtime, i.e. modify time+       -> IO ()+lutime path atime mtime = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_lutime p atime mtime++-- | Equivalent to <http://linux.die.net/man/2/link link(2)>.+link :: HasCallStack => CBytes -> CBytes -> IO ()+link path path' = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->+    withCBytesUnsafe path' $ hs_uv_fs_link p++-- | Equivalent to <http://linux.die.net/man/2/symlink symlink(2)>.+--+-- | Note On Windows the flags parameter can be specified to control how the symlink will be created.+--+--   * 'SYMLINK_DIR': indicates that path points to a directory.+--   * 'SYMLINK_JUNCTION': request that the symlink is created using junction points.+--+-- On other platforms these flags are ignored.+symlink :: HasCallStack => CBytes -> CBytes -> SymlinkFlag -> IO ()+symlink path path' flag = throwUVIfMinus_ . withCBytesUnsafe path $ \ p ->+    withCBytesUnsafe path' $ \ p' -> hs_uv_fs_symlink p p' flag++-- | Equivalent to <http://linux.die.net/man/2/readlink readlink(2)>.+readlink :: HasCallStack => CBytes -> IO CBytes+readlink path = do+    bracket+        (withCBytesUnsafe path $ \ p ->+            allocPrimUnsafe $ \ p' ->+                throwUVIfMinus (hs_uv_fs_readlink p p'))+        (hs_uv_fs_readlink_cleanup . fst)+        (fromCString . fst)+++-- | Equivalent to <http://linux.die.net/man/3/realpath realpath(3)> on Unix. Windows uses <https://msdn.microsoft.com/en-us/library/windows/desktop/aa364962(v=vs.85).aspx GetFinalPathNameByHandle>.+--+-- Warning This function has certain platform-specific caveats that were discovered when used in Node.+--+--  * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are found while+--    resolving the given path. This limit is hardcoded and cannot be sidestepped.+--+--  * Windows: while this function works in the common case, there are a number of corner cases where it doesn’t:+--+--      * Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk) cannot be resolved.+--      * Inconsistent casing when using drive letters.+--      * Resolved path bypasses subst’d drives.+--+-- While this function can still be used, it’s not recommended if scenarios such as the above need to be supported.+-- The background story and some more details on these issues can be checked <https://github.com/nodejs/node/issues/7726 here>.+--+-- Note This function is not implemented on Windows XP and Windows Server 2003. On these systems, UV_ENOSYS is returned.+realpath :: HasCallStack => CBytes -> IO CBytes+realpath path = do+    bracket+        (withCBytesUnsafe path $ \ p ->+            allocPrimUnsafe $ \ p' ->+                throwUVIfMinus (hs_uv_fs_realpath p p'))+        (hs_uv_fs_readlink_cleanup . fst)+        (fromCString . fst)++-- | Equivalent to <http://linux.die.net/man/2/chown chown(2)>.+chown :: HasCallStack => CBytes -> UID -> GID -> IO ()+chown path uid gid = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_chown p uid gid++-- | Equivalent to <http://linux.die.net/man/2/fchown fchown(2)>.+fchown :: HasCallStack => File -> UID -> GID -> IO ()+fchown uvf uid gid = checkFileClosed uvf $ \ fd -> throwUVIfMinus_ $ hs_uv_fs_fchown fd uid gid++-- | Equivalent to <http://linux.die.net/man/2/lchown lchown(2)>.+lchown :: HasCallStack => CBytes -> UID -> GID -> IO ()+lchown path uid gid = throwUVIfMinus_ . withCBytesUnsafe path $ \ p -> hs_uv_fs_lchown p uid gid
Z/IO/FileSystem/Threaded.hs view
@@ -7,7 +7,13 @@ Stability   : experimental Portability : non-portable -This module provides filesystem API exactly same with `Z.IO.FileSystem`, operations(except 'seek') are implemented using libuv's threadpool to achieve non-block behavior (non-block here meaning won't block other haskell threads), which would be prefered when the operations' estimated time is long(>1ms) or running with a non-threaded haskell runtime, such as accessing network filesystem or scan a very large directory. Otherwise you may block RTS's capability thus all the other haskell threads live on it.+This module provides filesystem API exactly same with `Z.IO.FileSystem.Base`,+operations(except 'seek') are implemented using libuv's threadpool to achieve+non-block behavior (non-block here meaning won't block other haskell threads),+which would be prefered when the operations' estimated time is long(>1ms) or+running with a non-threaded haskell runtime, such as accessing network filesystem+or scan a very large directory. Otherwise you may block RTS's capability thus+all the other haskell threads live on it.  The threadpool version operations have overheads similar to safe FFI, but provide same adventages: @@ -19,24 +25,31 @@  -} +-- FIXME: An elegant way to keep this module's API same with 'Z.IO.FileSystem.Base'+-- automatically.+ module Z.IO.FileSystem.Threaded-  ( -- * regular file devices+  ( -- * Regular file devices     File, initFile, readFileP, writeFileP, getFileFD, seek   , readFile, readTextFile, writeFile, writeTextFile   , readJSONFile, writeJSONFile-    -- * file offset bundle-  , FilePtrT, newFilePtrT, getFilePtrOffset, setFilePtrOffset-  -- * filesystem operations+    -- * File offset bundle+  , FilePtr, newFilePtr, getFilePtrOffset, setFilePtrOffset+  -- * Filesystem operations   , mkdir, mkdirp   , unlink-  , mkdtemp-  , rmdir, rmdirrf+  , mkdtemp, mkstemp , initTempFile, initTempDir+  , rmdir, rmrf   , DirEntType(..)   , scandir   , scandirRecursively+    -- ** File stats   , FStat(..), UVTimeSpec(..)-  , stat, lstat, fstat+  , doesPathExist, doesFileExist, doesDirExist   , isLink, isDir, isFile+  , isLinkSt, isDirSt, isFileSt+  , stat, lstat, fstat+  , stat', lstat'   , rename   , fsync, fdatasync   , ftruncate@@ -57,7 +70,8 @@   , pattern X_OK   -- ** FileMode   , FileMode-  , pattern DEFAULT_MODE+  , pattern DEFAULT_FILE_MODE+  , pattern DEFAULT_DIR_MODE   , pattern S_IRWXU   , pattern S_IRUSR   , pattern S_IWUSR@@ -108,27 +122,31 @@  import           Control.Monad import           Data.Bits-import           Data.Int import           Data.IORef+import           Data.Int import           Data.Word+import           Foreign.Marshal.Alloc    (allocaBytes) import           Foreign.Ptr-import           Foreign.Storable               (peekElemOff)-import           Foreign.Marshal.Alloc          (allocaBytes)-import           Z.Data.CBytes                  as CBytes+import           Foreign.Storable         (peekElemOff)+import           Prelude                  hiding (readFile, writeFile)+import qualified Z.Data.Builder           as B+import           Z.Data.CBytes            as CBytes+import qualified Z.Data.JSON              as JSON import           Z.Data.PrimRef.PrimIORef-import qualified Z.Data.Text                    as T-import qualified Z.Data.Text.Print              as T-import qualified Z.Data.Vector                  as V-import qualified Z.Data.JSON                    as JSON+import qualified Z.Data.Text              as T+import qualified Z.Data.Text.Print        as T+import qualified Z.Data.Vector            as V import           Z.Foreign import           Z.IO.Buffered+import qualified Z.IO.Environment         as Env import           Z.IO.Exception-import qualified Z.IO.FileSystem.FilePath       as P+import qualified Z.IO.FileSystem.FilePath as P import           Z.IO.Resource import           Z.IO.UV.FFI import           Z.IO.UV.Manager-import           Prelude hiding                 (writeFile, readFile) +#include "_Shared.hs"+ -------------------------------------------------------------------------------- -- File @@ -227,43 +245,6 @@                    (bufSiz-written)                    (off+fromIntegral written) --- | File bundled with offset.------ Reading or writing using 'Input' \/ 'Output' instance will automatically increase offset.--- 'FilePtrT' and its operations are NOT thread safe, use 'MVar' 'FilePtrT' in multiple threads.------ The notes on linux 'writeFileP' applied to 'FilePtr' too.-data FilePtrT = FilePtrT {-# UNPACK #-} !File-                         {-# UNPACK #-} !(PrimIORef Int64)---- |  Create a file offset bundle from an 'File'.----newFilePtrT :: File      -- ^ the file we're reading-            -> Int64      -- ^ initial offset-            -> IO FilePtrT-newFilePtrT uvf off = FilePtrT uvf <$> newPrimIORef off---- | Get current offset.-getFilePtrOffset :: FilePtrT -> IO Int64-getFilePtrOffset (FilePtrT _ offsetRef) = readPrimIORef offsetRef---- | Change current offset.-setFilePtrOffset :: FilePtrT -> Int64 -> IO ()-setFilePtrOffset (FilePtrT _ offsetRef) = writePrimIORef offsetRef--instance Input FilePtrT where-    readInput (FilePtrT file offsetRef) buf bufSiz =-        readPrimIORef offsetRef >>= \ off -> do-            l <- readFileP file buf bufSiz off-            writePrimIORef offsetRef (off + fromIntegral l)-            return l--instance Output FilePtrT where-    writeOutput (FilePtrT file offsetRef) buf bufSiz =-        readPrimIORef offsetRef >>= \ off -> do-            writeFileP file buf bufSiz off-            writePrimIORef offsetRef (off + fromIntegral bufSiz)- --------------------------------------------------------------------------------  -- | init a file 'Resource', which open a file when used.@@ -276,7 +257,7 @@ initFile :: CBytes           -> FileFlag        -- ^ Opening flags, e.g. 'O_CREAT' @.|.@ 'O_RDWR'           -> FileMode        -- ^ Sets the file mode (permission and sticky bits),-                               -- but only if the file was created, see 'DEFAULT_MODE'.+                               -- but only if the file was created, see 'DEFAULT_FILE_MODE'.           -> Resource File initFile path flags mode =     initResource@@ -290,35 +271,6 @@                 throwUVIfMinus_ (hs_uv_fs_close fd)                 writeIORef closedRef True) --- | Quickly open a file and read its content.-readFile :: HasCallStack => CBytes -> IO V.Bytes-readFile filename = do-    withResource (initFile filename O_RDONLY DEFAULT_MODE) $ \ file -> do-        readAll' =<< newBufferedInput file---- | Quickly open a file and read its content as UTF8 text.-readTextFile :: HasCallStack => CBytes -> IO T.Text-readTextFile filename = T.validate <$> readFile filename---- | Quickly open a file and write some content.-writeFile :: HasCallStack => CBytes -> V.Bytes -> IO ()-writeFile filename content = do-    withResource (initFile filename (O_WRONLY .|. O_CREAT) DEFAULT_MODE) $ \ file -> do-        withPrimVectorSafe content (writeOutput file)---- | Quickly open a file and write some content as UTF8 text.-writeTextFile :: HasCallStack => CBytes -> T.Text -> IO ()-writeTextFile filename content = writeFile filename (T.getUTF8Bytes content)---- | Quickly open a file and read its content as a JSON value.--- Throw 'OtherError' with name @EPARSE@ if JSON value is not parsed.-readJSONFile :: (HasCallStack, JSON.JSON a) => CBytes -> IO a-readJSONFile filename = unwrap "EPARSE" . JSON.decode' =<< readFile filename---- | Quickly open a file and write a JSON Value.-writeJSONFile :: (HasCallStack, JSON.JSON a) => CBytes -> a -> IO ()-writeJSONFile filename x = writeFile filename (JSON.encode x)- --------------------------------------------------------------------------------  -- | Equivalent to <http://linux.die.net/man/2/mkdir mkdir(2)>.@@ -331,34 +283,40 @@     withCBytesUnsafe path $ \ p ->         withUVRequest_ uvm (hs_uv_fs_mkdir_threaded p mode) --- | Equivalent to @mkdir -p@+-- | Recursive directory creation function. Like 'mkdir', but makes all+-- intermediate-level directories needed to contain the leaf directory. ----- Note mode is currently not implemented on Windows. On unix you should set execute bit--- if you want the directory is accessable(so that child folder can be created), e.g. 0o777.+-- Equivalent to @mkdir -p@,+--+-- Note mode is currently not implemented on Windows. On unix you should set+-- execute bit if you want the directory is accessable(so that child folder+-- can be created), e.g. 'DEFAULT_DIR_MODE'.+-- mkdirp :: HasCallStack => CBytes -> FileMode -> IO () mkdirp path mode = do     uvm <- getUVManager     r <- withCBytesUnsafe path $ \ p ->-        withUVRequest' uvm (hs_uv_fs_mkdir_threaded p mode)-            (\ r -> do-                when (r < 0 && fromIntegral r /= UV_ENOENT)-                    (throwUVIfMinus_ (return r))-                return r)-    when (fromIntegral r == UV_ENOENT) $ do-        (root, segs) <- P.splitSegments path-        case segs of-            seg:segs' -> loop segs' =<< P.join root seg-            _ -> throwUVIfMinus_ (return r)+        withUVRequest' uvm (hs_uv_fs_mkdir_threaded p mode) return+    case fromIntegral r of+        UV_ENOENT -> do+            (root, segs) <- P.splitSegments path+            case segs of+                seg:segs' -> loop segs' =<< P.join root seg+                _         -> throwUV r+        UV_EEXIST -> do+            canIgnore <- isDir path+            unless canIgnore (throwUV r)+        _ -> throwUV r   where     loop segs p = do         a <- access p F_OK         case a of             AccessOK     -> return ()             NoExistence  -> mkdir p mode-            NoPermission -> throwUVIfMinus_ (return UV_EACCES)+            NoPermission -> throwUV UV_EACCES         case segs of             (nextp:ps) -> P.join p nextp >>= loop ps-            _  -> return ()+            _          -> return ()  -- | Equivalent to <http://linux.die.net/man/2/unlink unlink(2)>. unlink :: HasCallStack => CBytes -> IO ()@@ -377,6 +335,7 @@ -- -- Note: the argument is the prefix of the temporary directory, -- so no need to add XXXXXX ending.+-- mkdtemp :: HasCallStack => CBytes -> IO CBytes mkdtemp path = do     let size = CBytes.length path@@ -386,6 +345,16 @@             withUVRequest_ uvm (hs_uv_fs_mkdtemp_threaded p size p')         return p'' +-- | Equivalent to <mkstemp https://man7.org/linux/man-pages/man3/mkstemp.3.html>+mkstemp :: HasCallStack => CBytes -> IO CBytes+mkstemp template = do+    let size = CBytes.length template+    CBytes.withCBytesUnsafe template $ \ p -> do+        (p'', _) <- CBytes.allocCBytesUnsafe (size+7) $ \ p' -> do  -- we append "XXXXXX\NUL" in C+            uvm <- getUVManager+            withUVRequest_ uvm (hs_uv_fs_mkstemp_threaded p size p')+        return p''+ -- | Equivalent to <http://linux.die.net/man/2/rmdir rmdir(2)>. -- -- Note this function may inherent OS limitations such as argument must be an empty folder.@@ -394,17 +363,32 @@     uvm <- getUVManager     withCBytesUnsafe path (\ p -> void . withUVRequest uvm $ hs_uv_fs_rmdir_threaded p) --- | Equivalent to @rmdir -rf@------ This function will try to remove folder and files contained by it.-rmdirrf :: HasCallStack => CBytes -> IO ()-rmdirrf path = do-    ds <- scandir path-    forM_ ds $ \ (d, t) -> do-        if t /= DirEntDir-        then unlink d-        else rmdirrf =<< path `P.join` d-    rmdir path+-- | Removes a file or directory at path together with its contents and+-- subdirectories. Symbolic links are removed without affecting their targets.+-- If the path does not exist, nothing happens.+rmrf :: HasCallStack => CBytes -> IO ()+rmrf path =+    withCBytesUnsafe path $ \path' ->+    allocaBytes uvStatSize $ \s -> do+        uvm <- getUVManager+        withUVRequest' uvm (hs_uv_fs_stat_threaded path' s) $ \ r -> do+            if  | r == fromIntegral UV_ENOENT -> pure ()+                | r < 0 -> throwUV r+                | otherwise -> do+                    st <- peekUVStat s+                    case stMode st .&. S_IFMT of+                        S_IFREG -> unlink path+                        S_IFLNK -> unlink path+                        S_IFDIR -> do+                            ds <- scandir path+                            forM_ ds $ \ (d, t) ->+                                if t /= DirEntDir+                                then unlink d+                                else rmrf =<< path `P.join` d+                            rmdir path+                        mode    -> do+                            let desc = B.buildText $ "Unsupported file mode: " >> B.hex mode+                            throwIO $ UnsupportedOperation (IOEInfo "" desc callStack)  -------------------------------------------------------------------------------- @@ -430,26 +414,6 @@             !p' <- fromCString p             return (p', typ')) --- | Find all files and directories within a given directory with a predicator.------ @---  import Z.IO.FileSystem.FilePath (splitExtension)---  -- find all haskell source file within current dir---  scandirRecursively "."  (\ p _ -> (== ".hs") . snd <$> splitExtension p)--- @-scandirRecursively :: HasCallStack => CBytes -> (CBytes -> DirEntType -> IO Bool) -> IO [CBytes]-scandirRecursively dir p = loop [] =<< P.normalize dir-  where-    loop acc0 pdir =-        foldM (\ acc (d,t) -> do-            d' <- pdir `P.join` d-            r <- p d' t-            let acc' = if r then (d':acc) else acc-            if (t == DirEntDir)-            then loop acc' d'-            else return acc'-        ) acc0 =<< scandir pdir- --------------------------------------------------------------------------------  -- | Equivalent to <http://linux.die.net/man/2/stat stat(2)>@@ -470,6 +434,32 @@             withUVRequest_ uvm (hs_uv_fs_lstat_threaded p s)             peekUVStat s +-- | Equivalent to <http://linux.die.net/man/2/stat stat(2)>+--+-- Return 'Nothing' instead of throwing 'NoSuchThing' if the file doesn't exist.+stat' :: HasCallStack => CBytes -> IO (Maybe FStat)+stat' path = do+    withCBytesUnsafe path $ \ p ->+         allocaBytes uvStatSize $ \ s -> do+            uvm <- getUVManager+            withUVRequest' uvm (hs_uv_fs_stat_threaded p s) $ \ r ->+                if  | r == fromIntegral UV_ENOENT -> pure Nothing+                    | r < 0           -> throwUV r+                    | otherwise       -> Just <$> peekUVStat s++-- | Equivalent to <http://linux.die.net/man/2/lstat lstat(2)>+--+-- Return 'Nothing' instead of throwing 'NoSuchThing' if the link doesn't exist.+lstat' :: HasCallStack => CBytes -> IO (Maybe FStat)+lstat' path =+    withCBytesUnsafe path $ \ p ->+         allocaBytes uvStatSize $ \ s -> do+            uvm <- getUVManager+            withUVRequest' uvm (hs_uv_fs_lstat_threaded p s) $ \ r ->+                if  | r == fromIntegral UV_ENOENT -> pure Nothing+                    | r < 0           -> throwUV r+                    | otherwise       -> Just <$> peekUVStat s+ -- | Equivalent to <http://linux.die.net/man/2/fstat fstat(2)> fstat :: HasCallStack => File -> IO FStat fstat uvf = checkFileClosed uvf $ \ fd ->@@ -477,18 +467,6 @@         uvm <- getUVManager         withUVRequest_ uvm (hs_uv_fs_fstat_threaded fd s)         peekUVStat s)---- | If given path is a symbolic link?-isLink :: HasCallStack => CBytes -> IO Bool-isLink p = lstat p >>= \ st -> return (stMode st .&. S_IFMT == S_IFLNK)---- | If given path is a directory or a symbolic link to a directory?-isDir :: HasCallStack => CBytes -> IO Bool-isDir p = stat p >>= \ st -> return (stMode st .&. S_IFMT == S_IFDIR)---- | If given path is a file or a symbolic link to a file?-isFile :: HasCallStack => CBytes -> IO Bool-isFile p = stat p >>= \ st -> return (stMode st .&. S_IFMT == S_IFREG)  -------------------------------------------------------------------------------- 
Z/IO/FileSystem/Watch.hs view
@@ -46,7 +46,7 @@ import           Z.IO.BIO import           Z.IO.BIO.Concurrent import           Z.IO.Exception-import           Z.IO.FileSystem+import           Z.IO.FileSystem.Base import qualified Z.IO.FileSystem.FilePath as P import           Z.IO.UV.FFI import           Z.IO.UV.Manager
+ Z/IO/FileSystem/_Shared.hs view
@@ -0,0 +1,156 @@+-- This file should be included from both base and threaded FS module++-- | File bundled with offset.+--+-- Reading or writing using 'Input' \/ 'Output' instance will automatically increase offset.+-- 'FilePtr' and its operations are NOT thread safe, use 'MVar' 'FilePtr' in multiple threads.+--+-- The notes on linux 'writeFileP' applied to 'FilePtr' too.+data FilePtr = FilePtr {-# UNPACK #-} !File+                       {-# UNPACK #-} !(PrimIORef Int64)++-- |  Create a file offset bundle from an 'File'.+--+newFilePtr :: File       -- ^ the file we're reading+           -> Int64      -- ^ initial offset+           -> IO FilePtr+newFilePtr uvf off = FilePtr uvf <$> newPrimIORef off++-- | Get current offset.+getFilePtrOffset :: FilePtr -> IO Int64+getFilePtrOffset (FilePtr _ offsetRef) = readPrimIORef offsetRef++-- | Change current offset.+setFilePtrOffset :: FilePtr -> Int64 -> IO ()+setFilePtrOffset (FilePtr _ offsetRef) = writePrimIORef offsetRef++instance Input FilePtr where+    readInput (FilePtr file offsetRef) buf bufSiz =+        readPrimIORef offsetRef >>= \ off -> do+            l <- readFileP file buf bufSiz off+            writePrimIORef offsetRef (off + fromIntegral l)+            return l++instance Output FilePtr where+    writeOutput (FilePtr file offsetRef) buf bufSiz =+        readPrimIORef offsetRef >>= \ off -> do+            writeFileP file buf bufSiz off+            writePrimIORef offsetRef (off + fromIntegral bufSiz)++-- | Quickly open a file and read its content.+readFile :: HasCallStack => CBytes -> IO V.Bytes+readFile filename = do+    withResource (initFile filename O_RDONLY DEFAULT_FILE_MODE) $ \ file -> do+        readAll' =<< newBufferedInput file++-- | Quickly open a file and read its content as UTF8 text.+readTextFile :: HasCallStack => CBytes -> IO T.Text+readTextFile filename = T.validate <$> readFile filename++-- | Quickly open a file and write some content.+writeFile :: HasCallStack => CBytes -> V.Bytes -> IO ()+writeFile filename content = do+    withResource (initFile filename (O_WRONLY .|. O_CREAT) DEFAULT_FILE_MODE) $ \ file -> do+        withPrimVectorSafe content (writeOutput file)++-- | Quickly open a file and write some content as UTF8 text.+writeTextFile :: HasCallStack => CBytes -> T.Text -> IO ()+writeTextFile filename content = writeFile filename (T.getUTF8Bytes content)++-- | Quickly open a file and read its content as a JSON value.+-- Throw 'OtherError' with name @EPARSE@ if JSON value is not parsed.+readJSONFile :: (HasCallStack, JSON.JSON a) => CBytes -> IO a+readJSONFile filename = unwrap "EPARSE" . JSON.decode' =<< readFile filename++-- | Quickly open a file and write a JSON Value.+writeJSONFile :: (HasCallStack, JSON.JSON a) => CBytes -> a -> IO ()+writeJSONFile filename x = writeFile filename (JSON.encode x)++--------------------------------------------------------------------------------++-- | Find all files and directories within a given directory with a predicator.+--+-- @+--  import Z.IO.FileSystem.FilePath (splitExtension)+--  -- find all haskell source file within current dir+--  scandirRecursively "."  (\\ p _ -> (== ".hs") . snd \<$\> splitExtension p)+-- @+scandirRecursively :: HasCallStack => CBytes -> (CBytes -> DirEntType -> IO Bool) -> IO [CBytes]+scandirRecursively dir p = loop [] =<< P.normalize dir+  where+    loop acc0 pdir =+        foldM (\ acc (d,t) -> do+            d' <- pdir `P.join` d+            r <- p d' t+            let acc' = if r then (d':acc) else acc+            if (t == DirEntDir)+            then loop acc' d'+            else return acc'+        ) acc0 =<< scandir pdir++--------------------------------------------------------------------------------++-- | Does given path exist?+--+doesPathExist :: CBytes -> IO Bool+doesPathExist path = maybe False (const True) <$> stat' path++-- | Returns 'True' if the argument file exists and is either a file or a+-- symbolic link to a file, and 'False' otherwise.+doesFileExist :: CBytes -> IO Bool+doesFileExist path = maybe False isFileSt <$> stat' path++-- | Returns 'True' if the argument directory exists and is either a directory or a+-- symbolic link to a directory, and 'False' otherwise.+doesDirExist :: CBytes -> IO Bool+doesDirExist path = maybe False isDirSt <$> stat' path++--------------------------------------------------------------------------------++-- | If given path is a symbolic link?+isLink :: HasCallStack => CBytes -> IO Bool+isLink = fmap isLinkSt . lstat++-- | If given path is a directory or a symbolic link to a directory?+isDir :: HasCallStack => CBytes -> IO Bool+isDir = fmap isDirSt . stat++-- | If given path is a file or a symbolic link to a file?+isFile :: HasCallStack => CBytes -> IO Bool+isFile = fmap isFileSt . stat++-- | Shortcut to @\\ st -> stMode st .&. S_IFMT == S_IFLNK@+--+-- Note you should use 'lstat' to get the link's stat.+isLinkSt :: FStat -> Bool+isLinkSt st = stMode st .&. S_IFMT == S_IFLNK++-- | Shortcut to @\\ st -> stMode st .&. S_IFMT == S_IFDIR@+isDirSt :: FStat -> Bool+isDirSt st = stMode st .&. S_IFMT == S_IFDIR++-- | Shortcut to @\\ st -> stMode st .&. S_IFMT == S_IFREG@+isFileSt :: FStat -> Bool+isFileSt st = stMode st .&. S_IFMT == S_IFREG++-------------------------------------------------------------------------------++-- | Make a temporary file under system 'Env.getTempDir' and automatically clean after used.+--+-- >>> withResource (initTempFile "foo") $ printStd+-- File 13+--+initTempFile :: CBytes -> Resource File+initTempFile prefix =+    initResource initAction unlink >>= (\f -> initFile f O_RDWR DEFAULT_FILE_MODE)+    where+        initAction = Env.getTempDir >>= (`P.join` prefix) >>= mkstemp++-- | Make a temporary directory under system 'Env.getTempDir' and automatically clean after used.+--+-- >>> withResource (initTempDir "foo") $ printStd+-- "/tmp/fooxfWR0L"+--+initTempDir :: CBytes -> Resource CBytes+initTempDir prefix =+    initResource (Env.getTempDir >>= (`P.join` prefix) >>= mkdtemp) rmrf
Z/IO/UV/FFI.hsc view
@@ -45,7 +45,7 @@ -------------------------------------------------------------------------------- -- Type alias type UVSlot = Int--- | UVSlotUnsafe wrap a slot which may not have a 'MVar' in blocking table, +-- | UVSlotUnsafe wrap a slot which may not have a 'MVar' in blocking table, --   i.e. the blocking table need to be resized. newtype UVSlotUnsafe = UVSlotUnsafe { unsafeGetSlot :: UVSlot } type FD = CInt@@ -77,7 +77,7 @@     <$> (#{peek hs_loop_data, buffer_table          } p)     <*> (#{peek hs_loop_data, buffer_size_table     } p) -type UVRunMode = CInt +type UVRunMode = CInt  pattern UV_RUN_DEFAULT :: UVRunMode pattern UV_RUN_DEFAULT = #const UV_RUN_DEFAULT@@ -174,14 +174,14 @@ foreign import ccall unsafe uv_udp_open :: Ptr UVHandle -> FD -> IO CInt foreign import ccall unsafe uv_udp_bind :: Ptr UVHandle -> MBA## SocketAddr -> UDPFlag -> IO CInt -type Membership = CInt +type Membership = CInt  pattern LEAVE_GROUP :: Membership pattern LEAVE_GROUP = #const UV_LEAVE_GROUP pattern JOIN_GROUP :: Membership pattern JOIN_GROUP = #const UV_JOIN_GROUP -type UDPFlag = CInt +type UDPFlag = CInt  pattern UDP_DEFAULT        :: UDPFlag pattern UDP_DEFAULT         = 0@@ -215,11 +215,11 @@  foreign import ccall unsafe hs_uv_udp_check_start :: Ptr UVHandle -> IO CInt -foreign import ccall unsafe hs_uv_udp_send +foreign import ccall unsafe hs_uv_udp_send     :: Ptr UVHandle -> MBA## SocketAddr -> Ptr Word8 -> Int -> IO UVSlotUnsafe foreign import ccall unsafe hs_uv_udp_send_connected     :: Ptr UVHandle -> Ptr Word8 -> Int -> IO UVSlotUnsafe-foreign import ccall unsafe uv_udp_getsockname +foreign import ccall unsafe uv_udp_getsockname     :: Ptr UVHandle -> MBA## SocketAddr -> MBA## CInt -> IO CInt foreign import ccall unsafe uv_udp_getpeername     :: Ptr UVHandle -> MBA## SocketAddr -> MBA## CInt -> IO CInt@@ -231,7 +231,7 @@ -- | Terminal mode. -- -- When in 'TTY_MODE_RAW' mode, input is always available character-by-character,--- not including modifiers. Additionally, all special processing of characters by the terminal is disabled, +-- not including modifiers. Additionally, all special processing of characters by the terminal is disabled, -- including echoing input characters. Note that CTRL+C will no longer cause a SIGINT when in this mode. type TTYMode = CInt @@ -299,10 +299,14 @@ pattern S_IXOTH :: FileMode pattern S_IXOTH = #const S_IXOTH --- | Default mode for open, 0o666(readable and writable).-pattern DEFAULT_MODE :: FileMode-pattern DEFAULT_MODE = 0o666+-- | Default mode for file open, 0x666(readable and writable).+pattern DEFAULT_FILE_MODE :: FileMode+pattern DEFAULT_FILE_MODE = 0o644 +-- | Default mode for open, 0x755.+pattern DEFAULT_DIR_MODE :: FileMode+pattern DEFAULT_DIR_MODE = 0o755+ -- | This is the file type mask. pattern S_IFMT :: FileMode pattern S_IFMT = #const S_IFMT@@ -328,24 +332,27 @@ foreign import ccall unsafe hs_uv_fs_mkdir   :: BA## Word8 -> FileMode -> IO Int foreign import ccall unsafe hs_uv_fs_rmdir   :: BA## Word8 -> IO Int foreign import ccall unsafe hs_uv_fs_mkdtemp :: BA## Word8 -> Int -> MBA## Word8 -> IO Int+foreign import ccall unsafe hs_uv_fs_mkstemp :: BA## Word8 -> Int -> MBA## Word8 -> IO Int  -- threaded functions-foreign import ccall unsafe hs_uv_fs_open_threaded +foreign import ccall unsafe hs_uv_fs_open_threaded     :: BA## Word8 -> FileFlag -> FileMode -> Ptr UVLoop -> IO UVSlotUnsafe-foreign import ccall unsafe hs_uv_fs_close_threaded +foreign import ccall unsafe hs_uv_fs_close_threaded     :: FD -> Ptr UVLoop -> IO UVSlotUnsafe-foreign import ccall unsafe hs_uv_fs_read_threaded  +foreign import ccall unsafe hs_uv_fs_read_threaded     :: FD -> Ptr Word8 -> Int -> Int64 -> Ptr UVLoop -> IO UVSlotUnsafe-foreign import ccall unsafe hs_uv_fs_write_threaded +foreign import ccall unsafe hs_uv_fs_write_threaded     :: FD -> Ptr Word8 -> Int -> Int64 -> Ptr UVLoop -> IO UVSlotUnsafe foreign import ccall unsafe hs_uv_fs_unlink_threaded     :: BA## Word8 -> Ptr UVLoop -> IO UVSlotUnsafe-foreign import ccall unsafe hs_uv_fs_mkdir_threaded +foreign import ccall unsafe hs_uv_fs_mkdir_threaded     :: BA## Word8 -> FileMode -> Ptr UVLoop -> IO UVSlotUnsafe-foreign import ccall unsafe hs_uv_fs_rmdir_threaded +foreign import ccall unsafe hs_uv_fs_rmdir_threaded     :: BA## Word8 -> Ptr UVLoop -> IO UVSlotUnsafe-foreign import ccall unsafe hs_uv_fs_mkdtemp_threaded +foreign import ccall unsafe hs_uv_fs_mkdtemp_threaded     :: BA## Word8 -> Int -> MBA## Word8 -> Ptr UVLoop -> IO UVSlotUnsafe+foreign import ccall unsafe hs_uv_fs_mkstemp_threaded+    :: BA## Word8 -> Int -> MBA## Word8 -> Ptr UVLoop -> IO UVSlotUnsafe  type FileFlag = CInt @@ -375,8 +382,8 @@  -- | If the 'O_CREAT' flag is set and the file already exists, fail the open. ----- Note In general, the behavior of 'O_EXCL' is undefined if it is used without 'O_CREAT'. There is one exception: on --- Linux 2.6 and later, 'O_EXCL' can be used without 'O_CREAT' if pathname refers to a block device. If the block +-- Note In general, the behavior of 'O_EXCL' is undefined if it is used without 'O_CREAT'. There is one exception: on+-- Linux 2.6 and later, 'O_EXCL' can be used without 'O_CREAT' if pathname refers to a block device. If the block -- device is in use by the system (e.g., mounted), the open will fail with the error @EBUSY@. pattern O_EXCL :: FileFlag pattern O_EXCL = #const UV_FS_O_EXCL@@ -389,7 +396,7 @@ pattern O_EXLOCK = #const UV_FS_O_EXLOCK  -- | Do not update the file access time when the file is read.--- +-- -- Note 'O_NOATIME' is not supported on Windows. pattern O_NOATIME :: FileFlag pattern O_NOATIME = #const UV_FS_O_NOATIME@@ -413,7 +420,7 @@ pattern O_NONBLOCK = #const UV_FS_O_NONBLOCK  -- | Access is intended to be random. The system can use this as a hint to optimize file caching.--- +-- -- Note 'O_RANDOM' is only supported on Windows via @FILE_FLAG_RANDOM_ACCESS@. pattern O_RANDOM :: FileFlag pattern O_RANDOM = #const UV_FS_O_RANDOM@@ -428,7 +435,7 @@   -- | Access is intended to be sequential from beginning to end. The system can use this as a hint to optimize file caching.--- +-- -- Note 'O_SEQUENTIAL' is only supported on Windows via @FILE_FLAG_SEQUENTIAL_SCAN@. pattern O_SEQUENTIAL :: FileFlag pattern O_SEQUENTIAL = #const UV_FS_O_SEQUENTIAL@@ -519,12 +526,12 @@     :: Ptr (Ptr DirEntType) -> Int -> IO () foreign import ccall unsafe hs_uv_fs_scandir     :: BA## Word8 -> MBA## (Ptr DirEntType) -> IO Int-foreign import ccall unsafe hs_uv_fs_scandir_extra_cleanup +foreign import ccall unsafe hs_uv_fs_scandir_extra_cleanup     :: Ptr (Ptr (Ptr DirEntType)) -> Int -> IO () foreign import ccall unsafe hs_uv_fs_scandir_threaded     :: BA## Word8 -> Ptr (Ptr (Ptr DirEntType)) -> Ptr UVLoop -> IO UVSlotUnsafe -data UVTimeSpec = UVTimeSpec +data UVTimeSpec = UVTimeSpec     { uvtSecond     :: {-# UNPACK #-} !CLong     , uvtNanoSecond :: {-# UNPACK #-} !CLong     } deriving (Show, Read, Eq, Ord, Generic)@@ -557,7 +564,7 @@     , stCtim     :: {-# UNPACK #-} !UVTimeSpec     , stBirthtim :: {-# UNPACK #-} !UVTimeSpec     } deriving (Show, Read, Eq, Ord, Generic)-        deriving anyclass (Print, JSON)+      deriving anyclass (Print, JSON)  uvStatSize :: Int uvStatSize = #{size uv_stat_t}@@ -601,11 +608,11 @@     :: FD -> Ptr UVLoop -> IO UVSlotUnsafe foreign import ccall unsafe hs_uv_fs_fdatasync_threaded     :: FD -> Ptr UVLoop -> IO UVSlotUnsafe-foreign import ccall unsafe hs_uv_fs_ftruncate_threaded +foreign import ccall unsafe hs_uv_fs_ftruncate_threaded     :: FD -> Int64 -> Ptr UVLoop -> IO UVSlotUnsafe  -- | Flags control copying.--- +-- --  * 'COPYFILE_EXCL': If present, uv_fs_copyfile() will fail with UV_EEXIST if the destination path already exists. The default behavior is to overwrite the destination if it exists. --  * 'COPYFILE_FICLONE': If present, uv_fs_copyfile() will attempt to create a copy-on-write reflink. If the underlying platform does not support copy-on-write, then a fallback copy mechanism is used. --  * 'COPYFILE_FICLONE_FORCE': If present, uv_fs_copyfile() will attempt to create a copy-on-write reflink. If the underlying platform does not support copy-on-write, or an error occurs while attempting to use copy-on-write, then an error is returned.@@ -638,7 +645,7 @@ pattern X_OK :: AccessMode pattern X_OK = #const X_OK -data AccessResult = NoExistence | NoPermission | AccessOK +data AccessResult = NoExistence | NoPermission | AccessOK     deriving (Show, Eq, Ord, Enum, Generic)     deriving anyclass (Print, JSON) @@ -696,7 +703,7 @@     :: BA## Word8 -> MBA## CString -> IO Int foreign import ccall unsafe hs_uv_fs_realpath     :: BA## Word8  -> MBA## CString -> IO Int-foreign import ccall unsafe hs_uv_fs_readlink_extra_cleanup +foreign import ccall unsafe hs_uv_fs_readlink_extra_cleanup     :: Ptr CString -> IO () foreign import ccall unsafe hs_uv_fs_readlink_threaded     :: BA## Word8  -> Ptr CString -> Ptr UVLoop -> IO UVSlotUnsafe@@ -716,7 +723,7 @@ -------------------------------------------------------------------------------- -- process -newtype UID = UID +newtype UID = UID #if defined(_WIN32)     Word8 #else@@ -726,7 +733,7 @@    deriving newtype (Storable, Prim, Unaligned, Num, JSON)    deriving anyclass Print -newtype GID = GID +newtype GID = GID #if defined(_WIN32)     Word8 #else@@ -749,12 +756,12 @@ pattern PROCESS_SETGID :: ProcessFlag pattern PROCESS_SETGID = (#const UV_PROCESS_SETGID) -- | Do not wrap any arguments in quotes, or perform any other escaping, when--- converting the argument list into a command line string. +-- converting the argument list into a command line string. -- -- This option is only meaningful on Windows systems. On Unix it is silently ignored. pattern PROCESS_WINDOWS_VERBATIM_ARGUMENTS :: ProcessFlag pattern PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (#const UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)--- | Spawn the child process in a detached state +-- | Spawn the child process in a detached state -- -- This will make it a process group leader, and will effectively enable the child to keep running after -- the parent exits.@@ -765,12 +772,12 @@ -- This option is only meaningful on Windows systems. On Unix it is silently ignored. pattern PROCESS_WINDOWS_HIDE :: ProcessFlag pattern PROCESS_WINDOWS_HIDE = (#const UV_PROCESS_WINDOWS_HIDE)--- | Hide the subprocess console window that would normally be created. +-- | Hide the subprocess console window that would normally be created. -- -- This option is only meaningful on Windows systems. On Unix it is silently ignored. pattern PROCESS_WINDOWS_HIDE_CONSOLE :: ProcessFlag pattern PROCESS_WINDOWS_HIDE_CONSOLE = (#const UV_PROCESS_WINDOWS_HIDE_CONSOLE)--- | Hide the subprocess GUI window that would normally be created. +-- | Hide the subprocess GUI window that would normally be created. -- -- This option is only meaningful on Windows systems. On Unix it is silently ignored. pattern PROCESS_WINDOWS_HIDE_GUI :: ProcessFlag@@ -793,7 +800,7 @@  data ProcessOptions = ProcessOptions     { processFile :: CBytes                     -- ^ Path pointing to the program to be executed.-    , processArgs :: [CBytes]                   -- ^ Command line arguments. +    , processArgs :: [CBytes]                   -- ^ Command line arguments.                                                 -- On Windows this uses CreateProcess which concatenates                                                 -- the arguments into a string this can cause some strange errors.                                                 -- See the 'PROCESS_WINDOWS_VERBATIM_ARGUMENTS'.@@ -803,7 +810,7 @@     , processUID :: UID -- ^ This happens only when the appropriate bits are set in the flags fields.     , processGID :: GID -- ^ This happens only when the appropriate bits are set in the flags fields.     , processStdStreams :: (ProcessStdStream, ProcessStdStream, ProcessStdStream) -- ^ Specifying how (stdin, stdout, stderr) should be passed/created to the child, see 'ProcessStdStream'-                            +     }   deriving (Eq, Ord, Show, Read, Generic)         deriving anyclass (Print, JSON) @@ -816,12 +823,12 @@  processStdStreamFlag :: ProcessStdStream -> CInt processStdStreamFlag ProcessIgnore = #const UV_IGNORE-processStdStreamFlag ProcessCreate = (#const UV_CREATE_PIPE) +processStdStreamFlag ProcessCreate = (#const UV_CREATE_PIPE)                             .|. (#const UV_READABLE_PIPE)                             .|. (#const UV_WRITABLE_PIPE) processStdStreamFlag (ProcessInherit _) = #const UV_INHERIT_FD -foreign import ccall unsafe hs_uv_spawn :: Ptr UVLoop +foreign import ccall unsafe hs_uv_spawn :: Ptr UVLoop                                         -> MBA## ProcessOptions         --  option                                         -> BA## Word8                   --  file                                         -> BAArray## Word8              --  all args@@ -888,7 +895,7 @@  -- | Data type for storing times. -- typedef struct { long tv_sec; long tv_usec; } uv_timeval_t;-data TimeVal = TimeVal +data TimeVal = TimeVal     { tv_sec  :: {-# UNPACK #-} !CLong     , tv_usec :: {-# UNPACK #-} !CLong     }   deriving (Show, Read, Eq, Ord, Generic)@@ -896,7 +903,7 @@  -- | Data type for resource usage results. ----- Members marked with (X) are unsupported on Windows. +-- Members marked with (X) are unsupported on Windows. -- See <https://man7.org/linux/man-pages/man2/getrusage.2.html getrusage(2)> for supported fields on Unix data ResUsage = ResUsage     { ru_utime    :: {-# UNPACK #-} !TimeVal   -- ^  user CPU time used, in microseconds@@ -950,7 +957,7 @@ foreign import ccall unsafe uv_os_getpriority :: PID -> MBA## CInt -> IO CInt foreign import ccall unsafe uv_os_setpriority :: PID -> CInt -> IO CInt -newtype PID = PID CInt +newtype PID = PID CInt     deriving (Eq, Ord, Show, Read, Generic)     deriving newtype (Storable, Prim, Unaligned, JSON)     deriving anyclass Print@@ -962,12 +969,12 @@ pattern PRIORITY_ABOVE_NORMAL :: Priority pattern PRIORITY_HIGH         :: Priority pattern PRIORITY_HIGHEST      :: Priority-pattern PRIORITY_LOW           = #const UV_PRIORITY_LOW         -pattern PRIORITY_BELOW_NORMAL  = #const UV_PRIORITY_BELOW_NORMAL  -pattern PRIORITY_NORMAL        = #const UV_PRIORITY_NORMAL        -pattern PRIORITY_ABOVE_NORMAL  = #const UV_PRIORITY_ABOVE_NORMAL  -pattern PRIORITY_HIGH          = #const UV_PRIORITY_HIGH          -pattern PRIORITY_HIGHEST       = #const UV_PRIORITY_HIGHEST       +pattern PRIORITY_LOW           = #const UV_PRIORITY_LOW+pattern PRIORITY_BELOW_NORMAL  = #const UV_PRIORITY_BELOW_NORMAL+pattern PRIORITY_NORMAL        = #const UV_PRIORITY_NORMAL+pattern PRIORITY_ABOVE_NORMAL  = #const UV_PRIORITY_ABOVE_NORMAL+pattern PRIORITY_HIGH          = #const UV_PRIORITY_HIGH+pattern PRIORITY_HIGHEST       = #const UV_PRIORITY_HIGHEST  foreign import ccall unsafe uv_hrtime :: IO Word64 @@ -997,9 +1004,9 @@     sn <- peekMBACBytes mba## (#offset uv_utsname_t, sysname)     re <- peekMBACBytes mba## (#offset uv_utsname_t, release)     ve <- peekMBACBytes mba## (#offset uv_utsname_t, version)-    ma <- peekMBACBytes mba##  (#offset uv_utsname_t, machine) +    ma <- peekMBACBytes mba##  (#offset uv_utsname_t, machine)     return (OSName sn re ve ma)-    + foreign import ccall unsafe uv_os_uname :: MBA## OSName -> IO CInt  foreign import ccall unsafe hs_uv_random :: MBA## Word8 -> CSize -> CInt -> IO CInt@@ -1018,10 +1025,10 @@ foreign import ccall unsafe uv_os_get_passwd :: MBA## PassWD -> IO CInt foreign import ccall unsafe uv_os_free_passwd :: MBA## PassWD -> IO () --- | Gets a subset of the password file entry for the current effective uid (not the real uid). +-- | Gets a subset of the password file entry for the current effective uid (not the real uid). -- -- The populated data includes the username, euid, gid, shell, and home directory.--- On non-Windows systems, all data comes from getpwuid_r(3). +-- On non-Windows systems, all data comes from getpwuid_r(3). -- On Windows, uid and gid are set to -1 and have no meaning, and shell is empty. getPassWD :: HasCallStack => IO PassWD getPassWD =  bracket@@ -1049,10 +1056,10 @@ data CPUInfo = CPUInfo     { cpu_model :: CBytes     , cpu_speed :: CInt-    , cpu_times_user :: Word64  -- ^ milliseconds +    , cpu_times_user :: Word64  -- ^ milliseconds     , cpu_times_nice :: Word64  -- ^ milliseconds-    , cpu_times_sys  :: Word64  -- ^ milliseconds -    , cpu_times_idle :: Word64  -- ^ milliseconds  +    , cpu_times_sys  :: Word64  -- ^ milliseconds+    , cpu_times_idle :: Word64  -- ^ milliseconds     , cpu_times_irq  :: Word64  -- ^ milliseconds     }   deriving (Eq, Ord, Show, Read, Generic)         deriving anyclass (Print, JSON)@@ -1060,8 +1067,8 @@ -- | Gets information about the CPUs on the system. getCPUInfo :: HasCallStack => IO [CPUInfo] getCPUInfo = bracket-    (do (p, (len, _)) <-  allocPrimUnsafe $ \ pp -> -            allocPrimUnsafe $ \ plen -> +    (do (p, (len, _)) <-  allocPrimUnsafe $ \ pp ->+            allocPrimUnsafe $ \ plen ->                 throwUVIfMinus_ (uv_cpu_info pp plen)         return (p, len))     (\ (p, len) -> uv_free_cpu_info p len)@@ -1084,7 +1091,7 @@ -- | Gets the load average. See: <https://en.wikipedia.org/wiki/Load_(computing)> getLoadAvg :: IO (Double, Double, Double) getLoadAvg = do-    (arr, _) <- allocPrimArrayUnsafe 3 uv_loadavg +    (arr, _) <- allocPrimArrayUnsafe 3 uv_loadavg     return ( indexPrimArray arr 0            , indexPrimArray arr 1            , indexPrimArray arr 2)
cbits/hs_uv_file.c view
@@ -90,6 +90,16 @@     return (HsInt)req.result; } +HsInt hs_uv_fs_mkstemp(const char* tpl, HsInt tpl_size, char* temp_path) {+    uv_fs_t req;+    strcpy(temp_path, tpl);+    strcpy(temp_path + tpl_size, "XXXXXX");+    uv_fs_mkstemp(NULL, &req, temp_path, NULL);+    strcpy(temp_path, req.path);    // save the temp path+    uv_fs_req_cleanup(&req);        // maybe not neccessary+    return (HsInt)req.result;+}+ HsInt hs_uv_fs_rmdir(const char* path){     uv_fs_t req;     uv_fs_rmdir(NULL, &req, path, NULL);@@ -281,7 +291,7 @@ void hs_uv_fs_callback(uv_fs_t* req){     uv_loop_t* loop = req->loop;     hs_loop_data* loop_data = loop->data;-    HsInt slot = (HsInt)req->data; +    HsInt slot = (HsInt)req->data;     // push the slot to event queue     loop_data->buffer_size_table[slot] = (HsInt)req->result;     loop_data->event_queue[loop_data->event_counter] = slot;@@ -294,7 +304,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot; @@ -309,7 +319,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_close(loop, req, (uv_file)file, hs_uv_fs_callback);@@ -323,7 +333,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     uv_buf_t buf = { .base = buffer, .len = (size_t)buffer_size };@@ -338,7 +348,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     uv_buf_t buf = { .base = buffer, .len = (size_t)buffer_size };@@ -353,7 +363,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_unlink(loop, req, path, hs_uv_fs_callback);@@ -367,7 +377,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_mkdir(loop, req, path, mode, hs_uv_fs_callback);@@ -377,10 +387,10 @@     } else return slot; } -void hs_uv_fs_mkdtemp_callback(uv_fs_t* req){+void hs_uv_fs_mktemp_callback(uv_fs_t* req){     uv_loop_t* loop = req->loop;     hs_loop_data* loop_data = loop->data;-    HsInt slot = (HsInt)req->data; +    HsInt slot = (HsInt)req->data;     char* path = loop_data->buffer_table[slot];     if (path != NULL) {         // push the slot to event queue@@ -397,24 +407,41 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     strcpy(temp_path, tpl);     strcpy(temp_path + tpl_size, "XXXXXX");     loop_data->buffer_table[slot] = temp_path;-    int r = uv_fs_mkdtemp(loop, req, temp_path, hs_uv_fs_mkdtemp_callback);+    int r = uv_fs_mkdtemp(loop, req, temp_path, hs_uv_fs_mktemp_callback);     if (r < 0) {         free_slot(loop_data, slot);         return (HsInt)r;     } else return slot; } +HsInt hs_uv_fs_mkstemp_threaded(const char* tpl, HsInt tpl_size, char* temp_path, uv_loop_t* loop){+    hs_loop_data* loop_data = loop->data;+    HsInt slot = alloc_slot(loop_data);+    if (slot < 0) return UV_ENOMEM;+    uv_fs_t* req =+        (uv_fs_t*)fetch_uv_struct(loop_data, slot);+    req->data = (void*)slot;+    strcpy(temp_path, tpl);+    strcpy(temp_path + tpl_size, "XXXXXX");+    loop_data->buffer_table[slot] = temp_path;+    int r = uv_fs_mkstemp(loop, req, temp_path, hs_uv_fs_mktemp_callback);+    if (r < 0) {+        free_slot(loop_data, slot);+        return (HsInt)r;+    } else return slot;+}+ HsInt hs_uv_fs_rmdir_threaded(const char* path, uv_loop_t* loop){     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_rmdir(loop, req, path, hs_uv_fs_callback);@@ -427,7 +454,7 @@ void hs_uv_fs_scandir_callback(uv_fs_t* req){     uv_loop_t* loop = req->loop;     hs_loop_data* loop_data = loop->data;-    HsInt slot = (HsInt)req->data; +    HsInt slot = (HsInt)req->data;     uv_dirent_t*** dents = (uv_dirent_t***)loop_data->buffer_table[slot];     if (dents != NULL) {         *dents = req->ptr;@@ -438,14 +465,14 @@         loop_data->event_counter += 1;     }     //  we can't cleanup request here, because doing that will-    //  destory our dents array, which we haven't copied in Haskell yet. +    //  destory our dents array, which we haven't copied in Haskell yet.     //  so we manually break down uv_fs_req_cleanup here:     //  we free path buffer first, then clean up dents later using-    //  hs_uv_fs_scandir_cleanup, or hs_uv_fs_scandir_extra_cleanup +    //  hs_uv_fs_scandir_cleanup, or hs_uv_fs_scandir_extra_cleanup     //  in case of async exception. #if defined(_WIN32)     if (req->file.pathw != NULL)-        uv__free(req->file.pathw);  +        uv__free(req->file.pathw); #else     if (req->path != NULL)         uv__free((void*) req->path);@@ -468,7 +495,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     loop_data->buffer_table[slot] = (char*)dents;@@ -482,7 +509,7 @@ void hs_uv_fs_stat_callback(uv_fs_t* req){     uv_loop_t* loop = req->loop;     hs_loop_data* loop_data = loop->data;-    HsInt slot = (HsInt)req->data; +    HsInt slot = (HsInt)req->data;     uv_stat_t* stat = (uv_stat_t*)loop_data->buffer_table[slot];     if (stat != NULL) {         // push the slot to event queue@@ -499,7 +526,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     loop_data->buffer_table[slot] = (char*)stat;@@ -514,7 +541,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     loop_data->buffer_table[slot] = (char*)stat;@@ -529,7 +556,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     loop_data->buffer_table[slot] = (char*)stat;@@ -544,7 +571,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_rename(loop, req, path, path2, hs_uv_fs_callback);@@ -558,7 +585,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_fsync(loop, req, file, hs_uv_fs_callback);@@ -572,7 +599,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_fdatasync(loop, req, file, hs_uv_fs_callback);@@ -586,7 +613,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_ftruncate(loop, req, file, off, hs_uv_fs_callback);@@ -600,7 +627,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_copyfile(loop, req, path, path2, flag, hs_uv_fs_callback);@@ -614,7 +641,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_access(loop, req, path, mode, hs_uv_fs_callback);@@ -628,7 +655,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_chmod(loop, req, path, mode, hs_uv_fs_callback);@@ -642,7 +669,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_fchmod(loop, req, file, mode, hs_uv_fs_callback);@@ -656,7 +683,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_utime(loop, req, path, atime, mtime, hs_uv_fs_callback);@@ -670,7 +697,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_futime(loop, req, file, atime, mtime, hs_uv_fs_callback);@@ -684,7 +711,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_lutime(loop, req, path, atime, mtime, hs_uv_fs_callback);@@ -698,7 +725,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_link(loop, req, path, path2, hs_uv_fs_callback);@@ -712,7 +739,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_symlink(loop, req, path, path2, flag, hs_uv_fs_callback);@@ -725,7 +752,7 @@ void hs_uv_fs_readlink_callback(uv_fs_t* req){     uv_loop_t* loop = req->loop;     hs_loop_data* loop_data = loop->data;-    HsInt slot = (HsInt)req->data; +    HsInt slot = (HsInt)req->data;     char** path = (char**)loop_data->buffer_table[slot];     if (path != NULL) {         *path = req->ptr;  // save the result path@@ -737,7 +764,7 @@     //  for the same reason with 'scandir', we can't cleanup request here #if defined(_WIN32)     if (req->file.pathw != NULL)-        uv__free(req->file.pathw);  +        uv__free(req->file.pathw); #else     if (req->path != NULL)         uv__free((void*) req->path);@@ -753,7 +780,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     loop_data->buffer_table[slot] = (char*)result_path;@@ -769,7 +796,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     loop_data->buffer_table[slot] = (char*)result_path;@@ -784,7 +811,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_chown(loop, req, path, uid, gid, hs_uv_fs_callback);@@ -798,7 +825,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_fchown(loop, req, file, uid, gid, hs_uv_fs_callback);@@ -812,7 +839,7 @@     hs_loop_data* loop_data = loop->data;     HsInt slot = alloc_slot(loop_data);     if (slot < 0) return UV_ENOMEM;-    uv_fs_t* req = +    uv_fs_t* req =         (uv_fs_t*)fetch_uv_struct(loop_data, slot);     req->data = (void*)slot;     int r = uv_fs_lchown(loop, req, path, uid, gid, hs_uv_fs_callback);@@ -830,7 +857,7 @@ #endif     if (r < 0) {         return uv_translate_sys_error(errno);-    } else { +    } else {         return r;     } }
include/hs_uv.h view
@@ -37,7 +37,7 @@  #if !defined(_WIN32) -#include <unistd.h> +#include <unistd.h>  #if defined(__sun) # include <sys/port.h>@@ -190,7 +190,7 @@ // // But in practice, we never directly return a free slot back to slot_table, because // the haskell thread allocating slot may be paused by RTS before its takeMVar parking its-// TSO since parking itself need an allocation. Now if uv_run fired its callback and +// TSO since parking itself need an allocation. Now if uv_run fired its callback and // free the slot, next registration will got the same slot, and mess up with previous // haskell thread. In order to solve this race condition, we free a slot in two steps: //@@ -302,7 +302,7 @@ int hs_uv_udp_check_start(uv_check_t* check);  ////////////////////////////////////////////////////////////////////////////////-// fs+// filesystem  // we define file open flag here for compatibility on libuv < v1.16 // see https://github.com/libuv/libuv/commit/4b666bd2d82a51f1c809b2703a91679789c1ec01#diff-a5e63f9b16ca783355e2d83941c3eafb@@ -586,7 +586,7 @@ void hs_uv_fs_readlink_cleanup(char* path);  ////////////////////////////////////////////////////////////////////////////////-// fs, none thread pool version+// filesystem, none thread pool version int64_t hs_seek(int file, int64_t off, int origin);  int32_t hs_uv_fs_open(const char* path, int flags, int mode);@@ -596,6 +596,7 @@ HsInt hs_uv_fs_unlink(const char* path); HsInt hs_uv_fs_mkdir(const char* path, int mode); HsInt hs_uv_fs_mkdtemp(const char* tpl, HsInt tpl_size, char* temp_path);+HsInt hs_uv_fs_mkstemp(const char* tpl, HsInt tpl_size, char* temp_path); HsInt hs_uv_fs_rmdir(const char* path); HsInt hs_uv_fs_scandir(const char* path, uv_dirent_t*** dents); HsInt hs_uv_fs_stat(const char* path, uv_stat_t* stat);@@ -629,6 +630,7 @@ HsInt hs_uv_fs_unlink_threaded(const char* path, uv_loop_t* loop); HsInt hs_uv_fs_mkdir_threaded(const char* path, int mode, uv_loop_t* loop); HsInt hs_uv_fs_mkdtemp_threaded(const char* tpl, HsInt tpl_size, char* temp_path, uv_loop_t* loop);+HsInt hs_uv_fs_mkstemp_threaded(const char* tpl, HsInt tpl_size, char* temp_path, uv_loop_t* loop); HsInt hs_uv_fs_rmdir_threaded(const char* path, uv_loop_t* loop); HsInt hs_uv_fs_scandir_threaded(const char* path, uv_dirent_t*** dents, uv_loop_t* loop); HsInt hs_uv_fs_stat_threaded(const char* path, uv_stat_t* stat, uv_loop_t* loop);
test/Z/IO/FileSystem/ThreadedSpec.hs view
@@ -35,7 +35,7 @@           let flags = O_RDWR .|. O_CREAT-            mode = DEFAULT_MODE+            mode = DEFAULT_FILE_MODE             filename = "test-file"          it "Opens and writes a file" $ do@@ -49,7 +49,7 @@                 written <- readExactly size i                 written @?= content -                fr <- newFilePtrT file 0+                fr <- newFilePtr file 0                 i <- newBufferedInput' 4096 fr                 written <- readExactly size i                 written @=? content@@ -72,7 +72,7 @@                 Just firstLine <- readLine i                 firstLine  @=? fst (V.break (== c2w '\n') content2) -                fr <- newFilePtrT file (fromIntegral $ size2 `div` 2)+                fr <- newFilePtr file (fromIntegral $ size2 `div` 2)                 i <- newBufferedInput' 4096 fr                 replicateM_ 512 $ do                     Just firstLine <- readLine i
test/Z/IO/FileSystemSpec.hs view
@@ -36,7 +36,7 @@           let flags = O_RDWR .|. O_CREAT-            mode = DEFAULT_MODE+            mode = DEFAULT_FILE_MODE             filename = "test-file"          it "Opens and writes a file" $ do
test/Z/IO/ProcessSpec.hs view
@@ -53,13 +53,13 @@         tempdir <- mkdtemp "stdio-filesystem-unit"         let ifilename = tempdir <> "/test-stdin"             ofilename = tempdir <> "/test-stdout"-        withResource (initFile ifilename (O_RDWR .|. O_CREAT) DEFAULT_MODE) $ \ input -> do+        withResource (initFile ifilename (O_RDWR .|. O_CREAT) DEFAULT_FILE_MODE) $ \ input -> do             bi <- newBufferedOutput' 4096 input             writeBuffer bi "hello world" >> flushBuffer bi -        ecode <- withResource (initFile ifilename O_RDWR DEFAULT_MODE) $ \ input -> do+        ecode <- withResource (initFile ifilename O_RDWR DEFAULT_FILE_MODE) $ \ input -> do -            withResource (initFile ofilename (O_RDWR .|. O_CREAT) DEFAULT_MODE) $ \ output -> do+            withResource (initFile ofilename (O_RDWR .|. O_CREAT) DEFAULT_FILE_MODE) $ \ output -> do                  iF <- getFileFD input                 oF <- getFileFD output@@ -71,7 +71,7 @@                          waitProcessExit pstate -        withResource (initFile ofilename (O_RDWR .|. O_CREAT) DEFAULT_MODE) $ \ output -> do+        withResource (initFile ofilename (O_RDWR .|. O_CREAT) DEFAULT_FILE_MODE) $ \ output -> do             bo <- newBufferedInput' 4096 output             o <- readBuffer bo             assertEqual "cat echo back" "hello world" o