Skip to content
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

How to preserve file permissions using packDirRecur #66

Closed
saurabhnanda opened this issue Mar 19, 2020 · 3 comments · Fixed by #68
Closed

How to preserve file permissions using packDirRecur #66

saurabhnanda opened this issue Mar 19, 2020 · 3 comments · Fixed by #68

Comments

@saurabhnanda
Copy link

saurabhnanda commented Mar 19, 2020

The following is not working as I am expecting it to. Am I doing anything wrong?

prepareZipFile :: FilePath -> IO FilePath
prepareZipFile dir = do
  Zip.createArchive zipFileName $ Zip.packDirRecur Zip.Deflate createSelector dir
  pure zipFileName
  where
    zipFileName = "/tmp/upload.zip"

    createSelector fpath = do
      s <- Zip.mkEntrySelector fpath
      Zip.setExternalFileAttrs ((0x100000 .|. 0o0755) `shiftL` 16) s
      -- fmode <- liftIO $ (fmap Unix.fileMode $ Unix.getFileStatus $ dir <> "/" <> fpath)
      -- Zip.setExternalFileAttrs (traceShowId $ fromIntegral $ (toInteger fmode) `shiftL` 16) s
      pure s
@saurabhnanda
Copy link
Author

saurabhnanda commented Mar 19, 2020

This is something that works, but IMO is too clunky. Why is packRecurDir not respecting all external file attributes?

prepareZipFile :: FilePath -> IO FilePath
prepareZipFile dir = do
  Zip.createArchive zipFileName $ do
    Zip.packDirRecur Zip.Deflate createSelector dir
    Zip.commit
    x <- toList <$> Zip.getEntries
    forM x $ \(es, _) -> Zip.setExternalFileAttrs ((0x100000 .|. 0o0755) `shiftL` 16) es
  pure zipFileName
  where
    zipFileName = "/tmp/upload.zip"

    createSelector fpath = do
      s <- Zip.mkEntrySelector fpath
      -- Zip.setExternalFileAttrs ((0x100000 .|. 0o0755) `shiftL` 16) s
      -- fmode <- liftIO $ (fmap Unix.fileMode $ Unix.getFileStatus $ dir <> "/" <> fpath)
      -- Zip.setExternalFileAttrs (traceShowId $ fromIntegral $ (toInteger fmode) `shiftL` 16) s
      pure s

@mrkkrp
Copy link
Owner

mrkkrp commented Mar 21, 2020

The callback createSelector is called before the entries are created. Event though we do not execute the actions immediately, the code tries to follow "common sense", so if you try to edit something (in your case, by setting external attributes) that doesn't yet exist, nothing happens.

Here is the code that clears editing actions when an entry is created:

SinkEntry m src s ->
( pa { paSinkEntry = M.insert s src (paSinkEntry pa)
, paCopyEntry = M.map (M.filter (/= s)) (paCopyEntry pa) }
, (clearEditingFor s ea)
{ eaCompression = M.insert s m (eaCompression ea) } )

Your approach from the second snippet looks good. I'd recommend to use forEntries to traverse all entries:

prepareZipFile :: FilePath -> IO FilePath
prepareZipFile dir = do
  Zip.createArchive zipFileName $ do
    Zip.packDirRecur Zip.Deflate Zip.mkEntrySelector dir
    Zip.commit
    forEntries $ Zip.setExternalFileAttrs ((0x100000 .|. 0o0755) `shiftL` 16)
  pure zipFileName
  where
    zipFileName = "/tmp/upload.zip"

BTW, why do you do ((0x100000 .|. 0o0755) shiftL 16) instead of using toFileMode from Codec.Archive.Zip.Unix? I'd guess that it does exactly what you need.

@mrkkrp
Copy link
Owner

mrkkrp commented Mar 21, 2020

The only problem with that approach is that the archive will be written two times. We could add an extra call back to the packDirRecur to make it possible to perform editing actions on not-yet-created entries. Tell me if you're interested in that feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants