Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 6724 → Rev 6725

/programs/fs/unzip60/qdos/Contents
0,0 → 1,20
Contents of the "qdos" subdirectory for UnZip 5.4 and later:
 
Contents this file
IZREADME.SMS release notes from Jonathan Hudson (author of port)
Makefile makefile for xtc68 cross-compiler on Linux (native QDOS exes)
callstub.c user interface stub for SMS/QDOS specific SFX archives
config.S assembler routine for ...?
crc68.s 68000 version of CRC code
izqdos.h SMS/QDOS-specific header file
makesfx.c source for MakeSFX utility (simple concatenation does not work)
qdos.c SMS/QDOS-specific functions
 
Notes:
 
"Makefile" is for the xtc68 cross compiler on Linux, but conversion to a
native c68 makefile should be trivial. To build a Linux (or other Unix)
UnZip that understands QDOS extra fields, add "-DQLZIP" to the LOCAL_UNZIP
environment variable and compile with the normal Unix makefile (for example,
linux_asm target). The "QLZIP" flag enables the Qdos "cross-UnZip" support
in unix/unix.c.
/programs/fs/unzip60/qdos/IZREADME.SMS
0,0 → 1,600
IZREADME_SMS (IZREADME.SMS): Info-ZIP for SMS/QDOS, last revised: 15-Jun-1998
===============================================================================
[was "InfoZIP_SMSQDOS_ReadMe" in J. Hudson's original ports, ca. 08/1995]
 
Info-ZIP Programs
=================
 
Zip
UnZip
UnZipSFX
fUnZip
 
Introduction
------------
 
This archive is a result of frustrations with contemporary (August 95)
versions of Zip and UnZip. While they use the same compression
algorithms as the Info-ZIP programs, there the compatibility ends. If
you just use Zip/UnZip only on SMS/QDOS, then perhaps this is not a
problem (but I know for some users it still is); if you use Zip/UnZip
to transport source code and data between diverse systems, then the
disregard for Info-ZIP standards is inconvenient, particularly the
fact that directories are not supported and files are always stored
underscored.
 
This release of Zip/UnZip offers:
 
o zipfile/directory compatibility with all other supported
platforms
 
o SMS/QDOS compatibility and back-compatible with earlier
versions.
 
o Improved performance (Zip is typically 50% faster)
 
o Command-line compatibility with Info-ZIP
 
o Self-extracting archives (but not very elegantly)
 
o Archives are marked as 'created by SMS/QDOS'.
 
o Optional recursion into directories
 
o Directory structure restored on unzip of Info-ZIP/PKZIP-
compatible archives.
 
o Config'urable for listing and unpack formats (Info-ZIP (.) or
SMS/QDOS (_) and 'Press any key' timeouts. Override options
from command line.
 
Info-ZIP Standards
------------------
 
This (rather long-winded and waffling) section discusses the
conventions and standards used by Info-ZIP-compatible archivers and how
"Info-ZIP for SMS/QDOS" achieves compatibility.
 
Info-ZIP Zip/UnZip on all supported platforms (Unix, DOS, OS/2, NT,
VAX/VMS, Amiga etc etc), works in a specific way. (Until now SMS/QDOS
was neither 'supported' nor Info-ZIP-compliant.)
 
a. The zipfile directory is in (/.) (Unix) format.
 
b. When zips are listed, it is in 'zipfile' (Unix) format.
 
c. When files are added, they are defined in native format.
 
d. When files are added, this is shown in 'zipfile' format.
 
e. When files are unpacked, this is done to native format, but
selection is done in 'zipfile' format.
 
Basically, the listing and stored format of a file is that of the
destination.
 
So, given a file structure at some arbitrary 'root' level.
 
Makefile
src (Dir)
afile.c
bfile.c
docs (Dir)
prog.txt
hdr (Dir)
cfile.h
dfile.h
 
Then these would be in Unix (and Amiga) as
 
Makefile
src/afile.c
src/bfile.c
src/docs/prog.txt
hdr/cfile.h
hdr/dfile.h
 
This is also how the zipfile directory appears.
 
And in DOS/OS2/NT
 
Makefile
src\afile.c
src\docs\prog.txt
hdr\cfile.h .. etc
 
And in VMS (we SHOUT in VMS and have a silly file system)
 
MAKEFILE
[SRC]AFILE.C
[SRC.DOC]PROG.TXT
[HDR]CFILE.H .. etc
(OK VMS purist, [.SRC] etc. Only an example)
 
And in SMS/QDOS (quiet again, but slightly ludicrous !)
 
Makefile
src_afile_c
src_doc_prog_txt
hdr_cfile_h .. etc
 
The main problem regarding SMS/QDOS is not that of extensions - (after
all, only VMS and DOS _really_ have extensions; Unix, AmigaDOS, NT and
OS/2 (and Win95) allow multiple '.' in.long.file.names.
 
The SMS/QDOS problem is that '_' is both a legal file name character
and a directory separator. This creates the difficulties, as
directories and files are somewhat different objects.
 
It is the intention that these versions of SMS/QDOS Zip/UnZip will
follow the Info-ZIP rules, thus providing compatibility with the other
platforms. It is possible to zip the file structure described above on
SMS/QDOS and unpack it on VMS and get the VMS structure as shown in the
example (and vice-versa). [We only choose the most obtuse file
systems for the examples].
 
In order to achieve this, SMS/QDOS names are mapped into Unix-style
ones when the zipfile is created and un-mapped when it is unpacked.
There is an option to unpack in 'zipfile' format (i.e. with '.' rather
than '_'), but there will be no option to pack to all '_'. That would
contravene the standard. However, a file
 
src_split_name_c (which is src->split_name_c !)
src/split_name.c)
 
where src is a hard directory, would be stored in the zip directory as
 
src/split_name.c
 
It does handle '_' with a little intelligence.
 
The default UnZip option will be to translate '.' to '_'; this is
because there are still many QDOS/Minerva users that cannot handle '.'
without quotes, which is immensely inconvenient. For many SMS users
'_' is also the most natural and convenient option. It also means that
SMS/QDOS <-> SMS/QDOS Zip - UnZip sequences are transparent.
 
There will, however, be two ways around this in UnZip.
 
1. It is possible to Config the UnZip default to be '.'
translations (or not).
 
2. The UnZip -Q1 option will toggle the default (Config'ed)
state.
 
Examples:
 
Given that we want/have
 
Makefile (Makefile)
src/afile.c (src_afile_c)
src/bfile.c (src_bfile_c)
src/docs/prog.txt (src_docs_prog_txt)
hdr/cfile.h (hdr_cfile_h)
hdr/dfile.h (hdr_dfile_h)
 
Then on SMS/QDOS we might have added the *.c files as
 
ex zip;'-r test *_c'
 
(or VMS, just to do something different)
 
zip -r test [.src]*.c
 
In both cases the file lists as above (left).
 
To unpack on SMS/QDOS (just the _c/.c files)
 
ex unzip;'test src/*.c'
 
(and VMS, unzip test src/*.c)
 
i.e. in both cases using the 'zipfile' format. As a concession to
SMS/QDOS, you could also have:
 
ex unzip;'test src_*_c'
 
but not unzip test [.src]*.c on VMS !!!!! Sorry, dinosaurs.
 
Both SMS/QDOS commands unpack to
 
src_afile_c etc, where src_ is a hard sub-directory.
 
(and the VMS example would unpack to [.src]afile.c, (or to src\afile.c on
DOS/NT/OS2 etc).
 
Options & SMS/QDOS Features
---------------------------
 
The options supported by Zip/UnZip are basically those documented in
the Info-ZIP documents and shown in on-line 'usage'. In particular, -r
and -j work as intended.
 
PLEASE NOTE: Previous SMS/QDOS zip/unzips have NOT followed these
conventions, for example -r was not implemented and -j was reversed.
 
A number of -Q (SMS/QDOS-specific) options (not yet in the current
documents or usage screens) are implemented.
 
The Zip 2.0.1 (and later) default is to add SMS/QDOS headers where
file type = 1 (exe) or 2 (rel) or (type > 0 && != 255 and (filesize %
64) != 0). Directories are included anyway, unless you zip -D.
 
Where a header is added for an 'exe' file a '*' is displayed after the
name in the zip display (and '#' for 'rel' files).
 
The -Q options for Zip are:
 
-Q1 Don't add headers for ANY files
-Q2 Add headers for all files
-Q4 Don't wait for interactive key press
 
(additive, so -Q5 => no headers, no wait, -Q6 all headers,
no wait etc)
 
(the default is exec/rel headers, 5 sec wait)
 
Zip has rationalised the file header storage in zipfiles. The
previous Zip used to store a QDOS header for each file. This was very
wasteful, for example compressing a SMS/QDOS release of PGP in this
way came to 730Kb, too large for a DD disk. Changing the Zip program
just to add a header record for the single PGP exe and the zipfile
size went down to around 690Kb.
 
And for UnZip
 
-Q1 Toggle unpack format status ('.' <-> '_')
-Q2 Toggle listing format
-Q4 Don't wait for key press
 
Files Types
-----------
 
The history of QDOS suffers from incompatible feature
implementations. For example, Thor directories have file type 3, CST
have type 4 and Level 2 have type 255. Some software writers (both
amateur and otherwise) have used type 3 or 4 for other purposes
(backward compatibility ?? who cares ??).
 
In order to bypass problems cause by incompatible (inconsiderate ?)
usage of file types, the file type denoting a directory is a
Config'urable item. The default is set to -1 (65535 in Config terms),
which means "determine directory type from the file header of the root
directory". If this is appears unsuccessful on your system, the value
can be Config'ed in the range 3-255.
 
Zip assumes a file is a directory if:
 
((type == CONFIGed_type) && (file_size % 64) == 0)
 
If you are unfortunate enough have files of that pass this test but
are not directories, then Zip will loop endless, as SMS/QDOS opens the
root directory again !!! (recursion: see recursion etc).
 
I suggest you refrain from zipping such files and contact the software
supplier and point out the error of their ways.
 
File Naming Issues
------------------
 
Zip will append a '_zip' suffix to the archive filename when the
supplied name (i.e. excluding device/directory parts) does not
contain a '_' or a '.'. This is broadly compatible with Info-ZIP,
taking into account the '_' aberation.
 
So
ex zip;'ram2_test ...' >> ram2_test_zip
 
ex zip;'ram2_test.zip ...' >> ram2_test.zip
 
ex zip;'ram2_test_rep ... ' >> ram2_test_rep
 
ex zip;'ram2_fdbbs.rep ... ' >> ram2_fdbbs.rep
 
ex zip;'ram2_test_rep.zip ...' >> ram2_test_rep.zip
 
This implies that if a file ram2_test.zip exists, and you do:
 
ex zip;'ram2_test ...'
 
Then a new file (test_zip) is created, rather than 'test.zip' being
updated.
 
Zip supports extensive recursive wild-carding, again the fact that '_'
can be a directory separator as well as part of a file name makes this
a bit tricky, but given the example:
 
test1_bas
test2_bas
dir1->demo1_bas where -> indicates a sub dir
dir2->demo2_bas
 
ex zip;'ram2_test *_bas'
just finds test1_bas, test2_bas
 
ex zip;'-r ram2_test *_bas'
recurses and finds all the files
 
You might think that
 
ex zip;'-r ram2_test *_*_bas'
 
would just find the files in the subdirectories--well yes, but it will
also find very other sub-dir'ed _bas file on the disk too. This is
a feature.
 
The pattern matching supports Unix-style 'regex' so you could:
 
ex zip;'ram2_test dir?_*_bas'
or
ex zip;'ram2_test dir[12]_*_bas
 
 
UnZip has now got a fixed -d option. This is used to specify the
directory to unpack the zipfile into, it must follow immediately
after the zip name.
 
ex unzip;'ram2_test_zip -d ram3_ *_txt'
 
would unpack all *_txt files to ram3_ .
 
It is not necessary to set the default directory to pack files, Zip
will remove any device names (and store any hard directory names,
unless you zip -j).
 
ex zip;'ram1_test flp1_*'
 
----->
adding: file.dat (deflated 50%)
adding: menu.rext # (deflated xx%)
adding: zip * (deflated yy%)
adding: hard_one (stored 0%)
adding: hard_one/stuff.bas (deflated ...)
 
Due to the way the file-mapping is implemented, it is not supported
over the nX_ type network device.
 
Config Options
--------------
 
A limited number of SMS/QDOS specific functions can be set using the
QJump Config program.
 
For Zip:
 
Timeout for interactive 'Press any key' prompt
 
65535 Wait forever (aka -1)
0 No wait
n (1-32767) Wait for 'n' clocks (1/50 sec)
 
Other values are unsupported. Note Config works on 'unsigned'
integer values (at least according to my manual).
 
Directory file type key.
 
Config will accept any value in the range 3-255, known useful
values are 3 (Thor), 4 (CST) and 255 (Level 2 devices). A value
of 65535 (aka -1) means "determine from device info".
 
For UnZip:
 
Timeout as above
 
Unpack mode (SMS/QOS ('_') or Info-ZIP ('.')
 
List format (Info-ZIP ('.') or SMS/QDOS ('_')
 
 
When the 'Press a key' text is displayed, if you press ESC, then it
waits until you press any other key, infinite timeout. This may be
useful if you want (much) more time to study a listing etc.
 
Defaults for timeout and directory type are 250 and -1 respectively.
 
More Goodies
------------
 
Part of the Zip compression code is now in assembler; it runs
noticably faster than the previous version. Compressing some arbitrary
files with the previous Zip it took 251 seconds, with Zip 2.0.1 it
took (a mere) 170 seconds (68008 QL).
 
More good news is that SMS/QDOS is just another system option on top
of standard Info-ZIP, unlike the previous ports that were much more
SMS/QDOS specific. For example, compiling the standard source with c68
(i.e. #define QDOS), then you get an SMS/QDOS version.
 
Compile with Linux/gcc and get the standard Linux version. Now, here's
the cool bit; compile with Linux/gcc and "-DQLZIP", and get a standard
Linux Zip/UnZip with SMS/QDOS (header) extensions.
 
so, on Linux:
 
zip -Q stuff.zip qtpi zip unzip
 
the -Q tells Zip to look for XTc68/Lux68 cross-compiler data size
blocks and produce a zipfile with SMS/QDOS headers in it (for exec
type programs). This works for exec files produced by the XTc68/Lux68
cross compilers and ANY SMS/QDOS files copied to a Unix or MS-DOS disk
from an SMS/QDOS floppy using 'qltools v2.2' (or later).
 
Self Extracting Archives
------------------------
 
Info-ZIP self-extracting archives (_sfx) are created in a rather
'brute-force' way. The UnZipSFX program is prepended to a zipfile.
 
i.e. file_sfx = unzipsfx + file_zip
ex file_sfx
 
Although the UnZipSFX program is a cut-down UnZip, it is still around
30Kb - 50Kb, depending on platform.
 
The success of this approach depends on how the operating system
loader loads executable files. On most systems where the loader only
loads the actual program part (Unix, VMS, DOS et al), the this is
quite efficient; if you make, say, a 4Mb zipfile and prepend a 30Kb
UnZipSFX image, then the system only loads the 30Kb program and the
process is efficient as the zipped data part is still unpacked from
disk. These systems also supply the running UnZipSFX program stub with
the path name of the file it was loaded from, so the program knows
what it has to unpack (so on Linux, for example):
 
cat /usr/bin/unzipsfx test.zip > test.sfx # concatenate the files
chmod 755 test.sfx # make executable
test.sfx # to extract, it
# 'knows' it is "test.sfx"
 
Unfortunately, the more simplistic nature of SMS/QDOS makes this much
more difficult and rather less efficient as: (see note 1)
 
a. The SMS/QDOS 'loader' loads the whole file into memory.
 
b. The SMS/DOS 'loader'/c68 run-time system does not return the
name of the file from which it was loaded.
 
c. You cannot so easily create a image file by concatenating two
files, it is also necessary to ensure the executable file
header is set correctly.
 
d. The show stopper. The data space required for the
self-extracting archive is required, as not easily maintained
during electronic transfer.
 
 
If anyone is still interested, then the following support for UnZipSFX
is provided.
 
o A program 'makesfx' will combine a stub (callstub), UnZipSFX image
and a zipfile to produce a sfx (self-extracting zip) file.
 
o A callable interface is supplied. The user calls the SFX file,
which creates the files necessary to do the extraction.
 
The makesfx program concatenates the supplied files to standard
output.
 
So, to create a sfx of all the _c files in the default directory.
 
# 1st create a zipfile of the required files
 
ex zip;'ram1_test_zip *_c'
 
# Now create the sfx file (ram2_test_sfx)
# our UnZipSFX image is in 'win1_bin'
# as is the call stub.
 
ex makesfx;'-o test_sfx -x win1_bin_unzipsfx -s win1_bin_callstub -z ram1_test_zip'
 
The arguments to makesfx are:
 
-s stubfile
-x UnZipSFX_program
-z Zip_file
-o Output_file
 
You can now unpack the _sfx file on any SMS/QDOS-compatible
system.
 
f$ = "win2_tmp_test_sfx"
a = alchp(flen(\f$))
lbytes f$,a
call a
rechp(a)
 
ZipInfo
-------
 
Given the above note concerning SMS/QDOS programs not knowing the name
by which the program was invoked, then the usual symbolic-link-of-unzip-
to-zipinfo trick is unavailable (presupposing there is some some SMS/QDOS
trick to emulate symbolic links).
 
ZipInfo functionality is only available via 'unzip -Z'. There is no
separate ZipInfo program.
 
Caveat ATP Users
----------------
 
ATP for SMS/QDOS users should pay particular attention to the
Zip/UnZip options in their atprc and compare with Info-ZIP Zip/UnZip
usage. Older versions of Zip/UnZip screwed up -j.
 
 
zip -jk
unzip -jo
 
Distribution & Copyright
------------------------
 
This software is written by and largely copyrighted by the 'Info-ZIP'
group whose members are noted in the accompanying documentation. This
particular SMS/QDOS port plus 'makesfx' was written by, but is not
copyrighted by, Jonathan R Hudson. The SMS/QDOS code in this release
is written from scratch and is not dependent on previous SMS/QDOS
releases, but is (largely) compatible.
 
As a courtesy to the authors of this package, please ensure that the
documentation is supplied when it is re-distributed.
 
In particular, if this archive is split into Zip and UnZip components,
ensure that this document ("IZREADME_SMS") is supplied in
each component.
 
SMS/QDOS version by:
Jonathan R Hudson (jrhudson@bigfoot.com)
 
I am grateful to Graham Goodwin for finding some most imaginative
means of breaking the beta code.
 
I'd also like to thank Thierry Godefroy for providing the 2.1/5.2
source code and making the initial contact with the Info-ZIP group.
 
And of course, many, many thanks to the Info-ZIP workers for making
this code freely available.
 
Note 1
------
 
The 'C' language FAQ ('frequently asked questions' [comp.lang.c])
notes on the matter of obtaining the load file name of a 'C' program:
 
16.5: How can my program discover the complete pathname to the
executable file from which it was invoked?
 
A: argv[0] may contain all or part of the pathname, or it may
contain nothing. You may be able to duplicate the command
language interpreter's search path logic to locate the
executable if the name in argv[0] is present but incomplete.
However, there is no guaranteed or portable solution.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
Note 2
------
 
NUL files for SMS2. There appears to be a conflict between SMS2/LBASIC
compiled programs and c68 programs using nul as stdin.
 
EW zip,nul;'ram1_test *_bas' # will not work
 
# This does work !
EW zip,#FOP_IN('nul');'ram2_test *_bas' : CLOSE
 
Note 3
------
 
version number incremented to 2.0.1a and 5.12a to accomodate Erling
Jacobsen's exit message requirements
 
version number incremented to Zip 2.0.1b to fix bug on zipping files
starting with leading underscore.
 
version number incremented to UnZip 5.12b to fix UnZip problem on
files zipped with leading './', and linked with revised (fixed) c68
'utime' function (could corrupt level 1 files). (source code _only_ as
IZQ004.zip).
 
Ported Zip 2.1 and UnZip 5.2 (July 1996). Released as INZIP005.zip
 
All later versions --- see Info-ZIP release notes and documentation.
/programs/fs/unzip60/qdos/Makefile
0,0 → 1,131
# Makefile for UnZip 5.53+ using QDOS/xtc68 and GNU make
#
# This makefile is a makefile for the xtc68 cross-compiler on Linux;
# conversion to a native c68 makefile should be trivial. This builds
# native QDOS binaries.
#
# Last modified: 25 Dec 06
 
include /etc/ql.mak
CFLAGS = -O -I. -I./qdos/
 
OBJS = unzip.o process.o crypt.o envargs.o explode.o \
unshrink.o extract.o zipinfo.o inflate.o match.o unreduce.o \
ubz2err.o ttyio.o fileio.o list.o globals.o qdos.o config.o crc32.o
 
FOBJS = funzip.o ttyio.o crypt.fo inflate.fo globals.fo config.o crc32.fo qdos.fo
 
XOBJS = unzip.xo process.xo crypt.xo extract.xo fileio.xo \
ttyio.xo inflate.xo match.xo globals.xo ubz2err.xo \
qdos.xo config.o crc32.xo
 
all : unzip unzipsfx funzip makesfx callstub
 
# xtc68/cc is brain dead !!
 
%.xo : %.c
qcpp -DSFX -DSFX_EXDIR -I. -I./qdos/ $*.c $*.i
c68 -O $*.i $*.s
as68 $*.s $*.xo
rm -f $*.s $*.i
 
%.fo : %.c
qcpp -DFUNZIP -I. -I./qdos/ $*.c $*.i
c68 -O $*.i $*.s
as68 $*.s $*.fo
rm -f $*.s $*.i
 
u : unzip
 
f : funzip
 
x : unzipsfx
 
m : makesfx
 
unzip : $(OBJS)
$(LD) $(LDFLAGS) -o$@ $(OBJS) $(LDLIBS)
 
unzipsfx : $(XOBJS)
$(LD) $(LDFLAGS) -o$@ $(XOBJS) $(LDLIBS)
 
funzip : $(FOBJS)
$(LD) $(LDFLAGS) -o$@ $(FOBJS) $(LDLIBS)
 
makesfx : qdos/makesfx.c
cp qdos/makesfx.c .
$(CC) $(CFLAGS) -o makesfx makesfx.c
rm -f makesfx.c
 
callstub : qdos/callstub.c
cp qdos/callstub.c .
$(CC) -screspr.o $(CFLAGS) -o callstub callstub.c
rm -f callstub.c
 
clean :
rm *.o *.xo *.fo
 
cleaner : clean
rm unzip funzip unzipsfx makesfx
 
 
$(OBJS) $(XOBJS) $(FOBJS) : unzip.h unzpriv.h globals.h \
qdos/izqdos.h
 
crc32.o crc32.fo crc32.xo : zip.h
crypt.o crypt.fo crypt.xo ttyio.o ttyio.fo ttyio.xo : zip.h
 
inflate.o inflate.fo inflate.xo : inflate.h
 
fileio.o fileio.xo : ebcdic.h
 
funzip.o : crc32.h
crc32.o crc32.fo crc32.xo crypt.o crypt.fo crypt.xo : crc32.h
fileio.o fileio.xo extract.o extract.xo process.o process.xo : crc32.h
 
 
crypt.o crypt.fo crypt.xo ttyio.o ttyio.fo ttyio.xo : crypt.h
unzip.o unzip.xo funzip.o : crypt.h
fileio.o fileio.xo extract.o extract.xo : crypt.h
inflate.o inflate.fo inflate.xo : crypt.h
 
crypt.o crypt.fo crypt.xo ttyio.o ttyio.fo ttyio.xo : ttyio.h
funzip.o fileio.o fileio.xo : ttyio.h
 
unzip.o unzip.xo : unzvers.h consts.h
 
 
# Special case object files:
 
qdos.o: qdos/qdos.c
cp qdos/qdos.c .
$(CC) -c -oqdos.o $(CFLAGS) $*.c
rm -f qdos.c
 
config.o: qdos/config.S
cp qdos/config.S .
$(CC) -c $*.S
rm -f config.S
 
qdos.xo: qdos/qdos.c
cp qdos/qdos.c .
qcpp -DSFX -DSFX_EXDIR -I. -I./qdos/ qdos.c qdos.i
c68 qdos.i qdos.s
as68 qdos.s qdos.xo
rm -f qdos.s qdos.i
rm -f qdos.c
 
qdos.fo: qdos/qdos.c
cp qdos/qdos.c .
qcpp -DFUNZIP -I. -I./qdos/ qdos.c qdos.i
c68 qdos.i qdos.s
as68 qdos.s qdos.fo
rm -f qdos.s qdos.i
rm -f qdos.c
 
install: unzip unzipsfx funzip makesfx callstub
qcp unzip /ql/exe/
qcp unzipsfx /ql/exe/
qcp funzip /ql/exe/
qcp makesfx /ql/exe/
cp callstub /ql/exe/
/programs/fs/unzip60/qdos/callstub.c
0,0 → 1,224
/*
Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
 
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in unzip.h) for terms of use.
If, for some reason, these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
#include <qdos.h>
#include <limits.h>
#include <string.h>
 
struct
{
short flag1;
short flag2;
long offset; // The offset from &ds to unzipsfx exe
long sfxlen; // size of unzipsfx program
long sfxdsiz; // data size of unzipsfx program
long sfxnam; // Name offset from start of sfxprog
long ziplen; // size of zip file
} ds = {0x4afb, 0x4afb, 0};
 
 
typedef struct {short len; char chrs[1];} __QP_t;
 
#define __QA(l) struct {short len; char chrs[(l)+1];}
 
#define T1 \
"\nThis is a self-extracting zip archive. In order to process the\n" \
"archive you will be asked to give the name of a temporary directory\n" \
"which must have at least as much free space as this SFX file.\n\n" \
"You will also be asked for the name of the directory to which the\n" \
"files are extracted. This directory _MUST_ exist. If you do not give\n" \
"an output directory, the current default is used.\n\n\n" \
"Device/directory for temporary files: "
#define T2 "Device/directory to extract to : "
 
#define T1LEN (sizeof(T1)-1)
#define T2LEN (sizeof(T2)-1)
 
static void xgetcwd (__QP_t *s)
{
extern char *_sys_var;
static __QP_t **q;
 
if (q = (__QP_t ** q) (_sys_var + 0xAC + 4))
{
memcpy (s->chrs, (*q)->chrs, (*q)->len);
s->len = (*q)->len;
*(s->chrs+s->len) = 0;
}
}
 
int checkdir(__QP_t *dir)
{
qdirect_t s;
int r,ch;
 
if(dir->len > 1)
{
if(*(dir->chrs + dir->len-2) == '_')
{
*(dir->chrs + dir->len-1) = 0;
dir->len--;
}
else
{
*(dir->chrs + dir->len-1) = '_';
}
}
else
{
xgetcwd(dir);
}
 
r = ERR_NF;
 
if((ch = io_open(dir->chrs, 4)) > 0)
{
if((r = fs_headr(ch, -1, &s, sizeof(s))) > 0)
{
r = (s.d_type == 0xff) ? 0 : ERR_NF;
}
io_close(ch);
}
return r;
}
 
int makesfx(__QP_t *tmp)
{
char *p = (char *)&ds;
char *q;
char txt[PATH_MAX];
int fd,r = 0;
qdirect_t qd;
 
memcpy(txt, tmp->chrs, tmp->len);
memcpy(txt+tmp->len, "SFX_EXE", 8);
 
q = p + ds.offset;
if((fd = io_open(txt, NEW_OVER)) > 0)
{
memcpy(txt+tmp->len+4, "DAT", 4);
memcpy(q+ds.sfxnam, txt, tmp->len+8);
fs_save(fd, q, ds.sfxlen);
qd.d_length = ds.sfxlen;
qd.d_datalen = ds.sfxdsiz;
qd.d_type = 1;
fs_heads(fd, -1, &qd, sizeof(qd));
io_close(fd);
if((fd = io_open(txt, NEW_OVER)) > 0)
{
q += ds.sfxlen;
fs_save(fd, q, ds.ziplen);
io_close(fd);
}
else r = fd;
}
else r = fd;
return r;
}
 
#define T3 "\n\nTo extract the files, run the command \"LRUN "
#define T4 "Press any key to exit "
#define T3LEN (sizeof(T3)-1)
#define T4LEN (sizeof(T4)-1)
 
int unpackit ( __QP_t *tmpdir, __QP_t *outdir, char *basfil, int con)
{
int ch, r = 0;
char c;
 
memcpy(basfil, tmpdir->chrs,tmpdir->len);
memcpy(basfil+tmpdir->len,"SFX_BAS", 8);
 
if((ch = io_open(basfil, NEW_OVER)) > 0)
{
char *p,txt[80];
int l;
 
p = txt;
*p++ = 'E';
*p++ = 'W';
*p++ = ' ';
memcpy(p, tmpdir->chrs, tmpdir->len);
p += tmpdir->len;
memcpy(p, "SFX_EXE;'-d ", 12);
p += 12;
memcpy(p, outdir->chrs, outdir->len);
p += outdir->len;
*p++ = '\'';
*p++ = '\n';
io_sstrg(ch, -1, txt, (int)(p-txt));
 
memcpy(txt, "delete ", 7);
p = txt + 7;
memcpy(p, tmpdir->chrs, tmpdir->len);
p += tmpdir->len;
memcpy(p, "SFX_EXE\n", 8);
p += 4;
l = (int)(p+4-txt);
io_sstrg(ch, -1, txt, l);
memcpy(p, "DAT\n", 4);
io_sstrg(ch, -1, txt, l);
memcpy(p, "BAS\n", 4);
io_sstrg(ch, -1, txt, l);
io_close(ch);
makesfx((__QP_t *)tmpdir);
}
else r = ch;
 
if(r == 0)
{
char t3[80];
char *p;
p = t3;
memcpy(p, T3, T3LEN);
p += T3LEN;
memcpy (p, basfil, tmpdir->len+7);
p += tmpdir->len+7;
*p++ = '"';
*p++ = '\n';
io_sstrg(con, -1, t3, (int)(p-t3));
}
io_sstrg(con, -1, T4, T4LEN);
io_fbyte(con, (5*60*50), &c);
return r;
}
 
int main(void)
{
int con;
int r,n;
__QA(PATH_MAX) tmpdir;
__QA(PATH_MAX) outdir;
char basfil[PATH_MAX];
 
con = io_open("con_480x160a16x38", 0);
sd_bordr(con, -1, 7, 2);
sd_clear(con, -1);
sd_cure (con, -1);
 
io_sstrg(con, -1, T1, T1LEN);
if((tmpdir.len = io_fline(con, -1, tmpdir.chrs, PATH_MAX-1)) > 1)
{
if((r = checkdir((__QP_t *)&tmpdir)) == 0)
{
io_sstrg(con, -1, T2, T2LEN);
if((outdir.len = io_fline(con, -1, outdir.chrs, PATH_MAX-1)) > 0)
{
if((r = checkdir((__QP_t *)&outdir)) == 0)
{
r = unpackit ((__QP_t *)&tmpdir, (__QP_t *)&outdir,
basfil, con);
}
}
}
}
sd_bordr(con, -1, 0, 0);
sd_clear(con, -1);
io_close(con);
return r;
}
/programs/fs/unzip60/qdos/config.S
0,0 → 1,154
#
;===========================================================================
; Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
;
; See the accompanying file LICENSE, version 2000-Apr-09 or later
; (the contents of which are also included in unzip.h) for terms of use.
; If, for some reason, all these files are missing, the Info-ZIP license
; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
;===========================================================================
 
.globl _qlflag
.globl _qlwait
#ifdef ZIP
.globl _dtype
#endif
 
.data
ds.w 0
dc.b '<<QCFX>>01'
#ifdef ZIP
dc.w 8
dc.b 'Info-ZIP'
* 12345678901234567890
ds.w 0
dc.w 3
dc.b '?.?'
ds.w 0
#else
dc.w 10
dc.b 'Info-UNZIP'
* 12345678901234567890
ds.w 0
dc.w 3
dc.b '?.?'
ds.w 0
#endif
dc.b 10
dc.b 0
l_4: dc.w _qlwait-l_4
dc.w 0
dc.w 0
l_5: dc.w hpt-l_5
l_6: dc.w hxx-l_6
 
#ifdef ZIP
dc.b 10
dc.b 0
d_4: dc.w _dtype-d_4
dc.w 0
dc.w 0
d_5: dc.w dpt-d_5
d_6: dc.w dxx-d_6
 
#else
dc.b 4
dc.b 0
l5:
dc.w list1-l5
dc.w 0
l5a:
dc.w Postit-l5a ; post proc
l6:
dc.w apt-l6
l7:
dc.w axx-l7
* -------------------------------------
dc.b 4
dc.b 0
l8:
dc.w list2-l8
dc.w 0
l8a:
dc.w Postit-l8a ; post proc
l9:
dc.w bpt-l9
la:
dc.w bxx-la
* -------------------------------------
#endif
dc.w -1 ; end
 
_qlflag:
dc.w 0
_qlwait:
dc.w 250
_dtype:
dc.w 255
 
hpt: dc.w 10
dc.b 'Exit Delay'
* 12345678901234567890
ds.w 0
hxx: dc.w 0
dc.w $ffff
dc.w -1
#ifdef ZIP
dpt: dc.w 14
dc.b 'Directory Type'
* 12345678901234567890
ds.w 0
dxx: dc.w 3
dc.w $ff
dc.w -1
#else
 
list1:
dc.b 0
list2:
dc.b 0
 
apt:
dc.w 11
dc.b 'Unpack Mode'
* 12345678901234567890
.even
axx: dc.b 0
dc.b 0
dc.w 8
dc.b 'SMS/QDOS'
.even
dc.b 1
dc.b 0
dc.w 7
dc.b 'Default'
.even
dc.w -1
.even
bpt:
dc.w 12
dc.b 'Listing Mode'
* 12345678901234567890
.even
bxx:
dc.w 0
dc.w 7
dc.b 'Default'
.even
dc.b 2
dc.b 0
dc.w 8
dc.b 'SMS/QDOS'
* 12345678901234567890
.even
dc.w -1
Postit:
lea.l _qlflag,a0
move.b list1,d0
move.b d0,(a0)
move.b list2,d0
or.b d0,(a0)
moveq #0,d0
rts
#endif
end
/programs/fs/unzip60/qdos/crc68.s
0,0 → 1,99
;===========================================================================
; Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
;
; See the accompanying file LICENSE, version 2000-Apr-09 or later
; (the contents of which are also included in zip.h) for terms of use.
; If, for some reason, all these files are missing, the Info-ZIP license
; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
;===========================================================================
.text
 
.globl _crc32 ; (ulg val, uch *buf, extent bufsize)
.globl _get_crc_table ; ulg *get_crc_table(void)
 
_crc32:
move.l 8(sp),d0
bne valid
moveq #0,d0
rts
valid: movem.l d2/d3,-(sp)
jsr _get_crc_table
move.l d0,a0
move.l 12(sp),d0
move.l 16(sp),a1
move.l 20(sp),d1
not.l d0
 
move.l d1,d2
lsr.l #3,d1
bra decr8
loop8: moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
decr8: dbra d1,loop8
and.w #7,d2
bra decr1
loop1: moveq #0,d3
move.b (a1)+,d3
eor.b d0,d3
lsl.w #2,d3
move.l 0(a0,d3.w),d3
lsr.l #8,d0
eor.l d3,d0
decr1: dbra d2,loop1
done: movem.l (sp)+,d2/d3
not.l d0
rts
/programs/fs/unzip60/qdos/izqdos.h
0,0 → 1,46
/*
Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
 
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in unzip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
#ifndef _IZQDOS_H
#define _IZQDOS_H
 
#include <qdos.h>
typedef struct
{
unsigned short shortid;
struct
{
unsigned char lo;
unsigned char hi;
} len;
char longid[8];
struct qdirect header;
} qdosextra;
 
typedef struct
{
unsigned short shortid;
struct
{
unsigned char lo;
unsigned char hi;
} len;
char longid[4];
struct qdirect header;
} jbextra;
 
#define SHORTID 0x4afb
#define JBSHORTID 0x4afb
#define LONGID "QDOS02"
#define JBLONGID "QZHD"
#define EXTRALEN (sizeof(qdosextra) - 2 * sizeof(char) - sizeof(short))
#define JBEXTRALEN (sizeof(jbextra) - 2 * sizeof(char) - sizeof(short))
 
extern short qlflag;
extern short qlwait;
#endif
/programs/fs/unzip60/qdos/makesfx.c
0,0 → 1,255
/*
Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
 
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in unzip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
/*
* makesfx - Makes a QDOS sfx zip file
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* created by Jonathan Hudson, 04/09/95
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
 
#define SFXFLAG "??Special Flag for unzipsfx hack ??"
 
#ifdef QDOS
# include <qdos.h>
# define ZMODE (X_OK|R_OK)
# define rev_long(x) (x)
# define XFLAG 0x4afb
#else
# define ZMODE (R_OK)
# define getchid(p1) p1
# include <sys/stat.h>
long rev_long(long l);
# define XFLAG 0xfb4a
 
typedef struct
{
long id;
long dlen;
} NTC;
 
struct qdirect {
long d_length __attribute__ ((packed)); /* file length */
unsigned char d_access __attribute__ ((packed)); /* file access type */
unsigned char d_type __attribute__ ((packed)); /* file type */
long d_datalen __attribute__ ((packed)); /* data length */
long d_reserved __attribute__ ((packed));/* Unused */
short d_szname __attribute__ ((packed)); /* size of name */
char d_name[36] __attribute__ ((packed));/* name area */
long d_update __attribute__ ((packed)); /* last update */
long d_refdate __attribute__ ((packed));
long d_backup __attribute__ ((packed)); /* EOD */
} ;
 
int fs_headr (int fd, long t, struct qdirect *qs, short size)
{
NTC ntc;
int r = -1;
struct stat s;
 
fstat(fd, &s);
qs->d_length = s.st_size;
lseek(fd, -8, SEEK_END);
read(fd, &ntc, 8);
if(ntc.id == *(long *)"XTcc")
{
qs->d_datalen = ntc.dlen; /* This is big endian */
qs->d_type = 1;
r = 0;
}
lseek(fd, 0, 0);
return 42; /* why not ??? */
}
 
typedef unsigned char uch;
 
long rev_long (long l)
{
uch cc[4];
cc[0] = (uch)(l >> 24);
cc[1] = (uch)((l >> 16) & 0xff);
cc[2] = (uch)((l >> 8) & 0xff);
cc[3] = (uch)(l & 0xff);
return *(long *)cc;
}
 
#endif
 
#define RBUFSIZ 4096
 
void usage(void)
{
fputs("makesfx -o outfile -z zipfile -xunzipsfx -sstubfile\n", stderr);
exit(0);
}
 
int main (int ac, char **av)
{
int fd, fo;
static char local_sig[4] = "PK\003\004";
char *p, tmp[4];
short ok = 0;
char *of = NULL;
char *xf = NULL;
char *zf = NULL;
char *sf = NULL;
int c;
 
while((c = getopt(ac, av, "o:z:x:s:h")) != EOF)
{
switch(c)
{
case 'o':
of = optarg;
break;
case 'z':
zf = optarg;
break;
case 'x':
xf = optarg;
break;
case 's':
sf = optarg;
break;
case 'h':
usage();
break;
}
}
 
 
if(zf && xf && of && sf)
{
if((fd = open(zf, O_RDONLY)) > 0)
{
if((read(fd, tmp, 4) == 4))
{
if(*(long *)tmp == *(long *)local_sig)
{
ok = 1;
}
}
close(fd);
}
if(!ok)
{
fprintf(stderr,
"Huum, %s doesn't look like a ZIP file to me\n", zf);
exit(0);
}
 
if(strstr(xf, "unzipsfx"))
{
if(access(xf, ZMODE))
{
fprintf(stderr, "Sorry, don't like the look of %s\n", xf);
exit(0);
}
}
 
if((fo = open(of, O_CREAT|O_TRUNC|O_RDWR, 0666)) != -1)
{
struct qdirect sd,xd;
int n;
int dsoff = 0;
int nfoff = 0;
int zlen = 0;
 
if((fd = open(sf, O_RDONLY)) != -1)
{
if(fs_headr(getchid(fd), -1, &sd, sizeof(sd)) > 0)
{
unsigned short *q;
p = malloc(sd.d_length);
n = read(fd, p, sd.d_length);
for(q = (unsigned short *)p;
q != (unsigned short *)(p+sd.d_length); q++)
{
if(*q == XFLAG && *(q+1) == XFLAG)
{
dsoff = (int)q-(int)p;
break;
}
}
write(fo, p, n);
close(fd);
}
}
 
if(dsoff == 0)
{
puts("Fails");
 
exit(0);
}
 
if((fd = open(xf, O_RDONLY)) != -1)
{
char *q;
if(fs_headr(getchid(fd), -1, &xd, sizeof(xd)) > 0)
{
p = realloc(p, xd.d_length);
n = read(fd, p, xd.d_length);
{
for(q = p; q < p+xd.d_length ; q++)
{
if(*q == '?')
{
if(memcmp(q, SFXFLAG, sizeof(SFXFLAG)-1) == 0)
{
nfoff = (int)(q-p);
break;
}
}
}
}
write(fo, p, n);
close(fd);
 
if((fd = open(zf, O_RDONLY)) > 0)
{
p = realloc(p, RBUFSIZ);
while((n = read(fd, p, RBUFSIZ)) > 0)
{
write(fo, p, n);
zlen += n;
}
close(fd);
}
lseek(fo, dsoff+4, SEEK_SET);
n = rev_long((sd.d_length-dsoff));
write(fo, &n, sizeof(long));
n = rev_long(xd.d_length);
write(fo, &n, sizeof(long));
write(fo, &xd.d_datalen, sizeof(long));
n = rev_long(nfoff);
write(fo, &n, sizeof(long));
n = rev_long(zlen);
write(fo, &n, sizeof(long));
close(fo);
}
else
{
close(fd);
fputs("Can't read unzipsfx header", stderr);
exit(0);
}
}
free(p);
}
}
else
usage();
 
return 0;
}
/programs/fs/unzip60/qdos/qdos.c
0,0 → 1,1130
/*
Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
 
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in unzip.h) for terms of use.
If, for some reason, these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
/*---------------------------------------------------------------------------
 
qdos.c
 
QDOS-specific routines for use with Info-ZIP's UnZip 5.3 and later.
 
Contains: Qstrfix()
QFilename()
QMatch()
chowner()
Qgetch()
QReturn()
LastDir()
screensize()
do_wild() <-- generic enough to put in file_io.c?
mapattr()
mapname()
checkdir()
qfix()
close_outfile()
stamp_file()
getp()
version()
 
---------------------------------------------------------------------------*/
 
#define UNZIP_INTERNAL
 
#include "unzip.h"
#include "crypt.h"
#include "ttyio.h"
#include <dirent.h>
#include "izqdos.h"
#include "unzvers.h"
 
#ifndef SFX
char _prog_name[] = "UnZip";
#else
char _prog_name[] = "??Special Flag for unzipsfx hack ??";
#endif
/* sorrid hack at request of GRR follows; hope the compiler stays kind to us */
char _version[] = {UZ_MAJORVER+'0','.',UZ_MINORVER+'0',UZ_PATCHLEVEL+'0'};
char _extra[] = " " UZ_BETALEVEL;
char _copyright[] = "(c) Info-ZIP Group";
char * _endmsg = NULL;
long _stack = 16*1024; /* huge stack (for qdos) */
 
extern void consetup_title(chanid_t,struct WINDOWDEF *);
void (*_consetup)(chanid_t,struct WINDOWDEF *) = consetup_title;
 
struct WINDOWDEF _condetails =
{
2,
1,
0,
7,
500,
220,
2,
30
};
 
 
static jobid_t chowner(chanid_t chan)
{
extern char *_sys_var;
char *scht;
long *cdb;
long jid;
 
scht = *((char **)(_sys_var + 0x78));
cdb = *(long **)((long *)scht + (chan & 0xffff));
jid = *(cdb + 2);
return jid;
}
 
int QReturn(int err)
{
jobid_t me,you;
 
me = getpid();
you = chowner(getchid(0));
 
if((me == you) && ((qlflag & 4) == 0))
{
if(isatty(0) && isatty(2) && qlwait)
{
char c = 0;
fputs("Press a key to exit", stderr);
if((io_fbyte(getchid(0), qlwait, &c) == 0) && c == 27)
{
io_fbyte(getchid(0), -1, &c);
}
}
}
if(err > 0) err = -err; /* We like -ve err nos (exclusively, alas) */
exit(err);
}
 
#ifndef FUNZIP
 
static int created_dir; /* used in mapname(), checkdir() */
static int renamed_fullpath; /* ditto */
 
char *Qstrfix (char *p)
{
char *q;
for (q = p; (q = strstr(q, ".zip"));)
{
*q = '_';
q += 4;
}
return p;
}
 
void QFilename(char *f)
{
char *o,*p,*q = strdup(f);
p = q;
 
if(*q == '.' && *(q+1) == '/') q += 2;
o = q;
 
for(;*q;q++)
{
if(*q == '/') *q = '_';
if((qlflag & 1) == 0)
{
if(*q == '.') *q = '_';
}
}
strcpy(f,o);
free(p);
}
 
int QMatch(uch c1, uch c2)
{
int m =0;
 
if(c1 != c2)
{
if(c1 == '_' && (c2 == '.' || c2 == '/'))
{
m = 1;
}
}
else
{
m = 1;
}
return m;
}
 
 
int Qgetch(void)
{
char ch;
 
if(io_fbyte(getchid(0), -1, &ch) < 0)
{
return EOF;
}
else
{
return (int) ch;
}
}
 
int screensize(int *tt_rows, int *tt_cols)
{
QLRECT_t rect;
 
if(0 == sd_chenq(getchid(1), -1, &rect))
{
if(tt_cols)
*tt_cols = rect.q_width;
if(tt_rows)
*tt_rows = rect.q_height;
}
else
{
if(tt_cols)
*tt_cols = 80;
if(tt_rows)
*tt_rows = 24;
}
return 0;
}
 
 
 
#ifndef SFX
char *LastDir(char *ws)
{
char *p;
char *q = ws;
struct stat s;
 
for(p = ws; *p; p++)
{
if(*p == '_')
{
char c;
 
p++;
c = *p;
*p = 0;
if(stat(ws, &s) == 0 && S_ISDIR(s.st_mode))
{
q = p;
}
*p = c;
}
}
return q;
}
 
 
/**********************/
/* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */
/**********************/
 
char *do_wild(__G__ wildspec)
__GDEF
ZCONST char *wildspec; /* only used first time on a given dir */
{
static DIR *wild_dir = (DIR *)NULL;
static ZCONST char *wildname;
static char *dirname, matchname[FILNAMSIZ];
static int notfirstcall=FALSE, have_dirname, dirnamelen;
struct dirent *file;
char basedir[40];
 
/* Even when we're just returning wildspec, we *always* do so in
* matchname[]--calling routine is allowed to append four characters
* to the returned string, and wildspec may be a pointer to argv[].
*/
if (!notfirstcall) { /* first call: must initialize everything */
char *ws = NULL, *us = NULL;
 
notfirstcall = TRUE;
 
/* break the wildspec into a directory part and a wildcard filename */
 
ws = (char *) iswild(wildspec);
 
if(ws == NULL)
{
strncpy(matchname, wildspec, FILNAMSIZ);
matchname[FILNAMSIZ-1] = '\0';
return matchname;
}
 
us = LastDir(wildspec);
 
if(us == wildspec)
{
dirname = basedir;
getcwd(basedir, sizeof(basedir)-1);
dirnamelen = strlen(basedir);
have_dirname = FALSE;
wildname = wildspec;
} else {
wildname = us; /* point at character after '/' */
dirnamelen = wildname - wildspec;
if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
Info(slide, 0x201, ((char *)slide,
"warning: cannot allocate wildcard buffers\n"));
strncpy(matchname, wildspec, FILNAMSIZ);
matchname[FILNAMSIZ-1] = '\0';
return matchname; /* but maybe filespec was not a wildcard */
}
strncpy(dirname, wildspec, dirnamelen);
dirname[dirnamelen] = '\0'; /* terminate for strcpy below */
have_dirname = TRUE;
}
 
if ((wild_dir = opendir(dirname)) != (DIR *)NULL) {
while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
if (match(file->d_name, wildname, 0 WISEP)) { /* 0=case sens.*/
if (have_dirname) {
strcpy(matchname, dirname);
strcpy(matchname+dirnamelen, file->d_name);
} else
strcpy(matchname, file->d_name);
return matchname;
}
}
/* if we get to here directory is exhausted, so close it */
closedir(wild_dir);
wild_dir = (DIR *)NULL;
}
 
/* return the raw wildspec in case that works (e.g., directory not
* searchable, but filespec was not wild and file is readable) */
strncpy(matchname, wildspec, FILNAMSIZ);
matchname[FILNAMSIZ-1] = '\0';
return matchname;
}
 
/* last time through, might have failed opendir but returned raw wildspec */
if (wild_dir == (DIR *)NULL) {
notfirstcall = FALSE; /* nothing left to try--reset for new wildspec */
if (have_dirname)
free(dirname);
return (char *)NULL;
}
 
/* If we've gotten this far, we've read and matched at least one entry
* successfully (in a previous call), so dirname has been copied into
* matchname already.
*/
while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
if (match(file->d_name, wildname, 0 WISEP)) { /* 0 == case sens. */
if (have_dirname) {
/* strcpy(matchname, dirname); */
strcpy(matchname+dirnamelen, file->d_name);
} else
strcpy(matchname, file->d_name);
return matchname;
}
}
 
