Update the write API
This change adds a FileOptions struct. This struct can be filled using a builder pattern to set the options for a file or folder. With this change, we also introduce the option to set the (unix) permissions of a file or folder.
This commit is contained in:
parent
82315c9511
commit
d2d19f6539
3 changed files with 91 additions and 15 deletions
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
|
|
||||||
name = "zip"
|
name = "zip"
|
||||||
version = "0.1.19"
|
version = "0.2.0"
|
||||||
authors = ["Mathijs van de Nes <git@mathijs.vd-nes.nl>"]
|
authors = ["Mathijs van de Nes <git@mathijs.vd-nes.nl>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/mvdnes/zip-rs.git"
|
repository = "https://github.com/mvdnes/zip-rs.git"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use zip::write::FileOptions;
|
||||||
|
|
||||||
extern crate zip;
|
extern crate zip;
|
||||||
|
|
||||||
|
@ -32,12 +33,13 @@ fn doit(filename: &str) -> zip::result::ZipResult<()>
|
||||||
|
|
||||||
let mut zip = zip::ZipWriter::new(file);
|
let mut zip = zip::ZipWriter::new(file);
|
||||||
|
|
||||||
try!(zip.start_file("test/", zip::CompressionMethod::Stored));
|
try!(zip.add_directory("test/", FileOptions::default()));
|
||||||
|
|
||||||
try!(zip.start_file("test/☃.txt", zip::CompressionMethod::Stored));
|
let options = FileOptions::default().compression_method(zip::CompressionMethod::Stored).unix_permissions(0o755);
|
||||||
|
try!(zip.start_file("test/☃.txt", options));
|
||||||
try!(zip.write_all(b"Hello, World!\n"));
|
try!(zip.write_all(b"Hello, World!\n"));
|
||||||
|
|
||||||
try!(zip.start_file("test/lorem_ipsum.txt", zip::CompressionMethod::Deflated));
|
try!(zip.start_file("test/lorem_ipsum.txt", FileOptions::default()));
|
||||||
try!(zip.write_all(LOREM_IPSUM));
|
try!(zip.write_all(LOREM_IPSUM));
|
||||||
|
|
||||||
try!(zip.finish());
|
try!(zip.finish());
|
||||||
|
|
96
src/write.rs
96
src/write.rs
|
@ -43,7 +43,8 @@ enum GenericZipWriter<W: Write + io::Seek>
|
||||||
/// let mut w = std::io::Cursor::new(buf);
|
/// let mut w = std::io::Cursor::new(buf);
|
||||||
/// let mut zip = zip::ZipWriter::new(w);
|
/// let mut zip = zip::ZipWriter::new(w);
|
||||||
///
|
///
|
||||||
/// try!(zip.start_file("hello_world.txt", zip::CompressionMethod::Stored));
|
/// let options = zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Stored);
|
||||||
|
/// try!(zip.start_file("hello_world.txt", options));
|
||||||
/// try!(zip.write(b"Hello, World!"));
|
/// try!(zip.write(b"Hello, World!"));
|
||||||
///
|
///
|
||||||
/// // Optionally finish the zip. (this is also done on drop)
|
/// // Optionally finish the zip. (this is also done on drop)
|
||||||
|
@ -69,6 +70,50 @@ struct ZipWriterStats
|
||||||
bytes_written: u64,
|
bytes_written: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Metadata for a file to be written
|
||||||
|
pub struct FileOptions {
|
||||||
|
compression_method: CompressionMethod,
|
||||||
|
last_modified_time: time::Tm,
|
||||||
|
permissions: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileOptions {
|
||||||
|
/// Construct a new FileOptions object
|
||||||
|
pub fn default() -> FileOptions {
|
||||||
|
FileOptions {
|
||||||
|
compression_method: CompressionMethod::Deflated,
|
||||||
|
last_modified_time: time::now(),
|
||||||
|
permissions: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the compression method for the new file
|
||||||
|
///
|
||||||
|
/// The default is `CompressionMethod::Deflated`
|
||||||
|
pub fn compression_method(mut self, method: CompressionMethod) -> FileOptions {
|
||||||
|
self.compression_method = method;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the last modified time
|
||||||
|
///
|
||||||
|
/// The default is the current timestamp
|
||||||
|
pub fn last_modified_time(mut self, mod_time: time::Tm) -> FileOptions {
|
||||||
|
self.last_modified_time = mod_time;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the permissions for the new file.
|
||||||
|
///
|
||||||
|
/// The format is represented with unix-style permissions.
|
||||||
|
/// The default is `0o644`, which represents `rw-r--r--` for files,
|
||||||
|
/// and `0o755`, which represents `rwxr-xr-x` for directories
|
||||||
|
pub fn unix_permissions(mut self, mode: u32) -> FileOptions {
|
||||||
|
self.permissions = Some(mode & 0o777);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<W: Write+io::Seek> Write for ZipWriter<W>
|
impl<W: Write+io::Seek> Write for ZipWriter<W>
|
||||||
{
|
{
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize>
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize>
|
||||||
|
@ -122,8 +167,8 @@ impl<W: Write+io::Seek> ZipWriter<W>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a new file for with the requested compression method.
|
/// Start a new file for with the requested options.
|
||||||
pub fn start_file<S>(&mut self, name: S, compression: CompressionMethod) -> ZipResult<()>
|
fn start_entry<S>(&mut self, name: S, options: FileOptions) -> ZipResult<()>
|
||||||
where S: Into<String>
|
where S: Into<String>
|
||||||
{
|
{
|
||||||
try!(self.finish_file());
|
try!(self.finish_file());
|
||||||
|
@ -132,13 +177,14 @@ impl<W: Write+io::Seek> ZipWriter<W>
|
||||||
let writer = self.inner.get_plain();
|
let writer = self.inner.get_plain();
|
||||||
let header_start = try!(writer.seek(io::SeekFrom::Current(0)));
|
let header_start = try!(writer.seek(io::SeekFrom::Current(0)));
|
||||||
|
|
||||||
|
let permissions = options.permissions.unwrap_or(0o100644);
|
||||||
let mut file = ZipFileData
|
let mut file = ZipFileData
|
||||||
{
|
{
|
||||||
system: System::Dos,
|
system: System::Unix,
|
||||||
version_made_by: DEFAULT_VERSION,
|
version_made_by: DEFAULT_VERSION,
|
||||||
encrypted: false,
|
encrypted: false,
|
||||||
compression_method: compression,
|
compression_method: options.compression_method,
|
||||||
last_modified_time: time::now(),
|
last_modified_time: options.last_modified_time,
|
||||||
crc32: 0,
|
crc32: 0,
|
||||||
compressed_size: 0,
|
compressed_size: 0,
|
||||||
uncompressed_size: 0,
|
uncompressed_size: 0,
|
||||||
|
@ -146,7 +192,7 @@ impl<W: Write+io::Seek> ZipWriter<W>
|
||||||
file_comment: String::new(),
|
file_comment: String::new(),
|
||||||
header_start: header_start,
|
header_start: header_start,
|
||||||
data_start: 0,
|
data_start: 0,
|
||||||
external_attributes: 0,
|
external_attributes: permissions << 16,
|
||||||
};
|
};
|
||||||
try!(write_local_file_header(writer, &file));
|
try!(write_local_file_header(writer, &file));
|
||||||
|
|
||||||
|
@ -160,7 +206,7 @@ impl<W: Write+io::Seek> ZipWriter<W>
|
||||||
self.files.push(file);
|
self.files.push(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(self.inner.switch_to(compression));
|
try!(self.inner.switch_to(options.compression_method));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -184,9 +230,36 @@ impl<W: Write+io::Seek> ZipWriter<W>
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Starts a file.
|
||||||
|
pub fn start_file<S>(&mut self, name: S, mut options: FileOptions) -> ZipResult<()>
|
||||||
|
where S: Into<String>
|
||||||
|
{
|
||||||
|
if options.permissions.is_none() {
|
||||||
|
options.permissions = Some(0o644);
|
||||||
|
}
|
||||||
|
*options.permissions.as_mut().unwrap() |= 0o100000;
|
||||||
|
try!(self.start_entry(name, options));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a directory entry.
|
||||||
|
///
|
||||||
|
/// You should not write data to the file afterwards.
|
||||||
|
pub fn add_directory<S>(&mut self, name: S, mut options: FileOptions) -> ZipResult<()>
|
||||||
|
where S: Into<String>
|
||||||
|
{
|
||||||
|
if options.permissions.is_none() {
|
||||||
|
options.permissions = Some(0o755);
|
||||||
|
}
|
||||||
|
*options.permissions.as_mut().unwrap() |= 0o40000;
|
||||||
|
options.compression_method = CompressionMethod::Stored;
|
||||||
|
try!(self.start_entry(name, options));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Finish the last file and write all other zip-structures
|
/// Finish the last file and write all other zip-structures
|
||||||
///
|
///
|
||||||
/// This will return the writer, but one should normally not append any data to the end of the file.
|
/// This will return the writer, but one should normally not append any data to the end of the file.
|
||||||
/// Note that the zipfile will also be finished on drop.
|
/// Note that the zipfile will also be finished on drop.
|
||||||
pub fn finish(&mut self) -> ZipResult<W>
|
pub fn finish(&mut self) -> ZipResult<W>
|
||||||
{
|
{
|
||||||
|
@ -369,7 +442,8 @@ fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData)
|
||||||
// central file header signature
|
// central file header signature
|
||||||
try!(writer.write_u32::<LittleEndian>(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE));
|
try!(writer.write_u32::<LittleEndian>(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE));
|
||||||
// version made by
|
// version made by
|
||||||
try!(writer.write_u16::<LittleEndian>(0x14FF));
|
let version_made_by = (file.system as u16) << 8 | (file.version_made_by as u16);
|
||||||
|
try!(writer.write_u16::<LittleEndian>(version_made_by));
|
||||||
// version needed to extract
|
// version needed to extract
|
||||||
try!(writer.write_u16::<LittleEndian>(20));
|
try!(writer.write_u16::<LittleEndian>(20));
|
||||||
// general puprose bit flag
|
// general puprose bit flag
|
||||||
|
@ -399,7 +473,7 @@ fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData)
|
||||||
// internal file attribytes
|
// internal file attribytes
|
||||||
try!(writer.write_u16::<LittleEndian>(0));
|
try!(writer.write_u16::<LittleEndian>(0));
|
||||||
// external file attributes
|
// external file attributes
|
||||||
try!(writer.write_u32::<LittleEndian>(0));
|
try!(writer.write_u32::<LittleEndian>(file.external_attributes));
|
||||||
// relative offset of local header
|
// relative offset of local header
|
||||||
try!(writer.write_u32::<LittleEndian>(file.header_start as u32));
|
try!(writer.write_u32::<LittleEndian>(file.header_start as u32));
|
||||||
// file name
|
// file name
|
||||||
|
|
Loading…
Add table
Reference in a new issue