bc and mtools out of the base system (gpl)

This commit is contained in:
Ben Gras 2007-04-20 12:06:14 +00:00
parent 0a0f800805
commit ac41dcd35f
111 changed files with 1 additions and 30185 deletions

View file

@ -4,7 +4,7 @@ MAKE = exec make -$(MAKEFLAGS)
BZIP2=bzip2-1.0.3
FLEX=flex-2.5.4
SMALLPROGRAMS=`arch` aal advent ash autil awk bc byacc cawf cron de dhcpd dis88 elle elvis ftp101 ftpd200 ibm indent m4 make mdb mined patch pax profile ps reboot rlogind scripts sh simple syslogd talk talkd telnet telnetd urlget yap zoneinfo
SMALLPROGRAMS=`arch` aal advent ash autil awk byacc cawf cron de dhcpd dis88 elle elvis ftp101 ftpd200 ibm indent m4 make mdb mined patch pax profile ps reboot rlogind scripts sh simple syslogd talk talkd telnet telnetd urlget yap zoneinfo
usage:
@echo "Usage: make all # Compile all commands" >&2

View file

@ -1,341 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View file

@ -1,89 +0,0 @@
# Makefile for bc
# A makefile for bc. This is part of the bc/sbc distribution.
#
#
# Make sure these have the correct directories for your machine.
#
# LIBDIR and BINDIR are where bc and libmath.b will be put.
#
PREFIX = /usr
LIBDIR = $(PREFIX)/lib
BINDIR = $(PREFIX)/bin
#
# Programs definitions for use by make.
#
SHELL = /bin/sh
YACC = yacc
#YACC = bison -y
LEX = flex -I8
#LEX = lex
CC = exec cc
CFLAGS = -D_POSIX_SOURCE
LDFLAGS = -i
#
#
OFILES = scan.o util.o main.o number.o storage.o load.o execute.o
#
SUBDIRS = Examples Test
#
all: bc
bc: $& config.h bc.o $(OFILES) global.o
$(CC) -o bc $(LDFLAGS) bc.o $(OFILES) global.o
sbc: sbc.o $(OFILES) global.o
$(CC) -o sbc $(LDFLAGS) sbc.o $(OFILES) global.o
math.h: libmath.b
$(MAKE) -$(MAKEFLAGS) fbc
./fbc -c libmath.b </dev/null >math.h
/bin/sh ./fix_math.h
rm -f ./fbc
fbc: $(OFILES) bc.o
echo \"\" > math.h
$(CC) -c $(CFLAGS) global.c
$(CC) -o fbc $(LDFLAGS) bc.o $(OFILES) global.o
install: $(BINDIR)/bc $(LIBDIR)/libmath.b
$(BINDIR)/bc: bc
install -cs -o bin $? $@
$(LIBDIR)/libmath.b: libmath.b
install -c -o bin $? $@
clean:
rm -f *.o *.bak core math.h bc sbc
scan.c: scan.l
$(LEX) scan.l
mv lex.yy.c scan.c
scan.o: scan.c
$(CC) -c $(CFLAGS) -wa scan.c
y.tab.h bc.c: bc.y
@echo "expect 1 shift/reduce conflict"
$(YACC) -d bc.y
mv y.tab.c bc.c
sbc.c: sbc.y
$(YACC) -d sbc.y
mv y.tab.c sbc.c
global.o: bcdefs.h global.h math.h
bc.o: bcdefs.h global.h
execute.o: bcdefs.h global.h
load.o: bcdefs.h global.h
main.o: bcdefs.h global.h version.h
number.o: bcdefs.h
sbc.o: bcdefs.h global.h
scan.o: y.tab.h bcdefs.h global.h
storage.o: bcdefs.h global.h
util.o: bcdefs.h global.h version.h
bcdefs.h: number.h const.h config.h
touch bcdefs.h

File diff suppressed because it is too large Load diff

View file

@ -1,612 +0,0 @@
%{
/* bc.y: The grammar for a POSIX compatable bc processor with some
extensions to the language. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h"
#include "proto.h"
%}
%start program
%union {
char *s_value;
char c_value;
int i_value;
arg_list *a_value;
}
/* Extensions over POSIX bc.
a) NAME was LETTER. This grammer allows longer names.
Single letter names will still work.
b) Relational_expression allowed only one comparison.
This grammar has added boolean expressions with
&& (and) || (or) and ! (not) and allowed all of them in
full expressions.
c) Added an else to the if.
d) Call by variable array parameters
e) read() procedure that reads a number under program control from stdin.
f) halt statement that halts the the program under program control. It
is an executed statement.
g) continue statement for for loops.
h) optional expressions in the for loop.
i) print statement to print multiple numbers per line.
j) warranty statement to print an extended warranty notice.
j) limits statement to print the processor's limits.
*/
%token <i_value> NEWLINE AND OR NOT
%token <s_value> STRING NAME NUMBER
/* '-', '+' are tokens themselves */
%token <c_value> MUL_OP
/* '*', '/', '%' */
%token <c_value> ASSIGN_OP
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
%token <s_value> REL_OP
/* '==', '<=', '>=', '!=', '<', '>' */
%token <c_value> INCR_DECR
/* '++', '--' */
%token <i_value> Define Break Quit Length
/* 'define', 'break', 'quit', 'length' */
%token <i_value> Return For If While Sqrt Else
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
%token <i_value> Scale Ibase Obase Auto Read
/* 'scale', 'ibase', 'obase', 'auto', 'read' */
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
/* Types of all other things. */
%type <i_value> expression return_expression named_expression opt_expression
%type <c_value> '+' '-'
%type <a_value> opt_parameter_list opt_auto_define_list define_list
%type <a_value> opt_argument_list argument_list
%type <i_value> program input_item semicolon_list statement_list
%type <i_value> statement function statement_or_error
/* precedence */
%left OR
%left AND
%nonassoc NOT
%left REL_OP
%right ASSIGN_OP
%left '+' '-'
%left MUL_OP
%right '^'
%nonassoc UNARY_MINUS
%nonassoc INCR_DECR
%%
program : /* empty */
{
$$ = 0;
if (interactive)
{
printf ("%s\n", BC_VERSION);
welcome ();
}
}
| program input_item
;
input_item : semicolon_list NEWLINE
{ run_code (); }
| function
{ run_code (); }
| error NEWLINE
{
yyerrok;
init_gen ();
}
;
semicolon_list : /* empty */
{ $$ = 0; }
| statement_or_error
| semicolon_list ';' statement_or_error
| semicolon_list ';'
;
statement_list : /* empty */
{ $$ = 0; }
| statement_or_error
| statement_list NEWLINE
| statement_list NEWLINE statement_or_error
| statement_list ';'
| statement_list ';' statement
;
statement_or_error : statement
| error statement
{ $$ = $2; }
;
statement : Warranty
{ warranty (""); }
| Limits
{ limits (); }
| expression
{
if ($1 & 2)
warn ("comparison in expression");
if ($1 & 1)
generate ("W");
else
generate ("p");
}
| STRING
{
$$ = 0;
generate ("w");
generate ($1);
free ($1);
}
| Break
{
if (break_label == 0)
yyerror ("Break outside a for/while");
else
{
sprintf (genstr, "J%1d:", break_label);
generate (genstr);
}
}
| Continue
{
warn ("Continue statement");
if (continue_label == 0)
yyerror ("Continue outside a for");
else
{
sprintf (genstr, "J%1d:", continue_label);
generate (genstr);
}
}
| Quit
{ exit (0); }
| Halt
{ generate ("h"); }
| Return
{ generate ("0R"); }
| Return '(' return_expression ')'
{ generate ("R"); }
| For
{
$1 = break_label;
break_label = next_label++;
}
'(' opt_expression ';'
{
if ($4 > 1)
warn ("Comparison in first for expression");
$4 = next_label++;
if ($4 < 0)
sprintf (genstr, "N%1d:", $4);
else
sprintf (genstr, "pN%1d:", $4);
generate (genstr);
}
opt_expression ';'
{
if ($7 < 0) generate ("1");
$7 = next_label++;
sprintf (genstr, "B%1d:J%1d:", $7, break_label);
generate (genstr);
$<i_value>$ = continue_label;
continue_label = next_label++;
sprintf (genstr, "N%1d:", continue_label);
generate (genstr);
}
opt_expression ')'
{
if ($10 > 1)
warn ("Comparison in third for expression");
if ($10 < 0)
sprintf (genstr, "J%1d:N%1d:", $4, $7);
else
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
generate (genstr);
}
statement
{
sprintf (genstr, "J%1d:N%1d:",
continue_label, break_label);
generate (genstr);
break_label = $1;
continue_label = $<i_value>9;
}
| If '(' expression ')'
{
$3 = if_label;
if_label = next_label++;
sprintf (genstr, "Z%1d:", if_label);
generate (genstr);
}
statement opt_else
{
sprintf (genstr, "N%1d:", if_label);
generate (genstr);
if_label = $3;
}
| While
{
$1 = next_label++;
sprintf (genstr, "N%1d:", $1);
generate (genstr);
}
'(' expression
{
$4 = break_label;
break_label = next_label++;
sprintf (genstr, "Z%1d:", break_label);
generate (genstr);
}
')' statement
{
sprintf (genstr, "J%1d:N%1d:", $1, break_label);
generate (genstr);
break_label = $4;
}
| '{' statement_list '}'
{ $$ = 0; }
| Print
{ warn ("print statement"); }
print_list
;
print_list : print_element
| print_element ',' print_list
;
print_element : STRING
{
generate ("O");
generate ($1);
free ($1);
}
| expression
{ generate ("P"); }
;
opt_else : /* nothing */
| Else
{
warn ("else clause in if statement");
$1 = next_label++;
sprintf (genstr, "J%d:N%1d:", $1, if_label);
generate (genstr);
if_label = $1;
}
statement
function : Define NAME '(' opt_parameter_list ')' '{'
NEWLINE opt_auto_define_list
{
/* Check auto list against parameter list? */
check_params ($4,$8);
sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
arg_str ($4,TRUE), arg_str ($8,TRUE));
generate (genstr);
free_args ($4);
free_args ($8);
$1 = next_label;
next_label = 0;
}
statement_list NEWLINE '}'
{
generate ("0R]");
next_label = $1;
}
;
opt_parameter_list : /* empty */
{ $$ = NULL; }
| define_list
;
opt_auto_define_list : /* empty */
{ $$ = NULL; }
| Auto define_list NEWLINE
{ $$ = $2; }
| Auto define_list ';'
{ $$ = $2; }
;
define_list : NAME
{ $$ = nextarg (NULL, lookup ($1,SIMPLE)); }
| NAME '[' ']'
{ $$ = nextarg (NULL, lookup ($1,ARRAY)); }
| define_list ',' NAME
{ $$ = nextarg ($1, lookup ($3,SIMPLE)); }
| define_list ',' NAME '[' ']'
{ $$ = nextarg ($1, lookup ($3,ARRAY)); }
;
opt_argument_list : /* empty */
{ $$ = NULL; }
| argument_list
;
argument_list : expression
{
if ($1 > 1) warn ("comparison in argument");
$$ = nextarg (NULL,0);
}
| NAME '[' ']'
{
sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
generate (genstr);
$$ = nextarg (NULL,1);
}
| argument_list ',' expression
{
if ($3 > 1) warn ("comparison in argument");
$$ = nextarg ($1,0);
}
| argument_list ',' NAME '[' ']'
{
sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
generate (genstr);
$$ = nextarg ($1,1);
}
;
opt_expression : /* empty */
{
$$ = -1;
warn ("Missing expression in for statement");
}
| expression
;
return_expression : /* empty */
{
$$ = 0;
generate ("0");
}
| expression
{
if ($1 > 1)
warn ("comparison in return expresion");
}
;
expression : named_expression ASSIGN_OP
{
if ($2 != '=')
{
if ($1 < 0)
sprintf (genstr, "DL%d:", -$1);
else
sprintf (genstr, "l%d:", $1);
generate (genstr);
}
}
expression
{
if ($4 > 1) warn("comparison in assignment");
if ($2 != '=')
{
sprintf (genstr, "%c", $2);
generate (genstr);
}
if ($1 < 0)
sprintf (genstr, "S%d:", -$1);
else
sprintf (genstr, "s%d:", $1);
generate (genstr);
$$ = 0;
}
;
| expression AND
{
warn("&& operator");
$2 = next_label++;
sprintf (genstr, "DZ%d:p", $2);
generate (genstr);
}
expression
{
sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
generate (genstr);
$$ = $1 | $4;
}
| expression OR
{
warn("|| operator");
$2 = next_label++;
sprintf (genstr, "B%d:", $2);
generate (genstr);
}
expression
{
int tmplab;
tmplab = next_label++;
sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
$2, tmplab, $2, tmplab);
generate (genstr);
$$ = $1 | $4;
}
| NOT expression
{
$$ = $2;
warn("! operator");
generate ("!");
}
| expression REL_OP expression
{
$$ = 3;
switch (*($2))
{
case '=':
generate ("=");
break;
case '!':
generate ("#");
break;
case '<':
if ($2[1] == '=')
generate ("{");
else
generate ("<");
break;
case '>':
if ($2[1] == '=')
generate ("}");
else
generate (">");
break;
}
}
| expression '+' expression
{
generate ("+");
$$ = $1 | $3;
}
| expression '-' expression
{
generate ("-");
$$ = $1 | $3;
}
| expression MUL_OP expression
{
genstr[0] = $2;
genstr[1] = 0;
generate (genstr);
$$ = $1 | $3;
}
| expression '^' expression
{
generate ("^");
$$ = $1 | $3;
}
| '-' expression %prec UNARY_MINUS
{
generate ("n");
$$ = $2;
}
| named_expression
{
$$ = 1;
if ($1 < 0)
sprintf (genstr, "L%d:", -$1);
else
sprintf (genstr, "l%d:", $1);
generate (genstr);
}
| NUMBER
{
int len = strlen($1);
$$ = 1;
if (len == 1 && *$1 == '0')
generate ("0");
else if (len == 1 && *$1 == '1')
generate ("1");
else
{
generate ("K");
generate ($1);
generate (":");
}
free ($1);
}
| '(' expression ')'
{ $$ = $2 | 1; }
| NAME '(' opt_argument_list ')'
{
$$ = 1;
if ($3 != NULL)
{
sprintf (genstr, "C%d,%s:",
lookup ($1,FUNCT),
arg_str ($3,FALSE));
free_args ($3);
}
else
{
sprintf (genstr, "C%d:", lookup ($1,FUNCT));
}
generate (genstr);
}
| INCR_DECR named_expression
{
$$ = 1;
if ($2 < 0)
{
if ($1 == '+')
sprintf (genstr, "DA%d:L%d:", -$2, -$2);
else
sprintf (genstr, "DM%d:L%d:", -$2, -$2);
}
else
{
if ($1 == '+')
sprintf (genstr, "i%d:l%d:", $2, $2);
else
sprintf (genstr, "d%d:l%d:", $2, $2);
}
generate (genstr);
}
| named_expression INCR_DECR
{
$$ = 1;
if ($1 < 0)
{
sprintf (genstr, "DL%d:x", -$1);
generate (genstr);
if ($2 == '+')
sprintf (genstr, "A%d:", -$1);
else
sprintf (genstr, "M%d:", -$1);
}
else
{
sprintf (genstr, "l%d:", $1);
generate (genstr);
if ($2 == '+')
sprintf (genstr, "i%d:", $1);
else
sprintf (genstr, "d%d:", $1);
}
generate (genstr);
}
| Length '(' expression ')'
{ generate ("cL"); $$ = 1;}
| Sqrt '(' expression ')'
{ generate ("cR"); $$ = 1;}
| Scale '(' expression ')'
{ generate ("cS"); $$ = 1;}
| Read '(' ')'
{
warn ("read function");
generate ("cI"); $$ = 1;
}
;
named_expression : NAME
{ $$ = lookup($1,SIMPLE); }
| NAME '[' expression ']'
{
if ($3 > 1) warn("comparison in subscript");
$$ = lookup($1,ARRAY);
}
| Ibase
{ $$ = 0; }
| Obase
{ $$ = 1; }
| Scale
{ $$ = 2; }
| Last
{ $$ = 3; }
;
%%

View file

@ -1,154 +0,0 @@
/* bcdefs.h: The single file to include all constants and type definitions. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* Include the configuration file. */
#include "config.h"
/* Standard includes for all files. */
#include <stdio.h>
#include <sys/types.h>
#include <ctype.h>
#ifdef STRINGS_H
#include <strings.h>
#else
#include <string.h>
#endif
#ifndef NO_LIMITS
#include <limits.h>
#endif
/* Include the other definitions. */
#include "const.h"
#include "number.h"
/* These definitions define all the structures used in
code and data storage. This includes the representation of
labels. The "guiding" principle is to make structures that
take a minimum of space when unused but can be built to contain
the full structures. */
/* Labels are first. Labels are generated sequentially in functions
and full code. They just "point" to a single bye in the code. The
"address" is the byte number. The byte number is used to get an
actual character pointer. */
typedef struct bc_label_group
{
long l_adrs [ BC_LABEL_GROUP ];
struct bc_label_group *l_next;
} bc_label_group;
/* Each function has its own code segments and labels. There can be
no jumps between functions so labels are unique to a function. */
typedef struct arg_list
{
int av_name;
struct arg_list *next;
} arg_list;
typedef struct
{
char f_defined; /* Is this function defined yet. */
char *f_body[BC_MAX_SEGS];
int f_code_size;
bc_label_group *f_label;
arg_list *f_params;
arg_list *f_autos;
} bc_function;
/* Code addresses. */
typedef struct {
int pc_func;
int pc_addr;
} program_counter;
/* Variables are "pushable" (auto) and thus we need a stack mechanism.
This is built into the variable record. */
typedef struct bc_var
{
bc_num v_value;
struct bc_var *v_next;
} bc_var;
/* bc arrays can also be "auto" variables and thus need the same
kind of stacking mechanisms. */
typedef struct bc_array_node
{
union
{
bc_num n_num [NODE_SIZE];
struct bc_array_node *n_down [NODE_SIZE];
} n_items;
} bc_array_node;
typedef struct bc_array
{
bc_array_node *a_tree;
short a_depth;
} bc_array;
typedef struct bc_var_array
{
bc_array *a_value;
char a_param;
struct bc_var_array *a_next;
} bc_var_array;
/* For the stacks, execution and function, we need records to allow
for arbitrary size. */
typedef struct estack_rec {
bc_num s_num;
struct estack_rec *s_next;
} estack_rec;
typedef struct fstack_rec {
int s_val;
struct fstack_rec *s_next;
} fstack_rec;
/* The following are for the name tree. */
typedef struct id_rec {
char *id; /* The program name. */
/* A name == 0 => nothing assigned yet. */
int a_name; /* The array variable name (number). */
int f_name; /* The function name (number). */
int v_name; /* The variable name (number). */
short balance; /* For the balanced tree. */
struct id_rec *left, *right; /* Tree pointers. */
} id_rec;

View file

@ -1,3 +0,0 @@
#!/bin/sh
make clean
make && make install

View file

@ -1,4 +0,0 @@
/* config.h */
#define SMALL_BUF
#define BC_MATH_FILE "/usr/lib/libmath.b"
#define SHORTNAMES

View file

@ -1,87 +0,0 @@
/* const.h: Constants for bc. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */
#ifdef NO_LIMITS
#define INT_MAX 0x7FFFFFFF
#define LONG_MAX 0x7FFFFFFF
#endif
/* Define constants in some reasonable size. The next 4 constants are
POSIX constants. */
#define BC_BASE_MAX INT_MAX
#define BC_SCALE_MAX INT_MAX
#define BC_STRING_MAX INT_MAX
/* Definitions for arrays. */
#define BC_DIM_MAX 65535 /* this should be NODE_SIZE^NODE_DEPTH-1 */
#define NODE_SIZE 16 /* Must be a power of 2. */
#define NODE_MASK 0xf /* Must be NODE_SIZE-1. */
#define NODE_SHIFT 4 /* Number of 1 bits in NODE_MASK. */
#define NODE_DEPTH 4
/* Other BC limits defined but not part of POSIX. */
#define BC_LABEL_GROUP 64
#define BC_LABEL_LOG 6
#define BC_MAX_SEGS 16 /* Code segments. */
#define BC_SEG_SIZE 1024
#define BC_SEG_LOG 10
/* Maximum number of variables, arrays and functions and the
allocation increment for the dynamic arrays. */
#define MAX_STORE 32767
#define STORE_INCR 32
/* Other interesting constants. */
#define FALSE 0
#define TRUE 1
#define SIMPLE 0
#define ARRAY 1
#define FUNCT 2
#define EXTERN extern
#ifdef __STDC__
#define CONST const
#define VOID void
#else
#define CONST
#define VOID
#endif
/* Include the version definition. */
#include "version.h"

View file

@ -1,783 +0,0 @@
/* execute.c - run a bc program. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include <signal.h>
#include "global.h"
#include "proto.h"
/* The SIGINT interrupt handling routine. */
int had_sigint;
void
stop_execution (sig)
int sig;
{
had_sigint = TRUE;
printf ("\n");
rt_error ("interrupted execution");
}
/* Get the current byte and advance the PC counter. */
unsigned char
byte (pc)
program_counter *pc;
{
int seg, offset;
seg = pc->pc_addr >> BC_SEG_LOG;
offset = pc->pc_addr++ % BC_SEG_SIZE;
return (functions[pc->pc_func].f_body[seg][offset]);
}
/* The routine that actually runs the machine. */
void
execute ()
{
int label_num, l_gp, l_off;
bc_label_group *gp;
char inst, ch;
int new_func;
int var_name;
int const_base;
bc_num temp_num;
arg_list *auto_list;
/* Initialize this run... */
pc.pc_func = 0;
pc.pc_addr = 0;
runtime_error = FALSE;
init_num (&temp_num);
/* Set up the interrupt mechanism for an interactive session. */
if (interactive)
{
signal (SIGINT, stop_execution);
had_sigint = FALSE;
}
while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error)
{
inst = byte(&pc);
#if DEBUG > 3
{ /* Print out address and the stack before each instruction.*/
int depth; estack_rec *temp = ex_stack;
printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst);
if (temp == NULL) printf ("empty stack.\n", inst);
else
{
depth = 1;
while (temp != NULL)
{
printf (" %d = ", depth);
out_num (temp->s_num, 10, out_char);
depth++;
temp = temp->s_next;
}
}
}
#endif
switch ( inst )
{
case 'A' : /* increment array variable (Add one). */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
incr_array (var_name);
break;
case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */
case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */
c_code = !is_zero (ex_stack->s_num);
pop ();
case 'J' : /* Jump to a label. */
label_num = byte(&pc); /* Low order bits first. */
label_num += byte(&pc) << 8;
if (inst == 'J' || (inst == 'B' && c_code)
|| (inst == 'Z' && !c_code)) {
gp = functions[pc.pc_func].f_label;
l_gp = label_num >> BC_LABEL_LOG;
l_off = label_num % BC_LABEL_GROUP;
while (l_gp-- > 0) gp = gp->l_next;
pc.pc_addr = gp->l_adrs[l_off];
}
break;
case 'C' : /* Call a function. */
/* Get the function number. */
new_func = byte(&pc);
if ((new_func & 0x80) != 0)
new_func = ((new_func << 8) & 0x7f) + byte(&pc);
/* Check to make sure it is defined. */
if (!functions[new_func].f_defined)
{
rt_error ("Function %s not defined.", f_names[new_func]);
break;
}
/* Check and push parameters. */
process_params (&pc, new_func);
/* Push auto variables. */
for (auto_list = functions[new_func].f_autos;
auto_list != NULL;
auto_list = auto_list->next)
auto_var (auto_list->av_name);
/* Push pc and ibase. */
fpush (pc.pc_func);
fpush (pc.pc_addr);
fpush (i_base);
/* Reset pc to start of function. */
pc.pc_func = new_func;
pc.pc_addr = 0;
break;
case 'D' : /* Duplicate top of stack */
push_copy (ex_stack->s_num);
break;
case 'K' : /* Push a constant */
/* Get the input base and convert it to a bc number. */
if (pc.pc_func == 0)
const_base = i_base;
else
const_base = fn_stack->s_val;
if (const_base == 10)
push_b10_const (&pc);
else
push_constant (prog_char, const_base);
break;
case 'L' : /* load array variable */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
load_array (var_name);
break;
case 'M' : /* decrement array variable (Minus!) */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
decr_array (var_name);
break;
case 'O' : /* Write a string to the output with processing. */
while ((ch = byte(&pc)) != '"')
if (ch != '\\')
out_char (ch);
else
{
ch = byte(&pc);
if (ch == '"') break;
switch (ch)
{
case 'n': out_char ('\n'); break;
case 't': out_char ('\t'); break;
case 'r': out_char ('\r'); break;
case 'b': out_char (007); break;
case 'f': out_char ('\f'); break;
case '\\': out_char ('\\'); break;
default: break;
}
}
if (interactive) fflush (stdout);
break;
case 'R' : /* Return from function */
if (pc.pc_func != 0)
{
/* "Pop" autos and parameters. */
pop_vars(functions[pc.pc_func].f_autos);
pop_vars(functions[pc.pc_func].f_params);
/* reset the pc. */
fpop ();
pc.pc_addr = fpop ();
pc.pc_func = fpop ();
}
else
rt_error ("Return from main program.");
break;
case 'S' : /* store array variable */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
store_array (var_name);
break;
case 'T' : /* Test tos for zero */
c_code = is_zero (ex_stack->s_num);
assign (c_code);
break;
case 'W' : /* Write the value on the top of the stack. */
case 'P' : /* Write the value on the top of the stack. No newline. */
out_num (ex_stack->s_num, o_base, out_char);
if (inst == 'W') out_char ('\n');
store_var (3); /* Special variable "last". */
if (interactive) fflush (stdout);
break;
case 'c' : /* Call special function. */
new_func = byte(&pc);
switch (new_func)
{
case 'L': /* Length function. */
/* For the number 0.xxxx, 0 is not significant. */
if (ex_stack->s_num->n_len == 1 &&
ex_stack->s_num->n_scale != 0 &&
ex_stack->s_num->n_value[0] == 0 )
int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
else
int2num (&ex_stack->s_num, ex_stack->s_num->n_len
+ ex_stack->s_num->n_scale);
break;
case 'S': /* Scale function. */
int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
break;
case 'R': /* Square Root function. */
if (!bc_sqrt (&ex_stack->s_num, scale))
rt_error ("Square root of a negative number");
break;
case 'I': /* Read function. */
push_constant (input_char, i_base);
break;
}
break;
case 'd' : /* Decrement number */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
decr_var (var_name);
break;
case 'h' : /* Halt the machine. */
exit (0);
case 'i' : /* increment number */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
incr_var (var_name);
break;
case 'l' : /* load variable */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
load_var (var_name);
break;
case 'n' : /* Negate top of stack. */
bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num);
break;
case 'p' : /* Pop the execution stack. */
pop ();
break;
case 's' : /* store variable */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
store_var (var_name);
break;
case 'w' : /* Write a string to the output. */
while ((ch = byte(&pc)) != '"') out_char (ch);
if (interactive) fflush (stdout);
break;
case 'x' : /* Exchange Top of Stack with the one under the tos. */
if (check_stack(2)) {
bc_num temp = ex_stack->s_num;
ex_stack->s_num = ex_stack->s_next->s_num;
ex_stack->s_next->s_num = temp;
}
break;
case '0' : /* Load Constant 0. */
push_copy (_zero_);
break;
case '1' : /* Load Constant 0. */
push_copy (_one_);
break;
case '!' : /* Negate the boolean value on top of the stack. */
c_code = is_zero (ex_stack->s_num);
assign (c_code);
break;
case '&' : /* compare greater than */
if (check_stack(2))
{
c_code = !is_zero (ex_stack->s_next->s_num)
&& !is_zero (ex_stack->s_num);
pop ();
assign (c_code);
}
break;
case '|' : /* compare greater than */
if (check_stack(2))
{
c_code = !is_zero (ex_stack->s_next->s_num)
|| !is_zero (ex_stack->s_num);
pop ();
assign (c_code);
}
break;
case '+' : /* add */
if (check_stack(2))
{
bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num);
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
break;
case '-' : /* subtract */
if (check_stack(2))
{
bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num);
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
break;
case '*' : /* multiply */
if (check_stack(2))
{
bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
&temp_num, scale);
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
break;
case '/' : /* divide */
if (check_stack(2))
{
if (bc_divide (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale) == 0)
{
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
else
rt_error ("Divide by zero");
}
break;
case '%' : /* remainder */
if (check_stack(2))
{
if (is_zero (ex_stack->s_num))
rt_error ("Modulo by zero");
else
{
bc_modulo (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale);
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
}
break;
case '^' : /* raise */
if (check_stack(2))
{
bc_raise (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale);
if (is_zero (ex_stack->s_next->s_num) && is_neg (ex_stack->s_num))
rt_error ("divide by zero");
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
break;
case '=' : /* compare equal */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == 0;
pop ();
assign (c_code);
}
break;
case '#' : /* compare not equal */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) != 0;
pop ();
assign (c_code);
}
break;
case '<' : /* compare less than */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == -1;
pop ();
assign (c_code);
}
break;
case '{' : /* compare less than or equal */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) <= 0;
pop ();
assign (c_code);
}
break;
case '>' : /* compare greater than */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == 1;
pop ();
assign (c_code);
}
break;
case '}' : /* compare greater than or equal */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) >= 0;
pop ();
assign (c_code);
}
break;
default : /* error! */
rt_error ("bad instruction: inst=%c", inst);
}
}
/* Clean up the function stack and pop all autos/parameters. */
while (pc.pc_func != 0)
{
pop_vars(functions[pc.pc_func].f_autos);
pop_vars(functions[pc.pc_func].f_params);
fpop ();
pc.pc_addr = fpop ();
pc.pc_func = fpop ();
}
/* Clean up the execution stack. */
while (ex_stack != NULL) pop();
/* Clean up the interrupt stuff. */
if (interactive)
{
signal (SIGINT, use_quit);
if (had_sigint)
printf ("Interruption completed.\n");
}
}
/* Prog_char gets another byte from the program. It is used for
conversion of text constants in the code to numbers. */
char
prog_char ()
{
return byte(&pc);
}
/* Read a character from the standard input. This function is used
by the "read" function. */
char
input_char ()
{
char in_ch;
/* Get a character from the standard input for the read function. */
in_ch = getchar();
/* Check for a \ quoted newline. */
if (in_ch == '\\')
{
in_ch = getchar();
if (in_ch == '\n')
in_ch = getchar();
}
/* Classify and preprocess the input character. */
if (isdigit(in_ch))
return (in_ch - '0');
if (in_ch >= 'A' && in_ch <= 'F')
return (in_ch + 10 - 'A');
if (in_ch >= 'a' && in_ch <= 'f')
return (in_ch + 10 - 'a');
if (in_ch == '.' || in_ch == '+' || in_ch == '-')
return (in_ch);
if (in_ch <= ' ')
return (' ');
return (':');
}
/* Push_constant converts a sequence of input characters as returned
by IN_CHAR into a number. The number is pushed onto the execution
stack. The number is converted as a number in base CONV_BASE. */
void
push_constant (in_char, conv_base)
char (*in_char)(VOID);
int conv_base;
{
int digits;
bc_num build, temp, result, mult, divisor;
char in_ch, first_ch;
char negative;
/* Initialize all bc numbers */
init_num (&temp);
init_num (&result);
init_num (&mult);
build = copy_num (_zero_);
negative = FALSE;
/* The conversion base. */
int2num (&mult, conv_base);
/* Get things ready. */
in_ch = in_char();
while (in_ch == ' ')
in_ch = in_char();
if (in_ch == '+')
in_ch = in_char();
else
if (in_ch == '-')
{
negative = TRUE;
in_ch = in_char();
}
/* Check for the special case of a single digit. */
if (in_ch < 16)
{
first_ch = in_ch;
in_ch = in_char();
if (in_ch < 16 && first_ch >= conv_base)
first_ch = conv_base - 1;
int2num (&build, (int) first_ch);
}
/* Convert the integer part. */
while (in_ch < 16)
{
if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
bc_multiply (build, mult, &result, 0);
int2num (&temp, (int) in_ch);
bc_add (result, temp, &build);
in_ch = in_char();
}
if (in_ch == '.')
{
in_ch = in_char();
if (in_ch >= conv_base) in_ch = conv_base-1;
free_num (&result);
free_num (&temp);
divisor = copy_num (_one_);
result = copy_num (_zero_);
digits = 0;
while (in_ch < 16)
{
bc_multiply (result, mult, &result, 0);
int2num (&temp, (int) in_ch);
bc_add (result, temp, &result);
bc_multiply (divisor, mult, &divisor, 0);
digits++;
in_ch = in_char();
if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
}
bc_divide (result, divisor, &result, digits);
bc_add (build, result, &build);
}
/* Final work. */
if (negative)
bc_sub (_zero_, build, &build);
push_num (build);
free_num (&temp);
free_num (&result);
free_num (&mult);
}
/* When converting base 10 constants from the program, we use this
more efficient way to convert them to numbers. PC tells where
the constant starts and is expected to be advanced to after
the constant. */
void
push_b10_const (pc)
program_counter *pc;
{
bc_num build;
program_counter look_pc;
int kdigits, kscale;
char inchar;
char *ptr;
/* Count the digits and get things ready. */
look_pc = *pc;
kdigits = 0;
kscale = 0;
inchar = byte (&look_pc);
while (inchar != '.' && inchar != ':')
{
kdigits++;
inchar = byte(&look_pc);
}
if (inchar == '.' )
{
inchar = byte(&look_pc);
while (inchar != ':')
{
kscale++;
inchar = byte(&look_pc);
}
}
/* Get the first character again and move the pc. */
inchar = byte(pc);
/* Secial cases of 0, 1, and A-F single inputs. */
if (kdigits == 1 && kscale == 0)
{
if (inchar == 0)
{
push_copy (_zero_);
inchar = byte(pc);
return;
}
if (inchar == 1) {
push_copy (_one_);
inchar = byte(pc);
return;
}
if (inchar > 9)
{
init_num (&build);
int2num (&build, inchar);
push_num (build);
inchar = byte(pc);
return;
}
}
/* Build the new number. */
if (kdigits == 0)
{
build = new_num (1,kscale);
ptr = build->n_value;
*ptr++ = 0;
}
else
{
build = new_num (kdigits,kscale);
ptr = build->n_value;
}
while (inchar != ':')
{
if (inchar != '.')
if (inchar > 9)
*ptr++ = 9;
else
*ptr++ = inchar;
inchar = byte(pc);
}
push_num (build);
}
/* Put the correct value on the stack for C_CODE. Frees TOS num. */
void
assign (c_code)
char c_code;
{
free_num (&ex_stack->s_num);
if (c_code)
ex_stack->s_num = copy_num (_one_);
else
ex_stack->s_num = copy_num (_zero_);
}

View file

@ -1,9 +0,0 @@
#!/bin/sh
ed - math.h <<EOS-EOS
1,1s/^/"/
1,\$s/\$/\\\\/
\$,\$d
\$,\$s/\\\\\$/"/
w
q
EOS-EOS

View file

@ -1,42 +0,0 @@
/* global.c: This defines the global variables. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
/* Since we want to define them here, we use the following define. */
#undef EXTERN
#define EXTERN
/* Define all the global variables for bc. */
#include "global.h"
#ifndef BC_MATH_FILE
CONST char libmath[] =
#include "math.h"
;
#endif

View file

@ -1,108 +0,0 @@
/* global.h: The global variables for bc. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* For the current "break level" and if statements. */
EXTERN int break_label;
EXTERN int if_label;
EXTERN int continue_label;
/* Label numbers. */
EXTERN int next_label;
/* Used for "code" generation. */
EXTERN char genstr[80];
EXTERN int out_count;
EXTERN char did_gen;
/* Interactive and other flags. */
EXTERN char interactive;
EXTERN char compile_only;
EXTERN char use_math;
EXTERN char warn_not_std;
EXTERN char std_only;
/* global variables for the bc machine. All will be dynamic in size.*/
/* Function storage. main is (0) and functions (1-f_count) */
EXTERN bc_function *functions;
EXTERN char **f_names;
EXTERN int f_count;
/* Variable stoarge and reverse names. */
EXTERN bc_var **variables;
EXTERN char **v_names;
EXTERN int v_count;
/* Array Variable storage and reverse names. */
EXTERN bc_var_array **arrays;
EXTERN char **a_names;
EXTERN int a_count;
/* Execution stack. */
EXTERN estack_rec *ex_stack;
/* Function return stack. */
EXTERN fstack_rec *fn_stack;
/* Other "storage". */
EXTERN int i_base;
EXTERN int o_base;
EXTERN int scale;
EXTERN char c_code;
EXTERN int out_col;
EXTERN char runtime_error;
EXTERN program_counter pc;
/* Input Line numbers and other error information. */
EXTERN int line_no;
EXTERN int had_error;
/* For larger identifiers, a tree, and how many "storage" locations
have been allocated. */
EXTERN int next_array;
EXTERN int next_func;
EXTERN int next_var;
EXTERN id_rec *name_tree;
/* For error message production */
EXTERN char **g_argv;
EXTERN int g_argc;
EXTERN char is_std_in;
/* defined in number.c */
extern bc_num _zero_;
extern bc_num _one_;
/* For use with getopt. Do not declare them here.*/
extern int optind;

View file

@ -1,255 +0,0 @@
/* libmath.b for bc for minix. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
scale = 20
/* Uses the fact that e^x = (e^(x/2))^2
When x is small enough, we use the series:
e^x = 1 + x + x^2/2! + x^3/3! + ...
*/
define e(x) {
auto a, d, e, f, i, m, v, z
/* Check the sign of x. */
if (x<0) {
m = 1
x = -x
}
/* Precondition x. */
z = scale;
scale = 4 + z + .44*x;
while (x > 1) {
f += 1;
x /= 2;
}
/* Initialize the variables. */
v = 1+x
a = x
d = 1
for (i=2; 1; i++) {
e = (a *= x) / (d *= i)
if (e == 0) {
if (f>0) while (f--) v = v*v;
scale = z
if (m) return (1/v);
return (v/1);
}
v += e
}
}
/* Natural log. Uses the fact that ln(x^2) = 2*ln(x)
The series used is:
ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1)
*/
define l(x) {
auto e, f, i, m, n, v, z
/* return something for the special case. */
if (x <= 0) return (1 - 10^scale)
/* Precondition x to make .5 < x < 2.0. */
z = scale;
scale += 4;
f = 2;
i=0
while (x >= 2) { /* for large numbers */
f *= 2;
x = sqrt(x);
}
while (x <= .5) { /* for small numbers */
f *= 2;
x = sqrt(x);
}
/* Set up the loop. */
v = n = (x-1)/(x+1)
m = n*n
/* Sum the series. */
for (i=3; 1; i+=2) {
e = (n *= m) / i
if (e == 0) {
v = f*v
scale = z
return (v/1)
}
v += e
}
}
/* Sin(x) uses the standard series:
sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */
define s(x) {
auto e, i, m, n, s, v, z
/* precondition x. */
z = scale
scale = 1.1*z + 1;
v = a(1)
if (x < 0) {
m = 1;
x = -x;
}
scale = 0
n = (x / v + 2 )/4
x = x - 4*n*v
if (n%2) x = -x
/* Do the loop. */
scale = z + 2;
v = e = x
s = -x*x
for (i=3; 1; i+=2) {
e *= s/(i*(i-1))
if (e == 0) {
scale = z
if (m) return (-v/1);
return (v/1);
}
v += e
}
}
/* Cosine : cos(x) = sin(x+pi/2) */
define c(x) {
auto v;
scale += 1;
v = s(x+a(1)*2);
scale -= 1;
return (v/1);
}
/* Arctan: Using the formula:
atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here)
For under .2, use the series:
atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */
define a(x) {
auto a, e, f, i, m, n, s, v, z
/* Special case and for fast answers */
if (x==1) {
if (scale <= 25) return (.7853981633974483096156608/1)
if (scale <= 40) return (.7853981633974483096156608458198757210492/1)
if (scale <= 60) \
return (.785398163397448309615660845819875721049292349843776455243736/1)
}
if (x==.2) {
if (scale <= 25) return (.1973955598498807583700497/1)
if (scale <= 40) return (.1973955598498807583700497651947902934475/1)
if (scale <= 60) \
return (.197395559849880758370049765194790293447585103787852101517688/1)
}
/* Negative x? */
if (x<0) {
m = 1;
x = -x;
}
/* Save the scale. */
z = scale;
/* Note: a and f are known to be zero due to being auto vars. */
/* Calculate atan of a known number. */
if (x > .2) {
scale = z+4;
a = a(.2);
}
/* Precondition x. */
scale = z+2;
while (x > .2) {
f += 1;
x = (x-.2) / (1+x*.2);
}
/* Initialize the series. */
v = n = x;
s = -x*x;
/* Calculate the series. */
for (i=3; 1; i+=2) {
e = (n *= s) / i;
if (e == 0) {
scale = z;
if (m) return ((f*a+v)/-1);
return ((f*a+v)/1);
}
v += e
}
}
/* Bessel function of integer order. Uses the following:
j(-n,x) = (-1)^n*j(n,x)
j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2))
- x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... )
*/
define j(n,x) {
auto a, d, e, f, i, m, s, v, z
/* Make n an integer and check for negative n. */
z = scale;
scale = 0;
n = n/1;
if (n<0) {
n = -n;
if (n%2 == 1) m = 1;
}
/* Compute the factor of x^n/(2^n*n!) */
f = 1;
for (i=2; i<=n; i++) f = f*i;
scale = 1.5*z;
f = x^n / 2^n / f;
/* Initialize the loop .*/
v = e = 1;
s = -x*x/4
scale = 1.5*z
/* The Loop.... */
for (i=1; 1; i++) {
e = e * s / i / (n+i);
if (e == 0) {
scale = z
if (m) return (-f*v/1);
return (f*v/1);
}
v += e;
}
}

View file

@ -1,333 +0,0 @@
/* load.c: This code "loads" code into the code segments. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h"
#include "proto.h"
/* Load variables. */
program_counter load_adr;
char load_str;
char load_const;
/* Initialize the load sequence. */
void
init_load ()
{
clear_func(0);
load_adr.pc_func = 0;
load_adr.pc_addr = 0;
load_str = FALSE;
load_const = FALSE;
}
/* addbyte adds one BYTE to the current code segment. */
void
addbyte (byte)
char byte;
{
int seg, offset, func;
/* If there was an error, don't continue. */
if (had_error) return;
/* Calculate the segment and offset. */
seg = load_adr.pc_addr >> BC_SEG_LOG;
offset = load_adr.pc_addr++ % BC_SEG_SIZE;
func = load_adr.pc_func;
if (seg >= BC_MAX_SEGS)
{
yyerror ("Function too big.");
return;
}
if (functions[func].f_body[seg] == NULL)
functions[func].f_body[seg] = (char *) bc_malloc (BC_SEG_SIZE);
/* Store the byte. */
functions[func].f_body[seg][offset] = byte;
functions[func].f_code_size++;
}
/* Define a label LAB to be the current program counter. */
void
def_label (lab)
long lab;
{
bc_label_group *temp;
int group, offset, func;
/* Get things ready. */
group = lab >> BC_LABEL_LOG;
offset = lab % BC_LABEL_GROUP;
func = load_adr.pc_func;
/* Make sure there is at least one label group. */
if (functions[func].f_label == NULL)
{
functions[func].f_label =
(bc_label_group *) bc_malloc (sizeof(bc_label_group));
functions[func].f_label->l_next = NULL;
}
/* Add the label group. */
temp = functions[func].f_label;
while (group > 0)
{
if (temp->l_next == NULL)
{
temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group));
temp->l_next->l_next = NULL;
}
temp = temp->l_next;
group --;
}
/* Define it! */
temp->l_adrs [offset] = load_adr.pc_addr;
}
/* Several instructions have integers in the code. They
are all known to be legal longs. So, no error code
is added. STR is the pointer to the load string and
must be moved to the last non-digit character. */
long
long_val (str)
char **str;
{ int val = 0;
char neg = FALSE;
if (**str == '-')
{
neg = TRUE;
(*str)++;
}
while (isdigit(**str))
val = val*10 + *(*str)++ - '0';
if (neg)
return -val;
else
return val;
}
/* load_code loads the CODE into the machine. */
void
load_code (code)
char *code;
{
char *str;
long ap_name; /* auto or parameter name. */
long label_no;
long vaf_name; /* variable, array or function number. */
long func;
program_counter save_adr;
/* Initialize. */
str = code;
/* Scan the code. */
while (*str != 0)
{
/* If there was an error, don't continue. */
if (had_error) return;
if (load_str)
{
if (*str == '"') load_str = FALSE;
addbyte (*str++);
}
else
if (load_const)
{
if (*str == '\n')
str++;
else
{
if (*str == ':')
{
load_const = FALSE;
addbyte (*str++);
}
else
if (*str == '.')
addbyte (*str++);
else
if (*str >= 'A')
addbyte (*str++ + 10 - 'A');
else
addbyte (*str++ - '0');
}
}
else
{
switch (*str)
{
case '"': /* Starts a string. */
load_str = TRUE;
break;
case 'N': /* A label */
str++;
label_no = long_val (&str);
def_label (label_no);
break;
case 'B': /* Branch to label. */
case 'J': /* Jump to label. */
case 'Z': /* Branch Zero to label. */
addbyte(*str++);
label_no = long_val (&str);
if (label_no > 65535L)
{ /* Better message? */
fprintf (stderr,"Program too big.\n");
exit(1);
}
addbyte ( (char) label_no & 0xFF);
addbyte ( (char) label_no >> 8);
break;
case 'F': /* A function, get the name and initialize it. */
str++;
func = long_val (&str);
clear_func (func);
#if DEBUG > 2
printf ("Loading function number %d\n", func);
#endif
/* get the parameters */
while (*str++ != '.')
{
if (*str == '.')
{
str++;
break;
}
ap_name = long_val (&str);
#if DEBUG > 2
printf ("parameter number %d\n", ap_name);
#endif
functions[(int)func].f_params =
nextarg (functions[(int)func].f_params, ap_name);
}
/* get the auto vars */
while (*str != '[')
{
if (*str == ',') str++;
ap_name = long_val (&str);
#if DEBUG > 2
printf ("auto number %d\n", ap_name);
#endif
functions[(int)func].f_autos =
nextarg (functions[(int)func].f_autos, ap_name);
}
save_adr = load_adr;
load_adr.pc_func = func;
load_adr.pc_addr = 0;
break;
case ']': /* A function end */
functions[load_adr.pc_func].f_defined = TRUE;
load_adr = save_adr;
break;
case 'C': /* Call a function. */
addbyte (*str++);
func = long_val (&str);
if (func < 128)
addbyte ( (char) func);
else
{
addbyte ((func >> 8) & 0xff | 0x80);
addbyte (func & 0xff);
}
if (*str == ',') str++;
while (*str != ':')
addbyte (*str++);
addbyte (':');
break;
case 'c': /* Call a special function. */
addbyte (*str++);
addbyte (*str);
break;
case 'K': /* A constant.... may have an "F" in it. */
addbyte (*str);
load_const = TRUE;
break;
case 'd': /* Decrement. */
case 'i': /* Increment. */
case 'l': /* Load. */
case 's': /* Store. */
case 'A': /* Array Increment */
case 'M': /* Array Decrement */
case 'L': /* Array Load */
case 'S': /* Array Store */
addbyte (*str++);
vaf_name = long_val (&str);
if (vaf_name < 128)
addbyte (vaf_name);
else
{
addbyte ((vaf_name >> 8) & 0xff | 0x80);
addbyte (vaf_name & 0xff);
}
break;
case '@': /* A command! */
switch (*(++str))
{
case 'i':
init_load ();
break;
case 'r':
execute ();
break;
}
break;
case '\n': /* Ignore the newlines */
break;
default: /* Anything else */
addbyte (*str);
}
str++;
}
}
}

View file

@ -1,204 +0,0 @@
/* main.c: The main program for bc. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include <signal.h>
#include "global.h"
#include "proto.h"
/* Variables for processing multiple files. */
char first_file;
extern FILE *yyin;
/* The main program for bc. */
int
main (argc, argv)
int argc;
char *argv[];
{
int ch;
/* Initialize many variables. */
compile_only = FALSE;
use_math = FALSE;
warn_not_std = FALSE;
std_only = FALSE;
if (isatty(0) && isatty(1))
interactive = TRUE;
else
interactive = FALSE;
/* Parse the command line */
ch = getopt (argc, argv, "lcisvw");
while (ch != EOF)
{
switch (ch)
{
case 'c': /* compile only */
compile_only = TRUE;
break;
case 'l': /* math lib */
use_math = TRUE;
break;
case 'i': /* force interactive */
interactive = TRUE;
break;
case 'w': /* Non standard features give warnings. */
warn_not_std = TRUE;
break;
case 's': /* Non standard features give errors. */
std_only = TRUE;
break;
case 'v': /* Print the version. */
printf ("%s\n", BC_VERSION);
break;
}
ch = getopt (argc, argv, "lcisvw");
}
/* Initialize the machine. */
init_storage();
init_load();
/* Set up interrupts to print a message. */
if (interactive)
signal (SIGINT, use_quit);
/* Initialize the front end. */
init_tree();
init_gen ();
g_argv = argv;
g_argc = argc;
is_std_in = FALSE;
first_file = TRUE;
if (!open_new_file ())
exit (1);
/* Do the parse. */
yyparse ();
/* End the compile only output with a newline. */
if (compile_only)
printf ("\n");
exit (0);
}
/* This is the function that opens all the files.
It returns TRUE if the file was opened, otherwise
it returns FALSE. */
int
open_new_file ()
{
FILE *new_file;
/* Set the line number. */
line_no = 1;
/* Check to see if we are done. */
if (is_std_in) return (FALSE);
/* Open the other files. */
if (use_math && first_file)
{
#ifdef BC_MATH_FILE
/* Make the first file be the math library. */
new_file = fopen (BC_MATH_FILE, "r");
use_math = FALSE;
if (new_file != NULL)
{
new_yy_file (new_file);
return TRUE;
}
else
{
fprintf (stderr, "Math Library unavailable.\n");
exit (1);
}
#else
/* Load the code from a precompiled version of the math libarary. */
extern char libmath[];
char tmp;
/* These MUST be in the order of first mention of each function.
That is why "a" comes before "c" even though "a" is defined after
after "c". "a" is used in "s"! */
tmp = lookup ("e", FUNCT);
tmp = lookup ("l", FUNCT);
tmp = lookup ("s", FUNCT);
tmp = lookup ("a", FUNCT);
tmp = lookup ("c", FUNCT);
tmp = lookup ("j", FUNCT);
load_code (libmath);
#endif
}
/* One of the argv values. */
while (optind < g_argc)
{
new_file = fopen (g_argv[optind], "r");
if (new_file != NULL)
{
new_yy_file (new_file);
optind++;
return TRUE;
}
fprintf (stderr, "File %s is unavailable.\n", g_argv[optind++]);
exit (1);
}
/* If we fall through to here, we should return stdin. */
new_yy_file (stdin);
is_std_in = TRUE;
return TRUE;
}
/* Set yyin to the new file. */
void
new_yy_file (file)
FILE *file;
{
if (!first_file) fclose (yyin);
yyin = file;
first_file = FALSE;
}
/* Message to use quit. */
void
use_quit (sig)
int sig;
{
printf ("\n(interrupt) use quit to exit.\n");
signal (SIGINT, use_quit);
}

File diff suppressed because it is too large Load diff

View file

@ -1,60 +0,0 @@
/* number.h: Arbitrary precision numbers header file. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
typedef enum {PLUS, MINUS} sign;
typedef struct
{
sign n_sign;
int n_len; /* The number of digits before the decimal point. */
int n_scale; /* The number of digits after the decimal point. */
int n_refs; /* The number of pointers to this number. */
char n_value[1]; /* The storage. Not zero char terminated. It is
allocated with all other fields. */
} bc_struct;
typedef bc_struct *bc_num;
/* Some useful macros and constants. */
#define CH_VAL(c) (c - '0')
#define BCD_CHAR(d) (d + '0')
#ifdef MIN
#undef MIN
#undef MAX
#endif
#define MAX(a,b) (a>b?a:b)
#define MIN(a,b) (a>b?b:a)
#define ODD(a) (a&1)
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

View file

@ -1,162 +0,0 @@
/* proto.h: Prototype function definitions for "external" functions. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* For the pc version using k&r ACK. (minix1.5 and earlier.) */
#ifdef SHORTNAMES
#define init_numbers i_numbers
#define push_constant push__constant
#define load_const in_load_const
#define yy_get_next_buffer yyget_next_buffer
#define yy_init_buffer yyinit_buffer
#define yy_last_accepting_state yylast_accepting_state
#define arglist1 arg1list
#endif
/* Include the standard library header files. */
#ifndef NO_UNISTD
#include <unistd.h>
#endif
#ifndef NO_STDLIB
#ifdef __STDC__
#include <stdlib.h>
#endif
#endif
/* Define the _PROTOTYPE macro if it is needed. */
#ifndef _PROTOTYPE
#ifdef __STDC__
#define _PROTOTYPE(func, args) func args
#else
#define _PROTOTYPE(func, args) func()
#endif
#endif
/* From execute.c */
_PROTOTYPE(void stop_execution, (int));
_PROTOTYPE(unsigned char byte, (program_counter *pc));
_PROTOTYPE(void execute, (void));
_PROTOTYPE(char prog_char, (void));
_PROTOTYPE(char input_char, (void));
_PROTOTYPE(void push_constant, (char (*in_char)(void), int conv_base));
_PROTOTYPE(void push_b10_const, (program_counter *pc));
_PROTOTYPE(void assign, (int c_code));
/* From util.c */
_PROTOTYPE(char *strcopyof, (char *str));
_PROTOTYPE(arg_list *nextarg, (arg_list *args, int val));
_PROTOTYPE(char *arg_str, (arg_list *args, int));
_PROTOTYPE(void free_args, (arg_list *args));
_PROTOTYPE(void check_params, (arg_list *params, arg_list *autos));
_PROTOTYPE(void init_gen, (void));
_PROTOTYPE(void generate, (char *str));
_PROTOTYPE(void run_code, (void));
_PROTOTYPE(void out_char, (int ch));
_PROTOTYPE(id_rec *find_id, (id_rec *tree, char *id));
_PROTOTYPE(int insert_id_rec, (id_rec **root, id_rec *new_id));
_PROTOTYPE(void init_tree, (void));
_PROTOTYPE(int lookup, (char *name, int namekind));
_PROTOTYPE(char *bc_malloc, (int));
_PROTOTYPE(void out_of_memory, (void));
_PROTOTYPE(void welcome, (void));
_PROTOTYPE(void warranty, (char *));
_PROTOTYPE(void limits, (void));
_PROTOTYPE(void yyerror, (char *str ,...));
_PROTOTYPE(void warn, (char *mesg ,...));
_PROTOTYPE(void rt_error, (char *mesg ,...));
_PROTOTYPE(void rt_warn, (char *mesg ,...));
/* From load.c */
_PROTOTYPE(void init_load, (void));
_PROTOTYPE(void addbyte, (int byte));
_PROTOTYPE(void def_label, (long lab));
_PROTOTYPE(long long_val, (char **str));
_PROTOTYPE(void load_code, (char *code));
/* From main.c */
_PROTOTYPE(int main, (int argc , char *argv []));
_PROTOTYPE(int open_new_file, (void));
_PROTOTYPE(void new_yy_file, (FILE *file));
_PROTOTYPE(void use_quit, (int));
/* From number.c */
_PROTOTYPE(void free_num, (bc_num *num));
_PROTOTYPE(bc_num new_num, (int length, int scale));
_PROTOTYPE(void init_numbers, (void));
_PROTOTYPE(bc_num copy_num, (bc_num num));
_PROTOTYPE(void init_num, (bc_num *num));
_PROTOTYPE(void str2num, (bc_num *num, char *str, int scale));
_PROTOTYPE(char *num2str, (bc_num num));
_PROTOTYPE(void int2num, (bc_num *num, int val));
_PROTOTYPE(long num2long, (bc_num num));
_PROTOTYPE(int bc_compare, (bc_num n1, bc_num n2));
_PROTOTYPE(char is_zero, (bc_num num));
_PROTOTYPE(char is_neg, (bc_num num));
_PROTOTYPE(void bc_add, (bc_num n1, bc_num n2, bc_num *result));
_PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result));
_PROTOTYPE(void bc_multiply, (bc_num n1, bc_num n2, bc_num *prod, int scale));
_PROTOTYPE(int bc_divide, (bc_num n1, bc_num n2, bc_num *quot, int scale));
_PROTOTYPE(int bc_modulo, (bc_num num1, bc_num num2, bc_num *result, int scale));
_PROTOTYPE(void bc_raise, (bc_num num1, bc_num num2, bc_num *result, int scale));
_PROTOTYPE(int bc_sqrt, (bc_num *num, int scale));
_PROTOTYPE(void out_long, (long val, int size, int space,
void (*out_char)(int)));
_PROTOTYPE(void out_num, (bc_num num, int o_base, void (* out_char)(int)));
/* From storage.c */
_PROTOTYPE(void init_storage, (void));
_PROTOTYPE(void more_functions, (void));
_PROTOTYPE(void more_variables, (void));
_PROTOTYPE(void more_arrays, (void));
_PROTOTYPE(void clear_func, (int func ));
_PROTOTYPE(int fpop, (void));
_PROTOTYPE(void fpush, (int val ));
_PROTOTYPE(void pop, (void));
_PROTOTYPE(void push_copy, (bc_num num ));
_PROTOTYPE(void push_num, (bc_num num ));
_PROTOTYPE(char check_stack, (int depth ));
_PROTOTYPE(bc_var *get_var, (int var_name ));
_PROTOTYPE(bc_num *get_array_num, (int var_index, long index ));
_PROTOTYPE(void store_var, (int var_name ));
_PROTOTYPE(void store_array, (int var_name ));
_PROTOTYPE(void load_var, (int var_name ));
_PROTOTYPE(void load_array, (int var_name ));
_PROTOTYPE(void decr_var, (int var_name ));
_PROTOTYPE(void decr_array, (int var_name ));
_PROTOTYPE(void incr_var, (int var_name ));
_PROTOTYPE(void incr_array, (int var_name ));
_PROTOTYPE(void auto_var, (int name ));
_PROTOTYPE(void free_a_tree, (bc_array_node *root, int depth ));
_PROTOTYPE(void pop_vars, (arg_list *list ));
_PROTOTYPE(void process_params, (program_counter *pc, int func ));
/* For the scanner and parser.... */
_PROTOTYPE(int yyparse, (void));
_PROTOTYPE(int yylex, (void));

View file

@ -1,448 +0,0 @@
, %{
/* sbc.y: A POSIX bc processor written for minix with no extensions. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h" /* To get the global variables. */
#include "proto.h"
%}
%start program
%union {
char *s_value;
char c_value;
int i_value;
arg_list *a_value;
}
%token <i_value> NEWLINE AND OR NOT
%token <s_value> STRING NAME NUMBER
/* '-', '+' are tokens themselves */
%token <c_value> MUL_OP
/* '*', '/', '%' */
%token <c_value> ASSIGN_OP
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
%token <s_value> REL_OP
/* '==', '<=', '>=', '!=', '<', '>' */
%token <c_value> INCR_DECR
/* '++', '--' */
%token <i_value> Define Break Quit Length
/* 'define', 'break', 'quit', 'length' */
%token <i_value> Return For If While Sqrt Else
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
%token <i_value> Scale Ibase Obase Auto Read
/* 'scale', 'ibase', 'obase', 'auto', 'read' */
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
/* The types of all other non-terminals. */
%type <i_value> expression named_expression return_expression
%type <a_value> opt_parameter_list parameter_list opt_auto_define_list
%type <a_value> define_list opt_argument_list argument_list
%type <i_value> program input_item semicolon_list statement_list
%type <i_value> statement_or_error statement function relational_expression
/* precedence */
%nonassoc REL_OP
%right ASSIGN_OP
%left '+' '-'
%left MUL_OP
%right '^'
%nonassoc UNARY_MINUS
%nonassoc INCR_DECR
%%
program : /* empty */
{
$$ = 0;
std_only = TRUE;
if (interactive)
{
printf ("s%s\n", BC_VERSION);
welcome();
}
}
| program input_item
;
input_item : semicolon_list NEWLINE
{ run_code(); }
| function
{ run_code(); }
| error NEWLINE
{
yyerrok;
init_gen() ;
}
;
semicolon_list : /* empty */
{ $$ = 0; }
| statement_or_error
| semicolon_list ';' statement_or_error
| semicolon_list ';'
;
statement_list : /* empty */
{ $$ = 0; }
| statement
| statement_list NEWLINE
| statement_list NEWLINE statement
| statement_list ';'
| statement_list ';' statement
;
statement_or_error : statement
| error statement
{ $$ = $2; }
;
statement : Warranty
{ warranty("s"); }
| expression
{
if ($1 & 1)
generate ("W");
else
generate ("p");
}
| STRING
{
$$ = 0;
generate ("w");
generate ($1);
free ($1);
}
| Break
{
if (break_label == 0)
yyerror ("Break outside a for/while");
else
{
sprintf (genstr, "J%1d:", break_label);
generate (genstr);
}
}
| Quit
{ exit(0); }
| Return
{ generate ("0R"); }
| Return '(' return_expression ')'
{ generate ("R"); }
| For
{
$1 = break_label;
break_label = next_label++;
}
'(' expression ';'
{
$4 = next_label++;
sprintf (genstr, "pN%1d:", $4);
generate (genstr);
}
relational_expression ';'
{
$7 = next_label++;
sprintf (genstr, "B%1d:J%1d:", $7, break_label);
generate (genstr);
$<i_value>$ = next_label++;
sprintf (genstr, "N%1d:", $<i_value>$);
generate (genstr);
}
expression ')'
{
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
generate (genstr);
}
statement
{
sprintf (genstr, "J%1d:N%1d:", $<i_value>9,
break_label);
generate (genstr);
break_label = $1;
}
| If '(' relational_expression ')'
{
$3 = next_label++;
sprintf (genstr, "Z%1d:", $3);
generate (genstr);
}
statement
{
sprintf (genstr, "N%1d:", $3);
generate (genstr);
}
| While
{
$1 = next_label++;
sprintf (genstr, "N%1d:", $1);
generate (genstr);
}
'(' relational_expression
{
$4 = break_label;
break_label = next_label++;
sprintf (genstr, "Z%1d:", break_label);
generate (genstr);
}
')' statement
{
sprintf (genstr, "J%1d:N%1d:", $1, break_label);
generate (genstr);
break_label = $4;
}
| '{' statement_list '}'
{ $$ = 0; }
;
function : Define NAME '(' opt_parameter_list ')' '{'
NEWLINE opt_auto_define_list
{
check_params ($4,$8);
sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
arg_str ($4,TRUE), arg_str ($8,TRUE));
generate (genstr);
free_args ($4);
free_args ($8);
$1 = next_label;
next_label = 0;
}
statement_list NEWLINE '}'
{
generate ("0R]");
next_label = $1;
}
;
opt_parameter_list : /* empty */
{ $$ = NULL; }
| parameter_list
;
parameter_list : NAME
{ $$ = nextarg (NULL, lookup($1,SIMPLE)); }
| define_list ',' NAME
{ $$ = nextarg ($1, lookup($3,SIMPLE)); }
;
opt_auto_define_list : /* empty */
{ $$ = NULL; }
| Auto define_list NEWLINE
{ $$ = $2; }
| Auto define_list ';'
{ $$ = $2; }
;
define_list : NAME
{ $$ = nextarg (NULL, lookup($1,SIMPLE)); }
| NAME '[' ']'
{ $$ = nextarg (NULL, lookup($1,ARRAY)); }
| define_list ',' NAME
{ $$ = nextarg ($1, lookup($3,SIMPLE)); }
| define_list ',' NAME '[' ']'
{ $$ = nextarg ($1, lookup($3,ARRAY)); }
;
opt_argument_list : /* empty */
{ $$ = NULL; }
| argument_list
;
argument_list : expression
{ $$ = nextarg (NULL,0); }
| argument_list ',' expression
{ $$ = nextarg ($1,0); }
;
relational_expression : expression
{ $$ = 0; }
| expression REL_OP expression
{
$$ = 0;
switch (*($2))
{
case '=':
generate ("=");
break;
case '!':
generate ("#");
break;
case '<':
if ($2[1] == '=')
generate ("{");
else
generate ("<");
break;
case '>':
if ($2[1] == '=')
generate ("}");
else
generate (">");
break;
}
}
;
return_expression : /* empty */
{
$$ = 0;
generate ("0");
}
| expression
;
expression : named_expression ASSIGN_OP
{
if ($2 != '=')
{
if ($1 < 0)
sprintf (genstr, "DL%d:", -$1);
else
sprintf (genstr, "l%d:", $1);
generate (genstr);
}
}
expression
{
$$ = 0;
if ($2 != '=')
{
sprintf (genstr, "%c", $2);
generate (genstr);
}
if ($1 < 0)
sprintf (genstr, "S%d:", -$1);
else
sprintf (genstr, "s%d:", $1);
generate (genstr);
}
| expression '+' expression
{ generate ("+"); }
| expression '-' expression
{ generate ("-"); }
| expression MUL_OP expression
{
genstr[0] = $2;
genstr[1] = 0;
generate (genstr);
}
| expression '^' expression
{ generate ("^"); }
| '-' expression %prec UNARY_MINUS
{ generate ("n"); $$ = 1;}
| named_expression
{
$$ = 1;
if ($1 < 0)
sprintf (genstr, "L%d:", -$1);
else
sprintf (genstr, "l%d:", $1);
generate (genstr);
}
| NUMBER
{
int len = strlen($1);
$$ = 1;
if (len == 1 && *$1 == '0')
generate ("0");
else
{
if (len == 1 && *$1 == '1')
generate ("1");
else
{
generate ("K");
generate ($1);
generate (":");
}
free ($1);
}
}
| '(' expression ')'
{ $$ = 1; }
| NAME '(' opt_argument_list ')'
{
$$ = 1;
if ($3 != NULL)
{
sprintf (genstr, "C%d,%s:", lookup($1,FUNCT),
arg_str ($3,FALSE));
free_args ($3);
}
else
sprintf (genstr, "C%d:", lookup($1,FUNCT));
generate (genstr);
}
| INCR_DECR named_expression
{
$$ = 1;
if ($2 < 0)
{
if ($1 == '+')
sprintf (genstr, "DA%d:L%d:", -$2, -$2);
else
sprintf (genstr, "DM%d:L%d:", -$2, -$2);
}
else
{
if ($1 == '+')
sprintf (genstr, "i%d:l%d:", $2, $2);
else
sprintf (genstr, "d%d:l%d:", $2, $2);
}
generate (genstr);
}
| named_expression INCR_DECR
{
$$ = 1;
if ($1 < 0)
{
sprintf (genstr, "DL%d:x", -$1);
generate (genstr);
if ($2 == '+')
sprintf (genstr, "A%d:", -$1);
else
sprintf (genstr, "M%d:", -$1);
}
else
{
sprintf (genstr, "l%d:", $1);
generate (genstr);
if ($2 == '+')
sprintf (genstr, "i%d:", $1);
else
sprintf (genstr, "d%d:", $1);
}
generate (genstr);
}
| Length '(' expression ')'
{ generate ("cL"); $$ = 1;}
| Sqrt '(' expression ')'
{ generate ("cR"); $$ = 1;}
| Scale '(' expression ')'
{ generate ("cS"); $$ = 1;}
;
named_expression : NAME
{ $$ = lookup($1,SIMPLE); }
| NAME '[' expression ']'
{ $$ = lookup($1,ARRAY); }
| Ibase
{ $$ = 0; }
| Obase
{ $$ = 1; }
| Scale
{ $$ = 2; }
;
%%

File diff suppressed because it is too large Load diff

View file

@ -1,190 +0,0 @@
%{
/* scan.l: the (f)lex description file for the scanner. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "y.tab.h"
#include "global.h"
#include "proto.h"
/* Using flex, we can ask for a smaller input buffer. With lex, this
does nothing! */
#ifdef SMALL_BUF
#undef YY_READ_BUF_SIZE
#define YY_READ_BUF_SIZE 512
#endif
/* We want to define our own yywrap. */
#undef yywrap
_PROTOTYPE(int yywrap, (void));
/* MINIX returns from read with < 0 if SIGINT is encountered.
In flex, we can redefine YY_INPUT to the following. In lex, this
does nothing! */
#include <errno.h>
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
if (errno != EINTR) \
YY_FATAL_ERROR( "read() in flex scanner failed" );
%}
DIGIT [0-9A-F]
LETTER [a-z]
%%
define return(Define);
break return(Break);
quit return(Quit);
length return(Length);
return return(Return);
for return(For);
if return(If);
while return(While);
sqrt return(Sqrt);
scale return(Scale);
ibase return(Ibase);
obase return(Obase);
auto return(Auto);
else return(Else);
read return(Read);
halt return(Halt);
last return(Last);
warranty return(Warranty);
continue return(Continue);
print return(Print);
limits return(Limits);
"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0];
return((int)yytext[0]); }
&& { return(AND); }
\|\| { return(OR); }
"!" { return(NOT); }
"*"|"/"|"%" { yylval.c_value = yytext[0]; return(MUL_OP); }
"="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); }
=\+|=-|=\*|=\/|=%|=\^ {
#ifdef OLD_EQ_OP
char warn_save;
warn_save = warn_not_std;
warn_not_std = TRUE;
warn ("Old fashioned =<op>");
warn_not_std = warn_save;
yylval.c_value = yytext[1];
#else
yylval.c_value = '=';
yyless (1);
#endif
return(ASSIGN_OP);
}
==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof((char *) yytext);
return(REL_OP); }
\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); }
"\n" { line_no++; return(NEWLINE); }
\\\n { line_no++; /* ignore a "quoted" newline */ }
[ \t]+ { /* ignore spaces and tabs */ }
"/*" {
int c;
for (;;)
{
while ( ((c=input()) != '*') && (c != EOF))
/* eat it */
if (c == '\n') line_no++;
if (c == '*')
{
while ( (c=input()) == '*') /* eat it*/;
if (c == '/') break; /* at end of comment */
if (c == '\n') line_no++;
}
if (c == EOF)
{
fprintf (stderr,"EOF encountered in a comment.\n");
break;
}
}
}
[a-z][a-z0-9_]* { yylval.s_value = strcopyof((char *) yytext); return(NAME); }
\"[^\"]*\" {
unsigned char *look;
int count = 0;
yylval.s_value = strcopyof((char *) yytext);
for (look = yytext; *look != 0; look++)
{
if (*look == '\n') line_no++;
if (*look == '"') count++;
}
if (count != 2) yyerror ("NUL character in string.");
return(STRING);
}
{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* {
unsigned char *src, *dst;
int len;
/* remove a trailing decimal point. */
len = strlen((char *) yytext);
if (yytext[len-1] == '.')
yytext[len-1] = 0;
/* remove leading zeros. */
src = yytext;
dst = yytext;
while (*src == '0') src++;
if (*src == 0) src--;
/* Copy strings removing the newlines. */
while (*src != 0)
{
if (*src == '\\')
{
src++; src++;
line_no++;
}
else
*dst++ = *src++;
}
*dst = 0;
yylval.s_value = strcopyof((char *) yytext);
return(NUMBER);
}
. {
if (yytext[0] < ' ')
yyerror ("illegal character: ^%c",yytext[0] + '@');
else
if (yytext[0] > '~')
yyerror ("illegal character: \\%3d", (int) yytext[0]);
else
yyerror ("illegal character: %s",yytext);
}
%%
/* This is the way to get multiple files input into lex. */
int
yywrap()
{
if (!open_new_file ()) return (1); /* EOF on standard in. */
return (0); /* We have more input. */
}

View file

@ -1,967 +0,0 @@
/* storage.c: Code and data storage manipulations. This includes labels. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h"
#include "proto.h"
/* Initialize the storage at the beginning of the run. */
void
init_storage ()
{
/* Functions: we start with none and ask for more. */
f_count = 0;
more_functions ();
f_names[0] = "(main)";
/* Variables. */
v_count = 0;
more_variables ();
/* Arrays. */
a_count = 0;
more_arrays ();
/* Other things... */
ex_stack = NULL;
fn_stack = NULL;
i_base = 10;
o_base = 10;
scale = 0;
c_code = FALSE;
init_numbers();
}
/* Three functions for increasing the number of functions, variables, or
arrays that are needed. This adds another 32 of the requested object. */
void
more_functions (VOID)
{
int old_count;
int indx1, indx2;
bc_function *old_f;
bc_function *f;
char **old_names;
/* Save old information. */
old_count = f_count;
old_f = functions;
old_names = f_names;
/* Add a fixed amount and allocate new space. */
f_count += STORE_INCR;
functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function));
f_names = (char **) bc_malloc (f_count*sizeof (char *));
/* Copy old ones. */
for (indx1 = 0; indx1 < old_count; indx1++)
{
functions[indx1] = old_f[indx1];
f_names[indx1] = old_names[indx1];
}
/* Initialize the new ones. */
for (; indx1 < f_count; indx1++)
{
f = &functions[indx1];
f->f_defined = FALSE;
for (indx2 = 0; indx2 < BC_MAX_SEGS; indx2++)
f->f_body [indx2] = NULL;
f->f_code_size = 0;
f->f_label = NULL;
f->f_autos = NULL;
f->f_params = NULL;
}
/* Free the old elements. */
if (old_count != 0)
{
free (old_f);
free (old_names);
}
}
void
more_variables ()
{
int indx;
int old_count;
bc_var **old_var;
char **old_names;
/* Save the old values. */
old_count = v_count;
old_var = variables;
old_names = v_names;
/* Increment by a fixed amount and allocate. */
v_count += STORE_INCR;
variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *));
v_names = (char **) bc_malloc (v_count*sizeof(char *));
/* Copy the old variables. */
for (indx = 3; indx < old_count; indx++)
variables[indx] = old_var[indx];
/* Initialize the new elements. */
for (; indx < v_count; indx++)
variables[indx] = NULL;
/* Free the old elements. */
if (old_count != 0)
{
free (old_var);
free (old_names);
}
}
void
more_arrays ()
{
int indx;
int old_count;
bc_var_array **old_ary;
char **old_names;
/* Save the old values. */
old_count = a_count;
old_ary = arrays;
old_names = a_names;
/* Increment by a fixed amount and allocate. */
a_count += STORE_INCR;
arrays = (bc_var_array **) bc_malloc (a_count*sizeof(bc_var_array *));
a_names = (char **) bc_malloc (a_count*sizeof(char *));
/* Copy the old arrays. */
for (indx = 1; indx < old_count; indx++)
arrays[indx] = old_ary[indx];
/* Initialize the new elements. */
for (; indx < v_count; indx++)
arrays[indx] = NULL;
/* Free the old elements. */
if (old_count != 0)
{
free (old_ary);
free (old_names);
}
}
/* clear_func clears out function FUNC and makes it ready to redefine. */
void
clear_func (func)
char func;
{
bc_function *f;
int indx;
bc_label_group *lg;
/* Set the pointer to the function. */
f = &functions[func];
f->f_defined = FALSE;
/* Clear the code segments. */
for (indx = 0; indx < BC_MAX_SEGS; indx++)
{
if (f->f_body[indx] != NULL)
{
free (f->f_body[indx]);
f->f_body[indx] = NULL;
}
}
f->f_code_size = 0;
if (f->f_autos != NULL)
{
free_args (f->f_autos);
f->f_autos = NULL;
}
if (f->f_params != NULL)
{
free_args (f->f_params);
f->f_params = NULL;
}
while (f->f_label != NULL)
{
lg = f->f_label->l_next;
free (f->f_label);
f->f_label = lg;
}
}
/* Pop the function execution stack and return the top. */
int
fpop()
{
fstack_rec *temp;
int retval;
if (fn_stack != NULL)
{
temp = fn_stack;
fn_stack = temp->s_next;
retval = temp->s_val;
free (temp);
}
return (retval);
}
/* Push VAL on to the function stack. */
void
fpush (val)
int val;
{
fstack_rec *temp;
temp = (fstack_rec *) bc_malloc (sizeof (fstack_rec));
temp->s_next = fn_stack;
temp->s_val = val;
fn_stack = temp;
}
/* Pop and discard the top element of the regular execution stack. */
void
pop ()
{
estack_rec *temp;
if (ex_stack != NULL)
{
temp = ex_stack;
ex_stack = temp->s_next;
free_num (&temp->s_num);
free (temp);
}
}
/* Push a copy of NUM on to the regular execution stack. */
void
push_copy (num)
bc_num num;
{
estack_rec *temp;
temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
temp->s_num = copy_num (num);
temp->s_next = ex_stack;
ex_stack = temp;
}
/* Push NUM on to the regular execution stack. Do NOT push a copy. */
void
push_num (num)
bc_num num;
{
estack_rec *temp;
temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
temp->s_num = num;
temp->s_next = ex_stack;
ex_stack = temp;
}
/* Make sure the ex_stack has at least DEPTH elements on it.
Return TRUE if it has at least DEPTH elements, otherwise
return FALSE. */
char
check_stack (depth)
int depth;
{
estack_rec *temp;
temp = ex_stack;
while ((temp != NULL) && (depth > 0))
{
temp = temp->s_next;
depth--;
}
if (depth > 0)
{
rt_error ("Stack error.");
return FALSE;
}
return TRUE;
}
/* The following routines manipulate simple variables and
array variables. */
/* get_var returns a pointer to the variable VAR_NAME. If one does not
exist, one is created. */
bc_var *
get_var (var_name)
int var_name;
{
bc_var *var_ptr;
var_ptr = variables[var_name];
if (var_ptr == NULL)
{
var_ptr = variables[var_name] = (bc_var *) bc_malloc (sizeof (bc_var));
init_num (&var_ptr->v_value);
}
return var_ptr;
}
/* get_array_num returns the address of the bc_num in the array
structure. If more structure is requried to get to the index,
this routine does the work to create that structure. VAR_INDEX
is a zero based index into the arrays storage array. INDEX is
the index into the bc array. */
bc_num *
get_array_num (var_index, index)
int var_index;
long index;
{
bc_var_array *ary_ptr;
bc_array *a_var;
bc_array_node *temp;
int log, ix, ix1;
int sub [NODE_DEPTH];
/* Get the array entry. */
ary_ptr = arrays[var_index];
if (ary_ptr == NULL)
{
ary_ptr = arrays[var_index] =
(bc_var_array *) bc_malloc (sizeof (bc_var_array));
ary_ptr->a_value = NULL;
ary_ptr->a_next = NULL;
ary_ptr->a_param = FALSE;
}
a_var = ary_ptr->a_value;
if (a_var == NULL) {
a_var = ary_ptr->a_value = (bc_array *) bc_malloc (sizeof (bc_array));
a_var->a_tree = NULL;
a_var->a_depth = 0;
}
/* Get the index variable. */
sub[0] = index & NODE_MASK;
ix = index >> NODE_SHIFT;
log = 1;
while (ix > 0 || log < a_var->a_depth)
{
sub[log] = ix & NODE_MASK;
ix >>= NODE_SHIFT;
log++;
}
/* Build any tree that is necessary. */
while (log > a_var->a_depth)
{
temp = (bc_array_node *) bc_malloc (sizeof(bc_array_node));
if (a_var->a_depth != 0)
{
temp->n_items.n_down[0] = a_var->a_tree;
for (ix=1; ix < NODE_SIZE; ix++)
temp->n_items.n_down[ix] = NULL;
}
else
{
for (ix=0; ix < NODE_SIZE; ix++)
temp->n_items.n_num[ix] = copy_num(_zero_);
}
a_var->a_tree = temp;
a_var->a_depth++;
}
/* Find the indexed variable. */
temp = a_var->a_tree;
while ( log-- > 1)
{
ix1 = sub[log];
if (temp->n_items.n_down[ix1] == NULL)
{
temp->n_items.n_down[ix1] =
(bc_array_node *) bc_malloc (sizeof(bc_array_node));
temp = temp->n_items.n_down[ix1];
if (log > 1)
for (ix=0; ix < NODE_SIZE; ix++)
temp->n_items.n_down[ix] = NULL;
else
for (ix=0; ix < NODE_SIZE; ix++)
temp->n_items.n_num[ix] = copy_num(_zero_);
}
else
temp = temp->n_items.n_down[ix1];
}
/* Return the address of the indexed variable. */
return &(temp->n_items.n_num[sub[0]]);
}
/* Store the top of the execution stack into VAR_NAME.
This includes the special variables ibase, obase, and scale. */
void
store_var (var_name)
int var_name;
{
bc_var *var_ptr;
long temp;
char toobig;
if (var_name > 2)
{
/* It is a simple variable. */
var_ptr = get_var (var_name);
if (var_ptr != NULL)
{
free_num(&var_ptr->v_value);
var_ptr->v_value = copy_num (ex_stack->s_num);
}
}
else
{
/* It is a special variable... */
toobig = FALSE;
if (is_neg (ex_stack->s_num))
{
switch (var_name)
{
case 0:
rt_warn ("negative ibase, set to 2");
temp = 2;
break;
case 1:
rt_warn ("negative obase, set to 2");
temp = 2;
break;
case 2:
rt_warn ("negative scale, set to 0");
temp = 0;
break;
}
}
else
{
temp = num2long (ex_stack->s_num);
if (!is_zero (ex_stack->s_num) && temp == 0)
toobig = TRUE;
}
switch (var_name)
{
case 0:
if (temp < 2 && !toobig)
{
i_base = 2;
rt_warn ("ibase too small, set to 2");
}
else
if (temp > 16 || toobig)
{
i_base = 16;
rt_warn ("ibase too large, set to 16");
}
else
i_base = (int) temp;
break;
case 1:
if (temp < 2 && !toobig)
{
o_base = 2;
rt_warn ("obase too small, set to 2");
}
else
if (temp > BC_BASE_MAX || toobig)
{
o_base = BC_BASE_MAX;
rt_warn ("obase too large, set to %d", BC_BASE_MAX);
}
else
o_base = (int) temp;
break;
case 2:
/* WARNING: The following if statement may generate a compiler
warning if INT_MAX == LONG_MAX. This is NOT a problem. */
if (temp > BC_SCALE_MAX || toobig )
{
scale = BC_SCALE_MAX;
rt_warn ("scale too large, set to %d", BC_SCALE_MAX);
}
else
scale = (int) temp;
}
}
}
/* Store the top of the execution stack into array VAR_NAME.
VAR_NAME is the name of an array, and the next to the top
of stack for the index into the array. */
void
store_array (var_name)
int var_name;
{
bc_num *num_ptr;
long index;
if (!check_stack(2)) return;
index = num2long (ex_stack->s_next->s_num);
if (index < 0 || index > BC_DIM_MAX ||
(index == 0 && !is_zero(ex_stack->s_next->s_num)))
rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
else
{
num_ptr = get_array_num (var_name, index);
if (num_ptr != NULL)
{
free_num (num_ptr);
*num_ptr = copy_num (ex_stack->s_num);
free_num (&ex_stack->s_next->s_num);
ex_stack->s_next->s_num = ex_stack->s_num;
init_num (&ex_stack->s_num);
pop();
}
}
}
/* Load a copy of VAR_NAME on to the execution stack. This includes
the special variables ibase, obase and scale. */
void
load_var (var_name)
int var_name;
{
bc_var *var_ptr;
switch (var_name)
{
case 0:
/* Special variable ibase. */
push_copy (_zero_);
int2num (&ex_stack->s_num, i_base);
break;
case 1:
/* Special variable obase. */
push_copy (_zero_);
int2num (&ex_stack->s_num, o_base);
break;
case 2:
/* Special variable scale. */
push_copy (_zero_);
int2num (&ex_stack->s_num, scale);
break;
default:
/* It is a simple variable. */
var_ptr = variables[var_name];
if (var_ptr != NULL)
push_copy (var_ptr->v_value);
else
push_copy (_zero_);
}
}
/* Load a copy of VAR_NAME on to the execution stack. This includes
the special variables ibase, obase and scale. */
void
load_array (var_name)
int var_name;
{
bc_num *num_ptr;
long index;
if (!check_stack(1)) return;
index = num2long (ex_stack->s_num);
if (index < 0 || index > BC_DIM_MAX ||
(index == 0 && !is_zero(ex_stack->s_num)))
rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
else
{
num_ptr = get_array_num (var_name, index);
if (num_ptr != NULL)
{
pop();
push_copy (*num_ptr);
}
}
}
/* Decrement VAR_NAME by one. This includes the special variables
ibase, obase, and scale. */
void
decr_var (var_name)
int var_name;
{
bc_var *var_ptr;
switch (var_name)
{
case 0: /* ibase */
if (i_base > 2)
i_base--;
else
rt_warn ("ibase too small in --");
break;
case 1: /* obase */
if (o_base > 2)
o_base--;
else
rt_warn ("obase too small in --");
break;
case 2: /* scale */
if (scale > 0)
scale--;
else
rt_warn ("scale can not be negative in -- ");
break;
default: /* It is a simple variable. */
var_ptr = get_var (var_name);
if (var_ptr != NULL)
bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value);
}
}
/* Decrement VAR_NAME by one. VAR_NAME is an array, and the top of
the execution stack is the index and it is popped off the stack. */
void
decr_array (var_name)
char var_name;
{
bc_num *num_ptr;
long index;
/* It is an array variable. */
if (!check_stack (1)) return;
index = num2long (ex_stack->s_num);
if (index < 0 || index > BC_DIM_MAX ||
(index == 0 && !is_zero (ex_stack->s_num)))
rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
else
{
num_ptr = get_array_num (var_name, index);
if (num_ptr != NULL)
{
pop ();
bc_sub (*num_ptr, _one_, num_ptr);
}
}
}
/* Increment VAR_NAME by one. This includes the special variables
ibase, obase, and scale. */
void
incr_var (var_name)
int var_name;
{
bc_var *var_ptr;
switch (var_name)
{
case 0: /* ibase */
if (i_base < 16)
i_base++;
else
rt_warn ("ibase too big in ++");
break;
case 1: /* obase */
if (o_base < BC_BASE_MAX)
o_base++;
else
rt_warn ("obase too big in ++");
break;
case 2:
if (scale < BC_SCALE_MAX)
scale++;
else
rt_warn ("Scale too big in ++");
break;
default: /* It is a simple variable. */
var_ptr = get_var (var_name);
if (var_ptr != NULL)
bc_add (var_ptr->v_value, _one_, &var_ptr->v_value);
}
}
/* Increment VAR_NAME by one. VAR_NAME is an array and top of
execution stack is the index and is popped off the stack. */
void
incr_array (var_name)
int var_name;
{
bc_num *num_ptr;
long index;
if (!check_stack (1)) return;
index = num2long (ex_stack->s_num);
if (index < 0 || index > BC_DIM_MAX ||
(index == 0 && !is_zero (ex_stack->s_num)))
rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
else
{
num_ptr = get_array_num (var_name, index);
if (num_ptr != NULL)
{
pop ();
bc_add (*num_ptr, _one_, num_ptr);
}
}
}
/* Routines for processing autos variables and parameters. */
/* NAME is an auto variable that needs to be pushed on its stack. */
void
auto_var (name)
int name;
{
bc_var *v_temp;
bc_var_array *a_temp;
int ix;
if (name > 0)
{
/* A simple variable. */
ix = name;
v_temp = (bc_var *) bc_malloc (sizeof (bc_var));
v_temp->v_next = variables[ix];
init_num (&v_temp->v_value);
variables[ix] = v_temp;
}
else
{
/* An array variable. */
ix = -name;
a_temp = (bc_var_array *) bc_malloc (sizeof (bc_var_array));
a_temp->a_next = arrays[ix];
a_temp->a_value = NULL;
a_temp->a_param = FALSE;
arrays[ix] = a_temp;
}
}
/* Free_a_tree frees everything associated with an array variable tree.
This is used when popping an array variable off its auto stack. */
void
free_a_tree ( root, depth )
bc_array_node *root;
int depth;
{
int ix;
if (root != NULL)
{
if (depth > 1)
for (ix = 0; ix < NODE_SIZE; ix++)
free_a_tree (root->n_items.n_down[ix], depth-1);
else
for (ix = 0; ix < NODE_SIZE; ix++)
free_num ( &(root->n_items.n_num[ix]));
free (root);
}
}
/* LIST is an NULL terminated list of varible names that need to be
popped off their auto stacks. */
void
pop_vars (list)
arg_list *list;
{
bc_var *v_temp;
bc_var_array *a_temp;
int ix;
while (list != NULL)
{
ix = list->av_name;
if (ix > 0)
{
/* A simple variable. */
v_temp = variables[ix];
if (v_temp != NULL)
{
variables[ix] = v_temp->v_next;
free_num (&v_temp->v_value);
free (v_temp);
}
}
else
{
/* An array variable. */
ix = -ix;
a_temp = arrays[ix];
if (a_temp != NULL)
{
arrays[ix] = a_temp->a_next;
if (!a_temp->a_param && a_temp->a_value != NULL)
{
free_a_tree (a_temp->a_value->a_tree,
a_temp->a_value->a_depth);
free (a_temp->a_value);
}
free (a_temp);
}
}
list = list->next;
}
}
/* A call is being made to FUNC. The call types are at PC. Process
the parameters by doing an auto on the parameter variable and then
store the value at the new variable or put a pointer the the array
variable. */
void
process_params (pc, func)
program_counter *pc;
int func;
{
char ch;
arg_list *params;
char warned = FALSE;
int ix, ix1;
bc_var *v_temp;
bc_var_array *a_src, *a_dest;
bc_num *n_temp;
/* Get the parameter names from the function. */
params = functions[func].f_params;
while ((ch = byte(pc)) != ':')
{
if (params != NULL)
{
if ((ch == '0') && params->av_name > 0)
{
/* A simple variable. */
ix = params->av_name;
v_temp = (bc_var *) bc_malloc (sizeof(bc_var));
v_temp->v_next = variables[ix];
v_temp->v_value = ex_stack->s_num;
init_num (&ex_stack->s_num);
variables[ix] = v_temp;
}
else
if ((ch == '1') && (params->av_name < 0))
{
/* The variables is an array variable. */
/* Compute source index and make sure some structure exists. */
ix = (int) num2long (ex_stack->s_num);
n_temp = get_array_num (ix, 0);
/* Push a new array and Compute Destination index */
auto_var (params->av_name);
ix1 = -params->av_name;
/* Set up the correct pointers in the structure. */
if (ix == ix1)
a_src = arrays[ix]->a_next;
else
a_src = arrays[ix];
a_dest = arrays[ix1];
a_dest->a_param = TRUE;
a_dest->a_value = a_src->a_value;
}
else
{
if (params->av_name < 0)
rt_error ("Parameter type mismatch parameter %s.",
a_names[-params->av_name]);
else
rt_error ("Parameter type mismatch, parameter %s.",
v_names[params->av_name]);
params++;
}
pop ();
}
else
{
if (!warned)
{
rt_error ("Parameter number mismatch");
warned = TRUE;
}
}
params = params->next;
}
if (params != NULL)
rt_error ("Parameter number mismatch");
}

View file

@ -1,796 +0,0 @@
/* util.c: Utility routines for bc. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#ifndef VARARGS
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "global.h"
#include "proto.h"
/* strcopyof mallocs new memory and copies a string to to the new
memory. */
char *
strcopyof (str)
char *str;
{
char *temp;
temp = (char *) bc_malloc (strlen (str)+1);
return (strcpy (temp,str));
}
/* nextarg adds another value to the list of arguments. */
arg_list *
nextarg (args, val)
arg_list *args;
char val;
{ arg_list *temp;
temp = (arg_list *) bc_malloc (sizeof (arg_list));
temp->av_name = val;
temp->next = args;
return (temp);
}
/* For generate, we must produce a string in the form
"val,val,...,val". We also need a couple of static variables
for retaining old generated strings. It also uses a recursive
function that builds the string. */
static char *arglist1 = NULL, *arglist2 = NULL;
/* make_arg_str does the actual construction of the argument string.
ARGS is the pointer to the list and LEN is the maximum number of
characters needed. 1 char is the minimum needed. COMMAS tells
if each number should be seperated by commas.*/
_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len, int commas));
static char *
make_arg_str (args, len, commas)
arg_list *args;
int len;
int commas;
{
char *temp;
char sval[20];
/* Recursive call. */
if (args != NULL)
temp = make_arg_str (args->next, len+11, commas);
else
{
temp = (char *) bc_malloc (len);
*temp = 0;
return temp;
}
/* Add the current number to the end of the string. */
if (len != 1 && commas)
sprintf (sval, "%d,", args->av_name);
else
sprintf (sval, "%d", args->av_name);
temp = strcat (temp, sval);
return (temp);
}
char *
arg_str (args, commas)
arg_list *args;
int commas;
{
if (arglist2 != NULL)
free (arglist2);
arglist2 = arglist1;
arglist1 = make_arg_str (args, 1, commas);
return (arglist1);
}
/* free_args frees an argument list ARGS. */
void
free_args (args)
arg_list *args;
{
arg_list *temp;
temp = args;
while (temp != NULL)
{
args = args->next;
free (temp);
temp = args;
}
}
/* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
There must be no duplicates any where. Also, this is where
warnings are generated for array parameters. */
void
check_params ( params, autos )
arg_list *params, *autos;
{
arg_list *tmp1, *tmp2;
/* Check for duplicate parameters. */
if (params != NULL)
{
tmp1 = params;
while (tmp1 != NULL)
{
tmp2 = tmp1->next;
while (tmp2 != NULL)
{
if (tmp2->av_name == tmp1->av_name)
yyerror ("duplicate parameter names");
tmp2 = tmp2->next;
}
if (tmp1->av_name < 0)
warn ("Array parameter");
tmp1 = tmp1->next;
}
}
/* Check for duplicate autos. */
if (autos != NULL)
{
tmp1 = autos;
while (tmp1 != NULL)
{
tmp2 = tmp1->next;
while (tmp2 != NULL)
{
if (tmp2->av_name == tmp1->av_name)
yyerror ("duplicate auto variable names");
tmp2 = tmp2->next;
}
tmp1 = tmp1->next;
}
}
/* Check for duplicate between parameters and autos. */
if ((params != NULL) && (autos != NULL))
{
tmp1 = params;
while (tmp1 != NULL)
{
tmp2 = autos;
while (tmp2 != NULL)
{
if (tmp2->av_name == tmp1->av_name)
yyerror ("variable in both parameter and auto lists");
tmp2 = tmp2->next;
}
tmp1 = tmp1->next;
}
}
}
/* Initialize the code generator the parser. */
void
init_gen ()
{
/* Get things ready. */
break_label = 0;
continue_label = 0;
next_label = 1;
out_count = 2;
if (compile_only)
printf ("@i");
else
init_load ();
had_error = FALSE;
did_gen = FALSE;
}
/* generate code STR for the machine. */
void
generate (str)
char *str;
{
did_gen = TRUE;
if (compile_only)
{
printf ("%s",str);
out_count += strlen(str);
if (out_count > 60)
{
printf ("\n");
out_count = 0;
}
}
else
load_code (str);
}
/* Execute the current code as loaded. */
void
run_code()
{
/* If no compile errors run the current code. */
if (!had_error && did_gen)
{
if (compile_only)
{
printf ("@r\n");
out_count = 0;
}
else
execute ();
}
/* Reinitialize the code generation and machine. */
if (did_gen)
init_gen();
else
had_error = FALSE;
}
/* Output routines: Write a character CH to the standard output.
It keeps track of the number of characters output and may
break the output with a "\<cr>". */
void
out_char (ch)
char ch;
{
if (ch == '\n')
{
out_col = 0;
putchar ('\n');
}
else
{
out_col++;
if (out_col == 70)
{
putchar ('\\');
putchar ('\n');
out_col = 1;
}
putchar (ch);
}
}
/* The following are "Symbol Table" routines for the parser. */
/* find_id returns a pointer to node in TREE that has the correct
ID. If there is no node in TREE with ID, NULL is returned. */
id_rec *
find_id (tree, id)
id_rec *tree;
char *id;
{
int cmp_result;
/* Check for an empty tree. */
if (tree == NULL)
return NULL;
/* Recursively search the tree. */
cmp_result = strcmp (id, tree->id);
if (cmp_result == 0)
return tree; /* This is the item. */
else if (cmp_result < 0)
return find_id (tree->left, id);
else
return find_id (tree->right, id);
}
/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
provided. insert_id_rec returns TRUE if the tree height from
ROOT down is increased otherwise it returns FALSE. This is a
recursive balanced binary tree insertion algorithm. */
int insert_id_rec (root, new_id)
id_rec **root;
id_rec *new_id;
{
id_rec *A, *B;
/* If root is NULL, this where it is to be inserted. */
if (*root == NULL)
{
*root = new_id;
new_id->left = NULL;
new_id->right = NULL;
new_id->balance = 0;
return (TRUE);
}
/* We need to search for a leaf. */
if (strcmp (new_id->id, (*root)->id) < 0)
{
/* Insert it on the left. */
if (insert_id_rec (&((*root)->left), new_id))
{
/* The height increased. */
(*root)->balance --;
switch ((*root)->balance)
{
case 0: /* no height increase. */
return (FALSE);
case -1: /* height increase. */
return (FALSE);
case -2: /* we need to do a rebalancing act. */
A = *root;
B = (*root)->left;
if (B->balance <= 0)
{
/* Single Rotate. */
A->left = B->right;
B->right = A;
*root = B;
A->balance = 0;
B->balance = 0;
}
else
{
/* Double Rotate. */
*root = B->right;
B->right = (*root)->left;
A->left = (*root)->right;
(*root)->left = B;
(*root)->right = A;
switch ((*root)->balance)
{
case -1:
A->balance = 1;
B->balance = 0;
break;
case 0:
A->balance = 0;
B->balance = 0;
break;
case 1:
A->balance = 0;
B->balance = -1;
break;
}
(*root)->balance = 0;
}
}
}
}
else
{
/* Insert it on the right. */
if (insert_id_rec (&((*root)->right), new_id))
{
/* The height increased. */
(*root)->balance ++;
switch ((*root)->balance)
{
case 0: /* no height increase. */
return (FALSE);
case 1: /* height increase. */
return (FALSE);
case 2: /* we need to do a rebalancing act. */
A = *root;
B = (*root)->right;
if (B->balance >= 0)
{
/* Single Rotate. */
A->right = B->left;
B->left = A;
*root = B;
A->balance = 0;
B->balance = 0;
}
else
{
/* Double Rotate. */
*root = B->left;
B->left = (*root)->right;
A->right = (*root)->left;
(*root)->left = A;
(*root)->right = B;
switch ((*root)->balance)
{
case -1:
A->balance = 0;
B->balance = 1;
break;
case 0:
A->balance = 0;
B->balance = 0;
break;
case 1:
A->balance = -1;
B->balance = 0;
break;
}
(*root)->balance = 0;
}
}
}
}
/* If we fall through to here, the tree did not grow in height. */
return (FALSE);
}
/* Initialize variables for the symbol table tree. */
void
init_tree()
{
name_tree = NULL;
next_array = 1;
next_func = 1;
next_var = 4; /* 0 => ibase, 1 => obase, 2 => scale, 3 => last. */
}
/* Lookup routines for symbol table names. */
int
lookup (name, namekind)
char *name;
int namekind;
{
id_rec *id;
/* Warn about non-standard name. */
if (strlen(name) != 1)
warn ("multiple letter name - %s", name);
/* Look for the id. */
id = find_id (name_tree, name);
if (id == NULL)
{
/* We need to make a new item. */
id = (id_rec *) bc_malloc (sizeof (id_rec));
id->id = strcopyof (name);
id->a_name = 0;
id->f_name = 0;
id->v_name = 0;
insert_id_rec (&name_tree, id);
}
/* Return the correct value. */
switch (namekind)
{
case ARRAY:
/* ARRAY variable numbers are returned as negative numbers. */
if (id->a_name != 0)
{
free (name);
return (-id->a_name);
}
id->a_name = next_array++;
a_names[id->a_name] = name;
if (id->a_name < MAX_STORE)
{
if (id->a_name >= a_count)
more_arrays ();
return (-id->a_name);
}
yyerror ("Too many array variables");
exit (1);
case FUNCT:
if (id->f_name != 0)
{
free(name);
return (id->f_name);
}
id->f_name = next_func++;
f_names[id->f_name] = name;
if (id->f_name < MAX_STORE)
{
if (id->f_name >= f_count)
more_functions ();
return (id->f_name);
}
yyerror ("Too many functions");
exit (1);
case SIMPLE:
if (id->v_name != 0)
{
free(name);
return (id->v_name);
}
id->v_name = next_var++;
v_names[id->v_name - 1] = name;
if (id->v_name <= MAX_STORE)
{
if (id->v_name >= v_count)
more_variables ();
return (id->v_name);
}
yyerror ("Too many variables");
exit (1);
}
}
/* Print the welcome banner. */
void
welcome()
{
#if !__minix
printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
printf ("For details type `warranty'. \n");
#endif
}
/* Print out the warranty information. */
void
warranty(prefix)
char *prefix;
{
printf ("\n%s%s\n\n", prefix, BC_VERSION);
printf ("%s%s%s%s%s%s%s%s%s%s%s",
" This program is free software; you can redistribute it and/or modify\n",
" it under the terms of the GNU General Public License as published by\n",
" the Free Software Foundation; either version 2 of the License , or\n",
" (at your option) any later version.\n\n",
" This program is distributed in the hope that it will be useful,\n",
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
" GNU General Public License for more details.\n\n",
" You should have received a copy of the GNU General Public License\n",
" along with this program. If not, write to the Free Software\n",
" Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
}
/* Print out the limits of this program. */
void
limits()
{
printf ("BC_BASE_MAX = %d\n", BC_BASE_MAX);
printf ("BC_DIM_MAX = %ld\n", (long) BC_DIM_MAX);
printf ("BC_SCALE_MAX = %d\n", BC_SCALE_MAX);
printf ("BC_STRING_MAX = %d\n", BC_STRING_MAX);
printf ("MAX Exponent = %ld\n", (long) LONG_MAX);
printf ("MAX code = %ld\n", (long) BC_MAX_SEGS * (long) BC_SEG_SIZE);
printf ("multiply digits = %ld\n", (long) LONG_MAX / (long) 90);
printf ("Number of vars = %ld\n", (long) MAX_STORE);
#ifdef OLD_EQ_OP
printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
#endif
}
/* bc_malloc will check the return value so all other places do not
have to do it! SIZE is the number of types to allocate. */
char *
bc_malloc (size)
int size;
{
char *ptr;
ptr = (char *) malloc (size);
if (ptr == NULL)
out_of_memory ();
return ptr;
}
/* The following routines are error routines for various problems. */
/* Malloc could not get enought memory. */
void
out_of_memory()
{
fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
exit (1);
}
/* The standard yyerror routine. Built with variable number of argumnets. */
#ifndef VARARGS
#ifdef __STDC__
void
yyerror (char *str, ...)
#else
void
yyerror (str)
char *str;
#endif
#else
void
yyerror (str, va_alist)
char *str;
#endif
{
char *name;
va_list args;
#ifndef VARARGS
va_start (args, str);
#else
va_start (args);
#endif
if (is_std_in)
name = "(standard_in)";
else
name = g_argv[optind-1];
fprintf (stderr,"%s %d: ",name,line_no);
vfprintf (stderr, str, args);
fprintf (stderr, "\n");
had_error = TRUE;
va_end (args);
}
/* The routine to produce warnings about non-standard features
found during parsing. */
#ifndef VARARGS
#ifdef __STDC__
void
warn (char *mesg, ...)
#else
void
warn (mesg)
char *mesg;
#endif
#else
void
warn (mesg, va_alist)
char *mesg;
#endif
{
char *name;
va_list args;
#ifndef VARARGS
va_start (args, mesg);
#else
va_start (args);
#endif
if (std_only)
{
if (is_std_in)
name = "(standard_in)";
else
name = g_argv[optind-1];
fprintf (stderr,"%s %d: ",name,line_no);
vfprintf (stderr, mesg, args);
fprintf (stderr, "\n");
had_error = TRUE;
}
else
if (warn_not_std)
{
if (is_std_in)
name = "(standard_in)";
else
name = g_argv[optind-1];
fprintf (stderr,"%s %d: (Warning) ",name,line_no);
vfprintf (stderr, mesg, args);
fprintf (stderr, "\n");
}
va_end (args);
}
/* Runtime error will print a message and stop the machine. */
#ifndef VARARGS
#ifdef __STDC__
void
rt_error (char *mesg, ...)
#else
void
rt_error (mesg)
char *mesg;
#endif
#else
void
rt_error (mesg, va_alist)
char *mesg;
#endif
{
va_list args;
char error_mesg [255];
#ifndef VARARGS
va_start (args, mesg);
#else
va_start (args);
#endif
vsprintf (error_mesg, mesg, args);
va_end (args);
fprintf (stderr, "Runtime error (func=%s, adr=%d): %s\n",
f_names[pc.pc_func], pc.pc_addr, error_mesg);
runtime_error = TRUE;
}
/* A runtime warning tells of some action taken by the processor that
may change the program execution but was not enough of a problem
to stop the execution. */
#ifndef VARARGS
#ifdef __STDC__
void
rt_warn (char *mesg, ...)
#else
void
rt_warn (mesg)
char *mesg;
#endif
#else
void
rt_warn (mesg, va_alist)
char *mesg;
#endif
{
va_list args;
char error_mesg [255];
#ifndef VARARGS
va_start (args, mesg);
#else
va_start (args);
#endif
vsprintf (error_mesg, mesg, args);
va_end (args);
fprintf (stderr, "Runtime warning (func=%s, adr=%d): %s\n",
f_names[pc.pc_func], pc.pc_addr, error_mesg);
}

View file

@ -1,3 +0,0 @@
#define BC_VERSION \
"bc 1.02 (Mar 3, 92) Copyright (C) 1991, 1992 Free Software Foundation, Inc."

View file

@ -1,40 +0,0 @@
#define NEWLINE 257
#define AND 258
#define OR 259
#define NOT 260
#define STRING 261
#define NAME 262
#define NUMBER 263
#define MUL_OP 264
#define ASSIGN_OP 265
#define REL_OP 266
#define INCR_DECR 267
#define Define 268
#define Break 269
#define Quit 270
#define Length 271
#define Return 272
#define For 273
#define If 274
#define While 275
#define Sqrt 276
#define Else 277
#define Scale 278
#define Ibase 279
#define Obase 280
#define Auto 281
#define Read 282
#define Warranty 283
#define Halt 284
#define Last 285
#define Continue 286
#define Print 287
#define Limits 288
#define UNARY_MINUS 289
typedef union {
char *s_value;
char c_value;
int i_value;
arg_list *a_value;
} YYSTYPE;
extern YYSTYPE yylval;

View file

@ -28,4 +28,3 @@ clean::
all install clean::
cd asmconv && $(MAKE) $@
cd mtools-3.9.7 && $(MAKE) $@

View file

@ -1,346 +0,0 @@
Copyright (C) 1995 Alain Knaff.
You may use, distribute and copy this program according to the terms of the
GNU General Public License version 2 or later.
Alain Knaff
----------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View file

@ -1,399 +0,0 @@
# Generated automatically from Makefile.in by configure.
#
# Makefile for Mtools
#
# check the Configure file for some examples of device-specific setups
# Berkeley flavors of Unix should include -DBSD in the CFLAGS. Pick
# a lock method... either -DLOCKF, -DFLOCK, or -DFCNTL and put that
# string in the CFLAGS line below.
# User specified flags
USERCFLAGS =
USERLDFLAGS = -stack 11m
USERLDLIBS =
MAKEINFO = makeinfo
TEXI2DVI = texi2dvi
TEXI2HTML = texi2html
# do not edit below this line
# =============================================================================
SHELL = /bin/sh
top_srcdir=.
srcdir=.
prefix = /usr
exec_prefix = ${prefix}
bindir = ${exec_prefix}/bin
infodir = ${prefix}/info
mandir = ${prefix}/man
infodir = ${prefix}/info
sysconfdir = /etc
CC = exec cc -D_MINIX
CXX = @CXX@
MYCFLAGS =
MYCXXFLAGS =
CPPFLAGS =
HOST_ID = -DCPU_i386 -DVENDOR_pc -DOS_Minix
DEFS = -DHAVE_CONFIG_H -DNO_CONFIG $(HOST_ID)
LDFLAGS =
LIBS =
SHLIB =
MACHDEPLIBS =
LN_S = ln -s
INSTALL = /usr/bin/install -cs
INSTALL_PROGRAM = ${INSTALL}
INSTALL_DATA = ${INSTALL} -m 644
INSTALL_INFO =
.SUFFIXES:
.SUFFIXES: .o .c
.SUFFIXES: .o .c
MAN1 = floppyd.1 mattrib.1 mbadblocks.1 mcat.1 mcd.1 mcopy.1 mdel.1 mdeltree.1 mdir.1 \
mdu.1 mformat.1 mkmanifest.1 mlabel.1 mmd.1 mmount.1 mmove.1 mpartition.1 \
mrd.1 mread.1 mren.1 mshowfat.1 mtoolstest.1 mtools.1 mtype.1 mzip.1
MAN1EXT = 1
MAN1DIR = $(mandir)/man${MAN1EXT}
MAN5 = mtools.5
MAN5EXT = 5
MAN5DIR = $(mandir)/man${MAN5EXT}
# all files in this directory included in the distribution
DIST = \
COPYING Changelog INSTALL Makefile Makefile.in README Release.notes \
buffer.c buffer.h codepage.c codepage.h codepages.c config.c \
config.guess config.h.in config.log config.sub configure configure.in \
copyfile.c devices.c devices.h dirCache.c dirCache.h directory.c direntry.c \
expand.c fat.c \
fat_free.c file.c file.h file_name.c file_read.c files filter.c floppyd.1 \
floppyd.c floppyd_io.c floppyd_io.h force_io.c fs.h fsP.h \
getopt.h hash.c htable.h init.c llong.c mainloop.c match.c mattrib.1 \
mattrib.c mbadblocks.1 mbadblocks.c mcat.1 mcat.c mcd.1 mcd.c mcopy.1 \
mcopy.c mdel.1 mdel.c mdeltree.1 mdir.1 mdir.c mdu.c mdu.1 mformat.1 \
mformat.c minfo.c \
misc.c tty.c scsi.c missFuncs.c mk_direntry.c mkmanifest.1 mkmanifest.c \
mlabel.1 mlabel.c mmd.1 mmd.c mmount.1 mmount.c mmove.1 mmove.c \
mpartition.1 mpartition.c mrd.1 \
mread.1 mren.1 msdos.h mshowfat.1 mtoolstest.1 mtools.1 mtools.5 mtools.c \
mtools.conf mtools.h mtype.1 nameclash.h patchlevel.c \
plain_io.c plain_io.h precmd.c privileges.c scripts signal.c stream.c stream.h \
streamcache.c streamcache.h subdir.c sysincludes.h unixdir.c todo toupper.c \
vfat.c vfat.h xdf_io.c xdf_io.h
#OBJS1 = buffer.o codepage.o codepages.o config.o copyfile.o devices.o \
#dirCache.o directory.o direntry.o expand.o fat.o fat_free.o file.o file_name.o \
#file_read.o filter.o floppyd_io.o force_io.o hash.o init.o llong.o match.o \
#mainloop.o mattrib.o mbadblocks.o mcat.o mcd.o mcopy.o mdel.o mdir.o \
#mdoctorfat.o mdu.o \
#mformat.o minfo.o misc.o missFuncs.o mk_direntry.o mlabel.o mmd.o mmount.o \
#mmove.o mpartition.o mshowfat.o mzip.o mtools.o patchlevel.o plain_io.o \
#precmd.o privileges.o scsi.o signal.o stream.o streamcache.o subdir.o \
#unixdir.o toupper.o tty.o vfat.o xdf_io.o
OBJS1 = buffer.o config.o copyfile.o devices.o \
dirCache.o directory.o direntry.o expand.o fat.o fat_free.o file.o file_name.o \
file_read.o filter.o floppyd_io.o force_io.o hash.o init.o llong.o match.o \
mainloop.o mattrib.o mbadblocks.o mcat.o mcd.o mcopy.o mdel.o mdir.o \
mdoctorfat.o mdu.o \
mformat.o minfo.o misc.o missFuncs.o mk_direntry.o mlabel.o mmd.o mmount.o \
mmove.o mpartition.o mshowfat.o mtools.o patchlevel.o plain_io.o \
precmd.o privileges.o scsi.o signal.o stream.o streamcache.o subdir.o \
unixdir.o toupper.o tty.o vfat.o xdf_io.o
OBJS2 = missFuncs.o mkmanifest.o misc.o patchlevel.o
SRCS3 = floppyd.c
OBJS4 = floppyd_installtest.o misc.o expand.o privileges.o
SRCS = buffer.c codepage.c codepages.c config.c copyfile.c devices.c \
dirCache.c directory.c direntry.c expand.c fat.c fat_free.c file.c file_name.c \
file_read.c filter.c floppyd_io.c force_io.c hash.c init.c match.c mainloop.c \
mattrib.c mbadblocks.c mcat.c mcd.c mcopy.c mdel.c mdir.c mdu.c mdoctorfat.c \
mformat.c minfo.c misc.c \
missFuncs.c mk_direntry.c mlabel.c mmd.c mmount.c mmove.c mpartition.c \
mshowfat.c mzip.c mtools.c plain_io.c precmd.c privileges.c scsi.o \
signal.c stream.c streamcache.c subdir.c unixdir.c toupper.c tty.o vfat.c \
xdf_io.c mkmanifest.c
SCRIPTS = mcheck mxtar uz tgz mcomp
LINKS=mattrib mcat mcd mcopy mdel mdeltree mdir mdu mformat minfo mlabel \
mmd mmount mmove mpartition mrd mread mren mtype mtoolstest mshowfat \
mbadblocks mzip
X_CFLAGS =
X_LIBS =
X_EXTRA_LIBS =
X_PRE_LIBS =
CFLAGS = $(CPPFLAGS) $(DEFS) $(MYCFLAGS) -I. -I. $(USERCFLAGS)
CXXFLAGS = $(CPPFLAGS) $(DEFS) $(MYCXXFLAGS) -I. -I. $(USERCFLAGS)
LINK = $(CC) $(LDFLAGS) $(USERLDFLAGS)
ALLLIBS = $(USERLDLIBS) $(MACHDEPLIBS) $(SHLIB) $(LIBS)
X_LDFLAGS = $(X_EXTRA_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lXau -lX11 $(LIBS)
X_CCFLAGS = $(X_CFLAGS) $(CFLAGS)
all: mtools
%.o: %.c
$(CC) $(CFLAGS) -c $<
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) -c $<
mtools: $(OBJS1)
$(LINK) $(OBJS1) -o $@ $(ALLLIBS)
mkmanifest: $(OBJS2)
$(LINK) $(OBJS2) -o $@ $(ALLLIBS)
floppyd.o: floppyd.c
$(CC) $(X_CCFLAGS) -c $<
floppyd: floppyd.o
$(LINK) $< -o $@ $(X_LDFLAGS)
floppyd_installtest: $(OBJS4)
$(LINK) $(OBJS4) -o $@ $(ALLLIBS)
$(LINKS): mtools
rm -f $@ && $(LN_S) mtools $@
mostlyclean:
-rm -f *~ *.orig *.o a.out core 2>/dev/null
clean: mostlyclean
-rm -f mtools $(LINKS) floppyd floppyd_installtest mkmanifest *.info* *.dvi *.html 2>/dev/null
texclean:
-rm mtools.aux mtools.toc mtools.log
-rm mtools.cps mtools.pgs mtools.vrs
-rm mtools.cp mtools.fn mtools.ky
-rm mtools.pg mtools.tp mtools.vr
info: mtools.info
%.info: %.texi
$(MAKEINFO) -I$(srcdir) $< --no-split --output=$@
dvi: mtools.dvi
%.dvi: %.texi
$(TEXI2DVI) $<
ps: mtools.ps
%.ps: %.dvi
dvips -f < $< > $@
pdf: mtools.pdf
%.pdf: %.ps
ps2pdf $< $@
html: mtools.html mtools_toc.html
%.html %_toc.html: %.texi
$(TEXI2HTML) $<
# Don't cd, to avoid breaking install-sh references.
install-info: info
$(top_srcdir)/mkinstalldirs $(infodir)
if test -f mtools.info; then \
for i in mtools.info*; do \
$(INSTALL_DATA) $$i $(infodir)/$$i; \
done; \
else \
for i in $(srcdir)/mtools.info*; do \
$(INSTALL_DATA) $$i $(infodir)/`echo $$i | sed 's|^$(srcdir)/||'`; \
done; \
fi; \
if [ -n "$(INSTALL_INFO)" ] ; then \
if [ -f $(infodir)/dir.info ] ; then \
$(INSTALL_INFO) $(infodir)/mtools.info $(infodir)/dir.info; \
fi; \
if [ -f $(infodir)/dir ] ; then \
$(INSTALL_INFO) $(infodir)/mtools.info $(infodir)/dir; \
fi; \
fi
uninstall-info:
cd $(infodir) && rm -f mtools.info*
install: $(bindir)/mtools
# The manual pages are of such horrible quality that one is better off without
# them. (Frankly this whole package is horrible.) Using -? hopefully gives
# enough clues for use. -- kjb
dontinstall:
$(MAN1DIR)/mattrib.1 $(MAN1DIR)/mbadblocks.1 \
$(MAN1DIR)/mcd.1 $(MAN1DIR)/mcopy.1 $(MAN1DIR)/mdel.1 \
$(MAN1DIR)/mdeltree.1 $(MAN1DIR)/mdir.1 $(MAN1DIR)/mdu.1 \
$(MAN1DIR)/mformat.1 $(MAN1DIR)/mlabel.1 \
$(MAN1DIR)/mmd.1 $(MAN1DIR)/mmove.1 $(MAN1DIR)/mrd.1 \
$(MAN1DIR)/mread.1 $(MAN1DIR)/mren.1 \
$(MAN1DIR)/mshowfat.1 $(MAN1DIR)/mtools.1 \
$(MAN1DIR)/mtype.1 $(MAN1DIR)/mzip.1
$(bindir)/mtools: mtools
install -c $? $@
$(MAN1DIR)/mattrib.1: mattrib.1
install -lc $? $@
$(MAN1DIR)/mbadblocks.1: mbadblocks.1
install -lc $? $@
$(MAN1DIR)/mcd.1: mcd.1
install -lc $? $@
$(MAN1DIR)/mcopy.1: mcopy.1
install -lc $? $@
$(MAN1DIR)/mdel.1: mdel.1
install -lc $? $@
$(MAN1DIR)/mdeltree.1: mdeltree.1
install -lc $? $@
$(MAN1DIR)/mdir.1: mdir.1
install -lc $? $@
$(MAN1DIR)/mdu.1: mdu.1
install -lc $? $@
$(MAN1DIR)/mformat.1: mformat.1
install -lc $? $@
$(MAN1DIR)/mlabel.1: mlabel.1
install -lc $? $@
$(MAN1DIR)/mmd.1: mmd.1
install -lc $? $@
$(MAN1DIR)/mmove.1: mmove.1
install -lc $? $@
$(MAN1DIR)/mrd.1: mrd.1
install -lc $? $@
$(MAN1DIR)/mread.1: mread.1
install -lc $? $@
$(MAN1DIR)/mren.1: mren.1
install -lc $? $@
$(MAN1DIR)/mshowfat.1: mshowfat.1
install -lc $? $@
$(MAN1DIR)/mtools.1: mtools.1
install -lc $? $@
$(MAN1DIR)/mtype.1: mtype.1
install -lc $? $@
$(MAN1DIR)/mzip.1: mzip.1
install -lc $? $@
#install: $(bindir)/mtools install-man install-links \
# $(bindir)/mkmanifest install-scripts install-info
#
#uninstall: uninstall-bin uninstall-man uninstall-links \
# uninstall-scripts
distclean: clean texclean
rm -f config.cache config.h config.status config.log Makefile
maintainer-clean: distclean
#$(bindir)/floppyd: floppyd
# $(top_srcdir)/mkinstalldirs $(bindir)
# $(INSTALL_PROGRAM) floppyd $(bindir)/floppyd
#
#$(bindir)/floppyd_installtest: floppyd_installtest
# $(top_srcdir)/mkinstalldirs $(bindir)
# $(INSTALL_PROGRAM) floppyd_installtest $(bindir)/floppyd_installtest
#
#$(bindir)/mtools: mtools
# $(top_srcdir)/mkinstalldirs $(bindir)
# $(INSTALL_PROGRAM) mtools $(bindir)/mtools
#
#$(bindir)/mkmanifest: mkmanifest
# $(top_srcdir)/mkinstalldirs $(bindir)
# $(INSTALL_PROGRAM) mkmanifest $(bindir)/mkmanifest
#$(ETCDIR)/mtools: mtools.etc
# cp mtools.etc $(ETCDIR)/mtools
install-links: $(bindir)/mtools
@for j in $(LINKS); do \
rm -f $(bindir)/$$j ; \
$(LN_S) mtools $(bindir)/$$j ; \
echo $(bindir)/$$j ; \
done
## "z" is the older version of "gz"; the name is just *too* short
install-scripts: $(bindir)/mtools
@$(top_srcdir)/mkinstalldirs $(bindir)
@for j in $(SCRIPTS) ; do \
$(INSTALL_PROGRAM) $(srcdir)/scripts/$$j $(bindir)/$$j ; \
echo $(bindir)/$$j ; \
done
rm -f $(bindir)/lz
$(LN_S) uz $(bindir)/lz
install-man:
@$(top_srcdir)/mkinstalldirs $(MAN1DIR)
@for j in $(MAN1); do \
$(INSTALL_DATA) $(srcdir)/$$j $(MAN1DIR)/$$j ; \
echo $(MAN1DIR)/$$j ; \
done
@$(top_srcdir)/mkinstalldirs $(MAN5DIR)
@for j in $(MAN5); do \
$(INSTALL_DATA) $(srcdir)/$$j $(MAN5DIR)/$$j ; \
echo $(MAN5DIR)/$$j ; \
done
uninstall-bin:
@for j in mtools mkmanifest; do \
rm -f $(bindir)/$$j ; \
echo $(bindir)/$$j ; \
done
uninstall-scripts:
@for j in $(SCRIPTS); do \
rm -f $(bindir)/$$j ; \
echo $(bindir)/$$j ; \
done
uninstall-man:
@for j in $(MAN1); do \
rm -f $(MAN1DIR)/$$j ; \
echo $(MAN1DIR)/$$j ; \
done
@for j in $(MAN5); do \
rm -f $(MAN5DIR)/$$j ; \
echo $(MAN5DIR)/$$j ; \
done
uninstall-links:
@for j in $(LINKS); \
do rm -f $(bindir)/$$j ; \
echo $(bindir)/$$j ; \
done
depend: $(SRCS)
makedepend -- $(CFLAGS) -- $^
check:
echo No self tests included
# check target needed even if empty, in order to make life easyer for
# automatic tools to install GNU soft
# DO NOT DELETE THIS LINE -- make depend depends on it.

View file

@ -1,53 +0,0 @@
Compilation
-----------
Type 'make install'.
This package has been heavily modified for Minix, and then minimized to
only those files needed for Minix. Don't use this as a basis for anything
else, get the original package instead. -- kjb
Doc
---
The most uptodate doc of this package is the texinfo doc. Type 'make
info' to get online info doc, and 'make dvi ; dvips mtools.dvi' to get
a printed copy. The info doc has a concept index. Make use of it.
You may get an info copy using the following command 'make info'.
This can then be viewed using emacs' info mode, or using a standalone
info viewer.
Man pages are still present, but contain less information, and are
less uptodate than the texinfo documentation.
If you do not have the necessary tools to view the texinfo doc, you
may also find it on the Workd Wide Web at the following locations:
http://mtools.linux.lu/mtools_toc.html
http://www.tux.org/pub/knaff/mtools/mtools_toc.html
Compiler
--------
Mtools should be compiled with an Ansi compiler, preferably gcc
Authors
-------
Original code (versions through 2.0.7?) by Emmet P. Gray (Texas, USA), who
no longer appears to be reachable by Internet e-mail. Viktor Dukhovni (at
Princeton, USA) had major input into v2.0.
Since 2.0.7: maintained primarily and until now informally by Alain
Knaff (Luxembourg) and David Niemi (Reston, Virginia, USA).
Please report bugs to the mtools mailing list at mtools@www.tux.org.
Before reporting any problems, check whether they have already been
fixed in the Alpha patches at http://mtools.linux.lu and
http://www.tux.org/pub/knaff
You may subscribe to the mtools mailing list by sending a message
containing 'subscribe mtools' in its body to majordomo@www.tux.org
Current Status
--------------
Stable release 3.3.

View file

@ -1,365 +0,0 @@
/*
* Buffer read/write module
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "buffer.h"
typedef struct Buffer_t {
Class_t *Class;
int refs;
Stream_t *Next;
Stream_t *Buffer;
size_t size; /* size of read/write buffer */
int dirty; /* is the buffer dirty? */
int sectorSize; /* sector size: all operations happen
* in multiples of this */
int cylinderSize; /* cylinder size: preferred alignemnt,
* but for efficiency, less data may be read */
int ever_dirty; /* was the buffer ever dirty? */
int dirty_pos;
int dirty_end;
mt_off_t current; /* first sector in buffer */
size_t cur_size; /* the current size */
char *buf; /* disk read/write buffer */
} Buffer_t;
/*
* Flush a dirty buffer to disk. Resets Buffer->dirty to zero.
* All errors are fatal.
*/
static int _buf_flush(Buffer_t *Buffer)
{
int ret;
if (!Buffer->Next || !Buffer->dirty)
return 0;
if(Buffer->current < 0L) {
fprintf(stderr,"Should not happen\n");
return -1;
}
#ifdef DEBUG
fprintf(stderr, "write %08x -- %02x %08x %08x\n",
Buffer,
(unsigned char) Buffer->buf[0],
Buffer->current + Buffer->dirty_pos,
Buffer->dirty_end - Buffer->dirty_pos);
#endif
ret = force_write(Buffer->Next,
Buffer->buf + Buffer->dirty_pos,
Buffer->current + Buffer->dirty_pos,
Buffer->dirty_end - Buffer->dirty_pos);
if(ret != Buffer->dirty_end - Buffer->dirty_pos) {
if(ret < 0)
perror("buffer_flush: write");
else
fprintf(stderr,"buffer_flush: short write\n");
return -1;
}
Buffer->dirty = 0;
Buffer->dirty_end = 0;
Buffer->dirty_pos = 0;
return 0;
}
static int invalidate_buffer(Buffer_t *Buffer, mt_off_t start)
{
/*fprintf(stderr, "invalidate %x\n", Buffer);*/
if(Buffer->sectorSize == 32) {
fprintf(stderr, "refreshing directory\n");
}
if(_buf_flush(Buffer) < 0)
return -1;
/* start reading at the beginning of start's sector
* don't start reading too early, or we might not even reach
* start */
Buffer->current = ROUND_DOWN(start, Buffer->sectorSize);
Buffer->cur_size = 0;
return 0;
}
#undef OFFSET
#define OFFSET (start - This->current)
typedef enum position_t {
OUTSIDE,
APPEND,
INSIDE,
ERROR
} position_t;
static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len)
{
if(start >= This->current &&
start < This->current + This->cur_size) {
maximize(*len, This->cur_size - OFFSET);
return INSIDE;
} else if(start == This->current + This->cur_size &&
This->cur_size < This->size &&
*len >= This->sectorSize) {
/* append to the buffer for this, three conditions have to
* be met:
* 1. The start falls exactly at the end of the currently
* loaded data
* 2. There is still space
* 3. We append at least one sector
*/
maximize(*len, This->size - This->cur_size);
*len = ROUND_DOWN(*len, This->sectorSize);
return APPEND;
} else {
if(invalidate_buffer(This, start) < 0)
return ERROR;
maximize(*len, This->cylinderSize - OFFSET);
maximize(*len, This->cylinderSize - This->current % This->cylinderSize);
return OUTSIDE;
}
}
static int buf_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
{
size_t length;
int offset;
char *disk_ptr;
int ret;
DeclareThis(Buffer_t);
if(!len)
return 0;
/*fprintf(stderr, "buf read %x %x %x\n", Stream, start, len);*/
switch(isInBuffer(This, start, &len)) {
case OUTSIDE:
case APPEND:
/* always load until the end of the cylinder */
length = This->cylinderSize -
(This->current + This->cur_size) % This->cylinderSize;
maximize(length, This->size - This->cur_size);
/* read it! */
ret=READS(This->Next,
This->buf + This->cur_size,
This->current + This->cur_size,
length);
if ( ret < 0 )
return ret;
This->cur_size += ret;
if (This->current+This->cur_size < start) {
fprintf(stderr, "Short buffer fill\n");
exit(1);
}
break;
case INSIDE:
/* nothing to do */
break;
case ERROR:
return -1;
}
offset = OFFSET;
disk_ptr = This->buf + offset;
maximize(len, This->cur_size - offset);
memcpy(buf, disk_ptr, len);
return len;
}
static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
{
char *disk_ptr;
DeclareThis(Buffer_t);
int offset, ret;
if(!len)
return 0;
This->ever_dirty = 1;
#ifdef DEBUG
fprintf(stderr, "buf write %x %02x %08x %08x -- %08x %08x -- %08x\n",
Stream, (unsigned char) This->buf[0],
start, len, This->current, This->cur_size, This->size);
fprintf(stderr, "%d %d %d %x %x\n",
start == This->current + This->cur_size,
This->cur_size < This->size,
len >= This->sectorSize, len, This->sectorSize);
#endif
switch(isInBuffer(This, start, &len)) {
case OUTSIDE:
#ifdef DEBUG
fprintf(stderr, "outside\n");
#endif
if(start % This->cylinderSize ||
len < This->sectorSize) {
size_t readSize;
readSize = This->cylinderSize -
This->current % This->cylinderSize;
ret=READS(This->Next, This->buf, This->current, readSize);
/* read it! */
if ( ret < 0 )
return ret;
This->cur_size = ret;
/* for dosemu. Autoextend size */
if(!This->cur_size) {
memset(This->buf,0,readSize);
This->cur_size = readSize;
}
offset = OFFSET;
break;
}
/* FALL THROUGH */
case APPEND:
#ifdef DEBUG
fprintf(stderr, "append\n");
#endif
len = ROUND_DOWN(len, This->sectorSize);
offset = OFFSET;
maximize(len, This->size - offset);
This->cur_size += len;
if(This->Next->Class->pre_allocate)
PRE_ALLOCATE(This->Next,
This->current + This->cur_size);
break;
case INSIDE:
/* nothing to do */
#ifdef DEBUG
fprintf(stderr, "inside\n");
#endif
offset = OFFSET;
maximize(len, This->cur_size - offset);
break;
case ERROR:
return -1;
default:
#ifdef DEBUG
fprintf(stderr, "Should not happen\n");
#endif
exit(1);
}
disk_ptr = This->buf + offset;
/* extend if we write beyond end */
if(offset + len > This->cur_size) {
len -= (offset + len) % This->sectorSize;
This->cur_size = len + offset;
}
memcpy(disk_ptr, buf, len);
if(!This->dirty || offset < This->dirty_pos)
This->dirty_pos = ROUND_DOWN(offset, This->sectorSize);
if(!This->dirty || offset + len > This->dirty_end)
This->dirty_end = ROUND_UP(offset + len, This->sectorSize);
if(This->dirty_end > This->cur_size) {
fprintf(stderr,
"Internal error, dirty end too big %x %x %x %d %x\n",
This->dirty_end, (unsigned int) This->cur_size, (unsigned int) len,
(int) offset, (int) This->sectorSize);
fprintf(stderr, "offset + len + grain - 1 = %x\n",
(int) (offset + len + This->sectorSize - 1));
fprintf(stderr, "ROUNDOWN(offset + len + grain - 1) = %x\n",
(int)ROUND_DOWN(offset + len + This->sectorSize - 1,
This->sectorSize));
fprintf(stderr, "This->dirty = %d\n", This->dirty);
exit(1);
}
This->dirty = 1;
return len;
}
static int buf_flush(Stream_t *Stream)
{
int ret;
DeclareThis(Buffer_t);
if (!This->ever_dirty)
return 0;
ret = _buf_flush(This);
if(ret == 0)
This->ever_dirty = 0;
return ret;
}
static int buf_free(Stream_t *Stream)
{
DeclareThis(Buffer_t);
if(This->buf)
free(This->buf);
This->buf = 0;
return 0;
}
static Class_t BufferClass = {
buf_read,
buf_write,
buf_flush,
buf_free,
0, /* set_geom */
get_data_pass_through, /* get_data */
0, /* pre-allocate */
};
Stream_t *buf_init(Stream_t *Next, int size,
int cylinderSize,
int sectorSize)
{
Buffer_t *Buffer;
Stream_t *Stream;
if(size % cylinderSize != 0) {
fprintf(stderr, "size not multiple of cylinder size\n");
exit(1);
}
if(cylinderSize % sectorSize != 0) {
fprintf(stderr, "cylinder size not multiple of sector size\n");
exit(1);
}
if(Next->Buffer){
Next->refs--;
Next->Buffer->refs++;
return Next->Buffer;
}
Stream = (Stream_t *) malloc (sizeof(Buffer_t));
if(!Stream)
return 0;
Buffer = (Buffer_t *) Stream;
Buffer->buf = malloc(size);
if ( !Buffer->buf){
Free(Stream);
return 0;
}
Buffer->size = size;
Buffer->dirty = 0;
Buffer->cylinderSize = cylinderSize;
Buffer->sectorSize = sectorSize;
Buffer->ever_dirty = 0;
Buffer->dirty_pos = 0;
Buffer->dirty_end = 0;
Buffer->current = 0;
Buffer->cur_size = 0; /* buffer currently empty */
Buffer->Next = Next;
Buffer->Class = &BufferClass;
Buffer->refs = 1;
Buffer->Buffer = 0;
Buffer->Next->Buffer = (Stream_t *) Buffer;
return Stream;
}

View file

@ -1,11 +0,0 @@
#ifndef MTOOLS_BUFFER_H
#define MTOOLS_BUFFER_H
#include "stream.h"
Stream_t *buf_init(Stream_t *Next,
int size,
int cylinderSize,
int sectorSize);
#endif

View file

@ -1,3 +0,0 @@
#!/bin/sh
make && make install

View file

@ -1,35 +0,0 @@
typedef struct Codepage_l {
int nr;
unsigned char tounix[128];
} Codepage_t;
typedef struct country_l {
int country;
int codepage;
int default_codepage;
int to_upper;
} country_t;
#ifndef NO_CONFIG
void init_codepage(void);
unsigned char to_dos(unsigned char c);
void to_unix(char *a, int n);
#define mstoupper(c) mstoupper[(c) & 0x7F]
#else /* NO_CONFIG */
/* Imagine a codepage with 128 uppercase letters for the top 128 characters. */
#define mstoupper(c) (c)
#define to_dos(c) (c)
#define to_unix(a, n) ((void) 0)
#define mstoupper(c) (c)
#endif
extern Codepage_t *Codepage;
extern char *mstoupper;
extern country_t countries[];
extern unsigned char toucase[][128];
extern Codepage_t codepages[];
extern char *country_string;

View file

@ -1,808 +0,0 @@
#include "sysincludes.h"
#include "mtools.h"
#include "codepage.h"
#include "mtoolsPaths.h"
/* global variables */
/* they are not really harmful here, because there is only one configuration
* file per invocations */
#ifndef NO_CONFIG
#define MAX_LINE_LEN 256
/* scanner */
static char buffer[MAX_LINE_LEN+1]; /* buffer for the whole line */
static char *pos; /* position in line */
static char *token; /* last scanned token */
static int token_length; /* length of the token */
static FILE *fp; /* file pointer for configuration file */
static int linenumber; /* current line number. Only used for printing
* error messages */
static int lastTokenLinenumber; /* line numnber for last token */
static const char *filename; /* current file name. Only used for printing
* error messages */
static int file_nr=0;
static int flag_mask; /* mask of currently set flags */
/* devices */
static int cur_devs; /* current number of defined devices */
static int cur_dev; /* device being filled in. If negative, none */
static int trusted=0; /* is the currently parsed device entry trusted? */
static int nr_dev; /* number of devices that the current table can hold */
static int token_nr; /* number of tokens in line */
static char letters[][2] = { /* drive letter to letter-as-a-string */
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
};
#endif /* !NO_CONFIG */
struct device *devices; /* the device table */
/* "environment" variables */
unsigned int mtools_skip_check=0;
unsigned int mtools_fat_compatibility=0;
unsigned int mtools_ignore_short_case=0;
unsigned int mtools_rate_0=0;
unsigned int mtools_rate_any=0;
unsigned int mtools_no_vfat=0;
unsigned int mtools_numeric_tail=1;
unsigned int mtools_dotted_dir=0;
unsigned int mtools_twenty_four_hour_clock=1;
char *mtools_date_string="mm-dd-yyyy";
char *country_string=0;
#ifndef NO_CONFIG
typedef struct switches_l {
const char *name;
caddr_t address;
enum {
T_INT,
T_STRING,
T_UINT
} type;
} switches_t;
static switches_t switches[] = {
{ "MTOOLS_LOWER_CASE", (caddr_t) & mtools_ignore_short_case, T_UINT },
{ "MTOOLS_FAT_COMPATIBILITY", (caddr_t) & mtools_fat_compatibility, T_UINT },
{ "MTOOLS_SKIP_CHECK", (caddr_t) & mtools_skip_check, T_UINT },
{ "MTOOLS_NO_VFAT", (caddr_t) & mtools_no_vfat, T_UINT },
{ "MTOOLS_RATE_0", (caddr_t) &mtools_rate_0, T_UINT },
{ "MTOOLS_RATE_ANY", (caddr_t) &mtools_rate_any, T_UINT },
{ "MTOOLS_NAME_NUMERIC_TAIL", (caddr_t) &mtools_numeric_tail, T_UINT },
{ "MTOOLS_DOTTED_DIR", (caddr_t) &mtools_dotted_dir, T_UINT },
{ "MTOOLS_TWENTY_FOUR_HOUR_CLOCK",
(caddr_t) &mtools_twenty_four_hour_clock, T_UINT },
{ "MTOOLS_DATE_STRING",
(caddr_t) &mtools_date_string, T_STRING },
{ "COUNTRY", (caddr_t) &country_string, T_STRING }
};
typedef struct {
const char *name;
int flag;
} flags_t;
static flags_t openflags[] = {
#ifdef O_SYNC
{ "sync", O_SYNC },
#endif
#ifdef O_NDELAY
{ "nodelay", O_NDELAY },
#endif
#ifdef O_EXCL
{ "exclusive", O_EXCL },
#endif
{ "none", 0 } /* hack for those compilers that choke on commas
* after the last element of an array */
};
static flags_t misc_flags[] = {
#ifdef USE_XDF
{ "use_xdf", USE_XDF_FLAG },
#endif
{ "scsi", SCSI_FLAG },
{ "nolock", NOLOCK_FLAG },
{ "mformat_only", MFORMAT_ONLY_FLAG },
{ "filter", FILTER_FLAG },
{ "privileged", PRIV_FLAG },
{ "vold", VOLD_FLAG },
{ "remote", FLOPPYD_FLAG }
};
static struct {
const char *name;
signed char fat_bits;
int tracks;
unsigned short heads;
unsigned short sectors;
} default_formats[] = {
{ "hd514", 12, 80, 2, 15 },
{ "high-density-5-1/4", 12, 80, 2, 15 },
{ "1.2m", 12, 80, 2, 15 },
{ "hd312", 12, 80, 2, 18 },
{ "high-density-3-1/2", 12, 80, 2, 18 },
{ "1.44m", 12, 80, 2, 18 },
{ "dd312", 12, 80, 2, 9 },
{ "double-density-3-1/2", 12, 80, 2, 9 },
{ "720k", 12, 80, 2, 9 },
{ "dd514", 12, 40, 2, 9 },
{ "double-density-5-1/4", 12, 40, 2, 9 },
{ "360k", 12, 40, 2, 9 },
{ "320k", 12, 40, 2, 8 },
{ "180k", 12, 40, 1, 9 },
{ "160k", 12, 40, 1, 8 }
};
#define OFFS(x) ((caddr_t)&((struct device *)0)->x)
static switches_t dswitches[]= {
{ "FILE", OFFS(name), T_STRING },
{ "OFFSET", OFFS(offset), T_UINT },
{ "PARTITION", OFFS(partition), T_UINT },
{ "FAT", OFFS(fat_bits), T_INT },
{ "FAT_BITS", OFFS(fat_bits), T_UINT },
{ "MODE", OFFS(mode), T_UINT },
{ "TRACKS", OFFS(tracks), T_UINT },
{ "CYLINDERS", OFFS(tracks), T_UINT },
{ "HEADS", OFFS(heads), T_UINT },
{ "SECTORS", OFFS(sectors), T_UINT },
{ "HIDDEN", OFFS(hidden), T_UINT },
{ "PRECMD", OFFS(precmd), T_STRING },
{ "BLOCKSIZE", OFFS(blocksize), T_UINT }
};
static void syntax(const char *msg, int thisLine)
{
char *drive=NULL;
if(thisLine)
lastTokenLinenumber = linenumber;
if(cur_dev >= 0)
drive = devices[cur_dev].drive;
fprintf(stderr,"Syntax error at line %d ", lastTokenLinenumber);
if(drive) fprintf(stderr, "for drive %s: ", drive);
if(token) fprintf(stderr, "column %ld ", (long)(token - buffer));
fprintf(stderr, "in file %s: %s\n", filename, msg);
exit(1);
}
static void get_env_conf(void)
{
char *s;
int i;
for(i=0; i< sizeof(switches) / sizeof(*switches); i++) {
s = getenv(switches[i].name);
if(s) {
if(switches[i].type == T_INT)
* ((int *)switches[i].address) = (int) strtol(s,0,0);
if(switches[i].type == T_UINT)
* ((int *)switches[i].address) = (unsigned int) strtoul(s,0,0);
else if (switches[i].type == T_STRING)
* ((char **)switches[i].address) = s;
}
}
}
static int mtools_getline(void)
{
if(!fgets(buffer, MAX_LINE_LEN, fp))
return -1;
linenumber++;
pos = buffer;
token_nr = 0;
buffer[MAX_LINE_LEN] = '\0';
if(strlen(buffer) == MAX_LINE_LEN)
syntax("line too long", 1);
return 0;
}
static void skip_junk(int expect)
{
lastTokenLinenumber = linenumber;
while(!pos || !*pos || strchr(" #\n\t", *pos)) {
if(!pos || !*pos || *pos == '#') {
if(mtools_getline()) {
pos = 0;
if(expect)
syntax("end of file unexpected", 1);
return;
}
} else
pos++;
}
token_nr++;
}
/* get the next token */
static char *get_next_token(void)
{
skip_junk(0);
if(!pos) {
token_length = 0;
token = 0;
return 0;
}
token = pos;
token_length = strcspn(token, " \t\n#:=");
pos += token_length;
return token;
}
static int match_token(const char *template)
{
return (strlen(template) == token_length &&
!strncasecmp(template, token, token_length));
}
static void expect_char(char c)
{
char buf[11];
skip_junk(1);
if(*pos != c) {
sprintf(buf, "expected %c", c);
syntax(buf, 1);
}
pos++;
}
static char *get_string(void)
{
char *end, *str;
skip_junk(1);
if(*pos != '"')
syntax(" \" expected", 0);
str = pos+1;
end = strchr(str, '\"');
if(!end)
syntax("unterminated string constant", 1);
*end = '\0';
pos = end+1;
return str;
}
static unsigned int get_unumber(void)
{
char *last;
unsigned int n;
skip_junk(1);
last = pos;
n=(unsigned int) strtoul(pos, &pos, 0);
if(last == pos)
syntax("numeral expected", 0);
pos++;
token_nr++;
return n;
}
static unsigned int get_number(void)
{
char *last;
int n;
skip_junk(1);
last = pos;
n=(int) strtol(pos, &pos, 0);
if(last == pos)
syntax("numeral expected", 0);
pos++;
token_nr++;
return n;
}
/* purge all entries pertaining to a given drive from the table */
static void purge(char drive, int fn)
{
int i,j;
drive = toupper(drive);
for(j=0, i=0; i < cur_devs; i++) {
if(devices[i].drive[0] != drive ||
devices[i].drive[1] != 0 ||
devices[i].file_nr == fn)
devices[j++] = devices[i];
}
cur_devs = j;
}
static void grow(void)
{
if(cur_devs >= nr_dev - 2) {
nr_dev = (cur_devs + 2) << 1;
if(!(devices=Grow(devices, nr_dev, struct device))){
printOom();
exit(1);
}
}
}
static void init_drive(void)
{
memset((char *)&devices[cur_dev], 0, sizeof(struct device));
devices[cur_dev].ssize = 2;
}
/* prepends a device to the table */
static void prepend(void)
{
int i;
grow();
for(i=cur_devs; i>0; i--)
devices[i] = devices[i-1];
cur_dev = 0;
cur_devs++;
init_drive();
}
/* appends a device to the table */
static void append(void)
{
grow();
cur_dev = cur_devs;
cur_devs++;
init_drive();
}
static void finish_drive_clause(void)
{
char *drive;
if(cur_dev == -1) {
trusted = 0;
return;
}
drive = devices[cur_dev].drive;
if(!devices[cur_dev].name)
syntax("missing filename", 0);
if(devices[cur_dev].tracks ||
devices[cur_dev].heads ||
devices[cur_dev].sectors) {
if(!devices[cur_dev].tracks ||
!devices[cur_dev].heads ||
!devices[cur_dev].sectors)
syntax("incomplete geometry: either indicate all of track/heads/sectors or none of them", 0);
if(!(devices[cur_dev].misc_flags &
(MFORMAT_ONLY_FLAG | FILTER_FLAG)))
syntax("if you supply a geometry, you also must supply one of the `mformat_only' or `filter' flags", 0);
}
devices[cur_dev].file_nr = file_nr;
devices[cur_dev].cfg_filename = filename;
if(! (flag_mask & PRIV_FLAG) && IS_SCSI(&devices[cur_dev]))
devices[cur_dev].misc_flags |= PRIV_FLAG;
if(!trusted && (devices[cur_dev].misc_flags & PRIV_FLAG)) {
fprintf(stderr,
"Warning: privileged flag ignored for drive %s: defined in file %s\n",
devices[cur_dev].drive, filename);
devices[cur_dev].misc_flags &= ~PRIV_FLAG;
}
trusted = 0;
cur_dev = -1;
}
static int set_var(struct switches_l *switches, int nr,
caddr_t base_address)
{
int i;
for(i=0; i < nr; i++) {
if(match_token(switches[i].name)) {
expect_char('=');
if(switches[i].type == T_UINT)
* ((int *)((long)switches[i].address+base_address)) =
get_unumber();
if(switches[i].type == T_INT)
* ((int *)((long)switches[i].address+base_address)) =
get_number();
else if (switches[i].type == T_STRING)
* ((char**)((long)switches[i].address+base_address))=
strdup(get_string());
return 0;
}
}
return 1;
}
static int set_openflags(struct device *dev)
{
int i;
for(i=0; i < sizeof(openflags) / sizeof(*openflags); i++) {
if(match_token(openflags[i].name)) {
dev->mode |= openflags[i].flag;
return 0;
}
}
return 1;
}
static int set_misc_flags(struct device *dev)
{
int i;
for(i=0; i < sizeof(misc_flags) / sizeof(*misc_flags); i++) {
if(match_token(misc_flags[i].name)) {
flag_mask |= misc_flags[i].flag;
skip_junk(0);
if(pos && *pos == '=') {
pos++;
switch(get_number()) {
case 0:
return 0;
case 1:
break;
default:
syntax("expected 0 or 1", 0);
}
}
dev->misc_flags |= misc_flags[i].flag;
return 0;
}
}
return 1;
}
static int set_def_format(struct device *dev)
{
int i;
for(i=0; i < sizeof(default_formats)/sizeof(*default_formats); i++) {
if(match_token(default_formats[i].name)) {
if(!dev->ssize)
dev->ssize = 2;
if(!dev->tracks)
dev->tracks = default_formats[i].tracks;
if(!dev->heads)
dev->heads = default_formats[i].heads;
if(!dev->sectors)
dev->sectors = default_formats[i].sectors;
if(!dev->fat_bits)
dev->fat_bits = default_formats[i].fat_bits;
return 0;
}
}
return 1;
}
static void get_codepage(void)
{
int i;
unsigned short n;
if(!Codepage)
Codepage = New(Codepage_t);
for(i=0; i<128; i++) {
n = get_number();
if(n > 0xff)
n = 0x5f;
Codepage->tounix[i] = n;
}
}
static void get_toupper(void)
{
int i;
if(!mstoupper)
mstoupper = safe_malloc(128);
for(i=0; i<128; i++)
mstoupper[i] = get_number();
}
static void parse_old_device_line(char drive)
{
char name[MAXPATHLEN];
int items;
long offset;
char newdrive;
/* finish any old drive */
finish_drive_clause();
/* purge out data of old configuration files */
purge(drive, file_nr);
/* reserve slot */
append();
items = sscanf(token,"%c %s %i %i %i %i %li",
&newdrive,name,&devices[cur_dev].fat_bits,
&devices[cur_dev].tracks,&devices[cur_dev].heads,
&devices[cur_dev].sectors, &offset);
devices[cur_dev].offset = (off_t) offset;
switch(items){
case 2:
devices[cur_dev].fat_bits = 0;
/* fall thru */
case 3:
devices[cur_dev].sectors = 0;
devices[cur_dev].heads = 0;
devices[cur_dev].tracks = 0;
/* fall thru */
case 6:
devices[cur_dev].offset = 0;
/* fall thru */
default:
break;
case 0:
case 1:
case 4:
case 5:
syntax("bad number of parameters", 1);
exit(1);
}
if(!devices[cur_dev].tracks){
devices[cur_dev].sectors = 0;
devices[cur_dev].heads = 0;
}
devices[cur_dev].drive = letters[toupper(newdrive) - 'A'];
if (!(devices[cur_dev].name = strdup(name))) {
printOom();
exit(1);
}
finish_drive_clause();
pos=0;
}
static int parse_one(int privilege)
{
int action=0;
get_next_token();
if(!token)
return 0;
if((match_token("drive") && ((action = 1)))||
(match_token("drive+") && ((action = 2))) ||
(match_token("+drive") && ((action = 3))) ||
(match_token("clear_drive") && ((action = 4))) ) {
/* finish off the previous drive */
finish_drive_clause();
get_next_token();
if(token_length != 1)
syntax("drive letter expected", 0);
if(action==1 || action==4)
/* replace existing drive */
purge(token[0], file_nr);
if(action==4)
return 1;
if(action==3)
prepend();
else
append();
memset((char*)(devices+cur_dev), 0, sizeof(*devices));
trusted = privilege;
flag_mask = 0;
devices[cur_dev].drive = letters[toupper(token[0]) - 'A'];
expect_char(':');
return 1;
}
if(token_nr == 1 && token_length == 1) {
parse_old_device_line(token[0]);
return 1;
}
if(match_token("default_fucase")) {
free(mstoupper);
mstoupper=0;
}
if(match_token("default_tounix")) {
Free(Codepage);
Codepage = 0;
}
if(match_token("fucase")) {
expect_char(':');
get_toupper();
return 1;
}
if(match_token("tounix")) {
expect_char(':');
get_codepage();
return 1;
}
if((cur_dev < 0 ||
(set_var(dswitches,
sizeof(dswitches)/sizeof(*dswitches),
(caddr_t)&devices[cur_dev]) &&
set_openflags(&devices[cur_dev]) &&
set_misc_flags(&devices[cur_dev]) &&
set_def_format(&devices[cur_dev]))) &&
set_var(switches,
sizeof(switches)/sizeof(*switches), 0))
syntax("unrecognized keyword", 1);
return 1;
}
static int parse(const char *name, int privilege)
{
fp = fopen(name, "r");
if(!fp)
return 0;
file_nr++;
filename = strdup(name);
linenumber = 0;
lastTokenLinenumber = 0;
pos = 0;
token = 0;
cur_dev = -1; /* no current device */
while(parse_one(privilege));
finish_drive_clause();
fclose(fp);
return 1;
}
void read_config(void)
{
char *homedir;
char *envConfFile;
char conf_file[MAXPATHLEN+sizeof(CFG_FILE1)];
/* copy compiled-in devices */
file_nr = 0;
cur_devs = nr_const_devices;
nr_dev = nr_const_devices + 2;
devices = NewArray(nr_dev, struct device);
if(!devices) {
printOom();
exit(1);
}
if(nr_const_devices)
memcpy(devices, const_devices,
nr_const_devices*sizeof(struct device));
(void) ((parse(CONF_FILE,1) |
parse(LOCAL_CONF_FILE,1) |
parse(SYS_CONF_FILE,1)) ||
(parse(OLD_CONF_FILE,1) |
parse(OLD_LOCAL_CONF_FILE,1)));
/* the old-name configuration files only get executed if none of the
* new-name config files were used */
homedir = get_homedir();
if ( homedir ){
strncpy(conf_file, homedir, MAXPATHLEN );
conf_file[MAXPATHLEN]='\0';
strcat( conf_file, CFG_FILE1);
parse(conf_file,0);
}
memset((char *)&devices[cur_devs],0,sizeof(struct device));
envConfFile = getenv("MTOOLSRC");
if(envConfFile)
parse(envConfFile,0);
/* environmental variables */
get_env_conf();
if(mtools_skip_check)
mtools_fat_compatibility=1;
init_codepage();
}
void mtoolstest(int argc, char **argv, int type)
{
/* testing purposes only */
struct device *dev;
int i,j;
char *drive=NULL;
char *path;
if (argc > 1 && (path = skip_drive(argv[1])) > argv[1]) {
drive = get_drive(argv[1], NULL);
}
for (dev=devices; dev->name; dev++) {
if(drive && strcmp(drive, dev->drive) != 0)
continue;
printf("drive %s:\n", dev->drive);
printf("\t#fn=%d mode=%d ",
dev->file_nr, dev->mode);
if(dev->cfg_filename)
printf("defined in %s\n", dev->cfg_filename);
else
printf("builtin\n");
printf("\tfile=\"%s\" fat_bits=%d \n",
dev->name,dev->fat_bits);
printf("\ttracks=%d heads=%d sectors=%d hidden=%d\n",
dev->tracks, dev->heads, dev->sectors, dev->hidden);
printf("\toffset=0x%lx\n", (long) dev->offset);
printf("\tpartition=%d\n", dev->partition);
if(dev->misc_flags)
printf("\t");
if(IS_SCSI(dev))
printf("scsi ");
if(IS_PRIVILEGED(dev))
printf("privileged");
if(IS_MFORMAT_ONLY(dev))
printf("mformat_only ");
if(SHOULD_USE_VOLD(dev))
printf("vold ");
#ifdef USE_XDF
if(SHOULD_USE_XDF(dev))
printf("use_xdf ");
#endif
if(dev->misc_flags)
printf("\n");
if(dev->mode)
printf("\t");
#ifdef O_SYNC
if(dev->mode & O_SYNC)
printf("sync ");
#endif
#ifdef O_NDELAY
if((dev->mode & O_NDELAY))
printf("nodelay ");
#endif
#ifdef O_EXCL
if((dev->mode & O_EXCL))
printf("exclusive ");
#endif
if(dev->mode)
printf("\n");
if(dev->precmd)
printf("\tprecmd=%s\n", dev->precmd);
printf("\n");
}
printf("tounix:\n");
for(i=0; i < 16; i++) {
putchar('\t');
for(j=0; j<8; j++)
printf("0x%02x ",
(unsigned char)Codepage->tounix[i*8+j]);
putchar('\n');
}
printf("\nfucase:\n");
for(i=0; i < 16; i++) {
putchar('\t');
for(j=0; j<8; j++)
printf("0x%02x ",
(unsigned char)mstoupper[i*8+j]);
putchar('\n');
}
if(country_string)
printf("COUNTRY=%s\n", country_string);
printf("mtools_fat_compatibility=%d\n",mtools_fat_compatibility);
printf("mtools_skip_check=%d\n",mtools_skip_check);
printf("mtools_lower_case=%d\n",mtools_ignore_short_case);
exit(0);
}
#else /* NO_CONFIG */
void read_config(void)
{
/* only compiled-in devices */
devices = NewArray(nr_const_devices + 1, struct device);
if(!devices) {
fprintf(stderr,"Out of memory error\n");
exit(1);
}
if(nr_const_devices)
memcpy(devices, const_devices,
nr_const_devices*sizeof(struct device));
}
#endif /* NO_CONFIG */

View file

@ -1,301 +0,0 @@
/* config.h. Generated automatically by configure. */
/* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
/* #undef _ALL_SOURCE */
#endif
/* Define to empty if the keyword does not work. */
/* #undef const */
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define as __inline if that's what the C compiler calls it. */
#define inline
/* Define if on MINIX. */
#define _MINIX 1
/* Define if the system does not provide POSIX.1 features except
with this defined. */
#define _POSIX_1_SOURCE 2
/* Define if you need to in order for stat and other things to work. */
#define _POSIX_SOURCE 1
/* Define as the return type of signal handlers (int or void). */
#define RETSIGTYPE void
/* Define if the `setpgrp' function takes no argument. */
#define SETPGRP_VOID 1
/* Define to `unsigned' if <sys/types.h> doesn't define. */
/* #undef size_t */
/* Define if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define if you can safely include both <sys/time.h> and <time.h>. */
/* #undef TIME_WITH_SYS_TIME */
/* Define if your <sys/time.h> declares struct tm. */
/* #undef TM_IN_SYS_TIME */
/* Define if the X Window System is missing or not being used. */
#define X_DISPLAY_MISSING 1
/* Define this if you want to use Xdf */
#define USE_XDF 1
/* Define this if you use mtools together with Solaris' vold */
/* #undef USING_VOLD */
/* Define this if you use mtools together with the new Solaris' vold
* support */
/* #undef USING_NEW_VOLD */
/* Define for debugging messages */
/* #undef DEBUG */
/* Define on non Unix OS'es which don't have the concept of tty's */
/* #undef USE_RAWTERM */
/* Define when sys_errlist is defined in the standard include files */
/* #undef DECL_SYS_ERRLIST */
/* Define when you want to include floppyd support */
/* #undef USE_FLOPPYD */
/* Define when the compiler supports LOFF_T type */
/* #undef HAVE_LOFF_T */
/* Define when the compiler supports OFFSET_T type */
/* #undef HAVE_OFFSET_T */
/* Define when the compiler supports LONG_LONG type */
/* #undef HAVE_LONG_LONG */
/* Define when the system has a 64 bit off_t type */
/* #undef HAVE_OFF_T_64 */
/* Define when you have an LLSEEK prototype */
/* #undef HAVE_LLSEEK_PROTOTYPE */
/* Define if you have the atexit function. */
#define HAVE_ATEXIT 1
/* Define if you have the basename function. */
/* #undef HAVE_BASENAME */
/* Define if you have the fchdir function. */
#ifdef __minix_vmd
#define HAVE_FCHDIR 1
#endif
/* Define if you have the flock function. */
/* #undef HAVE_FLOCK */
/* Define if you have the getpass function. */
#define HAVE_GETPASS 1
/* Define if you have the gettimeofday function. */
#define HAVE_GETTIMEOFDAY 1
/* Define if you have the htons function. */
/* #undef HAVE_HTONS */
/* Define if you have the llseek function. */
/* #undef HAVE_LLSEEK */
/* Define if you have the lockf function. */
#define HAVE_LOCKF 1
/* Define if you have the lseek64 function. */
/* #undef HAVE_LSEEK64 */
/* Define if you have the media_oldaliases function. */
/* #undef HAVE_MEDIA_OLDALIASES */
/* Define if you have the memcpy function. */
#define HAVE_MEMCPY 1
/* Define if you have the memmove function. */
#define HAVE_MEMMOVE 1
/* Define if you have the memset function. */
#define HAVE_MEMSET 1
/* Define if you have the on_exit function. */
/* #undef HAVE_ON_EXIT */
/* Define if you have the random function. */
#define HAVE_RANDOM 1
/* Define if you have the seteuid function. */
/* #undef HAVE_SETEUID */
/* Define if you have the setresuid function. */
/* #undef HAVE_SETRESUID */
/* Define if you have the snprintf function. */
#define HAVE_SNPRINTF 1
/* Define if you have the srandom function. */
#define HAVE_SRANDOM 1
/* Define if you have the strcasecmp function. */
#define HAVE_STRCASECMP 1
/* Define if you have the strchr function. */
#define HAVE_STRCHR 1
/* Define if you have the strcspn function. */
#define HAVE_STRCSPN 1
/* Define if you have the strdup function. */
/* #undef HAVE_STRDUP */
/* Define if you have the strerror function. */
#define HAVE_STRERROR 1
/* Define if you have the strncasecmp function. */
#define HAVE_STRNCASECMP 1
/* Define if you have the strpbrk function. */
#define HAVE_STRPBRK 1
/* Define if you have the strrchr function. */
#define HAVE_STRRCHR 1
/* Define if you have the strspn function. */
#define HAVE_STRSPN 1
/* Define if you have the strtol function. */
#define HAVE_STRTOL 1
/* Define if you have the strtoul function. */
#define HAVE_STRTOUL 1
/* Define if you have the tcflush function. */
#define HAVE_TCFLUSH 1
/* Define if you have the tcsetattr function. */
#define HAVE_TCSETATTR 1
/* Define if you have the tzset function. */
#define HAVE_TZSET 1
/* Define if you have the utime function. */
#define HAVE_UTIME 1
/* Define if you have the utimes function. */
/* #undef HAVE_UTIMES */
/* Define if you have the <arpa/inet.h> header file. */
/* #undef HAVE_ARPA_INET_H */
/* Define if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the <getopt.h> header file. */
/* #undef HAVE_GETOPT_H */
/* Define if you have the <libc.h> header file. */
/* #undef HAVE_LIBC_H */
/* Define if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define if you have the <linux/unistd.h> header file. */
/* #undef HAVE_LINUX_UNISTD_H */
/* Define if you have the <malloc.h> header file. */
/* #undef HAVE_MALLOC_H */
/* Define if you have the <memory.h> header file. */
/* #undef HAVE_MEMORY_H */
/* Define if you have the <mntent.h> header file. */
/* #undef HAVE_MNTENT_H */
/* Define if you have the <netdb.h> header file. */
/* #undef HAVE_NETDB_H */
/* Define if you have the <netinet/in.h> header file. */
/* #undef HAVE_NETINET_IN_H */
/* Define if you have the <sgtty.h> header file. */
#define HAVE_SGTTY_H 1
/* Define if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define if you have the <strings.h> header file. */
/* #undef HAVE_STRINGS_H */
/* Define if you have the <sys/file.h> header file. */
/* #undef HAVE_SYS_FILE_H */
/* Define if you have the <sys/floppy.h> header file. */
/* #undef HAVE_SYS_FLOPPY_H */
/* Define if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define if you have the <sys/param.h> header file. */
/* #undef HAVE_SYS_PARAM_H */
/* Define if you have the <sys/signal.h> header file. */
/* #undef HAVE_SYS_SIGNAL_H */
/* Define if you have the <sys/socket.h> header file. */
/* #undef HAVE_SYS_SOCKET_H */
/* Define if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define if you have the <sys/sysmacros.h> header file. */
/* #undef HAVE_SYS_SYSMACROS_H */
/* Define if you have the <sys/termio.h> header file. */
/* #undef HAVE_SYS_TERMIO_H */
/* Define if you have the <sys/termios.h> header file. */
/* #undef HAVE_SYS_TERMIOS_H */
/* Define if you have the <sys/time.h> header file. */
/* #undef HAVE_SYS_TIME_H */
/* Define if you have the <termio.h> header file. */
/* #undef HAVE_TERMIO_H */
/* Define if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if you have the <utime.h> header file. */
#define HAVE_UTIME_H 1
/* Define if you have the cam library (-lcam). */
/* #undef HAVE_LIBCAM */
/* Define if you have the nsl library (-lnsl). */
/* #undef HAVE_LIBNSL */
/* Define if you have the socket library (-lsocket). */
/* #undef HAVE_LIBSOCKET */
/* Define if you have the sun library (-lsun). */
/* #undef HAVE_LIBSUN */

View file

@ -1,62 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "file.h"
#include "llong.h"
/*
* Copy the data from source to target
*/
int copyfile(Stream_t *Source, Stream_t *Target)
{
char buffer[8*16384];
int pos;
int ret, retw;
size_t len;
mt_size_t mt_len;
if (!Source){
fprintf(stderr,"Couldn't open source file\n");
return -1;
}
if (!Target){
fprintf(stderr,"Couldn't open target file\n");
return -1;
}
pos = 0;
GET_DATA(Source, 0, &mt_len, 0, 0);
if (mt_len & ~max_off_t_31) {
fprintf(stderr, "File too big\n");
return -1;
}
len = truncBytes32(mt_len);
while(1){
ret = READS(Source, buffer, (mt_off_t) pos, 8*16384);
if (ret < 0 ){
perror("file read");
return -1;
}
if(!ret)
break;
if(got_signal)
return -1;
if (ret == 0)
break;
if ((retw = force_write(Target, buffer, (mt_off_t) pos, ret)) != ret){
if(retw < 0 )
perror("write in copy");
else
fprintf(stderr,
"Short write %d instead of %d\n", retw,
ret);
if(errno == ENOSPC)
got_signal = 1;
return ret;
}
pos += ret;
}
return pos;
}

File diff suppressed because it is too large Load diff

View file

@ -1,169 +0,0 @@
#ifdef OS_linux
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#ifndef MAJOR
#define MAJOR(dev) major(dev)
#endif /* MAJOR not defined */
#ifndef MINOR
#define MINOR(dev) minor(dev)
#endif /* MINOR not defined */
#else
#include <linux/fs.h> /* get MAJOR/MINOR from Linux kernel */
#ifndef major
#define major(x) MAJOR(x)
#endif
#endif /* HAVE_SYS_SYSMACROS_H */
#include <linux/fd.h>
#include <linux/fdreg.h>
#include <linux/major.h>
typedef struct floppy_raw_cmd RawRequest_t;
UNUSED(static inline void RR_INIT(struct floppy_raw_cmd *request))
{
request->data = 0;
request->length = 0;
request->cmd_count = 9;
request->flags = FD_RAW_INTR | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK
#ifdef FD_RAW_SOFTFAILUE
| FD_RAW_SOFTFAILURE | FD_RAW_STOP_IF_FAILURE
#endif
;
request->cmd[1] = 0;
request->cmd[6] = 0;
request->cmd[7] = 0x1b;
request->cmd[8] = 0xff;
request->reply_count = 0;
}
UNUSED(static inline void RR_SETRATE(struct floppy_raw_cmd *request, int rate))
{
request->rate = rate;
}
UNUSED(static inline void RR_SETDRIVE(struct floppy_raw_cmd *request,int drive))
{
request->cmd[1] = (request->cmd[1] & ~3) | (drive & 3);
}
UNUSED(static inline void RR_SETTRACK(struct floppy_raw_cmd *request,int track))
{
request->cmd[2] = track;
}
UNUSED(static inline void RR_SETPTRACK(struct floppy_raw_cmd *request,
int track))
{
request->track = track;
}
UNUSED(static inline void RR_SETHEAD(struct floppy_raw_cmd *request, int head))
{
if(head)
request->cmd[1] |= 4;
else
request->cmd[1] &= ~4;
request->cmd[3] = head;
}
UNUSED(static inline void RR_SETSECTOR(struct floppy_raw_cmd *request,
int sector))
{
request->cmd[4] = sector;
request->cmd[6] = sector-1;
}
UNUSED(static inline void RR_SETSIZECODE(struct floppy_raw_cmd *request,
int sizecode))
{
request->cmd[5] = sizecode;
request->cmd[6]++;
request->length += 128 << sizecode;
}
#if 0
static inline void RR_SETEND(struct floppy_raw_cmd *request, int end)
{
request->cmd[6] = end;
}
#endif
UNUSED(static inline void RR_SETDIRECTION(struct floppy_raw_cmd *request,
int direction))
{
if(direction == MT_READ) {
request->flags |= FD_RAW_READ;
request->cmd[0] = FD_READ & ~0x80;
} else {
request->flags |= FD_RAW_WRITE;
request->cmd[0] = FD_WRITE & ~0x80;
}
}
UNUSED(static inline void RR_SETDATA(struct floppy_raw_cmd *request,
caddr_t data))
{
request->data = data;
}
#if 0
static inline void RR_SETLENGTH(struct floppy_raw_cmd *request, int length)
{
request->length += length;
}
#endif
UNUSED(static inline void RR_SETCONT(struct floppy_raw_cmd *request))
{
#ifdef FD_RAW_MORE
request->flags |= FD_RAW_MORE;
#endif
}
UNUSED(static inline int RR_SIZECODE(struct floppy_raw_cmd *request))
{
return request->cmd[5];
}
UNUSED(static inline int RR_TRACK(struct floppy_raw_cmd *request))
{
return request->cmd[2];
}
UNUSED(static inline int GET_DRIVE(int fd))
{
struct stat statbuf;
if (fstat(fd, &statbuf) < 0 ){
perror("stat");
return -1;
}
if (!S_ISBLK(statbuf.st_mode) ||
MAJOR(statbuf.st_rdev) != FLOPPY_MAJOR)
return -1;
return MINOR( statbuf.st_rdev );
}
/* void print_message(RawRequest_t *raw_cmd,char *message);*/
int send_one_cmd(int fd, RawRequest_t *raw_cmd, const char *message);
int analyze_one_reply(RawRequest_t *raw_cmd, int *bytes, int do_print);
#endif

View file

@ -1,329 +0,0 @@
#include "sysincludes.h"
#include "vfat.h"
#include "dirCache.h"
void myfree(void *a)
{
free(a);
}
#define free myfree
#define BITS_PER_INT (sizeof(unsigned int) * 8)
static inline unsigned int rol(unsigned int arg, int shift)
{
arg &= 0xffffffff; /* for 64 bit machines */
return (arg << shift) | (arg >> (32 - shift));
}
static int calcHash(char *name)
{
unsigned long hash;
int i;
unsigned char c;
hash = 0;
i = 0;
while(*name) {
/* rotate it */
hash = rol(hash,5); /* a shift of 5 makes sure we spread quickly
* over the whole width, moreover, 5 is
* prime with 32, which makes sure that
* successive letters cannot cover each
* other easily */
c = toupper(*name);
hash ^= (c * (c+2)) ^ (i * (i+2));
hash &= 0xffffffff;
i++, name++;
}
hash = hash * (hash + 2);
/* the following two xors make sure all info is spread evenly over all
* bytes. Important if we only keep the low order bits later on */
hash ^= (hash & 0xfff) << 12;
hash ^= (hash & 0xff000) << 24;
return hash;
}
static int addBit(unsigned int *bitmap, int hash, int checkOnly)
{
int bit, entry;
bit = 1 << (hash % BITS_PER_INT);
entry = (hash / BITS_PER_INT) % DC_BITMAP_SIZE;
if(checkOnly)
return bitmap[entry] & bit;
else {
bitmap[entry] |= bit;
return 1;
}
}
static int _addHash(dirCache_t *cache, unsigned int hash, int checkOnly)
{
return
addBit(cache->bm0, hash, checkOnly) &&
addBit(cache->bm1, rol(hash,12), checkOnly) &&
addBit(cache->bm2, rol(hash,24), checkOnly);
}
static void addNameToHash(dirCache_t *cache, char *name)
{
_addHash(cache, calcHash(name), 0);
}
static void hashDce(dirCache_t *cache, dirCacheEntry_t *dce)
{
if(dce->beginSlot != cache->nrHashed)
return;
cache->nrHashed = dce->endSlot;
if(dce->longName)
addNameToHash(cache, dce->longName);
addNameToHash(cache, dce->shortName);
}
int isHashed(dirCache_t *cache, char *name)
{
int ret;
ret = _addHash(cache, calcHash(name), 1);
return ret;
}
void checkXYZ(dirCache_t *cache)
{
if(cache->entries[2])
printf(" at 2 = %d\n", cache->entries[2]->beginSlot);
}
int growDirCache(dirCache_t *cache, int slot)
{
if(slot < 0) {
fprintf(stderr, "Bad slot %d\n", slot);
exit(1);
}
if( cache->nr_entries <= slot) {
int i;
cache->entries = realloc(cache->entries,
(slot+1) * 2 *
sizeof(dirCacheEntry_t *));
if(!cache->entries)
return -1;
for(i= cache->nr_entries; i < (slot+1) * 2; i++) {
cache->entries[i] = 0;
}
cache->nr_entries = (slot+1) * 2;
}
return 0;
}
dirCache_t *allocDirCache(Stream_t *Stream, int slot)
{
dirCache_t **dcp;
if(slot < 0) {
fprintf(stderr, "Bad slot %d\n", slot);
exit(1);
}
dcp = getDirCacheP(Stream);
if(!*dcp) {
*dcp = New(dirCache_t);
if(!*dcp)
return 0;
(*dcp)->entries = NewArray((slot+1)*2+5, dirCacheEntry_t *);
if(!(*dcp)->entries) {
free(*dcp);
return 0;
}
(*dcp)->nr_entries = (slot+1) * 2;
memset( (*dcp)->bm0, 0, DC_BITMAP_SIZE);
memset( (*dcp)->bm1, 0, DC_BITMAP_SIZE);
memset( (*dcp)->bm2, 0, DC_BITMAP_SIZE);
(*dcp)->nrHashed = 0;
} else
if(growDirCache(*dcp, slot) < 0)
return 0;
return *dcp;
}
static void freeDirCacheRange(dirCache_t *cache, int beginSlot, int endSlot)
{
dirCacheEntry_t *entry;
int clearBegin;
int clearEnd;
int i;
if(endSlot < beginSlot) {
fprintf(stderr, "Bad slots %d %d in free range\n",
beginSlot, endSlot);
exit(1);
}
while(beginSlot < endSlot) {
entry = cache->entries[beginSlot];
if(!entry) {
beginSlot++;
continue;
}
clearEnd = entry->endSlot;
if(clearEnd > endSlot)
clearEnd = endSlot;
clearBegin = beginSlot;
for(i = clearBegin; i <clearEnd; i++)
cache->entries[i] = 0;
if(entry->endSlot == endSlot)
entry->endSlot = beginSlot;
else if(entry->beginSlot == beginSlot)
entry->beginSlot = endSlot;
else {
fprintf(stderr,
"Internal error, non contiguous de-allocation\n");
fprintf(stderr, "%d %d\n", beginSlot, endSlot);
fprintf(stderr, "%d %d\n", entry->beginSlot,
entry->endSlot);
exit(1);
}
if(entry->beginSlot == entry->endSlot) {
if(entry->longName)
free(entry->longName);
if(entry->shortName)
free(entry->shortName);
free(entry);
}
beginSlot = clearEnd;
}
}
static dirCacheEntry_t *allocDirCacheEntry(dirCache_t *cache, int beginSlot,
int endSlot,
dirCacheEntryType_t type)
{
dirCacheEntry_t *entry;
int i;
if(growDirCache(cache, endSlot) < 0)
return 0;
entry = New(dirCacheEntry_t);
if(!entry)
return 0;
entry->type = type;
entry->longName = 0;
entry->shortName = 0;
entry->beginSlot = beginSlot;
entry->endSlot = endSlot;
freeDirCacheRange(cache, beginSlot, endSlot);
for(i=beginSlot; i<endSlot; i++) {
cache->entries[i] = entry;
}
return entry;
}
dirCacheEntry_t *addUsedEntry(dirCache_t *cache, int beginSlot, int endSlot,
char *longName, char *shortName,
struct directory *dir)
{
dirCacheEntry_t *entry;
if(endSlot < beginSlot) {
fprintf(stderr,
"Bad slots %d %d in add used entry\n",
beginSlot, endSlot);
exit(1);
}
entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_USED);
if(!entry)
return 0;
entry->beginSlot = beginSlot;
entry->endSlot = endSlot;
if(longName)
entry->longName = strdup(longName);
entry->shortName = strdup(shortName);
entry->dir = *dir;
hashDce(cache, entry);
return entry;
}
static void mergeFreeSlots(dirCache_t *cache, int slot)
{
dirCacheEntry_t *previous, *next;
int i;
if(slot == 0)
return;
previous = cache->entries[slot-1];
next = cache->entries[slot];
if(next && next->type == DCET_FREE &&
previous && previous->type == DCET_FREE) {
for(i=next->beginSlot; i < next->endSlot; i++)
cache->entries[i] = previous;
previous->endSlot = next->endSlot;
free(next);
}
}
dirCacheEntry_t *addFreeEntry(dirCache_t *cache, int beginSlot, int endSlot)
{
dirCacheEntry_t *entry;
if(beginSlot < cache->nrHashed)
cache->nrHashed = beginSlot;
if(endSlot < beginSlot) {
fprintf(stderr, "Bad slots %d %d in add free entry\n",
beginSlot, endSlot);
exit(1);
}
if(endSlot == beginSlot)
return 0;
entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_FREE);
mergeFreeSlots(cache, beginSlot);
mergeFreeSlots(cache, endSlot);
return cache->entries[beginSlot];
}
dirCacheEntry_t *addEndEntry(dirCache_t *cache, int pos)
{
return allocDirCacheEntry(cache, pos, pos+1, DCET_END);
}
dirCacheEntry_t *lookupInDircache(dirCache_t *cache, int pos)
{
if(growDirCache(cache, pos+1) < 0)
return 0;
return cache->entries[pos];
}
void freeDirCache(Stream_t *Stream)
{
dirCache_t *cache, **dcp;
dcp = getDirCacheP(Stream);
cache = *dcp;
if(cache) {
freeDirCacheRange(cache, 0, cache->nr_entries);
free(cache);
*dcp = 0;
}
}

View file

@ -1,40 +0,0 @@
#ifndef MTOOLS_DIRCACHE_H
#define MTOOLS_DIRCACHE_H
typedef enum {
DCET_FREE,
DCET_USED,
DCET_END
} dirCacheEntryType_t;
#define DC_BITMAP_SIZE 128
typedef struct dirCacheEntry_t {
dirCacheEntryType_t type;
int beginSlot;
int endSlot;
char *shortName;
char *longName;
struct directory dir;
} dirCacheEntry_t;
typedef struct dirCache_t {
struct dirCacheEntry_t **entries;
int nr_entries;
unsigned int nrHashed;
unsigned int bm0[DC_BITMAP_SIZE];
unsigned int bm1[DC_BITMAP_SIZE];
unsigned int bm2[DC_BITMAP_SIZE];
} dirCache_t;
int isHashed(dirCache_t *cache, char *name);
int growDirCache(dirCache_t *cache, int slot);
dirCache_t *allocDirCache(Stream_t *Stream, int slot);
dirCacheEntry_t *addUsedEntry(dirCache_t *Stream, int begin, int end,
char *longName, char *shortName,
struct directory *dir);
void freeDirCache(Stream_t *Stream);
dirCacheEntry_t *addFreeEntry(dirCache_t *Stream, int begin, int end);
dirCacheEntry_t *addEndEntry(dirCache_t *Stream, int pos);
dirCacheEntry_t *lookupInDircache(dirCache_t *Stream, int pos);
#endif

View file

@ -1,106 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "stream.h"
#include "mtools.h"
#include "file.h"
#include "fs.h"
/* #define DEBUG */
/*
* Read a directory entry into caller supplied buffer
*/
struct directory *dir_read(direntry_t *entry, int *error)
{
int n;
*error = 0;
if((n=force_read(entry->Dir, (char *) (&entry->dir),
(mt_off_t) entry->entry * MDIR_SIZE,
MDIR_SIZE)) != MDIR_SIZE) {
if (n < 0) {
*error = -1;
}
return NULL;
}
return &entry->dir;
}
/*
* Make a subdirectory grow in length. Only subdirectories (not root)
* may grow. Returns a 0 on success, 1 on failure (disk full), or -1
* on error.
*/
int dir_grow(Stream_t *Dir, int size)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(FsPublic_t);
int ret;
int buflen;
char *buffer;
if (!getfreeMinClusters(Dir, 1))
return -1;
buflen = This->cluster_size * This->sector_size;
if(! (buffer=malloc(buflen)) ){
perror("dir_grow: malloc");
return -1;
}
memset((char *) buffer, '\0', buflen);
ret = force_write(Dir, buffer, (mt_off_t) size * MDIR_SIZE, buflen);
free(buffer);
if(ret < buflen)
return -1;
return 0;
}
void low_level_dir_write(direntry_t *entry)
{
force_write(entry->Dir,
(char *) (&entry->dir),
(mt_off_t) entry->entry * MDIR_SIZE, MDIR_SIZE);
}
/*
* Make a directory entry. Builds a directory entry based on the
* name, attribute, starting cluster number, and size. Returns a pointer
* to a static directory structure.
*/
struct directory *mk_entry(const char *filename, char attr,
unsigned int fat, size_t size, time_t date,
struct directory *ndir)
{
struct tm *now;
time_t date2 = date;
unsigned char hour, min_hi, min_low, sec;
unsigned char year, month_hi, month_low, day;
now = localtime(&date2);
strncpy(ndir->name, filename, 8);
strncpy(ndir->ext, filename + 8, 3);
ndir->attr = attr;
ndir->ctime_ms = 0;
hour = now->tm_hour << 3;
min_hi = now->tm_min >> 3;
min_low = now->tm_min << 5;
sec = now->tm_sec / 2;
ndir->ctime[1] = ndir->time[1] = hour + min_hi;
ndir->ctime[0] = ndir->time[0] = min_low + sec;
year = (now->tm_year - 80) << 1;
month_hi = (now->tm_mon + 1) >> 3;
month_low = (now->tm_mon + 1) << 5;
day = now->tm_mday;
ndir -> adate[1] = ndir->cdate[1] = ndir->date[1] = year + month_hi;
ndir -> adate[0] = ndir->cdate[0] = ndir->date[0] = month_low + day;
set_word(ndir->start, fat & 0xffff);
set_word(ndir->startHi, fat >> 16);
set_dword(ndir->size, size);
return ndir;
}

View file

@ -1,119 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "stream.h"
#include "file.h"
#include "mtoolsDirent.h"
void initializeDirentry(direntry_t *entry, Stream_t *Dir)
{
entry->entry = -1;
/* entry->parent = getDirentry(Dir);*/
entry->Dir = Dir;
entry->beginSlot = 0;
entry->endSlot = 0;
}
int isNotFound(direntry_t *entry)
{
return entry->entry == -2;
}
void rewindEntry(direntry_t *entry)
{
entry->entry = -1;
}
direntry_t *getParent(direntry_t *entry)
{
return getDirentry(entry->Dir);
}
static int getPathLen(direntry_t *entry)
{
int length=0;
while(1) {
if(entry->entry == -3) /* rootDir */
return strlen(getDrive(entry->Dir)) + 1 + length + 1;
length += 1 + strlen(entry->name);
entry = getDirentry(entry->Dir);
}
}
static char *sprintPwd(direntry_t *entry, char *ptr)
{
if(entry->entry == -3) {
strcpy(ptr, getDrive(entry->Dir));
strcat(ptr, ":/");
ptr = strchr(ptr, 0);
} else {
ptr = sprintPwd(getDirentry(entry->Dir), ptr);
if(ptr[-1] != '/')
*ptr++ = '/';
strcpy(ptr, entry->name);
ptr += strlen(entry->name);
}
return ptr;
}
#define NEED_ESCAPE "\"$\\"
static void _fprintPwd(FILE *f, direntry_t *entry, int recurs, int escape)
{
if(entry->entry == -3) {
fputs(getDrive(entry->Dir), f);
putc(':', f);
if(!recurs)
putc('/', f);
} else {
_fprintPwd(f, getDirentry(entry->Dir), 1, escape);
if (escape && strpbrk(entry->name, NEED_ESCAPE)) {
char *ptr;
for(ptr = entry->name; *ptr; ptr++) {
if (strchr(NEED_ESCAPE, *ptr))
putc('\\', f);
putc(*ptr, f);
}
} else {
fprintf(f, "/%s", entry->name);
}
}
}
void fprintPwd(FILE *f, direntry_t *entry, int escape)
{
if (escape)
putc('"', f);
_fprintPwd(f, entry, 0, escape);
if(escape)
putc('"', f);
}
char *getPwd(direntry_t *entry)
{
int size;
char *ret;
size = getPathLen(entry);
ret = malloc(size+1);
if(!ret)
return 0;
sprintPwd(entry, ret);
return ret;
}
int isSubdirOf(Stream_t *inside, Stream_t *outside)
{
while(1) {
if(inside == outside) /* both are the same */
return 1;
if(getDirentry(inside)->entry == -3) /* root directory */
return 0;
/* look further up */
inside = getDirentry(inside)->Dir;
}
}

View file

@ -1,83 +0,0 @@
/*
* Do filename expansion with the shell.
*/
#define EXPAND_BUF 2048
#include "sysincludes.h"
#include "mtools.h"
int safePopenOut(char **command, char *output, int len)
{
int pipefd[2];
pid_t pid;
int status;
int last;
if(pipe(pipefd)) {
return -2;
}
switch((pid=fork())){
case -1:
return -2;
case 0: /* the son */
close(pipefd[0]);
destroy_privs();
close(1);
close(2); /* avoid nasty error messages on stderr */
dup(pipefd[1]);
close(pipefd[1]);
execvp(command[0], command+1);
exit(1);
default:
close(pipefd[1]);
break;
}
last=read(pipefd[0], output, len);
kill(pid,9);
wait(&status);
if(last<0) {
return -1;
}
return last;
}
const char *expand(const char *input, char *ans)
{
int last;
char buf[256];
char *command[] = { "/bin/sh", "sh", "-c", 0, 0 };
ans[EXPAND_BUF-1]='\0';
if (input == NULL)
return(NULL);
if (*input == '\0')
return("");
/* any thing to expand? */
if (!strpbrk(input, "$*(){}[]\\?`~")) {
strncpy(ans, input, EXPAND_BUF-1);
return(ans);
}
/* popen an echo */
#ifdef HAVE_SNPRINTF
snprintf(buf, 255, "echo %s", input);
#else
sprintf(buf, "echo %s", input);
#endif
command[3]=buf;
last=safePopenOut(command, ans, EXPAND_BUF-1);
if(last<0) {
perror("Pipe read error");
exit(1);
}
if(last)
ans[last-1] = '\0';
else
strncpy(ans, input, EXPAND_BUF-1);
return ans;
}

View file

@ -1,929 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "stream.h"
#include "mtools.h"
#include "fsP.h"
extern Stream_t *default_drive;
#ifdef HAVE_LONG_LONG
typedef long long fatBitMask;
#else
typedef long fatBitMask;
#endif
typedef struct FatMap_t {
unsigned char *data;
fatBitMask dirty;
fatBitMask valid;
} FatMap_t;
#define SECT_PER_ENTRY (sizeof(fatBitMask)*8)
#define ONE ((fatBitMask) 1)
static inline int readSector(Fs_t *This, char *buf, unsigned int off,
size_t size)
{
return READS(This->Next, buf, sectorsToBytes((Stream_t *)This, off),
size << This->sectorShift);
}
static inline int forceReadSector(Fs_t *This, char *buf, unsigned int off,
size_t size)
{
return force_read(This->Next, buf, sectorsToBytes((Stream_t *)This, off),
size << This->sectorShift);
}
static inline int writeSector(Fs_t *This, char *buf, unsigned int off,
size_t size)
{
return WRITES(This->Next, buf, sectorsToBytes((Stream_t*)This, off),
size << This->sectorShift);
}
static inline int forceWriteSector(Fs_t *This, char *buf, unsigned int off,
size_t size)
{
return force_write(This->Next, buf, sectorsToBytes((Stream_t*)This, off),
size << This->sectorShift);
}
static FatMap_t *GetFatMap(Fs_t *Stream)
{
int nr_entries,i;
FatMap_t *map;
Stream->fat_error = 0;
nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY;
map = NewArray(nr_entries, FatMap_t);
if(!map)
return 0;
for(i=0; i< nr_entries; i++) {
map[i].data = 0;
map[i].valid = 0;
map[i].dirty = 0;
}
return map;
}
static inline int locate(Fs_t *Stream, int offset, int *slot, int *bit)
{
if(offset >= Stream->fat_len)
return -1;
*slot = offset / SECT_PER_ENTRY;
*bit = offset % SECT_PER_ENTRY;
return 0;
}
static inline int fatReadSector(Fs_t *This, int sector, int slot,
int bit, int dupe)
{
int fat_start, ret;
dupe = (dupe + This->primaryFat) % This->num_fat;
fat_start = This->fat_start + This->fat_len * dupe;
/* first, read as much as the buffer can give us */
ret = readSector(This,
(char *)(This->FatMap[slot].data+(bit<<This->sectorShift)),
fat_start+sector,
(SECT_PER_ENTRY - bit%SECT_PER_ENTRY));
if(ret < 0)
return 0;
if(ret < This->sector_size) {
/* if we got less than one sector's worth, insist to get at
* least one sector */
ret = forceReadSector(This,
(char *) (This->FatMap[slot].data +
(bit << This->sectorShift)),
fat_start+sector, 1);
if(ret < This->sector_size)
return 0;
return 1;
}
return ret >> This->sectorShift;
}
static int fatWriteSector(Fs_t *This, int sector, int slot, int bit, int dupe)
{
int fat_start;
dupe = (dupe + This->primaryFat) % This->num_fat;
if(dupe && !This->writeAllFats)
return This->sector_size;
fat_start = This->fat_start + This->fat_len * dupe;
return forceWriteSector(This,
(char *)
(This->FatMap[slot].data + bit * This->sector_size),
fat_start+sector, 1);
}
static unsigned char *loadSector(Fs_t *This,
unsigned int sector, fatAccessMode_t mode,
int recurs)
{
int slot, bit, i, ret;
if(locate(This,sector, &slot, &bit) < 0)
return 0;
#if 0
if (((This->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY) <= slot) {
fprintf(stderr,"This should not happen\n");
fprintf(stderr, "fat_len = %d\n", This->fat_len);
fprintf(stderr, "SECT_PER_ENTRY=%d\n", (int)SECT_PER_ENTRY);
fprintf(stderr, "sector = %d slot = %d bit=%d\n",
sector, slot, bit);
fprintf(stderr, "left = %d",(int)
((This->fat_len+SECT_PER_ENTRY-1) / SECT_PER_ENTRY));
return 0;
}
#endif
if(!This->FatMap[slot].data) {
/* allocate the storage space */
This->FatMap[slot].data =
malloc(This->sector_size * SECT_PER_ENTRY);
if(!This->FatMap[slot].data)
return 0;
memset(This->FatMap[slot].data, 0xee,
This->sector_size * SECT_PER_ENTRY);
}
if(! (This->FatMap[slot].valid & (ONE << bit))) {
ret = -1;
for(i=0; i< This->num_fat; i++) {
/* read the sector */
ret = fatReadSector(This, sector, slot, bit, i);
if(ret == 0) {
fprintf(stderr,
"Error reading fat number %d\n", i);
continue;
}
break;
}
/* all copies bad. Return error */
if(ret == 0)
return 0;
for(i=0; i < ret; i++)
This->FatMap[slot].valid |= ONE << (bit + i);
if(!recurs && ret == 1)
/* do some prefetching, if we happened to only
* get one sector */
loadSector(This, sector+1, mode, 1);
if(!recurs && batchmode)
for(i=0; i < 1024; i++)
loadSector(This, sector+i, mode, 1);
}
if(mode == FAT_ACCESS_WRITE) {
This->FatMap[slot].dirty |= ONE << bit;
This->fat_dirty = 1;
}
return This->FatMap[slot].data + (bit << This->sectorShift);
}
static unsigned char *getAddress(Fs_t *Stream,
unsigned int num, fatAccessMode_t mode)
{
unsigned char *ret;
int sector;
int offset;
sector = num >> Stream->sectorShift;
ret = 0;
if(sector == Stream->lastFatSectorNr &&
Stream->lastFatAccessMode >= mode)
ret = Stream->lastFatSectorData;
if(!ret) {
ret = loadSector(Stream, sector, mode, 0);
if(!ret)
return 0;
Stream->lastFatSectorNr = sector;
Stream->lastFatSectorData = ret;
Stream->lastFatAccessMode = mode;
}
offset = num & Stream->sectorMask;
return ret+offset;
}
static int readByte(Fs_t *Stream, int start)
{
unsigned char *address;
address = getAddress(Stream, start, FAT_ACCESS_READ);
if(!address)
return -1;
return *address;
}
/*
* Fat 12 encoding:
* | byte n | byte n+1 | byte n+2 |
* |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
* | | | | | | | | | | | | | | | | | | | | | | | | |
* | n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 |
* \_____ \____ \______/________/_____ /
* ____\______\________/ _____/ ____\_/
* / \ \ / / \
* | n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 |
* | FAT entry k | FAT entry k+1 |
*/
/*
* Get and decode a FAT (file allocation table) entry. Returns the cluster
* number on success or 1 on failure.
*/
static unsigned int fat12_decode(Fs_t *Stream, unsigned int num)
{
unsigned int start = num * 3 / 2;
int byte0 = readByte(Stream, start);
int byte1 = readByte(Stream, start+1);
if (num < 2 || byte0 < 0 || byte1 < 0 || num > Stream->num_clus+1) {
fprintf(stderr,"[1] Bad address %d\n", num);
return 1;
}
if (num & 1)
return (byte1 << 4) | ((byte0 & 0xf0)>>4);
else
return ((byte1 & 0xf) << 8) | byte0;
}
/*
* Puts a code into the FAT table. Is the opposite of fat_decode(). No
* sanity checking is done on the code. Returns a 1 on error.
*/
static void fat12_encode(Fs_t *Stream, unsigned int num, unsigned int code)
{
int start = num * 3 / 2;
unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_WRITE);
unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_WRITE);
if (num & 1) {
/* (odd) not on byte boundary */
*address0 = (*address0 & 0x0f) | ((code << 4) & 0xf0);
*address1 = (code >> 4) & 0xff;
} else {
/* (even) on byte boundary */
*address0 = code & 0xff;
*address1 = (*address1 & 0xf0) | ((code >> 8) & 0x0f);
}
}
/*
* Fat 16 encoding:
* | byte n | byte n+1 |
* |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
* | | | | | | | | | | | | | | | | |
* | FAT entry k |
*/
static unsigned int fat16_decode(Fs_t *Stream, unsigned int num)
{
unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_READ);
return _WORD(address);
}
static void fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code)
{
unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_WRITE);
set_word(address, code);
}
static unsigned int fast_fat16_decode(Fs_t *Stream, unsigned int num)
{
unsigned short *address =
(unsigned short *) getAddress(Stream, num << 1,
FAT_ACCESS_READ);
return *address;
}
static void fast_fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code)
{
unsigned short *address =
(unsigned short *) getAddress(Stream, num << 1,
FAT_ACCESS_WRITE);
*address = code;
}
/*
* Fat 32 encoding
*/
static unsigned int fat32_decode(Fs_t *Stream, unsigned int num)
{
unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_READ);
return _DWORD(address);
}
static void fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code)
{
unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_WRITE);
set_dword(address, code);
}
static unsigned int fast_fat32_decode(Fs_t *Stream, unsigned int num)
{
unsigned int *address =
(unsigned int *) getAddress(Stream, num << 2,
FAT_ACCESS_READ);
return *address;
}
static void fast_fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code)
{
unsigned int *address =
(unsigned int *) getAddress(Stream, num << 2,
FAT_ACCESS_WRITE);
*address = code;
}
/*
* Write the FAT table to the disk. Up to now the FAT manipulation has
* been done in memory. All errors are fatal. (Might not be too smart
* to wait till the end of the program to write the table. Oh well...)
*/
void fat_write(Fs_t *This)
{
int i, j, dups, ret, bit, slot;
int fat_start;
/*fprintf(stderr, "Fat write\n");*/
if (!This->fat_dirty)
return;
dups = This->num_fat;
if (This->fat_error)
dups = 1;
for(i=0; i<dups; i++){
j = 0;
fat_start = This->fat_start + i*This->fat_len;
for(slot=0;j<This->fat_len;slot++) {
if(!This->FatMap[slot].dirty) {
j += SECT_PER_ENTRY;
continue;
}
for(bit=0;
bit < SECT_PER_ENTRY && j<This->fat_len;
bit++,j++) {
if(!(This->FatMap[slot].dirty & (ONE << bit)))
continue;
ret = fatWriteSector(This,j,slot, bit, i);
if (ret < This->sector_size){
if (ret < 0 ){
perror("error in fat_write");
exit(1);
} else {
fprintf(stderr,
"end of file in fat_write\n");
exit(1);
}
}
/* if last dupe, zero it out */
if(i==dups-1)
This->FatMap[slot].dirty &= ~(1<<bit);
}
}
}
/* write the info sector, if any */
if(This->infoSectorLoc && This->infoSectorLoc != MAX32) {
/* initialize info sector */
InfoSector_t *infoSector;
infoSector = (InfoSector_t *) safe_malloc(This->sector_size);
set_dword(infoSector->signature1, INFOSECT_SIGNATURE1);
memset(infoSector->filler1, sizeof(infoSector->filler1),0);
memset(infoSector->filler2, sizeof(infoSector->filler2),0);
set_dword(infoSector->signature2, INFOSECT_SIGNATURE2);
set_dword(infoSector->pos, This->last);
set_dword(infoSector->count, This->freeSpace);
set_dword(infoSector->signature3, 0xaa55);
if(forceWriteSector(This, (char *)infoSector, This->infoSectorLoc, 1) !=
This->sector_size)
fprintf(stderr,"Trouble writing the info sector\n");
free(infoSector);
}
This->fat_dirty = 0;
This->lastFatAccessMode = FAT_ACCESS_READ;
}
/*
* Zero-Fat
* Used by mformat.
*/
int zero_fat(Fs_t *Stream, int media_descriptor)
{
int i, j;
int fat_start;
unsigned char *buf;
buf = malloc(Stream->sector_size);
if(!buf) {
perror("alloc fat sector buffer");
return -1;
}
for(i=0; i< Stream->num_fat; i++) {
fat_start = Stream->fat_start + i*Stream->fat_len;
for(j = 0; j < Stream->fat_len; j++) {
if(j <= 1)
memset(buf, 0, Stream->sector_size);
if(!j) {
buf[0] = media_descriptor;
buf[2] = buf[1] = 0xff;
if(Stream->fat_bits > 12)
buf[3] = 0xff;
if(Stream->fat_bits > 16) {
buf[4] = 0xff;
buf[5] = 0xff;
buf[6] = 0xff;
buf[7] = 0x0f;
}
}
if(forceWriteSector(Stream, (char *)buf,
fat_start + j, 1) !=
Stream->sector_size) {
fprintf(stderr,
"Trouble initializing a FAT sector\n");
free(buf);
return -1;
}
}
}
free(buf);
Stream->FatMap = GetFatMap(Stream);
if (Stream->FatMap == NULL) {
perror("alloc fat map");
return -1;
}
return 0;
}
void set_fat12(Fs_t *This)
{
This->fat_bits = 12;
This->end_fat = 0xfff;
This->last_fat = 0xff6;
This->fat_decode = fat12_decode;
This->fat_encode = fat12_encode;
}
static char word_endian_test[] = { 0x34, 0x12 };
void set_fat16(Fs_t *This)
{
This->fat_bits = 16;
This->end_fat = 0xffff;
This->last_fat = 0xfff6;
if(sizeof(unsigned short) == 2 &&
* (unsigned short *) word_endian_test == 0x1234) {
This->fat_decode = fast_fat16_decode;
This->fat_encode = fast_fat16_encode;
} else {
This->fat_decode = fat16_decode;
This->fat_encode = fat16_encode;
}
}
static char dword_endian_test[] = { 0x78, 0x56, 0x34, 0x12 };
void set_fat32(Fs_t *This)
{
This->fat_bits = 32;
This->end_fat = 0xfffffff;
This->last_fat = 0xffffff6;
if(sizeof(unsigned int) == 4 &&
* (unsigned int *) dword_endian_test == 0x12345678) {
This->fat_decode = fast_fat32_decode;
This->fat_encode = fast_fat32_encode;
} else {
This->fat_decode = fat32_decode;
This->fat_encode = fat32_encode;
}
}
static int check_fat(Fs_t *This)
{
/*
* This is only a sanity check. For disks with really big FATs,
* there is no point in checking the whole FAT.
*/
int i, f, tocheck;
if(mtools_skip_check)
return 0;
/* too few sectors in the FAT */
if(This->fat_len < NEEDED_FAT_SIZE(This))
return -1;
/* we do not warn about too much sectors in FAT, which may
* happen when a partition has been shrunk using FIPS, or on
* other occurrences */
tocheck = This->num_clus;
if (tocheck < 0 || tocheck + 1 >= This->last_fat) {
fprintf(stderr, "Too many clusters in FAT\n");
return -1;
}
if(tocheck > 4096)
tocheck = 4096;
for ( i= 3 ; i < tocheck; i++){
f = This->fat_decode(This,i);
if (f == 1 || (f < This->last_fat && f > This->num_clus)){
fprintf(stderr,
"Cluster # at %d too big(%#x)\n", i,f);
fprintf(stderr,"Probably non MS-DOS disk\n");
return -1;
}
}
return 0;
}
/*
* Read the first sector of FAT table into memory. Crude error detection on
* wrong FAT encoding scheme.
*/
static int check_media_type(Fs_t *This, struct bootsector *boot,
unsigned int tot_sectors)
{
unsigned char *address;
This->num_clus = (tot_sectors - This->clus_start) / This->cluster_size;
This->FatMap = GetFatMap(This);
if (This->FatMap == NULL) {
perror("alloc fat map");
return -1;
}
address = getAddress(This, 0, FAT_ACCESS_READ);
if(!address) {
fprintf(stderr,
"Could not read first FAT sector\n");
return -1;
}
if(mtools_skip_check)
return 0;
if(!address[0] && !address[1] && !address[2])
/* Some Atari disks have zeroes where Dos has media descriptor
* and 0xff. Do not consider this as an error */
return 0;
if((address[0] != boot->descr && boot->descr >= 0xf0 &&
((address[0] != 0xf9 && address[0] != 0xf7)
|| boot->descr != 0xf0)) || address[0] < 0xf0) {
fprintf(stderr,
"Bad media types %02x/%02x, probably non-MSDOS disk\n",
address[0],
boot->descr);
return -1;
}
if(address[1] != 0xff || address[2] != 0xff){
fprintf(stderr,"Initial byte of fat is not 0xff\n");
return -1;
}
return 0;
}
static int fat_32_read(Fs_t *This, struct bootsector *boot,
unsigned int tot_sectors)
{
int size;
This->fat_len = DWORD(ext.fat32.bigFat);
This->writeAllFats = !(boot->ext.fat32.extFlags[0] & 0x80);
This->primaryFat = boot->ext.fat32.extFlags[0] & 0xf;
This->rootCluster = DWORD(ext.fat32.rootCluster);
This->clus_start = This->fat_start + This->num_fat * This->fat_len;
/* read the info sector */
size = This->sector_size;
This->infoSectorLoc = WORD(ext.fat32.infoSector);
if(This->sector_size >= 512 &&
This->infoSectorLoc && This->infoSectorLoc != MAX32) {
InfoSector_t *infoSector;
infoSector = (InfoSector_t *) safe_malloc(size);
if(forceReadSector(This, (char *)infoSector,
This->infoSectorLoc, 1) == This->sector_size &&
_DWORD(infoSector->signature1) == INFOSECT_SIGNATURE1 &&
_DWORD(infoSector->signature2) == INFOSECT_SIGNATURE2) {
This->freeSpace = _DWORD(infoSector->count);
This->last = _DWORD(infoSector->pos);
}
free(infoSector);
}
set_fat32(This);
return(check_media_type(This,boot, tot_sectors) ||
check_fat(This));
}
static int old_fat_read(Fs_t *This, struct bootsector *boot,
int config_fat_bits,
size_t tot_sectors, int nodups)
{
This->writeAllFats = 1;
This->primaryFat = 0;
This->dir_start = This->fat_start + This->num_fat * This->fat_len;
This->clus_start = This->dir_start + This->dir_len;
This->infoSectorLoc = MAX32;
if(nodups)
This->num_fat = 1;
if(check_media_type(This,boot, tot_sectors))
return -1;
if(This->num_clus > FAT12) {
set_fat16(This);
/* third FAT byte must be 0xff */
if(!mtools_skip_check && readByte(This, 3) != 0xff)
return -1;
} else
set_fat12(This);
return check_fat(This);
}
/*
* Read the first sector of the FAT table into memory and initialize
* structures.
*/
int fat_read(Fs_t *This, struct bootsector *boot, int fat_bits,
size_t tot_sectors, int nodups)
{
This->fat_error = 0;
This->fat_dirty = 0;
This->last = MAX32;
This->freeSpace = MAX32;
This->lastFatSectorNr = 0;
This->lastFatSectorData = 0;
if(This->fat_len)
return old_fat_read(This, boot, fat_bits, tot_sectors, nodups);
else
return fat_32_read(This, boot, tot_sectors);
}
unsigned int fatDecode(Fs_t *This, unsigned int pos)
{
int ret;
ret = This->fat_decode(This, pos);
if(ret && (ret < 2 || ret > This->num_clus+1) && ret < This->last_fat) {
fprintf(stderr, "Bad FAT entry %d at %d\n", ret, pos);
This->fat_error++;
}
return ret;
}
/* append a new cluster */
void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos)
{
This->fat_encode(This, pos, newpos);
This->fat_encode(This, newpos, This->end_fat);
if(This->freeSpace != MAX32)
This->freeSpace--;
}
/* de-allocates the given cluster */
void fatDeallocate(Fs_t *This, unsigned int pos)
{
This->fat_encode(This, pos, 0);
if(This->freeSpace != MAX32)
This->freeSpace++;
}
/* allocate a new cluster */
void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value)
{
This->fat_encode(This, pos, value);
if(This->freeSpace != MAX32)
This->freeSpace--;
}
void fatEncode(Fs_t *This, unsigned int pos, unsigned int value)
{
unsigned int oldvalue = This->fat_decode(This, pos);
This->fat_encode(This, pos, value);
if(This->freeSpace != MAX32) {
if(oldvalue)
This->freeSpace++;
if(value)
This->freeSpace--;
}
}
unsigned int get_next_free_cluster(Fs_t *This, unsigned int last)
{
int i;
if(This->last != MAX32)
last = This->last;
if (last < 2 ||
last >= This->num_clus+1)
last = 1;
for (i=last+1; i< This->num_clus+2; i++) {
if (!fatDecode(This, i)) {
This->last = i;
return i;
}
}
for(i=2; i < last+1; i++) {
if (!fatDecode(This, i)) {
This->last = i;
return i;
}
}
fprintf(stderr,"No free cluster %d %d\n", This->preallocatedClusters,
This->last);
return 1;
}
int fat_error(Stream_t *Dir)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
if(This->fat_error)
fprintf(stderr,"Fat error detected\n");
return This->fat_error;
}
int fat32RootCluster(Stream_t *Dir)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
if(This->fat_bits == 32)
return This->rootCluster;
else
return 0;
}
/*
* Get the amount of free space on the diskette
*/
mt_size_t getfree(Stream_t *Dir)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
if(This->freeSpace == MAX32 || This->freeSpace == 0) {
register unsigned int i;
size_t total;
total = 0L;
for (i = 2; i < This->num_clus + 2; i++)
if (!fatDecode(This,i))
total++;
This->freeSpace = total;
}
return sectorsToBytes((Stream_t*)This,
This->freeSpace * This->cluster_size);
}
/*
* Ensure that there is a minimum of total sectors free
*/
int getfreeMinClusters(Stream_t *Dir, size_t size)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
register unsigned int i, last;
size_t total;
if(batchmode && This->freeSpace == MAX32)
getfree(Stream);
if(This->freeSpace != MAX32) {
if(This->freeSpace >= size)
return 1;
else {
fprintf(stderr, "Disk full\n");
got_signal = 1;
return 0;
}
}
total = 0L;
/* we start at the same place where we'll start later to actually
* allocate the sectors. That way, the same sectors of the FAT, which
* are already loaded during getfreeMin will be able to be reused
* during get_next_free_cluster */
last = This->last;
if ( last < 2 || last >= This->num_clus + 2)
last = 1;
for (i=last+1; i< This->num_clus+2; i++){
if (!fatDecode(This, i))
total++;
if(total >= size)
return 1;
}
for(i=2; i < last+1; i++){
if (!fatDecode(This, i))
total++;
if(total >= size)
return 1;
}
fprintf(stderr, "Disk full\n");
got_signal = 1;
return 0;
}
int getfreeMinBytes(Stream_t *Dir, mt_size_t size)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
size_t size2;
size2 = size / (This->sector_size * This->cluster_size);
if(size % (This->sector_size * This->cluster_size))
size2++;
return getfreeMinClusters(Dir, size2);
}
unsigned int getStart(Stream_t *Dir, struct directory *dir)
{
Stream_t *Stream = GetFs(Dir);
unsigned int first;
first = START(dir);
if(fat32RootCluster(Stream))
first |= STARTHI(dir) << 16;
return first;
}
int fs_free(Stream_t *Stream)
{
DeclareThis(Fs_t);
if(This->FatMap) {
int i, nr_entries;
nr_entries = (This->fat_len + SECT_PER_ENTRY - 1) /
SECT_PER_ENTRY;
for(i=0; i< nr_entries; i++)
if(This->FatMap[i].data)
free(This->FatMap[i].data);
free(This->FatMap);
}
return 0;
}

View file

@ -1,55 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "fsP.h"
#include "mtoolsDirent.h"
/*
* Remove a string of FAT entries (delete the file). The argument is
* the beginning of the string. Does not consider the file length, so
* if FAT is corrupted, watch out!
*/
int fat_free(Stream_t *Dir, unsigned int fat)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
unsigned int next_no_step;
/* a zero length file? */
if (fat == 0)
return(0);
/* CONSTCOND */
while (!This->fat_error) {
/* get next cluster number */
next_no_step = fatDecode(This,fat);
/* mark current cluster as empty */
fatDeallocate(This,fat);
if (next_no_step >= This->last_fat)
break;
fat = next_no_step;
}
return(0);
}
int fatFreeWithDir(Stream_t *Dir, struct directory *dir)
{
unsigned int first;
if((!strncmp(dir->name,". ",8) ||
!strncmp(dir->name,".. ",8)) &&
!strncmp(dir->ext," ",3)) {
fprintf(stderr,"Trying to remove . or .. entry\n");
return -1;
}
first = START(dir);
if(fat32RootCluster(Dir))
first |= STARTHI(dir) << 16;
return fat_free(Dir, first);
}
int fatFreeWithDirentry(direntry_t *entry)
{
return fatFreeWithDir(entry->Dir, &entry->dir);
}

View file

@ -1,676 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "stream.h"
#include "mtools.h"
#include "fsP.h"
#include "file.h"
#include "htable.h"
#include "dirCache.h"
typedef struct File_t {
Class_t *Class;
int refs;
struct Fs_t *Fs; /* Filesystem that this fat file belongs to */
Stream_t *Buffer;
int (*map)(struct File_t *this, off_t where, size_t *len, int mode,
mt_off_t *res);
size_t FileSize;
size_t preallocatedSize;
int preallocatedClusters;
/* Absolute position of first cluster of file */
unsigned int FirstAbsCluNr;
/* Absolute position of previous cluster */
unsigned int PreviousAbsCluNr;
/* Relative position of previous cluster */
unsigned int PreviousRelCluNr;
direntry_t direntry;
int hint;
struct dirCache_t *dcp;
unsigned int loopDetectRel;
unsigned int loopDetectAbs;
} File_t;
static Class_t FileClass;
T_HashTable *filehash;
static File_t *getUnbufferedFile(Stream_t *Stream)
{
while(Stream->Class != &FileClass)
Stream = Stream->Next;
return (File_t *) Stream;
}
Fs_t *getFs(Stream_t *Stream)
{
return getUnbufferedFile(Stream)->Fs;
}
struct dirCache_t **getDirCacheP(Stream_t *Stream)
{
return &getUnbufferedFile(Stream)->dcp;
}
direntry_t *getDirentry(Stream_t *Stream)
{
return &getUnbufferedFile(Stream)->direntry;
}
static int recalcPreallocSize(File_t *This)
{
size_t currentClusters, neededClusters;
int clus_size;
int neededPrealloc;
Fs_t *Fs = This->Fs;
int r;
if(This->FileSize & 0xc0000000) {
fprintf(stderr, "Bad filesize\n");
}
if(This->preallocatedSize & 0xc0000000) {
fprintf(stderr, "Bad preallocated size %x\n",
(int) This->preallocatedSize);
}
clus_size = Fs->cluster_size * Fs->sector_size;
currentClusters = (This->FileSize + clus_size - 1) / clus_size;
neededClusters = (This->preallocatedSize + clus_size - 1) / clus_size;
neededPrealloc = neededClusters - currentClusters;
if(neededPrealloc < 0)
neededPrealloc = 0;
r = fsPreallocateClusters(Fs, neededPrealloc - This->preallocatedClusters);
if(r)
return r;
This->preallocatedClusters = neededPrealloc;
return 0;
}
static int _loopDetect(unsigned int *oldrel, unsigned int rel,
unsigned int *oldabs, unsigned int abs)
{
if(*oldrel && rel > *oldrel && abs == *oldabs) {
fprintf(stderr, "loop detected! oldrel=%d newrel=%d abs=%d\n",
*oldrel, rel, abs);
return -1;
}
if(rel >= 2 * *oldrel + 1) {
*oldrel = rel;
*oldabs = abs;
}
return 0;
}
static int loopDetect(File_t *This, unsigned int rel, unsigned int abs)
{
return _loopDetect(&This->loopDetectRel, rel, &This->loopDetectAbs, abs);
}
static unsigned int _countBlocks(Fs_t *This, unsigned int block)
{
unsigned int blocks;
unsigned int rel, oldabs, oldrel;
blocks = 0;
oldabs = oldrel = rel = 0;
while (block <= This->last_fat && block != 1 && block) {
blocks++;
block = fatDecode(This, block);
rel++;
if(_loopDetect(&oldrel, rel, &oldabs, block) < 0)
block = -1;
}
return blocks;
}
unsigned int countBlocks(Stream_t *Dir, unsigned int block)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
return _countBlocks(This, block);
}
/* returns number of bytes in a directory. Represents a file size, and
* can hence be not bigger than 2^32
*/
static size_t countBytes(Stream_t *Dir, unsigned int block)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
return _countBlocks(This, block) *
This->sector_size * This->cluster_size;
}
void printFat(Stream_t *Stream)
{
File_t *This = getUnbufferedFile(Stream);
unsigned long n;
int rel;
unsigned long begin, end;
int first;
n = This->FirstAbsCluNr;
if(!n) {
printf("Root directory or empty file\n");
return;
}
rel = 0;
first = 1;
begin = end = 0;
do {
if (first || n != end+1) {
if (!first) {
if (begin != end)
printf("-%lu", end);
printf("> ");
}
begin = end = n;
printf("<%lu", begin);
} else {
end++;
}
first = 0;
n = fatDecode(This->Fs, n);
rel++;
if(loopDetect(This, rel, n) < 0)
n = 1;
} while (n <= This->Fs->last_fat && n != 1);
if(!first) {
if (begin != end)
printf("-%lu", end);
printf(">");
}
}
static int normal_map(File_t *This, off_t where, size_t *len, int mode,
mt_off_t *res)
{
int offset;
off_t end;
int NrClu; /* number of clusters to read */
unsigned int RelCluNr;
unsigned int CurCluNr;
unsigned int NewCluNr;
unsigned int AbsCluNr;
int clus_size;
Fs_t *Fs = This->Fs;
*res = 0;
clus_size = Fs->cluster_size * Fs->sector_size;
offset = where % clus_size;
if (mode == MT_READ)
maximize(*len, This->FileSize - where);
if (*len == 0 )
return 0;
if (This->FirstAbsCluNr < 2){
if( mode == MT_READ || *len == 0){
*len = 0;
return 0;
}
NewCluNr = get_next_free_cluster(This->Fs, 1);
if (NewCluNr == 1 ){
errno = ENOSPC;
return -2;
}
hash_remove(filehash, (void *) This, This->hint);
This->FirstAbsCluNr = NewCluNr;
hash_add(filehash, (void *) This, &This->hint);
fatAllocate(This->Fs, NewCluNr, Fs->end_fat);
}
RelCluNr = where / clus_size;
if (RelCluNr >= This->PreviousRelCluNr){
CurCluNr = This->PreviousRelCluNr;
AbsCluNr = This->PreviousAbsCluNr;
} else {
CurCluNr = 0;
AbsCluNr = This->FirstAbsCluNr;
}
NrClu = (offset + *len - 1) / clus_size;
while (CurCluNr <= RelCluNr + NrClu){
if (CurCluNr == RelCluNr){
/* we have reached the beginning of our zone. Save
* coordinates */
This->PreviousRelCluNr = RelCluNr;
This->PreviousAbsCluNr = AbsCluNr;
}
NewCluNr = fatDecode(This->Fs, AbsCluNr);
if (NewCluNr == 1 || NewCluNr == 0){
fprintf(stderr,"Fat problem while decoding %d %x\n",
AbsCluNr, NewCluNr);
exit(1);
}
if(CurCluNr == RelCluNr + NrClu)
break;
if (NewCluNr > Fs->last_fat && mode == MT_WRITE){
/* if at end, and writing, extend it */
NewCluNr = get_next_free_cluster(This->Fs, AbsCluNr);
if (NewCluNr == 1 ){ /* no more space */
errno = ENOSPC;
return -2;
}
fatAppend(This->Fs, AbsCluNr, NewCluNr);
}
if (CurCluNr < RelCluNr && NewCluNr > Fs->last_fat){
*len = 0;
return 0;
}
if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
break;
CurCluNr++;
AbsCluNr = NewCluNr;
if(loopDetect(This, CurCluNr, AbsCluNr)) {
errno = EIO;
return -2;
}
}
maximize(*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
end = where + *len;
if(batchmode && mode == MT_WRITE && end >= This->FileSize) {
*len += ROUND_UP(end, clus_size) - end;
}
if((*len + offset) / clus_size + This->PreviousAbsCluNr-2 >
Fs->num_clus) {
fprintf(stderr, "cluster too big\n");
exit(1);
}
*res = sectorsToBytes((Stream_t*)Fs,
(This->PreviousAbsCluNr-2) * Fs->cluster_size +
Fs->clus_start) + offset;
return 1;
}
static int root_map(File_t *This, off_t where, size_t *len, int mode,
mt_off_t *res)
{
Fs_t *Fs = This->Fs;
if(Fs->dir_len * Fs->sector_size < where) {
*len = 0;
errno = ENOSPC;
return -2;
}
maximize(*len, Fs->dir_len * Fs->sector_size - where);
if (*len == 0)
return 0;
*res = sectorsToBytes((Stream_t*)Fs, Fs->dir_start) + where;
return 1;
}
static int read_file(Stream_t *Stream, char *buf, mt_off_t iwhere,
size_t len)
{
DeclareThis(File_t);
mt_off_t pos;
int err;
off_t where = truncBytes32(iwhere);
Stream_t *Disk = This->Fs->Next;
err = This->map(This, where, &len, MT_READ, &pos);
if(err <= 0)
return err;
return READS(Disk, buf, pos, len);
}
static int write_file(Stream_t *Stream, char *buf, mt_off_t iwhere, size_t len)
{
DeclareThis(File_t);
mt_off_t pos;
int ret;
size_t requestedLen;
Stream_t *Disk = This->Fs->Next;
off_t where = truncBytes32(iwhere);
int err;
requestedLen = len;
err = This->map(This, where, &len, MT_WRITE, &pos);
if( err <= 0)
return err;
if(batchmode)
ret = force_write(Disk, buf, pos, len);
else
ret = WRITES(Disk, buf, pos, len);
if(ret > requestedLen)
ret = requestedLen;
if (ret > 0 && where + ret > This->FileSize )
This->FileSize = where + ret;
recalcPreallocSize(This);
return ret;
}
/*
* Convert an MSDOS time & date stamp to the Unix time() format
*/
static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
0, 0, 0 };
static inline time_t conv_stamp(struct directory *dir)
{
struct tm *tmbuf;
long tzone, dst;
time_t accum, tmp;
accum = DOS_YEAR(dir) - 1970; /* years past */
/* days passed */
accum = accum * 365L + month[DOS_MONTH(dir)-1] + DOS_DAY(dir);
/* leap years */
accum += (DOS_YEAR(dir) - 1972) / 4L;
/* back off 1 day if before 29 Feb */
if (!(DOS_YEAR(dir) % 4) && DOS_MONTH(dir) < 3)
accum--;
accum = accum * 24L + DOS_HOUR(dir); /* hours passed */
accum = accum * 60L + DOS_MINUTE(dir); /* minutes passed */
accum = accum * 60L + DOS_SEC(dir); /* seconds passed */
#ifndef OS_Minix
/* correct for Time Zone */
#ifdef HAVE_GETTIMEOFDAY
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
tzone = tz.tz_minuteswest * 60L;
}
#else
#ifdef HAVE_TZSET
{
#ifndef OS_ultrix
/* Ultrix defines this to be a different type */
extern long timezone;
#endif
tzset();
tzone = (long) timezone;
}
#else
tzone = 0;
#endif /* HAVE_TZSET */
#endif /* HAVE_GETTIMEOFDAY */
accum += tzone;
#endif /* OS_Minix */
/* correct for Daylight Saving Time */
tmp = accum;
tmbuf = localtime(&tmp);
#ifndef OS_Minix
dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L;
accum += dst;
#endif
return accum;
}
static int get_file_data(Stream_t *Stream, time_t *date, mt_size_t *size,
int *type, int *address)
{
DeclareThis(File_t);
if(date)
*date = conv_stamp(& This->direntry.dir);
if(size)
*size = (mt_size_t) This->FileSize;
if(type)
*type = This->direntry.dir.attr & ATTR_DIR;
if(address)
*address = This->FirstAbsCluNr;
return 0;
}
static int free_file(Stream_t *Stream)
{
DeclareThis(File_t);
Fs_t *Fs = This->Fs;
fsPreallocateClusters(Fs, -This->preallocatedClusters);
FREE(&This->direntry.Dir);
freeDirCache(Stream);
return hash_remove(filehash, (void *) Stream, This->hint);
}
static int flush_file(Stream_t *Stream)
{
DeclareThis(File_t);
direntry_t *entry = &This->direntry;
if(isRootDir(Stream)) {
return 0;
}
if(This->FirstAbsCluNr != getStart(entry->Dir, &entry->dir)) {
set_word(entry->dir.start, This->FirstAbsCluNr & 0xffff);
set_word(entry->dir.startHi, This->FirstAbsCluNr >> 16);
dir_write(entry);
}
return 0;
}
static int pre_allocate_file(Stream_t *Stream, mt_size_t isize)
{
DeclareThis(File_t);
size_t size = truncBytes32(isize);
if(size > This->FileSize &&
size > This->preallocatedSize) {
This->preallocatedSize = size;
return recalcPreallocSize(This);
} else
return 0;
}
static Class_t FileClass = {
read_file,
write_file,
flush_file, /* flush */
free_file, /* free */
0, /* get_geom */
get_file_data,
pre_allocate_file
};
static unsigned int getAbsCluNr(File_t *This)
{
if(This->FirstAbsCluNr)
return This->FirstAbsCluNr;
if(isRootDir((Stream_t *) This))
return 0;
return 1;
}
static unsigned int func1(void *Stream)
{
DeclareThis(File_t);
return getAbsCluNr(This) ^ (long) This->Fs;
}
static unsigned int func2(void *Stream)
{
DeclareThis(File_t);
return getAbsCluNr(This);
}
static int comp(void *Stream, void *Stream2)
{
DeclareThis(File_t);
File_t *This2 = (File_t *) Stream2;
return This->Fs != This2->Fs ||
getAbsCluNr(This) != getAbsCluNr(This2);
}
static void init_hash(void)
{
static int is_initialised=0;
if(!is_initialised){
make_ht(func1, func2, comp, 20, &filehash);
is_initialised = 1;
}
}
static Stream_t *_internalFileOpen(Stream_t *Dir, unsigned int first,
size_t size, direntry_t *entry)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
File_t Pattern;
File_t *File;
init_hash();
This->refs++;
if(first != 1){
/* we use the illegal cluster 1 to mark newly created files.
* do not manage those by hashtable */
Pattern.Fs = This;
Pattern.Class = &FileClass;
if(first || (entry && !IS_DIR(entry)))
Pattern.map = normal_map;
else
Pattern.map = root_map;
Pattern.FirstAbsCluNr = first;
Pattern.loopDetectRel = 0;
Pattern.loopDetectAbs = first;
if(!hash_lookup(filehash, (T_HashTableEl) &Pattern,
(T_HashTableEl **)&File, 0)){
File->refs++;
This->refs--;
return (Stream_t *) File;
}
}
File = New(File_t);
if (!File)
return NULL;
File->dcp = 0;
File->preallocatedClusters = 0;
File->preallocatedSize = 0;
/* memorize dir for date and attrib */
File->direntry = *entry;
if(entry->entry == -3)
File->direntry.Dir = (Stream_t *) File; /* root directory */
else
COPY(File->direntry.Dir);
File->Class = &FileClass;
File->Fs = This;
if(first || (entry && !IS_DIR(entry)))
File->map = normal_map;
else
File->map = root_map; /* FAT 12/16 root directory */
if(first == 1)
File->FirstAbsCluNr = 0;
else
File->FirstAbsCluNr = first;
File->loopDetectRel = 0;
File->loopDetectAbs = 0;
File->PreviousRelCluNr = 0xffff;
File->FileSize = size;
File->refs = 1;
File->Buffer = 0;
hash_add(filehash, (void *) File, &File->hint);
return (Stream_t *) File;
}
Stream_t *OpenRoot(Stream_t *Dir)
{
unsigned int num;
direntry_t entry;
size_t size;
Stream_t *file;
memset(&entry, 0, sizeof(direntry_t));
num = fat32RootCluster(Dir);
/* make the directory entry */
entry.entry = -3;
entry.name[0] = '\0';
mk_entry("/", ATTR_DIR, num, 0, 0, &entry.dir);
if(num)
size = countBytes(Dir, num);
else {
Fs_t *Fs = (Fs_t *) GetFs(Dir);
size = Fs->dir_len * Fs->sector_size;
}
file = _internalFileOpen(Dir, num, size, &entry);
bufferize(&file);
return file;
}
Stream_t *OpenFileByDirentry(direntry_t *entry)
{
Stream_t *file;
unsigned int first;
size_t size;
first = getStart(entry->Dir, &entry->dir);
if(!first && IS_DIR(entry))
return OpenRoot(entry->Dir);
if (IS_DIR(entry))
size = countBytes(entry->Dir, first);
else
size = FILE_SIZE(&entry->dir);
file = _internalFileOpen(entry->Dir, first, size, entry);
if(IS_DIR(entry)) {
bufferize(&file);
if(first == 1)
dir_grow(file, 0);
}
return file;
}
int isRootDir(Stream_t *Stream)
{
File_t *This = getUnbufferedFile(Stream);
return This->map == root_map;
}

View file

@ -1,11 +0,0 @@
#ifndef MTOOLS_FILE_H
#define MTOOLS_FILE_H
#include "stream.h"
#include "mtoolsDirent.h"
Stream_t *OpenFileByDirentry(direntry_t *entry);
Stream_t *OpenRoot(Stream_t *Dir);
void printFat(Stream_t *Stream);
direntry_t *getDirentry(Stream_t *Stream);
#endif

View file

@ -1,203 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "codepage.h"
/* Write a DOS name + extension into a legal unix-style name. */
char *unix_normalize (char *ans, char *name, char *ext)
{
char *a;
int j;
for (a=ans,j=0; (j<8) && (name[j] > ' '); ++j,++a)
*a = name[j];
if(*ext > ' ') {
*a++ = '.';
for (j=0; j<3 && ext[j] > ' '; ++j,++a)
*a = ext[j];
}
*a++ = '\0';
return ans;
}
typedef enum Case_l {
NONE,
UPPER,
LOWER
} Case_t;
static void TranslateToDos(const char *s, char *t, int count,
char *end, Case_t *Case, int *mangled)
{
*Case = NONE;
for( ; *s && (s < end || !end); s++) {
if(!count) {
*mangled |= 3;
break;
}
/* skip spaces & dots */
if(*s == ' ' || *s == '.') {
*mangled |= 3;
continue;
}
/* convert to dos */
if((*s) & 0x80) {
*mangled |= 1;
*t = to_dos(*s);
}
if ((*s & 0x7f) < ' ' ) {
*mangled |= 3;
*t = '_';
} else if (islower((unsigned char)*s)) {
*t = toupper(*s);
if(*Case == UPPER && !mtools_no_vfat)
*mangled |= 1;
else
*Case = LOWER;
} else if (isupper((unsigned char)*s)) {
*t = *s;
if(*Case == LOWER && !mtools_no_vfat)
*mangled |= 1;
else
*Case = UPPER;
} else if((*s) & 0x80)
*t = mstoupper(*t); /* upper case */
else
*t = *s;
count--;
t++;
}
}
/* dos_name
*
* Convert a Unix-style filename to a legal MSDOS name and extension.
* Will truncate file and extension names, will substitute
* the character '~' for any illegal character(s) in the name.
*/
char *dos_name(char *name, int verbose, int *mangled, char *ans)
{
char *s, *ext;
register int i;
Case_t BaseCase, ExtCase;
*mangled = 0;
/* skip drive letter */
name = skip_drive(name);
/* zap the leading path */
name = (char *) _basename(name);
if ((s = strrchr(name, '\\')))
name = s + 1;
memset(ans, ' ', 11);
ans[11]='\0';
/* skip leading dots and spaces */
i = strspn(name, ". ");
if(i) {
name += i;
*mangled = 3;
}
ext = strrchr(name, '.');
/* main name */
TranslateToDos(name, ans, 8, ext, &BaseCase, mangled);
if(ext)
TranslateToDos(ext+1, ans+8, 3, 0, &ExtCase, mangled);
if(*mangled & 2)
autorename_short(ans, 0);
if(!*mangled) {
if(BaseCase == LOWER)
*mangled |= BASECASE;
if(ExtCase == LOWER)
*mangled |= EXTCASE;
if((BaseCase == LOWER || ExtCase == LOWER) &&
!mtools_no_vfat) {
*mangled |= 1;
}
}
return ans;
}
/*
* Get rid of spaces in an MSDOS 'raw' name (one that has come from the
* directory structure) so that it can be used for regular expression
* matching with a Unix filename. Also used to 'unfix' a name that has
* been altered by dos_name().
*/
char *unix_name(char *name, char *ext, char Case, char *ans)
{
char *s, tname[9], text[4];
int i;
strncpy(tname, (char *) name, 8);
tname[8] = '\0';
if ((s = strchr(tname, ' ')))
*s = '\0';
if(!(Case & (BASECASE | EXTCASE)) && mtools_ignore_short_case)
Case |= BASECASE | EXTCASE;
if(Case & BASECASE)
for(i=0;i<8 && tname[i];i++)
tname[i] = tolower(tname[i]);
strncpy(text, (char *) ext, 3);
text[3] = '\0';
if ((s = strchr(text, ' ')))
*s = '\0';
if(Case & EXTCASE)
for(i=0;i<3 && text[i];i++)
text[i] = tolower(text[i]);
if (*text) {
strcpy(ans, tname);
strcat(ans, ".");
strcat(ans, text);
} else
strcpy(ans, tname);
/* fix special characters (above 0x80) */
to_unix(ans,11);
return(ans);
}
/* If null encountered, set *end to 0x40 and write nulls rest of way
* 950820: Win95 does not like this! It complains about bad characters.
* So, instead: If null encountered, set *end to 0x40, write the null, and
* write 0xff the rest of the way (that is what Win95 seems to do; hopefully
* that will make it happy)
*/
/* Always return num */
int unicode_write(char *in, struct unicode_char *out, int num, int *end_p)
{
int j;
for (j=0; j<num; ++j) {
out->uchar = '\0'; /* Hard coded to ASCII */
if (*end_p)
/* Fill with 0xff */
out->uchar = out->lchar = (char) 0xff;
else {
out->lchar = *in;
if (! *in) {
*end_p = VSE_LAST;
}
}
++out;
++in;
}
return num;
}

View file

@ -1,37 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "file.h"
/*
* Read the clusters given the beginning FAT entry. Returns 0 on success.
*/
int file_read(FILE *fp, Stream_t *Source, int textmode, int stripmode)
{
char buffer[16384];
int pos;
int ret;
if (!Source){
fprintf(stderr,"Couldn't open source file\n");
return -1;
}
pos = 0;
while(1){
ret = Source->Class->read(Source, buffer, (mt_off_t) pos, 16384);
if (ret < 0 ){
perror("file read");
return -1;
}
if ( ret == 0)
break;
if(!fwrite(buffer, 1, ret, fp)){
perror("write");
return -1;
}
pos += ret;
}
return 0;
}

View file

@ -1,140 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
typedef struct Filter_t {
Class_t *Class;
int refs;
Stream_t *Next;
Stream_t *Buffer;
int dospos;
int unixpos;
int mode;
int rw;
int lastchar;
} Filter_t;
#define F_READ 1
#define F_WRITE 2
/* read filter filters out messy dos' bizarre end of lines and final 0x1a's */
static int read_filter(Stream_t *Stream, char *buf, mt_off_t iwhere, size_t len)
{
DeclareThis(Filter_t);
int i,j,ret;
off_t where = truncBytes32(iwhere);
if ( where != This->unixpos ){
fprintf(stderr,"Bad offset\n");
exit(1);
}
if (This->rw == F_WRITE){
fprintf(stderr,"Change of transfer direction!\n");
exit(1);
}
This->rw = F_READ;
ret = READS(This->Next, buf, (mt_off_t) This->dospos, len);
if ( ret < 0 )
return ret;
j = 0;
for (i=0; i< ret; i++){
if ( buf[i] == '\r' )
continue;
if (buf[i] == 0x1a)
break;
This->lastchar = buf[j++] = buf[i];
}
This->dospos += i;
This->unixpos += j;
return j;
}
static int write_filter(Stream_t *Stream, char *buf, mt_off_t iwhere,
size_t len)
{
DeclareThis(Filter_t);
int i,j,ret;
char buffer[1025];
off_t where = truncBytes32(iwhere);
if(This->unixpos == -1)
return -1;
if (where != This->unixpos ){
fprintf(stderr,"Bad offset\n");
exit(1);
}
if (This->rw == F_READ){
fprintf(stderr,"Change of transfer direction!\n");
exit(1);
}
This->rw = F_WRITE;
j=i=0;
while(i < 1024 && j < len){
if (buf[j] == '\n' ){
buffer[i++] = '\r';
buffer[i++] = '\n';
j++;
continue;
}
buffer[i++] = buf[j++];
}
This->unixpos += j;
ret = force_write(This->Next, buffer, (mt_off_t) This->dospos, i);
if(ret >0 )
This->dospos += ret;
if ( ret != i ){
/* no space on target file ? */
This->unixpos = -1;
return -1;
}
return j;
}
static int free_filter(Stream_t *Stream)
{
DeclareThis(Filter_t);
char buffer=0x1a;
/* write end of file */
if (This->rw == F_WRITE)
return force_write(This->Next, &buffer, (mt_off_t) This->dospos, 1);
else
return 0;
}
static Class_t FilterClass = {
read_filter,
write_filter,
0, /* flush */
free_filter,
0, /* set geometry */
get_data_pass_through,
0
};
Stream_t *open_filter(Stream_t *Next)
{
Filter_t *This;
This = New(Filter_t);
if (!This)
return NULL;
This->Class = &FilterClass;
This->dospos = This->unixpos = This->rw = 0;
This->Next = Next;
This->refs = 1;
This->Buffer = 0;
return (Stream_t *) This;
}

View file

@ -1,559 +0,0 @@
/*
* IO to the floppyd daemon running on the local X-Server Host
*
* written by:
*
* Peter Schlaile
*
* udbz@rz.uni-karlsruhe.de
*
*/
#include "sysincludes.h"
#include "stream.h"
#include "mtools.h"
#include "msdos.h"
#include "scsi.h"
#include "partition.h"
#include "floppyd_io.h"
#ifdef USE_FLOPPYD
/* ######################################################################## */
typedef unsigned char Byte;
typedef unsigned long Dword;
char* AuthErrors[] = {
"Auth success!",
"Auth failed: Packet oversized!",
"Auth failed: X-Cookie doesn't match!",
"Auth failed: Wrong transmission protocol version!",
"Auth failed: Device locked!"
};
typedef struct RemoteFile_t {
Class_t *Class;
int refs;
Stream_t *Next;
Stream_t *Buffer;
int fd;
mt_off_t offset;
mt_off_t lastwhere;
mt_off_t size;
} RemoteFile_t;
#ifndef HAVE_HTONS
unsigned short myhtons(unsigned short parm)
{
Byte val[2];
val[0] = (parm >> 8) & 0xff;
val[1] = parm & 0xff;
return *((unsigned short*) (val));
}
#endif
Dword byte2dword(Byte* val)
{
Dword l;
l = (val[0] << 24) + (val[1] << 16) + (val[2] << 8) + val[3];
return l;
}
void dword2byte(Dword parm, Byte* rval)
{
rval[0] = (parm >> 24) & 0xff;
rval[1] = (parm >> 16) & 0xff;
rval[2] = (parm >> 8) & 0xff;
rval[3] = parm & 0xff;
}
Dword read_dword(int handle)
{
Byte val[4];
read(handle, val, 4);
return byte2dword(val);
}
void write_dword(int handle, Dword parm)
{
Byte val[4];
dword2byte(parm, val);
write(handle, val, 4);
}
/* ######################################################################## */
int authenticate_to_floppyd(int sock, char *display)
{
off_t filelen;
Byte buf[16];
char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
char *xcookie;
Dword errcode;
command[4] = display;
filelen=strlen(display);
filelen += 100;
xcookie = (char *) safe_malloc(filelen+4);
filelen = safePopenOut(command, xcookie+4, filelen);
if(filelen < 1)
return AUTH_AUTHFAILED;
dword2byte(4,buf);
dword2byte(FLOPPYD_PROTOCOL_VERSION,buf+4);
write(sock, buf, 8);
if (read_dword(sock) != 4) {
return AUTH_WRONGVERSION;
}
errcode = read_dword(sock);
if (errcode != AUTH_SUCCESS) {
return errcode;
}
dword2byte(filelen, xcookie);
write(sock, xcookie, filelen+4);
if (read_dword(sock) != 4) {
return AUTH_PACKETOVERSIZE;
}
errcode = read_dword(sock);
return errcode;
}
static int floppyd_reader(int fd, char* buffer, int len)
{
Dword errcode;
Dword gotlen;
int l;
int start;
Byte buf[16];
dword2byte(1, buf);
buf[4] = OP_READ;
dword2byte(4, buf+5);
dword2byte(len, buf+9);
write(fd, buf, 13);
if (read_dword(fd) != 8) {
errno = EIO;
return -1;
}
gotlen = read_dword(fd);
errcode = read_dword(fd);
if (gotlen != -1) {
if (read_dword(fd) != gotlen) {
errno = EIO;
return -1;
}
for (start = 0, l = 0; start < gotlen; start += l) {
l = read(fd, buffer+start, gotlen-start);
if (l == 0) {
errno = EIO;
return -1;
}
}
} else {
errno = errcode;
}
return gotlen;
}
static int floppyd_writer(int fd, char* buffer, int len)
{
Dword errcode;
Dword gotlen;
Byte buf[16];
dword2byte(1, buf);
buf[4] = OP_WRITE;
dword2byte(len, buf+5);
write(fd, buf, 9);
write(fd, buffer, len);
if (read_dword(fd) != 8) {
errno = EIO;
return -1;
}
gotlen = read_dword(fd);
errcode = read_dword(fd);
errno = errcode;
return gotlen;
}
static int floppyd_lseek(int fd, mt_off_t offset, int whence)
{
Dword errcode;
Dword gotlen;
Byte buf[32];
dword2byte(1, buf);
buf[4] = OP_SEEK;
dword2byte(8, buf+5);
dword2byte(truncBytes32(offset), buf+9);
dword2byte(whence, buf+13);
write(fd, buf, 17);
if (read_dword(fd) != 8) {
errno = EIO;
return -1;
}
gotlen = read_dword(fd);
errcode = read_dword(fd);
errno = errcode;
return gotlen;
}
/* ######################################################################## */
typedef int (*iofn) (int, char *, int);
static int floppyd_io(Stream_t *Stream, char *buf, mt_off_t where, int len,
iofn io)
{
DeclareThis(RemoteFile_t);
int ret;
where += This->offset;
if (where != This->lastwhere ){
if(floppyd_lseek( This->fd, where, SEEK_SET) < 0 ){
perror("floppyd_lseek");
This->lastwhere = (mt_off_t) -1;
return -1;
}
}
ret = io(This->fd, buf, len);
if ( ret == -1 ){
perror("floppyd_io");
This->lastwhere = (mt_off_t) -1;
return -1;
}
This->lastwhere = where + ret;
return ret;
}
static int floppyd_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
{
return floppyd_io(Stream, buf, where, len, (iofn) floppyd_reader);
}
static int floppyd_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
{
return floppyd_io(Stream, buf, where, len, (iofn) floppyd_writer);
}
static int floppyd_flush(Stream_t *Stream)
{
#if 0
Byte buf[16];
DeclareThis(RemoteFile_t);
dword2byte(1, buf);
buf[4] = OP_FLUSH;
write(This->fd, buf, 5);
if (read_dword(This->fd) != 8) {
errno = EIO;
return -1;
}
read_dword(This->fd);
read_dword(This->fd);
#endif
return 0;
}
static int floppyd_free(Stream_t *Stream)
{
Byte buf[16];
DeclareThis(RemoteFile_t);
if (This->fd > 2) {
dword2byte(1, buf);
buf[4] = OP_CLOSE;
write(This->fd, buf, 5);
return close(This->fd);
} else {
return 0;
}
}
static int floppyd_geom(Stream_t *Stream, struct device *dev,
struct device *orig_dev,
int media, struct bootsector *boot)
{
size_t tot_sectors;
int sect_per_track;
DeclareThis(RemoteFile_t);
dev->ssize = 2; /* allow for init_geom to change it */
dev->use_2m = 0x80; /* disable 2m mode to begin */
if(media == 0xf0 || media >= 0x100){
dev->heads = WORD(nheads);
dev->sectors = WORD(nsect);
tot_sectors = DWORD(bigsect);
SET_INT(tot_sectors, WORD(psect));
sect_per_track = dev->heads * dev->sectors;
tot_sectors += sect_per_track - 1; /* round size up */
dev->tracks = tot_sectors / sect_per_track;
} else if (media >= 0xf8){
media &= 3;
dev->heads = old_dos[media].heads;
dev->tracks = old_dos[media].tracks;
dev->sectors = old_dos[media].sectors;
dev->ssize = 0x80;
dev->use_2m = ~1;
} else {
fprintf(stderr,"Unknown media type\n");
exit(1);
}
This->size = (mt_off_t) 512 * dev->sectors * dev->tracks * dev->heads;
return 0;
}
static int floppyd_data(Stream_t *Stream, time_t *date, mt_size_t *size,
int *type, int *address)
{
DeclareThis(RemoteFile_t);
if(date)
/* unknown, and irrelevant anyways */
*date = 0;
if(size)
/* the size derived from the geometry */
*size = (mt_size_t) This->size;
if(type)
*type = 0; /* not a directory */
if(address)
*address = 0;
return 0;
}
/* ######################################################################## */
static Class_t FloppydFileClass = {
floppyd_read,
floppyd_write,
floppyd_flush,
floppyd_free,
floppyd_geom,
floppyd_data
};
/* ######################################################################## */
int get_host_and_port(const char* name, char** hostname, char **display,
short* port)
{
char* newname = strdup(name);
char* p;
char* p2;
p = newname;
while (*p != '/' && *p) p++;
p2 = p;
if (*p) p++;
*p2 = 0;
*port = atoi(p);
if (*port == 0) {
*port = FLOPPYD_DEFAULT_PORT;
}
*display = strdup(newname);
p = newname;
while (*p != ':' && *p) p++;
p2 = p;
if (*p) p++;
*p2 = 0;
*port += atoi(p); /* add display number to the port */
if (!*newname || strcmp(newname, "unix") == 0) {
free(newname);
newname = strdup("localhost");
}
*hostname = newname;
return 1;
}
/*
* * Return the IP address of the specified host.
* */
static IPaddr_t getipaddress(char *ipaddr)
{
struct hostent *host;
IPaddr_t ip;
if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
(strcmp(ipaddr, "255.255.255.255") != 0)) {
if ((host = gethostbyname(ipaddr)) != NULL) {
memcpy(&ip, host->h_addr, sizeof(ip));
}
endhostent();
}
#ifdef DEBUG
fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
#endif
return (ip);
}
/*
* * Connect to the floppyd server.
* */
static int connect_to_server(IPaddr_t ip, short port)
{
struct sockaddr_in addr;
int sock;
/*
* Allocate a socket.
*/
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return (-1);
}
/*
* Set the address to connect to.
*/
addr.sin_family = AF_INET;
#ifndef HAVE_HTONS
addr.sin_port = myhtons(port);
#else
addr.sin_port = htons(port);
#endif
addr.sin_addr.s_addr = ip;
/*
* Connect our socket to the above address.
*/
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
return (-1);
}
/*
* Set the keepalive socket option to on.
*/
{
int on = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
(char *)&on, sizeof(on));
}
return (sock);
}
static int ConnectToFloppyd(const char* name);
Stream_t *FloppydOpen(struct device *dev, struct device *dev2,
char *name, int mode, char *errmsg,
int mode2, int locked)
{
RemoteFile_t *This;
if (!dev || !(dev->misc_flags & FLOPPYD_FLAG))
return NULL;
This = New(RemoteFile_t);
if (!This){
printOom();
return NULL;
}
This->Class = &FloppydFileClass;
This->Next = 0;
This->offset = 0;
This->lastwhere = 0;
This->refs = 1;
This->Buffer = 0;
This->fd = ConnectToFloppyd(name);
if (This->fd == -1) {
Free(This);
return NULL;
}
return (Stream_t *) This;
}
static int ConnectToFloppyd(const char* name)
{
char* hostname;
char* display;
short port;
int rval = get_host_and_port(name, &hostname, &display, &port);
int sock;
int reply;
if (!rval) return -1;
sock = connect_to_server(getipaddress(hostname), port);
if (sock == -1) {
fprintf(stderr,
"Can't connect to floppyd server on %s, port %i!\n",
hostname, port);
return -1;
}
reply = authenticate_to_floppyd(sock, display);
if (reply != 0) {
fprintf(stderr,
"Permission denied, authentication failed!\n"
"%s\n", AuthErrors[reply]);
return -1;
}
free(hostname);
free(display);
return sock;
}
#endif

View file

@ -1,37 +0,0 @@
#ifndef MTOOLS_FLOPPYDIO_H
#define MTOOLS_FLOPPYDIO_H
#ifdef USE_FLOPPYD
#include "stream.h"
/*extern int ConnectToFloppyd(const char* name, Class_t** ioclass);*/
Stream_t *FloppydOpen(struct device *dev, struct device *dev2,
char *name, int mode, char *errmsg,
int mode2, int locked);
#define FLOPPYD_DEFAULT_PORT 5703
#define FLOPPYD_PROTOCOL_VERSION 10
enum FloppydOpcodes {
OP_READ,
OP_WRITE,
OP_SEEK,
OP_FLUSH,
OP_CLOSE,
OP_IOCTL
};
enum AuthErrorsEnum {
AUTH_SUCCESS,
AUTH_PACKETOVERSIZE,
AUTH_AUTHFAILED,
AUTH_WRONGVERSION,
AUTH_DEVLOCKED,
AUTH_BADPACKET
};
typedef unsigned long IPaddr_t;
#endif
#endif

View file

@ -1,48 +0,0 @@
/*
* Force I/O to be done to complete transfer length
*
* written by:
*
* Alain L. Knaff
* alain@linux.lu
*
*/
#include "sysincludes.h"
#include "msdos.h"
#include "stream.h"
static int force_io(Stream_t *Stream,
char *buf, mt_off_t start, size_t len,
int (*io)(Stream_t *, char *, mt_off_t, size_t))
{
int ret;
int done=0;
while(len){
ret = io(Stream, buf, start, len);
if ( ret <= 0 ){
if (done)
return done;
else
return ret;
}
start += ret;
done += ret;
len -= ret;
buf += ret;
}
return done;
}
int force_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
{
return force_io(Stream, buf, start, len,
Stream->Class->write);
}
int force_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
{
return force_io(Stream, buf, start, len,
Stream->Class->read);
}

View file

@ -1,26 +0,0 @@
#ifndef MTOOLS_FS_H
#define MTOOLS_FS_H
#include "stream.h"
typedef struct FsPublic_t {
Class_t *Class;
int refs;
Stream_t *Next;
Stream_t *Buffer;
int serialized;
unsigned long serial_number;
int cluster_size;
unsigned int sector_size;
} FsPublic_t;
Stream_t *fs_init(char *drive, int mode);
int fat_free(Stream_t *Dir, unsigned int fat);
int fatFreeWithDir(Stream_t *Dir, struct directory *dir);
int fat_error(Stream_t *Dir);
int fat32RootCluster(Stream_t *Dir);
char *getDrive(Stream_t *Stream);
#endif

View file

@ -1,84 +0,0 @@
#ifndef MTOOLS_FSP_H
#define MTOOLS_FSP_H
#include "stream.h"
#include "msdos.h"
#include "fs.h"
typedef enum fatAccessMode_t {
FAT_ACCESS_READ,
FAT_ACCESS_WRITE
} fatAccessMode_t;
typedef struct Fs_t {
Class_t *Class;
int refs;
Stream_t *Next;
Stream_t *Buffer;
int serialized;
unsigned long serial_number;
int cluster_size;
unsigned int sector_size;
int fat_error;
unsigned int (*fat_decode)(struct Fs_t *This, unsigned int num);
void (*fat_encode)(struct Fs_t *This, unsigned int num,
unsigned int code);
Stream_t *Direct;
int fat_dirty;
unsigned int fat_start;
unsigned int fat_len;
int num_fat;
unsigned int end_fat;
unsigned int last_fat;
int fat_bits;
struct FatMap_t *FatMap;
int dir_start;
int dir_len;
int clus_start;
int num_clus;
char *drive; /* for error messages */
/* fat 32 */
unsigned int primaryFat;
unsigned int writeAllFats;
unsigned int rootCluster;
int infoSectorLoc;
unsigned int last; /* last sector allocated, or MAX32 if unknown */
unsigned int freeSpace; /* free space, or MAX32 if unknown */
int preallocatedClusters;
int lastFatSectorNr;
unsigned char *lastFatSectorData;
fatAccessMode_t lastFatAccessMode;
int sectorMask;
int sectorShift;
} Fs_t;
int fs_free(Stream_t *Stream);
void set_fat12(Fs_t *Fs);
void set_fat16(Fs_t *Fs);
void set_fat32(Fs_t *Fs);
unsigned int get_next_free_cluster(Fs_t *Fs, unsigned int last);
unsigned int fatDecode(Fs_t *This, unsigned int pos);
void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos);
void fatDeallocate(Fs_t *This, unsigned int pos);
void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value);
void fatEncode(Fs_t *This, unsigned int pos, unsigned int value);
int fat_read(Fs_t *This, struct bootsector *boot, int fat_bits,
size_t tot_sectors, int nodups);
void fat_write(Fs_t *This);
int zero_fat(Fs_t *Fs, int media_descriptor);
extern Class_t FsClass;
int fsPreallocateClusters(Fs_t *Fs, long);
Fs_t *getFs(Stream_t *Stream);
#endif

View file

@ -1,205 +0,0 @@
/*
* hash.c - hash table.
*/
#include "sysincludes.h"
#include "htable.h"
#include "mtools.h"
struct hashtable {
T_HashFunc f1,f2;
T_ComparFunc compar;
int size; /* actual size of the array */
int fill; /* number of deleted or in use slots */
int inuse; /* number of slots in use */
int max; /* maximal number of elements to keep efficient */
T_HashTableEl *entries;
};
static int sizes[]={5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853,
25717, 51437, 102877, 205759, 411527, 823117, 1646237,
3292489, 6584983, 13169977, 26339969, 52679969, 105359939,
210719881, 421439783, 842879579, 1685759167, 0 };
static int deleted=0;
static int unallocated=0;
static int alloc_ht(T_HashTable *H, int size)
{
int i;
for(i=0; sizes[i]; i++)
if (sizes[i] > size*4 )
break;
if (!sizes[i])
for(i=0; sizes[i]; i++)
if (sizes[i] > size*2 )
break;
if (!sizes[i])
for(i=0; sizes[i]; i++)
if (sizes[i] > size)
break;
if(!sizes[i])
return -1;
size = sizes[i];
if(size < H->size)
size = H->size; /* never shrink the table */
H->max = size * 4 / 5 - 2;
H->size = size;
H->fill = 0;
H->inuse = 0;
H->entries = NewArray(size, T_HashTableEl);
if (H->entries == NULL)
return -1; /* out of memory error */
for(i=0; i < size; i++)
H->entries[i] = &unallocated;
return 0;
}
int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size,
T_HashTable **H)
{
*H = New(T_HashTable);
if (*H == NULL){
return -1; /* out of memory error */
}
(*H)->f1 = f1;
(*H)->f2 = f2;
(*H)->compar = c;
(*H)->size = 0;
if(alloc_ht(*H,size))
return -1;
return 0;
}
int free_ht(T_HashTable *H, T_HashFunc entry_free)
{
int i;
if(entry_free)
for(i=0; i< H->size; i++)
if (H->entries[i] != &unallocated &&
H->entries[i] != &deleted)
entry_free(H->entries[i]);
Free(H->entries);
Free(H);
return 0;
}
/* add into hash table without checking for repeats */
static int _hash_add(T_HashTable *H,T_HashTableEl *E, int *hint)
{
int f2, pos, ctr;
pos = H->f1(E) % H->size;
f2 = -1;
ctr = 0;
while(H->entries[pos] != &unallocated &&
H->entries[pos] != &deleted){
if (f2 == -1)
f2 = H->f2(E) % (H->size - 1);
pos = (pos+f2+1) % H->size;
ctr++;
}
if(H->entries[pos] == &unallocated)
H->fill++; /* only increase fill if the previous element was not yet
* counted, i.e. unallocated */
H->inuse++;
H->entries[pos] = E;
if(hint)
*hint = pos;
return 0;
}
static int rehash(T_HashTable *H)
{
int size,i;
T_HashTableEl *oldentries;
/* resize the table */
size = H->size;
oldentries = H->entries;
if(alloc_ht(H,((H->inuse+1)*4+H->fill)/5))
return -1;
for(i=0; i < size; i++){
if(oldentries[i] != &unallocated && oldentries[i] != &deleted)
_hash_add(H, oldentries[i], 0);
}
Free(oldentries);
return 0;
}
int hash_add(T_HashTable *H, T_HashTableEl *E, int *hint)
{
if (H->fill >= H->max)
rehash(H);
if (H->fill == H->size)
return -1; /*out of memory error */
return _hash_add(H,E, hint);
}
/* add into hash table without checking for repeats */
static int _hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2,
int *hint, int isIdentity)
{
int f2, pos, upos, ttl;
pos = H->f1(E) % H->size;
ttl = H->size;
f2 = -1;
upos = -1;
while(ttl &&
H->entries[pos] != &unallocated &&
(H->entries[pos] == &deleted ||
((isIdentity || H->compar(H->entries[pos], E) != 0) &&
(!isIdentity || H->entries[pos] != E)))){
if (f2 == -1)
f2 = H->f2(E) % (H->size - 1);
if (upos == -1 && H->entries[pos] == &deleted)
upos = pos;
pos = (pos+f2+1) % H->size;
ttl--;
}
if(H->entries[pos] == &unallocated || !ttl)
return -1;
if (upos != -1){
H->entries[upos] = H->entries[pos];
H->entries[pos] = &deleted;
pos = upos;
}
if(hint)
*hint = pos;
*E2= H->entries[pos];
return 0;
}
int hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2,
int *hint)
{
return _hash_lookup(H, E, E2, hint, 0);
}
/* add into hash table without checking for repeats */
int hash_remove(T_HashTable *H,T_HashTableEl *E, int hint)
{
T_HashTableEl *E2;
if (hint >=0 && hint < H->size &&
H->entries[hint] == E){
H->inuse--;
H->entries[hint] = &deleted;
return 0;
}
if(_hash_lookup(H, E, &E2, &hint, 1)) {
fprintf(stderr, "Removing non-existent entry\n");
exit(1);
return -1;
}
H->inuse--;
H->entries[hint] = &deleted;
return 0;
}

View file

@ -1,17 +0,0 @@
/*
* hashtable
*/
typedef struct hashtable T_HashTable;
typedef void *T_HashTableEl;
typedef unsigned int (*T_HashFunc)(void *);
typedef int (*T_ComparFunc)(void *, void *);
int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size, T_HashTable **H);
int hash_add(T_HashTable *H, T_HashTableEl *E, int *hint);
int hash_remove(T_HashTable *H, T_HashTableEl *E, int hint);
int hash_lookup(T_HashTable *H, T_HashTableEl *E, T_HashTableEl **E2,
int *hint);
int free_ht(T_HashTable *H, T_HashFunc entry_free);

View file

@ -1,414 +0,0 @@
/*
* Initialize an MSDOS diskette. Read the boot sector, and switch to the
* proper floppy disk device to match the format on the disk. Sets a bunch
* of global variables. Returns 0 on success, or 1 on failure.
*/
#include "sysincludes.h"
#include "msdos.h"
#include "stream.h"
#include "mtools.h"
#include "fsP.h"
#include "plain_io.h"
#include "floppyd_io.h"
#include "xdf_io.h"
#include "buffer.h"
extern int errno;
#ifndef OS_Minix /* Minix is memory starved. */
#define FULL_CYL
#endif
unsigned int num_clus; /* total number of cluster */
/*
* Read the boot sector. We glean the disk parameters from this sector.
*/
static int read_boot(Stream_t *Stream, struct bootsector * boot, int size)
{
/* read the first sector, or part of it */
if(!size)
size = BOOTSIZE;
if(size > 1024)
size = 1024;
if (force_read(Stream, (char *) boot, 0, size) != size)
return -1;
return 0;
}
static int fs_flush(Stream_t *Stream)
{
DeclareThis(Fs_t);
fat_write(This);
return 0;
}
Class_t FsClass = {
read_pass_through, /* read */
write_pass_through, /* write */
fs_flush,
fs_free, /* free */
0, /* set geometry */
get_data_pass_through,
0 /* pre allocate */
};
static int get_media_type(Stream_t *St, struct bootsector *boot)
{
int media;
media = boot->descr;
if(media < 0xf0){
char temp[512];
/* old DOS disk. Media descriptor in the first FAT byte */
/* old DOS disk always have 512-byte sectors */
if (force_read(St,temp,(mt_off_t) 512,512) == 512)
media = (unsigned char) temp[0];
else
media = 0;
} else
media += 0x100;
return media;
}
Stream_t *GetFs(Stream_t *Fs)
{
while(Fs && Fs->Class != &FsClass)
Fs = Fs->Next;
return Fs;
}
Stream_t *find_device(char *drive, int mode, struct device *out_dev,
struct bootsector *boot,
char *name, int *media, mt_size_t *maxSize)
{
char errmsg[200];
Stream_t *Stream;
struct device *dev;
int r;
#ifdef OS_Minix
static char *devname;
struct device onedevice[2];
struct stat stbuf;
free(devname);
devname = safe_malloc((9 + strlen(drive)) * sizeof(devname[0]));
strcpy(devname, "/dev/dosX");
if (isupper(drive[0]) && drive[1] == 0) {
/* single letter device name, use /dev/dos$drive */
devname[8]= drive[0];
} else
if (strchr(drive, '/') == NULL) {
/* a simple name, use /dev/$drive */
strcpy(devname+5, drive);
} else {
/* a pathname, use as is. */
strcpy(devname, drive);
}
if (stat(devname, &stbuf) != -1) {
memset(onedevice, 0, sizeof(onedevice));
onedevice[0].name = devname;
onedevice[0].drive = drive;
onedevice[1].name = NULL;
onedevice[1].drive = NULL;
dev = onedevice;
} else {
dev = devices;
}
#else
dev = devices;
#endif
Stream = NULL;
sprintf(errmsg, "Drive '%s:' not supported", drive);
/* open the device */
for (; dev->name; dev++) {
FREE(&Stream);
if (strcmp(dev->drive, drive) != 0)
continue;
*out_dev = *dev;
expand(dev->name,name);
#ifdef USING_NEW_VOLD
strcpy(name, getVoldName(dev, name));
#endif
Stream = 0;
#ifdef USE_XDF
Stream = XdfOpen(out_dev, name, mode, errmsg, 0);
if(Stream) {
out_dev->use_2m = 0x7f;
if(maxSize)
*maxSize = max_off_t_31;
}
#endif
#ifdef USE_FLOPPYD
if(!Stream) {
Stream = FloppydOpen(out_dev, dev, name, mode, errmsg, 0, 1);
if(Stream && maxSize)
*maxSize = max_off_t_31;
}
#endif
if (!Stream)
Stream = SimpleFileOpen(out_dev, dev, name, mode,
errmsg, 0, 1, maxSize);
if( !Stream)
continue;
/* read the boot sector */
if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){
sprintf(errmsg,
"init %s: could not read boot sector",
drive);
continue;
}
if((*media= get_media_type(Stream, boot)) <= 0xf0 ){
if (boot->jump[2]=='L')
sprintf(errmsg,
"diskette %s: is Linux LILO, not DOS",
drive);
else
sprintf(errmsg,"init %s: non DOS media", drive);
continue;
}
/* set new parameters, if needed */
errno = 0;
if(SET_GEOM(Stream, out_dev, dev, *media, boot)){
if(errno)
#ifdef HAVE_SNPRINTF
snprintf(errmsg, 199,
"Can't set disk parameters for %s: %s",
drive, strerror(errno));
#else
sprintf(errmsg,
"Can't set disk parameters for %s: %s",
drive, strerror(errno));
#endif
else
sprintf(errmsg,
"Can't set disk parameters for %s",
drive);
continue;
}
break;
}
/* print error msg if needed */
if ( dev->drive == 0 ){
FREE(&Stream);
fprintf(stderr,"%s\n",errmsg);
return NULL;
}
#ifdef OS_Minix
/* Minix can lseek up to 4G. */
if (maxSize) *maxSize = 0xFFFFFFFFUL;
#endif
return Stream;
}
Stream_t *fs_init(char *drive, int mode)
{
int blocksize;
int media,i;
int nhs;
int disk_size = 0; /* In case we don't happen to set this below */
size_t tot_sectors;
char name[EXPAND_BUF];
int cylinder_size;
struct device dev;
mt_size_t maxSize;
struct bootsector boot0;
#define boot (&boot0)
Fs_t *This;
This = New(Fs_t);
if (!This)
return NULL;
This->Direct = NULL;
This->Next = NULL;
This->refs = 1;
This->Buffer = 0;
This->Class = &FsClass;
This->preallocatedClusters = 0;
This->lastFatSectorNr = 0;
This->lastFatAccessMode = 0;
This->lastFatSectorData = 0;
This->drive = drive;
This->last = 0;
This->Direct = find_device(drive, mode, &dev, &boot0, name, &media,
&maxSize);
if(!This->Direct)
return NULL;
This->sector_size = WORD(secsiz);
if(This->sector_size > MAX_SECTOR){
fprintf(stderr,"init %s: sector size too big\n", drive);
return NULL;
}
i = log_2(This->sector_size);
if(i == 24) {
fprintf(stderr,
"init %c: sector size (%d) not a small power of two\n",
drive, This->sector_size);
return NULL;
}
This->sectorShift = i;
This->sectorMask = This->sector_size - 1;
cylinder_size = dev.heads * dev.sectors;
if (!tot_sectors) tot_sectors = dev.tracks * cylinder_size;
This->serialized = 0;
if ((media & ~7) == 0xf8){
i = media & 3;
This->cluster_size = old_dos[i].cluster_size;
tot_sectors = cylinder_size * old_dos[i].tracks;
This->fat_start = 1;
This->fat_len = old_dos[i].fat_len;
This->dir_len = old_dos[i].dir_len;
This->num_fat = 2;
This->sector_size = 512;
This->sectorShift = 9;
This->sectorMask = 511;
This->fat_bits = 12;
nhs = 0;
} else {
struct label_blk_t *labelBlock;
/*
* all numbers are in sectors, except num_clus
* (which is in clusters)
*/
tot_sectors = WORD(psect);
if(!tot_sectors) {
tot_sectors = DWORD(bigsect);
nhs = DWORD(nhs);
} else
nhs = WORD(nhs);
This->cluster_size = boot0.clsiz;
This->fat_start = WORD(nrsvsect);
This->fat_len = WORD(fatlen);
This->dir_len = WORD(dirents) * MDIR_SIZE / This->sector_size;
This->num_fat = boot0.nfat;
if (This->fat_len) {
labelBlock = &boot0.ext.old.labelBlock;
} else {
labelBlock = &boot0.ext.fat32.labelBlock;
}
if(labelBlock->dos4 == 0x29) {
This->serialized = 1;
This->serial_number = _DWORD(labelBlock->serial);
}
}
if (tot_sectors >= (maxSize >> This->sectorShift)) {
fprintf(stderr, "Big disks not supported on this architecture\n");
exit(1);
}
#ifndef OS_Minix /* Strange check, MS-DOS isn't that picky. */
if(!mtools_skip_check && (tot_sectors % dev.sectors)){
fprintf(stderr,
"Total number of sectors not a multiple of"
" sectors per track!\n");
fprintf(stderr,
"Add mtools_skip_check=1 to your .mtoolsrc file "
"to skip this test\n");
exit(1);
}
#endif
/* full cylinder buffering */
#ifdef FULL_CYL
disk_size = (dev.tracks) ? cylinder_size : 512;
#else /* FULL_CYL */
disk_size = (dev.tracks) ? dev.sectors : 512;
#endif /* FULL_CYL */
#if (defined OS_sysv4 && !defined OS_solaris)
/*
* The driver in Dell's SVR4 v2.01 is unreliable with large writes.
*/
disk_size = 0;
#endif /* (defined sysv4 && !defined(solaris)) */
#ifdef OS_linux
disk_size = cylinder_size;
#endif
#if 1
if(disk_size > 256) {
disk_size = dev.sectors;
if(dev.sectors % 2)
disk_size <<= 1;
}
#endif
if (disk_size % 2)
disk_size *= 2;
if(!dev.blocksize || dev.blocksize < This->sector_size)
blocksize = This->sector_size;
else
blocksize = dev.blocksize;
if (disk_size)
This->Next = buf_init(This->Direct,
8 * disk_size * blocksize,
disk_size * blocksize,
This->sector_size);
else
This->Next = This->Direct;
if (This->Next == NULL) {
perror("init: allocate buffer");
This->Next = This->Direct;
}
/* read the FAT sectors */
if(fat_read(This, &boot0, dev.fat_bits, tot_sectors, dev.use_2m&0x7f)){
This->num_fat = 1;
FREE(&This->Next);
Free(This->Next);
return NULL;
}
return (Stream_t *) This;
}
char *getDrive(Stream_t *Stream)
{
DeclareThis(Fs_t);
if(This->Class != &FsClass)
return getDrive(GetFs(Stream));
else
return This->drive;
}
int fsPreallocateClusters(Fs_t *Fs, long size)
{
if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1)
return -1;
Fs->preallocatedClusters += size;
return 0;
}

View file

@ -1,84 +0,0 @@
#include "sysincludes.h"
#include "stream.h"
#include "fsP.h"
#include "llong.h"
#include "mtools.h"
/* Warnings about integer overflow in expression can be ignored. These are
* due to the way that maximal values for those integers are computed:
* intentional overflow from smallest negative number (1000...) to highest
* positive number (0111...) by substraction of 1 */
#ifdef __GNUC__
/*
#warning "The following warnings about integer overflow in expression can be safely ignored"
*/
#endif
#if 1
const mt_off_t max_off_t_31 = MAX_OFF_T_B(31); /* Floppyd */
const mt_off_t max_off_t_41 = MAX_OFF_T_B(41); /* SCSI */
const mt_off_t max_off_t_seek = MAX_OFF_T_B(SEEK_BITS); /* SCSI */
#else
const mt_off_t max_off_t_31 = MAX_OFF_T_B(10); /* Floppyd */
const mt_off_t max_off_t_41 = MAX_OFF_T_B(10); /* SCSI */
const mt_off_t max_off_t_seek = MAX_OFF_T_B(10); /* SCSI */
#endif
off_t truncBytes32(mt_off_t off)
{
if (off & ~max_off_t_31) {
fprintf(stderr, "Internal error, offset too big\n");
exit(1);
}
return (off_t) off;
}
mt_off_t sectorsToBytes(Stream_t *Stream, off_t off)
{
DeclareThis(Fs_t);
return (mt_off_t) off << This->sectorShift;
}
#if defined HAVE_LLSEEK
# ifndef HAVE_LLSEEK_PROTOTYPE
extern long long llseek (int fd, long long offset, int origin);
# endif
#endif
#if defined HAVE_LSEEK64
# ifndef HAVE_LSEEK64_PROTOTYPE
extern long long lseek64 (int fd, long long offset, int origin);
# endif
#endif
int mt_lseek(int fd, mt_off_t where, int whence)
{
#if defined HAVE_LSEEK64
if(lseek64(fd, where, whence) >= 0)
return 0;
else
return -1;
#elif defined HAVE_LLSEEK
if(llseek(fd, where, whence) >= 0)
return 0;
else
return -1;
#else
if (lseek(fd, (off_t) where, whence) >= 0)
return 0;
else
return 1;
#endif
}
int log_2(int size)
{
int i;
for(i=0; i<24; i++) {
if(1 << i == size)
return i;
}
return 24;
}

View file

@ -1,81 +0,0 @@
#ifndef MTOOLS_LLONG_H
#define MTOOLS_LLONG_H
#if 1
#ifdef HAVE_OFF_T_64
/* if off_t is already 64 bits, be happy, and don't worry about the
* loff_t and llseek stuff */
#define MT_OFF_T off_t
#endif
#ifndef MT_OFF_T
# ifdef HAVE_LLSEEK
/* we have llseek. Now, what's its type called? loff_t or offset_t ? */
# ifdef HAVE_LOFF_T
# define MT_OFF_T loff_t
# else
# ifdef HAVE_OFFSET_T
# define MT_OFF_T offset_t
# endif
# endif
# endif
#endif
#ifndef MT_OFF_T
/* we still don't have a suitable mt_off_t type...*/
# ifdef HAVE_LONG_LONG
/* ... first try long long ... */
# define MT_OFF_T long long
# else
/* ... and if that fails, fall back on good ole' off_t */
# define MT_OFF_T off_t
# endif
#endif
typedef MT_OFF_T mt_off_t;
#else
/* testing: meant to flag dubious assignments between 32 bit length types
* and 64 bit ones */
typedef struct {
int lo;
int high;
} *mt_off_t;
#endif
typedef mt_off_t mt_size_t;
#define min(a,b) ((a) < (b) ? (a) : (b))
#define MAX_OFF_T_B(bits) \
(((mt_off_t) 1 << min(bits, sizeof(mt_off_t)*8 - 1)) - 1)
#ifdef HAVE_LLSEEK
# define SEEK_BITS 63
#else
# define SEEK_BITS (sizeof(off_t) * 8 - 1)
#endif
extern const mt_off_t max_off_t_31;
extern const mt_off_t max_off_t_41;
extern const mt_off_t max_off_t_seek;
extern off_t truncBytes32(mt_off_t off);
mt_off_t sectorsToBytes(Stream_t *This, off_t off);
mt_size_t getfree(Stream_t *Stream);
int getfreeMinBytes(Stream_t *Stream, mt_size_t ref);
Stream_t *find_device(char *drive, int mode, struct device *out_dev,
struct bootsector *boot,
char *name, int *media, mt_size_t *maxSize);
int mt_lseek(int fd, mt_off_t where, int whence);
int log_2(int);
#endif

View file

@ -1,557 +0,0 @@
/*
* mainloop.c
* Iterating over all the command line parameters, and matching patterns
* where needed
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "fs.h"
#include "mainloop.h"
#include "plain_io.h"
#include "file.h"
int unix_dir_loop(Stream_t *Stream, MainParam_t *mp);
int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg,
int follow_dir_link);
static int _unix_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
{
unix_dir_loop(Dir, mp);
return GOT_ONE;
}
int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link)
{
int ret;
int isdir;
mp->File = NULL;
mp->direntry = NULL;
mp->unixSourceName = arg;
/* mp->dir.attr = ATTR_ARCHIVE;*/
mp->loop = _unix_loop;
if((mp->lookupflags & DO_OPEN)){
mp->File = SimpleFileOpen(0, 0, arg, O_RDONLY, 0, 0, 0, 0);
if(!mp->File){
perror(arg);
#if 0
tmp = _basename(arg);
strncpy(mp->filename, tmp, VBUFSIZE);
mp->filename[VBUFSIZE-1] = '\0';
#endif
return ERROR_ONE;
}
GET_DATA(mp->File, 0, 0, &isdir, 0);
if(isdir) {
struct stat buf;
FREE(&mp->File);
#ifdef S_ISLNK
if(!follow_dir_link &&
lstat(arg, &buf) == 0 &&
S_ISLNK(buf.st_mode)) {
/* skip links to directories in order to avoid
* infinite loops */
fprintf(stderr,
"skipping directory symlink %s\n",
arg);
return 0;
}
#endif
if(! (mp->lookupflags & ACCEPT_DIR))
return 0;
mp->File = OpenDir(Stream, arg);
}
}
if(isdir)
ret = mp->dirCallback(0, mp);
else
ret = mp->unixcallback(mp);
FREE(&mp->File);
return ret;
}
int isSpecial(const char *name)
{
if(name[0] == '\0')
return 1;
if(!strcmp(name,"."))
return 1;
if(!strcmp(name,".."))
return 1;
return 0;
}
static int checkForDot(int lookupflags, const char *name)
{
return (lookupflags & NO_DOTS) && isSpecial(name);
}
typedef struct lookupState_t {
Stream_t *container;
int nbContainers;
Stream_t *Dir;
int nbDirs;
const char *filename;
} lookupState_t;
static int isUniqueTarget(const char *name)
{
return name && strcmp(name, "-");
}
static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
lookupState_t *lookupState)
{
Stream_t *MyFile=0;
int ret;
if(got_signal)
return ERROR_ONE;
if(lookupState) {
/* we are looking for a "target" file */
switch(lookupState->nbDirs) {
case 0: /* no directory yet, open it */
lookupState->Dir = OpenFileByDirentry(direntry);
lookupState->nbDirs++;
/* dump the container, we have
* better now */
FREE(&lookupState->container);
return 0;
case 1: /* we have already a directory */
FREE(&lookupState->Dir);
fprintf(stderr,"Ambigous\n");
return STOP_NOW | ERROR_ONE;
default:
return STOP_NOW | ERROR_ONE;
}
}
mp->direntry = direntry;
if(IS_DIR(direntry)) {
if(mp->lookupflags & (DO_OPEN | DO_OPEN_DIRS))
MyFile = mp->File = OpenFileByDirentry(direntry);
ret = mp->dirCallback(direntry, mp);
} else {
if(mp->lookupflags & DO_OPEN)
MyFile = mp->File = OpenFileByDirentry(direntry);
ret = mp->callback(direntry, mp);
}
FREE(&MyFile);
if(isUniqueTarget(mp->targetName))
ret |= STOP_NOW;
return ret;
}
static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
{
Stream_t *MyFile=0;
direntry_t entry;
int ret;
int r;
ret = 0;
r=0;
initializeDirentry(&entry, Dir);
while(!got_signal &&
(r=vfat_lookup(&entry, filename, -1,
mp->lookupflags, mp->shortname,
mp->longname)) == 0 ){
mp->File = NULL;
if(!checkForDot(mp->lookupflags,entry.name)) {
MyFile = 0;
if((mp->lookupflags & DO_OPEN) ||
(IS_DIR(&entry) &&
(mp->lookupflags & DO_OPEN_DIRS))) {
MyFile = mp->File = OpenFileByDirentry(&entry);
}
if(got_signal)
break;
mp->direntry = &entry;
if(IS_DIR(&entry))
ret |= mp->dirCallback(&entry,mp);
else
ret |= mp->callback(&entry, mp);
FREE(&MyFile);
}
if (fat_error(Dir))
ret |= ERROR_ONE;
if(mp->fast_quit && (ret & ERROR_ONE))
break;
}
if (r == -2)
return ERROR_ONE;
if(got_signal)
ret |= ERROR_ONE;
return ret;
}
static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
const char *filename1,
lookupState_t *lookupState)
{
/* Dir is de-allocated by the same entity which allocated it */
const char *ptr;
direntry_t entry;
int length;
int lookupflags;
int ret;
int have_one;
int doing_mcwd;
int r;
while(1) {
/* strip dots and // */
if(!strncmp(filename0,"./", 2)) {
filename0 += 2;
continue;
}
if(!strcmp(filename0,".") && filename1) {
filename0 ++;
continue;
}
if(filename0[0] == '/') {
filename0++;
continue;
}
if(!filename0[0]) {
if(!filename1)
break;
filename0 = filename1;
filename1 = 0;
continue;
}
break;
}
if(!strncmp(filename0,"../", 3) ||
(!strcmp(filename0, "..") && filename1)) {
/* up one level */
mp->File = getDirentry(mp->File)->Dir;
return recurs_dos_loop(mp, filename0+2, filename1, lookupState);
}
doing_mcwd = !!filename1;
ptr = strchr(filename0, '/');
if(!ptr) {
length = strlen(filename0);
ptr = filename1;
filename1 = 0;
} else {
length = ptr - filename0;
ptr++;
}
if(!ptr) {
if(mp->lookupflags & OPEN_PARENT) {
mp->targetName = filename0;
ret = handle_leaf(getDirentry(mp->File), mp,
lookupState);
mp->targetName = 0;
return ret;
}
if(!strcmp(filename0, ".") || !filename0[0]) {
return handle_leaf(getDirentry(mp->File),
mp, lookupState);
}
if(!strcmp(filename0, "..")) {
return handle_leaf(getParent(getDirentry(mp->File)), mp,
lookupState);
}
lookupflags = mp->lookupflags;
if(lookupState) {
lookupState->filename = filename0;
if(lookupState->nbContainers + lookupState->nbDirs > 0){
/* we have already one target, don't bother
* with this one. */
FREE(&lookupState->container);
} else {
/* no match yet. Remember this container for
* later use */
lookupState->container = COPY(mp->File);
}
lookupState->nbContainers++;
}
} else
lookupflags = ACCEPT_DIR | DO_OPEN | NO_DOTS;
ret = 0;
r = 0;
have_one = 0;
initializeDirentry(&entry, mp->File);
while(!(ret & STOP_NOW) &&
!got_signal &&
(r=vfat_lookup(&entry, filename0, length,
lookupflags | NO_MSG,
mp->shortname, mp->longname)) == 0 ){
if(checkForDot(lookupflags, entry.name))
/* while following the path, ignore the
* special entries if they were not
* explicitly given */
continue;
have_one = 1;
if(ptr) {
Stream_t *SubDir;
SubDir = mp->File = OpenFileByDirentry(&entry);
ret |= recurs_dos_loop(mp, ptr, filename1, lookupState);
FREE(&SubDir);
} else {
ret |= handle_leaf(&entry, mp, lookupState);
if(isUniqueTarget(mp->targetName))
return ret | STOP_NOW;
}
if(doing_mcwd)
break;
}
if (r == -2)
return ERROR_ONE;
if(got_signal)
return ret | ERROR_ONE;
if(doing_mcwd & !have_one)
return NO_CWD;
return ret;
}
static int common_dos_loop(MainParam_t *mp, const char *pathname,
lookupState_t *lookupState, int open_mode)
{
Stream_t *RootDir;
char *cwd;
char *drive;
char *rest;
int ret;
mp->loop = _dos_loop;
drive='\0';
cwd = "";
if((rest = skip_drive(pathname)) > pathname) {
drive = get_drive(pathname, NULL);
if (strncmp(pathname, mp->mcwd, rest - pathname) == 0)
cwd = skip_drive(mp->mcwd);
pathname = rest;
} else {
drive = get_drive(mp->mcwd, NULL);
cwd = skip_drive(mp->mcwd);
}
if(*pathname=='/') /* absolute path name */
cwd = "";
RootDir = mp->File = open_root_dir(drive, open_mode);
if(!mp->File)
return ERROR_ONE;
ret = recurs_dos_loop(mp, cwd, pathname, lookupState);
if(ret & NO_CWD) {
/* no CWD */
*mp->mcwd = '\0';
unlink_mcwd();
ret = recurs_dos_loop(mp, "", pathname, lookupState);
}
FREE(&RootDir);
return ret;
}
static int dos_loop(MainParam_t *mp, const char *arg)
{
return common_dos_loop(mp, arg, 0, mp->openflags);
}
static int dos_target_lookup(MainParam_t *mp, const char *arg)
{
lookupState_t lookupState;
int ret;
int lookupflags;
lookupState.nbDirs = 0;
lookupState.Dir = 0;
lookupState.nbContainers = 0;
lookupState.container = 0;
lookupflags = mp->lookupflags;
mp->lookupflags = DO_OPEN | ACCEPT_DIR;
ret = common_dos_loop(mp, arg, &lookupState, O_RDWR);
mp->lookupflags = lookupflags;
if(ret & ERROR_ONE)
return ret;
if(lookupState.nbDirs) {
mp->targetName = 0;
mp->targetDir = lookupState.Dir;
FREE(&lookupState.container); /* container no longer needed */
return ret;
}
switch(lookupState.nbContainers) {
case 0:
/* no match */
fprintf(stderr,"%s: no match for target\n", arg);
return MISSED_ONE;
case 1:
mp->targetName = strdup(lookupState.filename);
mp->targetDir = lookupState.container;
return ret;
default:
/* too much */
fprintf(stderr, "Ambigous %s\n", arg);
return ERROR_ONE;
}
}
int unix_target_lookup(MainParam_t *mp, const char *arg)
{
char *ptr;
mp->unixTarget = strdup(arg);
/* try complete filename */
if(access(mp->unixTarget, F_OK) == 0)
return GOT_ONE;
ptr = strrchr(mp->unixTarget, '/');
if(!ptr) {
mp->targetName = mp->unixTarget;
mp->unixTarget = strdup(".");
return GOT_ONE;
} else {
*ptr = '\0';
mp->targetName = ptr+1;
return GOT_ONE;
}
}
int target_lookup(MainParam_t *mp, const char *arg)
{
if((mp->lookupflags & NO_UNIX) || skip_drive(arg) > arg)
return dos_target_lookup(mp, arg);
else
return unix_target_lookup(mp, arg);
}
int main_loop(MainParam_t *mp, char **argv, int argc)
{
int i;
int ret, Bret;
Bret = 0;
if(argc != 1 && mp->targetName) {
fprintf(stderr,
"Several file names given, but last argument (%s) not a directory\n", mp->targetName);
}
for (i = 0; i < argc; i++) {
if ( got_signal )
break;
mp->originalArg = argv[i];
mp->basenameHasWildcard = strpbrk(_basename(mp->originalArg),
"*[?") != 0;
if (mp->unixcallback && skip_drive(argv[i]) == argv[i])
ret = unix_loop(0, mp, argv[i], 1);
else
ret = dos_loop(mp, argv[i]);
if (! (ret & (GOT_ONE | ERROR_ONE)) ) {
/* one argument was unmatched */
fprintf(stderr, "%s: File \"%s\" not found\n",
progname, argv[i]);
ret |= ERROR_ONE;
}
Bret |= ret;
if(mp->fast_quit && (Bret & (MISSED_ONE | ERROR_ONE)))
break;
}
FREE(&mp->targetDir);
if(Bret & ERROR_ONE)
return 1;
if ((Bret & GOT_ONE) && ( Bret & MISSED_ONE))
return 2;
if (Bret & MISSED_ONE)
return 1;
return 0;
}
static int dispatchToFile(direntry_t *entry, MainParam_t *mp)
{
if(entry)
return mp->callback(entry, mp);
else
return mp->unixcallback(mp);
}
void init_mp(MainParam_t *mp)
{
fix_mcwd(mp->mcwd);
mp->openflags = 0;
mp->targetName = 0;
mp->targetDir = 0;
mp->unixTarget = 0;
mp->dirCallback = dispatchToFile;
mp->unixcallback = NULL;
mp->shortname = mp->longname = 0;
mp->File = 0;
mp->fast_quit = 0;
}
const char *mpGetBasename(MainParam_t *mp)
{
if(mp->direntry)
return mp->direntry->name;
else
return _basename(mp->unixSourceName);
}
void mpPrintFilename(FILE *fp, MainParam_t *mp)
{
if(mp->direntry)
fprintPwd(fp, mp->direntry, 0);
else
fprintf(fp,"%s",mp->originalArg);
}
const char *mpPickTargetName(MainParam_t *mp)
{
/* picks the target name: either the one explicitly given by the
* user, or the same as the source */
if(mp->targetName)
return mp->targetName;
else
return mpGetBasename(mp);
}
char *mpBuildUnixFilename(MainParam_t *mp)
{
const char *target;
char *ret;
target = mpPickTargetName(mp);
ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target));
if(!ret)
return 0;
strcpy(ret, mp->unixTarget);
if(*target) {
#if 1 /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */
if(!mp->targetName && !mp->targetDir) {
struct stat buf;
if (!stat(ret, &buf) && !S_ISDIR(buf.st_mode))
return ret;
}
#endif
strcat(ret, "/");
strcat(ret, target);
}
return ret;
}

View file

@ -1,79 +0,0 @@
#ifndef MTOOLS_MAINLOOP_H
#define MTOOLS_MAINLOOP_H
#ifndef OS_Minix
#include <sys/param.h>
#endif
#include "vfat.h"
#include "mtoolsDirent.h"
typedef struct MainParam_t {
/* stuff needing to be initialised by the caller */
int (*loop)(Stream_t *Dir, struct MainParam_t *mp,
const char *filename);
int (*dirCallback)(direntry_t *, struct MainParam_t *);
int (*callback)(direntry_t *, struct MainParam_t *);
int (*unixcallback)(struct MainParam_t *mp);
void *arg; /* command-specific parameters
* to be passed to callback */
int openflags; /* flags used to open disk */
int lookupflags; /* flags used to lookup up using vfat_lookup */
int fast_quit; /* for commands manipulating multiple files, quit
* as soon as even _one_ file has a problem */
char *shortname; /* where to put the short name of the matched file */
char *longname; /* where to put the long name of the matched file */
/* out parameters */
Stream_t *File;
direntry_t *direntry; /* dir of this entry */
char *unixSourceName; /* filename of the last opened Unix source
* file (Unix equiv of Dos direntry) */
Stream_t *targetDir; /* directory where to place files */
char *unixTarget; /* directory on Unix where to put files */
const char *targetName; /* basename of target file, or NULL if same
* basename as source should be conserved */
char *originalArg; /* original argument, complete with wildcards */
int basenameHasWildcard; /* true if there are wildcards in the
* basename */
/* internal data */
char mcwd[MAX_PATH+4];
char *fileName; /* resolved Unix filename */
} MainParam_t;
void init_mp(MainParam_t *MainParam);
int main_loop(MainParam_t *MainParam, char **argv, int argc);
int target_lookup(MainParam_t *mp, const char *arg);
Stream_t *open_root_dir(char *drivename, int flags);
const char *mpGetBasename(MainParam_t *mp); /* statically allocated
* string */
void mpPrintFilename(FILE *file, MainParam_t *mp);
const char *mpPickTargetName(MainParam_t *mp); /* statically allocated string */
char *mpBuildUnixFilename(MainParam_t *mp); /* dynamically allocated, must
* be freed */
int isSpecial(const char *name);
#define MISSED_ONE 2 /* set if one cmd line argument didn't match any files */
#define GOT_ONE 4 /* set if a match was found, used for exit status */
#define NO_CWD 8 /* file not found while looking for current working
* directory */
#define ERROR_ONE 16 /* flat out error, such as problems with target file,
interrupt by user, etc. */
#define STOP_NOW 32 /* stop as soon as possible, not necessarily an error */
#endif

View file

@ -1,142 +0,0 @@
/*
* Do shell-style pattern matching for '?', '\', '[..]', and '*' wildcards.
* Returns 1 if match, 0 if not.
*/
#include "sysincludes.h"
#include "mtools.h"
static int casecmp(char a,char b)
{
return toupper(a) == toupper(b);
}
static int exactcmp(char a,char b)
{
return a == b;
}
static int parse_range(const char **p, const char *s, char *out,
int (*compfn)(char a, char b))
{
char table[256];
int reverse;
int i;
short first, last;
if (**p == '^') {
reverse = 1;
(*p)++;
} else
reverse=0;
for(i=0; i<256; i++)
table[i]=0;
while(**p != ']') {
if(!**p)
return 0;
if((*p)[1] == '-') {
first = **p;
(*p)+=2;
if(**p == ']')
last = 256;
else
last = *((*p)++);
for(i=first; i<last; i++)
table[i] = 1;
} else
table[(int) *((*p)++)] = 1;
}
if(out)
*out = *s;
if(table[(int) *s])
return 1 ^ reverse;
if(compfn == exactcmp)
return reverse;
if(table[tolower(*s)]) {
if(out)
*out = tolower(*s);
return 1 ^ reverse;
}
if(table[toupper(*s)]) {
if(out)
*out = toupper(*s);
return 1 ^ reverse;
}
return reverse;
}
static int _match(const char *s, const char *p, char *out, int Case,
int length,
int (*compfn) (char a, char b))
{
for (; *p != '\0' && length; ) {
switch (*p) {
case '?': /* match any one character */
if (*s == '\0')
return(0);
if(out)
*(out++) = *s;
break;
case '*': /* match everything */
while (*p == '*' && length) {
p++;
length--;
}
/* search for next char in pattern */
while(*s) {
if(_match(s, p, out, Case, length,
compfn))
return 1;
if(out)
*out++ = *s;
s++;
}
continue;
case '[': /* match range of characters */
p++;
length--;
if(!parse_range(&p, s, out++, compfn))
return 0;
break;
case '\\': /* Literal match with next character */
p++;
length--;
/* fall thru */
default:
if (!compfn(*s,*p))
return(0);
if(out)
*(out++) = *p;
break;
}
p++;
length--;
s++;
}
if(out)
*out = '\0';
/* string ended prematurely ? */
if (*s != '\0')
return(0);
else
return(1);
}
int match(const char *s, const char *p, char *out, int Case, int length)
{
int (*compfn)(char a, char b);
if(Case)
compfn = casecmp;
else
/*compfn = exactcmp;*/
compfn = casecmp;
return _match(s, p, out, Case, length, compfn);
}

View file

@ -1,233 +0,0 @@
/*
* mattrib.c
* Change MSDOS file attribute flags
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "mainloop.h"
typedef struct Arg_t {
char add;
unsigned char remove;
struct MainParam_t mp;
int recursive;
int doPrintName;
} Arg_t;
int concise;
static int attrib_file(direntry_t *entry, MainParam_t *mp)
{
Arg_t *arg=(Arg_t *) mp->arg;
if(entry->entry != -3) {
/* if not root directory, change it */
entry->dir.attr = (entry->dir.attr & arg->remove) | arg->add;
dir_write(entry);
}
return GOT_ONE;
}
static int replay_attrib(direntry_t *entry, MainParam_t *mp)
{
if ( (IS_ARCHIVE(entry) && IS_DIR(entry)) ||
(!IS_ARCHIVE(entry) && !IS_DIR(entry)) ||
IS_SYSTEM(entry) || IS_HIDDEN(entry)) {
printf("mattrib ");
if (IS_ARCHIVE(entry) && IS_DIR(entry)) {
printf("+a ");
}
if (!IS_ARCHIVE(entry) && !IS_DIR(entry)) {
printf("-a ");
}
if (IS_SYSTEM(entry)) {
printf("+s ");
}
if (IS_HIDDEN(entry)) {
printf("+h ");
}
fprintPwd(stdout, entry, 1);
printf("\n");
}
return GOT_ONE;
}
static int view_attrib(direntry_t *entry, MainParam_t *mp)
{
printf(" ");
if(IS_ARCHIVE(entry))
putchar('A');
else
putchar(' ');
fputs(" ",stdout);
if(IS_SYSTEM(entry))
putchar('S');
else
putchar(' ');
if(IS_HIDDEN(entry))
putchar('H');
else
putchar(' ');
if(IS_READONLY(entry))
putchar('R');
else
putchar(' ');
printf(" ");
fprintPwd(stdout, entry, 0);
printf("\n");
return GOT_ONE;
}
static int concise_view_attrib(direntry_t *entry, MainParam_t *mp)
{
Arg_t *arg=(Arg_t *) mp->arg;
if(IS_ARCHIVE(entry))
putchar('A');
if(IS_DIR(entry))
putchar('D');
if(IS_SYSTEM(entry))
putchar('S');
if(IS_HIDDEN(entry))
putchar('H');
if(IS_READONLY(entry))
putchar('R');
if(arg->doPrintName) {
putchar(' ');
fprintPwd(stdout, entry, 0);
}
putchar('\n');
return GOT_ONE;
}
static int recursive_attrib(direntry_t *entry, MainParam_t *mp)
{
mp->callback(entry, mp);
return mp->loop(mp->File, mp, "*");
}
static void usage(void) NORETURN;
static void usage(void)
{
fprintf(stderr, "Mtools version %s, dated %s\n",
mversion, mdate);
fprintf(stderr,
"Usage: %s [-p/X] [-a|+a] [-h|+h] [-r|+r] [-s|+s] msdosfile [msdosfiles...]\n"
"\t-p Replay how mattrib would set up attributes\n"
"\t-/ Recursive\n"
"\t-X Concise\n",
progname);
exit(1);
}
static int letterToCode(int letter)
{
switch (toupper(letter)) {
case 'A':
return ATTR_ARCHIVE;
case 'H':
return ATTR_HIDDEN;
case 'R':
return ATTR_READONLY;
case 'S':
return ATTR_SYSTEM;
default:
usage();
}
}
void mattrib(int argc, char **argv, int type)
{
Arg_t arg;
int view;
int c;
int concise;
int replay;
char *ptr;
arg.add = 0;
arg.remove = 0xff;
arg.recursive = 0;
arg.doPrintName = 1;
view = 0;
concise = 0;
replay = 0;
while ((c = getopt(argc, argv, "/ahrsAHRSXp")) != EOF) {
switch (c) {
default:
arg.remove &= ~letterToCode(c);
break;
case 'p':
replay = 1;
break;
case '/':
arg.recursive = 1;
break;
case 'X':
concise = 1;
break;
case '?':
usage();
}
}
for(;optind < argc;optind++) {
switch(argv[optind][0]) {
case '+':
for(ptr = argv[optind] + 1; *ptr; ptr++)
arg.add |= letterToCode(*ptr);
continue;
case '-':
for(ptr = argv[optind] + 1; *ptr; ptr++)
arg.remove &= ~letterToCode(*ptr);
continue;
}
break;
}
if(arg.remove == 0xff && !arg.add)
view = 1;
if (optind >= argc)
usage();
init_mp(&arg.mp);
if(view){
if(concise) {
arg.mp.callback = concise_view_attrib;
arg.doPrintName = (argc - optind > 1 ||
arg.recursive ||
strpbrk(argv[optind], "*[?") != 0);
} else if (replay) {
arg.mp.callback = replay_attrib;
} else
arg.mp.callback = view_attrib;
arg.mp.openflags = O_RDONLY;
} else {
arg.mp.callback = attrib_file;
arg.mp.openflags = O_RDWR;
}
if(arg.recursive)
arg.mp.dirCallback = recursive_attrib;
arg.mp.arg = (void *) &arg;
arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR;
if(arg.recursive)
arg.mp.lookupflags |= DO_OPEN_DIRS | NO_DOTS;
exit(main_loop(&arg.mp, argv + optind, argc - optind));
}

View file

@ -1,77 +0,0 @@
/*
* mbadblocks.c
* Mark bad blocks on disk
*
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "mainloop.h"
#include "fsP.h"
void mbadblocks(int argc, char **argv, int type)
{
int i;
char *in_buf;
int in_len;
off_t start;
struct MainParam_t mp;
Fs_t *Fs;
Stream_t *Dir;
int ret;
if (argc != 2 || skip_drive(argv[1]) == argv[1]) {
fprintf(stderr, "Mtools version %s, dated %s\n",
mversion, mdate);
fprintf(stderr, "Usage: %s drive:\n", argv[0]);
exit(1);
}
init_mp(&mp);
Dir = open_root_dir(get_drive(argv[1], NULL), O_RDWR);
if (!Dir) {
fprintf(stderr,"%s: Cannot initialize drive\n", argv[0]);
exit(1);
}
Fs = (Fs_t *)GetFs(Dir);
in_len = Fs->cluster_size * Fs->sector_size;
in_buf = malloc(in_len);
if(!in_buf) {
FREE(&Dir);
printOom();
exit(1);
}
for(i=0; i < Fs->clus_start; i++ ){
ret = READS(Fs->Next,
in_buf, sectorsToBytes((Stream_t*)Fs, i), Fs->sector_size);
if( ret < 0 ){
perror("early error");
exit(1);
}
if(ret < Fs->sector_size){
fprintf(stderr,"end of file in file_read\n");
exit(1);
}
}
in_len = Fs->cluster_size * Fs->sector_size;
for(i=2; i< Fs->num_clus + 2; i++){
if(got_signal)
break;
if(Fs->fat_decode((Fs_t*)Fs,i))
continue;
start = (i - 2) * Fs->cluster_size + Fs->clus_start;
ret = force_read(Fs->Next, in_buf,
sectorsToBytes((Stream_t*)Fs, start), in_len);
if(ret < in_len ){
printf("Bad cluster %d found\n", i);
fatEncode((Fs_t*)Fs, i, 0xfff7);
continue;
}
}
FREE(&Dir);
exit(0);
}

View file

@ -1,129 +0,0 @@
/*
* mcat.c
* Same thing as cat /dev/fd0 or cat file >/dev/fd0
* Something, that isn't possible with floppyd anymore.
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "mainloop.h"
#include "fsP.h"
#include "xdf_io.h"
#include "floppyd_io.h"
#include "plain_io.h"
void usage(void)
{
fprintf(stderr, "Mtools version %s, dated %s\n",
mversion, mdate);
fprintf(stderr, "Usage: mcat [-w] device\n");
fprintf(stderr, " -w write on device else read\n");
exit(1);
}
#define BUF_SIZE 16000
void mcat(int argc, char **argv, int type)
{
struct device *dev;
struct device out_dev;
char *drive, name[EXPAND_BUF];
char errmsg[200];
Stream_t *Stream;
char buf[BUF_SIZE];
mt_off_t address = 0;
char mode = O_RDONLY;
int optindex = 1;
size_t len;
noPrivileges = 1;
if (argc < 2) {
usage();
}
if (argv[1][0] == '-') {
if (argv[1][1] != 'w') {
usage();
}
mode = O_WRONLY;
optindex++;
}
if (argc - optindex < 1)
usage();
if (skip_drive(argv[optindex]) == argv[optindex])
usage();
drive = get_drive(argv[optindex], NULL);
/* check out a drive whose letter and parameters match */
sprintf(errmsg, "Drive '%s:' not supported", drive);
Stream = NULL;
for (dev=devices; dev->name; dev++) {
FREE(&Stream);
if (strcmp(dev->drive, drive) != 0)
continue;
out_dev = *dev;
expand(dev->name,name);
#ifdef USING_NEW_VOLD
strcpy(name, getVoldName(dev, name));
#endif
Stream = 0;
#ifdef USE_XDF
Stream = XdfOpen(&out_dev, name, mode, errmsg, 0);
if(Stream)
out_dev.use_2m = 0x7f;
#endif
#ifdef USE_FLOPPYD
if(!Stream)
Stream = FloppydOpen(&out_dev, dev, name,
mode, errmsg, 0, 1);
#endif
if (!Stream)
Stream = SimpleFileOpen(&out_dev, dev, name, mode,
errmsg, 0, 1, 0);
if( !Stream)
continue;
break;
}
/* print error msg if needed */
if ( dev->drive == 0 ){
FREE(&Stream);
fprintf(stderr,"%s\n",errmsg);
exit(1);
}
if (mode == O_WRONLY) {
while ((len = fread(buf, 1, BUF_SIZE, stdin))
== BUF_SIZE) {
WRITES(Stream, buf, address, BUF_SIZE);
address += BUF_SIZE;
}
if (len)
WRITES(Stream, buf, address, len);
} else {
while ((len = READS(Stream, buf, address, BUF_SIZE))
== BUF_SIZE) {
fwrite(buf, 1, BUF_SIZE, stdout);
address += BUF_SIZE;
}
if (len)
fwrite(buf, 1, len, stdout);
}
FREE(&Stream);
exit(0);
}

View file

@ -1,46 +0,0 @@
/*
* mcd.c: Change MSDOS directories
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mainloop.h"
#include "mtools.h"
static int mcd_callback(direntry_t *entry, MainParam_t *mp)
{
FILE *fp;
if (!(fp = open_mcwd("w"))){
fprintf(stderr,"mcd: Can't open mcwd .file for writing\n");
return ERROR_ONE;
}
fprintPwd(fp, entry,0);
fprintf(fp, "\n");
fclose(fp);
return GOT_ONE | STOP_NOW;
}
void mcd(int argc, char **argv, int type)
{
struct MainParam_t mp;
if (argc > 2) {
fprintf(stderr, "Mtools version %s, dated %s\n",
mversion, mdate);
fprintf(stderr, "Usage: %s: msdosdirectory\n", argv[0]);
exit(1);
}
init_mp(&mp);
mp.lookupflags = ACCEPT_DIR | NO_DOTS;
mp.dirCallback = mcd_callback;
if (argc == 1) {
printf("%s\n", mp.mcwd);
exit(0);
} else
exit(main_loop(&mp, argv + 1, 1));
}

View file

@ -1,584 +0,0 @@
/*
* mcopy.c
* Copy an MSDOS files to and from Unix
*
*/
#define LOWERCASE
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "mainloop.h"
#include "plain_io.h"
#include "nameclash.h"
#include "file.h"
#include "fs.h"
/*
* Preserve the file modification times after the fclose()
*/
static void set_mtime(const char *target, time_t mtime)
{
if (target && strcmp(target, "-") && mtime != 0L) {
#ifdef HAVE_UTIMES
struct timeval tv[2];
tv[0].tv_sec = mtime;
tv[0].tv_usec = 0;
tv[1].tv_sec = mtime;
tv[1].tv_usec = 0;
utimes((char *)target, tv);
#else
#ifdef HAVE_UTIME
struct utimbuf utbuf;
utbuf.actime = mtime;
utbuf.modtime = mtime;
utime(target, &utbuf);
#endif
#endif
}
return;
}
typedef struct Arg_t {
int recursive;
int preserveAttributes;
int preserveTime;
unsigned char attr;
char *path;
int textmode;
int needfilter;
int nowarn;
int verbose;
int type;
MainParam_t mp;
ClashHandling_t ch;
} Arg_t;
/* Write the Unix file */
static int unix_write(direntry_t *entry, MainParam_t *mp, int needfilter)
{
Arg_t *arg=(Arg_t *) mp->arg;
time_t mtime;
Stream_t *File=mp->File;
Stream_t *Target, *Source;
struct stat stbuf;
int ret;
char errmsg[80];
char *unixFile;
File->Class->get_data(File, &mtime, 0, 0, 0);
if (!arg->preserveTime)
mtime = 0L;
if(arg->type)
unixFile = "-";
else
unixFile = mpBuildUnixFilename(mp);
if(!unixFile) {
printOom();
return ERROR_ONE;
}
/* if we are creating a file, check whether it already exists */
if(!arg->type) {
if (!arg->nowarn && &arg->type && !access(unixFile, 0)){
if( ask_confirmation("File \"%s\" exists, overwrite (y/n) ? ",
unixFile,0)) {
free(unixFile);
return ERROR_ONE;
}
/* sanity checking */
if (!stat(unixFile, &stbuf) && !S_ISREG(stbuf.st_mode)) {
fprintf(stderr,"\"%s\" is not a regular file\n",
unixFile);
free(unixFile);
return ERROR_ONE;
}
}
}
if(!arg->type && arg->verbose) {
fprintf(stderr,"Copying ");
mpPrintFilename(stderr,mp);
fprintf(stderr,"\n");
}
if(got_signal) {
free(unixFile);
return ERROR_ONE;
}
if ((Target = SimpleFileOpen(0, 0, unixFile,
O_WRONLY | O_CREAT | O_TRUNC,
errmsg, 0, 0, 0))) {
ret = 0;
if(needfilter && arg->textmode){
Source = open_filter(COPY(File));
if (!Source)
ret = -1;
} else
Source = COPY(File);
if (ret == 0 )
ret = copyfile(Source, Target);
FREE(&Source);
FREE(&Target);
if(ret <= -1){
if(!arg->type) {
unlink(unixFile);
free(unixFile);
}
return ERROR_ONE;
}
if(!arg->type) {
set_mtime(unixFile, mtime);
free(unixFile);
}
return GOT_ONE;
} else {
fprintf(stderr,"%s\n", errmsg);
if(!arg->type)
free(unixFile);
return ERROR_ONE;
}
}
static int makeUnixDir(char *filename)
{
if(!mkdir(filename, 0777))
return 0;
if(errno == EEXIST) {
struct stat buf;
if(stat(filename, &buf) < 0)
return -1;
if(S_ISDIR(buf.st_mode))
return 0;
errno = ENOTDIR;
}
return -1;
}
/* Copy a directory to Unix */
static int unix_copydir(direntry_t *entry, MainParam_t *mp)
{
Arg_t *arg=(Arg_t *) mp->arg;
time_t mtime;
Stream_t *File=mp->File;
int ret;
char *unixFile;
if (!arg->recursive && mp->basenameHasWildcard)
return 0;
File->Class->get_data(File, &mtime, 0, 0, 0);
if (!arg->preserveTime)
mtime = 0L;
if(!arg->type && arg->verbose) {
fprintf(stderr,"Copying ");
fprintPwd(stderr, entry,0);
fprintf(stderr, "\n");
}
if(got_signal)
return ERROR_ONE;
unixFile = mpBuildUnixFilename(mp);
if(!unixFile) {
printOom();
return ERROR_ONE;
}
if(arg->type || !*mpPickTargetName(mp) || !makeUnixDir(unixFile)) {
Arg_t newArg;
newArg = *arg;
newArg.mp.arg = (void *) &newArg;
newArg.mp.unixTarget = unixFile;
newArg.mp.targetName = 0;
newArg.mp.basenameHasWildcard = 1;
ret = mp->loop(File, &newArg.mp, "*");
set_mtime(unixFile, mtime);
free(unixFile);
return ret | GOT_ONE;
} else {
perror("mkdir");
fprintf(stderr,
"Failure to make directory %s\n",
unixFile);
free(unixFile);
return ERROR_ONE;
}
}
static int dos_to_unix(direntry_t *entry, MainParam_t *mp)
{
return unix_write(entry, mp, 1);
}
static int unix_to_unix(MainParam_t *mp)
{
return unix_write(0, mp, 0);
}
static int directory_dos_to_unix(direntry_t *entry, MainParam_t *mp)
{
return unix_copydir(entry, mp);
}
/*
* Open the named file for read, create the cluster chain, return the
* directory structure or NULL on error.
*/
static int writeit(char *dosname,
char *longname,
void *arg0,
direntry_t *entry)
{
Stream_t *Target;
time_t now;
int type, fat, ret;
time_t date;
mt_size_t filesize, newsize;
Arg_t *arg = (Arg_t *) arg0;
if (arg->mp.File->Class->get_data(arg->mp.File,
& date, &filesize, &type, 0) < 0 ){
fprintf(stderr, "Can't stat source file\n");
return -1;
}
if (type){
if (arg->verbose)
fprintf(stderr, "\"%s\" is a directory\n", longname);
return -1;
}
/*if (!arg->single || arg->recursive)*/
if(arg->verbose)
fprintf(stderr,"Copying %s\n", longname);
if(got_signal)
return -1;
/* will it fit? */
if (!getfreeMinBytes(arg->mp.targetDir, filesize))
return -1;
/* preserve mod time? */
if (arg->preserveTime)
now = date;
else
getTimeNow(&now);
mk_entry(dosname, arg->attr, 1, 0, now, &entry->dir);
Target = OpenFileByDirentry(entry);
if(!Target){
fprintf(stderr,"Could not open Target\n");
exit(1);
}
if (arg->needfilter & arg->textmode)
Target = open_filter(Target);
ret = copyfile(arg->mp.File, Target);
GET_DATA(Target, 0, &newsize, 0, &fat);
FREE(&Target);
if (arg->needfilter & arg->textmode)
newsize++; /* ugly hack: we gathered the size before the Ctrl-Z
* was written. Increment it manually */
if(ret < 0 ){
fat_free(arg->mp.targetDir, fat);
return -1;
} else {
mk_entry(dosname, arg->attr, fat, truncBytes32(newsize),
now, &entry->dir);
return 0;
}
}
static int dos_write(direntry_t *entry, MainParam_t *mp, int needfilter)
/* write a messy dos file to another messy dos file */
{
int result;
Arg_t * arg = (Arg_t *) (mp->arg);
const char *targetName = mpPickTargetName(mp);
if(entry && arg->preserveAttributes)
arg->attr = entry->dir.attr;
else
arg->attr = ATTR_ARCHIVE;
arg->needfilter = needfilter;
if (entry && mp->targetDir == entry->Dir){
arg->ch.ignore_entry = -1;
arg->ch.source = entry->entry;
} else {
arg->ch.ignore_entry = -1;
arg->ch.source = -2;
}
result = mwrite_one(mp->targetDir, targetName, 0,
writeit, (void *)arg, &arg->ch);
if(result == 1)
return GOT_ONE;
else
return ERROR_ONE;
}
static Stream_t *subDir(Stream_t *parent, const char *filename)
{
direntry_t entry;
initializeDirentry(&entry, parent);
switch(vfat_lookup(&entry, filename, -1, ACCEPT_DIR, 0, 0)) {
case 0:
return OpenFileByDirentry(&entry);
case -1:
return NULL;
default: /* IO Error */
return NULL;
}
}
static int dos_copydir(direntry_t *entry, MainParam_t *mp)
/* copyes a directory to Dos */
{
Arg_t * arg = (Arg_t *) (mp->arg);
Arg_t newArg;
time_t now;
time_t date;
int ret;
const char *targetName = mpPickTargetName(mp);
if (!arg->recursive && mp->basenameHasWildcard)
return 0;
if(entry && isSubdirOf(mp->targetDir, mp->File)) {
fprintf(stderr, "Cannot recursively copy directory ");
fprintPwd(stderr, entry,0);
fprintf(stderr, " into one of its own subdirectories ");
fprintPwd(stderr, getDirentry(mp->targetDir),0);
fprintf(stderr, "\n");
return ERROR_ONE;
}
if (arg->mp.File->Class->get_data(arg->mp.File,
& date, 0, 0, 0) < 0 ){
fprintf(stderr, "Can't stat source file\n");
return ERROR_ONE;
}
if(!arg->type && arg->verbose)
fprintf(stderr,"Copying %s\n", mpGetBasename(mp));
if(entry && arg->preserveAttributes)
arg->attr = entry->dir.attr;
else
arg->attr = 0;
if (entry && (mp->targetDir == entry->Dir)){
arg->ch.ignore_entry = -1;
arg->ch.source = entry->entry;
} else {
arg->ch.ignore_entry = -1;
arg->ch.source = -2;
}
/* preserve mod time? */
if (arg->preserveTime)
now = date;
else
getTimeNow(&now);
newArg = *arg;
newArg.mp.arg = &newArg;
newArg.mp.targetName = 0;
newArg.mp.basenameHasWildcard = 1;
if(*targetName) {
/* maybe the directory already exist. Use it */
newArg.mp.targetDir = subDir(mp->targetDir, targetName);
if(!newArg.mp.targetDir)
newArg.mp.targetDir = createDir(mp->targetDir,
targetName,
&arg->ch, arg->attr,
now);
} else
newArg.mp.targetDir = mp->targetDir;
if(!newArg.mp.targetDir)
return ERROR_ONE;
ret = mp->loop(mp->File, &newArg.mp, "*");
if(*targetName)
FREE(&newArg.mp.targetDir);
return ret | GOT_ONE;
}
static int dos_to_dos(direntry_t *entry, MainParam_t *mp)
{
return dos_write(entry, mp, 0);
}
static int unix_to_dos(MainParam_t *mp)
{
return dos_write(0, mp, 1);
}
static void usage(void)
{
fprintf(stderr,
"Mtools version %s, dated %s\n", mversion, mdate);
fprintf(stderr,
"Usage: %s [-/spabtnmvQB] [-D clash_option] sourcefile targetfile\n", progname);
fprintf(stderr,
" %s [-/spabtnmvQB] [-D clash_option] sourcefile [sourcefiles...] targetdirectory\n",
progname);
fprintf(stderr,
"\t-/ -s Recursive\n"
"\t-p Preserve attributes\n"
"\t-a -t Textmode\n"
"\t-n Overwrite UNIX files without confirmation\n"
"\t-m Preserve file time (default under Minix)\n"
"\t-v Verbose\n"
"\t-Q Quit on the first error\n"
"\t-b -B Batch mode (faster, but less crash resistent)\n"
"\t-o Overwrite DOS files without confirmation\n");
exit(1);
}
void mcopy(int argc, char **argv, int mtype)
{
Arg_t arg;
int c, ret, fastquit;
int todir;
/* get command line options */
init_clash_handling(& arg.ch);
/* get command line options */
todir = 0;
arg.recursive = 0;
#ifdef OS_Minix
arg.preserveTime = 1; /* Copy file time as DOS does. */
#else
arg.preserveTime = 0;
#endif
arg.preserveAttributes = 0;
arg.nowarn = 0;
arg.textmode = 0;
arg.verbose = 0;
arg.type = mtype;
fastquit = 0;
while ((c = getopt(argc, argv, "abB/sptnmvQD:o")) != EOF) {
switch (c) {
case 's':
case '/':
arg.recursive = 1;
break;
case 'p':
arg.preserveAttributes = 1;
break;
case 'a':
case 't':
arg.textmode = 1;
break;
case 'n':
arg.nowarn = 1;
break;
case 'm':
arg.preserveTime = 1;
break;
case 'v':
arg.verbose = 1;
break;
case 'Q':
fastquit = 1;
break;
case 'B':
case 'b':
batchmode = 1;
break;
case 'o':
handle_clash_options(&arg.ch, c);
break;
case 'D':
if(handle_clash_options(&arg.ch, *optarg))
usage();
break;
case '?':
usage();
default:
break;
}
}
if (argc - optind < 1)
usage();
init_mp(&arg.mp);
arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN | NO_DOTS;
arg.mp.fast_quit = fastquit;
arg.mp.arg = (void *) &arg;
arg.mp.openflags = O_RDONLY;
/* last parameter is "-", use mtype mode */
if(!mtype && !strcmp(argv[argc-1], "-")) {
arg.type = mtype = 1;
argc--;
}
if(mtype){
/* Mtype = copying to stdout */
arg.mp.targetName = strdup("-");
arg.mp.unixTarget = strdup("");
arg.mp.callback = dos_to_unix;
arg.mp.dirCallback = unix_copydir;
arg.mp.unixcallback = unix_to_unix;
} else {
char *target;
if (argc - optind == 1) {
/* copying to the current directory */
target = ".";
} else {
/* target is the last item mentioned */
argc--;
target = argv[argc];
}
ret = target_lookup(&arg.mp, target);
if(!arg.mp.targetDir && !arg.mp.unixTarget) {
fprintf(stderr,"Bad target %s\n", target);
exit(1);
}
/* callback functions */
if(arg.mp.unixTarget) {
arg.mp.callback = dos_to_unix;
arg.mp.dirCallback = directory_dos_to_unix;
arg.mp.unixcallback = unix_to_unix;
} else {
arg.mp.dirCallback = dos_copydir;
arg.mp.callback = dos_to_dos;
arg.mp.unixcallback = unix_to_dos;
}
}
exit(main_loop(&arg.mp, argv + optind, argc - optind));
}

View file

@ -1,173 +0,0 @@
/*
* mdel.c
* Delete an MSDOS file
*
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "stream.h"
#include "mainloop.h"
#include "fs.h"
#include "file.h"
typedef struct Arg_t {
int deltype;
int verbose;
} Arg_t;
static int del_entry(direntry_t *entry, MainParam_t *mp)
{
Arg_t *arg=(Arg_t *) mp->arg;
direntry_t longNameEntry;
int i;
if(got_signal)
return ERROR_ONE;
if(entry->entry == -3) {
fprintf(stderr, "Cannot remove root directory\n");
return ERROR_ONE;
}
if (arg->verbose) {
fprintf(stderr,"Removing ");
fprintPwd(stdout, entry,0);
putchar('\n');
}
if ((entry->dir.attr & (ATTR_READONLY | ATTR_SYSTEM)) &&
(ask_confirmation("%s: \"%s\" is read only, erase anyway (y/n) ? ",
progname, entry->name)))
return ERROR_ONE;
if (fatFreeWithDirentry(entry))
return ERROR_ONE;
initializeDirentry(&longNameEntry, entry->Dir);
for(i=entry->beginSlot; i< entry->endSlot; i++) {
int error;
longNameEntry.entry=i;
dir_read(&longNameEntry, &error);
if(error)
break;
longNameEntry.dir.name[0] = (char) DELMARK;
dir_write(&longNameEntry);
}
entry->dir.name[0] = (char) DELMARK;
dir_write(entry);
return GOT_ONE;
}
static int del_file(direntry_t *entry, MainParam_t *mp)
{
char shortname[13];
direntry_t subEntry;
Stream_t *SubDir;
Arg_t *arg = (Arg_t *) mp->arg;
MainParam_t sonmp;
int ret;
int r;
sonmp = *mp;
sonmp.arg = mp->arg;
r = 0;
if (IS_DIR(entry)){
/* a directory */
SubDir = OpenFileByDirentry(entry);
initializeDirentry(&subEntry, SubDir);
ret = 0;
while((r=vfat_lookup(&subEntry, "*", 1,
ACCEPT_DIR | ACCEPT_PLAIN,
shortname, NULL)) == 0 ){
if(shortname[0] != DELMARK &&
shortname[0] &&
shortname[0] != '.' ){
if(arg->deltype != 2){
fprintf(stderr,
"Directory ");
fprintPwd(stderr, entry,0);
fprintf(stderr," non empty\n");
ret = ERROR_ONE;
break;
}
if(got_signal) {
ret = ERROR_ONE;
break;
}
ret = del_file(&subEntry, &sonmp);
if( ret & ERROR_ONE)
break;
ret = 0;
}
}
FREE(&SubDir);
if (r == -2)
return ERROR_ONE;
if(ret)
return ret;
}
return del_entry(entry, mp);
}
static void usage(void)
{
fprintf(stderr,
"Mtools version %s, dated %s\n", mversion, mdate);
fprintf(stderr,
"Usage: %s [-v] msdosfile [msdosfiles...]\n"
"\t-v Verbose\n",
progname);
exit(1);
}
void mdel(int argc, char **argv, int deltype)
{
Arg_t arg;
MainParam_t mp;
int c,i;
arg.verbose = 0;
while ((c = getopt(argc, argv, "v")) != EOF) {
switch (c) {
case 'v':
arg.verbose = 1;
break;
default:
usage();
}
}
if(argc == optind)
usage();
init_mp(&mp);
mp.callback = del_file;
mp.arg = (void *) &arg;
mp.openflags = O_RDWR;
arg.deltype = deltype;
switch(deltype){
case 0:
mp.lookupflags = ACCEPT_PLAIN; /* mdel */
break;
case 1:
mp.lookupflags = ACCEPT_DIR; /* mrd */
break;
case 2:
mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN; /* mdeltree */
break;
}
mp.lookupflags |= NO_DOTS;
for(i=optind;i<argc;i++) {
int b,l;
b = skip_drive(argv[i]) - argv[i];
l = strlen(argv[i]+b);
if(l > 1 && argv[i][b+l-1] == '/')
argv[i][b+l-1] = '\0';
}
exit(main_loop(&mp, argv + optind, argc - optind));
}

View file

@ -1,579 +0,0 @@
/*
* mdir.c:
* Display an MSDOS directory
*/
#include "sysincludes.h"
#include "msdos.h"
#include "vfat.h"
#include "mtools.h"
#include "file.h"
#include "mainloop.h"
#include "fs.h"
#include "codepage.h"
#ifdef TEST_SIZE
#include "fsP.h"
#endif
static int recursive;
static int wide;
static int all;
static int concise;
static int fast=0;
#if 0
static int testmode = 0;
#endif
static char *dirPath;
static char *currentDrive;
static Stream_t *currentDir;
static int filesInDir; /* files in current dir */
static int filesOnDrive; /* files on drive */
static int dirsOnDrive; /* number of listed directories on this drive */
static int debug = 0; /* debug mode */
static mt_size_t bytesInDir;
static mt_size_t bytesOnDrive;
static Stream_t *RootDir;
static char shortname[13];
static char longname[VBUFSIZE];
/*
* Print an MSDOS directory date stamp.
*/
static inline void print_date(struct directory *dir)
{
char year[5];
char day[3];
char month[3];
char *p;
sprintf(year, "%04d", DOS_YEAR(dir));
sprintf(day, "%02d", DOS_DAY(dir));
sprintf(month, "%02d", DOS_MONTH(dir));
for(p=mtools_date_string; *p; p++) {
if(!strncasecmp(p, "yyyy", 4)) {
printf("%04d", DOS_YEAR(dir));
p+= 3;
continue;
} else if(!strncasecmp(p, "yy", 2)) {
printf("%02d", DOS_YEAR(dir) % 100);
p++;
continue;
} else if(!strncasecmp(p, "dd", 2)) {
printf("%02d", DOS_DAY(dir));
p++;
continue;
} else if(!strncasecmp(p, "mm", 2)) {
printf("%02d", DOS_MONTH(dir));
p++;
continue;
}
putchar(*p);
}
}
/*
* Print an MSDOS directory time stamp.
*/
static inline void print_time(struct directory *dir)
{
char am_pm;
int hour = DOS_HOUR(dir);
if(!mtools_twenty_four_hour_clock) {
am_pm = (hour >= 12) ? 'p' : 'a';
if (hour > 12)
hour = hour - 12;
if (hour == 0)
hour = 12;
} else
am_pm = ' ';
printf("%2d:%02d%c", hour, DOS_MINUTE(dir), am_pm);
}
/*
* Return a number in dotted notation
*/
static const char *dotted_num(mt_size_t num, int width, char **buf)
{
int len;
register char *srcp, *dstp;
int size;
unsigned long numlo;
unsigned long numhi;
if (num < 0) {
/* warn about negative numbers here. They should not occur */
fprintf(stderr, "Invalid negative number\n");
}
size = width + width;
*buf = malloc(size+1);
if (*buf == NULL)
return "";
/* Create the number in maximum width; make sure that the string
* length is not exceeded (in %6ld, the result can be longer than 6!)
*/
numlo = num % 1000000000;
numhi = num / 1000000000;
if(numhi && size > 9) {
sprintf(*buf, "%.*lu%09lu", size-9, numhi, numlo);
} else {
sprintf(*buf, "%.*lu", size, numlo);
}
for (srcp=*buf; srcp[1] != '\0'; ++srcp)
if (srcp[0] == '0')
srcp[0] = ' ';
else
break;
len = strlen(*buf);
srcp = (*buf)+len;
dstp = (*buf)+len+1;
for ( ; dstp >= (*buf)+4 && isdigit (srcp[-1]); ) {
srcp -= 3; /* from here we copy three digits */
dstp -= 4; /* that's where we put these 3 digits */
}
/* now finally copy the 3-byte blocks to their new place */
while (dstp < (*buf) + len) {
dstp[0] = srcp[0];
dstp[1] = srcp[1];
dstp[2] = srcp[2];
if (dstp + 3 < (*buf) + len)
/* use spaces instead of dots: they please both
* Americans and Europeans */
dstp[3] = ' ';
srcp += 3;
dstp += 4;
}
return (*buf) + len-width;
}
static inline int print_volume_label(Stream_t *Dir, char *drive)
{
Stream_t *Stream = GetFs(Dir);
direntry_t entry;
DeclareThis(FsPublic_t);
char shortname[13];
char longname[VBUFSIZE];
int r;
RootDir = OpenRoot(Stream);
if(concise)
return 0;
/* find the volume label */
initializeDirentry(&entry, RootDir);
if((r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
shortname, longname)) ) {
if (r == -2) {
/* I/O Error */
return -1;
}
printf(" Volume in drive %s has no label", drive);
} else if (*longname)
printf(" Volume in drive %s is %s (abbr=%s)",
drive, longname, shortname);
else
printf(" Volume in drive %s is %s",
drive, shortname);
if(This->serialized)
printf("\n Volume Serial Number is %04lX-%04lX",
(This->serial_number >> 16) & 0xffff,
This->serial_number & 0xffff);
return 0;
}
static void printSummary(int files, mt_size_t bytes)
{
if(!filesInDir)
printf("No files\n");
else {
char *s1;
printf(" %3d file", files);
if(files == 1)
putchar(' ');
else
putchar('s');
printf(" %s bytes\n",
dotted_num(bytes, 13, &s1));
if(s1)
free(s1);
}
}
static void leaveDirectory(int haveError);
static void leaveDrive(int haveError)
{
if(!currentDrive)
return;
leaveDirectory(haveError);
if(!concise && !haveError) {
char *s1;
if(dirsOnDrive > 1) {
printf("\nTotal files listed:\n");
printSummary(filesOnDrive, bytesOnDrive);
}
if(RootDir && !fast) {
mt_off_t bytes = getfree(RootDir);
printf(" %s bytes free\n\n",
dotted_num(bytes,17, &s1));
#ifdef TEST_SIZE
((Fs_t*)GetFs(RootDir))->freeSpace = 0;
bytes = getfree(RootDir);
printf(" %s bytes free\n\n",
dotted_num(bytes,17, &s1));
#endif
}
if(s1)
free(s1);
}
FREE(&RootDir);
currentDrive = NULL;
}
static int enterDrive(Stream_t *Dir, char *drive)
{
int r;
if(currentDrive != NULL && strcmp(currentDrive, drive) == 0)
return 0; /* still the same */
leaveDrive(0);
currentDrive = drive;
r = print_volume_label(Dir, drive);
if (r)
return r;
bytesOnDrive = 0;
filesOnDrive = 0;
dirsOnDrive = 0;
return 0;
}
static char *emptyString="<out-of-memory>";
static void leaveDirectory(int haveError)
{
if(!currentDir)
return;
if (!haveError) {
if(dirPath && dirPath != emptyString)
free(dirPath);
if(wide)
putchar('\n');
if(!concise)
printSummary(filesInDir, bytesInDir);
}
FREE(&currentDir);
}
static int enterDirectory(Stream_t *Dir)
{
int r;
char *drive;
char *slash;
if(currentDir == Dir)
return 0; /* still the same directory */
leaveDirectory(0);
drive = getDrive(Dir);
r=enterDrive(Dir, drive);
if(r)
return r;
currentDir = COPY(Dir);
dirPath = getPwd(getDirentry(Dir));
if(!dirPath)
dirPath=emptyString;
if(concise &&
(slash = strrchr(dirPath, '/')) != NULL && slash[1] == '\0')
*slash = '\0';
/* print directory title */
if(!concise)
printf("\nDirectory for %s\n", dirPath);
if(!wide && !concise)
printf("\n");
dirsOnDrive++;
bytesInDir = 0;
filesInDir = 0;
return 0;
}
static int list_file(direntry_t *entry, MainParam_t *mp)
{
unsigned long size;
int i;
int Case;
int r;
if(!all && (entry->dir.attr & 0x6))
return 0;
if(concise && isSpecial(entry->name))
return 0;
r=enterDirectory(entry->Dir);
if (r)
return ERROR_ONE;
if (wide) {
if(filesInDir % 5)
putchar(' ');
else
putchar('\n');
}
if(IS_DIR(entry)){
size = 0;
} else
size = FILE_SIZE(&entry->dir);
Case = entry->dir.Case;
if(!(Case & (BASECASE | EXTCASE)) &&
mtools_ignore_short_case)
Case |= BASECASE | EXTCASE;
if(Case & EXTCASE){
for(i=0; i<3;i++)
entry->dir.ext[i] = tolower(entry->dir.ext[i]);
}
to_unix(entry->dir.ext,3);
if(Case & BASECASE){
for(i=0; i<8;i++)
entry->dir.name[i] = tolower(entry->dir.name[i]);
}
to_unix(entry->dir.name,8);
if(wide){
if(IS_DIR(entry))
printf("[%s]%*s", shortname,
(int) (15 - 2 - strlen(shortname)), "");
else
printf("%-15s", shortname);
} else if(!concise) {
/* is a subdirectory */
if(mtools_dotted_dir)
printf("%-13s", shortname);
else
printf("%-8.8s %-3.3s ",
entry->dir.name,
entry->dir.ext);
if(IS_DIR(entry))
printf("<DIR> ");
else
printf(" %8ld", (long) size);
printf(" ");
print_date(&entry->dir);
printf(" ");
print_time(&entry->dir);
if(debug)
printf(" %s %d ", entry->dir.name, START(&entry->dir));
if(*longname)
printf(" %s", longname);
printf("\n");
} else {
printf("%s/%s", dirPath, entry->name);
if(IS_DIR(entry))
putchar('/');
putchar('\n');
}
filesOnDrive++;
filesInDir++;
bytesOnDrive += (mt_size_t) size;
bytesInDir += (mt_size_t) size;
return GOT_ONE;
}
static int list_non_recurs_directory(direntry_t *entry, MainParam_t *mp)
{
int r;
/* list top-level directory
* If this was matched by wildcard in the basename, list it as
* file, otherwise, list it as directory */
if (mp->basenameHasWildcard) {
/* wildcard, list it as file */
return list_file(entry, mp);
} else {
/* no wildcard, list it as directory */
MainParam_t subMp;
r=enterDirectory(mp->File);
if(r)
return ERROR_ONE;
subMp = *mp;
subMp.dirCallback = subMp.callback;
return mp->loop(mp->File, &subMp, "*") | GOT_ONE;
}
}
static int list_recurs_directory(direntry_t *entry, MainParam_t *mp)
{
MainParam_t subMp;
int ret;
/* first list the files */
subMp = *mp;
subMp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN;
subMp.dirCallback = list_file;
subMp.callback = list_file;
ret = mp->loop(mp->File, &subMp, "*");
/* then list subdirectories */
subMp = *mp;
subMp.lookupflags = ACCEPT_DIR | NO_DOTS | NO_MSG | DO_OPEN;
return ret | mp->loop(mp->File, &subMp, "*");
}
#if 0
static int test_directory(direntry_t *entry, MainParam_t *mp)
{
Stream_t *File=mp->File;
Stream_t *Target;
char errmsg[80];
if ((Target = SimpleFileOpen(0, 0, "-",
O_WRONLY,
errmsg, 0, 0, 0))) {
copyfile(File, Target);
FREE(&Target);
}
return GOT_ONE;
}
#endif
static void usage(void)
{
fprintf(stderr, "Mtools version %s, dated %s\n",
mversion, mdate);
fprintf(stderr, "Usage: %s: [-waXbfds/] msdosdirectory\n",
progname);
fprintf(stderr,
" %s: [-waXbfds/] msdosfile [msdosfiles...]\n",
progname);
fprintf(stderr,
"\t-w Wide listing\n"
"\t-a All, including hidden files\n"
"\t-b -X Concise listing\n"
"\t-f Fast, no free space summary\n"
"\t-d Debug mode\n"
"\t-s -/ Recursive\n");
exit(1);
}
void mdir(int argc, char **argv, int type)
{
int ret;
MainParam_t mp;
int faked;
int c;
char *fakedArgv[] = { "." };
concise = 0;
recursive = 0;
wide = all = 0;
/* first argument */
while ((c = getopt(argc, argv, "waXbfds/")) != EOF) {
switch(c) {
case 'w':
wide = 1;
break;
case 'a':
all = 1;
break;
case 'b':
case 'X':
concise = 1;
/*recursive = 1;*/
break;
case 's':
case '/':
recursive = 1;
break;
case 'f':
fast = 1;
break;
case 'd':
debug = 1;
break;
#if 0
case 't': /* test mode */
testmode = 1;
break;
#endif
default:
usage();
}
}
/* fake an argument */
faked = 0;
if (optind == argc) {
argv = fakedArgv;
argc = 1;
optind = 0;
}
init_mp(&mp);
currentDrive = '\0';
currentDir = 0;
RootDir = 0;
dirPath = 0;
#if 0
if (testmode) {
mp.lookupflags = ACCEPT_DIR | NO_DOTS;
mp.dirCallback = test_directory;
} else
#endif
if(recursive) {
mp.lookupflags = ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
mp.dirCallback = list_recurs_directory;
} else {
mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN | DO_OPEN_DIRS;
mp.dirCallback = list_non_recurs_directory;
mp.callback = list_file;
}
mp.longname = longname;
mp.shortname = shortname;
ret=main_loop(&mp, argv + optind, argc - optind);
leaveDirectory(ret);
leaveDrive(ret);
exit(ret);
}

View file

@ -1,166 +0,0 @@
/* Test program for doctoring the fat */
/*
* mcopy.c
* Copy an MSDOS files to and from Unix
*
*/
#define LOWERCASE
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "mainloop.h"
#include "plain_io.h"
#include "nameclash.h"
#include "file.h"
#include "fs.h"
#include "fsP.h"
typedef struct Arg_t {
char *target;
MainParam_t mp;
ClashHandling_t ch;
Stream_t *sourcefile;
unsigned long fat;
int markbad;
int setsize;
unsigned long size;
Fs_t *Fs;
} Arg_t;
static int dos_doctorfat(direntry_t *entry, MainParam_t *mp)
{
Fs_t *Fs = getFs(mp->File);
Arg_t *arg=(Arg_t *) mp->arg;
if(!arg->markbad && entry->entry != -3) {
/* if not root directory, change it */
set_word(entry->dir.start, arg->fat & 0xffff);
set_word(entry->dir.startHi, arg->fat >> 16);
if(arg->setsize)
set_dword(entry->dir.size, arg->size);
dir_write(entry);
}
arg->Fs = Fs;
return GOT_ONE;
}
static int unix_doctorfat(MainParam_t *mp)
{
fprintf(stderr,"File does not reside on a Dos fs\n");
return ERROR_ONE;
}
static void usage(void)
{
fprintf(stderr,
"Mtools version %s, dated %s\n", mversion, mdate);
fprintf(stderr,
"Usage: %s [-b] [-o offset] [-s size] file fat\n", progname);
exit(1);
}
void mdoctorfat(int argc, char **argv, int mtype)
{
Arg_t arg;
int c, ret;
long address, begin, end;
char *number, *eptr;
int i, j;
long offset;
/* get command line options */
init_clash_handling(& arg.ch);
offset = 0;
arg.markbad = 0;
arg.setsize = 0;
/* get command line options */
while ((c = getopt(argc, argv, "bo:s:")) != EOF) {
switch (c) {
case 'b':
arg.markbad = 1;
break;
case 'o':
offset = strtoul(optarg,0,0);
break;
case 's':
arg.setsize=1;
arg.size = strtoul(optarg,0,0);
break;
case '?':
usage();
break;
}
}
if (argc - optind < 2)
usage();
/* only 1 file to copy... */
init_mp(&arg.mp);
arg.mp.arg = (void *) &arg;
arg.mp.callback = dos_doctorfat;
arg.mp.unixcallback = unix_doctorfat;
arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN;
arg.mp.openflags = O_RDWR;
arg.fat = strtoul(argv[optind+1], 0, 0) + offset;
ret=main_loop(&arg.mp, argv + optind, 1);
if(ret)
exit(ret);
address = 0;
for(i=optind+1; i < argc; i++) {
number = argv[i];
if (*number == '<') {
number++;
}
begin = strtoul(number, &eptr, 0);
if (eptr && *eptr == '-') {
number = eptr+1;
end = strtoul(number, &eptr, 0);
} else {
end = begin;
}
if (eptr == number) {
fprintf(stderr, "Not a number: %s\n", number);
exit(-1);
}
if (eptr && *eptr == '>') {
eptr++;
}
if (eptr && *eptr) {
fprintf(stderr, "Not a number: %s\n", eptr);
exit(-1);
}
for (j=begin; j <= end; j++) {
if(arg.markbad) {
arg.Fs->fat_encode(arg.Fs, j+offset, arg.Fs->last_fat ^ 6 ^ 8);
} else {
if(address) {
arg.Fs->fat_encode(arg.Fs, address, j+offset);
}
address = j+offset;
}
}
}
if (address && !arg.markbad) {
arg.Fs->fat_encode(arg.Fs, address, arg.Fs->end_fat);
}
exit(ret);
}

View file

@ -1,121 +0,0 @@
/*
* mdu.c:
* Display the space occupied by an MSDOS directory
*/
#include "sysincludes.h"
#include "msdos.h"
#include "vfat.h"
#include "mtools.h"
#include "file.h"
#include "mainloop.h"
#include "fs.h"
#include "codepage.h"
typedef struct Arg_t {
int all;
int inDir;
int summary;
struct Arg_t *parent;
char *target;
char *path;
unsigned int blocks;
MainParam_t mp;
} Arg_t;
static void usage(void)
{
fprintf(stderr, "Mtools version %s, dated %s\n",
mversion, mdate);
fprintf(stderr, "Usage: %s [-as] msdosdirectory\n"
"\t-a All (also show individual files)\n"
"\t-s Summary for directory only\n",
progname);
exit(1);
}
static int file_mdu(direntry_t *entry, MainParam_t *mp)
{
unsigned int blocks;
Arg_t * arg = (Arg_t *) (mp->arg);
blocks = countBlocks(entry->Dir,getStart(entry->Dir, &entry->dir));
if(arg->all || !arg->inDir) {
printf("%-7d ", blocks);
fprintPwd(stdout, entry,0);
fputc('\n', stdout);
}
arg->blocks += blocks;
return GOT_ONE;
}
static int dir_mdu(direntry_t *entry, MainParam_t *mp)
{
Arg_t *parentArg = (Arg_t *) (mp->arg);
Arg_t arg;
int ret;
arg = *parentArg;
arg.mp.arg = (void *) &arg;
arg.parent = parentArg;
arg.inDir = 1;
/* account for the space occupied by the directory itself */
if(!isRootDir(entry->Dir)) {
arg.blocks = countBlocks(entry->Dir,
getStart(entry->Dir, &entry->dir));
} else {
arg.blocks = 0;
}
/* recursion */
ret = mp->loop(mp->File, &arg.mp, "*");
if(!arg.summary || !parentArg->inDir) {
printf("%-7d ", arg.blocks);
fprintPwd(stdout, entry,0);
fputc('\n', stdout);
}
arg.parent->blocks += arg.blocks;
return ret;
}
void mdu(int argc, char **argv, int type)
{
Arg_t arg;
int c;
arg.all = 0;
arg.inDir = 0;
arg.summary = 0;
while ((c = getopt(argc, argv, "as")) != EOF) {
switch (c) {
case 'a':
arg.all = 1;
break;
case 's':
arg.summary = 1;
break;
case '?':
usage();
}
}
if (optind >= argc)
usage();
if(arg.summary && arg.all) {
fprintf(stderr,"-a and -s options are mutually exclusive\n");
usage();
}
init_mp(&arg.mp);
arg.mp.callback = file_mdu;
arg.mp.openflags = O_RDONLY;
arg.mp.dirCallback = dir_mdu;
arg.mp.arg = (void *) &arg;
arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
exit(main_loop(&arg.mp, argv + optind, argc - optind));
}

File diff suppressed because it is too large Load diff

View file

@ -1,172 +0,0 @@
/*
* mlabel.c
* Make an MSDOS volume label
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mainloop.h"
#include "vfat.h"
#include "mtools.h"
#include "nameclash.h"
static void usage(void)
{
fprintf(stderr,
"Mtools version %s, dated %s\n", mversion, mdate);
fprintf(stderr,
"Usage: %s [-v] drive\n\t-v Verbose\n", progname);
exit(1);
}
static void displayInfosector(Stream_t *Stream, struct bootsector *boot)
{
InfoSector_t *infosec;
if(WORD(ext.fat32.infoSector) == MAX32)
return;
infosec = (InfoSector_t *) safe_malloc(WORD(secsiz));
force_read(Stream, (char *) infosec,
(mt_off_t) WORD(secsiz) * WORD(ext.fat32.infoSector),
WORD(secsiz));
printf("\nInfosector:\n");
printf("signature=0x%08x\n", _DWORD(infosec->signature1));
if(_DWORD(infosec->count) != MAX32)
printf("free clusters=%u\n", _DWORD(infosec->count));
if(_DWORD(infosec->pos) != MAX32)
printf("last allocated cluster=%u\n", _DWORD(infosec->pos));
}
void minfo(int argc, char **argv, int type)
{
struct bootsector boot0;
#define boot (&boot0)
char name[EXPAND_BUF];
int media;
int tot_sectors;
struct device dev;
char *drive;
int verbose=0;
int c;
Stream_t *Stream;
struct label_blk_t *labelBlock;
while ((c = getopt(argc, argv, "v")) != EOF) {
switch (c) {
case 'v':
verbose = 1;
break;
default:
usage();
}
}
if(argc == optind)
usage();
for(;optind < argc; optind++) {
if(skip_drive(argv[optind]) == argv[optind])
usage();
drive = get_drive(argv[optind], NULL);
if(! (Stream = find_device(drive, O_RDONLY, &dev, boot,
name, &media, 0)))
exit(1);
tot_sectors = DWORD(bigsect);
SET_INT(tot_sectors, WORD(psect));
printf("device information:\n");
printf("===================\n");
printf("filename=\"%s\"\n", name);
printf("sectors per track: %d\n", dev.sectors);
printf("heads: %d\n", dev.heads);
printf("cylinders: %d\n\n", dev.tracks);
printf("mformat command line: mformat -t %d -h %d -s %d ",
dev.tracks, dev.heads, dev.sectors);
if(DWORD(nhs))
printf("-H %d ", DWORD(nhs));
printf("%s:\n", drive);
printf("\n");
printf("bootsector information\n");
printf("======================\n");
printf("banner:\"%8s\"\n", boot->banner);
printf("sector size: %d bytes\n", WORD(secsiz));
printf("cluster size: %d sectors\n", boot->clsiz);
printf("reserved (boot) sectors: %d\n", WORD(nrsvsect));
printf("fats: %d\n", boot->nfat);
printf("max available root directory slots: %d\n",
WORD(dirents));
printf("small size: %d sectors\n", WORD(psect));
printf("media descriptor byte: 0x%x\n", boot->descr);
printf("sectors per fat: %d\n", WORD(fatlen));
printf("sectors per track: %d\n", WORD(nsect));
printf("heads: %d\n", WORD(nheads));
printf("hidden sectors: %d\n", DWORD(nhs));
printf("big size: %d sectors\n", DWORD(bigsect));
if(WORD(fatlen)) {
labelBlock = &boot->ext.old.labelBlock;
} else {
labelBlock = &boot->ext.fat32.labelBlock;
}
printf("physical drive id: 0x%x\n",
labelBlock->physdrive);
printf("reserved=0x%x\n",
labelBlock->reserved);
printf("dos4=0x%x\n",
labelBlock->dos4);
printf("serial number: %08X\n",
_DWORD(labelBlock->serial));
printf("disk label=\"%11.11s\"\n",
labelBlock->label);
printf("disk type=\"%8.8s\"\n",
labelBlock->fat_type);
if(!WORD(fatlen)){
printf("Big fatlen=%u\n",
DWORD(ext.fat32.bigFat));
printf("Extended flags=0x%04x\n",
WORD(ext.fat32.extFlags));
printf("FS version=0x%04x\n",
WORD(ext.fat32.fsVersion));
printf("rootCluster=%u\n",
DWORD(ext.fat32.rootCluster));
if(WORD(ext.fat32.infoSector) != MAX32)
printf("infoSector location=%d\n",
WORD(ext.fat32.infoSector));
if(WORD(ext.fat32.backupBoot) != MAX32)
printf("backup boot sector=%d\n",
WORD(ext.fat32.backupBoot));
displayInfosector(Stream,boot);
}
if(verbose) {
int size;
unsigned char *buf;
printf("\n");
size = WORD(secsiz);
buf = (unsigned char *) malloc(size);
if(!buf) {
fprintf(stderr, "Out of memory error\n");
exit(1);
}
size = READS(Stream, buf, (mt_off_t) 0, size);
if(size < 0) {
perror("read boot sector");
exit(1);
}
print_sector("Boot sector hexdump", buf, size);
}
}
exit(0);
}

View file

@ -1,307 +0,0 @@
/*
* Miscellaneous routines.
*/
#include "sysincludes.h"
#include "msdos.h"
#include "stream.h"
#include "vfat.h"
#include "mtools.h"
void printOom(void)
{
fprintf(stderr, "Out of memory error");
}
char *get_homedir(void)
{
struct passwd *pw;
uid_t uid;
char *homedir;
char *username;
homedir = getenv ("HOME");
/*
* first we call getlogin.
* There might be several accounts sharing one uid
*/
if ( homedir )
return homedir;
pw = 0;
username = getenv("LOGNAME");
if ( !username )
username = getlogin();
if ( username )
pw = getpwnam( username);
if ( pw == 0 ){
/* if we can't getlogin, look up the pwent by uid */
uid = geteuid();
pw = getpwuid(uid);
}
/* we might still get no entry */
if ( pw )
return pw->pw_dir;
return 0;
}
static void get_mcwd_file_name(char *file)
{
char *mcwd_path;
char *homedir;
mcwd_path = getenv("MCWD");
if (mcwd_path == NULL || *mcwd_path == '\0'){
homedir= get_homedir();
if(!homedir)
homedir="/tmp";
strncpy(file, homedir, MAXPATHLEN-6);
file[MAXPATHLEN-6]='\0';
strcat( file, "/.mcwd");
} else {
strncpy(file, mcwd_path, MAXPATHLEN);
file[MAXPATHLEN]='\0';
}
}
void unlink_mcwd()
{
char file[MAXPATHLEN+1];
get_mcwd_file_name(file);
unlink(file);
}
FILE *open_mcwd(const char *mode)
{
struct stat sbuf;
char file[MAXPATHLEN+1];
time_t now;
get_mcwd_file_name(file);
if (*mode == 'r'){
if (stat(file, &sbuf) < 0)
return NULL;
/*
* Ignore the info, if the file is more than 6 hours old
*/
getTimeNow(&now);
if (now - sbuf.st_mtime > 6 * 60 * 60) {
fprintf(stderr,
"Warning: \"%s\" is out of date, removing it\n",
file);
unlink(file);
return NULL;
}
}
return fopen(file, mode);
}
/* Fix the info in the MCWD file to be a proper directory name.
* Always has a leading separator. Never has a trailing separator
* (unless it is the path itself). */
const char *fix_mcwd(char *ans)
{
FILE *fp;
char *s;
char buf[MAX_PATH];
fp = open_mcwd("r");
if(!fp){
strcpy(ans, "A:/");
return ans;
}
if (!fgets(buf, MAX_PATH, fp))
return("A:/");
buf[strlen(buf) -1] = '\0';
fclose(fp);
/* drive letter present? */
s = skip_drive(buf);
if (s > buf) {
strncpy(ans, buf, s - buf);
ans[s - buf] = '\0';
} else
strcpy(ans, "A:");
/* add a leading separator */
if (*s != '/' && *s != '\\') {
strcat(ans, "/");
strcat(ans, s);
} else
strcat(ans, s);
#if 0
/* translate to upper case */
for (s = ans; *s; ++s) {
*s = toupper(*s);
if (*s == '\\')
*s = '/';
}
#endif
/* if only drive, colon, & separator */
if (strlen(ans) == 3)
return(ans);
/* zap the trailing separator */
if (*--s == '/')
*s = '\0';
return ans;
}
void *safe_malloc(size_t size)
{
void *p;
p = malloc(size);
if(!p){
printOom();
exit(1);
}
return p;
}
void print_sector(char *message, unsigned char *data, int size)
{
int col;
int row;
printf("%s:\n", message);
for(row = 0; row * 16 < size; row++){
printf("%03x ", row * 16);
for(col = 0; col < 16; col++)
printf("%02x ", data [row*16+col]);
for(col = 0; col < 16; col++) {
if(isprint(data [row*16+col]))
printf("%c", data [row*16+col]);
else
printf(".");
}
printf("\n");
}
}
time_t getTimeNow(time_t *now)
{
static int haveTime = 0;
static time_t sharedNow;
if(!haveTime) {
time(&sharedNow);
haveTime = 1;
}
if(now)
*now = sharedNow;
return sharedNow;
}
char *skip_drive(const char *filename)
{
char *p;
/* Skip drive name. Return pointer just after the `:', or a pointer
* to the start of the file name if there is is no drive name.
*/
p = strchr(filename, ':');
return (p == NULL || p == filename) ? (char *) filename : p + 1;
}
char *get_drive(const char *filename, const char *def)
{
const char *path;
char *drive;
const char *rest;
size_t len;
/* Return the drive name part of a full filename. */
path = filename;
rest = skip_drive(path);
if (rest == path) {
if (def == NULL) def = "A:";
path = def;
rest = skip_drive(path);
if (rest == path) {
path = "A:";
rest = path+2;
}
}
len = rest - path;
drive = safe_malloc(len * sizeof(drive[0]));
len--;
memcpy(drive, path, len);
drive[len] = 0;
if (len == 1) drive[0] = toupper(drive[0]);
return drive;
}
#if 0
#undef free
#undef malloc
static int total=0;
void myfree(void *ptr)
{
int *size = ((int *) ptr)-1;
total -= *size;
fprintf(stderr, "freeing %d bytes at %p total alloced=%d\n",
*size, ptr, total);
free(size);
}
void *mymalloc(size_t size)
{
int *ptr;
ptr = (int *)malloc(size+sizeof(int));
if(!ptr)
return 0;
*ptr = size;
ptr++;
total += size;
fprintf(stderr, "allocating %d bytes at %p total allocated=%d\n",
size, ptr, total);
return (void *) ptr;
}
void *mycalloc(size_t nmemb, size_t size)
{
void *ptr = mymalloc(nmemb * size);
if(!ptr)
return 0;
memset(ptr, 0, size);
return ptr;
}
void *myrealloc(void *ptr, size_t size)
{
int oldsize = ((int *)ptr) [-1];
void *new = mymalloc(size);
if(!new)
return 0;
memcpy(new, ptr, oldsize);
myfree(ptr);
return new;
}
char *mystrdup(char *src)
{
char *dest;
dest = mymalloc(strlen(src)+1);
if(!dest)
return 0;
strcpy(dest, src);
return dest;
}
#endif

View file

@ -1,386 +0,0 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file contains excerpts of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#include "sysincludes.h"
#include "mtools.h"
#ifndef HAVE_STRDUP
char *strdup(const char *str)
{
char *nstr;
if (str == (char*)0)
return 0;
nstr = (char*)malloc((strlen(str) + 1));
if (nstr == (char*)0)
{
(void)fprintf(stderr, "strdup(): not enough memory to duplicate `%s'\n",
str);
exit(1);
}
(void)strcpy(nstr, str);
return nstr;
}
#endif /* HAVE_STRDUP */
#ifndef HAVE_MEMCPY
/*
* Copy contents of memory (with possible overlapping).
*/
char *memcpy(char *s1, const char *s2, size_t n)
{
bcopy(s2, s1, n);
return(s1);
}
#endif
#ifndef HAVE_MEMSET
/*
* Copies the character c, n times to string s
*/
char *memset(char *s, char c, size_t n)
{
char *s1 = s;
while (n > 0) {
--n;
*s++ = c;
}
return(s1);
}
#endif /* HAVE_MEMSET */
#ifndef HAVE_STRCHR
char * strchr (const char* s, int c)
{
if (!s) return NULL;
while (*s && *s != c) s++;
if (*s)
return (char*) s;
else
return NULL;
}
#endif
#ifndef HAVE_STRRCHR
char * strrchr (const char* s1, int c)
{
char* s = (char*) s1;
char* start = (char*) s;
if (!s) return NULL;
s += strlen(s)-1;
while (*s != c && (unsigned long) s != (unsigned long) start) s--;
if ((unsigned long) s == (unsigned long) start && *s != c)
return NULL;
else
return s;
}
#endif
#ifndef HAVE_STRPBRK
/*
* Return ptr to first occurrence of any character from `brkset'
* in the character string `string'; NULL if none exists.
*/
char *strpbrk(const char *string, const char *brkset)
{
register char *p;
if (!string || !brkset)
return(0);
do {
for (p = brkset; *p != '\0' && *p != *string; ++p)
;
if (*p != '\0')
return(string);
}
while (*string++);
return(0);
}
#endif /* HAVE_STRPBRK */
#ifndef HAVE_STRTOUL
static int getdigit(char a, int max)
{
int dig;
if(a < '0')
return -1;
if(a <= '9') {
dig = a - '0';
} else if(a >= 'a')
dig = a - 'a' + 10;
else if(a >= 'A')
dig = a - 'A' + 10;
if(dig >= max)
return -1;
else
return dig;
}
unsigned long strtoul(const char *string, char **eptr, int base)
{
int accu, dig;
if(base < 1 || base > 36) {
if(string[0] == '0') {
switch(string[1]) {
case 'x':
case 'X':
return strtoul(string+2, eptr, 16);
case 'b':
case 'B':
return strtoul(string+2, eptr, 2);
default:
return strtoul(string, eptr, 8);
}
}
return strtoul(string, eptr, 10);
}
if(base == 16 && string[0] == '0' &&
(string[1] == 'x' || string[1] == 'X'))
string += 2;
if(base == 2 && string[0] == '0' &&
(string[1] == 'b' || string[1] == 'B'))
string += 2;
accu = 0;
while( (dig = getdigit(*string, base)) != -1 ) {
accu = accu * base + dig;
string++;
}
if(eptr)
*eptr = (char *) string;
return accu;
}
#endif /* HAVE_STRTOUL */
#ifndef HAVE_STRTOL
long strtol(const char *string, char **eptr, int base)
{
long l;
if(*string == '-') {
return -(long) strtoul(string+1, eptr, base);
} else {
if (*string == '+')
string ++;
return (long) strtoul(string, eptr, base);
}
}
#endif
#ifndef HAVE_STRSPN
/* Return the length of the maximum initial segment
of S which contains only characters in ACCEPT. */
size_t strspn(const char *s, const char *accept)
{
register char *p;
register char *a;
register size_t count = 0;
for (p = s; *p != '\0'; ++p)
{
for (a = accept; *a != '\0'; ++a)
if (*p == *a)
break;
if (*a == '\0')
return count;
else
++count;
}
return count;
}
#endif /* HAVE_STRSPN */
#ifndef HAVE_STRCSPN
/* Return the length of the maximum inital segment of S
which contains no characters from REJECT. */
size_t strcspn (const char *s, const char *reject)
{
register size_t count = 0;
while (*s != '\0')
if (strchr (reject, *s++) == NULL)
++count;
else
return count;
return count;
}
#endif /* HAVE_STRCSPN */
#ifndef HAVE_STRERROR
#ifndef DECL_SYS_ERRLIST
extern char *sys_errlist[];
#endif
char *strerror(int errno)
{
return sys_errlist[errno];
}
#endif
#ifndef HAVE_STRCASECMP
/* Compare S1 and S2, ignoring case, returning less than, equal to or
greater than zero if S1 is lexiographically less than,
equal to or greater than S2. */
int strcasecmp(const char *s1, const char *s2)
{
register const unsigned char *p1 = (const unsigned char *) s1;
register const unsigned char *p2 = (const unsigned char *) s2;
unsigned char c1, c2;
if (p1 == p2)
return 0;
do
{
c1 = tolower (*p1++);
c2 = tolower (*p2++);
if (c1 == '\0')
break;
}
while (c1 == c2);
return c1 - c2;
}
#endif
#ifndef HAVE_STRCASECMP
/* Compare S1 and S2, ignoring case, returning less than, equal to or
greater than zero if S1 is lexiographically less than,
equal to or greater than S2. */
int strncasecmp(const char *s1, const char *s2, size_t n)
{
register const unsigned char *p1 = (const unsigned char *) s1;
register const unsigned char *p2 = (const unsigned char *) s2;
unsigned char c1, c2;
if (p1 == p2)
return 0;
c1 = c2 = 1;
while (c1 && c1 == c2 && n-- > 0)
{
c1 = tolower (*p1++);
c2 = tolower (*p2++);
}
return c1 - c2;
}
#endif
#ifndef HAVE_GETPASS
char *getpass(const char *prompt)
{
static char password[129];
int l;
fprintf(stderr,"%s",prompt);
fgets(password, 128, stdin);
l = strlen(password);
if(l && password[l-1] == '\n')
password[l-1] = '\0';
return password;
}
#endif
#ifndef HAVE_ATEXIT
#ifdef HAVE_ON_EXIT
int atexit(void (*function)(void))
{
return on_exit( (void(*)(int,void*)) function, 0);
}
#else
typedef struct exitCallback {
void (*function) (void);
struct exitCallback *next;
} exitCallback_t;
static exitCallback_t *callback = 0;
int atexit(void (*function) (void))
{
exitCallback_t *newCallback;
newCallback = New(exitCallback_t);
if(!newCallback) {
printOom();
exit(1);
}
newCallback->function = function;
newCallback->next = callback;
callback = newCallback;
return 0;
}
#undef exit
void myexit(int code)
{
void (*function)(void);
while(callback) {
function = callback->function;
callback = callback->next;
function();
}
exit(code);
}
#endif
#endif
/*#ifndef HAVE_BASENAME*/
const char *_basename(const char *filename)
{
char *ptr;
ptr = strrchr(filename, '/');
if(ptr)
return ptr+1;
else
return filename;
}
/*#endif*/

View file

@ -1,618 +0,0 @@
/*
* mk_direntry.c
* Make new directory entries, and handles name clashes
*
*/
/*
* This file is used by those commands that need to create new directory entries
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "nameclash.h"
#include "fs.h"
#include "stream.h"
#include "mainloop.h"
static inline int ask_rename(ClashHandling_t *ch,
char *longname, int isprimary, char *argname)
{
char shortname[13];
int mangled;
/* TODO: Would be nice to suggest "autorenamed" version of name, press
* <Return> to get it.
*/
#if 0
fprintf(stderr,"Entering ask_rename, isprimary=%d.\n", isprimary);
#endif
if(!opentty(0))
return 0;
#define maxsize (isprimary ? MAX_VNAMELEN+1 : 11+1)
#define name (isprimary ? argname : shortname)
mangled = 0;
do {
fprintf(stderr, "New %s name for \"%s\": ",
isprimary ? "primary" : "secondary", longname);
fflush(stderr);
if (! fgets(name, maxsize, opentty(0)))
return 0;
/* Eliminate newline(s) in the file name */
name[strlen(name)-1]='\0';
if (!isprimary)
ch->name_converter(shortname,0, &mangled, argname);
} while (mangled & 1);
return 1;
#undef maxsize
#undef name
}
static inline clash_action ask_namematch(char *name, int isprimary,
ClashHandling_t *ch, int no_overwrite,
int reason)
{
char ans[10];
clash_action a;
int perm;
char unix_shortname[13];
#define EXISTS 0
#define RESERVED 1
#define ILLEGALS 2
static const char *reasons[]= {
"already exists",
"is reserved",
"contains illegal character(s)"};
if (!isprimary)
name = unix_normalize(unix_shortname, name, name+8);
a = ch->action[isprimary];
if(a == NAMEMATCH_NONE && !opentty(1)) {
/* no default, and no tty either . Skip the troublesome file */
return NAMEMATCH_SKIP;
}
perm = 0;
while (a == NAMEMATCH_NONE) {
fprintf(stderr, "%s file name \"%s\" %s.\n",
isprimary ? "Long" : "Short", name, reasons[reason]);
fprintf(stderr,
"a)utorename A)utorename-all r)ename R)ename-all ");
if(!no_overwrite)
fprintf(stderr,"o)verwrite O)verwrite-all");
fprintf(stderr,
"\ns)kip S)kip-all q)uit (aArR");
if(!no_overwrite)
fprintf(stderr,"oO");
fprintf(stderr,"sSq): ");
fflush(stderr);
fflush(opentty(1));
if (mtools_raw_tty) {
int rep;
rep = fgetc(opentty(1));
fputs("\n", stderr);
if(rep == EOF)
ans[0] = 'q';
else
ans[0] = rep;
} else {
fgets(ans, 9, opentty(0));
}
perm = isupper((unsigned char)ans[0]);
switch(tolower((unsigned char)ans[0])) {
case 'a':
a = NAMEMATCH_AUTORENAME;
break;
case 'r':
if(isprimary)
a = NAMEMATCH_PRENAME;
else
a = NAMEMATCH_RENAME;
break;
case 'o':
if(no_overwrite)
continue;
a = NAMEMATCH_OVERWRITE;
break;
case 's':
a = NAMEMATCH_SKIP;
break;
case 'q':
perm = 0;
a = NAMEMATCH_QUIT;
break;
default:
perm = 0;
}
}
/* Keep track of this action in case this file collides again */
ch->action[isprimary] = a;
if (perm)
ch->namematch_default[isprimary] = a;
/* if we were asked to overwrite be careful. We can't set the action
* to overwrite, else we get won't get a chance to specify another
* action, should overwrite fail. Indeed, we'll be caught in an
* infinite loop because overwrite will fail the same way for the
* second time */
if(a == NAMEMATCH_OVERWRITE)
ch->action[isprimary] = NAMEMATCH_NONE;
return a;
}
/* Returns:
* 2 if file is to be overwritten
* 1 if file was renamed
* 0 if it was skipped
*
* If a short name is involved, handle conversion between the 11-character
* fixed-length record DOS name and a literal null-terminated name (e.g.
* "COMMAND COM" (no null) <-> "COMMAND.COM" (null terminated)).
*
* Also, immediately copy the original name so that messages can use it.
*/
static inline clash_action process_namematch(char *name,
char *longname,
int isprimary,
ClashHandling_t *ch,
int no_overwrite,
int reason)
{
clash_action action;
#if 0
fprintf(stderr,
"process_namematch: name=%s, default_action=%d, ask=%d.\n",
name, default_action, ch->ask);
#endif
action = ask_namematch(name, isprimary, ch, no_overwrite, reason);
switch(action){
case NAMEMATCH_QUIT:
got_signal = 1;
return NAMEMATCH_SKIP;
case NAMEMATCH_SKIP:
return NAMEMATCH_SKIP;
case NAMEMATCH_RENAME:
case NAMEMATCH_PRENAME:
/* We need to rename the file now. This means we must pass
* back through the loop, a) ensuring there isn't a potential
* new name collision, and b) finding a big enough VSE.
* Change the name, so that it won't collide again.
*/
ask_rename(ch, longname, isprimary, name);
return action;
case NAMEMATCH_AUTORENAME:
/* Very similar to NAMEMATCH_RENAME, except that we need to
* first generate the name.
* TODO: Remember previous name so we don't
* keep trying the same one.
*/
if (isprimary) {
autorename_long(name, 1);
return NAMEMATCH_PRENAME;
} else {
autorename_short(name, 1);
return NAMEMATCH_RENAME;
}
case NAMEMATCH_OVERWRITE:
if(no_overwrite)
return NAMEMATCH_SKIP;
else
return NAMEMATCH_OVERWRITE;
default:
return NAMEMATCH_NONE;
}
}
static void clear_scan(char *longname, int use_longname, struct scan_state *s)
{
s->shortmatch = s->longmatch = s->slot = -1;
s->free_end = s->got_slots = s->free_start = 0;
if (use_longname & 1)
s->size_needed = 2 + (strlen(longname)/VSE_NAMELEN);
else
s->size_needed = 1;
}
static int contains_illegals(const char *string, const char *illegals)
{
for(; *string ; string++)
if((*string < ' ' && *string != '\005' && !(*string & 0x80)) ||
strchr(illegals, *string))
return 1;
return 0;
}
static int is_reserved(char *ans, int islong)
{
int i;
static const char *dev3[] = {"CON", "AUX", "PRN", "NUL", " "};
static const char *dev4[] = {"COM", "LPT" };
for (i = 0; i < sizeof(dev3)/sizeof(*dev3); i++)
if (!strncasecmp(ans, dev3[i], 3) &&
((islong && !ans[3]) ||
(!islong && !strncmp(ans+3," ",5))))
return 1;
for (i = 0; i < sizeof(dev4)/sizeof(*dev4); i++)
if (!strncasecmp(ans, dev4[i], 3) &&
(ans[3] >= '1' && ans[3] <= '4') &&
((islong && !ans[4]) ||
(!islong && !strncmp(ans+4," ",4))))
return 1;
return 0;
}
static inline clash_action get_slots(Stream_t *Dir,
char *dosname, char *longname,
struct scan_state *ssp,
ClashHandling_t *ch)
{
int error;
clash_action ret;
int match=0;
direntry_t entry;
int isprimary;
int no_overwrite;
int reason;
int pessimisticShortRename;
pessimisticShortRename = (ch->action[0] == NAMEMATCH_AUTORENAME);
entry.Dir = Dir;
no_overwrite = 1;
if((is_reserved(longname,1)) ||
longname[strspn(longname,". ")] == '\0'){
reason = RESERVED;
isprimary = 1;
} else if(contains_illegals(longname,long_illegals)) {
reason = ILLEGALS;
isprimary = 1;
} else if(is_reserved(dosname,0)) {
reason = RESERVED;
ch->use_longname = 1;
isprimary = 0;
} else if(contains_illegals(dosname,short_illegals)) {
reason = ILLEGALS;
ch->use_longname = 1;
isprimary = 0;
} else {
reason = EXISTS;
clear_scan(longname, ch->use_longname, ssp);
switch (lookupForInsert(Dir, dosname, longname, ssp,
ch->ignore_entry,
ch->source_entry,
pessimisticShortRename &&
ch->use_longname)) {
case -1:
return NAMEMATCH_ERROR;
case 0:
return NAMEMATCH_SKIP;
/* Single-file error error or skip request */
case 5:
return NAMEMATCH_GREW;
/* Grew directory, try again */
case 6:
return NAMEMATCH_SUCCESS; /* Success */
}
match = -2;
if (ssp->longmatch > -1) {
/* Primary Long Name Match */
#ifdef debug
fprintf(stderr,
"Got longmatch=%d for name %s.\n",
longmatch, longname);
#endif
match = ssp->longmatch;
isprimary = 1;
} else if ((ch->use_longname & 1) && (ssp->shortmatch != -1)) {
/* Secondary Short Name Match */
#ifdef debug
fprintf(stderr,
"Got secondary short name match for name %s.\n",
longname);
#endif
match = ssp->shortmatch;
isprimary = 0;
} else if (ssp->shortmatch >= 0) {
/* Primary Short Name Match */
#ifdef debug
fprintf(stderr,
"Got primary short name match for name %s.\n",
longname);
#endif
match = ssp->shortmatch;
isprimary = 1;
} else
return NAMEMATCH_RENAME;
if(match > -1) {
entry.entry = match;
dir_read(&entry, &error);
if (error)
return NAMEMATCH_ERROR;
/* if we can't overwrite, don't propose it */
no_overwrite = (match == ch->source || IS_DIR(&entry));
}
}
ret = process_namematch(isprimary ? longname : dosname, longname,
isprimary, ch, no_overwrite, reason);
if (ret == NAMEMATCH_OVERWRITE && match > -1){
if((entry.dir.attr & 0x5) &&
(ask_confirmation("file is read only, overwrite anyway (y/n) ? ",0,0)))
return NAMEMATCH_RENAME;
/* Free up the file to be overwritten */
if(fatFreeWithDirentry(&entry))
return NAMEMATCH_ERROR;
#if 0
if(isprimary &&
match - ssp->match_free + 1 >= ssp->size_needed){
/* reuse old entry and old short name for overwrite */
ssp->free_start = match - ssp->size_needed + 1;
ssp->free_size = ssp->size_needed;
ssp->slot = match;
ssp->got_slots = 1;
strncpy(dosname, dir.name, 3);
strncpy(dosname + 8, dir.ext, 3);
return ret;
} else
#endif
{
entry.dir.name[0] = DELMARK;
dir_write(&entry);
return NAMEMATCH_RENAME;
}
}
return ret;
}
static inline int write_slots(Stream_t *Dir,
char *dosname,
char *longname,
struct scan_state *ssp,
write_data_callback *cb,
void *arg,
int Case)
{
direntry_t entry;
/* write the file */
if (fat_error(Dir))
return 0;
entry.Dir = Dir;
entry.entry = ssp->slot;
strncpy(entry.name, longname, sizeof(entry.name)-1);
entry.name[sizeof(entry.name)-1]='\0';
entry.dir.Case = Case & (EXTCASE | BASECASE);
if (cb(dosname, longname, arg, &entry) >= 0) {
if ((ssp->size_needed > 1) &&
(ssp->free_end - ssp->free_start >= ssp->size_needed)) {
ssp->slot = write_vfat(Dir, dosname, longname,
ssp->free_start, &entry);
} else {
ssp->size_needed = 1;
write_vfat(Dir, dosname, 0,
ssp->free_start, &entry);
}
/* clear_vses(Dir, ssp->free_start + ssp->size_needed,
ssp->free_end); */
} else
return 0;
return 1; /* Successfully wrote the file */
}
static void stripspaces(char *name)
{
char *p,*non_space;
non_space = name;
for(p=name; *p; p++)
if (*p != ' ')
non_space = p;
if(name[0])
non_space[1] = '\0';
}
int _mwrite_one(Stream_t *Dir,
char *argname,
char *shortname,
write_data_callback *cb,
void *arg,
ClashHandling_t *ch)
{
char longname[VBUFSIZE];
const char *dstname;
char dosname[13];
int expanded;
struct scan_state scan;
clash_action ret;
expanded = 0;
if(isSpecial(argname)) {
fprintf(stderr, "Cannot create entry named . or ..\n");
return -1;
}
if(ch->name_converter == dos_name) {
if(shortname)
stripspaces(shortname);
if(argname)
stripspaces(argname);
}
if(shortname){
ch->name_converter(shortname,0, &ch->use_longname, dosname);
if(ch->use_longname & 1){
/* short name mangled, treat it as a long name */
argname = shortname;
shortname = 0;
}
}
/* Skip drive letter */
dstname = skip_drive(argname);
/* Copy original argument dstname to working value longname */
strncpy(longname, dstname, VBUFSIZE-1);
if(shortname) {
ch->name_converter(shortname,0, &ch->use_longname, dosname);
if(strcmp(shortname, longname))
ch->use_longname |= 1;
} else
ch->name_converter(longname,0, &ch->use_longname, dosname);
ch->action[0] = ch->namematch_default[0];
ch->action[1] = ch->namematch_default[1];
while (1) {
switch((ret=get_slots(Dir, dosname, longname,
&scan, ch))){
case NAMEMATCH_ERROR:
return -1; /* Non-file-specific error,
* quit */
case NAMEMATCH_SKIP:
return -1; /* Skip file (user request or
* error) */
case NAMEMATCH_PRENAME:
ch->name_converter(longname,0,
&ch->use_longname, dosname);
continue;
case NAMEMATCH_RENAME:
continue; /* Renamed file, loop again */
case NAMEMATCH_GREW:
/* No collision, and not enough slots.
* Try to grow the directory
*/
if (expanded) { /* Already tried this
* once, no good */
fprintf(stderr,
"%s: No directory slots\n",
progname);
return -1;
}
expanded = 1;
if (dir_grow(Dir, scan.max_entry))
return -1;
continue;
case NAMEMATCH_OVERWRITE:
case NAMEMATCH_SUCCESS:
return write_slots(Dir, dosname, longname,
&scan, cb, arg,
ch->use_longname);
default:
fprintf(stderr,
"Internal error: clash_action=%d\n",
ret);
return -1;
}
}
}
int mwrite_one(Stream_t *Dir,
const char *_argname,
const char *_shortname,
write_data_callback *cb,
void *arg,
ClashHandling_t *ch)
{
char *argname;
char *shortname;
int ret;
if(_argname)
argname = strdup(_argname);
else
argname = 0;
if(_shortname)
shortname = strdup(_shortname);
else
shortname = 0;
ret = _mwrite_one(Dir, argname, shortname, cb, arg, ch);
if(argname)
free(argname);
if(shortname)
free(shortname);
return ret;
}
void init_clash_handling(ClashHandling_t *ch)
{
ch->ignore_entry = -1;
ch->source_entry = -2;
ch->nowarn = 0; /*Don't ask, just do default action if name collision */
ch->namematch_default[0] = NAMEMATCH_AUTORENAME;
ch->namematch_default[1] = NAMEMATCH_NONE;
ch->name_converter = dos_name; /* changed by mlabel */
ch->source = -2;
}
int handle_clash_options(ClashHandling_t *ch, char c)
{
int isprimary;
if(isupper(c))
isprimary = 0;
else
isprimary = 1;
c = tolower(c);
switch(c) {
case 'o':
/* Overwrite if primary name matches */
ch->namematch_default[isprimary] = NAMEMATCH_OVERWRITE;
return 0;
case 'r':
/* Rename primary name interactively */
ch->namematch_default[isprimary] = NAMEMATCH_RENAME;
return 0;
case 's':
/* Skip file if primary name collides */
ch->namematch_default[isprimary] = NAMEMATCH_SKIP;
return 0;
case 'm':
ch->namematch_default[isprimary] = NAMEMATCH_NONE;
return 0;
case 'a':
ch->namematch_default[isprimary] = NAMEMATCH_AUTORENAME;
return 0;
default:
return -1;
}
}

View file

@ -1,251 +0,0 @@
/*
* mlabel.c
* Make an MSDOS volume label
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mainloop.h"
#include "vfat.h"
#include "mtools.h"
#include "nameclash.h"
char *label_name(char *filename, int verbose,
int *mangled, char *ans)
{
int len;
int i;
int have_lower, have_upper;
strcpy(ans," ");
len = strlen(filename);
if(len > 11){
*mangled = 1;
len = 11;
} else
*mangled = 0;
strncpy(ans, filename, len);
have_lower = have_upper = 0;
for(i=0; i<11; i++){
if(islower((unsigned char)ans[i]))
have_lower = 1;
if(isupper(ans[i]))
have_upper = 1;
ans[i] = toupper((unsigned char)ans[i]);
if(strchr("^+=/[]:,?*\\<>|\".", ans[i])){
*mangled = 1;
ans[i] = '~';
}
}
if (have_lower && have_upper)
*mangled = 1;
return ans;
}
int labelit(char *dosname,
char *longname,
void *arg0,
direntry_t *entry)
{
time_t now;
/* find out current time */
getTimeNow(&now);
mk_entry(dosname, 0x8, 0, 0, now, &entry->dir);
return 0;
}
static void usage(void)
{
fprintf(stderr, "Mtools version %s, dated %s\n",
mversion, mdate);
fprintf(stderr, "Usage: %s [-vscn] [-N serial] drive:[label]\n"
"\t-v Verbose\n"
"\t-s Show label\n"
"\t-c Clear label\n"
"\t-n New random serial number\n"
"\t-N New given serial number\n", progname);
exit(1);
}
void mlabel(int argc, char **argv, int type)
{
char *drive, *newLabel;
int verbose, clear, interactive, show, open_mode;
direntry_t entry;
int result=0;
char longname[VBUFSIZE];
char shortname[13];
ClashHandling_t ch;
struct MainParam_t mp;
Stream_t *RootDir;
int c;
int mangled;
enum { SER_NONE, SER_RANDOM, SER_SET } set_serial = SER_NONE;
long serial = 0;
int need_write_boot = 0;
int have_boot = 0;
char *eptr = "";
struct bootsector boot;
Stream_t *Fs=0;
int r;
struct label_blk_t *labelBlock;
init_clash_handling(&ch);
ch.name_converter = label_name;
ch.ignore_entry = -2;
verbose = 0;
clear = 0;
show = 0;
while ((c = getopt(argc, argv, "vcsnN:")) != EOF) {
switch (c) {
case 'v':
verbose = 1;
break;
case 'c':
clear = 1;
break;
case 's':
show = 1;
break;
case 'n':
set_serial = SER_RANDOM;
srandom((long)time (0));
serial=random();
break;
case 'N':
set_serial = SER_SET;
serial = strtol(optarg, &eptr, 16);
if(*eptr) {
fprintf(stderr,
"%s not a valid serial number\n",
optarg);
exit(1);
}
break;
default:
usage();
}
}
if (argc - optind != 1 || skip_drive(argv[optind]) == argv[optind])
usage();
init_mp(&mp);
newLabel = skip_drive(argv[optind]);
interactive = !show && !clear &&!newLabel[0] &&
(set_serial == SER_NONE);
open_mode = O_RDWR;
drive = get_drive(argv[optind], NULL);
RootDir = open_root_dir(drive, open_mode);
if(strlen(newLabel) > VBUFSIZE) {
fprintf(stderr, "Label too long\n");
FREE(&RootDir);
exit(1);
}
if(!RootDir && open_mode == O_RDWR && !clear && !newLabel[0] &&
( errno == EACCES || errno == EPERM) ) {
show = 1;
interactive = 0;
RootDir = open_root_dir(drive, O_RDONLY);
}
if(!RootDir) {
fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]);
exit(1);
}
initializeDirentry(&entry, RootDir);
r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
shortname, longname);
if (r == -2) {
FREE(&RootDir);
exit(1);
}
if(show || interactive){
if(isNotFound(&entry))
printf(" Volume has no label\n");
else if (*longname)
printf(" Volume label is %s (abbr=%s)\n",
longname, shortname);
else
printf(" Volume label is %s\n", shortname);
}
/* ask for new label */
if(interactive){
newLabel = longname;
fprintf(stderr,"Enter the new volume label : ");
fgets(newLabel, VBUFSIZE, stdin);
if(newLabel[0])
newLabel[strlen(newLabel)-1] = '\0';
}
if((!show || newLabel[0]) && !isNotFound(&entry)){
/* if we have a label, wipe it out before putting new one */
if(interactive && newLabel[0] == '\0')
if(ask_confirmation("Delete volume label (y/n): ",0,0)){
FREE(&RootDir);
exit(0);
}
entry.dir.name[0] = DELMARK;
entry.dir.attr = 0; /* for old mlabel */
dir_write(&entry);
}
if (newLabel[0] != '\0') {
ch.ignore_entry = 1;
result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ?
0 : 1;
}
have_boot = 0;
if( (!show || newLabel[0]) || set_serial != SER_NONE) {
Fs = GetFs(RootDir);
have_boot = (force_read(Fs,(char *)&boot,0,sizeof(boot)) ==
sizeof(boot));
}
if(_WORD(boot.fatlen)) {
labelBlock = &boot.ext.old.labelBlock;
} else {
labelBlock = &boot.ext.fat32.labelBlock;
}
if(!show || newLabel[0]){
if(!newLabel[0])
strncpy(shortname, "NO NAME ",11);
else
label_name(newLabel, verbose, &mangled, shortname);
if(have_boot && boot.descr >= 0xf0 &&
labelBlock->dos4 == 0x29) {
strncpy(labelBlock->label, shortname, 11);
need_write_boot = 1;
}
}
if((set_serial != SER_NONE) & have_boot) {
if(have_boot && boot.descr >= 0xf0 &&
labelBlock->dos4 == 0x29) {
set_dword(labelBlock->serial, serial);
need_write_boot = 1;
}
}
if(need_write_boot) {
force_write(Fs, (char *)&boot, 0, sizeof(boot));
}
FREE(&RootDir);
exit(result);
}

View file

@ -1,174 +0,0 @@
/*
* mmd.c
* Makes an MSDOS directory
*/
#define LOWERCASE
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "mainloop.h"
#include "plain_io.h"
#include "nameclash.h"
#include "file.h"
#include "fs.h"
/*
* Preserve the file modification times after the fclose()
*/
typedef struct Arg_t {
char *target;
MainParam_t mp;
Stream_t *SrcDir;
int entry;
ClashHandling_t ch;
Stream_t *targetDir;
} Arg_t;
typedef struct CreateArg_t {
Stream_t *Dir;
Stream_t *NewDir;
unsigned char attr;
time_t mtime;
} CreateArg_t;
/*
* Open the named file for read, create the cluster chain, return the
* directory structure or NULL on error.
*/
int makeit(char *dosname,
char *longname,
void *arg0,
direntry_t *targetEntry)
{
Stream_t *Target;
CreateArg_t *arg = (CreateArg_t *) arg0;
int fat;
direntry_t subEntry;
/* will it fit? At least one cluster must be free */
if (!getfreeMinClusters(targetEntry->Dir, 1))
return -1;
mk_entry(dosname, ATTR_DIR, 1, 0, arg->mtime, &targetEntry->dir);
Target = OpenFileByDirentry(targetEntry);
if(!Target){
fprintf(stderr,"Could not open Target\n");
return -1;
}
/* this allocates the first cluster for our directory */
initializeDirentry(&subEntry, Target);
subEntry.entry = 1;
GET_DATA(targetEntry->Dir, 0, 0, 0, &fat);
if (fat == fat32RootCluster(targetEntry->Dir)) {
fat = 0;
}
mk_entry(".. ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir);
dir_write(&subEntry);
FLUSH((Stream_t *) Target);
subEntry.entry = 0;
GET_DATA(Target, 0, 0, 0, &fat);
mk_entry(". ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir);
dir_write(&subEntry);
mk_entry(dosname, ATTR_DIR | arg->attr, fat, 0, arg->mtime,
&targetEntry->dir);
arg->NewDir = Target;
return 0;
}
static void usage(void)
{
fprintf(stderr,
"Mtools version %s, dated %s\n", mversion, mdate);
fprintf(stderr,
"Usage: %s [-D clash_option] file targetfile\n", progname);
fprintf(stderr,
" %s [-D clash_option] file [files...] target_directory\n",
progname);
exit(1);
}
Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch,
unsigned char attr, time_t mtime)
{
CreateArg_t arg;
int ret;
arg.Dir = Dir;
arg.attr = attr;
arg.mtime = mtime;
if (!getfreeMinClusters(Dir, 1))
return NULL;
ret = mwrite_one(Dir, filename,0, makeit, &arg, ch);
if(ret < 1)
return NULL;
else
return arg.NewDir;
}
static int createDirCallback(direntry_t *entry, MainParam_t *mp)
{
Stream_t *ret;
time_t now;
ret = createDir(mp->File, mp->targetName, &((Arg_t *)(mp->arg))->ch,
ATTR_DIR, getTimeNow(&now));
if(ret == NULL)
return ERROR_ONE;
else {
FREE(&ret);
return GOT_ONE;
}
}
void mmd(int argc, char **argv, int type)
{
Arg_t arg;
int c;
/* get command line options */
init_clash_handling(& arg.ch);
/* get command line options */
while ((c = getopt(argc, argv, "D:o")) != EOF) {
switch (c) {
case '?':
usage();
case 'o':
handle_clash_options(&arg.ch, c);
break;
case 'D':
if(handle_clash_options(&arg.ch, *optarg))
usage();
break;
default:
break;
}
}
if (argc - optind < 1)
usage();
init_mp(&arg.mp);
arg.mp.arg = (void *) &arg;
arg.mp.openflags = O_RDWR;
arg.mp.callback = createDirCallback;
arg.mp.lookupflags = OPEN_PARENT | DO_OPEN_DIRS;
exit(main_loop(&arg.mp, argv + optind, argc - optind));
}

View file

@ -1,85 +0,0 @@
/*
* Mount an MSDOS disk
*
* written by:
*
* Alain L. Knaff
* alain@linux.lu
*
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#ifdef OS_linux
#include <sys/wait.h>
#include "mainloop.h"
#include "fs.h"
extern int errno;
void mmount(int argc, char **argv, int type)
{
char drive;
int pid;
int status;
struct device dev;
char name[EXPAND_BUF];
int media;
struct bootsector boot;
Stream_t *Stream;
if (argc<2 || !argv[1][0] || argv[1][1] != ':' || argv[1][2]){
fprintf(stderr,"Usage: %s -V drive:\n", argv[0]);
exit(1);
}
drive = toupper(argv[1][0]);
Stream = find_device(drive, O_RDONLY, &dev, &boot, name, &media, 0);
if(!Stream)
exit(1);
FREE(&Stream);
destroy_privs();
if ( dev.partition ) {
char part_name[4];
sprintf(part_name, "%d", dev.partition %1000);
strcat(name, part_name);
}
/* and finally mount it */
switch((pid=fork())){
case -1:
fprintf(stderr,"fork failed\n");
exit(1);
case 0:
close(2);
open("/dev/null", O_RDWR);
argv[1] = strdup("mount");
if ( argc > 2 )
execvp("mount", argv + 1 );
else
execlp("mount", "mount", name, 0);
perror("exec mount");
exit(1);
default:
while ( wait(&status) != pid );
}
if ( WEXITSTATUS(status) == 0 )
exit(0);
argv[0] = strdup("mount");
argv[1] = strdup("-r");
if(!argv[0] || !argv[1]){
printOom();
exit(1);
}
if ( argc > 2 )
execvp("mount", argv);
else
execlp("mount", "mount","-r", name, 0);
exit(1);
}
#endif /* linux */

View file

@ -1,314 +0,0 @@
/*
* mmove.c
* Renames/moves an MSDOS file
*
*/
#define LOWERCASE
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "mainloop.h"
#include "plain_io.h"
#include "nameclash.h"
#include "file.h"
#include "fs.h"
/*
* Preserve the file modification times after the fclose()
*/
typedef struct Arg_t {
const char *fromname;
int verbose;
MainParam_t mp;
direntry_t *entry;
ClashHandling_t ch;
} Arg_t;
/*
* Open the named file for read, create the cluster chain, return the
* directory structure or NULL on error.
*/
int renameit(char *dosname,
char *longname,
void *arg0,
direntry_t *targetEntry)
{
Arg_t *arg = (Arg_t *) arg0;
int fat;
targetEntry->dir = arg->entry->dir;
strncpy(targetEntry->dir.name, dosname, 8);
strncpy(targetEntry->dir.ext, dosname + 8, 3);
if(IS_DIR(targetEntry)) {
direntry_t *movedEntry;
/* get old direntry. It is important that we do this
* on the actual direntry which is stored in the file,
* and not on a copy, because we will modify it, and the
* modification should be visible at file
* de-allocation time */
movedEntry = getDirentry(arg->mp.File);
if(movedEntry->Dir != targetEntry->Dir) {
/* we are indeed moving it to a new directory */
direntry_t subEntry;
Stream_t *oldDir;
/* we have a directory here. Change its parent link */
initializeDirentry(&subEntry, arg->mp.File);
switch(vfat_lookup(&subEntry, "..", 2, ACCEPT_DIR,
NULL, NULL)) {
case -1:
fprintf(stderr,
" Directory has no parent entry\n");
break;
case -2:
return ERROR_ONE;
case 0:
GET_DATA(targetEntry->Dir, 0, 0, 0, &fat);
if (fat == fat32RootCluster(targetEntry->Dir)) {
fat = 0;
}
subEntry.dir.start[1] = (fat >> 8) & 0xff;
subEntry.dir.start[0] = fat & 0xff;
dir_write(&subEntry);
if(arg->verbose){
fprintf(stderr,
"Easy, isn't it? I wonder why DOS can't do this.\n");
}
break;
}
/* wipe out original entry */
movedEntry->dir.name[0] = DELMARK;
dir_write(movedEntry);
/* free the old parent, allocate the new one. */
oldDir = movedEntry->Dir;
*movedEntry = *targetEntry;
COPY(targetEntry->Dir);
FREE(&oldDir);
return 0;
}
}
/* wipe out original entry */
arg->mp.direntry->dir.name[0] = DELMARK;
dir_write(arg->mp.direntry);
return 0;
}
static int rename_file(direntry_t *entry, MainParam_t *mp)
/* rename a messy DOS file to another messy DOS file */
{
int result;
Stream_t *targetDir;
char *shortname;
const char *longname;
Arg_t * arg = (Arg_t *) (mp->arg);
arg->entry = entry;
targetDir = mp->targetDir;
if (targetDir == entry->Dir){
arg->ch.ignore_entry = -1;
arg->ch.source = entry->entry;
arg->ch.source_entry = entry->entry;
} else {
arg->ch.ignore_entry = -1;
arg->ch.source = -2;
}
longname = mpPickTargetName(mp);
shortname = 0;
result = mwrite_one(targetDir, longname, shortname,
renameit, (void *)arg, &arg->ch);
if(result == 1)
return GOT_ONE;
else
return ERROR_ONE;
}
static int rename_directory(direntry_t *entry, MainParam_t *mp)
{
int ret;
/* moves a DOS dir */
if(isSubdirOf(mp->targetDir, mp->File)) {
fprintf(stderr, "Cannot move directory ");
fprintPwd(stderr, entry,0);
fprintf(stderr, " into one of its own subdirectories (");
fprintPwd(stderr, getDirentry(mp->targetDir),0);
fprintf(stderr, ")\n");
return ERROR_ONE;
}
if(entry->entry == -3) {
fprintf(stderr, "Cannot move a root directory: ");
fprintPwd(stderr, entry,0);
return ERROR_ONE;
}
ret = rename_file(entry, mp);
if(ret & ERROR_ONE)
return ret;
return ret;
}
static int rename_oldsyntax(direntry_t *entry, MainParam_t *mp)
{
int result;
Stream_t *targetDir;
const char *shortname, *longname;
Arg_t * arg = (Arg_t *) (mp->arg);
arg->entry = entry;
targetDir = entry->Dir;
arg->ch.ignore_entry = -1;
arg->ch.source = entry->entry;
arg->ch.source_entry = entry->entry;
#if 0
if(!strcasecmp(mp->shortname, arg->fromname)){
longname = mp->longname;
shortname = mp->targetName;
} else {
#endif
longname = mp->targetName;
shortname = 0;
#if 0
}
#endif
result = mwrite_one(targetDir, longname, shortname,
renameit, (void *)arg, &arg->ch);
if(result == 1)
return GOT_ONE;
else
return ERROR_ONE;
}
static void usage(void)
{
fprintf(stderr,
"Mtools version %s, dated %s\n", mversion, mdate);
fprintf(stderr,
"Usage: %s [-vo] [-D clash_option] file targetfile\n", progname);
fprintf(stderr,
" %s [-vo] [-D clash_option] file [files...] target_directory\n",
progname);
fprintf(stderr, "\t-v Verbose\n");
exit(1);
}
void mmove(int argc, char **argv, int oldsyntax)
{
Arg_t arg;
int c;
char shortname[13];
char longname[VBUFSIZE];
char *def_drive;
int i;
/* get command line options */
init_clash_handling(& arg.ch);
/* get command line options */
arg.verbose = 0;
while ((c = getopt(argc, argv, "vD:o")) != EOF) {
switch (c) {
case 'v': /* dummy option for mcopy */
arg.verbose = 1;
break;
case '?':
usage();
case 'o':
handle_clash_options(&arg.ch, c);
break;
case 'D':
if(handle_clash_options(&arg.ch, *optarg))
usage();
break;
default:
break;
}
}
if (argc - optind < 2)
usage();
init_mp(&arg.mp);
arg.mp.arg = (void *) &arg;
arg.mp.openflags = O_RDWR;
/* look for a default drive */
def_drive = NULL;
for(i=optind; i<argc; i++)
if(skip_drive(argv[i]) > argv[i]){
char *drive = get_drive(argv[i], NULL);
if(!def_drive)
def_drive = drive;
else if(strcmp(def_drive, drive) != 0){
fprintf(stderr,
"Cannot move files across different drives\n");
exit(1);
}
}
if(def_drive) {
char mcwd[MAXPATHLEN];
strcpy(mcwd, skip_drive(arg.mp.mcwd));
if(strlen(def_drive) + 1 + strlen(mcwd) + 1 > MAXPATHLEN){
fprintf(stderr,
"Path name to current directory too long\n");
exit(1);
}
strcpy(arg.mp.mcwd, def_drive);
strcat(arg.mp.mcwd, ":");
strcat(arg.mp.mcwd, mcwd);
}
if (oldsyntax && (argc - optind != 2 || strpbrk(":/", argv[argc-1])))
oldsyntax = 0;
arg.mp.lookupflags =
ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS | NO_UNIX;
if (!oldsyntax){
target_lookup(&arg.mp, argv[argc-1]);
arg.mp.callback = rename_file;
arg.mp.dirCallback = rename_directory;
} else {
/* do not look up the target; it will be the same dir as the
* source */
arg.fromname = _basename(skip_drive(argv[optind]));
arg.mp.targetName = strdup(argv[argc-1]);
arg.mp.callback = rename_oldsyntax;
}
arg.mp.longname = longname;
longname[0]='\0';
arg.mp.shortname = shortname;
shortname[0]='\0';
exit(main_loop(&arg.mp, argv + optind, argc - optind - 1));
}

View file

@ -1,706 +0,0 @@
/*
* mformat.c
*/
#define DONT_NEED_WAIT
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "mainloop.h"
#include "fsP.h"
#include "file.h"
#include "plain_io.h"
#include "nameclash.h"
#include "buffer.h"
#include "scsi.h"
#include "partition.h"
#ifdef OS_linux
#include "linux/hdreg.h"
#define _LINUX_STRING_H_
#define kdev_t int
#include "linux/fs.h"
#undef _LINUX_STRING_H_
#endif
#define tolinear(x) \
(sector(x)-1+(head(x)+cyl(x)*used_dev->heads)*used_dev->sectors)
static inline void print_hsc(hsc *h)
{
printf(" h=%d s=%d c=%d\n",
head(*h), sector(*h), cyl(*h));
}
static void set_offset(hsc *h, int offset, int heads, int sectors)
{
int head, sector, cyl;
if(! heads || !sectors)
head = sector = cyl = 0; /* linear mode */
else {
sector = offset % sectors;
offset = offset / sectors;
head = offset % heads;
cyl = offset / heads;
if(cyl > 1023) cyl = 1023;
}
h->head = head;
h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2);
h->cyl = cyl & 0xff;
}
void setBeginEnd(struct partition *partTable, int begin, int end,
int heads, int sectors, int activate, int type)
{
set_offset(&partTable->start, begin, heads, sectors);
set_offset(&partTable->end, end-1, heads, sectors);
set_dword(partTable->start_sect, begin);
set_dword(partTable->nr_sects, end-begin);
if(activate)
partTable->boot_ind = 0x80;
else
partTable->boot_ind = 0;
if(!type) {
if(end-begin < 4096)
type = 1; /* DOS 12-bit FAT */
else if(end-begin<32*2048)
type = 4; /* DOS 16-bit FAT, <32M */
else
type = 6; /* DOS 16-bit FAT >= 32M */
}
partTable->sys_ind = type;
}
int consistencyCheck(struct partition *partTable, int doprint, int verbose,
int *has_activated, int *last_end, int *j,
struct device *used_dev, int target_partition)
{
int i;
int inconsistency;
*j = 0;
*last_end = 1;
/* quick consistency check */
inconsistency = 0;
*has_activated = 0;
for(i=1; i<5; i++){
if(!partTable[i].sys_ind)
continue;
if(partTable[i].boot_ind)
(*has_activated)++;
if((used_dev &&
(used_dev->heads != head(partTable[i].end)+1 ||
used_dev->sectors != sector(partTable[i].end))) ||
sector(partTable[i].start) != 1){
fprintf(stderr,
"Partition %d is not aligned\n",
i);
inconsistency=1;
}
if(*j && *last_end > BEGIN(partTable[i])) {
fprintf(stderr,
"Partitions %d and %d badly ordered or overlapping\n",
*j,i);
inconsistency=1;
}
*last_end = END(partTable[i]);
*j = i;
if(used_dev &&
cyl(partTable[i].start) != 1023 &&
tolinear(partTable[i].start) != BEGIN(partTable[i])) {
fprintf(stderr,
"Start position mismatch for partition %d\n",
i);
inconsistency=1;
}
if(used_dev &&
cyl(partTable[i].end) != 1023 &&
tolinear(partTable[i].end)+1 != END(partTable[i])) {
fprintf(stderr,
"End position mismatch for partition %d\n",
i);
inconsistency=1;
}
if(doprint && verbose) {
if(i==target_partition)
putchar('*');
else
putchar(' ');
printf("Partition %d\n",i);
printf(" active=%x\n", partTable[i].boot_ind);
printf(" start:");
print_hsc(&partTable[i].start);
printf(" type=0x%x\n", partTable[i].sys_ind);
printf(" end:");
print_hsc(&partTable[i].end);
printf(" start=%d\n", BEGIN(partTable[i]));
printf(" nr=%d\n", _DWORD(partTable[i].nr_sects));
printf("\n");
}
}
return inconsistency;
}
/* setsize function. Determines scsicam mapping if this cannot be inferred from
* any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */
/*
* Function : static int setsize(unsigned long capacity,unsigned int *cyls,
* unsigned int *hds, unsigned int *secs);
*
* Purpose : to determine a near-optimal int 0x13 mapping for a
* SCSI disk in terms of lost space of size capacity, storing
* the results in *cyls, *hds, and *secs.
*
* Returns : -1 on failure, 0 on success.
*
* Extracted from
*
* WORKING X3T9.2
* DRAFT 792D
*
*
* Revision 6
* 10-MAR-94
* Information technology -
* SCSI-2 Common access method
* transport and SCSI interface module
*
* ANNEX A :
*
* setsize() converts a read capacity value to int 13h
* head-cylinder-sector requirements. It minimizes the value for
* number of heads and maximizes the number of cylinders. This
* will support rather large disks before the number of heads
* will not fit in 4 bits (or 6 bits). This algorithm also
* minimizes the number of sectors that will be unused at the end
* of the disk while allowing for very large disks to be
* accommodated. This algorithm does not use physical geometry.
*/
static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
unsigned int *secs) {
unsigned int rv = 0;
unsigned long heads, sectors, cylinders, temp;
cylinders = 1024L; /* Set number of cylinders to max */
sectors = 62L; /* Maximize sectors per track */
temp = cylinders * sectors; /* Compute divisor for heads */
heads = capacity / temp; /* Compute value for number of heads */
if (capacity % temp) { /* If no remainder, done! */
heads++; /* Else, increment number of heads */
temp = cylinders * heads; /* Compute divisor for sectors */
sectors = capacity / temp; /* Compute value for sectors per
track */
if (capacity % temp) { /* If no remainder, done! */
sectors++; /* Else, increment number of sectors */
temp = heads * sectors; /* Compute divisor for cylinders */
cylinders = capacity / temp;/* Compute number of cylinders */
}
}
if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */
*cyls = (unsigned int) cylinders; /* Stuff return values */
*secs = (unsigned int) sectors;
*hds = (unsigned int) heads;
return(rv);
}
static void setsize0(unsigned long capacity,unsigned int *cyls,
unsigned int *hds, unsigned int *secs)
{
int r;
/* 1. First try "Megabyte" sizes */
if(capacity < 1024 * 2048 && !(capacity % 1024)) {
*cyls = capacity >> 11;
*hds = 64;
*secs = 32;
return;
}
/* then try scsicam's size */
r = setsize(capacity,cyls,hds,secs);
if(r || *hds > 255 || *secs > 63) {
/* scsicam failed. Do megabytes anyways */
*cyls = capacity >> 11;
*hds = 64;
*secs = 32;
return;
}
}
static void usage(void)
{
fprintf(stderr,
"Mtools version %s, dated %s\n", mversion, mdate);
fprintf(stderr,
"Usage: %s [-pradcv] [-I [-B bootsect-template] [-s sectors] "
"[-t cylinders] "
"[-h heads] [-T type] [-b begin] [-l length] "
"drive\n", progname);
exit(1);
}
void mpartition(int argc, char **argv, int dummy)
{
Stream_t *Stream;
unsigned int dummy2;
int i,j;
int sec_per_cyl;
int doprint = 0;
int verbose = 0;
int create = 0;
int force = 0;
int length = 0;
int remove = 0;
int initialize = 0;
int tot_sectors=0;
int type = 0;
int begin_set = 0;
int size_set = 0;
int end_set = 0;
int last_end = 0;
int activate = 0;
int has_activated = 0;
int inconsistency=0;
int begin=0;
int end=0;
int sizetest=0;
int dirty = 0;
int open2flags = NO_OFFSET;
int c;
struct device used_dev;
int argtracks, argheads, argsectors;
char *drive, name[EXPAND_BUF];
unsigned char buf[512];
struct partition *partTable=(struct partition *)(buf+ 0x1ae);
struct device *dev;
char errmsg[200];
char *bootSector=0;
argtracks = 0;
argheads = 0;
argsectors = 0;
/* get command line options */
while ((c = getopt(argc, argv, "adprcIT:t:h:s:fvpb:l:S:B:")) != EOF) {
switch (c) {
case 'B':
bootSector = optarg;
break;
case 'a':
/* no privs, as it could be abused to
* make other partitions unbootable, or
* to boot a rogue kernel from this one */
open2flags |= NO_PRIV;
activate = 1;
dirty = 1;
break;
case 'd':
activate = -1;
dirty = 1;
break;
case 'p':
doprint = 1;
break;
case 'r':
remove = 1;
dirty = 1;
break;
case 'I':
/* could be abused to nuke all other
* partitions */
open2flags |= NO_PRIV;
initialize = 1;
dirty = 1;
break;
case 'c':
create = 1;
dirty = 1;
break;
case 'T':
/* could be abused to "manually" create
* extended partitions */
open2flags |= NO_PRIV;
type = strtoul(optarg,0,0);
break;
case 't':
argtracks = atoi(optarg);
break;
case 'h':
argheads = atoi(optarg);
break;
case 's':
argsectors = atoi(optarg);
break;
case 'f':
/* could be abused by creating overlapping
* partitions and other such Snafu */
open2flags |= NO_PRIV;
force = 1;
break;
case 'v':
verbose++;
break;
case 'S':
/* testing only */
/* could be abused to create partitions
* extending beyond the actual size of the
* device */
open2flags |= NO_PRIV;
tot_sectors = strtoul(optarg,0,0);
sizetest = 1;
break;
case 'b':
begin_set = 1;
begin = atoi(optarg);
break;
case 'l':
size_set = 1;
length = atoi(optarg);
break;
default:
usage();
}
}
if (argc - optind != 1 || skip_drive(argv[optind]) == argv[optind])
usage();
drive = get_drive(argv[optind], NULL);
/* check out a drive whose letter and parameters match */
sprintf(errmsg, "Drive '%s:' not supported", drive);
Stream = 0;
for(dev=devices;dev->drive;dev++) {
FREE(&(Stream));
/* drive letter */
if (strcmp(dev->drive, drive) != 0)
continue;
if (dev->partition < 1 || dev->partition > 4) {
sprintf(errmsg,
"Drive '%c:' is not a partition",
drive);
continue;
}
used_dev = *dev;
SET_INT(used_dev.tracks, argtracks);
SET_INT(used_dev.heads, argheads);
SET_INT(used_dev.sectors, argsectors);
expand(dev->name, name);
Stream = SimpleFileOpen(&used_dev, dev, name,
dirty ? O_RDWR : O_RDONLY,
errmsg, open2flags, 1, 0);
if (!Stream) {
#ifdef HAVE_SNPRINTF
snprintf(errmsg,199,"init: open: %s", strerror(errno));
#else
sprintf(errmsg,"init: open: %s", strerror(errno));
#endif
continue;
}
/* try to find out the size */
if(!sizetest)
tot_sectors = 0;
if(IS_SCSI(dev)) {
unsigned char cmd[10];
unsigned char data[10];
cmd[0] = SCSI_READ_CAPACITY;
memset ((void *) &cmd[2], 0, 8);
memset ((void *) &data[0], 137, 10);
scsi_cmd(get_fd(Stream), cmd, 10, SCSI_IO_READ,
data, 10, get_extra_data(Stream));
tot_sectors = 1 +
(data[0] << 24) +
(data[1] << 16) +
(data[2] << 8) +
(data[3] );
if(verbose)
printf("%d sectors in total\n", tot_sectors);
}
#ifdef OS_linux
if (tot_sectors == 0) {
ioctl(get_fd(Stream), BLKGETSIZE, &tot_sectors);
}
#endif
/* read the partition table */
if (READS(Stream, (char *) buf, 0, 512) != 512) {
#ifdef HAVE_SNPRINTF
snprintf(errmsg, 199,
"Error reading from '%s', wrong parameters?",
name);
#else
sprintf(errmsg,
"Error reading from '%s', wrong parameters?",
name);
#endif
continue;
}
if(verbose>=2)
print_sector("Read sector", buf, 512);
break;
}
/* print error msg if needed */
if ( dev->drive == 0 ){
FREE(&Stream);
fprintf(stderr,"%s: %s\n", argv[0],errmsg);
exit(1);
}
if((used_dev.sectors || used_dev.heads) &&
(!used_dev.sectors || !used_dev.heads)) {
fprintf(stderr,"You should either indicate both the number of sectors and the number of heads,\n");
fprintf(stderr," or none of them\n");
exit(1);
}
if(initialize) {
if (bootSector) {
int fd;
fd = open(bootSector, O_RDONLY);
if (fd < 0) {
perror("open boot sector");
exit(1);
}
read(fd, (char *) buf, 512);
}
memset((char *)(partTable+1), 0, 4*sizeof(*partTable));
set_dword(((unsigned char*)buf)+510, 0xaa55);
}
/* check for boot signature, and place it if needed */
if((buf[510] != 0x55) || (buf[511] != 0xaa)) {
fprintf(stderr,"Boot signature not set\n");
fprintf(stderr,
"Use the -I flag to initialize the partition table, and set the boot signature\n");
inconsistency = 1;
}
if(remove){
if(!partTable[dev->partition].sys_ind)
fprintf(stderr,
"Partition for drive %c: does not exist\n",
drive);
if((partTable[dev->partition].sys_ind & 0x3f) == 5) {
fprintf(stderr,
"Partition for drive %c: may be an extended partition\n",
drive);
fprintf(stderr,
"Use the -f flag to remove it anyways\n");
inconsistency = 1;
}
memset(&partTable[dev->partition], 0, sizeof(*partTable));
}
if(create && partTable[dev->partition].sys_ind) {
fprintf(stderr,
"Partition for drive %c: already exists\n", drive);
fprintf(stderr,
"Use the -r flag to remove it before attempting to recreate it\n");
}
/* find out number of heads and sectors, and whether there is
* any activated partition */
has_activated = 0;
for(i=1; i<5; i++){
if(!partTable[i].sys_ind)
continue;
if(partTable[i].boot_ind)
has_activated++;
/* set geometry from entry */
if (!used_dev.heads)
used_dev.heads = head(partTable[i].end)+1;
if(!used_dev.sectors)
used_dev.sectors = sector(partTable[i].end);
if(i<dev->partition && !begin_set)
begin = END(partTable[i]);
if(i>dev->partition && !end_set && !size_set) {
end = BEGIN(partTable[i]);
end_set = 1;
}
}
#ifdef OS_linux
if(!used_dev.sectors && !used_dev.heads) {
if(!IS_SCSI(dev)) {
struct hd_geometry geom;
if(ioctl(get_fd(Stream), HDIO_GETGEO, &geom) == 0) {
used_dev.heads = geom.heads;
used_dev.sectors = geom.sectors;
}
}
}
#endif
if(!used_dev.sectors && !used_dev.heads) {
if(tot_sectors)
setsize0(tot_sectors,&dummy2,&used_dev.heads,
&used_dev.sectors);
else {
used_dev.heads = 64;
used_dev.sectors = 32;
}
}
if(verbose)
fprintf(stderr,"sectors: %d heads: %d %d\n",
used_dev.sectors, used_dev.heads, tot_sectors);
sec_per_cyl = used_dev.sectors * used_dev.heads;
if(create) {
if(!end_set && tot_sectors) {
end = tot_sectors - tot_sectors % sec_per_cyl;
end_set = 1;
}
/* if the partition starts right at the beginning of
* the disk, keep one track unused to allow place for
* the master boot record */
if(!begin && !begin_set)
begin = used_dev.sectors;
if(!size_set && used_dev.tracks) {
size_set = 2;
length = sec_per_cyl * used_dev.tracks;
/* round the size in order to take
* into account any "hidden" sectors */
/* do we anchor this at the beginning ?*/
if(begin_set || dev->partition <= 2 || !end_set)
length -= begin % sec_per_cyl;
else if(end - length < begin)
/* truncate any overlap */
length = end - begin;
}
if(size_set) {
if(!begin_set && dev->partition >2 && end_set)
begin = end - length;
else
end = begin + length;
} else if(!end_set) {
fprintf(stderr,"Unknown size\n");
exit(1);
}
setBeginEnd(&partTable[dev->partition], begin, end,
used_dev.heads, used_dev.sectors,
!has_activated, type);
}
if(activate) {
if(!partTable[dev->partition].sys_ind) {
fprintf(stderr,
"Partition for drive %c: does not exist\n",
drive);
} else {
switch(activate) {
case 1:
partTable[dev->partition].boot_ind=0x80;
break;
case -1:
partTable[dev->partition].boot_ind=0x00;
break;
}
}
}
inconsistency |= consistencyCheck(partTable, doprint, verbose,
&has_activated, &last_end, &j,
&used_dev, dev->partition);
if(doprint && !inconsistency && partTable[dev->partition].sys_ind) {
printf("The following command will recreate the partition for drive %c:\n",
drive);
used_dev.tracks =
(_DWORD(partTable[dev->partition].nr_sects) +
(BEGIN(partTable[dev->partition]) % sec_per_cyl)) /
sec_per_cyl;
printf("mpartition -c -t %d -h %d -s %d -b %u %c:\n",
used_dev.tracks, used_dev.heads, used_dev.sectors,
BEGIN(partTable[dev->partition]), drive);
}
if(tot_sectors && last_end >tot_sectors) {
fprintf(stderr,
"Partition %d exceeds beyond end of disk\n",
j);
exit(1);
}
switch(has_activated) {
case 0:
fprintf(stderr,
"Warning: no active (bootable) partition present\n");
break;
case 1:
break;
default:
fprintf(stderr,
"Warning: %d active (bootable) partitions present\n",
has_activated);
fprintf(stderr,
"Usually, a disk should have exactly one active partition\n");
break;
}
if(inconsistency && !force) {
fprintf(stderr,
"inconsistency detected!\n" );
if(dirty)
fprintf(stderr,
"Retry with the -f switch to go ahead anyways\n");
exit(1);
}
if(dirty) {
/* write data back to the disk */
if(verbose>=2)
print_sector("Writing sector", buf, 512);
if (WRITES(Stream, (char *) buf, 0, 512) != 512) {
fprintf(stderr,"Error writing partition table");
exit(1);
}
if(verbose>=3)
print_sector("Sector written", buf, 512);
FREE(&Stream);
}
exit(0);
}

View file

@ -1,237 +0,0 @@
#ifndef MTOOLS_MSDOS_H
#define MTOOLS_MSDOS_H
/*
* msdos common header file
*/
#define MAX_SECTOR 8192 /* largest sector size */
#define MDIR_SIZE 32 /* MSDOS directory entry size in bytes*/
#define MAX_CLUSTER 8192 /* largest cluster size */
#define MAX_PATH 128 /* largest MSDOS path length */
#define MAX_DIR_SECS 64 /* largest directory (in sectors) */
#define MSECTOR_SIZE msector_size
#define NEW 1
#define OLD 0
#define _WORD(x) ((unsigned char)(x)[0] + (((unsigned char)(x)[1]) << 8))
#define _DWORD(x) (_WORD(x) + (_WORD((x)+2) << 16))
#define DELMARK ((char) 0xe5)
struct directory {
char name[8]; /* 0 file name */
char ext[3]; /* 8 file extension */
unsigned char attr; /* 11 attribute byte */
unsigned char Case; /* 12 case of short filename */
unsigned char ctime_ms; /* 13 creation time, milliseconds (?) */
unsigned char ctime[2]; /* 14 creation time */
unsigned char cdate[2]; /* 16 creation date */
unsigned char adate[2]; /* 18 last access date */
unsigned char startHi[2]; /* 20 start cluster, Hi */
unsigned char time[2]; /* 22 time stamp */
unsigned char date[2]; /* 24 date stamp */
unsigned char start[2]; /* 26 starting cluster number */
unsigned char size[4]; /* 28 size of the file */
};
#define EXTCASE 0x10
#define BASECASE 0x8
#define MAX32 0xffffffff
#define MAX_SIZE 0x7fffffff
#define FILE_SIZE(dir) (_DWORD((dir)->size))
#define START(dir) (_WORD((dir)->start))
#define STARTHI(dir) (_WORD((dir)->startHi))
/* ASSUMPTION: long is at least 32 bits */
UNUSED(static inline void set_dword(unsigned char *data, unsigned long value))
{
data[3] = (value >> 24) & 0xff;
data[2] = (value >> 16) & 0xff;
data[1] = (value >> 8) & 0xff;
data[0] = (value >> 0) & 0xff;
}
/* ASSUMPTION: short is at least 16 bits */
UNUSED(static inline void set_word(unsigned char *data, unsigned short value))
{
data[1] = (value >> 8) & 0xff;
data[0] = (value >> 0) & 0xff;
}
/*
* hi byte | low byte
* |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
* | | | | | | | | | | | | | | | | |
* \ 7 bits /\4 bits/\ 5 bits /
* year +80 month day
*/
#define DOS_YEAR(dir) (((dir)->date[1] >> 1) + 1980)
#define DOS_MONTH(dir) (((((dir)->date[1]&0x1) << 3) + ((dir)->date[0] >> 5)))
#define DOS_DAY(dir) ((dir)->date[0] & 0x1f)
/*
* hi byte | low byte
* |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
* | | | | | | | | | | | | | | | | |
* \ 5 bits /\ 6 bits /\ 5 bits /
* hour minutes sec*2
*/
#define DOS_HOUR(dir) ((dir)->time[1] >> 3)
#define DOS_MINUTE(dir) (((((dir)->time[1]&0x7) << 3) + ((dir)->time[0] >> 5)))
#define DOS_SEC(dir) (((dir)->time[0] & 0x1f) * 2)
typedef struct InfoSector_t {
unsigned char signature1[4];
unsigned char filler1[0x1e0];
unsigned char signature2[4];
unsigned char count[4];
unsigned char pos[4];
unsigned char filler2[14];
unsigned char signature3[2];
} InfoSector_t;
#define INFOSECT_SIGNATURE1 0x41615252
#define INFOSECT_SIGNATURE2 0x61417272
typedef struct label_blk_t {
unsigned char physdrive; /* 36 physical drive ? */
unsigned char reserved; /* 37 reserved */
unsigned char dos4; /* 38 dos > 4.0 diskette */
unsigned char serial[4]; /* 39 serial number */
char label[11]; /* 43 disk label */
char fat_type[8]; /* 54 FAT type */
} label_blk_t;
/* FAT32 specific info in the bootsector */
typedef struct fat32_t {
unsigned char bigFat[4]; /* 36 nb of sectors per FAT */
unsigned char extFlags[2]; /* 40 extension flags */
unsigned char fsVersion[2]; /* 42 ? */
unsigned char rootCluster[4]; /* 44 start cluster of root dir */
unsigned char infoSector[2]; /* 48 changeable global info */
unsigned char backupBoot[2]; /* 50 back up boot sector */
unsigned char reserved[6]; /* 52 ? */
unsigned char reserved2[6]; /* 52 ? */
struct label_blk_t labelBlock;
} fat32; /* ends at 58 */
typedef struct oldboot_t {
struct label_blk_t labelBlock;
unsigned char res_2m; /* 62 reserved by 2M */
unsigned char CheckSum; /* 63 2M checksum (not used) */
unsigned char fmt_2mf; /* 64 2MF format version */
unsigned char wt; /* 65 1 if write track after format */
unsigned char rate_0; /* 66 data transfer rate on track 0 */
unsigned char rate_any; /* 67 data transfer rate on track<>0 */
unsigned char BootP[2]; /* 68 offset to boot program */
unsigned char Infp0[2]; /* 70 T1: information for track 0 */
unsigned char InfpX[2]; /* 72 T2: information for track<>0 */
unsigned char InfTm[2]; /* 74 T3: track sectors size table */
unsigned char DateF[2]; /* 76 Format date */
unsigned char TimeF[2]; /* 78 Format time */
unsigned char junk[1024 - 80]; /* 80 remaining data */
} oldboot_t;
struct bootsector {
unsigned char jump[3]; /* 0 Jump to boot code */
char banner[8] PACKED; /* 3 OEM name & version */
unsigned char secsiz[2] PACKED; /* 11 Bytes per sector hopefully 512 */
unsigned char clsiz; /* 13 Cluster size in sectors */
unsigned char nrsvsect[2]; /* 14 Number of reserved (boot) sectors */
unsigned char nfat; /* 16 Number of FAT tables hopefully 2 */
unsigned char dirents[2] PACKED;/* 17 Number of directory slots */
unsigned char psect[2] PACKED; /* 19 Total sectors on disk */
unsigned char descr; /* 21 Media descriptor=first byte of FAT */
unsigned char fatlen[2]; /* 22 Sectors in FAT */
unsigned char nsect[2]; /* 24 Sectors/track */
unsigned char nheads[2]; /* 26 Heads */
unsigned char nhs[4]; /* 28 number of hidden sectors */
unsigned char bigsect[4]; /* 32 big total sectors */
union {
struct fat32_t fat32;
struct oldboot_t old;
} ext;
};
#define CHAR(x) (boot->x[0])
#define WORD(x) (_WORD(boot->x))
#define DWORD(x) (_DWORD(boot->x))
#define OFFSET(x) (((char *) (boot->x)) - ((char *)(boot->jump)))
extern struct OldDos_t {
int tracks;
int sectors;
int heads;
int dir_len;
int cluster_size;
int fat_len;
int media;
} old_dos[];
#define FAT12 4085 /* max. number of clusters described by a 12 bit FAT */
#define FAT16 65525
#define ATTR_ARCHIVE 0x20
#define ATTR_DIR 0x10
#define ATTR_LABEL 0x8
#define ATTR_SYSTEM 0x4
#define ATTR_HIDDEN 0x2
#define ATTR_READONLY 0x1
#define HAS_BIT(entry,x) ((entry)->dir.attr & (x))
#define IS_ARCHIVE(entry) (HAS_BIT((entry),ATTR_ARCHIVE))
#define IS_DIR(entry) (HAS_BIT((entry),ATTR_DIR))
#define IS_LABEL(entry) (HAS_BIT((entry),ATTR_LABEL))
#define IS_SYSTEM(entry) (HAS_BIT((entry),ATTR_SYSTEM))
#define IS_HIDDEN(entry) (HAS_BIT((entry),ATTR_HIDDEN))
#define IS_READONLY(entry) (HAS_BIT((entry),ATTR_READONLY))
#define MAX_SECT_PER_CLUSTER 64
/* Experimentally, it turns out that DOS only accepts cluster sizes
* which are powers of two, and less than 128 sectors (else it gets a
* divide overflow) */
#define FAT_SIZE(bits, sec_siz, clusters) \
((((clusters)+2) * ((bits)/4) - 1) / 2 / (sec_siz) + 1)
#define NEEDED_FAT_SIZE(x) FAT_SIZE((x)->fat_bits, (x)->sector_size, \
(x)->num_clus)
/* disk size taken by FAT and clusters */
#define DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) \
((n) * FAT_SIZE(bits, sec_siz, clusters) + \
(clusters) * (cluster_size))
#define TOTAL_DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) \
(DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) + 2)
/* approx. total disk size: assume 1 boot sector and one directory sector */
extern const char *mversion;
extern const char *mdate;
extern char *Version;
extern char *Date;
int init(char drive, int mode);
#define MT_READ 1
#define MT_WRITE 2
#endif

View file

@ -1,87 +0,0 @@
/*
* mcopy.c
* Copy an MSDOS files to and from Unix
*
*/
#define LOWERCASE
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "mainloop.h"
#include "plain_io.h"
#include "nameclash.h"
#include "file.h"
#include "fs.h"
typedef struct Arg_t {
char *target;
MainParam_t mp;
ClashHandling_t ch;
Stream_t *sourcefile;
} Arg_t;
static int dos_showfat(direntry_t *entry, MainParam_t *mp)
{
Stream_t *File=mp->File;
fprintPwd(stdout, entry,0);
putchar(' ');
printFat(File);
printf("\n");
return GOT_ONE;
}
static int unix_showfat(MainParam_t *mp)
{
fprintf(stderr,"File does not reside on a Dos fs\n");
return ERROR_ONE;
}
static void usage(void)
{
fprintf(stderr,
"Mtools version %s, dated %s\n", mversion, mdate);
fprintf(stderr,
"Usage: %s file ...\n", progname);
exit(1);
}
void mshowfat(int argc, char **argv, int mtype)
{
Arg_t arg;
int c, ret;
/* get command line options */
init_clash_handling(& arg.ch);
/* get command line options */
while ((c = getopt(argc, argv, "")) != EOF) {
switch (c) {
case '?':
usage();
break;
}
}
if (argc - optind < 1)
usage();
/* only 1 file to copy... */
init_mp(&arg.mp);
arg.mp.arg = (void *) &arg;
arg.mp.callback = dos_showfat;
arg.mp.unixcallback = unix_showfat;
arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN;
ret=main_loop(&arg.mp, argv + optind, argc - optind);
exit(ret);
}

View file

@ -1,186 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "partition.h"
#include "vfat.h"
const char *progname;
static const struct dispatch {
const char *cmd;
void (*fn)(int, char **, int);
int type;
} dispatch[] = {
{"attrib",mattrib, 0},
{"badblocks",mbadblocks, 0},
{"cat",mcat, 0},
{"cd",mcd, 0},
{"copy",mcopy, 0},
{"del",mdel, 0},
{"deltree",mdel, 2},
{"dir",mdir, 0},
{"doctorfat",mdoctorfat, 0},
{"du",mdu, 0},
{"format",mformat, 0},
{"info", minfo, 0},
{"label",mlabel, 0},
{"md",mmd, 0},
{"mkdir",mmd, 0},
#ifdef OS_linux
{"mount",mmount, 0},
#endif
{"partition",mpartition, 0},
{"rd",mdel, 1},
{"rmdir",mdel, 1},
{"read",mcopy, 0},
{"move",mmove, 0},
{"ren",mmove, 1},
{"showfat", mshowfat, 0},
#ifndef NO_CONFIG
{"toolstest", mtoolstest, 0},
#endif
{"type",mcopy, 1},
{"write",mcopy, 0},
#ifndef OS_Minix
{"zip", mzip, 0}
#endif
};
#define NDISPATCH (sizeof dispatch / sizeof dispatch[0])
int main(int argc,char **argv)
{
const char *name;
int i;
init_privs();
#ifdef __EMX__
_wildcard(&argc,&argv);
#endif
/*#define PRIV_TEST*/
#ifdef PRIV_TEST
{
int euid;
char command[100];
printf("INIT: %d %d\n", getuid(), geteuid());
drop_privs();
printf("DROP: %d %d\n", getuid(), geteuid());
reclaim_privs();
printf("RECLAIM: %d %d\n", getuid(), geteuid());
euid = geteuid();
if(argc & 1) {
drop_privs();
printf("DROP: %d %d\n", getuid(), geteuid());
}
if(!((argc-1) & 2)) {
destroy_privs();
printf("DESTROY: %d %d\n", getuid(), geteuid());
}
sprintf(command, "a.out %d", euid);
system(command);
return 1;
}
#endif
#ifdef __EMX__
_wildcard(&argc,&argv);
#endif
/* check whether the compiler lays out structures in a sane way */
if(sizeof(struct partition) != 16 ||
sizeof(struct directory) != 32 ||
sizeof(struct vfat_subentry) !=32) {
fprintf(stderr,"Mtools has not been correctly compiled\n");
fprintf(stderr,"Recompile it using a more recent compiler\n");
return 137;
}
#ifdef __EMX__
argv[0] = _getname(argv[0]); _remext(argv[0]); name = argv[0];
#else
name = _basename(argv[0]);
#endif
#if 0
/* this allows the different tools to be called as "mtools -c <command>"
** where <command> is mdir, mdel, mcopy etcetera
** Mainly done for the BeOS, which doesn't support links yet.
*/
if(argc >= 3 &&
!strcmp(argv[1], "-c") &&
!strcmp(name, "mtools")) {
argc-=2;
argv+=2;
name = argv[0];
}
#endif
/* print the version */
if(argc >= 2 &&
(strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") ==0)) {
printf("%c%s version %s, dated %s\n",
toupper(name[0]), name+1,
mversion, mdate);
printf("configured with the following options: ");
#ifdef USE_XDF
printf("enable-xdf ");
#else
printf("disable-xdf ");
#endif
#ifdef USING_VOLD
printf("enable-vold ");
#else
printf("disable-vold ");
#endif
#ifdef USING_NEW_VOLD
printf("enable-new-vold ");
#else
printf("disable-new-vold ");
#endif
#ifdef DEBUG
printf("enable-debug ");
#else
printf("disable-debug ");
#endif
#ifdef USE_RAWTERM
printf("enable-raw-term ");
#else
printf("disable-raw-term ");
#endif
printf("\n");
return 0;
}
if (argc >= 2 && strcmp(name, "mtools") == 0) {
/* mtools command ... */
argc--;
argv++;
name = argv[0];
}
progname = argv[0];
read_config();
setup_signal();
for (i = 0; i < NDISPATCH; i++) {
if (!strcmp(name,dispatch[i].cmd)
|| (name[0] == 'm' && !strcmp(name+1,dispatch[i].cmd)))
dispatch[i].fn(argc, argv, dispatch[i].type);
}
if (strcmp(name,"mtools"))
fprintf(stderr,"Unknown mtools command '%s'\n",name);
fprintf(stderr,"Usage: mtools [-V] command [-options] arguments ...\n");
fprintf(stderr,"Supported commands:");
for (i = 0; i < NDISPATCH; i++) {
fprintf(stderr, i%8 == 0 ? "\n\t" : ", ");
fprintf(stderr, "%s", dispatch[i].cmd);
}
putc('\n', stderr);
fprintf(stderr, "Use 'mtools command -?' for help per command\n");
return 1;
}

View file

@ -1,234 +0,0 @@
#ifndef MTOOLS_MTOOLS_H
#define MTOOLS_MTOOLS_H
#include "msdos.h"
#if defined(OS_sco3)
#define MAXPATHLEN 1024
#include <signal.h>
extern int lockf(int, int, off_t); /* SCO has no proper include file for lockf */
#endif
#define SCSI_FLAG 1
#define PRIV_FLAG 2
#define NOLOCK_FLAG 4
#define USE_XDF_FLAG 8
#define MFORMAT_ONLY_FLAG 16
#define VOLD_FLAG 32
#define FLOPPYD_FLAG 64
#define FILTER_FLAG 128
#define IS_SCSI(x) ((x) && ((x)->misc_flags & SCSI_FLAG))
#define IS_PRIVILEGED(x) ((x) && ((x)->misc_flags & PRIV_FLAG))
#define IS_NOLOCK(x) ((x) && ((x)->misc_flags & NOLOCK_FLAG))
#define IS_MFORMAT_ONLY(x) ((x) && ((x)->misc_flags & MFORMAT_ONLY_FLAG))
#define SHOULD_USE_VOLD(x) ((x)&& ((x)->misc_flags & VOLD_FLAG))
#define SHOULD_USE_XDF(x) ((x)&& ((x)->misc_flags & USE_XDF_FLAG))
typedef struct device {
const char *name; /* full path to device */
char *drive; /* the drive letter / device name */
int fat_bits; /* FAT encoding scheme */
unsigned int mode; /* any special open() flags */
unsigned int tracks; /* tracks */
unsigned int heads; /* heads */
unsigned int sectors; /* sectors */
unsigned int hidden; /* number of hidden sectors. Used for
* mformatting partitioned devices */
off_t offset; /* skip this many bytes */
unsigned int partition;
unsigned int misc_flags;
/* Linux only stuff */
unsigned int ssize;
unsigned int use_2m;
char *precmd; /* command to be executed before opening
* the drive */
/* internal variables */
int file_nr; /* used during parsing */
int blocksize; /* size of disk block in bytes */
const char *cfg_filename; /* used for debugging purposes */
} device_t;
#ifndef OS_linux
#define BOOTSIZE 512
#else
#define BOOTSIZE 256
#endif
#include "stream.h"
extern const char *short_illegals, *long_illegals;
#define maximize(target, max) do { \
if(max < 0) { \
if(target > 0) \
target = 0; \
} else if(target > max) { \
target = max; \
} \
} while(0)
#define minimize(target, min) do { \
if(target < min) \
target = min; \
} while(0)
int init_geom(int fd, struct device *dev, struct device *orig_dev,
struct stat *stat);
int readwrite_sectors(int fd, /* file descriptor */
int *drive,
int rate,
int seektrack,
int track, int head, int sector, int size, /* address */
char *data,
int bytes,
int direction,
int retries);
int lock_dev(int fd, int mode, struct device *dev);
char *unix_normalize (char *ans, char *name, char *ext);
char *dos_name(char *filename, int verbose, int *mangled, char *buffer);
struct directory *mk_entry(const char *filename, char attr,
unsigned int fat, size_t size, time_t date,
struct directory *ndir);
int copyfile(Stream_t *Source, Stream_t *Target);
int getfreeMinClusters(Stream_t *Stream, size_t ref);
FILE *opentty(int mode);
int is_dir(Stream_t *Dir, char *path);
void bufferize(Stream_t **Dir);
int dir_grow(Stream_t *Dir, int size);
int match(const char *, const char *, char *, int, int);
char *unix_name(char *name, char *ext, char Case, char *answer);
void *safe_malloc(size_t size);
Stream_t *open_filter(Stream_t *Next);
extern int got_signal;
/* int do_gotsignal(char *, int);
#define got_signal do_gotsignal(__FILE__, __LINE__) */
void setup_signal(void);
#define SET_INT(target, source) \
if(source)target=source
UNUSED(static inline int compare (long ref, long testee))
{
return (ref && ref != testee);
}
Stream_t *GetFs(Stream_t *Fs);
char *label_name(char *filename, int verbose,
int *mangled, char *ans);
/* environmental variables */
extern unsigned int mtools_skip_check;
extern unsigned int mtools_fat_compatibility;
extern unsigned int mtools_ignore_short_case;
extern unsigned int mtools_no_vfat;
extern unsigned int mtools_numeric_tail;
extern unsigned int mtools_dotted_dir;
extern unsigned int mtools_twenty_four_hour_clock;
extern char *mtools_date_string;
extern unsigned int mtools_rate_0, mtools_rate_any;
extern int mtools_raw_tty;
extern int batchmode;
void read_config(void);
extern struct device *devices;
extern struct device const_devices[];
extern const int nr_const_devices;
#define New(type) ((type*)(malloc(sizeof(type))))
#define Grow(adr,n,type) ((type*)(realloc((char *)adr,n*sizeof(type))))
#define Free(adr) (free((char *)adr));
#define NewArray(size,type) ((type*)(calloc((size),sizeof(type))))
void mattrib(int argc, char **argv, int type);
void mbadblocks(int argc, char **argv, int type);
void mcat(int argc, char **argv, int type);
void mcd(int argc, char **argv, int type);
void mcopy(int argc, char **argv, int type);
void mdel(int argc, char **argv, int type);
void mdir(int argc, char **argv, int type);
void mdoctorfat(int argc, char **argv, int type);
void mdu(int argc, char **argv, int type);
void mformat(int argc, char **argv, int type);
void minfo(int argc, char **argv, int type);
void mlabel(int argc, char **argv, int type);
void mmd(int argc, char **argv, int type);
void mmount(int argc, char **argv, int type);
void mmove(int argc, char **argv, int type);
void mpartition(int argc, char **argv, int type);
void mshowfat(int argc, char **argv, int mtype);
void mtoolstest(int argc, char **argv, int type);
void mzip(int argc, char **argv, int type);
extern int noPrivileges;
void init_privs(void);
void reclaim_privs(void);
void drop_privs(void);
void destroy_privs(void);
uid_t get_real_uid(void);
void closeExec(int fd);
extern const char *progname;
void precmd(struct device *dev);
void print_sector(char *message, unsigned char *data, int size);
time_t getTimeNow(time_t *now);
#ifdef USING_NEW_VOLD
char *getVoldName(struct device *dev, char *name);
#endif
Stream_t *OpenDir(Stream_t *Parent, const char *filename);
/* int unix_dir_loop(Stream_t *Stream, MainParam_t *mp);
int unix_loop(MainParam_t *mp, char *arg); */
struct dirCache_t **getDirCacheP(Stream_t *Stream);
int isRootDir(Stream_t *Stream);
unsigned int getStart(Stream_t *Dir, struct directory *dir);
unsigned int countBlocks(Stream_t *Dir, unsigned int block);
char *getDrive(Stream_t *Stream);
void printOom(void);
int ask_confirmation(const char *, const char *, const char *);
char *get_homedir(void);
#define EXPAND_BUF 2048
const char *expand(const char *, char *);
const char *fix_mcwd(char *);
FILE *open_mcwd(const char *mode);
void unlink_mcwd(void);
char *skip_drive(const char *path);
char *get_drive(const char *path, const char *def);
int safePopenOut(char **command, char *output, int len);
#define ROUND_DOWN(value, grain) ((value) - (value) % (grain))
#define ROUND_UP(value, grain) ROUND_DOWN((value) + (grain)-1, (grain))
#endif

View file

@ -1,40 +0,0 @@
#ifndef MTOOLS_DIRENTRY_H
#define MTOOLS_DIRENTRY_H
#include "sysincludes.h"
#include "vfat.h"
typedef struct direntry_t {
struct Stream_t *Dir;
/* struct direntry_t *parent; parent level */
int entry; /* slot in parent directory (-3 if root) */
struct directory dir; /* descriptor in parent directory (random if
* root)*/
char name[MAX_VNAMELEN+1]; /* name in its parent directory, or
* NULL if root */
int beginSlot; /* begin and end slot, for delete */
int endSlot;
} direntry_t;
#include "stream.h"
int vfat_lookup(direntry_t *entry, const char *filename, int length,
int flags, char *shortname, char *longname);
struct directory *dir_read(direntry_t *entry, int *error);
void initializeDirentry(direntry_t *entry, struct Stream_t *Dir);
int isNotFound(direntry_t *entry);
direntry_t *getParent(direntry_t *entry);
void dir_write(direntry_t *entry);
void low_level_dir_write(direntry_t *entry);
int fatFreeWithDirentry(direntry_t *entry);
int labelit(char *dosname,
char *longname,
void *arg0,
direntry_t *entry);
int isSubdirOf(Stream_t *inside, Stream_t *outside);
char *getPwd(direntry_t *entry);
void fprintPwd(FILE *f, direntry_t *entry, int escape);
int write_vfat(Stream_t *, char *, char *, int, direntry_t *);
#endif

View file

@ -1,32 +0,0 @@
/*
* Paths of the configuration files.
* This file may be changed by the user as needed.
* There are three empty lines between each definition.
* These ensure that "local" patches and official patches have
* only a very low probability of conflicting.
*/
#define CONF_FILE "/etc/mtools.conf"
#define OLD_CONF_FILE "/etc/mtools"
#define LOCAL_CONF_FILE "/etc/default/mtools.conf"
/* Use this if you like to keep the configuration file in a non-standard
* place such as /etc/default, /opt/etc, /usr/etc, /usr/local/etc ...
*/
#define SYS_CONF_FILE SYSCONFDIR "/mtools.conf"
#define OLD_LOCAL_CONF_FILE "/etc/default/mtools"
#define CFG_FILE1 "/.mtoolsrc"
/* END */

View file

@ -1,57 +0,0 @@
#ifndef MTOOLS_NAMECLASH_H
#define MTOOLS_NAMECLASH_H
#include "stream.h"
typedef enum clash_action {
NAMEMATCH_NONE,
NAMEMATCH_AUTORENAME,
NAMEMATCH_QUIT,
NAMEMATCH_SKIP,
NAMEMATCH_RENAME,
NAMEMATCH_PRENAME, /* renaming of primary name */
NAMEMATCH_OVERWRITE,
NAMEMATCH_ERROR,
NAMEMATCH_SUCCESS,
NAMEMATCH_GREW
} clash_action;
/* clash handling structure */
typedef struct ClashHandling_t {
clash_action action[2];
clash_action namematch_default[2];
int nowarn; /* Don't ask, just do default action if name collision*/
int got_slots;
int mod_time;
/* unsigned int dot; */
char *myname;
unsigned char *dosname;
int single;
int use_longname;
int ignore_entry;
int source; /* to prevent the source from overwriting itself */
int source_entry; /* to account for the space freed up by the original
* name */
char * (*name_converter)(char *filename, int verbose,
int *mangled, char *ans);
} ClashHandling_t;
/* write callback */
typedef int (write_data_callback)(char *,char *, void *, struct direntry_t *);
int mwrite_one(Stream_t *Dir,
const char *argname,
const char *shortname,
write_data_callback *cb,
void *arg,
ClashHandling_t *ch);
int handle_clash_options(ClashHandling_t *ch, char c);
void init_clash_handling(ClashHandling_t *ch);
Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch,
unsigned char attr, time_t mtime);
#endif

View file

@ -1,31 +0,0 @@
typedef struct hsc {
unsigned char byte0;
unsigned char head; /* starting head */
unsigned char sector; /* starting sector */
unsigned char cyl; /* starting cylinder */
} hsc;
#define head(x) ((x).head)
#define sector(x) ((x).sector & 0x3f)
#define cyl(x) ((x).cyl | (((x).sector & 0xc0)<<2))
#define BEGIN(p) _DWORD((p).start_sect)
#define END(p) (_DWORD((p).start_sect)+(_DWORD((p).nr_sects)))
struct partition {
hsc start;
hsc end;
unsigned char start_sect[4]; /* starting sector counting from 0 */
unsigned char nr_sects[4]; /* nr of sectors in partition */
};
#define boot_ind start.byte0
#define sys_ind end.byte0
int consistencyCheck(struct partition *partTable, int doprint, int verbose,
int *has_activated, int *last_end, int *j,
struct device *used_dev, int target_partition);
void setBeginEnd(struct partition *partTable, int begin, int end,
int heads, int sector, int activate, int type);

View file

@ -1,2 +0,0 @@
const char *mversion="3.9.7";
const char *mdate = "1 jun 2000";

View file

@ -1,749 +0,0 @@
/*
* Io to a plain file or device
*
* written by:
*
* Alain L. Knaff
* alain@linux.lu
*
*/
#include "sysincludes.h"
#include "stream.h"
#include "mtools.h"
#include "msdos.h"
#include "plain_io.h"
#include "scsi.h"
#include "partition.h"
#include "llong.h"
typedef struct SimpleFile_t {
Class_t *Class;
int refs;
Stream_t *Next;
Stream_t *Buffer;
struct stat stat;
int fd;
mt_off_t offset;
mt_off_t lastwhere;
int seekable;
int privileged;
#ifdef OS_hpux
int size_limited;
#endif
int scsi_sector_size;
void *extra_data; /* extra system dependant information for scsi */
} SimpleFile_t;
/*
* Create an advisory lock on the device to prevent concurrent writes.
* Uses either lockf, flock, or fcntl locking methods. See the Makefile
* and the Configure files for how to specify the proper method.
*/
int lock_dev(int fd, int mode, struct device *dev)
{
#if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB))
/**/
#else /* FLOCK */
#if (defined(HAVE_LOCKF) && defined(F_TLOCK))
/**/
#else /* LOCKF */
#if (defined(F_SETLK) && defined(F_WRLCK))
struct flock flk;
#endif /* FCNTL */
#endif /* LOCKF */
#endif /* FLOCK */
if(IS_NOLOCK(dev))
return 0;
#if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB))
if (flock(fd, (mode ? LOCK_EX : LOCK_SH)|LOCK_NB) < 0)
#else /* FLOCK */
#if (defined(HAVE_LOCKF) && defined(F_TLOCK))
if (mode && lockf(fd, F_TLOCK, 0) < 0)
#else /* LOCKF */
#if (defined(F_SETLK) && defined(F_WRLCK))
flk.l_type = mode ? F_WRLCK : F_RDLCK;
flk.l_whence = 0;
flk.l_start = 0L;
flk.l_len = 0L;
if (fcntl(fd, F_SETLK, &flk) < 0)
#endif /* FCNTL */
#endif /* LOCKF */
#endif /* FLOCK */
{
if(errno == EINVAL
#ifdef EOPNOTSUPP
|| errno == EOPNOTSUPP
#endif
)
return 0;
else
return 1;
}
return 0;
}
typedef int (*iofn) (int, char *, int);
static int file_io(Stream_t *Stream, char *buf, mt_off_t where, int len,
iofn io)
{
DeclareThis(SimpleFile_t);
int ret;
where += This->offset;
if (This->seekable && where != This->lastwhere ){
if(mt_lseek( This->fd, where, SEEK_SET) < 0 ){
perror("seek");
This->lastwhere = (mt_off_t) -1;
return -1;
}
}
#ifdef OS_hpux
/*
* On HP/UX, we can not write more than MAX_LEN bytes in one go.
* If more are written, the write fails with EINVAL
*/
#define MAX_SCSI_LEN (127*1024)
if(This->size_limited && len > MAX_SCSI_LEN)
len = MAX_SCSI_LEN;
#endif
ret = io(This->fd, buf, len);
#ifdef OS_hpux
if (ret == -1 &&
errno == EINVAL && /* if we got EINVAL */
len > MAX_SCSI_LEN) {
This->size_limited = 1;
len = MAX_SCSI_LEN;
ret = io(This->fd, buf, len);
}
#endif
if ( ret == -1 ){
perror("plain_io");
This->lastwhere = (mt_off_t) -1;
return -1;
}
This->lastwhere = where + ret;
return ret;
}
static int file_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
{
return file_io(Stream, buf, where, len, (iofn) read);
}
static int file_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
{
return file_io(Stream, buf, where, len, (iofn) write);
}
static int file_flush(Stream_t *Stream)
{
#if 0
DeclareThis(SimpleFile_t);
return fsync(This->fd);
#endif
return 0;
}
static int file_free(Stream_t *Stream)
{
DeclareThis(SimpleFile_t);
if (This->fd > 2)
return close(This->fd);
else
return 0;
}
static int file_geom(Stream_t *Stream, struct device *dev,
struct device *orig_dev,
int media, struct bootsector *boot)
{
int ret;
DeclareThis(SimpleFile_t);
size_t tot_sectors;
int BootP, Infp0, InfpX, InfTm;
int sectors, j;
unsigned char sum;
int sect_per_track;
struct label_blk_t *labelBlock;
dev->ssize = 2; /* allow for init_geom to change it */
dev->use_2m = 0x80; /* disable 2m mode to begin */
if(media == 0xf0 || media >= 0x100){
dev->heads = WORD(nheads);
dev->sectors = WORD(nsect);
tot_sectors = DWORD(bigsect);
SET_INT(tot_sectors, WORD(psect));
sect_per_track = dev->heads * dev->sectors;
tot_sectors += sect_per_track - 1; /* round size up */
dev->tracks = tot_sectors / sect_per_track;
BootP = WORD(ext.old.BootP);
Infp0 = WORD(ext.old.Infp0);
InfpX = WORD(ext.old.InfpX);
InfTm = WORD(ext.old.InfTm);
if(WORD(fatlen)) {
labelBlock = &boot->ext.old.labelBlock;
} else {
labelBlock = &boot->ext.fat32.labelBlock;
}
if (boot->descr >= 0xf0 &&
labelBlock->dos4 == 0x29 &&
strncmp( boot->banner,"2M", 2 ) == 0 &&
BootP < 512 && Infp0 < 512 && InfpX < 512 && InfTm < 512 &&
BootP >= InfTm + 2 && InfTm >= InfpX && InfpX >= Infp0 &&
Infp0 >= 76 ){
for (sum=0, j=63; j < BootP; j++)
sum += boot->jump[j];/* checksum */
dev->ssize = boot->jump[InfTm];
if (!sum && dev->ssize <= 7){
dev->use_2m = 0xff;
dev->ssize |= 0x80; /* is set */
}
}
} else if (media >= 0xf8){
media &= 3;
dev->heads = old_dos[media].heads;
dev->tracks = old_dos[media].tracks;
dev->sectors = old_dos[media].sectors;
dev->ssize = 0x80;
dev->use_2m = ~1;
} else {
fprintf(stderr,"Unknown media type\n");
exit(1);
}
sectors = dev->sectors;
dev->sectors = dev->sectors * WORD(secsiz) / 512;
#ifdef JPD
printf("file_geom:media=%0X=>cyl=%d,heads=%d,sects=%d,ssize=%d,use2m=%X\n",
media, dev->tracks, dev->heads, dev->sectors, dev->ssize,
dev->use_2m);
#endif
ret = init_geom(This->fd,dev, orig_dev, &This->stat);
dev->sectors = sectors;
#ifdef JPD
printf("f_geom: after init_geom(), sects=%d\n", dev->sectors);
#endif
return ret;
}
static int file_data(Stream_t *Stream, time_t *date, mt_size_t *size,
int *type, int *address)
{
DeclareThis(SimpleFile_t);
if(date)
*date = This->stat.st_mtime;
if(size)
*size = This->stat.st_size;
if(type)
*type = S_ISDIR(This->stat.st_mode);
if(address)
*address = 0;
return 0;
}
/* ZIP or other scsi device on Solaris or SunOS system.
Since Sun won't accept a non-Sun label on a scsi disk, we must
bypass Sun's disk interface and use low-level SCSI commands to read
or write the ZIP drive. We thus replace the file_read and file_write
routines with our own scsi_read and scsi_write routines, that use the
uscsi ioctl interface. By James Dugal, jpd@usl.edu, 11-96. Tested
under Solaris 2.5 and SunOS 4.3.1_u1 using GCC.
Note: the mtools.conf entry for a ZIP drive would look like this:
(solaris) drive C: file="/dev/rdsk/c0t5d0s2" partition=4 FAT=16 nodelay exclusive scsi=&
(sunos) drive C: file="/dev/rsd5c" partition=4 FAT=16 nodelay exclusive scsi=1
Note 2: Sol 2.5 wants mtools to be suid-root, to use the ioctl. SunOS is
happy if we just have access to the device, so making mtools sgid to a
group called, say, "ziprw" which has rw permission on /dev/rsd5c, is fine.
*/
#define MAXBLKSPERCMD 255
static void scsi_init(SimpleFile_t *This)
{
int fd = This->fd;
unsigned char cdb[10],buf[8];
memset(cdb, 0, sizeof cdb);
memset(buf,0, sizeof(buf));
cdb[0]=SCSI_READ_CAPACITY;
if (scsi_cmd(fd, (unsigned char *)cdb,
sizeof(cdb), SCSI_IO_READ, buf, sizeof(buf), This->extra_data)==0)
{
This->scsi_sector_size=
((unsigned)buf[5]<<16)|((unsigned)buf[6]<<8)|(unsigned)buf[7];
if (This->scsi_sector_size != 512)
fprintf(stderr," (scsi_sector_size=%d)\n",This->scsi_sector_size);
}
}
int scsi_io(Stream_t *Stream, char *buf, mt_off_t where, size_t len, int rwcmd)
{
unsigned int firstblock, nsect;
int clen,r,max;
off_t offset;
unsigned char cdb[10];
DeclareThis(SimpleFile_t);
firstblock=truncBytes32((where + This->offset)/This->scsi_sector_size);
/* 512,1024,2048,... bytes/sector supported */
offset=truncBytes32(where + This->offset -
firstblock*This->scsi_sector_size);
nsect=(offset+len+This->scsi_sector_size-1)/ This->scsi_sector_size;
#if defined(OS_sun) && defined(OS_i386)
if (This->scsi_sector_size>512)
firstblock*=This->scsi_sector_size/512; /* work around a uscsi bug */
#endif /* sun && i386 */
if (len>512) {
/* avoid buffer overruns. The transfer MUST be smaller or
* equal to the requested size! */
while (nsect*This->scsi_sector_size>len)
--nsect;
if(!nsect) {
fprintf(stderr,"Scsi buffer too small\n");
exit(1);
}
if(rwcmd == SCSI_IO_WRITE && offset) {
/* there seems to be no memmove before a write */
fprintf(stderr,"Unaligned write\n");
exit(1);
}
/* a better implementation should use bounce buffers.
* However, in normal operation no buffer overruns or
* unaligned writes should happen anyways, as the logical
* sector size is (hopefully!) equal to the physical one
*/
}
max = scsi_max_length();
if (nsect > max)
nsect=max;
/* set up SCSI READ/WRITE command */
memset(cdb, 0, sizeof cdb);
switch(rwcmd) {
case SCSI_IO_READ:
cdb[0] = SCSI_READ;
break;
case SCSI_IO_WRITE:
cdb[0] = SCSI_WRITE;
break;
}
cdb[1] = 0;
if (firstblock > 0x1fffff || nsect > 0xff) {
/* I suspect that the ZIP drive also understands Group 1
* commands. If that is indeed true, we may chose Group 1
* more agressively in the future */
cdb[0] |= SCSI_GROUP1;
clen=10; /* SCSI Group 1 cmd */
/* this is one of the rare case where explicit coding is
* more portable than macros... The meaning of scsi command
* bytes is standardised, whereas the preprocessor macros
* handling it might be not... */
cdb[2] = (unsigned char) (firstblock >> 24) & 0xff;
cdb[3] = (unsigned char) (firstblock >> 16) & 0xff;
cdb[4] = (unsigned char) (firstblock >> 8) & 0xff;
cdb[5] = (unsigned char) firstblock & 0xff;
cdb[6] = 0;
cdb[7] = (unsigned char) (nsect >> 8) & 0xff;
cdb[8] = (unsigned char) nsect & 0xff;
cdb[9] = 0;
} else {
clen = 6; /* SCSI Group 0 cmd */
cdb[1] |= (unsigned char) ((firstblock >> 16) & 0x1f);
cdb[2] = (unsigned char) ((firstblock >> 8) & 0xff);
cdb[3] = (unsigned char) firstblock & 0xff;
cdb[4] = (unsigned char) nsect;
cdb[5] = 0;
}
if(This->privileged)
reclaim_privs();
r=scsi_cmd(This->fd, (unsigned char *)cdb, clen, rwcmd, buf,
nsect*This->scsi_sector_size, This->extra_data);
if(This->privileged)
drop_privs();
if(r) {
perror(rwcmd == SCSI_IO_READ ? "SCMD_READ" : "SCMD_WRITE");
return -1;
}
#ifdef JPD
printf("finished %u for %u\n", firstblock, nsect);
#endif
#ifdef JPD
printf("zip: read or write OK\n");
#endif
if (offset>0) memmove(buf,buf+offset,nsect*This->scsi_sector_size-offset);
if (len==256) return 256;
else if (len==512) return 512;
else return nsect*This->scsi_sector_size-offset;
}
int scsi_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
{
#ifdef JPD
printf("zip: to read %d bytes at %d\n", len, where);
#endif
return scsi_io(Stream, buf, where, len, SCSI_IO_READ);
}
int scsi_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
{
#ifdef JPD
Printf("zip: to write %d bytes at %d\n", len, where);
#endif
return scsi_io(Stream, buf, where, len, SCSI_IO_WRITE);
}
static Class_t ScsiClass = {
scsi_read,
scsi_write,
file_flush,
file_free,
file_geom,
file_data,
0 /* pre-allocate */
};
static Class_t SimpleFileClass = {
file_read,
file_write,
file_flush,
file_free,
file_geom,
file_data,
0 /* pre_allocate */
};
Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev,
const char *name, int mode, char *errmsg,
int mode2, int locked, mt_size_t *maxSize)
{
SimpleFile_t *This;
#ifdef __EMX__
HFILE FileHandle;
ULONG Action;
APIRET rc;
#endif
This = New(SimpleFile_t);
if (!This){
printOom();
return 0;
}
This->scsi_sector_size = 512;
This->seekable = 1;
#ifdef OS_hpux
This->size_limited = 0;
#endif
This->Class = &SimpleFileClass;
if (!name || strcmp(name,"-") == 0 ){
if (mode == O_RDONLY)
This->fd = 0;
else
This->fd = 1;
This->seekable = 0;
This->refs = 1;
This->Next = 0;
This->Buffer = 0;
if (fstat(This->fd, &This->stat) < 0) {
Free(This);
if(errmsg)
#ifdef HAVE_SNPRINTF
snprintf(errmsg,199,"Can't stat -: %s",
strerror(errno));
#else
sprintf(errmsg,"Can't stat -: %s",
strerror(errno));
#endif
return NULL;
}
return (Stream_t *) This;
}
if(dev) {
if(!(mode2 & NO_PRIV))
This->privileged = IS_PRIVILEGED(dev);
mode |= dev->mode;
}
precmd(dev);
if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
reclaim_privs();
#ifdef __EMX__
#define DOSOPEN_FLAGS (OPEN_FLAGS_DASD | OPEN_FLAGS_WRITE_THROUGH | \
OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_RANDOM | \
OPEN_FLAGS_NO_CACHE)
#define DOSOPEN_FD_ACCESS (OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE)
#define DOSOPEN_HD_ACCESS (OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY)
if (skip_drive(name) > name) {
rc = DosOpen(
name, &FileHandle, &Action, 0L, FILE_NORMAL,
OPEN_ACTION_OPEN_IF_EXISTS, DOSOPEN_FLAGS |
(IS_NOLOCK(dev)?DOSOPEN_HD_ACCESS:DOSOPEN_FD_ACCESS),
0L);
#ifdef DEBUG
if (rc != NO_ERROR) fprintf (stderr, "DosOpen() returned %d\n", rc);
#endif
if (!IS_NOLOCK(dev)) {
rc = DosDevIOCtl(
FileHandle, 0x08L, DSK_LOCKDRIVE, 0, 0, 0, 0, 0, 0);
#ifdef DEBUG
if (rc != NO_ERROR) fprintf (stderr, "DosDevIOCtl() returned %d\n", rc);
#endif
}
if (rc == NO_ERROR)
This->fd = _imphandle(FileHandle); else This->fd = -1;
} else
#endif
{
if (IS_SCSI(dev))
This->fd = scsi_open(name, mode, IS_NOLOCK(dev)?0444:0666,
&This->extra_data);
else
This->fd = open(name, mode, IS_NOLOCK(dev)?0444:0666);
}
if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
drop_privs();
if (This->fd < 0) {
Free(This);
if(errmsg)
#ifdef HAVE_SNPRINTF
snprintf(errmsg, 199, "Can't open %s: %s",
name, strerror(errno));
#else
sprintf(errmsg, "Can't open %s: %s",
name, strerror(errno));
#endif
return NULL;
}
if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
closeExec(This->fd);
#ifdef __EMX__
if (*(name+1) != ':')
#endif
if (fstat(This->fd, &This->stat) < 0){
Free(This);
if(errmsg) {
#ifdef HAVE_SNPRINTF
snprintf(errmsg,199,"Can't stat %s: %s",
name, strerror(errno));
#else
if(strlen(name) > 50) {
sprintf(errmsg,"Can't stat file: %s",
strerror(errno));
} else {
sprintf(errmsg,"Can't stat %s: %s",
name, strerror(errno));
}
#endif
}
return NULL;
}
#ifndef __EMX__
/* lock the device on writes */
if (locked && lock_dev(This->fd, mode == O_RDWR, dev)) {
if(errmsg)
#ifdef HAVE_SNPRINTF
snprintf(errmsg,199,
"plain floppy: device \"%s\" busy (%s):",
dev ? dev->name : "unknown", strerror(errno));
#else
sprintf(errmsg,
"plain floppy: device \"%s\" busy (%s):",
(dev && strlen(dev->name) < 50) ?
dev->name : "unknown", strerror(errno));
#endif
close(This->fd);
Free(This);
return NULL;
}
#endif
/* set default parameters, if needed */
if (dev){
if ((IS_MFORMAT_ONLY(dev) || !dev->tracks) &&
init_geom(This->fd, dev, orig_dev, &This->stat)){
close(This->fd);
Free(This);
if(errmsg)
sprintf(errmsg,"init: set default params");
return NULL;
}
This->offset = (mt_off_t) dev->offset;
} else
This->offset = 0;
This->refs = 1;
This->Next = 0;
This->Buffer = 0;
if(maxSize) {
if (IS_SCSI(dev)) {
*maxSize = MAX_OFF_T_B(31+log_2(This->scsi_sector_size));
} else {
*maxSize = max_off_t_seek;
}
if(This->offset > *maxSize) {
close(This->fd);
Free(This);
if(errmsg)
sprintf(errmsg,"init: Big disks not supported");
return NULL;
}
*maxSize -= This->offset;
}
/* partitioned drive */
/* jpd@usl.edu: assume a partitioned drive on these 2 systems is a ZIP*/
/* or similar drive that must be accessed by low-level scsi commands */
/* AK: introduce new "scsi=1" statement to specifically set
* this option. Indeed, there could conceivably be partitioned
* devices where low level scsi commands will not be needed */
if(IS_SCSI(dev)) {
This->Class = &ScsiClass;
if(This->privileged)
reclaim_privs();
scsi_init(This);
if(This->privileged)
drop_privs();
}
while(!(mode2 & NO_OFFSET) &&
dev && dev->partition && dev->partition <= 4) {
int has_activated, last_end, j;
unsigned char buf[2048];
struct partition *partTable=(struct partition *)(buf+ 0x1ae);
size_t partOff;
/* read the first sector, or part of it */
if (force_read((Stream_t *)This, (char*) buf, 0, 512) != 512)
break;
if( _WORD(buf+510) != 0xaa55)
break;
partOff = BEGIN(partTable[dev->partition]);
if (maxSize) {
if (partOff > *maxSize >> 9) {
close(This->fd);
Free(This);
if(errmsg)
sprintf(errmsg,"init: Big disks not supported");
return NULL;
}
*maxSize -= (mt_off_t) partOff << 9;
}
This->offset += (mt_off_t) partOff << 9;
if(!partTable[dev->partition].sys_ind) {
if(errmsg)
sprintf(errmsg,
"init: non-existant partition");
close(This->fd);
Free(This);
return NULL;
}
if(!dev->tracks) {
dev->heads = head(partTable[dev->partition].end)+1;
dev->sectors = sector(partTable[dev->partition].end);
dev->tracks = cyl(partTable[dev->partition].end) -
cyl(partTable[dev->partition].start)+1;
}
dev->hidden=dev->sectors*head(partTable[dev->partition].start);
if(!mtools_skip_check &&
consistencyCheck((struct partition *)(buf+0x1ae), 0, 0,
&has_activated, &last_end, &j, dev, 0)) {
fprintf(stderr,
"Warning: inconsistent partition table\n");
fprintf(stderr,
"Possibly unpartitioned device\n");
fprintf(stderr,
"\n*** Maybe try without partition=%d in "
"device definition ***\n\n",
dev->partition);
fprintf(stderr,
"If this is a PCMCIA card, or a disk "
"partitioned on another computer, this "
"message may be in error: add "
"mtools_skip_check=1 to your .mtoolsrc "
"file to suppress this warning\n");
}
break;
/* NOTREACHED */
}
This->lastwhere = -This->offset;
/* provoke a seek on those devices that don't start on a partition
* boundary */
return (Stream_t *) This;
}
int get_fd(Stream_t *Stream)
{
DeclareThis(SimpleFile_t);
return This->fd;
}
void *get_extra_data(Stream_t *Stream)
{
DeclareThis(SimpleFile_t);
return This->extra_data;
}

View file

@ -1,21 +0,0 @@
#ifndef MTOOLS_PLAINIO_H
#define MTOOLS_PLAINIO_H
#include "stream.h"
#include "msdos.h"
#ifdef __EMX__
#include <io.h>
#endif
/* plain io */
#define NO_PRIV 1
#define NO_OFFSET 2
Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev,
const char *name, int mode, char *errmsg, int mode2,
int locked, mt_size_t *maxSize);
int check_parameters(struct device *ref, struct device *testee);
int get_fd(Stream_t *Stream);
void *get_extra_data(Stream_t *Stream);
#endif

View file

@ -1,31 +0,0 @@
/*
* Do filename expansion with the shell.
*/
#define EXPAND_BUF 2048
#include "sysincludes.h"
#include "mtools.h"
void precmd(struct device *dev)
{
int status;
pid_t pid;
if(!dev || !dev->precmd)
return;
switch((pid=fork())){
case -1:
perror("Could not fork");
exit(1);
break;
case 0: /* the son */
execl("/bin/sh", "sh", "-c", dev->precmd, 0);
break;
default:
wait(&status);
break;
}
}

View file

@ -1,166 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
/*#define PRIV_DEBUG*/
#if 0
#undef HAVE_SETEUID
#define HAVE_SETRESUID
#include <asm/unistd.h>
int setresuid(int a, int b, int c)
{
syscall(164, a, b, c);
}
#endif
static inline void print_privs(const char *message)
{
#ifdef PRIV_DEBUG
/* for debugging purposes only */
fprintf(stderr,"%s egid=%d rgid=%d\n", message, getegid(), getgid());
fprintf(stderr,"%s euid=%d ruid=%d\n", message, geteuid(), getuid());
#endif
}
int noPrivileges=0;
static gid_t rgid, egid;
static uid_t ruid, euid;
/* privilege management routines for SunOS and Solaris. These are
* needed in order to issue raw SCSI read/write ioctls. Mtools drops
* its privileges at the beginning, and reclaims them just for the
* above-mentioned ioctl's. Before popen(), exec() or system, it
* drops its privileges completely, and issues a warning.
*/
/* group id handling is lots easyer, as long as we don't use group 0.
* If you want to use group id's, create a *new* group mtools or
* floppy. Chgrp any devices that you only want to be accessible to
* mtools to this group, and give them the appropriate privs. Make
* sure this group doesn't own any other files: be aware that any user
* with access to mtools may mformat these files!
*/
static inline void Setuid(uid_t uid)
{
#if defined HAVE_SETEUID || defined HAVE_SETRESUID
if(euid == 0) {
#ifdef HAVE_SETEUID
seteuid(uid);
#else
setresuid(ruid, uid, euid);
#endif
} else
#endif
setuid(uid);
}
/* In reclaim_privs and drop privs, we have to manipulate group privileges
* when having no root privileges, else we might lose them */
void reclaim_privs(void)
{
if(noPrivileges)
return;
setgid(egid);
Setuid(euid);
print_privs("after reclaim privs, both uids should be 0 ");
}
void drop_privs(void)
{
Setuid(ruid);
setgid(rgid);
print_privs("after drop_privs, real should be 0, effective should not ");
}
void destroy_privs(void)
{
#if defined HAVE_SETEUID || defined HAVE_SETRESUID
if(euid == 0) {
#ifdef HAVE_SETEUID
setuid(0); /* get the necessary privs to drop real root id */
setuid(ruid); /* this should be enough to get rid of the three
* ids */
seteuid(ruid); /* for good measure... just in case we came
* accross a system which implemented sane
* semantics instead of POSIXly broken
* semantics for setuid */
#else
setresuid(ruid, ruid, ruid);
#endif
}
#endif
/* we also destroy group privileges */
drop_privs();
/* saved set [ug]id will go away by itself on exec */
print_privs("destroy_privs, no uid should be zero ");
}
uid_t get_real_uid(void)
{
return ruid;
}
void init_privs(void)
{
euid = geteuid();
ruid = getuid();
egid = getegid();
rgid = getgid();
#ifndef F_SETFD
if(euid != ruid) {
fprintf(stderr,
"Setuid installation not supported on this platform\n");
fprintf(stderr,
"Missing F_SETFD");
exit(1);
}
#endif
if(euid == 0 && ruid != 0) {
#ifdef HAVE_SETEUID
setuid(0); /* set real uid to 0 */
#else
#ifndef HAVE_SETRESUID
/* on this machine, it is not possible to reversibly drop
* root privileges. We print an error and quit */
/* BEOS is no longer a special case, as both euid and ruid
* return 0, and thus we do not get any longer into this
* branch */
fprintf(stderr,
"Seteuid call not supported on this architecture.\n");
fprintf(stderr,
"Mtools cannot be installed setuid root.\n");
fprintf(stderr,
"However, it can be installed setuid to a non root");
fprintf(stderr,
"user or setgid to any id.\n");
exit(1);
#endif
#endif
}
drop_privs();
print_privs("after init, real should be 0, effective should not ");
}
void closeExec(int fd)
{
#ifdef F_SETFD
fcntl(fd, F_SETFD, 1);
#endif
}

View file

@ -1,274 +0,0 @@
/*
* scsi.c
* Iomega Zip/Jaz drive tool
* change protection mode and eject disk
*/
/* scis.c by Markus Gyger <mgyger@itr.ch> */
/* This code is based on ftp://gear.torque.net/pub/ziptool.c */
/* by Grant R. Guenther with the following copyright notice: */
/* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */
/* http://www.torque.net/ziptool.html */
/* A.K. Moved this from mzip.c to a separate file in order to share with
* plain_io.c */
#include "sysincludes.h"
#include "mtools.h"
#include "scsi.h"
#if defined OS_hpux
#include <sys/scsi.h>
#endif
#ifdef OS_solaris
#include <sys/scsi/scsi.h>
#endif /* solaris */
#ifdef OS_sunos
#include <scsi/generic/commands.h>
#include <scsi/impl/uscsi.h>
#endif /* sunos */
#ifdef sgi
#include <sys/dsreq.h>
#endif
#ifdef OS_linux
#define SCSI_IOCTL_SEND_COMMAND 1
struct scsi_ioctl_command {
int inlen;
int outlen;
char cmd[5008];
};
#endif
#ifdef _SCO_DS
#include <sys/scsicmd.h>
#endif
#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2)
#include <camlib.h>
#endif
int scsi_max_length(void)
{
#ifdef OS_linux
return 8;
#else
return 255;
#endif
}
int scsi_open(const char *name, int flag, int mode, void **extra_data)
{
#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2)
struct cam_device *cam_dev;
cam_dev = cam_open_device(name, O_RDWR);
*extra_data = (void *) cam_dev;
if (cam_dev)
return cam_dev->fd;
else
return -1;
#else
return open(name, O_RDONLY
#ifdef O_NDELAY
| O_NDELAY
#endif
/* O_RDONLY | dev->mode*/);
#endif
}
int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode,
void *data, size_t len, void *extra_data)
{
#if defined OS_hpux
struct sctl_io sctl_io;
memset(&sctl_io, 0, sizeof sctl_io); /* clear reserved fields */
memcpy(sctl_io.cdb, cdb, cmdlen); /* copy command */
sctl_io.cdb_length = cmdlen; /* command length */
sctl_io.max_msecs = 2000; /* allow 2 seconds for cmd */
switch (mode) {
case SCSI_IO_READ:
sctl_io.flags = SCTL_READ;
sctl_io.data_length = len;
sctl_io.data = data;
break;
case SCSI_IO_WRITE:
sctl_io.flags = 0;
sctl_io.data_length = data ? len : 0;
sctl_io.data = len ? data : 0;
break;
}
if (ioctl(fd, SIOC_IO, &sctl_io) == -1) {
perror("scsi_io");
return -1;
}
return sctl_io.cdb_status;
#elif defined OS_sunos || defined OS_solaris
struct uscsi_cmd uscsi_cmd;
memset(&uscsi_cmd, 0, sizeof uscsi_cmd);
uscsi_cmd.uscsi_cdb = (char *)cdb;
uscsi_cmd.uscsi_cdblen = cmdlen;
#ifdef OS_solaris
uscsi_cmd.uscsi_timeout = 20; /* msec? */
#endif /* solaris */
uscsi_cmd.uscsi_buflen = (u_int)len;
uscsi_cmd.uscsi_bufaddr = data;
switch (mode) {
case SCSI_IO_READ:
uscsi_cmd.uscsi_flags = USCSI_READ;
break;
case SCSI_IO_WRITE:
uscsi_cmd.uscsi_flags = USCSI_WRITE;
break;
}
if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) {
perror("scsi_io");
return -1;
}
if(uscsi_cmd.uscsi_status) {
errno = 0;
fprintf(stderr,"scsi status=%x\n",
(unsigned short)uscsi_cmd.uscsi_status);
return -1;
}
return 0;
#elif defined OS_linux
struct scsi_ioctl_command scsi_cmd;
memcpy(scsi_cmd.cmd, cdb, cmdlen); /* copy command */
switch (mode) {
case SCSI_IO_READ:
scsi_cmd.inlen = 0;
scsi_cmd.outlen = len;
break;
case SCSI_IO_WRITE:
scsi_cmd.inlen = len;
scsi_cmd.outlen = 0;
memcpy(scsi_cmd.cmd + cmdlen,data,len);
break;
}
if (ioctl(fd, SCSI_IOCTL_SEND_COMMAND, &scsi_cmd) < 0) {
perror("scsi_io");
return -1;
}
switch (mode) {
case SCSI_IO_READ:
memcpy(data, &scsi_cmd.cmd[0], len);
break;
case SCSI_IO_WRITE:
break;
}
return 0; /* where to get scsi status? */
#elif defined _SCO_DS
struct scsicmd scsi_cmd;
memset(scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */
memcpy(scsi_cmd.cdb, cdb, cmdlen);
scsi_cmd.cdb_len = cmdlen;
scsi_cmd.data_len = len;
scsi_cmd.data_ptr = data;
scsi_cmd.is_write = mode == SCSI_IO_WRITE;
if (ioctl(fd,SCSIUSERCMD,&scsi_cmd) == -1) {
perror("scsi_io");
printf("scsi status: host=%x; target=%x\n",
(unsigned)scsi_cmd.host_sts,(unsigned)scsi_cmd.target_sts);
return -1;
}
return 0;
#elif defined sgi
struct dsreq scsi_cmd;
scsi_cmd.ds_cmdbuf = (char *)cdb;
scsi_cmd.ds_cmdlen = cmdlen;
scsi_cmd.ds_databuf = data;
scsi_cmd.ds_datalen = len;
switch (mode) {
case SCSI_IO_READ:
scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE;
break;
case SCSI_IO_WRITE:
scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE;
break;
}
scsi_cmd.ds_time = 10000;
scsi_cmd.ds_link = 0;
scsi_cmd.ds_synch =0;
scsi_cmd.ds_ret =0;
if (ioctl(fd, DS_ENTER, &scsi_cmd) == -1) {
perror("scsi_io");
return -1;
}
if(scsi_cmd.ds_status) {
errno = 0;
fprintf(stderr,"scsi status=%x\n",
(unsigned short)scsi_cmd.ds_status);
return -1;
}
return 0;
#elif (defined OS_freebsd) && (__FreeBSD__ >= 2)
#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
union ccb *ccb;
int flags;
int r;
struct cam_device *cam_dev = (struct cam_device *) extra_data;
if (cam_dev==NULL || cam_dev->fd!=fd)
{
fprintf(stderr,"invalid file descriptor\n");
return -1;
}
ccb = cam_getccb(cam_dev);
bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen);
if (mode == SCSI_IO_READ)
flags = CAM_DIR_IN;
else if (data && len)
flags = CAM_DIR_OUT;
else
flags = CAM_DIR_NONE;
cam_fill_csio(&ccb->csio,
/* retry */ 1,
/* cbfcnp */ NULL,
flags,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/*data_ptr*/ len ? data : 0,
/*data_len */ data ? len : 0,
96,
cmdlen,
5000);
if (cam_send_ccb(cam_dev, ccb) < 0 ||
(ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
return -1;
}
return 0;
#else
fprintf(stderr, "scsi_io not implemented\n");
return -1;
#endif
}

View file

@ -1,22 +0,0 @@
#ifndef __mtools_scsi_h
#define __mtools_scsi_h
#define SCSI_READ 0x8
#define SCSI_WRITE 0xA
#define SCSI_IOMEGA 0xC
#define SCSI_INQUIRY 0x12
#define SCSI_MODE_SENSE 0x1a
#define SCSI_START_STOP 0x1b
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e
#define SCSI_GROUP1 0x20
#define SCSI_READ_CAPACITY 0x25
typedef enum { SCSI_IO_READ, SCSI_IO_WRITE } scsi_io_mode_t;
int scsi_max_length(void);
int scsi_cmd(int fd, unsigned char cdb[6], int clen, scsi_io_mode_t mode,
void *data, size_t len, void *extra_data);
int scsi_open(const char *name, int flags, int mode, void **extra_data);
#endif /* __mtools_scsi_h */

View file

@ -1,35 +0,0 @@
#include "sysincludes.h"
#include "mtools.h"
#undef got_signal
int got_signal = 0;
void signal_handler(int dummy)
{
got_signal = 1;
#if 0
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
#endif
}
#if 0
int do_gotsignal(char *f, int n)
{
if(got_signal)
fprintf(stderr, "file=%s line=%d\n", f, n);
return got_signal;
}
#endif
void setup_signal(void)
{
/* catch signals */
signal(SIGHUP, (SIG_CAST)signal_handler);
signal(SIGINT, (SIG_CAST)signal_handler);
signal(SIGTERM, (SIG_CAST)signal_handler);
signal(SIGQUIT, (SIG_CAST)signal_handler);
}

View file

@ -1,65 +0,0 @@
#include "sysincludes.h"
#include "msdos.h"
#include "stream.h"
int batchmode = 0;
int flush_stream(Stream_t *Stream)
{
int ret=0;
if(!batchmode) {
if(Stream->Class->flush)
ret |= Stream->Class->flush(Stream);
if(Stream->Next)
ret |= flush_stream(Stream->Next);
}
return ret;
}
Stream_t *copy_stream(Stream_t *Stream)
{
if(Stream)
Stream->refs++;
return Stream;
}
int free_stream(Stream_t **Stream)
{
int ret=0;
if(!*Stream)
return -1;
if(! --(*Stream)->refs){
if((*Stream)->Class->flush)
ret |= (*Stream)->Class->flush(*Stream);
if((*Stream)->Class->freeFunc)
ret |= (*Stream)->Class->freeFunc(*Stream);
if((*Stream)->Next)
ret |= free_stream(&(*Stream)->Next);
Free(*Stream);
} else if ( (*Stream)->Next )
ret |= flush_stream((*Stream)->Next);
*Stream = NULL;
return ret;
}
#define GET_DATA(stream, date, size, type, address) \
(stream)->Class->get_data( (stream), (date), (size), (type), (address) )
int get_data_pass_through(Stream_t *Stream, time_t *date, mt_size_t *size,
int *type, int *address)
{
return GET_DATA(Stream->Next, date, size, type, address);
}
int read_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
{
return READS(Stream->Next, buf, start, len);
}
int write_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
{
return WRITES(Stream->Next, buf, start, len);
}

Some files were not shown because too many files have changed in this diff Show more