closedir(wild_dir); /* have read at least one entry; nothing left */
wild_dir = (DIR *)NULL;
notfirstcall = FALSE; /* reset for new wildspec */
if (have_dirname)
free(dirname);
return (char *)NULL;
 
} /* end function do_wild() */
 
#endif /* !SFX */
 
 
 
 
 
/**********************/
/* Function mapattr() */
/**********************/
 
int mapattr(__G)
__GDEF
{
ulg tmp = G.crec.external_file_attributes;
 
switch (G.pInfo->hostnum) {
case AMIGA_:
tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */
G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
break;
case THEOS_:
tmp &= 0xF1FFFFFFL;
if ((tmp & 0xF0000000L) != 0x40000000L)
tmp &= 0x01FFFFFFL; /* not a dir, mask all ftype bits */
else
tmp &= 0x41FFFFFFL; /* leave directory bit as set */
/* fall through! */
case QDOS_:
case UNIX_:
case VMS_:
case ACORN_:
case ATARI_:
case ATHEOS_:
case BEOS_:
case TANDEM_:
G.pInfo->file_attr = (unsigned)(tmp >> 16);
if (G.pInfo->file_attr != 0 || !G.extra_field) {
return 0;
} else {
/* Some (non-Info-ZIP) implementations of Zip for Unix and
VMS (and probably others ??) leave 0 in the upper 16-bit
part of the external_file_attributes field. Instead, they
store file permission attributes in some extra field.
As a work-around, we search for the presence of one of
these extra fields and fall back to the MSDOS compatible
part of external_file_attributes if one of the known
e.f. types has been detected.
Later, we might implement extraction of the permission
bits from the VMS extra field. But for now, the work-around
should be sufficient to provide "readable" extracted files.
(For ASI Unix e.f., an experimental remap of the e.f.
mode value IS already provided!)
*/
ush ebID;
unsigned ebLen;
uch *ef = G.extra_field;
unsigned ef_len = G.crec.extra_field_length;
int r = FALSE;
 
while (!r && ef_len >= EB_HEADSIZE) {
ebID = makeword(ef);
ebLen = (unsigned)makeword(ef+EB_LEN);
if (ebLen > (ef_len - EB_HEADSIZE))
/* discoverd some e.f. inconsistency! */
break;
switch (ebID) {
case EF_ASIUNIX:
if (ebLen >= (EB_ASI_MODE+2)) {
G.pInfo->file_attr =
(unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
/* force stop of loop: */
ef_len = (ebLen + EB_HEADSIZE);
break;
}
/* else: fall through! */
case EF_PKVMS:
/* "found nondecypherable e.f. with perm. attr" */
r = TRUE;
default:
break;
}
ef_len -= (ebLen + EB_HEADSIZE);
ef += (ebLen + EB_HEADSIZE);
}
if (!r)
return 0;
}
/* fall through! */
/* all remaining cases: expand MSDOS read-only bit into write perms */
case FS_FAT_:
/* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the
* Unix attributes in the upper 16 bits of the external attributes
* field, just like Info-ZIP's Zip for Unix. We try to use that
* value, after a check for consistency with the MSDOS attribute
* bits (see below).
*/
G.pInfo->file_attr = (unsigned)(tmp >> 16);
/* fall through! */
case FS_HPFS_:
case FS_NTFS_:
case MAC_:
case TOPS20_:
default:
/* Ensure that DOS subdir bit is set when the entry's name ends
* in a '/'. Some third-party Zip programs fail to set the subdir
* bit for directory entries.
*/
if ((tmp & 0x10) == 0) {
extent fnlen = strlen(G.filename);
if (fnlen > 0 && G.filename[fnlen-1] == '/')
tmp |= 0x10;
}
/* read-only bit --> write perms; subdir bit --> dir exec bit */
tmp = !(tmp & 1) << 1 | (tmp & 0x10) >> 4;
if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6))
/* keep previous G.pInfo->file_attr setting, when its "owner"
* part appears to be consistent with DOS attribute flags!
*/
return 0;
G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
break;
} /* end switch (host-OS-created-by) */
 
