Skip to content

Commit bed491b

Browse files
committed
Writing entries: go from PosixString to ByteString directly, not through String and BS.pack
1 parent 041488f commit bed491b

File tree

4 files changed

+47
-32
lines changed

4 files changed

+47
-32
lines changed

Codec/Archive/Tar/PackAscii.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ module Codec.Archive.Tar.PackAscii
66
, fromPosixString
77
, posixToByteString
88
, byteToPosixString
9+
, packAscii
910
) where
1011

1112
import Data.ByteString (ByteString)
13+
import qualified Data.ByteString.Char8 as BS.Char8
1214
import qualified Data.ByteString.Short as Sh
15+
import Data.Char
16+
import GHC.Stack
1317
import System.IO.Unsafe (unsafePerformIO)
1418
import "os-string" System.OsString.Posix (PosixString)
1519
import qualified "os-string" System.OsString.Posix as PS
@@ -26,3 +30,8 @@ posixToByteString = Sh.fromShort . PS.getPosixString
2630

2731
byteToPosixString :: ByteString -> PosixString
2832
byteToPosixString = PS.PosixString . Sh.toShort
33+
34+
packAscii :: HasCallStack => FilePath -> BS.Char8.ByteString
35+
packAscii xs
36+
| all isAscii xs = BS.Char8.pack xs
37+
| otherwise = error $ "packAscii: only ASCII inputs are supported, but got " ++ xs

