669 Commits

Author SHA1 Message Date
Ben Gras
a9d80e6283 don't include branch rev after all.. looks too weird in the tag. 2009-11-05 08:25:23 +00:00
David van Moolenbroek
6c4197f77e PM, VFS: remove unused param.h definitions 2009-10-29 13:29:04 +00:00
David van Moolenbroek
66998b594f PM: remove unused core_name variable 2009-10-29 12:07:53 +00:00
David van Moolenbroek
20ca68f5c9 DS: do not panic when sending reply fails 2009-10-27 17:06:45 +00:00
Erik van der Kouwe
379e087d6b Create man pages for bigsh and dev2name 2009-10-27 15:34:22 +00:00
David van Moolenbroek
bd30f2a988 Ground work for larger file systems, and miscellaneous fixes:
- MFS and mkfs(1) now perform extra sanity checks
- fsck(1) can now deal with inode tables extending beyond the file
  system's first 4GB
- badblocks(8) no longer writes out the superblock for no reason
- mkfs(1) no longer crashes when given no parameters
- more(1) no longer crashes when standard output is redirected
2009-10-26 13:35:39 +00:00
Ben Gras
5920582bde Don't check DMA_ST_ERROR before DMA_ST_INT is set (which is done too) 2009-10-22 14:31:29 +00:00
Erik van der Kouwe
204f9d496a Increase limits on PCI devices to have space for the new RTL8139 ACLSs 2009-10-21 09:14:58 +00:00
Ben Gras
97ae67e780 if from branch, include branch name in in-image tag and .iso filename. 2009-10-19 15:46:27 +00:00
Ben Gras
96b608c3f2 throw out unnecessary drive1 thing 2009-10-19 15:45:43 +00:00
Ben Gras
6b01026668 newer at_wini.c (really incl atapi dma this time) 2009-10-19 15:45:14 +00:00
Ben Gras
3017061093 include OSS on CD 2009-10-19 15:13:44 +00:00
Ben Gras
0333f21d8e - reverse order of transfer command and DMA initiation - fixes DMA problem
that some hardware had
 - clear DMA_ST_INT after DMA - fixes infinite number of interrupts 
   that some hardware had
 - initial ATAPI DMA implementation, doesn't actually increase performance
   on my test hardware so possibly not right yet, disabled by default
2009-10-19 14:23:04 +00:00
Ben Gras
53567bf741 no DEBUG_VMASSERT committed 2009-10-18 20:08:55 +00:00
Erik van der Kouwe
4c2f0eb22f Suppress spurious scancodes in VMWare 2009-10-18 07:12:42 +00:00
Erik van der Kouwe
44a4c8c0d2 Add more identifiers to drivers.conf for orinoco and rtl8137.
Increase RSS_NR_PCI_ID and remove dumplicate reference
to /etc/drivers.conf; each such reference uses _PATH_DRIVERS_CONF
from <minix/paths.h> now.
2009-10-14 07:20:13 +00:00
Ben Gras
abdf8e26fb moving OSS to a package. 2009-10-12 12:53:36 +00:00
David van Moolenbroek
0143cb2335 support for head -n (suggested by xorquewasp) 2009-10-10 22:36:46 +00:00
Erik van der Kouwe
fc2634d1ed Network card autodetection in netconf.sh 2009-10-10 15:54:05 +00:00
Erik van der Kouwe
cb6dbfca2c Add lspci command and SI_PCI_INFO getsysinfo call 2009-10-09 10:48:46 +00:00
David van Moolenbroek
045f1cdb10 inet: fix TCP connection corruption bug (causing test40 to fail sometimes) 2009-10-06 20:32:58 +00:00
Erik van der Kouwe
e9533909ff Report make issue in UPDATING (approved by Ben) 2009-10-06 14:17:13 +00:00
Erik van der Kouwe
d9a34f96e7 Add nohup tool (approved by Ben) 2009-10-06 14:16:35 +00:00
Ben Gras
dbbc0c23d5 fix compiler warning by including for prototype. 2009-10-05 16:45:03 +00:00
Ben Gras
c373473f24 add prototype for wait_for() to fix compiler warning. 2009-10-05 16:43:02 +00:00
Ben Gras
45ae52aec0 fix compiler warnings using dubious casts. 2009-10-05 16:41:28 +00:00
Ben Gras
2f4ea30d96 fix compiler warning 2009-10-05 16:40:21 +00:00
Ben Gras
1a85c6be78 fix compiler warning due to const char * -> char * 2009-10-05 16:38:12 +00:00
Ben Gras
24e1e83028 really revert endpoint_t -> int
debugging info on panic: decode segment selectors and descriptors, now moved
to arch-specific part, prototypes added; sanity checking in debug.h made
optional with vmassert().
2009-10-05 15:47:23 +00:00
Ben Gras
30804b9ed7 thanks to tomas: fix for level0() race condition - global variable can
be used concurrently.  pass the function in eax instead; this gets rid
of the global variable.  also execute the function directly if we're
already trapped into the kernel.

revert of u32_t endpoint_t to int (some code assumes endpoints are
negative for negative slot numbers).
2009-10-05 15:22:31 +00:00
Ben Gras
88a12c70d2 little more info in pagefault exception handler. 2009-10-03 12:23:02 +00:00
Ben Gras
6bd3002f06 - exact magic values for entered/nonentered states in recursive enter check
- read_*() functions to read segment selector values
 - decode loaded segments on panic
2009-10-03 12:17:46 +00:00
Ben Gras
fe35879325 - panic if there's no runnable process
- more basic sanity check before recursive enter check (data segment)
 - try to jump to boot monitor instantly on recursive panic