/* for originating systems with no concept of "group," "other," "system": */
umask( (int)(tmp=umask(0)) ); /* apply mask to expanded r/w(/x) perms */
G.pInfo->file_attr &= ~tmp;
 
return 0;
 
} /* end function mapattr() */
 
 
 
/************************/
/* Function mapname() */
/************************/
int mapname(__G__ renamed)
__GDEF
int renamed;
/*
* returns:
* MPN_OK - no problem detected
* MPN_INF_TRUNC - caution (truncated filename)
* MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
* MPN_ERR_SKIP - error -> skip entry
* MPN_ERR_TOOLONG - error -> path is too long
* MPN_NOMEM - error (memory allocation failed) -> skip entry
* [also MPN_VOL_LABEL, MPN_CREATED_DIR]
*/
{
char pathcomp[FILNAMSIZ]; /* path-component buffer */
char *pp, *cp=(char *)NULL; /* character pointers */
char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
int error = MPN_OK;
register unsigned workch; /* hold the character being tested */
 
 
/*---------------------------------------------------------------------------
Initialize various pointers and counters and stuff.
---------------------------------------------------------------------------*/
 
if (G.pInfo->vollabel)
return MPN_VOL_LABEL; /* can't set disk volume labels in SMS/QDOS */
 
/* can create path as long as not just freshening, or if user told us */
G.create_dirs = (!uO.fflag || renamed);
 
created_dir = FALSE; /* not yet */
 
/* user gave full pathname: don't prepend rootpath */
renamed_fullpath = (renamed && (*G.filename == '/'));
 
if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
return MPN_NOMEM; /* initialize path buffer, unless no memory */
 
*pathcomp = '\0'; /* initialize translation buffer */
pp = pathcomp; /* point to translation buffer */
if (uO.jflag) /* junking directories */
cp = (char *)strrchr(G.filename, '/');
if (cp == (char *)NULL) /* no '/' or not junking dirs */
cp = G.filename; /* point to internal zipfile-member pathname */
else
++cp; /* point to start of last component of path */
 
/*---------------------------------------------------------------------------
Begin main loop through characters in filename.
---------------------------------------------------------------------------*/
 
while ((workch = (uch)*cp++) != 0) {
 
switch (workch) {
case '/': /* can assume -j flag not given */
*pp = '\0';
if (((error = checkdir(__G__ pathcomp, APPEND_DIR))
& MPN_MASK) > MPN_INF_TRUNC)
return error;
pp = pathcomp; /* reset conversion buffer for next piece */
lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
break;
 
case '.':
if (pp == pathcomp) { /* nothing appended yet... */
if (*cp == '/') { /* don't bother appending "./" to */
++cp; /* the path: skip behind the '/' */
break;
} else if (!uO.ddotflag && *cp == '.' && cp[1] == '/') {
/* "../" dir traversal detected */
cp += 2; /* skip over behind the '/' */
killed_ddot = TRUE; /* set "show message" flag */
break;
}
}
*pp++ = (((qlflag & 1) == 0) ? '_' : '.');
break;
 
case ';': /* VMS version (or DEC-20 attrib?) */
lastsemi = pp;
*pp++ = ';'; /* keep for now; remove VMS ";##" */
break; /* later, if requested */
 
default:
/* allow European characters in filenames: */
if (isprint(workch) || (128 <= workch && workch <= 254))
*pp++ = (char)workch;
} /* end switch */
 
} /* end while loop */
 
/* Show warning when stripping insecure "parent dir" path components */
if (killed_ddot && QCOND2) {
Info(slide, 0, ((char *)slide,
"warning: skipped \"../\" path component(s) in %s\n",
FnFilter1(G.filename)));
if (!(error & ~MPN_MASK))
error = (error & MPN_MASK) | PK_WARN;
}
 
/*---------------------------------------------------------------------------
Report if directory was created (and no file to create: filename ended
in '/'), check name to be sure it exists, and combine path and name be-
fore exiting.
---------------------------------------------------------------------------*/
 
if (G.filename[strlen(G.filename) - 1] == '/') {
G.filename[strlen(G.filename) - 1] = '_';
checkdir(__G__ G.filename, GETPATH);
if (created_dir) {
if (QCOND2) {
Info(slide, 0, ((char *)slide, " creating: %s\n",
FnFilter1(G.filename)));
}
/* set dir time (note trailing '/') */
return (error & ~MPN_MASK) | MPN_CREATED_DIR;
}
/* dir existed already; don't look for data to extract */
return (error & ~MPN_MASK) | MPN_INF_SKIP;
}
 
*pp = '\0'; /* done with pathcomp: terminate it */
 
/* if not saving them, remove VMS version numbers (appended ";###") */
if (!uO.V_flag && lastsemi) {
pp = lastsemi + 1;
while (isdigit((uch)(*pp)))
++pp;
if (*pp == '\0') /* only digits between ';' and end: nuke */
*lastsemi = '\0';
}
 
if (*pathcomp == '\0') {
Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
FnFilter1(G.filename)));
return (error & ~MPN_MASK) | MPN_ERR_SKIP;
}
 
checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
checkdir(__G__ G.filename, GETPATH);
 
return error;
 
} /* end function mapname() */
 
 
 
 
/***********************/
/* Function checkdir() */
/***********************/
 
int checkdir(__G__ pathcomp, flag)
__GDEF
char *pathcomp;
int flag;
/*
* returns:
* MPN_OK - no problem detected
* MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
* MPN_INF_SKIP - path doesn't exist, not allowed to create
* MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
* exists and is not a directory, but is supposed to be
* MPN_ERR_TOOLONG - path is too long
* MPN_NOMEM - can't allocate memory for filename buffers
*/
{
static int rootlen = 0; /* length of rootpath */
static char *rootpath; /* user's "extract-to" directory */
static char *buildpath; /* full path (so far) to extracted file */
static char *end; /* pointer to end of buildpath ('\0') */
 
# define FN_MASK 7
# define FUNCTION (flag & FN_MASK)
 
 
/*---------------------------------------------------------------------------
APPEND_DIR: append the path component to the path being built and check
for its existence. If doesn't exist and we are creating directories, do
so for this one; else signal success or error as appropriate.
---------------------------------------------------------------------------*/
 
if (FUNCTION == APPEND_DIR) {
int too_long = FALSE;
#ifdef SHORT_NAMES
char *old_end = end;
#endif
 
Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
while ((*end = *pathcomp++) != '\0')
++end;
#ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */
if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
*(end = old_end + FILENAME_MAX) = '\0';
#endif
 
/* GRR: could do better check, see if overrunning buffer as we go:
* check end-buildpath after each append, set warning variable if
* within 20 of FILNAMSIZ; then if var set, do careful check when
* appending. Clear variable when begin new path. */
 
if ((end-buildpath) > FILNAMSIZ-2) /* need '/', one-char name, '\0' */
too_long = TRUE; /* check if extracting directory? */
if (stat(buildpath, &G.statbuf)) { /* path doesn't exist */
if (!G.create_dirs) { /* told not to create (freshening) */
free(buildpath);
return MPN_INF_SKIP; /* path doesn't exist: nothing to do */
}
if (too_long) {
Info(slide, 1, ((char *)slide,
"checkdir error: path too long: %s\n",
FnFilter1(buildpath)));
free(buildpath);
/* no room for filenames: fatal */
return MPN_ERR_TOOLONG;
}
if (mkdir(buildpath, 0777) == -1) { /* create the directory */
Info(slide, 1, ((char *)slide,
"checkdir error: cannot create %s\n\
unable to process %s.\n",
FnFilter2(buildpath), FnFilter1(G.filename)));
free(buildpath);
/* path didn't exist, tried to create, failed */
return MPN_ERR_SKIP;
}
created_dir = TRUE;
} else if (!S_ISDIR(G.statbuf.st_mode)) {
Info(slide, 1, ((char *)slide,
"checkdir error: %s exists but is not directory\n\
unable to process %s.\n",
FnFilter2(buildpath), FnFilter1(G.filename)));
free(buildpath);
/* path existed but wasn't dir */
return MPN_ERR_SKIP;
}
if (too_long) {
Info(slide, 1, ((char *)slide,
"checkdir error: path too long: %s\n", FnFilter1(buildpath)));
free(buildpath);
/* no room for filenames: fatal */
return MPN_ERR_TOOLONG;
}
*end++ = '_';
*end = '\0';
Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
return MPN_OK;
 
} /* end if (FUNCTION == APPEND_DIR) */
 
/*---------------------------------------------------------------------------
GETPATH: copy full path to the string pointed at by pathcomp, and free
buildpath.
---------------------------------------------------------------------------*/
 
if (FUNCTION == GETPATH) {
strcpy(pathcomp, buildpath);
Trace((stderr, "getting and freeing path [%s]\n",
FnFilter1(pathcomp)));
free(buildpath);
buildpath = end = (char *)NULL;
return MPN_OK;
}
 
/*---------------------------------------------------------------------------
APPEND_NAME: assume the path component is the filename; append it and
return without checking for existence.
---------------------------------------------------------------------------*/
 
if (FUNCTION == APPEND_NAME) {
#ifdef SHORT_NAMES
char *old_end = end;
#endif
short dlen;
 
Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
while ((*end = *pathcomp++) != '\0') {
++end;
#ifdef SHORT_NAMES /* truncate name at 14 characters, typically */
if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
*(end = old_end + FILENAME_MAX) = '\0';
#endif
if (isdirdev(buildpath))
{
dlen = 5;
}
else
{
dlen = 0;
}
 
if ((end-buildpath-dlen) >= FILNAMSIZ) {
*--end = '\0';
Info(slide, 0x201, ((char *)slide,
"checkdir warning: path too long; truncating\n\
%s\n -> %s\n",
FnFilter1(G.filename), FnFilter2(buildpath)));
return MPN_INF_TRUNC; /* filename truncated */
}
}
Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
/* could check for existence here, prompt for new name... */
return MPN_OK;
}
 
/*---------------------------------------------------------------------------
INIT: allocate and initialize buffer space for the file currently being
extracted. If file was renamed with an absolute path, don't prepend the
extract-to path.
---------------------------------------------------------------------------*/
 
/* GRR: for VMS and TOPS-20, add up to 13 to strlen */
 
if (FUNCTION == INIT) {
Trace((stderr, "initializing buildpath to "));
if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1))
== (char *)NULL)
return MPN_NOMEM;
if ((rootlen > 0) && !renamed_fullpath) {
strcpy(buildpath, rootpath);
end = buildpath + rootlen;
} else {
*buildpath = '\0';
end = buildpath;
}
Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
return MPN_OK;
}
 
