/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 */ |