2009-10-03 11:30:35 +00:00
Ben Gras
e716fae585 packman -y: noninteractive mode to install all packages 2009-10-03 09:57:37 +00:00
Ben Gras
fb5b10a081 fixed grep usage in filter (again) 2009-10-02 13:29:36 +00:00
Ben Gras
85ad7b6b11 don't have ackpack in the list any more as it installs an
old /usr/bin/make.
2009-10-02 13:23:58 +00:00
Ben Gras
7f423d0fa2 Unique matching for package name when grepping for it in the master list. 2009-10-02 13:02:36 +00:00
David van Moolenbroek
e7dea9c609 Add id(1) -g, -n, -r options (Bug#302, reported by Aleksey Cheusov) 2009-10-02 12:23:00 +00:00
Tomas Hruby
982f4a0cbb isofs links with libsysutil which does not exist anymore 2009-10-02 12:07:46 +00:00
Ben Gras
b9e0af1c1e dirs for OSS 2009-10-02 10:35:05 +00:00
Ben Gras
57be617a8d revert to 16MB to fix reinstall for now. 2009-10-02 09:48:15 +00:00
David van Moolenbroek
e913d66749 INET: fix panic when network drivers are started late (Bug#309, reported by Niek Linnenbank) 2009-10-01 21:24:12 +00:00
David van Moolenbroek
8f9a90192f RS: disable harmless warning 2009-10-01 19:21:57 +00:00
Ben Gras
d3382c4a6c postgresql in packing list 2009-10-01 18:14:49 +00:00
Ben Gras
0d83eeb194 slightly larger /usr needed 2009-10-01 17:45:14 +00:00
Ben Gras
5a0c76e64a connect OSS to the build (clean and install only) 2009-10-01 17:23:54 +00:00
David van Moolenbroek
6168bcefa6 Fix bios_wini using wrong size for vector (Bug#280, reported by John Peace) 2009-10-01 16:59:04 +00:00
David van Moolenbroek
bc029d0bc6 Remove treecmp utility (Bug#310, reported by John Peace) 2009-10-01 16:58:13 +00:00
David van Moolenbroek
2ac8124914 Fix writeisofs lseek() usage (Bug#311, reported by John Peace 2009-10-01 16:56:46 +00:00
Ben Gras
b7ac32bfa4 dir for oss config files 2009-10-01 16:55:54 +00:00
David van Moolenbroek
0c1ae1965e Fix syslog buffer overflow (Bug#270, reported by Kevin Jordan) 2009-10-01 16:54:56 +00:00
Ben Gras
cb50e7e135 support for OSS. 2009-10-01 16:36:14 +00:00
Thomas Veerman
cb6f6a94f7 Fixes to ISOFS 2009-10-01 14:34:17 +00:00
Thomas Veerman
471ad9384f Initial import of ISOFS by Jacopo Urbani 2009-10-01 14:00:27 +00:00
Ben Gras
cee82da892 implement VAR += .. feature, contributed by Pieter Hijma 2009-10-01 11:29:08 +00:00
David van Moolenbroek
49808dcf77 PM delay call infrastructure improvements
- allow PM to tell sys_runctl() whether to use delay call feature
- only use this feature in PM for delivering signals - not for exits
- do better error checking in PM on sys_runctl() calls
- rename SIGKREADY to SIGNDELAY
2009-10-01 10:36:09 +00:00
David van Moolenbroek
f11f597777 Make message type ranges in com.h (eventually) unique 2009-10-01 10:33:01 +00:00
David van Moolenbroek
a8ebc69c6e Fix erroneous times() call in udpstat/tcpstat.
Reported by John Peace, bug #312.
Also fix times(2) man page.
2009-10-01 10:31:29 +00:00
Tomas Hruby
6539c356c6 idle_task() declared 3x in kernel/proto.h. 2 declarations removed 2009-10-01 07:59:15 +00:00
Arun Thomas
8f4ca2dc92 Increase root partition size to 64 MB. 2009-09-30 14:11:58 +00:00
Ben Gras
e326a01446 - retrieve binary packages and sources from webserver to make a release, incrementally using wget
(so wget required)
 - don't build List file again, but use webserver List file and filter it
2009-09-30 13:11:22 +00:00
Arun Thomas
782a05b919 Bump release to 3.1.5 in issue.install 2009-09-30 13:00:38 +00:00
David van Moolenbroek
b423d7b477 Merge of David's ptrace branch. Summary:
o Support for ptrace T_ATTACH/T_DETACH and T_SYSCALL
o PM signal handling logic should now work properly, even with debuggers
  being present
o Asynchronous PM/VFS protocol, full IPC support for senda(), and
  AMF_NOREPLY senda() flag

DETAILS

Process stop and delay call handling of PM:
o Added sys_runctl() kernel call with sys_stop() and sys_resume()
  aliases, for PM to stop and resume a process
o Added exception for sending/syscall-traced processes to sys_runctl(),
  and matching SIGKREADY pseudo-signal to PM
o Fixed PM signal logic to deal with requests from a process after
  stopping it (so-called "delay calls"), using the SIGKREADY facility
o Fixed various PM panics due to race conditions with delay calls versus
  VFS calls
o Removed special PRIO_STOP priority value
o Added SYS_LOCK RTS kernel flag, to stop an individual process from
  running while modifying its process structure

Signal and debugger handling in PM:
o Fixed debugger signals being dropped if a second signal arrives when
  the debugger has not retrieved the first one
o Fixed debugger signals being sent to the debugger more than once
o Fixed debugger signals unpausing process in VFS; removed PM_UNPAUSE_TR
  protocol message
o Detached debugger signals from general signal logic and from being
  blocked on VFS calls, meaning that even VFS can now be traced
o Fixed debugger being unable to receive more than one pending signal in
  one process stop
o Fixed signal delivery being delayed needlessly when multiple signals
  are pending
o Fixed wait test for tracer, which was returning for children that were
  not waited for
o Removed second parallel pending call from PM to VFS for any process
o Fixed process becoming runnable between exec() and debugger trap
o Added support for notifying the debugger before the parent when a
  debugged child exits
o Fixed debugger death causing child to remain stopped forever
o Fixed consistently incorrect use of _NSIG

Extensions to ptrace():
o Added T_ATTACH and T_DETACH ptrace request, to attach and detach a
  debugger to and from a process
o Added T_SYSCALL ptrace request, to trace system calls
o Added T_SETOPT ptrace request, to set trace options
o Added TO_TRACEFORK trace option, to attach automatically to children
  of a traced process
o Added TO_ALTEXEC trace option, to send SIGSTOP instead of SIGTRAP upon
  a successful exec() of the tracee
o Extended T_GETUSER ptrace support to allow retrieving a process's priv
  structure
o Removed T_STOP ptrace request again, as it does not help implementing
  debuggers properly
o Added MINIX3-specific ptrace test (test42)
o Added proper manual page for ptrace(2)

Asynchronous PM/VFS interface:
o Fixed asynchronous messages not being checked when receive() is called
  with an endpoint other than ANY
o Added AMF_NOREPLY senda() flag, preventing such messages from
  satisfying the receive part of a sendrec()
o Added asynsend3() that takes optional flags; asynsend() is now a
  #define passing in 0 as third parameter
o Made PM/VFS protocol asynchronous; reintroduced tell_fs()
o Made PM_BASE request/reply number range unique
o Hacked in a horrible temporary workaround into RS to deal with newly
  revealed RS-PM-VFS race condition triangle until VFS is asynchronous

System signal handling:
o Fixed shutdown logic of device drivers; removed old SIGKSTOP signal
o Removed is-superuser check from PM's do_procstat() (aka getsigset())
o Added sigset macros to allow system processes to deal with the full
  signal set, rather than just the POSIX subset

Miscellaneous PM fixes:
o Split do_getset into do_get and do_set, merging common code and making
  structure clearer
o Fixed setpriority() being able to put to sleep processes using an
  invalid parameter, or revive zombie processes
o Made find_proc() global; removed obsolete proc_from_pid()
o Cleanup here and there

Also included:
o Fixed false-positive boot order kernel warning
o Removed last traces of old NOTIFY_FROM code

THINGS OF POSSIBLE INTEREST

o It should now be possible to run PM at any priority, even lower than
  user processes
o No assumptions are made about communication speed between PM and VFS,
  although communication must be FIFO
o A debugger will now receive incoming debuggee signals at kill time
  only; the process may not yet be fully stopped
o A first step has been made towards making the SYSTEM task preemptible
2009-09-30 09:57:22 +00:00
Ben Gras
8d9aa1fe4f throw out exec debugging message. 2009-09-30 08:36:13 +00:00
Ben Gras
2c56b7eebc there is no elvis. 2009-09-30 08:21:21 +00:00
Ben Gras
5f8a77061b audio package obsolete 2009-09-30 07:41:03 +00:00
Ben Gras
bcd7d04203 throw out FIXME reminders for release 2009-09-30 07:40:34 +00:00
Tomas Hruby
40b1d58077 Mostly a revert of r5306. com.h defines MAX_NR_TASKS value which replaces
NR_TASKS in the endpoint macros. MAX_NR_TASKS defines the maximal number of
kernel tasks. It is unlikely that we will ever need this many tasks as the goal
is not to have such a difference in the future. For now it makes possible to
remove the limiting NR_TASKS from the endpoint code.
2009-09-29 20:13:41 +00:00
Tomas Hruby
4dad30937b Removed macros that depend on NOTIFY_FROM from servers and drivers. They
determine the information defined by these macros from the m_source field of the
notify message.
2009-09-29 18:47:56 +00:00
Ben Gras
0e1fd9ea33 add SDL-1.2.13 2009-09-29 14:32:49 +00:00
Ben Gras
07a5bd0fe3 sort; throw out old packages; qemu in 2009-09-29 14:31:26 +00:00
Thomas Veerman
4b02d58176 Removed debug string 2009-09-29 13:23:04 +00:00
Ben Gras
699e4345ea revert mkfs change; might run out of inodes, but large number of inodes
makes mkfs not want to mkfs large filesystems.

find optimal formula (e.g. dynamic capping of no. of inodes) later.
2009-09-29 12:14:35 +00:00
Ben Gras
0e43db1375 disable address space randomisation feature in normal mode. 2009-09-29 12:10:30 +00:00
Tomas Hruby
256610f1d5 Macros in endpoint.h need to know about endpoint_t 2009-09-28 16:25:47 +00:00
Ben Gras
da67a3af00 disable 'clever' optimisation (workaround for vmware(?) problem) 2009-09-28 15:47:01 +00:00
Ben Gras
856ec906bd assert overammbitious. 2009-09-28 01:23:11 +00:00
Ben Gras
7a45f80bd5 threw out sanity checks before pagetable rewrites, triggering false
page table inconsistencies.

fix handle_memory logic. again.
2009-09-27 12:44:36 +00:00
Ben Gras
67602ce85e field for sanity check feature. 2009-09-27 12:37:37 +00:00
Ben Gras
5715637aa2 new prototypes. 2009-09-27 12:37:16 +00:00
Ben Gras
5cf59f9225 verbose printing and sanity checking functions. 2009-09-27 12:36:48 +00:00
Ben Gras
a02d9aae0a re-enable munmap(). 2009-09-25 19:01:27 +00:00
Ben Gras
e114ae8195 unnecessarily verbose message. 2009-09-25 17:59:38 +00:00
Ben Gras
e900735ddd old reminder 2009-09-25 17:58:23 +00:00
Ben Gras
cd3e83f849 get_randomness restored. 2009-09-25 17:57:24 +00:00
Ben Gras
e64e75dbc5 also don't let user process change ss segment selector when returning from
signal.
2009-09-25 17:44:26 +00:00
Ben Gras
aa1c90fdd7 correct logic error in region.c. 2009-09-25 17:39:39 +00:00
Ben Gras
1d0854e6db pre-APPROVEd (thanks Arun) sanity check function. 2009-09-25 11:12:06 +00:00
Tomas Hruby
97fe6a4ba5 Broken pipes fix
- fix for the broken partial pipes r/w operations
2009-09-24 16:03:25 +00:00
Tomas Hruby
ab6fc64984 ps fix
It removes the no more existing marcos (XPIPE XPOPEN XDOPEN XLOCK XSELECT) and
replaces them with the new ones from servers/vfs/const.h No more dependency on
NR_TASKS macro.
2009-09-24 16:00:59 +00:00
Ben Gras
f236d1dd9c throw out the debugging stuff again. 2009-09-23 16:26:05 +00:00
Ben Gras
af77f4e964 debug output in SANITYCHECKS mode 2009-09-23 16:02:27 +00:00
Ben Gras
f87a91ce95 missing level-- in out-of-memory case. 2009-09-23 15:19:36 +00:00
Ben Gras
74616a057b temporarily disable munmap() to mask memory problem. 2009-09-23 13:34:04 +00:00
Ben Gras
4c11d7e6f5 - simplify findhole() for use for 1 page only
- do WMF_FREE
 - added WMF_VERIFY to check page table contents
 - randomize address space usage in vm self
2009-09-23 13:33:01 +00:00
Ben Gras
9e53925504 save a few lines of unnecessary output. 2009-09-23 13:27:21 +00:00
Arun Thomas
b2e3153263 Release script: Increase root ramdisk to 8KB 2009-09-23 11:07:55 +00:00
Ben Gras
0d7b967413 give sys_fork() a real endpoint_t * arg 2009-09-23 10:48:57 +00:00
Erik van der Kouwe
789c8a6ee4 Fixed compilation errors in ps.c and rs/manager.c. The former was fixed by disabling code using no-longer-existant flags and the latter by removing the spurious parameter i from sys_privctl 2009-09-23 08:46:17 +00:00
Tomas Hruby
dd0ea3aba0 NOT_REACHABLE() removed until ack will be taught to handle macros as a grownup
compiler
2009-09-23 07:25:04 +00:00
Tomas Hruby
7c10365f1b removed idt_reload()
- not part of klib386 yet
2009-09-23 07:20:57 +00:00
Tomas Hruby
f53377ed67 Removed the broken PROC_EVENT and SYN_ALARM from VFS 2009-09-22 22:11:20 +00:00
Tomas Hruby
8590ac260d Removed dependency of vfs on NR_TASKS macro
- all macros in consts.h that depend on NR_TASKS replaced by a FP_BLOCKED_ON_*

- fp_suspended removed and replaced by fp_blocked_on. Testing whether a process
  is supended is qeual to testing whether fp_blocked_on is FP_BLOCKED_ON_NONE or
  not

- fp_task is valid only if fp_blocked_on == FP_BLOCKED_ON_OTHER

- no need of special values that do not colide with valid and special endpoints
  since they are not used as endpoints anymore

- suspend only takes FP_BLOCKED_ON_* values not endpoints anymore

- suspend(task) replaced by wait_for(task) which sets fp_task so we remember who
  are we waiting for and suspend sets fp_blocked_on to FP_BLOCKED_ON_OTHER to
  signal that we are waiting for some other process

- some functions should take endpoint_t instead of int, fixed
2009-09-22 21:48:26 +00:00
Tomas Hruby
48602fcfae NOT_REACHABLE macro
- marks code path that should be unreachable (never executed)

- if hit, panics and reports the problem

- the end of main() marked as such. The SMP changes need some magic with stack
  switching before the AP can be started as they need to run on the boot stack
  before figuring out what is their own stack. As main() uses the boot stack to,
  we need to switch to to the stack of BSP before executing the last part of
  main() which needs to be in a separate function so we can jump to it.
  Therefore restart() won't be the last call in main() which may be confusing.
  The macro can/should be used in other such places too.
2009-09-22 21:46:47 +00:00
Tomas Hruby
c0a1fd1292 Removed NR_TASKS from macros manipulating endpoint_t
- the magic numbers ANY, NONE and SELF are kept for the compatibility with the
  current userspace. It is OK as long as NR_PROCS is greater so they don't
  colide with other endpoints

- the 32 bit endpoint_t value is split in half, lower 16 bits for process slot
  number and upper half for generation number

- transition to a structured endpoint_t in the future possible
2009-09-22 21:45:26 +00:00
Tomas Hruby
b900311656 endpoint_t in syslib
- headers use the endpoint_t in syslib.h and the implmentation was using int
  instead. Both uses endpoint_t now

- every variable named like proc, proc_nr or proc_nr_e of type endpoint_t has
  name proc_ep now

- endpoint_t defined as u32_t not int
2009-09-22 21:42:02 +00:00
Ben Gras
64df404150 umount before ramdisk spec to allow resizing 2009-09-22 14:01:17 +00:00
Ben Gras
6492bf0019 allow resizing of ramdisks. 2009-09-22 13:57:21 +00:00
Erik van der Kouwe
a97c9633ff Remove duplicate nanosleep stub 2009-09-22 12:05:22 +00:00
Ben Gras
0b713b0de5 unmap VR_DIRECT mappings too (fix for X) 2009-09-22 11:51:17 +00:00
Ben Gras
76a02db5e7 unused, thanks david 2009-09-21 21:00:36 +00:00
Ben Gras
c2324398f4 sha1 unused now. 2009-09-21 20:32:53 +00:00
Ben Gras
813021b56b forgot to svn add this. 2009-09-21 19:56:30 +00:00
Ben Gras
32fa22fc2d RS_LOOKUP feature for libc functions that want to access servers.
let ipc talk to all USER processes and vice versa.

pm sig wrapper notify has to be called from two files.

actually install include files.
2009-09-21 15:25:15 +00:00
Ben Gras
a5599efd9c fp might be NULL. 2009-09-21 15:23:08 +00:00
Ben Gras
a4d1b17453 ipc tests by GQ 2009-09-21 14:53:53 +00:00
Ben Gras
75d3db4911 new ipc server that implements shared memory and semaphores.
this server, tests, vm support, library stubs and other contributions
are the work of Guanqun Lu, a 2009 GSOC student.
2009-09-21 14:53:13 +00:00
Ben Gras
32fbbd370c - pages that points to page directory values of all processes,
shared with the kernel, mapped into kernel address space; 
   kernel is notified of its location. kernel segment size is
   increased to make it fit.
 - map in kernel and other processes that don't have their
   own page table using single 4MB (global) mapping.
 - new sanity check facility: objects that are allocated with
   the slab allocator are, when running with sanity checking on,
   marked readonly until they are explicitly unlocked using the USE()
   macro.
 - another sanity check facility: collect all uses of memory and
   see if they don't overlap with (a) eachother and (b) free memory
 - own munmap() and munmap_text() functions.
 - exec() recovers from out-of-memory conditions properly now; this
   solves some weird exec() behaviour
 - chew off memory from the same side of the chunk as where we
   start scanning, solving some memory fragmentation issues
 - use avl trees for freelist and phys_ranges in regions
 - implement most useful part of munmap()
 - remap() stuff is GQ's for shared memory
2009-09-21 14:49:49 +00:00
Ben Gras
f5459e38db - some exec debugging prints when errors happen
- lookup mounted_on check to avoid NULL dereference
 - some errors in exec() shouldn't be fatal
2009-09-21 14:49:26 +00:00
Ben Gras
e402927576 support for vm priv system.
fix NULL envp ptr.
2009-09-21 14:49:04 +00:00
Ben Gras
5f497bcf22 - Introduce some macros for field names, so that endpt, pendpt,
addr and taddr don't have to be defined any more, so that <sys/mman.h>
    can be included for proper prototypes of munmap() and friends.
  - rename our GETPID to MINIX_GETPID to avoid a name conflict with
    other sources
  - PM needs its own munmap() and munmap_text() to avoid sending messages
    to VM at the startup phase. It *does* want to do that, but only
    after initialising. So they're called again with unmap_ok set to 1
    later.
  - getnuid(), getngid() implementation
2009-09-21 14:48:19 +00:00
Ben Gras
a0d8cc0765 - No maximum block size any more.
- If allocation of a new buffer fails, use an already-allocated
   unused buffer if available (low memory conditions)
 - Allocate buffers dynamically, so memory isn't wasted on wrong-sized
   buffers.
 - No more _MAX_BLOCK_SIZE.
2009-09-21 14:47:51 +00:00
Ben Gras
08d291da53 no more scheduling queue dumps (kernel will print this over serial);
initial vm stats retrieve support
2009-09-21 14:47:24 +00:00
Ben Gras
90be3a051f clever hack to avoid starting from 0 disabled because
when own 0-pages are mapped out, this doesn't work and
isn't necessary.
2009-09-21 14:46:42 +00:00
Ben Gras
d6819ff659 various syscall entry points 2009-09-21 14:46:10 +00:00
Ben Gras
40411ea908 rename GETPID to MINIX_GETPID (for now); macro for field name 2009-09-21 14:45:46 +00:00
Ben Gras
76ba69151d more vm stubs 2009-09-21 14:45:09 +00:00
Ben Gras
e8b3ac74a6 ftime() 2009-09-21 14:44:35 +00:00
Ben Gras
b2adf0c1ae more pid queries; PM field macros; vm stubs 2009-09-21 14:44:00 +00:00
Ben Gras
348978e64a vm stubs; no more sys_vm_setbuf 2009-09-21 14:42:58 +00:00
Ben Gras
c9fee544b6 sysvipc dir 2009-09-21 14:42:13 +00:00
Ben Gras
da8360c0a3 change startup code to call munmap()/munmap_text() to map out
own 0-pages.
2009-09-21 14:41:47 +00:00
Ben Gras
1c217d038c new sysv ipc call stubs 2009-09-21 14:41:03 +00:00
Ben Gras
8c2bece89f - remove unused kmalloc
- initial implementation of _read_host_time_ns, a function to retrieve
   real-time in ns in vmware virtual machines
2009-09-21 14:39:15 +00:00
Ben Gras
cd8b915ed9 Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
    on every kernel entry (trap, interrupt, exception). the primary
    purpose is to reduce the number of required reloads.
Result:
  - kernel can only access memory of process that was running when
    kernel was entered
  - kernel must be mapped into every process page table, so traps to
    kernel keep working
Problem:
  - kernel must often access memory of arbitrary processes (e.g. send
    arbitrary processes messages); this can't happen directly any more;
    usually because that process' page table isn't loaded at all, sometimes
    because that memory isn't mapped in at all, sometimes because it isn't
    mapped in read-write.
So:
  - kernel must be able to map in memory of any process, in its own
    address space.
Implementation:
  - VM and kernel share a range of memory in which addresses of
    all page tables of all processes are available. This has two purposes:
      . Kernel has to know what data to copy in order to map in a range
      . Kernel has to know where to write the data in order to map it in
    That last point is because kernel has to write in the currently loaded
    page table.
  - Processes and kernel are separated through segments; kernel segments
    haven't changed.
  - The kernel keeps the process whose page table is currently loaded
    in 'ptproc.'
  - If it wants to map in a range of memory, it writes the value of the
    page directory entry for that range into the page directory entry
    in the currently loaded map. There is a slot reserved for such
    purposes. The kernel can then access this memory directly.
  - In order to do this, its segment has been increased (and the
    segments of processes start where it ends).
  - In the pagefault handler, detect if the kernel is doing
    'trappable' memory access (i.e. a pagefault isn't a fatal
     error) and if so,
       - set the saved instruction pointer to phys_copy_fault,
	 breaking out of phys_copy
       - set the saved eax register to the address of the page
	 fault, both for sanity checking and for checking in
	 which of the two ranges that phys_copy was called
	 with the fault occured
  - Some boot-time processes do not have their own page table,
    and are mapped in with the kernel, and separated with
    segments. The kernel detects this using HASPT. If such a
    process has to be scheduled, any page table will work and
    no page table switch is done.

Major changes in kernel are
  - When accessing user processes memory, kernel no longer
    explicitly checks before it does so if that memory is OK.
    It simply makes the mapping (if necessary), tries to do the
    operation, and traps the pagefault if that memory isn't present;
    if that happens, the copy function returns EFAULT.
    So all of the CHECKRANGE_OR_SUSPEND macros are gone.
  - Kernel no longer has to copy/read and parse page tables.
  - A message copying optimisation: when messages are copied, and
    the recipient isn't mapped in, they are copied into a buffer
    in the kernel. This is done in QueueMess. The next time
    the recipient is scheduled, this message is copied into
    its memory. This happens in schedcheck().
    This eliminates the mapping/copying step for messages, and makes
    it easier to deliver messages. This eliminates soft_notify.
  - Kernel no longer creates a page table at all, so the vm_setbuf
    and pagetable writing in memory.c is gone.

Minor changes in kernel are
  - ipc_stats thrown out, wasn't used
  - misc flags all renamed to MF_*
  - NOREC_* macros to enter and leave functions that should not
    be called recursively; just sanity checks really
  - code to fully decode segment selectors and descriptors
    to print on exceptions
  - lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 14:31:52 +00:00
Ben Gras
f5b04e1881 minor change to panic code 2009-09-21 14:28:16 +00:00
Ben Gras
ad4fc01b7b - new entry for bios_wini and ipc
- start ipc server on botting
2009-09-21 14:26:20 +00:00
Ben Gras
89bf7bae27 - tty: only report unrecognized scancodes once; forget about
remembering the origin and cursor position as that feature didn't
   really work properly anyway
 - tty: map in video and font memory using a vm call, access it from C,
   thereby eliminating pesky weird segment calls and assembly to access it,
   and unbreaks loadfont (Roman Ignatov)
 - bios_wini: fix bios_wini by allocating a <1MB buffers for it
 - memory: preallocate ramdisk, makes it a bit faster (and doesn't
   fail halfway if you allocate a huge one)
 - floppy: use <1MB buffer
 - ramdisk proto: because of the 2x1 page reservations, binaries
   got a little fatter and didn't fit on the ramdisk any more.
   increase it.
2009-09-21 14:25:54 +00:00
Ben Gras
36e935fe0f - added 'datasizes' script that shows you the size allocated
for each symbol, usually answering those "why is does my binary have
   such a lot of BSS" questions.
 - stop binpackage looking in /var/spool for package files.
 - let makewhatis recognize .Sh as heading name
 - setup, fsck, df: allow >4kB block sizes painlessly
 - mkfs: new #-of-inodes heuristic that depends on kb, not
   on blocks; i've run out of inodes on my /usr
 - asmconv: don't silently truncate .aligns to 16 bytes
 - ipc* commands for shared memory support
2009-09-21 14:24:29 +00:00
Ben Gras
ba91b3b7d2 - remove unused bootdelay feauture
- only print a line for every boot process if 'verbose' variable set to
   nonzero; reason: with serial output, the long output
   significantly slows down frequent reboots, and causes 'scroll damage'
   that in some cases is pretty bad. also the verbose output doesn't tell
   you the one thing you might want to know about a process: how much memory
   is it using? or how much memory is everything using?
 - short format does print out total memory allocated for processes
2009-09-21 14:23:47 +00:00
Ben Gras
8a54d267f0 - VM_KERN_NOPAGEZERO feature is gone
- sys_getbiosbuffer feature is gone (from kernel; available from vm)
- bump version number because munmap() calls that newly compiled binaries
  will do trigger an ugly (but harmless) error message in older VM's
- some new VM calls and flags, the new IPC calls
- some new CR0 register bits
- added files for shared memory
2009-09-21 14:23:10 +00:00
David van Moolenbroek
0a27cf279e test31 fix 2009-09-20 18:15:24 +00:00
David van Moolenbroek
1fe1b219c9 test32 fix 2009-09-20 16:47:57 +00:00
David van Moolenbroek
f2def7d360 Kernel: correct a few SYSTEM source documentation comments 2009-09-17 20:51:34 +00:00
Tomas Hruby
db56801ddc Some clean up of the segment selectors macros
- [ABCD]_INDEX are not used anywhere

- value of *_SELECTOR is now calculated using the *_INDEX value so changing the
  index does not break the selector

- TSS is now the last of the global selectors. There will be TSS per CPU on SMP
  and the number will vary depending on the maximal supported number of CPUs
  configured
2009-09-15 10:01:06 +00:00
Tomas Hruby
71077d1228 iskernelp() and isuserp() test pointers
- we may test even not fully initialized entries, e.g. during boot
  crash

- is we know the process number we should use iskerneln
  and isusern
2009-09-15 09:58:46 +00:00
Tomas Hruby
78793f4f38 pproc_addr unused and removed 2009-09-15 09:57:54 +00:00
Tomas Hruby
4fd433694f proc_addr() returns address based on location in proc array
- pproc_addr is not neccessary to get the address of a process if we know its
  number

- local proc variables in system calls implementation (sys_task) conflicts with
  the global proc array of all process, therefore the variable were renamed to
  proc_nr as they hold the process number
2009-09-15 09:57:22 +00:00
Erik van der Kouwe
3615d93383 Handle SIGSTOP more consistently and according to POSIX rules; it can no longer be ignored 2009-09-13 12:24:23 +00:00
David van Moolenbroek
ba83b7663d PM: some tiny fixes 2009-09-12 18:36:07 +00:00
David van Moolenbroek
c72487dc9f remove unused NEW_KSIG definition 2009-09-07 22:12:50 +00:00
David van Moolenbroek
e538509508 Kernel: remove unused CHECK_DEADLOCK definition 2009-09-07 20:23:31 +00:00
David van Moolenbroek
18ae423990 it's/its 2009-09-06 17:13:08 +00:00
David van Moolenbroek
9c19233879 Kernel: do_[sv]devio.c header corrections 2009-09-06 15:54:15 +00:00
David van Moolenbroek
8ef6c9b063 cleanup: sys_irqrmpolicy does not need IRQ vector 2009-09-06 14:24:44 +00:00
David van Moolenbroek
9b417d616f remove unused IRQ_ENDPT definition 2009-09-06 14:14:03 +00:00
David van Moolenbroek
979bcfc195 - sys_privctl: don't mix message types
- sys_privctl: remove CTL_MM_PRIV (third parameter)
- remove obsolete sys_svrctl.c library file
2009-09-06 12:37:13 +00:00
David van Moolenbroek
32b2758ba8 syslib: make sys_nice use field aliases 2009-09-05 12:51:00 +00:00
Erik van der Kouwe
f92e0dafb5 Disabled check in test 28 which hard links a directory; this is nott required by POSIX and not supported (currently) by MINIX. Also corrected total number of tests. 2009-09-04 20:23:25 +00:00
Erik van der Kouwe
141e5531ad Now all tests except for 28 succeed in root mode 2009-09-04 14:14:49 +00:00
Erik van der Kouwe
9dda815067 Remove redundant line from previous patch 2009-09-04 13:36:43 +00:00
Erik van der Kouwe
e1e4d6649f Allow setuid tests 11 and 33 to run. The former still fails (but now with a meaningful error) while the latter succeeds. Only 2 tests are left borken on default MINIX, namely 11 and 28. 2009-09-04 13:18:49 +00:00
Erik van der Kouwe
ec4b567894 Avoid alarm to prevent the setitimer interval from being reset 2009-09-03 20:35:22 +00:00
Thomas Veerman
360dc9104c - Added netconf script which makes it a lot easier to change network settings.
- Modified the setup script to use the netconf script for the network
   configuration:
    - Moved step 2 to step 8 and renamed the steps in between.
    - Autopart adapted to print step 3 instead of step 4.
2009-09-03 09:38:27 +00:00
David van Moolenbroek
8aeb17c75e typo 2009-09-02 21:55:26 +00:00
Ben Gras
3d3e12f50f postgresql services entry. 2009-09-02 13:23:22 +00:00
David van Moolenbroek
7e9e0ce9bc FXP: support for 8086/1064 (reported and tested by Jose Luis Sanchez) 2009-08-30 16:13:46 +00:00
David van Moolenbroek
a57fbb11cd Fix time(1) for custom system HZ values (reported by Jose Luis Sanchez 2009-08-30 16:06:59 +00:00
Tomas Hruby
2e293ce7c0 system_init() renamed to arch_init()
- a better name for architecture specific init function

- some of x86 init code must execute in protected mode

- prot_init() removed from this function and still called in cstart() Imho this
  should be called from the architecture specific assembly not cstart. cstart
  perform Minix monitor specific tasks and will be touched once another
  bootloader is in use, e.g. booting via tftp, therefore we keep it as is for
  now.

- this is a backport from the SMP code which requires this. Merging will be simpler
2009-08-30 14:55:30 +00:00
Tomas Hruby
b1aaee6dcc Printing the trap info even if kernel crashes is handy. 2009-08-29 19:38:11 +00:00
Tomas Hruby
50473107c2 saved_proc in exception() may be NULL
If an exception happens in kernel while the kernel is booting and no processes
are running yet, saved_proc == NULL and priting any process related information
results in dumping rubish.

This check is mostly useful when debugging kernel stuff. Should _never_ happen
on a production kernel.
2009-08-29 19:26:46 +00:00
David van Moolenbroek
42f0bf7dda VFS: fetch_name() buffer underflow (reported by John Peace, bug #305) 2009-08-29 08:22:50 +00:00
Tomas Hruby
4903a734b8 IDT is initialized in idt_init() not in prot_init()
This is a backport form the SMP branch. Not required here, it only makes life
for SMP easier. And future merging too.

- filling the IDT is removed from prot_init()

- struct gate_table_s is a public type

- gate_table_pic is a global array as it is used by APIC code too

- idt_copy_vectors() is also global and used by idt_init() as well as
  apic_idt_init()

- idt_init() is called right after prot_init() in system_init()
2009-08-28 15:55:30 +00:00
Erik van der Kouwe
1162806940 Re-disable complete_bars, it was not needed for PRO/100 despite the error message 2009-08-27 07:10:03 +00:00
Erik van der Kouwe
ada4859302 Extend Intel PRO/100 support 2009-08-26 21:01:46 +00:00
David van Moolenbroek
d84472dfc8 urlget: broken ftpget call, reported by Charles Littlefield 2009-08-23 13:53:03 +00:00
David van Moolenbroek
47e6506d7b support for TCP sockets in send/sendto/recv/recvfrom 2009-08-21 09:59:09 +00:00
Erik van der Kouwe
5cdd995dc5 Use su to allow tests 3, 6, 17, 18, 19, 21 and 25 to work as root, making testing easier 2009-08-18 19:58:34 +00:00
Erik van der Kouwe
192c0be4a8 Fix HUGE_VAL warnings 2009-08-18 19:10:48 +00:00
Erik van der Kouwe
d81563a9b1 Fix HUGE_VAL warnings 2009-08-18 19:10:20 +00:00
Tomas Hruby
f3e0c5c381 VFS quits gracefully if mount fails and mounted_on remains uninitialized 2009-08-18 13:30:05 +00:00
Thomas Veerman
b47483433c Added a hack to start binaries from the boot image only. In particular, setting
bin_img=1 in the boot monitor will make sure that during the boot procedure the
mfs binary that is part of the boot image is the only binary that is used to
mount partitions. This is useful when for some reason the mfs binary on disk 
malfunctions, rendering Minix unable to boot. By setting bin_img=1, the binary
on disk is ignored and the binary in the boot image is used instead.

- 'service' now accepts an additional flag -r. -r implies -c. -r instructs RS
  to first look in memory if the binary has already been copied to memory and
  execute that version, instead of loading the binary from disk. For example,
  the first time a MFS is being started it is copied (-c) to memory and
  executed from there. The second time MFS is being started this way, RS will
  look in memory for a previously copied MFS binary and reuse it if it exists.
- The mount and newroot commands now accept an additional flag -i, which
  instructs them to set the MS_REUSE flag in the mount flags.
- The mount system call now supports the MS_REUSE flag and invokes 'service'
  with the -r flag when MS_REUSE is set.
- /etc/rc and the rc script that's included in the boot image check for the
  existence of the bin_img flag in the boot monitor, and invoke mount and 
  newroot with the -i flag accordingly.
2009-08-18 11:36:01 +00:00
David van Moolenbroek
47a2bfeddd small errno.h corrections 2009-08-18 09:26:51 +00:00
Erik van der Kouwe
5490ef1083 Fixed some warnings 2009-08-17 18:49:15 +00:00
Erik van der Kouwe
fdf47c1046 Fixed some warnings 2009-08-17 18:49:07 +00:00
Erik van der Kouwe
b3ab0cb03a Fixed some warnings 2009-08-17 18:48:57 +00:00
Erik van der Kouwe
fcbb7ac780 Fixed some warnings 2009-08-17 18:48:27 +00:00
Erik van der Kouwe
2d7dfd1a46 Fix warning in panic 2009-08-17 17:56:34 +00:00
Tomas Hruby
bd2dd15cc6 Missing defines preventing recursive includesion in some include/sys/*.h files 2009-08-17 14:34:14 +00:00
Erik van der Kouwe
d1b4c5be5b Removed obsolete declarations in include/ipc.h 2009-08-16 15:12:07 +00:00
Erik van der Kouwe
f5421e64f8 Nanosleep was implemented twice, removed from _sleep.c 2009-08-16 12:55:59 +00:00
Erik van der Kouwe
3573bc1abe Function nanosleep now checks arguments 2009-08-16 12:13:33 +00:00
Erik van der Kouwe
83b84cbe64 Man page for new function nanosleep(3), updated man page for sleep(3) 2009-08-16 12:12:40 +00:00
David van Moolenbroek
247e1e8fa8 man page fix: sigaction.2 signals list 2009-08-15 23:27:32 +00:00
David van Moolenbroek
769a0cdb35 PM: make SIGBUS, but not SIGUSR1 or SIGUSR2, cause a core dump 2009-08-15 23:23:24 +00:00
David van Moolenbroek
ff6318d559 run test 41, too (oops) 2009-08-15 22:31:38 +00:00
David van Moolenbroek
5a13b2eda8 nanosleep(3), and sleep(3) rewrite, by Erik van der Kouwe 2009-08-15 22:14:48 +00:00
David van Moolenbroek
323f0abdd6 Support for setitimer(ITIMER_VIRTUAL/ITIMER_PROF). New test (41) for setitimer. 2009-08-15 21:37:26 +00:00
David van Moolenbroek
d82e260a90 Support for setitimer(ITIMER_REAL). 2009-08-15 16:09:32 +00:00
David van Moolenbroek
062bb2c1e8 fix test14's "clever" (broken) filename generation 2009-08-15 15:13:57 +00:00
David van Moolenbroek
4db12454e9 awk: support for whitespace between array name and bracket 2009-08-15 12:05:41 +00:00
David van Moolenbroek
708929bc32 awk: support for ENVIRON 2009-08-15 11:34:41 +00:00
Tomas Hruby
88f7b63019 u64_t for human beings - the high and low parts are named hi and lo, lib/sysutil/profile.c updated accordingly 2009-08-13 15:47:49 +00:00
David van Moolenbroek
aae63b5410 move _mount.c from lib/posix to lib/other 2009-08-13 09:55:50 +00:00
Thomas Veerman
f50d94b793 Fixed compilation issue. 2009-08-13 09:02:43 +00:00
Thomas Veerman
c2ffe723d1 - Moved (u)mount prototypes from unistd.h to sys/mount.h.
- Prepared mount system call to accept multiple mount flags
   instead of just read_only (however, it remains backwards
   compatible).
 - Updated the man mount(2) to reflect new header file usage. 
 - Updated badblocks, newroot, mount, and umount commands to use the
   new header file.
2009-08-12 19:57:37 +00:00
David van Moolenbroek
1defc4fc3a compile and install mdb(1) by default again 2009-08-11 09:08:33 +00:00
Tomas Hruby
09a47e6a40 vm_assert macros fix up 2009-08-11 07:53:32 +00:00
Arun Thomas
b8eedfee6b Lance cleanup 2009-07-22 12:36:19 +00:00
Thomas Veerman
df41717f44 Fixed case error 2009-07-22 08:59:57 +00:00
David van Moolenbroek
5a370afc8e MFS put_inode issues (reported by Maurizio Lombardi) 2009-07-22 08:54:28 +00:00
Arun Thomas
0be5720af1 Fix VirtualBox Lance bug; ec_reinit should be called only once. 2009-07-21 13:13:45 +00:00
Thomas Veerman
70d25344a2 Added select test 2009-07-14 09:43:33 +00:00
Thomas Veerman
ce916bcb91 Fixed a minor select bug:
- When one does a select on a file descriptor that is meaningless for that particular file type, select shall indicate that the file descriptor is ready for that particular operation and that the file descriptor has no exceptional condition pending.
2009-07-14 09:39:05 +00:00
David van Moolenbroek
b21beea985 IS: fix up PM flags field somewhat 2009-07-12 15:30:59 +00:00
David van Moolenbroek
1d0e43c8f1 make remove(3) remove directories as well 2009-07-12 14:44:37 +00:00
David van Moolenbroek
f80aaae86a MFS: remove some redundant code (reported by Maurizio Lombardi) 2009-07-12 13:57:34 +00:00
David van Moolenbroek
013241a006 RS: the plural of 'child' is 'children' 2009-07-11 17:59:05 +00:00
David van Moolenbroek
cf89d27218 make unstack work on gcc-compiled binaries 2009-07-11 17:55:24 +00:00
David van Moolenbroek
9e075d8623 PM cleanup: remove unused fields from mproc structure 2009-07-11 17:15:33 +00:00
David van Moolenbroek
1a9e07b0e5 PM: fix ptrace(T_EXIT) 'exit_proc: not idle' race condition. 2009-07-11 13:22:56 +00:00
David van Moolenbroek
14f3a0e018 PM: add clarifying comment about exiting system processes early (thanks Philip) 2009-07-11 11:19:39 +00:00
David van Moolenbroek
9808816c14 MFS fixes:
- Don't dereference NULL dir inode in advance_* (reported by Maurizio Lombardi)
- Fix potential inode reference leak in fs_slink_*
2009-07-11 10:36:57 +00:00
David van Moolenbroek
73c5bbf1a3 PM: add EXITING process flag as stopgap between starting coredump and setting ZOMBIE flag 2009-07-09 22:33:56 +00:00
David van Moolenbroek
1450a8ac6d let IS call getuptime() 2009-07-09 20:54:35 +00:00
David van Moolenbroek
f15d1fb13d Fix race condition in test 25 2009-07-09 11:44:35 +00:00
David van Moolenbroek
693a6652ca PM cleanup: remove obsolete HAS_DMA flag 2009-07-08 20:08:46 +00:00
David van Moolenbroek
67d986f882 PM cleanup: merge exit and coredump paths 2009-07-08 17:16:53 +00:00
David van Moolenbroek
5e173f55f5 Remove leftover PowerPC cruft. Reported by Evgeniy Ivanov. 2009-07-07 18:55:11 +00:00
David van Moolenbroek
12451e6b06 Miscellaneous PM fixes:
o Don't call vm_willexit() more than once upon normal process exit
o Correct two cases of indenting of the no-discussion-possible kind
o Perform slightly stricter ptrace(2) checks:
  - process calling ptrace must be target process's parent
  - process must call wait/waitpid before using ptrace on stopped child
  - no ptrace on zombies
o Allow user processes to use ptrace(T_STOP) to stop an active child
2009-07-05 22:48:18 +00:00
David van Moolenbroek
b8b8f537bd IPC privileges fixes
Kernel:
o Remove s_ipc_sendrec, instead using s_ipc_to for all send primitives
o Centralize s_ipc_to bit manipulation,
  - disallowing assignment of bits pointing to unused priv structs;
  - preventing send-to-self by not setting bit for own priv struct;
  - preserving send mask matrix symmetry in all cases
o Add IPC send mask checks to SENDA, which were missing entirely somehow
o Slightly improve IPC stats accounting for SENDA
o Remove SYSTEM from user processes' send mask
o Half-fix the dependency between boot image order and process numbers,
  - correcting the table order of the boot processes;
  - documenting the order requirement needed for proper send masks;
  - warning at boot time if the order is violated

RS:
o Add support in /etc/drivers.conf for servers that talk to user processes,
  - disallowing IPC to user processes if no "ipc" field is present
  - adding a special "USER" label to explicitly allow IPC to user processes
o Always apply IPC masks when specified; remove -i flag from service(8)
o Use kernel send mask symmetry to delay adding IPC permissions for labels
  that do not exist yet, adding them to that label's process upon creation
o Add VM to ipc permissions list for rtl8139 and fxp in drivers.conf

Left to future fixes:
o Removal of the table order vs process numbers dependency altogether,
  possibly using per-process send list structures as used for SYSTEM calls
o Proper assignment of send masks to boot processes;
  some of the assigned (~0) masks are much wider than necessary
o Proper assignment of IPC send masks for many more servers in drivers.conf
o Removal of the debugging warning about the now legitimate case where RS's
  add_forward_ipc cannot find the IPC destination's label yet
2009-07-02 16:25:31 +00:00
David van Moolenbroek
aa84986819 more small man page fixes 2009-06-25 10:41:55 +00:00
David van Moolenbroek
be9606a4e0 random man page update: cut.1 2009-06-24 21:13:28 +00:00
David van Moolenbroek
3018cd023a random man page fix: cawf.1 2009-06-24 11:42:05 +00:00
David van Moolenbroek
951581a29c fix installation of home directories in setup.sh 2009-06-23 13:40:32 +00:00
Arun Thomas
dacc0644c8 Restore last(1) and uptime(1) building/installing. 2009-06-23 12:22:35 +00:00
David van Moolenbroek
d8b9bf642b make mdb(1) compile again 2009-06-17 14:59:22 +00:00
David van Moolenbroek
66d1f1260c remove last traces of FSDEVMAP svrctl 2009-06-13 13:09:14 +00:00
David van Moolenbroek
87beb9c469 better solution for poweroff(8) 2009-06-12 13:17:33 +00:00
David van Moolenbroek
12a01e8f01 poweroff(8) aesthetics 2009-06-12 13:13:29 +00:00
David van Moolenbroek
24bb7fbb4c added poweroff(8) 2009-06-12 13:02:51 +00:00
Arun Thomas
86d89ed3f1 ls(1) manpage corrections
-Add missing '-n' option to synopsis.
-MINIX 3 does support symbolic links now.

Thanks to River Tarnell for the patch.
2009-05-30 11:01:17 +00:00
Arun Thomas
a415b68523 Release.sh now uses packages.install and package_sources.install to
determine which packages and package sources to include on the
installation media, as opposed to including everything in the
PACKAGEDIR AND PACKAGESOURCEDIR directories.
2009-05-30 09:31:19 +00:00
Arun Thomas
dac531addf Support for VMWare Workstation 6.x
VMWare Workstation 6.x would previously die when running MINIX 3 with an
IOSPACE assertion and several error messages about multiply registered
I/O ports. The assertion is triggered when we probe for BAR sizes in
record_bar(). The solution: The PCI driver now disables I/O and mem
access before probing for BAR sizes.

Bumped up NR_PCIDEV and NR_PCIBUS, since Workstation 6.x virtualizes
more PCI buses and devices.
2009-05-27 23:35:34 +00:00
Arun Thomas
745f99bb1d Update issue.install for 3.1.4 2009-05-27 12:42:32 +00:00
David van Moolenbroek
83885ebc39 make lseek64 return correct new position 2009-05-23 13:47:17 +00:00
David van Moolenbroek
00a2463d71 update readlink(2) manpage accordingly 2009-05-20 11:49:10 +00:00
David van Moolenbroek
9797d17d54 move symlink type check for readlink() into VFS, and return the right POSIX error 2009-05-20 09:46:06 +00:00
David van Moolenbroek
50b77e3529 VFS consistency: use I_PIPE/NO_PIPE when checking v_pipe 2009-05-19 14:34:44 +00:00
Ben Gras
8ee3d26722 don't include /usr/src changes in packages. 2009-05-19 10:55:15 +00:00
Ben Gras
fe39483dc9 4MB mask 2009-05-18 15:56:13 +00:00
Ben Gras
f86da99e67 map in kernel in 4MB, global-bit-set 'pages' if hardware
supports it. helps performance.

broken use of region data structure for kernel mapping to be fixed.
2009-05-18 15:34:42 +00:00
David van Moolenbroek
f76d75a5ec Various VFS and MFS fixes to improve correctness, consistency and
POSIX compliance.

VFS changes:
* truncate() on a file system mounted read-only no longer panics MFS.
* ftruncate() and fcntl(F_FREESP) now check for write permission on
  the file descriptor instead of the file, write().
* utime(), chown() and fchown() now check for file system read-only
  status.

MFS changes:
* link() and rename() no longer return the internal EENTERMOUNT and
  ELEAVEMOUNT errors to the application as part of a check on the
  source path.
* rename() now treats EENTERMOUNT from the destination path check as
  an error, preventing file system corruption from renaming a normal
  directory to an existing mountpoint directory.
* mountpoints (mounted-on dirs) are hidden better during lookups:
  - if a lookup starts from a mountpoint, the first component has to
    be ".." (anything else being a VFS-FS protocol violation).
  - in that case, the permissions of the mountpoint are not checked.
  - in all other cases, visiting a mountpoint always results in
    EENTERMOUNT.
* a lookup on ".." from a mount root or chroot(2) root no longer
  succeeds if the caller does not have search permission on that
  directory.
* POSIX: getdents() now updates directory access times.
* POSIX: readlink() now returns partial results instead of ERANGE.

Miscellaneous changes:
* semaphore file handling bug (leading to hangs) fixed in test 32.

The VFS changes should now put the burden of checking for read-only
status of file systems entirely on VFS, and limit the access
permission checks that file systems have to perform, to checking
search permission on directories during lookups. From this point on,
any deviation from that spceification should be considered a bug.
Note that for legacy reasons, the root partition is assumed to be
mounted read-write.
2009-05-18 11:27:12 +00:00
Ben Gras
bdab3c4cfb Library call for cpu features; make kernel and vm use this to query cpu
features (specifically: 4MB pages and TLB global bit).  Only enable
these features in CR4 if available. 4MB pages to be used in the near
future.
2009-05-15 17:07:36 +00:00
Ben Gras
d0b6e76bfb correct the revision variable used in /etc/version 2009-05-15 13:02:23 +00:00
Arun Thomas
d749b3b965 -Remove qemu_pci boot variable. Useres no longer need to set qemu_pci when
booting MINIX under QEMU/KVM.
-Kept the diagnostic message, however.
2009-05-14 19:07:37 +00:00
Ben Gras
143422fa0a C CPUID interface. 2009-05-14 15:55:28 +00:00
Arun Thomas
db4faccbf9 -Installation info is on the wiki now, so remove setup guides and update
README.
-Remove obsolete FAT partitioning utility.
-Update startup banner.
2009-05-14 15:54:02 +00:00
David van Moolenbroek
c2aef85eda Clear trace bit for child on fork.
Without this, a forking single-stepped process will have its child
die from a TRAP signal right away.
2009-05-13 21:58:10 +00:00
David van Moolenbroek
fe8c612aa4 support in 'mount' for specifying file system type and options 2009-05-13 15:39:44 +00:00
David van Moolenbroek
3affa4c796 'service' null pointer dereference fix 2009-05-12 16:52:00 +00:00
Ben Gras
dd56aa321f to let tty run with its own page table (instead of with the kernel identity
map table), make it map in video memory.

sadly, this breaks tty in non-paged mode.

happily, this simplifies the code by throwing out the messing
around with segments, and throws out vidcopy.s.
2009-05-12 12:43:18 +00:00
Ben Gras
909c1bb8a7 don't bother with unmapping physical memory in non-sanitycheck mode. 2009-05-12 11:51:53 +00:00
Ben Gras
581e68433a basic sparepage optimisation
some simplification of linear/virtual address translation
(less hardcoding and more use of arch_*2* functions)
2009-05-12 11:38:29 +00:00
Ben Gras
f9e81cb57b remove bogus arch_map2vir calls 2009-05-12 11:36:15 +00:00
Ben Gras
6fad23f500 don't call this function with a bogus addr (done by region.c print code) 2009-05-12 11:35:49 +00:00
Ben Gras
e3ca89c0be more sanity checking. sanity checking disabled by default.
give every process a full pagetable by default now.

first step to disabling kernel page table code (processes
might not have page tables -> no address translation).
2009-05-12 11:35:01 +00:00
Ben Gras
ebe050dbe2 large page size constant. 2009-05-12 09:23:27 +00:00
Ben Gras
d2caeb6146 start all processes, including VM, in VM_PROCSTART in linear address space,
to make space for kernel to be able to map in things below there.
2009-05-11 19:11:37 +00:00
Ben Gras
ade4c03b73 Don't build arch objs more than once. 2009-05-11 19:05:45 +00:00
Ben Gras
7c88767f75 remove debug msg 2009-05-11 11:57:20 +00:00
David van Moolenbroek
9a01c828c8 VFS-FS error codes: better safe than sorry 2009-05-11 11:30:04 +00:00
David van Moolenbroek
0ac1aaccca Limited support for nested FS->VFS requests during VFS->FS call.
- Changed VFS-FS protocol to only store OK or negative error code in
  m_type field of reply messages.
- Changed VFS to treat nonzero positive replies from FS as requests.
- Added backwards compatibility to VFS and MFS.
No protection of global data structures is provided in VFS, so many
VFS calls cannot be made safely by FS servers during many FS calls.
Use with caution (or, preferably, not at all).
2009-05-11 10:02:28 +00:00
David van Moolenbroek
dcfaf50f79 wrong field index in at_wini env_parse call 2009-05-10 16:58:23 +00:00
David van Moolenbroek
a2485b346c potential buffer overruns in env_* routines 2009-05-10 16:54:37 +00:00
David van Moolenbroek
e08b38a5c4 regression fix: vfs lookup passes incorrect chroot information after crossing mountpoints 2009-05-09 17:53:22 +00:00
David van Moolenbroek
021808b12a fix for commands that try to include mfs constants from vfs 2009-05-08 20:37:06 +00:00
David van Moolenbroek
293be6b80b quick cleanup of old mfs cruft from vfs 2009-05-08 14:12:41 +00:00
Ben Gras
dc1238b7b9 make unpause() decrease susp_count, as it shouldn't be decreased
if the process was REVIVING. (susp_count doesn't count those
 processes.) this together with dev_io SELECT suspend side effect
 for asynch. character devices solves the hanging pipe bug. or
 at last vastly improves it.

 added sanity checks, turned off by default.

 made the {NOT_,}{SUSPENDING,REVIVING} constants weirder to
 help sanity checking.
2009-05-08 13:56:41 +00:00
David van Moolenbroek
113b1ec5f3 remove unused global variable from vfs 2009-05-08 13:54:01 +00:00
Ben Gras
ece26e2731 don't suspend the process as a side-effect if
device returns SUSPEND if it's select; select already
does this.
2009-05-08 13:50:29 +00:00
David van Moolenbroek
2a48c4ad48 Reenable RS table dump from IS (Shift+F6) 2009-05-08 12:38:14 +00:00
David van Moolenbroek
e9e347f5b6 Fix for large transfer operations not advancing buffer address
offset when DMA transfer unit is smaller than given buffer size.
Bug tracker item #82.
2009-05-08 12:29:57 +00:00
David van Moolenbroek
4af032bbfe Kernel interrupt hook management fixes:
- properly assign unique hook IDs
- after hook removal, remove hook-specific interrupt disable flag
2009-05-07 14:52:07 +00:00
Ben Gras
a38287067a disable scary looking debug messages. 2009-05-07 09:58:16 +00:00
Ben Gras
746e138036 turn off scary looking debug messages. 2009-05-07 09:57:43 +00:00
Ben Gras
8b72765e39 ignore errors of pipe read (can happen with shutdown now,
now that all fd's are closed neatly in vfs), change messaging
in unexpected restarts
2009-05-06 15:38:32 +00:00
Ben Gras
fd7ef243e4 cleanup of vfs shutdown logic; makes clean unmounts easier (but
needs checking if fp_wd or fp_rd is NULL before use)
2009-04-29 16:59:18 +00:00
Ben Gras
b7e23b70e8 - delete unused .h files
- slight code cleanup
 - neater exit procedure: exit when unmount
   message received and kill signal (from RS 'down' or
   reboot/shutdown) received (speed up unmount, but don't
   confuse VFS by exiting before/during unmount msg)
2009-04-27 16:13:51 +00:00
Ben Gras
bb23344283 spurious debug 2009-04-27 16:11:38 +00:00
Ben Gras
02f047d008 lose -s flag for umount. 2009-04-27 14:23:57 +00:00
Ben Gras
a12113e476 process restarts are pretty rare/serious. 2009-04-27 14:07:47 +00:00
Ben Gras
4593eaec24 minor fixes to install script - allow 8kB blocksize (necessary for
large filesystems)
2009-04-27 12:59:49 +00:00
Ben Gras
60e7602aad When we receive a PROC_EVENT message from PM, exit nicely; avoids
annoying graceful RS timeout on unmount.
2009-04-27 12:02:31 +00:00
Ben Gras
e5209d51f1 bad dma fallback to pio mode 2009-04-27 11:53:11 +00:00
Ben Gras
3b3e3b36c2 some more vm bits. 2009-04-23 15:21:03 +00:00
Ben Gras
ef8a741301 set global flag for kernel pages, so tlb entries for kernel aren't thrown
away on cr3 reload. minor optimization.
2009-04-23 15:11:16 +00:00
Arun Thomas
e9e1ae1cfc Move queue.h to include/sys so that it can be used elsewhere. Pull in
FreeBSD's r179210 queue.h.
2009-04-22 20:02:39 +00:00
Arun Thomas
f149733e16 Disable IOMMU warnings. 2009-04-22 16:53:46 +00:00
Arun Thomas
3b37103fa3 Make the rtl8139 and orinoco drivers handle the system shutdown case
like other drivers. Also, some minor cleanups.
2009-04-22 12:42:37 +00:00
Ben Gras
2dd02cc560 mark pages whose refcount were >1 and drop to 1 and are
read/write writable in the pagetable right away instead of waiting for
a pagefault. minor optimization.

some a sanity check of SLAB-allocated pointers.

vm gets its own _exit and __exit like PM, so the stock (library) panic works.
2009-04-22 12:39:29 +00:00
Ben Gras
e0f3a5acf1 - enable ipc warnings by default
- ipc checking code in kernel didn't properly catch the
   sendrec() to self case; added special case check
 - triggered by PM using stock panic() - needs its own _exit()

reported by Joren l'Ami.
2009-04-17 13:46:37 +00:00
Ben Gras
e5717f7aef clarify not found error message a bit. 2009-04-14 14:16:24 +00:00
Ben Gras
4cd6875d05 don't flush output for SIGWINCH. found by Joren l'Ami. 2009-04-06 09:39:42 +00:00
Ben Gras
65a9f0253b unnecessary debugging message 2009-04-02 16:43:35 +00:00
Ben Gras
9647fbc94e moved type and constants for random data to include file;
added consistency check in random; added source of randomness
internal to random using timing; only retrieve random bins that are full.
2009-04-02 15:24:44 +00:00
Ben Gras
51596bc608 print who the message is from. 2009-04-02 11:56:50 +00:00
Ben Gras
73ee8b8b99 don't make susp_count negative. 2009-04-02 11:44:26 +00:00
Ben Gras
b560a36b20 trace fix contributed by Joren l'Ami 2009-04-02 11:38:23 +00:00
Ben Gras
dc9a1bc30c increment nph when printing physical regions; suggested by Guanqun Lu 2009-03-31 14:26:24 +00:00
Ben Gras
45d54cf1b0 change DmaMode checks from DEV_WRITE to DEV_WRITE_S 2009-03-31 14:23:33 +00:00
Arun Thomas
9e7837f63c Tweak 64-bit integer type declarations; Fixes GCC sysutil build
breakage.
2009-03-30 17:07:39 +00:00
Ben Gras
3bb80322d9 suppress more mostly-harmless messages. 2009-03-26 16:11:27 +00:00
Ben Gras
2d1c884e35 suppress these noisy, alarming messages. 2009-03-26 15:56:08 +00:00
Ben Gras
cd2d85c13d no 'small minix' option 2009-03-26 15:54:09 +00:00
Ben Gras
f56316a168 don't need to explicitly enable lance any more. 2009-03-26 15:23:07 +00:00
Ben Gras
cf8c4cc851 ignore linmem.
don't disable the driver by default.
2009-03-26 15:22:08 +00:00
Ben Gras
4e2291fff2 SizeMB isn't used any more. 2009-03-26 13:19:14 +00:00
Ben Gras
ec50fa00c7 don't execute hlt in real mode.
workaround for getting minix under qemu kvm.
Ameya, ape800 at few.vu.nl.
2009-03-24 16:08:10 +00:00
Ben Gras
fc11209417 more inodes than default for /usr on cd. 2009-03-24 15:41:51 +00:00
Ben Gras
46d28c6ffb workaround for qemu writing the configuration byte on the AUX port pre-0.10. 2009-03-24 15:41:18 +00:00
Ben Gras
d8d63f0e07 make USRMB settable 2009-03-19 14:14:57 +00:00
Ben Gras
e5079dfc02 multiple ram disks; also make release process use this
so temporary partitions aren't needed any more.
2009-03-19 13:48:19 +00:00
Arun Thomas
347fa61675 Increase ARG_MAX 2009-03-17 07:38:35 +00:00
Arun Thomas
5eb353ebbc Update setup's NIC selection dialog 2009-03-06 17:45:22 +00:00
Arun Thomas
7ce582c783 Define 64 bit integer types when compiling with GCC 2009-03-06 16:56:46 +00:00
Ben Gras
8af5f877bc 2009-03-04 17:44:34 +00:00
Ben Gras
3f6e061948 fix error check 2009-03-04 17:38:27 +00:00
Ben Gras
a742aed5ad only assign value if request went ok. 2009-02-19 17:14:36 +00:00
Ben Gras
cd37a0299c Check for firstdatazone overflow. 2009-02-17 13:01:25 +00:00
Ben Gras
733d6c1ef6 help debugging cause of these sometimes odd calls. 2009-02-17 12:09:59 +00:00
Ben Gras
570b9cd753 Checking wrong inode pointer for refcount in mount (!) 2009-02-17 09:50:02 +00:00
Ben Gras
379be7f0fb A serial ata pci card we have. 2009-02-16 13:20:10 +00:00
Ben Gras
1f3dd53283 We don't install the bzip2 manual, much less four copies of it, and
it's quite big.
2009-02-16 10:01:22 +00:00
Ben Gras
01f1132eac let at_wini see ata raid controllers 2009-02-12 12:28:28 +00:00
Ben Gras
59e972f074 let drivers allocate memory at 64k physical boundary. 2009-02-12 12:26:08 +00:00
Ben Gras
6ac0338584 Don't declare the cprof buf if CPROFILE isn't on. 2009-02-06 16:31:28 +00:00
Ben Gras
b696823379 stingy stack. 2009-02-06 16:29:00 +00:00
Ben Gras
95ff97d4fb readclock easily runs out of stack with so little of it. 2009-02-06 16:28:35 +00:00
Ben Gras
eafd4730ea check for devices that would need more blocks than 32
bits allow..
2009-02-05 16:30:20 +00:00
Ben Gras
6e86e6706d fix compiler warning; missing memory range check 2009-02-05 13:00:03 +00:00
Ben Gras
bb18be5d06 simplified the code a little, corrected some hasty statements. 2009-02-04 17:30:01 +00:00
Ben Gras
6a0e8e3b80 Added a separate keymap for escaped scancodes. This makes the code
a little cleaner (escaped scancodes are less of a special case) and
lets us be completely flexible when assigning meaning to them.

Future: a tool and ioctl to load the escaped keymap.
2009-02-04 17:04:16 +00:00
Ben Gras
ba4687e519 the escaped keymap is usually the same as the original. 2009-02-04 16:55:30 +00:00
Ben Gras
113932905f disable interrupts if necessary in kernel debug code to dump all process
stacks.
2009-01-29 15:13:54 +00:00
Ben Gras
80f5eea8b8 If serial debugging in the boot monitor / kernel is enabled, don't touch
the serial line in use for it (mostly so that input isn't eaten by tty).
2009-01-29 15:06:40 +00:00
Ben Gras
d0a2e6b2f4 use library panic, doesn't need its own any more. 2009-01-29 14:41:44 +00:00
Ben Gras
c628f24bc2 moved stacktrace to sysctl, as vmctl is very privileged so can't
be used outside VM. IS code cleanup. added stacktrace feature to IS.
2009-01-27 12:54:33 +00:00
Ben Gras
3cc092ff06 . new kernel call sysctl for generic unprivileged system operations;
now used for printing diagnostic messages through the kernel message
   buffer. this lets processes print diagnostics without sending messages
   to tty and log directly, simplifying the message protocol a lot and
   reducing difficulties with deadlocks and other situations in which
   diagnostics are blackholed (e.g. grants don't work). this makes
   DIAGNOSTICS(_S), ASYN_DIAGNOSTICS and DIAG_REPL obsolete, although tty
   and log still accept the codes for 'old' binaries. This also simplifies
   diagnostics in several servers and drivers - only tty needs its own
   kputc() now.
 . simplifications in vfs, and some effort to get the vnode references
   right (consistent) even during shutdown. m_mounted_on is now NULL
   for root filesystems (!) (the original and new root), a less awkward
   special case than 'm_mounted_on == m_root_node'. root now has exactly
   one reference, to root, if no files are open, just like all other
   filesystems. m_driver_e is unused.
2009-01-26 17:43:59 +00:00
Ben Gras
4984a86f32 don't hang on disappearing filesystem. 2009-01-26 13:02:41 +00:00
Ben Gras
b784e88026 prototype 2009-01-22 17:09:45 +00:00
Ben Gras
539192f4c3 must be unsigned for base+limit check to to work 2009-01-22 13:05:20 +00:00
Ben Gras
36c12c1251 package list sanity check 2009-01-20 15:49:42 +00:00
Ben Gras
0f41416100 minor cleanup, extra check 2009-01-20 15:47:00 +00:00
Ben Gras
723a756c14 reduce kernel buffer size. 2009-01-20 13:57:24 +00:00
Ben Gras
86e7e4828e sanity check function 2009-01-20 13:43:18 +00:00
Ben Gras
45ec30f6af mostly harmless sanity checks. 2009-01-20 13:43:00 +00:00
Ben Gras
6a267baeb8 simplification suggested by Mark Farnsworth 2009-01-15 14:42:40 +00:00
Ben Gras
36909196cf make bootinfo valid immediately 2009-01-14 08:56:20 +00:00
Ben Gras
4f08002c2c RS needs a bit more memory 2009-01-14 08:55:48 +00:00
Ben Gras
ef2867de41 don't print if we're already printing to serial. 2009-01-14 08:54:17 +00:00
Ben Gras
b4934f0e12 debug twiddle. 2009-01-14 08:52:50 +00:00
Ben Gras
b450c33377 sometime this will be a new release. 2009-01-14 08:38:37 +00:00
Ben Gras
5cbcc11ed3 compile fix for new lock timings 2009-01-12 22:14:43 +00:00
Ben Gras
3ca00a926c don't produce kernel output if serial debug is on. 2009-01-11 23:47:03 +00:00
Ben Gras
d5f978411e use #include name for servarname 2009-01-11 23:45:29 +00:00
Ben Gras
037f39767c debug msg 2009-01-09 21:47:04 +00:00
Ben Gras
cd54beeb30 cprofile not conditional 2009-01-09 21:45:27 +00:00
Ben Gras
c27008fbcc cprofile not conditional 2009-01-09 21:44:52 +00:00
Ben Gras
e190ff9f84 cprofile always on 2009-01-09 21:42:36 +00:00
Ben Gras
b82588848d cprofile always on; data type and definitions to include file 2009-01-09 21:40:29 +00:00
Ben Gras
628ed99101 CPROFILE wants this 2009-01-09 21:11:23 +00:00
Ben Gras
22d9444773 don't always time that 2009-01-09 20:58:35 +00:00
Ben Gras
7d48584659 profbuf syscall 2009-01-09 17:47:38 +00:00
Ben Gras
ad87da99d3 bigger ramdisk for bigger binaries 2009-01-09 17:47:18 +00:00
Ben Gras
7606dc5f1f profiling reminder 2009-01-09 16:44:47 +00:00
Ben Gras
ad03a650e6 timing library from kernel into library 2009-01-09 16:39:31 +00:00
Ben Gras
7740d0379c no longer in kernel 2009-01-09 16:35:25 +00:00
Ben Gras
128a0508c0 timing measurement code out of kernel and into library
(so other components can use it too)
2009-01-09 16:15:15 +00:00
Ben Gras
54b3f50b05 actually build and install zoneinfo. 2008-12-21 04:33:50 +00:00
Ben Gras
1943df25dd forget about bad block testing. 2008-12-21 04:26:41 +00:00
Ben Gras
523fdf2729 stopgap measure against elvis going nuts when files that are too large
are opened.
2008-12-21 04:01:01 +00:00
Ben Gras
0579810535 don't ignore the fact that scancodes are escaped.
if not understood explicitly, print diagnostic and 
ignore scancode.
2008-12-21 03:53:25 +00:00
Ben Gras
23a158b361 don't check senda() buffer if size is 0. 2008-12-21 03:46:42 +00:00
Ben Gras
203eb54a4c make space for first code and data pages if so configured. 2008-12-19 15:46:29 +00:00
Ben Gras
d2757d4b73 debug buffer slightly usabler. 2008-12-19 15:19:42 +00:00
Ben Gras
866a4a667e phys addr arg of 0 must be possible for pt_writemap too (instead of meaning
unmap).
2008-12-19 13:29:12 +00:00
Ben Gras
b740ff055f if serial output is enabled in the boot monitor, on the first serial line,
enable serial debug output in the kernel too.
2008-12-19 13:21:42 +00:00
Ben Gras
7fdc181d5f /boot/boot install helper script. 2008-12-19 12:52:45 +00:00
Ben Gras
8072ef5509 oops, shouldn't be on in svn. 2008-12-18 17:42:29 +00:00
Ben Gras
3121eec6bd . map text (kernel's and processes') in readonly
. map kernel in non-user
 . don't map in first pages of kernel code and data
   if possible

these first pages could actually be freed but as the
kernel isn't allowed to touch them either we can't reuse
them until VM has totally taken over page table management
and kernel doesn't rely on identity mapping any more.
2008-12-18 15:35:22 +00:00
Ben Gras
f0000078c3 make kernel leave a page-sized gap in its code and data to not be
mapped in if so configured.
2008-12-18 14:30:55 +00:00
Ben Gras
834d9d34e8 Initialize deferred field. This seems to fix a hanging select() bug. 2008-12-17 14:20:08 +00:00
Ben Gras
2528a06954 bugfix for lance. works in vmware now. 2008-12-17 01:20:15 +00:00
Ben Gras
34d5401ed4 put put_vnode() back where it belongs! 2008-12-16 16:11:24 +00:00
Ben Gras
46ecfa2b5c syslib function for VMCTL_STACKTRACE 2008-12-16 14:42:32 +00:00
Ben Gras
710f44c4b8 added code for debugging pagefaults 2008-12-16 14:33:53 +00:00
Ben Gras
4be5b6f437 2008-12-16 14:32:56 +00:00
Ben Gras
a306c63e0b 2008-12-15 15:16:26 +00:00
Ben Gras
8beff61807 get fproc table. don't print size as that doesn't say much in VM mode.
this restores ps.
2008-12-15 13:05:52 +00:00
Ben Gras
e4e3995fb0 don't force vm to print to serial; don't kill processes when they
have 'bad' memory ranges (as it's the requestor's fault)
2008-12-11 17:36:33 +00:00
Ben Gras
ef812af5a6 use VM functions to allocate ramdisk on demand. some unification in code. 2008-12-11 17:33:13 +00:00
Ben Gras
73e3431dfd DEV_BOOT is obsolete. 2008-12-11 16:50:11 +00:00
Ben Gras
0cd26cd1c0 DEV_BOOT is obsolete. 2008-12-11 16:50:01 +00:00
Ben Gras
6009642110 for compatability with older images. 2008-12-11 15:50:33 +00:00
Ben Gras
5db1a042c2 stacktrace feature. 2008-12-11 15:33:43 +00:00
Ben Gras
6300c26921 prototype fix 2008-12-11 15:02:44 +00:00
Ben Gras
fe3e0181d4 straggler. 2008-12-11 14:55:06 +00:00
Ben Gras
70f1f28439 dynamic HZ, library stacktrace 2008-12-11 14:54:42 +00:00
Ben Gras
b6b361a474 rc script needs to open its own stdin, stdout and stderr 2008-12-11 14:50:56 +00:00
Ben Gras
011de3ac49 everyone needs GETINFO for HZ 2008-12-11 14:50:28 +00:00
Ben Gras
2024bf0bcf . no more HZ
. let user processes query HZ
 . no more custom panic()
2008-12-11 14:49:17 +00:00
Ben Gras
ccf70aa989 system_hz replaces HZ 2008-12-11 14:48:05 +00:00
Ben Gras
7d674f4b8e no more HZ; less debugging statements 2008-12-11 14:47:48 +00:00
Ben Gras
b9a0d46ea9 debug out 2008-12-11 14:46:46 +00:00
Ben Gras
3287b7f7d8 don't hang old binaries 2008-12-11 14:45:49 +00:00
Ben Gras
5e1bb6eb63 added some code to debug why filesystems won't unmount 2008-12-11 14:45:31 +00:00
Ben Gras
e96f86ed8c throw out debugging code. 2008-12-11 14:44:10 +00:00
Ben Gras
eeba8ef01f No more HZ. 2008-12-11 14:43:53 +00:00
Ben Gras
e9f0c576a3 Open stdin, stdout and stderr only after /etc/rc has executed. (/etc/rc
executes it itself.) This avoids keeping /dev nodes on the temporary
root filesystem (initial mfs) in use unnecessarily.
2008-12-11 14:43:25 +00:00
Ben Gras
1d8aed840c . no more HZ, but use sys_hz() to get that value
. memory maps in physical memory (for /dev/mem) with new vm interface
 . pci complete_bars() seems to be buggy behaviour sometimes
 . startup script opens its own stdout, stderr and stdin so init doesn't
   have to do it
2008-12-11 14:42:23 +00:00
Ben Gras
6cfe4bdd2d slight args change 2008-12-11 14:37:42 +00:00
Ben Gras
991000dd70 dynamic HZ 2008-12-11 14:37:18 +00:00
Ben Gras
eae27c899a move senda to sep. file 2008-12-11 14:37:02 +00:00
Ben Gras
3e29947e28 No more HZ; move stacktrace() to library 2008-12-11 14:36:37 +00:00
Ben Gras
825dfb0282 introduce Hz variable that is what used to be the HZ constant.
default 60Hz of course.
2008-12-11 14:33:33 +00:00
Ben Gras
4c1ac39678 Changes so the HZ constant isn't needed any more. 2008-12-11 14:27:18 +00:00
Ben Gras
37a9ce7275 I want to see /dev/imgrd so I can unmount it when it's free. 2008-12-11 14:26:50 +00:00
Ben Gras
5aea2817bc syslogd needs a bit more stack. 2008-12-11 14:26:27 +00:00
Ben Gras
9d096e014b . print kernel stacktrace unconditionally on panic
. provide a panic() in the kernel for if a library function wants to panic
2008-12-11 14:23:58 +00:00
Ben Gras
b61687fb1b . VM needs a higher priority than VFS, PM etc
. introduce FULLVM flag: MEMORY and the initial MFS
   get their own full address spaces, making their stacks
   and heaps not preallocated (well, freed after VM has
   initialized it) and letting them allocate more dynamically.
   MEMORY in particular needs this to map in physical memory
   using its own page table, without having to allocate.
2008-12-11 14:21:47 +00:00
Ben Gras
034b5c6042 PM_PROC_NR shouldn't be hardcoded as the caller. 2008-12-11 14:18:51 +00:00
Ben Gras
66b161238d function to increase process stack (pointer). used by VM to set up large,
sparse, non-preallocated heap and stack.
2008-12-11 14:17:45 +00:00
Ben Gras
e911d44a5c system image processes with full address space are allowed to have pagefaults. 2008-12-11 14:16:40 +00:00
Ben Gras
c4fb567bd5 . replace HZ by runtime system_hz (sysenv variable 'hz')
. new flag PROC_FULLVM in table indicating process wants full address
   space (this is then created and managed by VM)
2008-12-11 14:15:23 +00:00
Ben Gras
afef5e0711 . some flags to <minix/const.h>
. add system_hz for runtime HZ value
2008-12-11 14:12:52 +00:00
Ben Gras
dd9e9c74cd vm map request - ioctl to /dev/video 2008-12-11 14:11:59 +00:00
Ben Gras
3f30c3a0ee add va_copy() 2008-12-11 14:10:56 +00:00
Ben Gras
9bbee4f1ce 2008-12-11 14:10:37 +00:00
Ben Gras
e75e231abc VMCTL_INCSP to increase process stack pointer.
(Used to change the virtual address of the stack before a process has
started executing.)
2008-12-11 14:10:17 +00:00
Ben Gras
682b9a872e . ser_putc() goes to library
. another cmd for getinfo - obtaining current HZ value
2008-12-11 14:09:38 +00:00
Ben Gras
ef5b6f8cdf . HZ no longer constant, but settable at boot time; default is DEFAULT_HZ (60)
. some kernel flags to <minix/const.h>
2008-12-11 14:08:53 +00:00
Ben Gras
a74132ec69 fix race condition that can trigger 'enqueue already ready process' panic. 2008-12-11 13:42:37 +00:00
Ben Gras
567f2f0ba0 umap fix 2008-12-08 17:06:38 +00:00
Ben Gras
68d0c4defe - code shared with exec() letting boot-time processes have
their own fully fledged virtual address space and freeing
   their pre-allocated heap+stack area (necessary to let memory
   driver map in arbitrary areas of memory for /dev/mem without
   sys_vm_map)
 - small optimization preallocating memory on exec
 - finished VR_DIRECT physical mapping code
2008-12-08 16:43:20 +00:00
Ben Gras
f4d0d635fd - hz dynamic
- new map /dev/video implementation
 - ser_putc into library
2008-12-08 16:40:29 +00:00
Ben Gras
fe56202038 floppy must be able to allocate a bit more for nonpaged mode. 2008-11-19 17:31:42 +00:00
Ben Gras
9b33056d2b make allocmem accept and return values in bytes, ramdisk expects this. 2008-11-19 15:40:17 +00:00
Ben Gras
51fdce1d36 minor fixes 2008-11-19 14:10:33 +00:00
Ben Gras
6c92081a5a paged mode is default. 2008-11-19 13:19:37 +00:00
Ben Gras
16e14559e6 include libraries. 2008-11-19 13:15:35 +00:00
Ben Gras
7b3d952a77 lingering file 2008-11-19 12:38:31 +00:00
Ben Gras
b686e8b6d7 lingering file. 2008-11-19 12:35:46 +00:00
Ben Gras
c078ec0331 Basic VM and other minor improvements.
Not complete, probably not fully debugged or optimized.
2008-11-19 12:26:10 +00:00
Philip Homburg
c888305e21 Reverted accidental change to stat.c. 2008-10-02 14:11:12 +00:00
Philip Homburg
005bc7a649 Some changes that were missing from the previous commit 2008-10-02 13:48:05 +00:00
Philip Homburg
5b5b54c76c Minix 3 version 2008-10-02 13:45:46 +00:00
Philip Homburg
659ab96c1f Unmodified source of the software fault injection utility 2008-10-02 13:43:32 +00:00
Ben Gras
58f428a704 throw out two time consuming tests 2008-10-01 15:09:33 +00:00
David van Moolenbroek
e8b863702a Added lance entry to drivers.conf. 2008-07-22 15:11:01 +00:00
David van Moolenbroek
f73b541952 Backport of fix from asynchvfs branch for PM-LOG-VFS-PM deadlock that resulted in VFS panics. 2008-06-24 13:53:03 +00:00
Ben Gras
39aa2e6489 A glob() implementation. 2008-04-08 13:14:33 +00:00
Ben Gras
d939a9c54b Use $PAGER if set. Suggested by gigabo at gmail.com. 2008-04-08 12:34:35 +00:00
Philip Homburg
4696d74480 Select support for eth by Erik van der Kouwe. 2008-03-12 14:10:21 +00:00
Philip Homburg
60c1131b94 SYS_MAPDMAx -> SYS_MAPDMA, added IOMMU_MAP 2008-02-25 14:39:19 +00:00
Philip Homburg
9d41dbc55e Build libdriver_asyn for target image 2008-02-25 14:38:09 +00:00
Philip Homburg
9d62f56ea1 SYS_MAPDMAx -> SYS_MAPDMA. 2008-02-25 14:36:28 +00:00
Philip Homburg
f82a1c4df7 Fixed include files. 2008-02-25 14:35:54 +00:00
Philip Homburg
a508e0a03c _function, function -> call_nr 2008-02-25 14:35:11 +00:00
Philip Homburg
822fcd368d Added O_REOPEN, better error handling. 2008-02-25 12:13:30 +00:00
Philip Homburg
41efa40ad2 Added XDOPEN. 2008-02-25 12:12:07 +00:00
Philip Homburg
9d176133ee Added libdriver_asyn and amddev 2008-02-25 12:07:48 +00:00
Philip Homburg
4474166403 Driver for AMD's DEV. 2008-02-25 12:07:19 +00:00
Philip Homburg
a51dbad054 Asynchrnous character device interface. 2008-02-25 11:54:04 +00:00
Philip Homburg
65df875abb Need separate 'prev_next' pointers for kernel and TTY. 2008-02-25 11:53:37 +00:00
Philip Homburg
830b79f0d5 Link random number genertor with libdriver_asyn 2008-02-25 10:25:43 +00:00
Philip Homburg
bc125e3e1c Copy of libdriver for asynch interface to character drivers. Has to be cleaned
up.
2008-02-25 10:24:46 +00:00
Philip Homburg
404325b193 Support for I/O MMU. 2008-02-25 10:19:29 +00:00
Philip Homburg
668515afe2 More heap for fxp, support for I/O MMU. 2008-02-25 10:12:09 +00:00
Philip Homburg
54f714e59e Respond to RS ping request, asynch interface, register with I/O MMU. 2008-02-25 10:02:24 +00:00
Philip Homburg
00ef93d6a2 Use nonblocking sends to reply, fixed reply message for DIAGNOSTICS(_S) 2008-02-22 16:03:00 +00:00
Philip Homburg
e3d4c74393 Functions that check arguments and return a status code and functions that
don't.
2008-02-22 15:59:12 +00:00
Philip Homburg
fecd153c2c Declare and call functions that check arguments and return a status code. 2008-02-22 15:56:12 +00:00
Philip Homburg
8a07b7687a Use nonblocking send to reply. 2008-02-22 15:52:13 +00:00
Philip Homburg
bc7e3c02a3 Asynchronous select implementation. 2008-02-22 15:46:59 +00:00
Philip Homburg
ff7eae2ad8 Private copy of kputc to support asynch communication with log device. 2008-02-22 15:43:33 +00:00
Philip Homburg
2ec762c60c Asynchronous communication with character specials. 2008-02-22 15:41:07 +00:00
Philip Homburg
d9a9b727e2 Added dmap_async_driver and dmap_sel_filp fields. Support for asynch character
drivers (needs cleaning up).
2008-02-22 15:01:00 +00:00
Philip Homburg
9df94c5ee8 Use dev_t instead of Dev_t in structures. 2008-02-22 14:54:00 +00:00
Philip Homburg
097d8fee66 Use nonblocking send for reply. Support for asynchronous message passing
(needs cleaning up).
2008-02-22 14:53:02 +00:00
Philip Homburg
66c930ef8b Higher NCALLS requires bigger table. New calls are in PM. 2008-02-22 14:51:38 +00:00
Philip Homburg
93ff4c327f Added XDOPEN. 2008-02-22 14:50:41 +00:00
Philip Homburg
9388a27070 Support for O_REOPEN flag and pass the filp numbet to dev_open. 2008-02-22 14:49:02 +00:00
Philip Homburg
7387449b23 Support for suspending on character device open and on drivers that need to
be restarted.
2008-02-22 14:47:40 +00:00
Philip Homburg
ca91b3b5be New fp_flags. Currently used to signal that is process should be suspended
a driver is restarted.
2008-02-22 14:32:23 +00:00
Philip Homburg
6ef71b8198 Pass suspend_reopen flag to dev_io. 2008-02-22 14:26:41 +00:00
Philip Homburg
047cc090e4 Added filp_state for driver recovery and filp_select_flags to store select
state for character specials that use asynch I/O.
2008-02-22 14:19:23 +00:00
Philip Homburg
1d7d5aa629 dev_close needs the filp number for asynch I/O, dev_io gets suspend_reopen
flag to suspend a process until the filedescriptor is re-opened. Added 
dev_reopen, asyn_io, suspended_ep, reopen_reply, asynsend, diag_repl, 
close_filp, close_reply, unpause, select_reply1, select_reply2.
2008-02-22 14:03:14 +00:00
Philip Homburg
e5df351245 Support for blocking open on char specials (due to asynch message passing),
asynch. close, added close_filp function.
2008-02-22 13:57:11 +00:00
Philip Homburg
73ea967b6c Keep track of error statistics, rate limit debug output, added SYS_MAPDMA. 2008-02-22 12:38:22 +00:00
Philip Homburg
992edfd558 Keep track of various statistics related to IPC and SYSTEM. 2008-02-22 12:36:46 +00:00
Philip Homburg
5996d1de58 Added do_mapdma. 2008-02-22 12:25:59 +00:00
Philip Homburg
f6872f8323 Added ipc_stats_target. 2008-02-22 12:25:44 +00:00
Philip Homburg
4a86b1fea5 Changes to debug output, mostly rate limiting. 2008-02-22 11:00:06 +00:00
Philip Homburg
3c2e122d6d Disabled code to set ipc_stats_target. 2008-02-22 10:58:27 +00:00
Philip Homburg
2679321ba0 Added do_mapdma. 2008-02-22 10:51:37 +00:00
Philip Homburg
594035f13c More verbose (optional) debug output for exceptions. 2008-02-22 10:43:18 +00:00
Philip Homburg
f5389ecf19 Code to dump IPC statistics over a serial line. (Disabled) code to disable the
FPU.
2008-02-22 10:40:38 +00:00
Philip Homburg
1cffa69d2c Support for I/O MMU: do not re-use a memory segment until the I/O MMU has
removed it from its map.
2008-02-21 16:33:34 +00:00
Philip Homburg
75520b7403 ipc restrictions for some drivers and I/O MMU (amddev) 2008-02-21 16:24:35 +00:00
Philip Homburg
3f23bca404 Removed defines not needed by mfs (XPIPE, XLOCK, XPOPEN, XSELECT, DUP_MASK). 2008-02-21 16:22:36 +00:00
Philip Homburg
ca8291c815 Support for restricting limiting IPC to a set of endpoints. Not enabled by
default, pass -i to service. Do not reply to bogus request types. Reply using
sendnb.
2008-02-21 16:20:22 +00:00
Philip Homburg
19db2b646e Removed superfluous argument. 2008-02-21 16:09:58 +00:00
Philip Homburg
d9858cfabf Removed some debug output. 2008-02-21 16:08:08 +00:00
Philip Homburg
4951a741b0 adddma/deldma/getdma/sys_mapdma 2008-02-21 16:02:22 +00:00
Philip Homburg
959ed5a191 Added ERESTART 2008-02-21 16:00:39 +00:00
Philip Homburg
07c258a9c7 Added adddma/deldma/getdma. 2008-02-21 15:58:55 +00:00
Philip Homburg
e674f1a54f Added ERESTART. 2008-02-21 15:58:26 +00:00
Philip Homburg
3b3fc8a9c4 Added O_REOPEN. 2008-02-21 15:58:06 +00:00
Philip Homburg
82cb46af0a Changes for asynchronous interface to character specials.
Removed DEV_SEL_WATCH. Added SYS_MAPDMAx. New message type (DIAG_REPL) for
replies to DIAGNOSTICS(_S).
2008-02-21 15:57:35 +00:00
Philip Homburg
698df384c3 Extra calls to PM for I/O MMUs. 2008-02-21 15:51:27 +00:00
Philip Homburg
cb2b7ada63 Nonblocking send. 2008-02-21 15:50:09 +00:00
Philip Homburg
fc4593fb42 List of service/driver names that are allowed as IPC endpoints for a new
driver/service.
2008-02-21 15:49:44 +00:00
Philip Homburg
124a128736 Defines for AMD I/O MMU 2008-02-21 15:47:11 +00:00
Ben Gras
2c45324c47 keymap contributed by Roman Ignatov. 2008-02-06 15:16:50 +00:00
Ben Gras
2876d5c4ba Optimization in searching for new zones to allocate contributed
by Jens de Smit.
2008-02-06 15:05:57 +00:00
Ben Gras
cd89066f9a Trust $PATH. 2007-12-19 10:51:21 +00:00
Ben Gras
b250847120 Makefile for audio drivers. 2007-12-19 10:37:29 +00:00
Ben Gras
8e727c97ce always re-enable irq, so devices sharing this irq don't go deaf
as IRQ_REENABLE isn't specified.
2007-12-14 12:44:20 +00:00
Ben Gras
50fa859819 A rint() implementation. 2007-12-14 11:59:54 +00:00
Ben Gras
bd489b6c0b Original imported versions of s_rint.c and math_private.h. 2007-12-11 12:32:26 +00:00
Ben Gras
3f2230eee5 add M_SQRT1_2 (1/sqrt(2)) 2007-12-11 10:59:02 +00:00
Ben Gras
e39af6d1ff yearly fsck increase. 2007-12-11 10:51:35 +00:00
Ben Gras
45744bff41 Connect new audio drivers to build. 2007-11-23 11:53:33 +00:00
Ben Gras
b79b305ba1 More es1371 bij Pieter Hijma. 2007-11-23 11:52:34 +00:00
Ben Gras
c67a56708e es1370 driver and updated es1371 and framework by Pieter Hijma. 2007-11-23 11:40:33 +00:00
Ben Gras
0d2d8c6db2 audio drivers. (not updated for trunk.)
sb16: port of isa sb16 driver to user-space. Port by Peter Boonstoppel.
es1371: By Laurens Bronwasser.
2007-11-23 11:30:50 +00:00
Ben Gras
1327804478 MFS doesn't need sys_exit(). 2007-10-23 14:24:41 +00:00
Ben Gras
67d1b67805 exit prototype 2007-10-23 14:19:16 +00:00
Ben Gras
e8aec69c7b tweak to panic functions of mfs and vfs.
. print newline
  . when recursive panic detected, don't simply return, confusing
    the caller, but print a diagnostic and exit
  . don't call sys_exit as this may confuse PM; it should be OK
    to call PM exit() nowadays.
2007-10-23 14:17:51 +00:00
Ben Gras
515e8216e1 Basic entry for dpeth suggested by Jens de Smit. 2007-10-17 11:02:33 +00:00
Ben Gras
0ae1ff99b8 Fix for DL_STAT_REPLY/DL_TASK_REPLY
Bug found and fixed by Jens de Smit <jfdsmit at few.vu.nl>.
2007-10-17 10:53:47 +00:00
Ben Gras
23f6e478df Fixed a glitch introduced in safe i/o conversion. 2007-10-17 10:50:18 +00:00
Ben Gras
21ae963cf1 Fixes two wrong grant return checks and one 'grant leak'. 2007-10-17 10:46:20 +00:00
Ben Gras
af591d2151 Internally, floppy driver still used vircopies ('unsafe' copies), but
this isn't allowed in its drivers.conf entry. Changed these to memcpy()
calls.  Bug reported by Maurizio Lombardi in comp.os.minix.
2007-10-16 14:31:35 +00:00
Ben Gras
b6e07e1835 close device if mount fails after device opened. 2007-09-26 15:06:41 +00:00
Philip Homburg
b74b3315a3 Added PF_UNIX and PF_INET to make porting easier. 2007-09-17 11:35:44 +00:00
Philip Homburg
af678531aa Disabled some debug output in recvfrom. 2007-09-17 11:22:06 +00:00
Ben Gras
38604e4e3a Don't truncate read requests based on v_size; v_size can be stale in the
case of directories extended by subfilesystem. Rely on subfilesystem to
do read size truncating and return actual i/o size. This fixes bug 81 in
gforge, and unbreaks test 23.
2007-09-11 15:52:22 +00:00
Ben Gras
007bb33c7d Make test 17 use dir 17 2007-09-11 14:56:48 +00:00
Ben Gras
ff9f4dd59c fix for i/o data/addr pair set macro's. 2007-09-11 11:22:29 +00:00
Philip Homburg
ab3062c8c0 REQ_FSTATFS now operates on the root inode (the inode parameter has been
removed)
2007-08-17 11:20:59 +00:00
Philip Homburg
9c3f85d14f Better interface for sys_times. 2007-08-16 13:16:26 +00:00
Philip Homburg
341270673b mfs no longer needs access to VIRCOPY, Added rs.inet. Start inet with
rs.inet as the restart script.
2007-08-15 12:56:35 +00:00
Philip Homburg
4b1cd8c0ec Return EIO if a filedescriptor cannot be re-opened after a driver restart.
Select now returns such a filedescriptor as ready (instead of EBADF). 
Reply before dev_up in FSSIGNON to avoid the problem that a DEV_OPEN
request is received by a driver that expects a reply from the FSSIGNON.
2007-08-15 12:53:52 +00:00
Philip Homburg
c26de9f435 Close UDP socket after error. 2007-08-15 12:50:24 +00:00
Philip Homburg
90fde6e97d cleanup 2007-08-10 13:02:39 +00:00
Philip Homburg
06e1f0da61 Better recovery when req_readsuper fails. 2007-08-10 13:01:38 +00:00
Philip Homburg
57c6f099f2 Removed old debug code. 2007-08-08 15:27:07 +00:00
Philip Homburg
e2f06e7c89 Directory check before access check. 2007-08-08 15:26:47 +00:00
Philip Homburg
a116b3aa55 To return the right error, check first is an object is a directory (for
mkdir, rmdir/unlink, mknod), simply pipe code by using v_pipe_rd_pos and
v_pipe_wr_pos directly. Some cleanup work in open.c
2007-08-08 14:01:36 +00:00
Philip Homburg
c2bf536a55 Disable POSIX-required behavior wrt trailing slashes. 2007-08-08 11:40:47 +00:00
Philip Homburg
d232b2ef42 Removed invalid consistency check. 2007-08-07 14:27:19 +00:00
Philip Homburg
9c51f0b92a O_EXCL check went missing. 2007-08-07 14:26:56 +00:00
Philip Homburg
d01d630727 include "../vfs/dmap.h". 2007-08-07 13:26:25 +00:00
Philip Homburg
1b883a3613 Removed references to stacktrace. 2007-08-07 13:21:55 +00:00
Philip Homburg
a318cd291f Somehow request.c got garbled. 2007-08-07 13:12:27 +00:00
Philip Homburg
f46319037b New VFS interface 2007-08-07 12:52:47 +00:00
Philip Homburg
2ca2b86a3a Added new interface to VFS. 2007-08-07 12:38:35 +00:00
Philip Homburg
a81e82b3da Tell the kernel about the new boottime and don't tell VFS.
Tell DS about all processes in the boot image. PM_STIME is removed.
Diagnostic for calls to do_getprocnr (DS should be used to get endpoints).
2007-08-07 12:28:42 +00:00
Philip Homburg
fd151245e9 Removed sigaction call. PM tries to talk to DS. DS should not talk to PM. 2007-08-07 12:25:21 +00:00
Philip Homburg
1f04287b3f Removed dmap table. Publish endpoint in DS before calling mapdriver5. 2007-08-07 12:24:06 +00:00
Philip Homburg
6ef2e9b866 Added global variable boottime, prototype for do_stime, and table entry for
SYS_STIME.
2007-08-07 12:21:40 +00:00
Philip Homburg
fab77fd01f Added do_stime.c, return boot time in do_times.c 2007-08-07 12:20:31 +00:00
Philip Homburg
4f787035ea Removed check for grants that wrap. 2007-08-07 12:19:45 +00:00
Philip Homburg
2519a7cb61 Added getuptime2.c 2007-08-07 12:14:04 +00:00
Philip Homburg
5aa84fb0e6 Added mapdriver5.s. 2007-08-07 12:05:36 +00:00
Philip Homburg
21e7edb683 Added sys_stime.c, T_CHILD_UTIME and T_CHILD_STIME are gone, should
change interface of sys_times.
2007-08-07 12:04:29 +00:00
Philip Homburg
1f02168ce7 Added _mapdriver5.c. 2007-08-07 12:02:38 +00:00
Philip Homburg
4d2f56daf6 Added prototype for mapdriver5 (from RS to VFS, report the name of a driver
instead of its endpoint).
2007-08-07 11:59:02 +00:00
Philip Homburg
6b0db0d181 Many changes to the VFS/FS interface. 2007-08-07 11:58:03 +00:00
Philip Homburg
d9166df3f7 Added FS_READY (from vfsif.h), and MAPDRIVER (from RS to VFS) 2007-08-07 11:57:33 +00:00
Philip Homburg
23fd914307 New message type 9: 5 longs, 3 shorts, and 2 chars. 2007-08-07 11:56:28 +00:00
Philip Homburg
498728bdbe New call SYS_STIME, restructured fields for SYS_TIMES, removed PM_STIME,
added VFS_BASE.
2007-08-07 11:55:28 +00:00
Philip Homburg
fc0d7995e9 Some parts of dmap can be private (to vfs) 2007-08-07 11:53:41 +00:00
Philip Homburg
bf6620d285 Added prototypes for sys_stime and getuptime2 (tell the kernel about the
boot time and return the boot time together with the uptime)
2007-08-07 11:52:15 +00:00
Philip Homburg
2a58d1dc58 Constants for symlink loops 2007-08-07 11:43:49 +00:00
Philip Homburg
1d4afb3599 Compile-time option to duplicate console output to the first serial line 2007-08-07 11:27:03 +00:00
Philip Homburg
acfaea0fa2 More space on ramdisk 2007-08-07 11:22:35 +00:00
Philip Homburg
f352a3fb15 Print the value of a capability as well. 2007-08-07 11:21:57 +00:00
Ben Gras
a80365f407 . add checks to printer driver kernel calls
. correct some i/o locations for printer in drivers.conf
2007-08-06 11:17:08 +00:00
Ben Gras
03446f5554 micro_delay in sysutil, used in ti1225, dp8390, fxp and
orinoco now. Uses a combination of tickdelay (where possible) and
calibrated busywait (where necessary).
2007-07-31 15:01:49 +00:00
Ben Gras
2dc2db4ba1 'fix' crlf style 2007-07-24 14:49:39 +00:00
Ben Gras
816f5dd550 a driver for wireless pci cards with the Prism chipset from Intersil
Original version, by Stevens Le Blond and Michael Valkering.
2007-07-24 14:49:09 +00:00
Ben Gras
e2932a1180 . remove small image (doesn't fit)
. edparams line a bit more readable
 . use image built in build tree, not regular source tree
2007-07-17 14:36:42 +00:00
Ben Gras
cd4756933a Typo reported by Johnathan Gurley. 2007-07-17 11:40:02 +00:00
Ben Gras
30ba1ec187 also allow vm_map. 2007-07-11 13:45:06 +00:00
Ben Gras
eb4609c108 Don't exit when rebooting. 2007-07-11 13:44:45 +00:00
Ben Gras
d524b0b351 Don't quit (some processes want to talk to pci at reboot time) 2007-07-11 13:44:00 +00:00
Ben Gras
ee3e40516b . clarify panic messages in syslib about pci
. use ds_retrieve_u32 instead of _pm_findproc
2007-07-11 13:38:13 +00:00
Ben Gras
c829928cf1 Give arp and install the default amount of memory - otherwise they run
out of memory in extreme cases.
2007-07-11 13:36:31 +00:00
Ben Gras
2746a5a2a9 Reported by Erik van der Kouwe <vdkouwe at cs.vu.nl>:
-  fprintf(stderr, "%s: reboot(): %s\n", strerror(errno));
+  fprintf(stderr, "%s: reboot(): %s\n", prog, strerror(errno));
  
Other minor fixes inspired by other warnings produced by gcc.
2007-07-02 11:16:27 +00:00
Ben Gras
ad93329236 Assume bios parameters are wrong/missing if any of the parameters are 0. 2007-05-30 16:13:52 +00:00
Ben Gras
ed920a691d include 'printer' driver 2007-05-30 15:40:12 +00:00
Ben Gras
b918f61820 Boot monitor flag that enables 'sticky right-alt', permanent change
to col selected from the keymap untill right-alt is pressed again.

Sticky alt code and russian keymap contributed by Roman Ignatov
and Yaroslav Schekin.
2007-05-16 13:14:37 +00:00
Ben Gras
b6cd5d0351 Include fonts blobs in src repository. 2007-05-16 13:00:43 +00:00
Ben Gras
b00f287449 Restore user-owned bits from PSW after a signal handler, instead of
copying complete PSW after signal handler.

This fixes a psw corruption bug reported by Jens de Smit <jst260@few.vu.nl>.
2007-05-08 15:43:00 +00:00
Philip Homburg
56a68dc32b Hack in service to use RS_START instead of RS_UP. RS reports the use of RS_UP. 2007-05-02 15:20:28 +00:00
Philip Homburg
2db15eaa80 Added fxp. rtl8139 doesn't need to be root anymore. 2007-05-02 11:40:15 +00:00
Philip Homburg
2d49b4ecb5 Use ds_retrieve_u32 to get the endpoint of inet. 2007-05-02 11:39:10 +00:00
Philip Homburg
a124958e59 Use ds_retrieve_u32 to get the endpoint of inet. 2007-05-02 11:32:22 +00:00
Philip Homburg
33d31720a5 Use ds_retrieve_u32 to get the endpoint of inet and of the ethernet drivers. 2007-05-02 11:30:16 +00:00
Philip Homburg
9852471c08 Use ds_retrieve_u32 to find the endpoint of pci. 2007-05-02 11:24:51 +00:00
Ben Gras
47c18edb26 date not built from here 2007-05-01 14:18:55 +00:00
Ben Gras
b49ba611bd shell at least as big in 'big' as in normal 2007-05-01 14:11:10 +00:00
Philip Homburg
02a229f14d Publish endpoints in ds. 2007-04-27 13:03:33 +00:00
Philip Homburg
93f9bb4a57 Restrict access to rs to root's processes. 2007-04-27 12:27:40 +00:00
Philip Homburg
69ca935251 getpeuid implementation. Get the uid of a process (by endpoint) 2007-04-27 12:21:06 +00:00
Ben Gras
8eb09f6ddc . readall: use lseek64() to read more than 4GB of a device
. vfs: 64-bit offset support for character device i/o
   (also remove unused dev_bio function)
 . memory: /dev/null and /dev/zero are infinitely large, don't stop
   reading/writing at 4GB
2007-04-24 13:27:33 +00:00
Ben Gras
cc7c561d41 obsolete manpages (these have become packages) 2007-04-24 13:25:57 +00:00
Philip Homburg
0dc0d3fe5b Fixed releasing PCI resources after a driver terminates. 2007-04-24 12:55:37 +00:00
Ben Gras
ac64c1b3dc Take out obsolete message about 4GB. 2007-04-24 12:40:25 +00:00
Ben Gras
72e6862e4e dp8390 doesn't cope with the different semantics of the pci
functions.

Bug and workaround reported by "E.Agafonov" <e.a.agafonov@gmail.com>.
2007-04-24 12:29:51 +00:00
Philip Homburg
cab8f526de Fixed some lose ends in the serial line debug dump code. 2007-04-23 15:59:16 +00:00
Philip Homburg
29f7031340 Remove KILL and VIRCOPY from drivers that don't need them. Added rtl8139. 2007-04-23 15:39:46 +00:00
Philip Homburg
50f81c4939 Ethernet driver changes for asynchronous inet. 2007-04-23 15:38:00 +00:00
Philip Homburg
bb659b1ad6 Disabled ser_putc for reporting debug internal to tty over the serial line.
Disabled return statement for serial debug input in the kernel.
2007-04-23 14:59:32 +00:00
Philip Homburg
a3c8619923 Added do_del_acl. More detailed debug output for the secure device capability. 2007-04-23 14:54:51 +00:00
Philip Homburg
0bd4c5ee7d Initial convertion to asynchronous sends for communicating with ethernet
drivers.
2007-04-23 14:49:20 +00:00
Philip Homburg
b613f5cb4b Report and detect exec failures using a pipe.
XXX Hardcoded values for s_ipc_to and s_ipc_sendrec.
2007-04-23 14:47:04 +00:00
Philip Homburg
727ce18aa8 Initialize exec_pipe. 2007-04-23 14:43:25 +00:00
Philip Homburg
849285f66d Diagnostics from service go to standard error. 2007-04-23 14:42:58 +00:00
Philip Homburg
e68a2b4d6a Extra flags RS_SIGNALED and RS_EXECFAILED. Pipe for detecting exec failures. 2007-04-23 14:42:08 +00:00
Philip Homburg
b4a88a3705 Removed ECHO from dump, added SENDA. Also dump s_ipc_sendrec. 2007-04-23 14:40:13 +00:00
Philip Homburg
77f5b40141 Round memory size up for VM. 2007-04-23 14:38:55 +00:00
Philip Homburg
b5e6319ae7 Removed some indentation. 2007-04-23 14:33:42 +00:00
Philip Homburg
13da935060 Debug dumps over the serial line. Direct output to video memory. 2007-04-23 14:25:17 +00:00
Philip Homburg
c59b23859e Clean and support for asynchronous sends. 2007-04-23 14:24:30 +00:00
Philip Homburg
47233bdf30 Fixed bad boundary condition, support for asynchronous I/O. 2007-04-23 14:23:37 +00:00
Philip Homburg
c7a7c0cb17 Removed some white space. 2007-04-23 13:58:37 +00:00
Philip Homburg
94bc849574 Poll serial line for debug output requests when do_serial_debug is true. 2007-04-23 13:56:27 +00:00
Philip Homburg
8937b6a8de Initialize s_ipc_sendrec. 2007-04-23 13:46:54 +00:00
Philip Homburg
da4bb9144d Removed ECHO. 2007-04-23 13:46:26 +00:00
Philip Homburg
f41429d815 Cleanup. 2007-04-23 13:44:56 +00:00
Philip Homburg
cb3e271b24 Fields for asynchronous sends (s_asyntab and s_asynsize) and for allowed
sendrecs (s_ipc_sendrec).
2007-04-23 13:37:30 +00:00
Philip Homburg
6554f3d3dc Added MF_ASYNMSG. 2007-04-23 13:36:38 +00:00
Ben Gras
1d7cea10ed str[] is too small - reported by Erik van der Kouwe <vdkouwe@cs.vu.nl>. 2007-04-23 13:36:13 +00:00
Philip Homburg
8eb27a714e More debug output. Dump kernel process on serial line. Directly put
text in video memory.
2007-04-23 13:36:11 +00:00
Philip Homburg
c082f607df Disallow unaligned access to I/O ports. 2007-04-23 13:31:45 +00:00
Philip Homburg
d2cec7db49 Disallow unaligned access to I/O ports. 2007-04-23 13:31:16 +00:00
Philip Homburg
7541e0753b Separate permissions for sendrec. Actually initialize send/sendrec permissions
for data supplied by rs.
2007-04-23 13:30:04 +00:00
Philip Homburg
d80e25068c GET_PRIVID: return the ID of a process' privilege structure. 2007-04-23 13:28:14 +00:00
Philip Homburg
2b2d3d5131 Fail unsafe sdevio. Disallow unaligned I/O ports. 2007-04-23 13:22:26 +00:00
Philip Homburg
bc17115a34 Prototypes for exception and stacktrace. Declare additional arguments
for exception to be able to print nexted exceptions.
2007-04-23 13:19:25 +00:00
Philip Homburg
b4f6994278 Use sprintf to avoid buffer overflows. 2007-04-23 13:04:31 +00:00
Philip Homburg
82e77742b5 Added pci_del_acl. Fixed return value of pci_set_acl. 2007-04-23 12:14:44 +00:00
Philip Homburg
4ce2267dd3 Type _exit and abort before generating a trap. 2007-04-23 12:13:51 +00:00
Philip Homburg
4ce9ca03cf Added cpf_reload to reload the safecopy table pointer (for example after a
fork).
2007-04-23 12:12:32 +00:00
Philip Homburg
e9899f3c86 Added sendnb and senda, removed echo and _ipcnew.s. 2007-04-23 12:11:03 +00:00
Philip Homburg
35c3f52d99 Renamed BUSC_PCI_ACL to BUSC_PCI_SET_ACL, added BUSC_PCI_DEL_ACL.
Added DL_STAT_REPLY and GET_PRIVID.
2007-04-23 12:01:47 +00:00
Philip Homburg
555bc29a0c sys_getprivid macro to get the ID of a process' privilege structure.
Prototype for pci_del_acl.
2007-04-23 12:00:46 +00:00
Philip Homburg
36c764be1c Asynchronous send. 2007-04-23 11:59:19 +00:00
Philip Homburg
a17ff08fb9 Prototype for cpf_reload. 2007-04-23 11:58:41 +00:00
Ben Gras
ac41dcd35f bc and mtools out of the base system (gpl) 2007-04-20 12:06:14 +00:00
Ben Gras
0a0f800805 Make mkfs message a bit clearer. 2007-04-19 14:13:27 +00:00
Ben Gras
3b614085c6 Don't limit partitions to 4GB. 2007-04-19 14:08:41 +00:00
Ben Gras
365e867a88 Some features for the automatic image build. 2007-04-18 11:42:48 +00:00
Ben Gras
673c7ced15 Print svn rev and date info in /etc/version. 2007-04-18 11:39:18 +00:00
Ben Gras
8aa0d26891 update binary_sizes to not make binaries smaller than the build does. 2007-04-17 13:50:58 +00:00
1037 changed files with 87276 additions and 122086 deletions

View File

@@ -18,6 +18,7 @@ char version[]= "2.20";
#include <string.h>
#include <errno.h>
#include <ibm/partition.h>
#include <ibm/bios.h>
#include <minix/config.h>
#include <minix/type.h>
#include <minix/com.h>
@@ -28,6 +29,7 @@ char version[]= "2.20";
#if BIOS
#include <kernel/const.h>
#include <kernel/type.h>
#include <sys/video.h>
#endif
#if UNIX
#include <stdio.h>
@@ -46,6 +48,12 @@ char version[]= "2.20";
#define arraylimit(a) ((a) + arraysize(a))
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
int serial_line = -1;
u16_t vid_port; /* Video i/o port. */
u32_t vid_mem_base; /* Video memory base address. */
u32_t vid_mem_size; /* Video memory size. */
int fsok= -1; /* File system state. Initially unknown. */
static int block_size;
@@ -590,6 +598,19 @@ void initialize(void)
bootdev.name[5] += bootdev.secondary;
}
/* Find out about the video hardware. */
raw_copy(mon2abs(&vid_port), VDU_CRT_BASE_ADDR, sizeof(vid_port));
if(vid_port == C_6845) {
vid_mem_base = COLOR_BASE;
vid_mem_size = COLOR_SIZE;
} else {
vid_mem_base = MONO_BASE;
vid_mem_size = MONO_SIZE;
}
if(get_video() >= 3)
vid_mem_size = EGA_SIZE;
#else /* DOS */
/* Take the monitor out of the memory map if we have memory to spare,
* note that only half our PSP is needed at the new place, the first
@@ -859,6 +880,9 @@ void get_parameters(void)
b_setvar(E_SPECIAL|E_VAR|E_DEV, "rootdev", "ram");
b_setvar(E_SPECIAL|E_VAR|E_DEV, "ramimagedev", "bootdev");
b_setvar(E_SPECIAL|E_VAR, "ramsize", "0");
#define STRINGIT2(x) #x
#define STRINGIT1(x) STRINGIT2(x)
b_setvar(E_SPECIAL|E_VAR, "hz", STRINGIT1(DEFAULT_HZ));
#if BIOS
processor = getprocessor();
if(processor == 1586) processor = 686;
@@ -1066,9 +1090,6 @@ dev_t name2dev(char *name)
if (strcmp(n, "ram") == 0) {
dev= DEV_RAM;
} else
if (strcmp(n, "boot") == 0) {
dev= DEV_BOOT;
} else
if (n[0] == 'f' && n[1] == 'd' && numeric(n+2)) {
/* Floppy. */
tmpdev.device= a2l(n+2);
@@ -1370,13 +1391,14 @@ void boot_device(char *devname)
void ctty(char *line)
{
if (line == nil) {
serial_init(-1);
} else
if (between('0', line[0], '3') && line[1] == 0) {
serial_init(line[0] - '0');
serial_line = -1;
} else if (between('0', line[0], '3') && line[1] == 0) {
serial_line = line[0] - '0';
} else {
printf("Bad serial line number: %s\n", line);
return;
}
serial_init(serial_line);
}
#else /* DOS */
@@ -1854,9 +1876,6 @@ void monitor(void)
#if BIOS
unsigned char cdspec[25];
void bootcdinfo(u32_t, int *, int drive);
void boot(void)
/* Load Minix and start it, among other things. */
{
@@ -1959,3 +1978,4 @@ void main(int argc, char **argv)
/*
* $PchId: boot.c,v 1.14 2002/02/27 19:46:14 philip Exp $
*/

View File

@@ -162,6 +162,7 @@ EXTERN environment *env; /* Lists the environment. */
char *b_value(char *name); /* Get/set the value of a variable. */
int b_setvar(int flags, char *name, char *value);
void b_unset(char *name);
void parse_code(char *code); /* Parse boot monitor commands. */

View File

@@ -640,7 +640,7 @@ _getch:
test ax, ax
jnz gotch
getch:
hlt ! Play dead until interrupted (see pause())
! hlt ! Play dead until interrupted (see pause())
movb ah, #0x01 ! Keyboard status
int 0x16
jz 0f ! Nothing typed
@@ -741,7 +741,7 @@ nulch: ret
! power, or tells an x86 emulator that nothing is happening right now.
.define _pause
_pause:
hlt
! hlt
ret
! void set_mode(unsigned mode);

View File

@@ -18,6 +18,8 @@
#include <minix/const.h>
#include <minix/type.h>
#include <minix/syslib.h>
#include <minix/tty.h>
#include <sys/video.h>
#include <kernel/const.h>
#include <kernel/type.h>
#include <ibm/partition.h>
@@ -27,6 +29,11 @@
static int block_size = 0;
extern int serial_line;
extern u16_t vid_port; /* Video i/o port. */
extern u32_t vid_mem_base; /* Video memory base address. */
extern u32_t vid_mem_size; /* Video memory size. */
#define click_shift clck_shft /* 7 char clash with click_size. */
/* Some kernels have extra features: */
@@ -376,14 +383,49 @@ int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit)
return 1;
}
static void restore_screen(void)
{
struct boot_tty_info boot_tty_info;
u32_t info_location;
#define LINES 25
#define CHARS 80
static u16_t consolescreen[LINES][CHARS];
/* Try and find out what the main console was displaying
* by looking into video memory.
*/
info_location = vid_mem_base+vid_mem_size-sizeof(boot_tty_info);
raw_copy(mon2abs(&boot_tty_info), info_location,
sizeof(boot_tty_info));
if(boot_tty_info.magic == TTYMAGIC) {
if(boot_tty_info.flags & (BTIF_CONSORIGIN|BTIF_CONSCURSOR) ==
(BTIF_CONSORIGIN|BTIF_CONSCURSOR)) {
int line;
raw_copy(mon2abs(consolescreen),
vid_mem_base + boot_tty_info.consorigin,
sizeof(consolescreen));
clear_screen();
for(line = 0; line < LINES; line++) {
int ch;
for(ch = 0; ch < CHARS; ch++) {
u16_t newch = consolescreen[line][ch] & BYTE;
if(newch < ' ') newch = ' ';
putch(newch);
}
}
}
}
}
void exec_image(char *image)
/* Get a Minix image into core, patch it up and execute. */
{
char *delayvalue;
int i;
struct image_header hdr;
char *buf;
u32_t vsec, addr, limit, aout, n;
u32_t vsec, addr, limit, aout, n, totalmem = 0;
struct process *procp; /* Process under construction. */
long a_text, a_data, a_bss, a_stack;
int banner= 0;
@@ -392,13 +434,18 @@ void exec_image(char *image)
char *console;
char params[SECTOR_SIZE];
extern char *sbrk(int);
char *verb;
int verbose = 0;
/* The stack is pretty deep here, so check if heap and stack collide. */
(void) sbrk(0);
if ((verb= b_value("verbose")) != nil && a2l(verb) > 0)
verbose = 1;
printf("\nLoading ");
pretty_image(image);
printf(".\n\n");
printf(".\n");
vsec= 0; /* Load this sector from image next. */
addr= mem[0].base; /* Into this memory block. */
@@ -413,6 +460,8 @@ void exec_image(char *image)
/* Read the many different processes: */
for (i= 0; vsec < image_size; i++) {
u32_t startaddr;
startaddr = addr;
if (i == PROCESS_MAX) {
printf("There are more then %d programs in %s\n",
PROCESS_MAX, image);
@@ -456,7 +505,7 @@ void exec_image(char *image)
hdr.process.a_syms= addr;
raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR);
if (!banner) {
if (!banner && verbose) {
printf(" cs ds text data bss");
if (k_flags & K_CHMEM) printf(" stack");
putch('\n');
@@ -506,14 +555,14 @@ void exec_image(char *image)
/* Make space for bss and stack unless... */
if (i != KERNEL_IDX && (k_flags & K_CLAIM)) a_bss= a_stack= 0;
printf("%07lx %07lx %8ld %8ld %8ld",
if(verbose) {
printf("%07lx %07lx %8ld %8ld %8ld",
procp->cs, procp->ds,
hdr.process.a_text, hdr.process.a_data,
hdr.process.a_bss
);
if (k_flags & K_CHMEM) printf(" %8ld", a_stack);
printf(" %s\n", hdr.name);
);
}
if ((k_flags & K_CHMEM) && verbose) printf(" %8ld", a_stack);
/* Note that a_data may be negative now, but we can look at it
* as -a_data bss bytes.
@@ -540,6 +589,15 @@ void exec_image(char *image)
/* Process endpoint. */
procp->end= addr;
if(verbose)
printf(" %s\n", hdr.name);
else {
u32_t mem;
mem = addr-startaddr;
printf("%s ", hdr.name);
totalmem += mem;
}
if (i == 0 && (k_flags & K_HIGH)) {
/* Load the rest in extended memory. */
addr= mem[1].base;
@@ -547,6 +605,9 @@ void exec_image(char *image)
}
}
if(!verbose)
printf("(%dk)\n", totalmem/1024);
if ((n_procs= i) == 0) {
printf("There are no programs in %s\n", image);
errno= 0;
@@ -570,11 +631,6 @@ void exec_image(char *image)
}
#endif
/* Do delay if wanted. */
if((delayvalue = b_value("bootdelay")) != nil > 0) {
delay(delayvalue);
}
/* Run the trailer function just before starting Minix. */
if (!run_trailer()) { errno= 0; return; }
@@ -607,8 +663,13 @@ void exec_image(char *image)
/* Read leftover character, if any. */
scan_keyboard();
/* Restore screen contents. */
restore_screen();
}
ino_t latest_version(char *version, struct stat *stp)
/* Recursively read the current directory, selecting the newest image on
* the way up. (One can't use r_stat while reading a directory.)
@@ -701,6 +762,13 @@ void bootminix(void)
if ((image= select_image(b_value("image"))) == nil) return;
if(serial_line >= 0) {
char linename[2];
linename[0] = serial_line + '0';
linename[1] = '\0';
b_setvar(E_VAR, SERVARNAME, linename);
}
exec_image(image);
switch (errno) {
@@ -716,6 +784,9 @@ void bootminix(void)
/* No error or error already reported. */;
}
free(image);
if(serial_line >= 0)
b_unset(SERVARNAME);
}
/*

View File

@@ -61,7 +61,7 @@ static char dirbuf[_MAX_BLOCK_SIZE]; /* Scratch/Directory block. */
static block_t a_indir, a_dindir; /* Addresses of the indirects. */
static off_t dirpos; /* Reading pos in a dir. */
#define fsbuf(b) (* (struct buf *) (b))
#define fsbuf(b) (* (union fsdata_u *) (b))
#define zone_shift (super.s_log_zone_size) /* zone to block ratio */
@@ -110,6 +110,7 @@ void r_stat(Ino_t inum, struct stat *stp)
block_t block;
block_t ino_block;
ino_t ino_offset;
union fsdata_u *blockbuf;
/* Calculate start of i-list */
block = START_BLOCK + super.s_imap_blocks + super.s_zmap_blocks;
@@ -120,13 +121,14 @@ void r_stat(Ino_t inum, struct stat *stp)
block += ino_block;
/* Fetch the block */
readblock(block, scratch, block_size);
blockbuf = (union fsdata_u *) scratch;
readblock(block, blockbuf, block_size);
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
d2_inode *dip;
int i;
dip= &fsbuf(scratch).b_v2_ino[ino_offset];
dip= &blockbuf->b__v2_ino[ino_offset];
curfil.i_mode= dip->d2_mode;
curfil.i_nlinks= dip->d2_nlinks;
@@ -142,7 +144,7 @@ void r_stat(Ino_t inum, struct stat *stp)
d1_inode *dip;
int i;
dip= &fsbuf(scratch).b_v1_ino[ino_offset];
dip= &blockbuf->b__v1_ino[ino_offset];
curfil.i_mode= dip->d1_mode;
curfil.i_nlinks= dip->d1_nlinks;
@@ -263,8 +265,8 @@ off_t r_vir2abs(off_t virblk)
i = zone / (zone_t) nr_indirects;
ind_zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
? fsbuf(dindir).b_v2_ind[i]
: fsbuf(dindir).b_v1_ind[i];
? fsbuf(dindir).b__v2_ind[i]
: fsbuf(dindir).b__v1_ind[i];
zone %= (zone_t) nr_indirects;
}
if (ind_zone == 0) return 0;
@@ -276,8 +278,8 @@ off_t r_vir2abs(off_t virblk)
a_indir= z;
}
zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
? fsbuf(indir).b_v2_ind[(int) zone]
: fsbuf(indir).b_v1_ind[(int) zone];
? fsbuf(indir).b__v2_ind[(int) zone]
: fsbuf(indir).b__v1_ind[(int) zone];
/* Calculate absolute datablock number */
z = ((block_t) zone << zone_shift) + zone_index;

27
boot/updateboot.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/sh
set -e
BOOT=/boot/boot
ROOT=`printroot -r`
if [ ! -b "$ROOT" ]
then echo root device $ROOT not found
exit 1
fi
echo -n "Install boot as $BOOT on current root and patch into $ROOT? (y/N) "
read ans
if [ ! "$ans" = y ]
then echo Aborting.
exit 1
fi
make install || true
echo Installing boot monitor into $BOOT.
cp boot $BOOT
echo Patching position of $BOOT into $ROOT.
installboot -d "$ROOT" /usr/mdec/bootblock $BOOT
sync

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

@@ -55,16 +55,16 @@ sh: $(OBJS)
install: /usr/bin/ash /usr/bin/sh /bin/sh /bin/bigsh
/usr/bin/ash: sh
install -cs -o bin $? $@
install -cs -o bin $< $@
/usr/bin/sh: /usr/bin/ash
install -l $? $@
install -l $< $@
/bin/sh: /usr/bin/ash
install -lcs $? $@
install -lcs $< $@
/bin/bigsh: /usr/bin/ash
install -S 6600k -lcs $? $@
install -S 6600k -lcs $< $@
clean:
rm -f $(CLEANFILES) sh core
@@ -75,7 +75,7 @@ token.def: mktokens
sh mktokens
arith.c: arith.y
$(YACC) -d $?
$(YACC) -d $<
mv y.tab.c $@
mv y.tab.h arith_y.h

View File

@@ -131,8 +131,8 @@ struct sig sigtab[] = {
#ifdef SIGXFSZ
SIGXFSZ, "XFSZ", NULL,
#endif
#ifdef SIGVTALARM
SIGVTALARM, "VTALARM", "Virtual alarm",
#ifdef SIGVTALRM
SIGVTALRM, "VTALARM", "Virtual alarm",
#endif
#ifdef SIGPROF
SIGPROF, "PROF", "Profiling alarm",

View File

@@ -548,6 +548,8 @@ int sig;
case SIGTTIN: return "ttin"; /* 21 */
case SIGTTOU: return "ttou"; /* 22 */
case SIGWINCH: return "winch"; /* 23 */
case SIGVTALRM: return "vtalrm"; /* 24 */
case SIGPROF: return "prof"; /* 25 */
#ifdef __minix_vmd
case SIGFPEMU: return "fpemu"; /* 30 */
#endif

View File

@@ -291,11 +291,32 @@ scanreg()
return REGEXP;
}
static int c0;
isarrayindex()
{
int c, c2;
next:
while ((c = Getc()) == ' ' || c == '\t')
;
if (c == '\\') {
if ((c2 = Getc()) == '\n') {
lineno++;
goto next;
}
Ungetc(c2);
}
if (c != '[') Ungetc(c);
return (c == '[');
}
#define UNGET_DEPTH 2
static int unget[UNGET_DEPTH], unget_depth;
Ungetc(c)
{
c0 = c;
if (unget_depth == UNGET_DEPTH) error("unget buffer overflow");
unget[unget_depth++] = c;
if (linep > line) {
if (--linep < line)
@@ -308,9 +329,8 @@ Getc()
register int c;
char *s, *t;
if (c0) {
c = c0; c0 = 0;
}
if (unget_depth > 0)
c = unget[--unget_depth];
else if (srcprg)
c = *srcprg ? *srcprg++ : EOF;
else

View File

@@ -36,7 +36,7 @@ char *cmd;
int iflg; /* interactive mode */
#endif
main(argc, argv) char **argv;
main(argc, argv, envp) char **argv, *envp;
{
char *s, *strpbrk(), *strchr();
void onint();
@@ -98,7 +98,7 @@ main(argc, argv) char **argv;
xargc--;
}
initarg(cmd, xargc, xargv);
initarg(cmd, xargc, xargv, envp);
if (xargc == 0) {
ifp = stdin; *FILENAME = "-";
}

View File

@@ -36,6 +36,7 @@ extern prmflg;
SYMBOL *hashtab[HASHSIZE];
SYMBOL *funtab[HASHSIZE];
SYMBOL *argtab[HASHSIZE];
SYMBOL *envtab[HASHSIZE];
char *strsave(), *emalloc(), *strchr();
CELL *lookup(), *install(), *_install(), *mkcell(), *mktmp(), *getvar();
@@ -86,11 +87,11 @@ setvar(s) char *s;
}
}
initarg(arg0, argc, argv) char *arg0, **argv;
initarg(arg0, argc, argv, envp) char *arg0, **argv, **envp;
{
CELL *u;
register int i;
register char str[4];
register char str[4], *p;
ARGC = &install("ARGC", VAR|NUM, (char *)NULL, (double)argc+1, hashtab)->c_fval;
u = install("ARGV", ARR, (char *)NULL, 0.0, hashtab);
@@ -103,6 +104,19 @@ initarg(arg0, argc, argv) char *arg0, **argv;
else
install(str, VAR|STR, argv[i], 0.0, argtab);
}
u = install("ENVIRON", ARR, (char *)NULL, 0.0, hashtab);
u->c_sval = (char *) envtab;
for (i = 0; envp[i] && *envp[i]; i++) {
if ((p = strchr(envp[i], '=')) != NULL) {
*p = 0;
if (isnum(p+1))
install(envp[i], VAR|STR|NUM, p+1, atof(p+1), envtab);
else
install(envp[i], VAR|STR, p+1, 0.0, envtab);
*p = '=';
}
}
}
static

View File

@@ -265,7 +265,7 @@ stat()
case DELETE:
lex();
u = getvar(text, hashtab, ARR);
if (Getc() != '[')
if (!isarrayindex())
synerr("'[' expected");
p = doarray(u);
p->n_type = DELETE;
@@ -842,7 +842,7 @@ g1:
lex();
break;
case IDENT: case ARG:
if ((c = Getc()) == '[') { /* array */
if (isarrayindex()) { /* array */
/* 940403 */
if (sym == ARG) {
u = (CELL *)emalloc(sizeof(CELL));
@@ -855,7 +855,6 @@ g1:
}
}
else {
Ungetc(c);
if (sym == ARG) {
u = mkcell(POS, NULL, (double)sym1);
p = node1(ARG, u);

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;

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -367,6 +367,9 @@ int tmpstart(filename)
}
nbytes++;
}
if(i >= MAXBLKS) {
FAIL("Too many blocks: %d.", i);
}
lnum[i - 1] = nlines;
}
FoundEOF:

View File

@@ -2,7 +2,7 @@
/* $Header$ */
extern int yylex();
extern int yylex(void);
int main( argc, argv )
int argc;

View File

@@ -2,7 +2,7 @@
/* $Header$ */
int yywrap()
int yywrap(void)
{
return 1;
}

View File

@@ -353,7 +353,7 @@ int exit_status;
{
int tblsiz;
int unlink();
int unlink(const char *);
if ( skelfile != NULL )
{

View File

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

View File

@@ -521,7 +521,7 @@ void gnu_emit_instruction(asm86_t *a)
assert(a->args->operator == 'W' && isanumber(a->args->name));
n= strtoul(a->args->name, nil, 0);
for (s= 0; s <= 4 && (1 << s) < n; s++) {}
for (s= 0; s <= 16 && (1 << s) < n; s++) {}
gnu_printf(".align\t%u", s);
} else
if ((p= opcode2name(a->opcode)) != nil) {

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;
}
}

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