/*---------------------------------------------------------------------------
ROOT: if appropriate, store the path in rootpath and create it if
necessary; else assume it's a zipfile member and return. This path
segment gets used in extracting all members from every zipfile specified
on the command line.
---------------------------------------------------------------------------*/
 
#if (!defined(SFX) || defined(SFX_EXDIR))
if (FUNCTION == ROOT) {
Trace((stderr, "initializing root path to [%s]\n",
FnFilter1(pathcomp)));
if (pathcomp == (char *)NULL) {
rootlen = 0;
return MPN_OK;
}
if (rootlen > 0) /* rootpath was already set, nothing to do */
return MPN_OK;
if ((rootlen = strlen(pathcomp)) > 0) {
char *tmproot;
 
if ((tmproot = (char *)malloc(rootlen+2)) == (char *)NULL) {
rootlen = 0;
return MPN_NOMEM;
}
strcpy(tmproot, pathcomp);
if ((stat(tmproot, &G.statbuf) ||
!S_ISDIR(G.statbuf.st_mode)))
{ /* path does not exist */
if (!G.create_dirs /* || iswild(tmproot) */ ) {
free(tmproot);
rootlen = 0;
/* skip (or treat as stored file) */
return MPN_INF_SKIP;
}
/* create the directory (could add loop here scanning tmproot
* to create more than one level, but why really necessary?) */
if (mkdir(tmproot, 0777) == -1) {
Info(slide, 1, ((char *)slide,
"checkdir: cannot create extraction directory: %s\n",
FnFilter1(tmproot)));
free(tmproot);
rootlen = 0;
/* path didn't exist, tried to create, and failed: */
/* file exists, or 2+ subdir levels required */
return MPN_ERR_SKIP;
}
}
if (tmproot[rootlen-1] == '/' || tmproot[rootlen-1] == '_') {
tmproot[--rootlen] = '\0';
}
tmproot[rootlen++] = '_';
tmproot[rootlen] = '\0';
if ((rootpath = (char *)realloc(tmproot, rootlen+1)) == NULL) {
free(tmproot);
rootlen = 0;
return MPN_NOMEM;
}
}
Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
return MPN_OK;
}
#endif /* !SFX || SFX_EXDIR */
 
