-
Notifications
You must be signed in to change notification settings - Fork 98
Fix issue 60: confusing error messages in rename/createLink/createSymbolicLink #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
484566b
652608e
1a120a0
bb7bb1c
d92e482
3dae5ac
a37b638
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -102,8 +102,19 @@ import System.Posix.Files.Common | |
| import System.Posix.Error | ||
| import System.Posix.Internals | ||
|
|
||
| #if !MIN_VERSION_base(4, 11, 0) | ||
| import Data.Monoid ((<>)) | ||
| #endif | ||
|
|
||
| import Data.Time.Clock.POSIX (POSIXTime) | ||
|
|
||
| -- throwErrnoTwoPathsIfMinus1_ | ||
| -- | ||
| -- | For operations that require two paths (e.g., renaming a file) | ||
| throwErrnoTwoPathsIfMinus1_ :: (Eq a, Num a) => String -> FilePath -> FilePath -> IO a -> IO () | ||
| throwErrnoTwoPathsIfMinus1_ loc path1 path2 = | ||
| throwErrnoIfMinus1_ (loc <> " '" <> path1 <> "' to '" <> path2 <> "'") | ||
luispedro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| -- ----------------------------------------------------------------------------- | ||
| -- chmod() | ||
|
|
||
|
|
@@ -228,7 +239,7 @@ createLink :: FilePath -> FilePath -> IO () | |
| createLink name1 name2 = | ||
| withFilePath name1 $ \s1 -> | ||
| withFilePath name2 $ \s2 -> | ||
| throwErrnoPathIfMinus1_ "createLink" name1 (c_link s1 s2) | ||
| throwErrnoTwoPathsIfMinus1_ "createLink" name1 name2 (c_link s1 s2) | ||
|
|
||
| -- | @removeLink path@ removes the link named @path@. | ||
| -- | ||
|
|
@@ -241,18 +252,18 @@ removeLink name = | |
| -- ----------------------------------------------------------------------------- | ||
| -- Symbolic Links | ||
|
|
||
| -- | @createSymbolicLink file1 file2@ creates a symbolic link named @file2@ | ||
| -- which points to the file @file1@. | ||
| -- | @createSymbolicLink name1 name2@ creates a symbolic link named @name2@ | ||
| -- which points to the file @name1@. | ||
| -- | ||
| -- Symbolic links are interpreted at run-time as if the contents of the link | ||
| -- had been substituted into the path being followed to find a file or directory. | ||
| -- | ||
| -- Note: calls @symlink@. | ||
| createSymbolicLink :: FilePath -> FilePath -> IO () | ||
| createSymbolicLink file1 file2 = | ||
| withFilePath file1 $ \s1 -> | ||
| withFilePath file2 $ \s2 -> | ||
| throwErrnoPathIfMinus1_ "createSymbolicLink" file2 (c_symlink s1 s2) | ||
| createSymbolicLink name1 name2 = | ||
| withFilePath name1 $ \s1 -> | ||
| withFilePath name2 $ \s2 -> | ||
| throwErrnoTwoPathsIfMinus1_ "createSymbolicLink" name1 name2 (c_symlink s1 s2) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @luispedro The error message created by this is wrong, see new bug #353.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, this should be: throwErrnoPathIfMinus1_ ("createSymbolicLink to " <> name1) name2 (c_symlink s1 s2)Because we should make a reasonable effort to record the file location (source of the symlink) where the error occurred, that can be as or more useful than the descriptive string. Example results for comparison: λ> do { tryIOError (createSymbolicLink "/foo" "/bar") ; throwErrnoPathIfMinus1_ "createSymlink to /foo" "/bar" (pure (-1)) }
*** Exception: /bar: createSymlink to /foo: permission denied (Permission denied)
λ> do { tryIOError (createSymbolicLink "/foo" "/bar") ; throwErrnoIfMinus1_ "createSymlink /bar to /foo" (pure (-1)) }
*** Exception: createSymlink /bar to /foo: permission denied (Permission denied)This is different from the rename case where either of the paths could be the source of the problem, but one could make a case for the source path as a sensible default, and consider also recording that.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @vdukhovni I don't fully understand what you're saying: Isn't this simply slightly rewording the same sentence? (I have nothing against the wording, it's good as well, but "we should make a reasonable effort to record the file location (source of the symlink)" is true either way, isn't it?)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
My issue isn't with how the resulting error is rendered by its λ> :set -XLambdaCase
λ> import GHC.IO.Exception
λ> import Control.Exception
λ> import GHC.Internal.Foreign.C.Error
λ> import System.Posix.Files
λ> import System.IO.Error
λ> handler :: IOException -> Maybe IOException; handler = Just
λ> eperm :: IO (Either IOException ()); eperm = try $ createSymbolicLink "/foo" "/bar"
λ> raisePath = throwErrnoPathIfMinus1_ "createSymlink to /foo" "/bar" $ pure (-1)
λ>
λ> tryJust handler (createSymbolicLink "/foo" "/bar") >>= \ case { Left e -> pure $ ioe_filename e; Right _ -> pure (Just "no error") }
Nothing
λ> tryJust handler (eperm >> raisePath) >>= \ case { Left e -> pure $ ioe_filename e; Right _ -> pure (Just "no error") }
Just "/bar"The difference is in the By using λ> tryJust handler (eperm >> raisePath) >>= \ case { Left e -> pure . Just $ (,,,,,) <$> ioe_handle <*> ioe_type <*> ioe_location <*> ioe_description <*> ioe_errno <*> ioe_filename $ e; _ -> pure Nothing }
Just (Nothing,permission denied,"createSymlink to /foo","Permission denied",Just 13,Just "/bar")
λ>
λ> tryJust handler (createSymbolicLink "/foo" "/bar") >>= \ case { Left e -> pure . Just $ (,,,,,) <$> ioe_handle <*> ioe_type <*> ioe_location <*> ioe_description <*> ioe_errno <*> ioe_filename $ e; _ -> pure Nothing }
Just (Nothing,permission denied,"createSymbolicLink '/foo' to '/bar'","Permission denied",Just 13,Nothing)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @vdukhovni Thanks for the example! I agree, we definitely should populate |
||
|
|
||
| foreign import ccall unsafe "symlink" | ||
| c_symlink :: CString -> CString -> IO CInt | ||
|
|
@@ -290,7 +301,7 @@ rename :: FilePath -> FilePath -> IO () | |
| rename name1 name2 = | ||
| withFilePath name1 $ \s1 -> | ||
| withFilePath name2 $ \s2 -> | ||
| throwErrnoPathIfMinus1_ "rename" name1 (c_rename s1 s2) | ||
| throwErrnoTwoPathsIfMinus1_ "rename" name1 name2 (c_rename s1 s2) | ||
|
|
||
| foreign import ccall unsafe "rename" | ||
| c_rename :: CString -> CString -> IO CInt | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.