úÎï‘ê÷M      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKL)This function tells whether or not a file/directory is symbolic  link. 0This function returns the link counter of a file/ directory. FThis function returns whether or not a directory has sub-directories. The  operation returns the 5UTC time at which the file or directory was created. 'The time is only available on Windows. The  operation returns the 5UTC time at which the file or directory was changed. ,The time is only available on Unix and Mac. Note that Unix'%s rename() does not change ctime but MacOS's rename() does. The  operation returns the ;UTC time at which the file or directory was last modified. The operation may fail with:  isPermissionError( if the user is not permitted to access  the modification time; or  isDoesNotExistError* if the file or directory does not exist. The  operation returns the ;UTC time at which the file or directory was last accessed. MMM=If the operating system has a notion of current directories, ! returns an absolute path to the *current directory of the calling process. The operation may fail with:   HardwareFault  A physical I/O error has occurred. [EIO]  isDoesNotExistError /  NoSuchThing 5There is no path referring to the current directory. [EPERM, ENOENT, ESTALE...]  isPermissionError / PermissionDenied BThe process has insufficient privileges to perform the operation. [EACCES]  ResourceExhausted ?Insufficient resources are available to perform the operation.  UnsupportedOperation 9The operating system has no notion of current directory. Returns the current user's home directory. GThe directory returned is expected to be writable by the current user, but note that it isn'.t generally considered good practice to store $application-specific data here; use   instead.  On Unix,  returns the value of the HOME ?environment variable. On Windows, the system is queried for a 'suitable path; a typical path might be C:Documents And Settingsuser. The operation may fail with:  UnsupportedOperation 6The operating system has no notion of home directory.  isDoesNotExistError ;The home directory for the current user does not exist, or cannot be found. Returns the current user's home directory from the HOME environment variable. BReturns the pathname of a directory in which application-specific 8data for the current user can be stored. The result of ( for a given application is specific to the current user. GThe argument should be the name of the application, which will be used Bto construct the pathname (so avoid using unusual characters that &might result in an invalid pathname). GNote: the directory may not actually exist, and may need to be created ?first. It is expected that the parent directory exists and is  writable. On Unix, this function returns $HOME/.appName. On Windows, a typical path might be  9 C:/Documents And Settings/user/Application Data/appName The operation may fail with:  UnsupportedOperation KThe operating system has no notion of application-specific data directory.  isDoesNotExistError ;The home directory for the current user does not exist, or cannot be found. Returns the current user's document directory. GThe directory returned is expected to be writable by the current user, but note that it isn'.t generally considered good practice to store $application-specific data here; use   instead.  On Unix,   returns the value of the HOME ?environment variable. On Windows, the system is queried for a 'suitable path; a typical path might be C:/Documents and Settings/user/ My Documents. The operation may fail with:  UnsupportedOperation :The operating system has no notion of document directory.  isDoesNotExistError ?The document directory for the current user does not exist, or cannot be found. !3Returns the current directory for temporary files.  On Unix, ! returns the value of the TMPDIR environment variable or "/tmp" if the variable isn' t defined. NOn Windows, the function checks for the existence of environment variables in 3the following order and uses the first path found:  TMP environment variable.  TEMP environment variable. # USERPROFILE environment variable.  The Windows directory The operation may fail with:  UnsupportedOperation ;The operating system has no notion of temporary directory. The function doesn'"t verify whether the path exists. N"CThis function copy the permission of the first file to the second.   !N" !N"5O+Is the operating system Unix or Linux like P%Is the operating system Windows like #*The character that separates directories.  pathSeparator == '/'  isPathSeparator pathSeparator $%The list of all possible separators. ( Windows: pathSeparators == ['\\', '/'] " Posix: pathSeparators == ['/'] % pathSeparator `elem` pathSeparators %Rather than using (== #), use this. Test if something  is a path separator. 0 isPathSeparator a == (a `elem` pathSeparators) &File extension character  extSeparator == '.' ')Is the character an extension character? ) isExtSeparator a == (a == extSeparator) (Split on the extension. - is the inverse. & uncurry (++) (splitExtension x) == x . uncurry addExtension (splitExtension x) == x . splitExtension "file.txt" == ("file",".txt") & splitExtension "file" == ("file","") 8 splitExtension "file/file.txt" == ("file/file",".txt") : splitExtension "file.txt/boris" == ("file.txt/boris","") B splitExtension "file.txt/boris.ext" == ("file.txt/boris",".ext") J splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob",".fred") : splitExtension "file/path.txt/" == ("file/path.txt/","") )%Get the extension of a file, returns "" for no extension, .ext otherwise. + takeExtension x == snd (splitExtension x) ; Valid x => takeExtension (addExtension x "ext") == ".ext" ? Valid x => takeExtension (replaceExtension x "ext") == ".ext" *ASet the extension of a file, overwriting one if already present. 2 replaceExtension "file.txt" ".bob" == "file.bob" 1 replaceExtension "file.txt" "bob" == "file.bob" . replaceExtension "file" ".bob" == "file.bob" * replaceExtension "file.txt" "" == "file" ; replaceExtension "file.fred.bob" "txt" == "file.fred.txt" + Alias to -*, for people who like that sort of thing. ,Remove last extension, and the "." preceding it. + dropExtension x == fst (splitExtension x) -6Add an extension, even if there is already one there.  E.g.  addExtension "foo.txt" "bat" -> " foo.txt.bat". 1 addExtension "file.txt" "bib" == "file.txt.bib" , addExtension "file." ".bib" == "file..bib" * addExtension "file" ".bib" == "file.bib"  addExtension "/" "x" == "/.x" U Valid x => takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext" ? Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt" .+Does the given filename have an extension? 0 null (takeExtension x) == not (hasExtension x) /Split on all extensions 5 splitExtensions "file.tar.gz" == ("file",".tar.gz") 0Drop all extensions ' not $ hasExtension (dropExtensions x) 1Get all extensions + takeExtensions "file.tar.gz" == ".tar.gz" Q-Is the given character a valid drive letter? B only a-z and A-Z are letters, not isAlpha which is more unicodey 2&Split a path into a drive and a path.  On Unix, / is a Drive. " uncurry (++) (splitDrive x) == x + Windows: splitDrive "file" == ("","file") 1 Windows: splitDrive "c:/file" == ("c:/","file") C Windows: splitDrive "\\\\shared\\test" == ("\\\\shared\\","test") 7 Windows: splitDrive "\\\\shared" == ("\\\\shared","") S Windows: splitDrive "\\\\?\\UNC\\shared\\file" == ("\\\\?\\UNC\\shared\\","file") O Windows: splitDrive "\\\\?\\UNCshared\\file" == ("\\\\?\\","UNCshared\\file") A Windows: splitDrive "\\\\?\\d:\\file" == ("\\\\?\\d:\\","file") . Windows: splitDrive "/d" == ("","/d") -- xxx 4 Posix: splitDrive "/test" == ("/","test") -- xxx / Posix: splitDrive "//test" == ("//","test") 5 Posix: splitDrive "test/file" == ("","test/file") + Posix: splitDrive "file" == ("","file") RSTUV3'Join a drive and the rest of the path. 0 uncurry joinDrive (splitDrive x) == x * Windows: joinDrive "C:" "foo" == "C:foo" , Windows: joinDrive "C:/" "bar" == "C:/bar" @ Windows: joinDrive "\\\\share" "foo" == "\\\\share/foo" -- xxx 2 Windows: joinDrive "/:" "foo" == "/:/foo" -- xxx 4Get the drive from a filepath. # takeDrive x == fst (splitDrive x) 5 Delete the drive, if it exists. # dropDrive x == snd (splitDrive x) 6Does a path have a drive. ( not (hasDrive x) == null (takeDrive x) 7Is an element a drive 8*Split a filename into directory and file. C is the inverse. % uncurry (++) (splitFileName x) == x 3 Valid x => uncurry combine (splitFileName x) == x 6 splitFileName "file/bob.txt" == ("file/", "bob.txt") ( splitFileName "file/" == ("file/", "") $ splitFileName "bob" == ("", "bob") ( Posix: splitFileName "/" == ("/","") * Windows: splitFileName "c:" == ("c:","") 9Set the filename. 4 Valid x => replaceFileName x (takeFileName x) == x :Drop the filename. ) dropFileName x == fst (splitFileName x) ;Get the file name.  takeFileName "test/" == ""  takeFileName x `isSuffixOf` x ) takeFileName x == snd (splitFileName x) > Valid x => takeFileName (replaceFileName x "fred") == "fred" 2 Valid x => takeFileName (x </> "fred") == "fred" ( Valid x => isRelative (takeFileName x) <1Get the base name, without an extension or path. ( takeBaseName "file/test.txt" == "test" # takeBaseName "dave.ext" == "dave"  takeBaseName "" == ""  takeBaseName "test" == "test" 1 takeBaseName (addTrailingPathSeparator x) == "" / takeBaseName "file/file.tar.gz" == "file.tar" =Set the base name. 9 replaceBaseName "file/test.txt" "bob" == "file/bob.txt" ) replaceBaseName "fred" "bill" == "bill" G replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar" ) replaceBaseName x (takeBaseName x) == x >FIs an item either a directory or the last character a path separator? * hasTrailingPathSeparator "test" == False * hasTrailingPathSeparator "test/" == True ?BAdd a trailing file path separator if one is not already present. 7 hasTrailingPathSeparator (addTrailingPathSeparator x) @ hasTrailingPathSeparator x ==> addTrailingPathSeparator x == x 6 addTrailingPathSeparator "test/rest" == "test/rest/" @$Remove any trailing path separators 7 dropTrailingPathSeparator "file/test/" == "file/test" K not (hasTrailingPathSeparator (dropTrailingPathSeparator x)) || isDrive x & dropTrailingPathSeparator "/" == "/" A+Get the directory name, move up one level. * takeDirectory x `isPrefixOf` x % takeDirectory "foo" == "" 6 takeDirectory "/foo/bar/baz" == "/foo/bar" ; takeDirectory "/foo/bar/baz/" == "/foo/bar/baz" 4 takeDirectory "foo/bar/baz" == "foo/bar" = Windows: takeDirectory "foo\\bar\\\\" == "foo\\bar" -- xxx ( Windows: takeDirectory "C:/" == "C:/" B2Set the directory, keeping the filename the same. 8 replaceDirectory x (takeDirectory x) `equalFilePath` x C&Combine two paths, if the second path L, then it returns the second. I Valid x => combine (takeDirectory x) (takeFileName x) `equalFilePath` x  combine "/" "test" == "/test" $ combine "home" "bob" == "home/bob" W1Combine two paths, assuming rhs is NOT absolute. DA nice alias for C. E)Split a path by the directory separator.  concat (splitPath x) == x / splitPath "test//item/" == ["test//","item/"] 8 splitPath "test/item/file" == ["test/","item/","file"]  splitPath "" == [] = Windows: splitPath "c:/test/path" == ["c:/","test/","path"] 9 Posix: splitPath "/file/test" == ["/","file/","test"] FJust as E , but don',t add the trailing slashes to each element. 1 splitDirectories "test/file" == ["test","file"] 6 splitDirectories "/test/file" == ["/","test","file"] < Valid x => joinPath (splitDirectories x) `equalFilePath` x  splitDirectories "" == [] G"Join path elements back together. ( Valid x => joinPath (splitPath x) == x  joinPath [] == "" < Posix: joinPath ["test","file","path"] == "test/file/path" HEquality of two s.  If you call !System.Directory.canonicalizePath 3 first this has a much better chance of working.  Note that this doesn' t follow symlinks or DOSNAM~1s. ' x == y ==> equalFilePath x y ; normalise x == normalise y ==> equalFilePath x y % Posix: equalFilePath "foo" "foo/" + Posix: not (equalFilePath "foo" "/foo") * Posix: not (equalFilePath "foo" "FOO") $ Windows: equalFilePath "foo" "FOO" I/Contract a filename, based on a relative path. There is no corresponding  makeAbsolute function, instead use  !System.Directory.canonicalizePath which has the same effect. ~ Valid y => equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x " makeRelative x x == "." X null y || equalFilePath (makeRelative x (x </> y)) y || null (takeFileName x) 8 Windows: makeRelative "C:/Home" "c:/home/bob" == "bob" @ Windows: makeRelative "C:/Home" "D:/Home/Bob" == "D:/Home/Bob" > Windows: makeRelative "C:/Home" "C:Home/Bob" == "C:Home/Bob" 4 Windows: makeRelative "/Home" "/home/bob" == "bob" : Posix: makeRelative "/Home" "/home/bob" == "/home/bob" E Posix: makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar" . Posix: makeRelative "/fred" "bob" == "bob" @ Posix: makeRelative "/file/test" "/file/test/fred" == "fred" B Posix: makeRelative "/file/test" "/file/test/fred/" == "fred/" @ Posix: makeRelative "some/path" "some/path/a/b/c" == "a/b/c" JNormalise a file  //( outside of the drive can be made blank  / -> #  ./ -> "" : Posix: normalise "/file/\\test////" == "/file/\\test/" 3 Posix: normalise "/file/./test" == "/file/test" K Posix: normalise "/test/file/../bob/fred/" == "/test/file/../bob/fred/" 5 Posix: normalise "../bob/fred/" == "../bob/fred/" 1 Posix: normalise "./bob/fred/" == "bob/fred/" 7 Windows: normalise "c:\\file/bob\\" == "C:/file/bob/" # Windows: normalise "c:/" == "C:/" D Windows: normalise "\\\\server\\test" == "\\\\server\\test" -- xxx  Windows: normalise "." == "." ! Posix: normalise "./" == "./" XK0Is a path relative, or is it fixed to the root? * Windows: isRelative "path\\test" == True ) Windows: isRelative "c:\\test" == False & Windows: isRelative "c:test" == True " Windows: isRelative "c:" == True ( Windows: isRelative "\\\\foo" == False $ Windows: isRelative "/foo" == True ) Posix: isRelative "test/path" == True & Posix: isRelative "/test" == False YL not . K $ isAbsolute x == not (isRelative x) +#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKL*#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLM  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLM  ! "#$%&'()*,-.+/012346578;9:<=ABCDEGF>?@JHIKLZ                     !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abceasy-file-0.1.0System.EasyFileSystem.EasyFile.MissingSystem.EasyFile.DirectorySystem.EasyFile.FilePathbaseGHC.IOFilePathdirectory-1.1.0.0System.Directory doesFileExistdoesDirectoryExistsetCurrentDirectorygetDirectoryContentscanonicalizePathcopyFile renameFilerenameDirectory removeFileremoveDirectoryRecursiveremoveDirectorycreateDirectoryIfMissingcreateDirectorysetPermissionsgetPermissions searchable executablewritablereadable Permissions isSymlink getLinkCounthasSubDirectoriesgetCreationTime getChangeTimegetModificationTime getAccessTimegetCurrentDirectorygetHomeDirectorygetHomeDirectory2getAppUserDataDirectorygetUserDocumentsDirectorygetTemporaryDirectorycopyPermissions pathSeparatorpathSeparatorsisPathSeparator extSeparatorisExtSeparatorsplitExtension takeExtensionreplaceExtension<.> dropExtension addExtension hasExtensionsplitExtensionsdropExtensionstakeExtensions splitDrive joinDrive takeDrive dropDrivehasDriveisDrive splitFileNamereplaceFileName dropFileName takeFileName takeBaseNamereplaceBaseNamehasTrailingPathSeparatoraddTrailingPathSeparatordropTrailingPathSeparator takeDirectoryreplaceDirectorycombine splitPathsplitDirectoriesjoinPath equalFilePath makeRelative normalise isRelative isAbsoluteepochTimeToUTCTimefixPathisPosix isWindowsisLetteraddSlash readDriveUNCreadDriveLetterreadDriveSharereadDriveShareName combineAlwaysnormaliseDriveisRelativeDrive