/*---------------------------------------------------------------------------
END: free rootpath, immediately prior to program exit.
---------------------------------------------------------------------------*/
 
if (FUNCTION == END) {
Trace((stderr, "freeing rootpath\n"));
if (rootlen > 0) {
free(rootpath);
rootlen = 0;
}
return MPN_OK;
}
 
return MPN_INVALID; /* should never reach */
 
} /* end function checkdir() */
 
 
static void qfix(__G__ ef_ptr, ef_len)
__GDEF
uch *ef_ptr;
unsigned ef_len;
{
qdosextra qextra;
 
while (ef_len >= EB_HEADSIZE)
{
qdosextra *extra = &qextra;
jbextra *jbp = (jbextra *)&qextra;
unsigned eb_len = makeword(EB_LEN + ef_ptr);
 
if (eb_len > (ef_len - EB_HEADSIZE)) {
/* discovered some extra field inconsistency! */
Trace((stderr,
"qfix: block length %u > rest ef_size %u\n", eb_len,
ef_len - EB_HEADSIZE));
break;
}
 
/* Must ensure that we don't use ODD addresses here */
 
memcpy(&qextra, ef_ptr, sizeof(qdosextra));
switch (extra->shortid) {
case SHORTID:
if (!strncmp(extra->longid, LONGID, strlen(LONGID)))
{
if (eb_len != EXTRALEN)
fputs("warning: invalid length in Qdos field", stderr);
if (extra->header.d_type)
{
fs_heads(fgetchid(G.outfile), (timeout_t)-1,
&extra->header, 14);
G.pInfo->file_attr |= S_IXUSR;
}
}
 
if (!strncmp(jbp->longid, JBLONGID, strlen(JBLONGID)))
{
if (eb_len != JBEXTRALEN)
fputs("warning: invalid length in QZ field", stderr);
if (jbp->header.d_type)
{
fs_heads(fgetchid(G.outfile), (timeout_t)-1,
&jbp->header, 14);
G.pInfo->file_attr |= S_IXUSR;
}
}
break;
 
default:
Trace((stderr,"qfix: unknown extra field block, ID=%d\n",
extra->shortid));
break;
}
 
/* Skip this extra field block */
ef_ptr += (eb_len + EB_HEADSIZE);
ef_len -= (eb_len + EB_HEADSIZE);
}
}
 
 
#ifdef QDOS
# include <utime.h>
long timezone = 0;
#endif
 
 
/****************************/
/* Function close_outfile() */
/****************************/
 
