@@ -28,13 +28,23 @@ def __iter__(self):
2828
2929
3030@contextmanager
31- def new_archive_read (format_name = 'all' , filter_name = 'all' ):
31+ def new_archive_read (format_name = 'all' , filter_name = 'all' , passphrase = None ):
3232 """Creates an archive struct suitable for reading from an archive.
3333
3434 Returns a pointer if successful. Raises ArchiveError on error.
3535 """
3636 archive_p = ffi .read_new ()
3737 try :
38+ if passphrase :
39+ if not isinstance (passphrase , bytes ):
40+ passphrase = passphrase .encode ('utf-8' )
41+ try :
42+ ffi .read_add_passphrase (archive_p , passphrase )
43+ except AttributeError :
44+ raise NotImplementedError (
45+ f"the libarchive being used (version { ffi .version_number ()} , "
46+ f"path { ffi .libarchive_path } ) doesn't support encryption"
47+ )
3848 ffi .get_read_filter_function (filter_name )(archive_p )
3949 ffi .get_read_format_function (format_name )(archive_p )
4050 yield archive_p
@@ -46,23 +56,24 @@ def new_archive_read(format_name='all', filter_name='all'):
4656def custom_reader (
4757 read_func , format_name = 'all' , filter_name = 'all' ,
4858 open_func = VOID_CB , close_func = VOID_CB , block_size = page_size ,
49- archive_read_class = ArchiveRead
59+ archive_read_class = ArchiveRead , passphrase = None ,
5060):
5161 """Read an archive using a custom function.
5262 """
5363 open_cb = OPEN_CALLBACK (open_func )
5464 read_cb = READ_CALLBACK (read_func )
5565 close_cb = CLOSE_CALLBACK (close_func )
56- with new_archive_read (format_name , filter_name ) as archive_p :
66+ with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
5767 ffi .read_open (archive_p , None , open_cb , read_cb , close_cb )
5868 yield archive_read_class (archive_p )
5969
6070
6171@contextmanager
62- def fd_reader (fd , format_name = 'all' , filter_name = 'all' , block_size = 4096 ):
72+ def fd_reader (fd , format_name = 'all' , filter_name = 'all' , block_size = 4096 ,
73+ passphrase = None ):
6374 """Read an archive from a file descriptor.
6475 """
65- with new_archive_read (format_name , filter_name ) as archive_p :
76+ with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
6677 try :
6778 block_size = fstat (fd ).st_blksize
6879 except (OSError , AttributeError ): # pragma: no cover
@@ -72,10 +83,11 @@ def fd_reader(fd, format_name='all', filter_name='all', block_size=4096):
7283
7384
7485@contextmanager
75- def file_reader (path , format_name = 'all' , filter_name = 'all' , block_size = 4096 ):
86+ def file_reader (path , format_name = 'all' , filter_name = 'all' , block_size = 4096 ,
87+ passphrase = None ):
7688 """Read an archive from a file.
7789 """
78- with new_archive_read (format_name , filter_name ) as archive_p :
90+ with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
7991 try :
8092 block_size = stat (path ).st_blksize
8193 except (OSError , AttributeError ): # pragma: no cover
@@ -85,17 +97,17 @@ def file_reader(path, format_name='all', filter_name='all', block_size=4096):
8597
8698
8799@contextmanager
88- def memory_reader (buf , format_name = 'all' , filter_name = 'all' ):
100+ def memory_reader (buf , format_name = 'all' , filter_name = 'all' , passphrase = None ):
89101 """Read an archive from memory.
90102 """
91- with new_archive_read (format_name , filter_name ) as archive_p :
103+ with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
92104 ffi .read_open_memory (archive_p , cast (buf , c_void_p ), len (buf ))
93105 yield ArchiveRead (archive_p )
94106
95107
96108@contextmanager
97109def stream_reader (stream , format_name = 'all' , filter_name = 'all' ,
98- block_size = page_size ):
110+ block_size = page_size , passphrase = None ):
99111 """Read an archive from a stream.
100112
101113 The `stream` object must support the standard `readinto` method.
@@ -115,14 +127,14 @@ def read_func(archive_p, context, ptrptr):
115127 open_cb = OPEN_CALLBACK (VOID_CB )
116128 read_cb = READ_CALLBACK (read_func )
117129 close_cb = CLOSE_CALLBACK (VOID_CB )
118- with new_archive_read (format_name , filter_name ) as archive_p :
130+ with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
119131 ffi .read_open (archive_p , None , open_cb , read_cb , close_cb )
120132 yield ArchiveRead (archive_p )
121133
122134
123135@contextmanager
124136def seekable_stream_reader (stream , format_name = 'all' , filter_name = 'all' ,
125- block_size = page_size ):
137+ block_size = page_size , passphrase = None ):
126138 """Read an archive from a seekable stream.
127139
128140 The `stream` object must support the standard `readinto`, 'seek' and
@@ -149,7 +161,7 @@ def seek_func(archive_p, context, offset, whence):
149161 read_cb = READ_CALLBACK (read_func )
150162 seek_cb = SEEK_CALLBACK (seek_func )
151163 close_cb = CLOSE_CALLBACK (VOID_CB )
152- with new_archive_read (format_name , filter_name ) as archive_p :
164+ with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
153165 ffi .read_set_seek_callback (archive_p , seek_cb )
154166 ffi .read_open (archive_p , None , open_cb , read_cb , close_cb )
155167 yield ArchiveRead (archive_p )
0 commit comments