#include <errno.h>
#include <stdlib.h>
#include <time.h>
+#include <unistd.h>
#include "gl/crc.h"
#include "gl/fwriteerror.h"
{
char *file_name; /* File name, for use in error mesages. */
FILE *file; /* Output stream. */
+ uint32_t offset; /* Offset in output stream. */
uint16_t date, time; /* Date and time in MS-DOS format. */
put_bytes (struct zip_writer *zw, const void *p, size_t n)
{
fwrite (p, 1, n, zw->file);
+ zw->offset += n;
}
static void
time_t now;
FILE *file;
- file = fopen (file_name, "wb");
- if (file == NULL)
+ if (strcmp (file_name, "-"))
{
- msg_error (errno, _("%s: error opening output file"), file_name);
- return NULL;
+ file = fopen (file_name, "wb");
+ if (file == NULL)
+ {
+ msg_error (errno, _("%s: error opening output file"), file_name);
+ return NULL;
+ }
+ }
+ else
+ {
+ if (isatty (STDOUT_FILENO))
+ {
+ msg (ME, _("%s: not writing ZIP file to terminal"), file_name);
+ return NULL;
+ }
+
+ file = stdout;
}
zw = xmalloc (sizeof *zw);
zw->file_name = xstrdup (file_name);
zw->file = file;
+ zw->offset = 0;
zw->ok = true;
zip_writer_add (struct zip_writer *zw, FILE *file, const char *member_name)
{
struct zip_member *member;
- uint32_t offset, size;
+ uint32_t size;
size_t bytes_read;
uint32_t crc;
char buf[4096];
/* Local file header. */
- offset = ftello (zw->file);
+ uint32_t offset = zw->offset;
put_local_header (zw, member_name, 0, 0, 1 << 3);
/* File data. */
with the correct file size and CRC. Otherwise, write data descriptor. */
if (fseeko (zw->file, offset, SEEK_SET) == 0)
{
+ uint32_t save_offset = zw->offset;
put_local_header (zw, member_name, crc, size, 0);
if (fseeko (zw->file, size, SEEK_CUR)
&& zw->ok)
msg_error (errno, _("%s: error seeking in output file"), zw->file_name);
zw->ok = false;
}
+ zw->offset = save_offset;
}
else
{
if (zw == NULL)
return true;
- dir_start = ftello (zw->file);
+ dir_start = zw->offset;
for (i = 0; i < zw->n_members; i++)
{
struct zip_member *m = &zw->members[i];
free (m->name);
}
free (zw->members);
- dir_end = ftello (zw->file);
+ dir_end = zw->offset;
/* End of central directory record. */
put_u32 (zw, MAGIC_EOCD); /* end of central dir signature */
put_u16 (zw, 0); /* .ZIP file comment length */
ok = zw->ok;
- if (ok && fwriteerror (zw->file))
+ if (ok && zw->file != stdout && fwriteerror (zw->file))
{
msg_error (errno, _("%s: write failed"), zw->file_name);
ok = false;
dnl
AT_BANNER([zip])
-AT_SETUP([Basic zip - unzip test])
+AT_SETUP([basic zip - unzip test])
AT_KEYWORDS([compression])
-
-AT_CHECK([dnl
here=`pwd`
dir1=$here/original
dir2=$here/recovered
names="$names $bn";
done
-(cd $dir1 && zip-test w foo.zip $names)
+AT_CHECK([cd $dir1 && zip-test w foo.zip $names])
+# If zipinfo is installed, make sure it can read the zipfile.
+if (zipinfo -v) >/dev/null 2>&1; then
+ AT_CHECK([zipinfo $dir1/foo.zip], [0], [ignore])
+fi
mkdir -p $dir2
cp $dir1/foo.zip $dir2
cd $dir2
-zip-test r foo.zip $names
-# Compare the files to their originals
-for f in $names; do
- diff $dir1/$f $dir2/$f;
- if test $? -ne 0 ; then exit 1; fi;
-done
+AT_CHECK([zip-test r foo.zip $names])
-exit 0
+AT_CHECK([
+ # Compare the files to their originals
+ for f in $names; do
+ diff $dir1/$f $dir2/$f;
+ if test $? -ne 0 ; then exit 1; fi;
+ done
])
+AT_CLEANUP
-AT_CLEANUP
+AT_SETUP([zip to pipe])
+AT_KEYWORDS([compression])
+here=`pwd`
+dir1=$here/original
+dir2=$here/recovered
+
+mkdir -p $dir1
+
+# Generate files of differing sizes with random data in them
+names=""
+s=1;
+while test $s -le 8192 ; do
+ name=$dir1/$s
+ dd if=/dev/urandom of=$name count=1 bs=$s 2> /dev/null
+ s=$(($s * 2));
+ bn=`basename $name`;
+ names="$names $bn";
+done
+
+# The pipe through "cat" below is essential because it makes the
+# output file un-seekable.
+AT_CHECK([cd $dir1 && zip-test w - $names | cat > foo.zip])
+
+# If zipinfo is installed, make sure it can read the zipfile.
+if (zipinfo -v) >/dev/null 2>&1; then
+ AT_CHECK([zipinfo $dir1/foo.zip], [0], [ignore])
+fi
+mkdir -p $dir2
+cp $dir1/foo.zip $dir2
+cd $dir2
+
+AT_CHECK([zip-test r foo.zip $names])
+
+AT_CHECK([
+ # Compare the files to their originals
+ for f in $names; do
+ diff $dir1/$f $dir2/$f;
+ if test $? -ne 0 ; then exit 1; fi;
+ done
+])
+AT_CLEANUP