void close_outfile(__G)
__GDEF
{
union {
iztimes t3; /* mtime, atime, ctime */
struct utimbuf t2; /* modtime, actime */
} zt;
#ifdef USE_EF_UT_TIME
unsigned eb_izux_flg;
#endif
 
if (G.extra_field) {
qfix(__G__ G.extra_field, G.lrec.extra_field_length);
}
 
fclose(G.outfile);
 
/*---------------------------------------------------------------------------
Change the file permissions from default ones to those stored in the
zipfile.
---------------------------------------------------------------------------*/
 
#ifndef NO_CHMOD
if (chmod(G.filename, 0xffff & G.pInfo->file_attr))
perror("chmod (file attributes) error");
#endif
 
/*---------------------------------------------------------------------------
Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
time: adjust base year from 1980 to 1970, do usual conversions from
yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
light savings time differences. If we have a Unix extra field, however,
we're laughing: both mtime and atime are ours.
---------------------------------------------------------------------------*/
 
/* skip restoring time stamps on user's request */
if (uO.D_flag <= 1) {
#ifdef USE_EF_UT_TIME
eb_izux_flg = (G.extra_field ? ef_scan_for_izux(G.extra_field,
G.lrec.extra_field_length, 0,
G.lrec.last_mod_dos_datetime,
#ifdef IZ_CHECK_TZ
(G.tz_is_valid ? &(zt.t3) : NULL),
#else
&(zt.t3),
#endif
NULL) : 0);
if (eb_izux_flg & EB_UT_FL_MTIME) {
TTrace((stderr,
"\nclose_outfile: Unix e.f. modif. time = %ld\n",
zt.t3.mtime));
} else {
zt.t3.mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
}
if (eb_izux_flg & EB_UT_FL_ATIME) {
TTrace((stderr,
"close_outfile: Unix e.f. access time = %ld\n",
zt.t3.atime));
} else {
zt.t3.atime = zt.t3.mtime;
TTrace((stderr,
"\nclose_outfile: modification/access times = %ld\n",
zt.t3.mtime));
}
#else
zt.t3.atime = zt.t3.mtime
= dos_to_unix_time(G.lrec.last_mod_dos_datetime);
#endif
 
/* set the file's access and modification times */
if (utime(G.filename, &(zt.t2))) {
Info(slide, 0x201, ((char *)slide,
"warning: cannot set the time for %s\n",
FnFilter1(G.filename)));
}
}
 
} /* end function close_outfile() */
 
 
 
 
#ifdef TIMESTAMP
 