Codec/Archive/Tar/Types.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,11 @@ type EntryContent = GenEntryContent LinkTarget
187187
-- | Ownership information for 'GenEntry'.
188188
data Ownership = Ownership {
189189
-- | The owner user name. Should be set to @\"\"@ if unknown.
190+
-- Must not contain non-ASCII characters.
190191
ownerName :: String,
191192

192193
-- | The owner group name. Should be set to @\"\"@ if unknown.
194+
-- Must not contain non-ASCII characters.
193195
groupName :: String,
194196

195197
-- | Numeric owner user id. Should be set to @0@ if unknown.

Codec/Archive/Tar/Write.hs

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,15 @@ putEntry entry = case entryContent entry of
6161

6262
putHeader :: Entry -> LBS.ByteString
6363
putHeader entry =
64-
LBS.Char8.pack
65-
$ take 148 block
66-
++ putOct 7 checksum
67-
++ ' ' : drop 156 block
64+
LBS.fromStrict
65+
$ BS.take 148 block
66+
<> putOct 7 checksum
67+
<> BS.Char8.cons ' ' (BS.drop 156 block)
6868
where
6969
block = putHeaderNoChkSum entry
70-
checksum = foldl' (\x y -> x + ord y) 0 block
70+
checksum = BS.Char8.foldl' (\x y -> x + ord y) 0 block
7171

72-
putHeaderNoChkSum :: Entry -> String
72+
putHeaderNoChkSum :: Entry -> BS.ByteString
7373
putHeaderNoChkSum Entry {
7474
entryTarPath = TarPath name prefix,
7575
entryContent = content,
@@ -79,40 +79,40 @@ putHeaderNoChkSum Entry {
7979
entryFormat = format
8080
} =
8181

82-
concat
82+
BS.concat
8383
[ putPosixString 100 name
8484
, putOct 8 permissions
8585
, putOct 8 $ ownerId ownership
8686
, putOct 8 $ groupId ownership
8787
, numField 12 contentSize
8888
, putOct 12 modTime
89-
, replicate 8 ' ' -- dummy checksum
89+
, BS.Char8.replicate 8 ' ' -- dummy checksum
9090
, putChar8 typeCode
9191
, putPosixString 100 linkTarget
92-
] ++
92+
] <>
9393
case format of
9494
V7Format ->
95-
replicate 255 '\NUL'
96-
UstarFormat -> concat
95+
BS.Char8.replicate 255 '\NUL'
96+
UstarFormat -> BS.Char8.concat
9797
[ putBString 8 ustarMagic
9898
, putString 32 $ ownerName ownership
9999
, putString 32 $ groupName ownership
100100
, putOct 8 deviceMajor
101101
, putOct 8 deviceMinor
102102
, putPosixString 155 prefix
103-
, replicate 12 '\NUL'
103+
, BS.Char8.replicate 12 '\NUL'
104104
]
105-
GnuFormat -> concat
105+
GnuFormat -> BS.Char8.concat
106106
[ putBString 8 gnuMagic
107107
, putString 32 $ ownerName ownership
108108
, putString 32 $ groupName ownership
109109
, putGnuDev 8 deviceMajor
110110
, putGnuDev 8 deviceMinor
111111
, putPosixString 155 prefix
112-
, replicate 12 '\NUL'
112+
, BS.Char8.replicate 12 '\NUL'
113113
]
114114
where
115-
numField :: FieldWidth -> Int64 -> String
115+
numField :: FieldWidth -> Int64 -> BS.Char8.ByteString
116116
numField w n
117117
| n >= 0 && n < 1 `shiftL` (3 * (w - 1))
118118
= putOct w n
@@ -133,7 +133,7 @@ putHeaderNoChkSum Entry {
133133
putGnuDev w n = case content of
134134
CharacterDevice _ _ -> putOct w n
135135
BlockDevice _ _ -> putOct w n
136-
_ -> replicate w '\NUL'
136+
_ -> BS.Char8.replicate w '\NUL'
137137

138138
ustarMagic, gnuMagic :: BS.ByteString
139139
ustarMagic = BS.Char8.pack "ustar\NUL00"
@@ -143,27 +143,27 @@ gnuMagic = BS.Char8.pack "ustar \NUL"
143143

144144
type FieldWidth = Int
145145

146-
putBString :: FieldWidth -> BS.ByteString -> String
147-
putBString n s = BS.Char8.unpack (BS.take n s) ++ replicate (n - BS.length s) '\NUL'
146+
putBString :: FieldWidth -> BS.ByteString -> BS.ByteString
147+
putBString n s = BS.take n s <> BS.Char8.replicate (n - BS.length s) '\NUL'
148148

149-
putPosixString :: FieldWidth -> PosixString -> String
150-
putPosixString n s = fromPosixString (PS.take n s) ++ replicate (n - PS.length s) '\NUL'
149+
putPosixString :: FieldWidth -> PosixString -> BS.ByteString
150+
putPosixString n s = posixToByteString (PS.take n s) <> BS.Char8.replicate (n - PS.length s) '\NUL'
151151

152-
putString :: FieldWidth -> String -> String
153-
putString n s = take n s ++ replicate (n - length s) '\NUL'
152+
putString :: FieldWidth -> String -> BS.ByteString
153+
putString n s = BS.take n (packAscii s) <> BS.Char8.replicate (n - length s) '\NUL'
154154

155-
{-# SPECIALISE putLarge :: FieldWidth -> Int64 -> String #-}
156-
putLarge :: (Bits a, Integral a) => FieldWidth -> a -> String
157-
putLarge n0 x0 = '\x80' : reverse (go (n0-1) x0)
155+
{-# SPECIALISE putLarge :: FieldWidth -> Int64 -> BS.ByteString #-}
156+
putLarge :: (Bits a, Integral a) => FieldWidth -> a -> BS.ByteString
157+
putLarge n0 x0 = BS.Char8.pack $ '\x80' : reverse (go (n0-1) x0)
158158
where go 0 _ = []
159159
go n x = chr (fromIntegral (x .&. 0xff)) : go (n-1) (x `shiftR` 8)
160160

161-
putOct :: (Integral a, Show a) => FieldWidth -> a -> String
161+
putOct :: (Integral a, Show a) => FieldWidth -> a -> BS.ByteString
162162
putOct n x =
163-
let octStr = take (n-1) $ showOct x ""
164-
in replicate (n - length octStr - 1) '0'
165-
++ octStr
166-
++ putChar8 '\NUL'
163+
let octStr = BS.take (n-1) $ BS.Char8.pack $ showOct x ""
164+
in BS.Char8.replicate (n - BS.length octStr - 1) '0'
165+
<> octStr
166+
<> putChar8 '\NUL'
167167

168-
putChar8 :: Char -> String
169-
putChar8 c = [c]
168+
putChar8 :: Char -> BS.ByteString
169+
putChar8 = BS.Char8.singleton

changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.6.2.0 Bodigrim <[email protected]> March 2024
2+
3+
* Fix issues with Unicode support in filenames.
4+
15
## 0.6.1.0 Bodigrim <[email protected]> January 2024
26

37
* Support Unicode in filenames (encoded as UTF-8).

0 commit comments

Comments
 (0)