/***************************/
/* Function stamp_file() */
/***************************/
 
int stamp_file(fname, modtime)
ZCONST char *fname;
time_t modtime;
{
struct utimbuf tp;
 
tp.modtime = tp.actime = modtime;
return (utime(fname, &tp));
 
} /* end function stamp_file() */
 
#endif /* TIMESTAMP */
 
 
 
 
#ifndef SFX
 
/************************/
/* Function version() */
/************************/
 
void version(__G)
__GDEF
{
 
sprintf((char *)slide, LoadFarString(CompiledWith),
"c68", " v4.2x", "SMS/QDOS",
" on ", __DATE__, "","");
(*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
 
} /* end function version() */
 
#endif /* !SFX */
#endif /* !FUNZIP */
 
#if CRYPT
 
char *getp(__G__ m, p, n)
__GDEF
const char *m; /* prompt for password */
char *p; /* return value: line input */
int n; /* bytes available in p[] */
{
int c; /* one-byte buffer for read() to use */
int i; /* number of characters input */
char *w; /* warning on retry */
 
/* get password */
w = "";
sd_cure(getchid(0), -1); /* enable cursor */
do {
fputs(w, stderr); /* warning if back again */
fputs(m, stderr); /* display prompt and flush */
fflush(stderr);
i = 0;
do {
c = getch();
if (c == 0xc2) {
if (i > 0) {
i--; /* the `del' keys works */
fputs("\b \b", stderr);
}
}
else if (i < n) {
p[i++] = c; /* truncate past n */
if(c != '\n') putc('*', stderr);
}
} while (c != '\n');
 
putc('\n', stderr); fflush(stderr);
w = "(line too long--try again)\n";
} while (p[i-1] != '\n');
 
p[i-1] = 0; /* terminate at newline */
sd_curs(getchid(0), -1); /* suppress cursor */
return p; /* return pointer to password */
 
} /* end function getp() */
 
#endif /* CRYPT */