diff -u --recursive --new-file v2.1.77/linux/CREDITS linux/CREDITS --- v2.1.77/linux/CREDITS Fri Jan 2 14:37:00 1998 +++ linux/CREDITS Sun Jan 4 10:40:15 1998 @@ -430,6 +430,18 @@ E: dje@cygnus.com D: Wrote Xenix FS (part of standard kernel since 0.99.15) +N: Riccardo Facchetti +E: fizban@tin.it +P: 1024/6E657BB5 AF 22 90 33 78 76 04 8B AF F9 97 1E B5 E2 65 30 +D: Audio Excel DSP 16 init driver author +D: libmodem author +D: Yet Another Micro Monitor port and current mantainer +D: First ELF-HOWTO author +D: random kernel hacker +S: Via Paolo VI n.29 +S: 23900 - LECCO (Lc) +S: Italy + N: Rik Faith E: faith@cs.unc.edu E: r.faith@ieee.org diff -u --recursive --new-file v2.1.77/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.1.77/linux/Documentation/devices.txt Wed Dec 10 11:12:42 1997 +++ linux/Documentation/devices.txt Sun Jan 4 10:40:15 1998 @@ -93,10 +93,14 @@ the position within the series. block Floppy disks - 0 = /dev/fd0 First floppy disk autodetect - 1 = /dev/fd1 Second floppy disk autodetect - 2 = /dev/fd2 Third floppy disk autodetect - 3 = /dev/fd3 Fourth floppy disk autodetect + 0 = /dev/fd0 Controller 1, drive 1 autodetect + 1 = /dev/fd1 Controller 1, drive 2 autodetect + 2 = /dev/fd2 Controller 1, drive 3 autodetect + 3 = /dev/fd3 Controller 1, drive 4 autodetect + 128 = /dev/fd4 Controller 2, drive 1 autodetect + 129 = /dev/fd5 Controller 2, drive 2 autodetect + 130 = /dev/fd6 Controller 2, drive 3 autodetect + 131 = /dev/fd7 Controller 2, drive 4 autodetect To specify format, add to the autodetect device number: 0 = /dev/fd? Autodetect format diff -u --recursive --new-file v2.1.77/linux/Documentation/networking/depca.txt linux/Documentation/networking/depca.txt --- v2.1.77/linux/Documentation/networking/depca.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/depca.txt Sat Jan 3 20:49:41 1998 @@ -0,0 +1,92 @@ + +DE10x +===== + +Memory Addresses: + + SW1 SW2 SW3 SW4 +64K on on on on d0000 dbfff + off on on on c0000 cbfff + off off on on e0000 ebfff + +32K on on off on d8000 dbfff + off on off on c8000 cbfff + off off off on e8000 ebfff + +DBR ROM on on dc000 dffff + off on cc000 cffff + off off ec000 effff + +Note that the 2K mode is set by SW3/SW4 on/off or off/off. Address +assignment is through the RBSA register. + +I/O Address: + SW5 +0x300 on +0x200 off + +Remote Boot: + SW6 +Disable on +Enable off + +Remote Boot Timeout: + SW7 +2.5min on +30s off + +IRQ: + SW8 SW9 SW10 SW11 SW12 +2 on off off off off +3 off on off off off +4 off off on off off +5 off off off on off +7 off off off off on + +DE20x +===== + +Memory Size: + + SW3 SW4 +64K on on +32K off on +2K on off +2K off off + +Start Addresses: + + SW1 SW2 SW3 SW4 +64K on on on on c0000 cffff + on off on on d0000 dffff + off on on on e0000 effff + +32K on on off off c8000 cffff + on off off off d8000 dffff + off on off off e8000 effff + +Illegal off off - - - - + +I/O Address: + SW5 +0x300 on +0x200 off + +Remote Boot: + SW6 +Disable on +Enable off + +Remote Boot Timeout: + SW7 +2.5min on +30s off + +IRQ: + SW8 SW9 SW10 SW11 SW12 +5 on off off off off +9 off on off off off +10 off off on off off +11 off off off on off +15 off off off off on + diff -u --recursive --new-file v2.1.77/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.77/linux/MAINTAINERS Fri Jan 2 14:37:01 1998 +++ linux/MAINTAINERS Sun Jan 4 11:56:05 1998 @@ -64,71 +64,40 @@ it has been replaced by a better system and you should be using that. -EXT2 FILE SYSTEM -P: Remy Card -M: Remy.Card@linux.org -L: linux-kernel@vger.rutgers.edu -S: Maintained - -DISKQUOTA: -P: Marco van Wieringen -M: mvw@planets.elm.net -L: linux-kernel@vger.rutgers.edu -S: Maintained - 3C501 NETWORK DRIVER P: Alan Cox M: net-patches@lxorguk.ukuu.org.uk L: linux-net@vger.rutgers.edu S: Maintained -8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] -P: Paul Gortmaker -M gpg109@rsphy1.anu.edu.au -L: linux-net@vger.rutgers.edu -S: Maintained -W: http://rsphy1.anu.edu.au/~gpg109/ne2000.html - -ETHEREXPRESS-16 NETWORK DRIVER -P: Philip Blundell -M: Philip.Blundell@pobox.com -L: linux-net@vger.rutgers.edu -S: Maintained - 3C505 NETWORK DRIVER P: Philip Blundell M: Philip.Blundell@pobox.com L: linux-net@vger.rutgers.edu S: Maintained -NI5010 NETWORK DRIVER -P: Jan-Pascal van Best and Andreas Mohr -M: jvbest@qv3pluto.leidenuniv.nl (Best) -M: 100.30936@germany.net (Mohr) -L: linux-net@vger.rutgers.edu -S: Maintained - -TLAN NETWORK DRIVER -P: James Banks -M: james.banks@caldera.com +8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] +P: Paul Gortmaker +M gpg109@rsphy1.anu.edu.au L: linux-net@vger.rutgers.edu -S: Supported +S: Maintained +W: http://rsphy1.anu.edu.au/~gpg109/ne2000.html -DIGI RIGHTSWITCH NETWORK DRIVER -P: Rick Richardson -M: rick@dgii.com -L: linux-net@vger.rutgers.edu -W: http://www.dgii.com/linux/ +AEDSP16 DRIVER +P: Riccardo Facchetti +M: fizban@tin.it S: Maintained -WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS -P: Jean Tourrilhes -M: jt@hplb.hpl.hp.com +ADVANSYS SCSI DRIVER +P: Bob Frey +M: Bob Frey +W: http://www.advansys.com/linux S: Maintained -HP100: Driver for HP 10/100 Mbit/s Network Adapter Series -P: Jarsolav Kysela -M: perex@jcu.cz +AHA152X SCSI DRIVER +P: Juergen E. Fischer +M: Juergen Fischer +L: linux-scsi@vger.rutgers.edu S: Maintained APM DRIVER @@ -137,22 +106,16 @@ L: linux-laptop@vger.rutgers.edu S: Maintained -TOKEN-RING NETWORK DRIVER -P: Paul Norton -M: pnorton@cts.com -L: linux-net@vger.rutgers.edu -S: Maintained - APPLETALK NETWORK LAYER P: Jay Schulist M: Jay.Schulist@spacs.k12.wi.us L: linux-atalk@netspace.org S: Maintained -DECnet NETWORK LAYER -P: Steven Whitehouse -M: SteveW@ACM.org -L: netdev@roxanne.nuclecu.unam.mx +ARPD SUPPORT +P: Jonathan Layes +M: layes@loran.com +L: linux-net@vger.rutgers.edu S: Maintained AX.25 NETWORK LAYER @@ -161,24 +124,6 @@ L: linux-hams@vger.rutgers.edu S: Maintained -DAMA SLAVE for AX.25 -P: Joerg Reuter -M: jreuter@lykos.oche.de -L: linux-hams@vger.rutgers.edu -S: Maintained - -Z8530 DRIVER FOR AX.25 -P: Joerg Reuter -M: jreuter@lykos.oche.de -L: linux-hams@vger.rutgers.edu -S: Maintained - -HIGH-SPEED SCC DRIVER FOR AX.25 -P: Klaus Kudielka -M: oe1kib@oe1xtu.ampr.org -L: linux-hams@vger.rutgers.edu -S: Maintained - BAYCOM/HDLCDRV/SOUNDMODEM DRIVERS FOR AX.25 P: Thomas Sailer M: sailer@ife.ee.ethz.ch @@ -193,22 +138,58 @@ W: http://www.dandelion.com/Linux/ S: Maintained +CONFIGURE.HELP +P: Axel Boldt +M: boldt@math.ucsb.edu +S: Maintained + +CREDITS FILE +P: John A. Martin +M: jam@acm.org +S: Maintained + CYCLADES ASYNC MUX DRIVER P: Marcio Saito M: Marcio Saito W: http://www.cyclades.com/ S: Supported -EATA ISA/EISA/PCI SCSI DRIVER -P: Dario Ballabio -M: dario@milano.europe.dg.com -L: linux-scsi@vger.rutgers.edu +DAMA SLAVE for AX.25 +P: Joerg Reuter +M: jreuter@lykos.oche.de +L: linux-hams@vger.rutgers.edu S: Maintained -U14-34F SCSI DRIVER -P: Dario Ballabio -M: dario@milano.europe.dg.com -L: linux-scsi@vger.rutgers.edu +DECnet NETWORK LAYER +P: Steven Whitehouse +M: SteveW@ACM.org +L: netdev@roxanne.nuclecu.unam.mx +S: Maintained + +DEVICE NUMBER REGISTRY +P: H. Peter Anvin +M: hpa@zytor.com +L: linux-kernel@vger.rutgers.edu +S: Maintained + +DIGI INTL. EPCA DRIVER: +P: Daniel Taylor +M: support@dgii.com +M: digilnux@dgii.com +L: digiboard@list.fuller.edu +S: Maintained + +DIGI RIGHTSWITCH NETWORK DRIVER +P: Rick Richardson +M: rick@dgii.com +L: linux-net@vger.rutgers.edu +W: http://www.dgii.com/linux/ +S: Maintained + +DISKQUOTA: +P: Marco van Wieringen +M: mvw@planets.elm.net +L: linux-kernel@vger.rutgers.edu S: Maintained EATA-DMA SCSI DRIVER @@ -217,18 +198,29 @@ L: linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu S: Maintained +EATA ISA/EISA/PCI SCSI DRIVER +P: Dario Ballabio +M: dario@milano.europe.dg.com +L: linux-scsi@vger.rutgers.edu +S: Maintained + EATA-PIO SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net L: linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu S: Maintained -GDT SCSI DISK ARRAY CONTROLLER DRIVER -P: Achim Leubner -M: achim@vortex.de -L: linux-scsi@vger.rutgers.edu -W: http://www.icp-vortex.com/ -S: Supported +ETHEREXPRESS-16 NETWORK DRIVER +P: Philip Blundell +M: Philip.Blundell@pobox.com +L: linux-net@vger.rutgers.edu +S: Maintained + +EXT2 FILE SYSTEM +P: Remy Card +M: Remy.Card@linux.org +L: linux-kernel@vger.rutgers.edu +S: Maintained FILE LOCKING (flock() and fcntl()/lockf()) P: Andy Walker @@ -236,36 +228,55 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +FPU EMULATOR +P: Bill Metzenthen +M: billm@suburbia.net +W: http://suburbia.net/~billm/floating-point/emulator/ +S: Maintained + FRAME RELAY DLCI/FRAD (Sangoma drivers too) P: Mike McLagan M: mike.mclagan@linux.org L: linux-net@vger.rutgers.edu S: Maintained +FTAPE/QIC-117: +P: Claus-Justus Heine +M: claus@momo.math.rwth-aachen.de +L: linux-tape@vger.rutgers.edu +W: http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ +S: Maintained + FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit) P: Rik Faith M: faith@cs.unc.edu L: linux-scsi@vger.rutgers.edu S: Odd fixes (e.g., new signatures) -SCSI TAPE DRIVER -P: Kai Mdkisara -M: Kai.Makisara@metla.fi +GDT SCSI DISK ARRAY CONTROLLER DRIVER +P: Achim Leubner +M: achim@vortex.de L: linux-scsi@vger.rutgers.edu -S: Maintained +W: http://www.icp-vortex.com/ +S: Supported -FTAPE/QIC-117: -P: Claus-Justus Heine -M: claus@momo.math.rwth-aachen.de -L: linux-tape@vger.rutgers.edu -W: http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ +HAYES ESP SERIAL DRIVER: +P: Andrew J. Robinson +M: arobinso@nyx.net +L: linux-kernel@vger.rutgers.edu +W: http://www.nyx.net/~arobinso +S: Maintainted + +HIGH-SPEED SCC DRIVER FOR AX.25 +P: Klaus Kudielka +M: oe1kib@oe1xtu.ampr.org +L: linux-hams@vger.rutgers.edu S: Maintained -IPX NETWORK LAYER -P: -M: -L: -S: Orphan +HP100: Driver for HP 10/100 Mbit/s Network Adapter Series +P: Jarsolav Kysela +M: perex@jcu.cz +S: Maintained IDE DRIVER [GENERAL] P: Mark Lord @@ -285,12 +296,41 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +IPX NETWORK LAYER +P: +M: +L: +S: Orphan + ISDN SUBSYSTEM P: Fritz Elfert M: fritz@wuemaus.franken.de L: isdn4linux@hub-wue.franken.de S: Maintained +JOYSTICK DRIVER +P: Vojtech Pavlik +M: vojtech@atrey.karlin.mff.cuni.cz +S: Maintained + +KERNEL AUTOMOUNTER (AUTOFS) +P: H. Peter Anvin +M: hpa@zytor.com +L: autofs@linux.kernel.org +S: Maintained + +LINUX FOR POWERPC (PREP) +P: Cort Dougan +M: cort@cs.nmt.edu +W: http://www.cs.nmt.edu/~linuxppc/ +S: Maintained + +LINUX FOR POWER MACINTOSH +P: Paul Mackerras +M: paulus@cs.anu.edu.au +L: linux-pmac@samba.anu.edu.au +S: Maintained + M68K: P: Jes Sorensen M: Jes.Sorensen@cern.ch @@ -298,16 +338,17 @@ L: linux-m68k@lists.linux-m68k.org S: Maintained -MODULE SUPPORT [GENERAL], KERNELD -P: Richard Henderson -M: richard@gnu.ai.mit.edu -L: linux-kernel@vger.rutgers.edu +M68K ON APPLE MACINTOSH: +P: Alan Cox +M: Alan.Cox@linux.org +W: http://www.mac.linux-m68k.org/home.html +L: linux-mac68k@wave.lm.com S: Maintained -ARPD SUPPORT -P: Jonathan Layes -M: layes@loran.com -L: linux-net@vger.rutgers.edu +MENUCONFIG: +P: William Roadcap +M: roadcapw@cfw.com +L: linux-kernel@vger.rutgers.edu S: Maintained MIPS: @@ -317,6 +358,18 @@ L: linux-mips@fnet.fr S: Maintained +MODULE SUPPORT [GENERAL], KERNELD +P: Richard Henderson +M: richard@gnu.ai.mit.edu +L: linux-kernel@vger.rutgers.edu +S: Maintained + +MOUSE AND MISC DEVICES [GENERAL] +P: Alessandro Rubini +M: rubini@ipvvis.unipv.it +L: linux-kernel@vger.rutgers.edu +S: Maintained + NCP FILESYSTEM: P: Volker Lendecke M: lendecke@Math.Uni-Goettingen.de @@ -329,6 +382,11 @@ L: linux-hams@vger.rutgers.edu S: Maintained +NETWORK BLOCK DEVICE +P: Pavel Machek +M: pavel@atrey.karlin.mff.cuni.cz +S: Maintained + NETWORKING [GENERAL]: P: Networking Teak M: netdev@nuclecu.unam.mx @@ -341,9 +399,63 @@ M: davem@caip.rutgers.edu P: Eric Schenk M: Eric.Schenk@dna.lth.se +P: Alexey Kuznetsov +M: kuznet@ms2.inr.ac.ru L: netdev@roxanne.nuclecu.unam.mx S: Maintained +NI5010 NETWORK DRIVER +P: Jan-Pascal van Best and Andreas Mohr +M: jvbest@qv3pluto.leidenuniv.nl (Best) +M: 100.30936@germany.net (Mohr) +L: linux-net@vger.rutgers.edu +S: Maintained + +NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility) +P: Eberhard Moenkeberg +M: emoenke@gwdg.de +L: linux-kernel@vger.rutgers.edu +S: Maintained + +PARALLEL PORT SHARING SUPPORT +P: Phil Blundell +M: Philip.Blundell@pobox.com +P: Tim Waugh +M: tim@cyberelk.demon.co.uk +P: David Campbell +M: campbell@tirian.che.curtin.edu.au +L: linux-parport@torque.net +L: pnp-list@redhat.com +W: http://www.cyberelk.demon.co.uk/parport.html +W: http://www.cage.curtin.edu.au/~campbell/parbus/ +S: Maintained + +PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES +P: Grant Guenther +M: grant@torque.net +L: linux-parport@torque.net +W: http://www.torque.net/linux-pp.html +S: Maintained + +PCI ID DATABASE +P: Jens Maurer +M: jmaurer@cck.uni-kl.de +S: Maintained + +PCNET32 NETWORK DRIVER +P: Thomas Bogendoerfer +M: tsbogend@alpha.franken.de +L: linux-net@vger.rutgers.edu +S: Maintained + +PNP SUPPORT +P: Tom Lees +M: tom@lpsg.demon.co.uk +L: pnp-list@lpsg.demon.co.uk +L: pnp-list@redhat.com (maybe) +W: http://www.lpsg.demon.co.uk/pnp-linux.html +S: Maintained + PPP PROTOCOL DRIVERS AND COMPRESSORS P: Al Longyear M: longyear@pobox.com @@ -356,18 +468,29 @@ L: linux-kernel@vger.rutgers.edu S: Maintained -STARMODE RADIO IP (STRIP) PROTOCOL DRIVER -P: Stuart Cheshire -M: cheshire@cs.stanford.edu -W: http://mosquitonet.Stanford.EDU/strip.html +RISCOM8 DRIVER: +P: Dmitry Gorodchanin +M: begemot@bgm.rosprint.net +L: linux-kernel@vger.rutgers.edu S: Maintained -WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP) -P: Gene Kozin -M: genek@compuserve.com -M: dm@sangoma.com -W: http://www.sangoma.com -S: Supported +SBPCD CDROM DRIVER +P: Eberhard Moenkeberg +M: emoenke@gwdg.de +L: linux-kernel@vger.rutgers.edu +S: Maintained + +SCSI SUBSYSTEM +P: Leonard N. Zubkoff +M: Leonard N. Zubkoff +L: linux-scsi@vger.rutgers.edu +S: Maintained + +SCSI TAPE DRIVER +P: Kai Mdkisara +M: Kai.Makisara@metla.fi +L: linux-scsi@vger.rutgers.edu +S: Maintained SMB FILESYSTEM: P: Volker Lendecke @@ -381,51 +504,17 @@ L: linux-smp@vger.rutgers.edu S: Maintained +SOUND +P: Alan Cox +M: Alan Cox@linux.org +S: Maintained + SPARC: P: David S. Miller M: davem@caip.rutgers.edu L: sparclinux@vger.rutgers.edu S: Maintained -SCSI SUBSYSTEM -P: Leonard N. Zubkoff -M: Leonard N. Zubkoff -L: linux-scsi@vger.rutgers.edu -S: Maintained - -SVGA HANDLING: -P: Martin Mares -M: mj@k332.feld.cvut.cz -L: linux-video@atrey.karlin.mff.cuni.cz -S: Maintained - -VFAT FILESYSTEM: -P: Gordon Chaffee -M: chaffee@cs.berkeley.edu -L: linux-kernel@vger.rutgers.edu -W: http://bmrc.berkeley.edu/people/chaffee -S: Maintained - -DIGI INTL. EPCA DRIVER: -P: Daniel Taylor -M: support@dgii.com -M: digilnux@dgii.com -L: digiboard@list.fuller.edu -S: Maintained - -RISCOM8 DRIVER: -P: Dmitry Gorodchanin -M: begemot@bgm.rosprint.net -L: linux-kernel@vger.rutgers.edu -S: Maintained - -HAYES ESP SERIAL DRIVER: -P: Andrew J. Robinson -M: arobinso@nyx.net -L: linux-kernel@vger.rutgers.edu -W: http://www.nyx.net/~arobinso -S: Maintainted - SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER P: Roger Wolff M: R.E.Wolff@BitWizard.nl @@ -440,140 +529,75 @@ W: http://www.stallion.com S: Supported -MOUSE AND MISC DEVICES [GENERAL] -P: Alessandro Rubini -M: rubini@ipvvis.unipv.it -L: linux-kernel@vger.rutgers.edu -S: Maintained - -MENUCONFIG: -P: William Roadcap -M: roadcapw@cfw.com -L: linux-kernel@vger.rutgers.edu +STARMODE RADIO IP (STRIP) PROTOCOL DRIVER +P: Stuart Cheshire +M: cheshire@cs.stanford.edu +W: http://mosquitonet.Stanford.EDU/strip.html S: Maintained -CONFIGURE.HELP -P: Axel Boldt -M: boldt@math.ucsb.edu +SVGA HANDLING: +P: Martin Mares +M: mj@k332.feld.cvut.cz +L: linux-video@atrey.karlin.mff.cuni.cz S: Maintained -PCI ID DATABASE -P: Jens Maurer -M: jmaurer@cck.uni-kl.de +SYSV FILESYSTEM +P: Krzysztof G. Baranowski +M: kgb@manjak.knm.org.pl S: Maintained -PCNET32 NETWORK DRIVER -P: Thomas Bogendoerfer -M: tsbogend@alpha.franken.de +TLAN NETWORK DRIVER +P: James Banks +M: james.banks@caldera.com L: linux-net@vger.rutgers.edu -S: Maintained +S: Supported -ADVANSYS SCSI DRIVER -P: Bob Frey -M: Bob Frey -W: http://www.advansys.com/linux +TOKEN-RING NETWORK DRIVER +P: Paul Norton +M: pnorton@cts.com +L: linux-net@vger.rutgers.edu S: Maintained -AHA152X SCSI DRIVER -P: Juergen E. Fischer -M: Juergen Fischer +U14-34F SCSI DRIVER +P: Dario Ballabio +M: dario@milano.europe.dg.com L: linux-scsi@vger.rutgers.edu S: Maintained -SBPCD CDROM DRIVER -P: Eberhard Moenkeberg -M: emoenke@gwdg.de -L: linux-kernel@vger.rutgers.edu -S: Maintained - -NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility) -P: Eberhard Moenkeberg -M: emoenke@gwdg.de -L: linux-kernel@vger.rutgers.edu -S: Maintained - UNIFORM CDROM DRIVER P: Erik Andersen M: andersee@debian.org L: linux-kernel@vger.rutgers.edu S: Maintained -PARALLEL PORT SHARING SUPPORT -P: Phil Blundell -M: Philip.Blundell@pobox.com -P: Tim Waugh -M: tim@cyberelk.demon.co.uk -P: David Campbell -M: campbell@tirian.che.curtin.edu.au -L: linux-parport@torque.net -L: pnp-list@redhat.com -W: http://www.cyberelk.demon.co.uk/parport.html -W: http://www.cage.curtin.edu.au/~campbell/parbus/ -S: Maintained - -PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES -P: Grant Guenther -M: grant@torque.net -L: linux-parport@torque.net -W: http://www.torque.net/linux-pp.html -S: Maintained - -PNP SUPPORT -P: Tom Lees -M: tom@lpsg.demon.co.uk -L: pnp-list@lpsg.demon.co.uk -L: pnp-list@redhat.com (maybe) -W: http://www.lpsg.demon.co.uk/pnp-linux.html -S: Maintained - -LINUX FOR POWERPC (PREP) -P: Cort Dougan -M: cort@cs.nmt.edu -W: http://www.cs.nmt.edu/~linuxppc/ -S: Maintained - -LINUX FOR POWER MACINTOSH -P: Paul Mackerras -M: paulus@cs.anu.edu.au -L: linux-pmac@samba.anu.edu.au -S: Maintained - -FPU EMULATOR -P: Bill Metzenthen -M: billm@suburbia.net -W: http://suburbia.net/~billm/floating-point/emulator/ -S: Maintained - -CREDITS FILE -P: John A. Martin -M: jam@acm.org -S: Maintained - -KERNEL AUTOMOUNTER (AUTOFS) -P: H. Peter Anvin -M: hpa@zytor.com -L: autofs@linux.kernel.org -S: Maintained - -DEVICE NUMBER REGISTRY -P: H. Peter Anvin -M: hpa@zytor.com +VFAT FILESYSTEM: +P: Gordon Chaffee +M: chaffee@cs.berkeley.edu L: linux-kernel@vger.rutgers.edu +W: http://bmrc.berkeley.edu/people/chaffee S: Maintained -JOYSTICK DRIVER -P: Vojtech Pavlik -M: vojtech@atrey.karlin.mff.cuni.cz +VIDEO FOR LINUX +P: Alan Cox +M: Alan.Cox@linux.org S: Maintained -NETWORK BLOCK DEVICE -P: Pavel Machek -M: pavel@atrey.karlin.mff.cuni.cz +WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP) +P: Gene Kozin +M: genek@compuserve.com +M: dm@sangoma.com +W: http://www.sangoma.com +S: Supported + +WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS +P: Jean Tourrilhes +M: jt@hplb.hpl.hp.com S: Maintained -SYSV FILESYSTEM -P: Krzysztof G. Baranowski -M: kgb@manjak.knm.org.pl +Z8530 DRIVER FOR AX.25 +P: Joerg Reuter +M: jreuter@lykos.oche.de +L: linux-hams@vger.rutgers.edu S: Maintained REST: diff -u --recursive --new-file v2.1.77/linux/Makefile linux/Makefile --- v2.1.77/linux/Makefile Fri Jan 2 14:37:01 1998 +++ linux/Makefile Mon Jan 5 01:41:01 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 77 +SUBLEVEL = 78 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) @@ -209,19 +209,23 @@ mkdir include/linux/modules; \ fi -oldconfig: symlinks +oldconfig: symlinks scripts/split-include $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in + scripts/split-include include/linux/autoconf.h include/config -xconfig: symlinks +xconfig: symlinks scripts/split-include $(MAKE) -C scripts kconfig.tk wish -f scripts/kconfig.tk + scripts/split-include include/linux/autoconf.h include/config -menuconfig: include/linux/version.h symlinks +menuconfig: include/linux/version.h symlinks scripts/split-include $(MAKE) -C scripts/lxdialog all $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in + scripts/split-include include/linux/autoconf.h include/config -config: symlinks +config: symlinks scripts/split-include $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in + scripts/split-include include/linux/autoconf.h include/config linuxsubdirs: dummy set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done @@ -339,8 +343,9 @@ clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` - rm -f core `find . -type f -name 'core' -print` + rm -f `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` + rm -f `find . -type f -name 'core' -print` + rm -f `find . -name '.*.flags' -print` rm -f vmlinux System.map rm -f .tmp* rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash @@ -361,8 +366,9 @@ rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog rm -f .menuconfig.log rm -f include/asm + rm -rf include/config rm -f .depend `find . -name .depend -print` - rm -f .hdepend scripts/mkdep + rm -f .hdepend scripts/mkdep scripts/split-include rm -f $(TOPDIR)/include/linux/modversions.h rm -rf $(TOPDIR)/include/linux/modules rm -rf modules @@ -380,10 +386,9 @@ find . -type f -print | sort | xargs sum > .SUMS dep-files: scripts/mkdep archdep include/linux/version.h - scripts/mkdep init/*.c > .tmpdepend + scripts/mkdep init/*.c > .depend scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done - mv .tmpdepend .depend MODVERFILE := @@ -393,6 +398,9 @@ depend dep: dep-files $(MODVERFILE) +checkconfig: + perl -w scripts/checkconfig.pl `find $(FINDHPATH) $(SUBDIRS) -name '*.[hcS]' -print | sort` + ifdef CONFIGURATION ..$(CONFIGURATION): @echo @@ -421,3 +429,6 @@ scripts/mkdep: scripts/mkdep.c $(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c + +scripts/split-include: scripts/split-include.c + $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c diff -u --recursive --new-file v2.1.77/linux/Rules.make linux/Rules.make --- v2.1.77/linux/Rules.make Mon Apr 14 16:28:05 1997 +++ linux/Rules.make Mon Jan 5 01:41:01 1998 @@ -45,13 +45,18 @@ # %.s: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o $@ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $< -o $@ %.i: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E $< > $@ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -E $< > $@ %.o: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -c -o $@ $< + @ ( \ + echo 'ifeq ($(strip $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@)),$$(strip $$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@)))' ; \ + echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ + echo 'endif' \ + ) > .$@.flags %.o: %.s $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $< @@ -66,29 +71,39 @@ # ifdef O_TARGET ALL_O = $(OX_OBJS) $(O_OBJS) -$(O_TARGET): $(ALL_O) $(TOPDIR)/include/linux/config.h +$(O_TARGET): $(ALL_O) rm -f $@ ifneq "$(strip $(ALL_O))" "" $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(ALL_O) else $(AR) rcs $@ endif + @ ( \ + echo 'ifeq ($(strip $(EXTRA_LDFLAGS) $(ALL_O)),$$(strip $$(EXTRA_LDFLAGS) $$(ALL_O)))' ; \ + echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ + echo 'endif' \ + ) > .$@.flags endif # O_TARGET # # Rule to compile a set of .o files into one .a file # ifdef L_TARGET -$(L_TARGET): $(LX_OBJS) $(L_OBJS) $(TOPDIR)/include/linux/config.h +$(L_TARGET): $(LX_OBJS) $(L_OBJS) rm -f $@ $(AR) $(EXTRA_ARFLAGS) rcs $@ $(LX_OBJS) $(L_OBJS) + @ ( \ + echo 'ifeq ($(strip $(EXTRA_ARFLAGS) $(LX_OBJS) $(L_OBJS)),$$(strip $$(EXTRA_ARFLAGS) $$(LX_OBJS) $$(L_OBJS)))' ; \ + echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ + echo 'endif' \ + ) > .$@.flags endif # # This make dependencies quickly # fastdep: dummy - $(TOPDIR)/scripts/mkdep *.[chS] > .depend + $(TOPDIR)/scripts/mkdep $(wildcard *.[chS] local.h.master) > .depend ifdef ALL_SUB_DIRS set -e; for i in $(ALL_SUB_DIRS); do $(MAKE) -C $$i fastdep; done endif @@ -131,7 +146,7 @@ ifneq "$(strip $(ALL_MOBJS))" "" echo $(PDWN) cd $$TOPDIR/modules; for i in $(ALL_MOBJS); do \ - ln -sf ../$(PDWN)/$$i .; done + ln -sf ../$(PDWN)/$$i $$i; done endif # @@ -198,19 +213,54 @@ ifneq "$(strip $(SYMTAB_OBJS))" "" $(SYMTAB_OBJS): $(TOPDIR)/include/linux/modversions.h $(SYMTAB_OBJS:.o=.c) - $(CC) $(CFLAGS) -DEXPORT_SYMTAB -c $(@:.o=.c) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c) + @ ( \ + echo 'ifeq ($(strip $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB),$$(strip $$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB))' ; \ + echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ + echo 'endif' \ + ) > .$@.flags endif endif # CONFIG_MODULES # -# include dependency files they exist +# include dependency files if they exist # -ifeq (.depend,$(wildcard .depend)) +ifneq ($(wildcard .depend),) include .depend endif -ifeq ($(TOPDIR)/.hdepend,$(wildcard $(TOPDIR)/.hdepend)) +ifneq ($(wildcard $(TOPDIR)/.hdepend),) include $(TOPDIR)/.hdepend +endif + +# +# Find files whose flags have changed and force recompilation. +# For safety, this works in the converse direction: +# every file is forced, except those whose flags are positively up-to-date. +# +FILES_FLAGS_UP_TO_DATE := + +FILES_FLAGS_EXIST := $(wildcard .*.flags) +ifneq ($(FILES_FLAGS_EXIST),) +include $(FILES_FLAGS_EXIST) +endif + +FILES_FLAGS_CHANGED := $(strip \ + $(filter-out $(FILES_FLAGS_UP_TO_DATE), \ + $(O_TARGET) $(O_OBJS) $(OX_OBJS) \ + $(L_TARGET) $(L_OBJS) $(LX_OBJS) \ + $(M_OBJS) $(MX_OBJS) \ + $(MI_OBJS) $(MIX_OBJS) \ + )) + +# A kludge: .S files don't get flag dependencies (yet), +# because that will involve changing a lot of Makefiles. +FILES_FLAGS_CHANGED := $(strip \ + $(filter-out $(patsubst %.S, %.o, $(wildcard *.S)), \ + $(FILES_FLAGS_CHANGED))) + +ifneq ($(FILES_FLAGS_CHANGED),) +$(FILES_FLAGS_CHANGED): dummy endif diff -u --recursive --new-file v2.1.77/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.1.77/linux/arch/i386/config.in Sun Dec 21 22:36:12 1997 +++ linux/arch/i386/config.in Mon Jan 5 00:06:25 1998 @@ -109,10 +109,10 @@ endmenu # Conditionally compile in the Uniform CD-ROM driver -if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_CM206" = "y" -o "$CONFIG_CDU31A" = "y" ]; then +if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_MCDX" = "y" -o "$CONFIG_CM206" = "y" -o "$CONFIG_CDU31A" = "y" ]; then define_bool CONFIG_CDROM y else - if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" -o "$CONFIG_SBPCD" = "m" -o "$CONFIG_MCD" = "m" -o "$CONFIG_CM206" = "m" -o "$CONFIG_CDU31A" = "m" ]; then + if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" -o "$CONFIG_SBPCD" = "m" -o "$CONFIG_MCD" = "m" -o "$CONFIG_MCDX" = "m" -o "$CONFIG_CM206" = "m" -o "$CONFIG_CDU31A" = "m" ]; then define_bool CONFIG_CDROM m else define_bool CONFIG_CDROM n diff -u --recursive --new-file v2.1.77/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.77/linux/arch/i386/defconfig Fri Jan 2 14:37:01 1998 +++ linux/arch/i386/defconfig Sun Jan 4 23:50:43 1998 @@ -237,6 +237,7 @@ # CONFIG_NTFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_AUTOFS_FS=y # CONFIG_UFS_FS is not set diff -u --recursive --new-file v2.1.77/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.1.77/linux/arch/i386/kernel/vm86.c Mon Dec 1 12:04:11 1997 +++ linux/arch/i386/kernel/vm86.c Sun Jan 4 10:55:08 1998 @@ -122,7 +122,7 @@ -static do_vm86_irq_handling(int subfunction, int irqnumber); +static int do_vm86_irq_handling(int subfunction, int irqnumber); static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk); asmlinkage int sys_vm86old(struct vm86_struct * v86) diff -u --recursive --new-file v2.1.77/linux/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c --- v2.1.77/linux/drivers/ap1000/ddv.c Thu Dec 4 14:53:54 1997 +++ linux/drivers/ap1000/ddv.c Sun Jan 4 10:40:15 1998 @@ -985,9 +985,10 @@ int init_module(void) { int error = ddv_init(); - ddv_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 }); - if (!error) + if (!error) { + ddv_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 }); printk(KERN_INFO "DDV: Loaded as module.\n"); + } return error; } @@ -995,6 +996,7 @@ void cleanup_module(void) { int i; + struct gendisk ** gdp; for (i = 0 ; i < NUM_DDVDEVS; i++) invalidate_buffers(MKDEV(MAJOR_NR, i)); @@ -1004,6 +1006,11 @@ OPT_IO(PRST) = PRST_IRST; unregister_blkdev( MAJOR_NR, DEVICE_NAME ); + for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) + if (*gdp == &ddv_gendisk) + break; + if (*gdp) + *gdp = (*gdp)->next; free_irq(APOPT0_IRQ, NULL); blk_dev[MAJOR_NR].request_fn = 0; } diff -u --recursive --new-file v2.1.77/linux/drivers/block/acsi.c linux/drivers/block/acsi.c --- v2.1.77/linux/drivers/block/acsi.c Mon Aug 4 16:25:37 1997 +++ linux/drivers/block/acsi.c Sun Jan 4 10:40:15 1998 @@ -1820,12 +1820,19 @@ void cleanup_module(void) { + struct gendisk ** gdp; + del_timer( &acsi_timer ); blk_dev[MAJOR_NR].request_fn = 0; free_pages( (unsigned long)acsi_buffer, ACSI_BUFFER_ORDER ); if (unregister_blkdev( MAJOR_NR, "ad" ) != 0) printk( KERN_ERR "acsi: cleanup_module failed\n"); + for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) + if (*gdp == &acsi_gendisk) + break; + if (*gdp) + *gdp = (*gdp)->next; } #endif diff -u --recursive --new-file v2.1.77/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.77/linux/drivers/block/floppy.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/floppy.c Sun Jan 4 10:55:08 1998 @@ -4246,7 +4246,7 @@ void cleanup_module(void) { - int fdc, dummy; + int dummy; unregister_blkdev(MAJOR_NR, "fd"); diff -u --recursive --new-file v2.1.77/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.1.77/linux/drivers/block/genhd.c Fri Jan 2 14:37:01 1998 +++ linux/drivers/block/genhd.c Sun Jan 4 10:40:15 1998 @@ -255,6 +255,45 @@ done: brelse(bh); } +#ifdef CONFIG_SOLARIS_X86_PARTITION +static void +solaris_x86_partition(struct gendisk *hd, kdev_t dev, long offset) { + + struct buffer_head *bh; + struct solaris_x86_vtoc *v; + struct solaris_x86_slice *s; + int i; + + if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) + return; + v = (struct solaris_x86_vtoc *)(bh->b_data + 512); + if(v->v_sanity != SOLARIS_X86_VTOC_SANE) { + brelse(bh); + return; + } + printk(" v_version != 1) { + printk(" cannot handle version %ld vtoc>", v->v_version); + brelse(bh); + return; + } + for(i=0; iv_slice[i]; + + if (s->s_tag == 0) + continue; + printk(" [s%d]", i); + /* solaris partitions are relative to current MS-DOS + * one but add_partition starts relative to sector + * zero of the disk. Therefore, must add the offset + * of the current partition */ + add_partition(hd, current_minor, s->s_start+offset, s->s_size); + current_minor++; + } + brelse(bh); + printk(" >"); +} +#endif #ifdef CONFIG_BSD_DISKLABEL /* @@ -419,6 +458,18 @@ printk(" <"); bsd_disklabel_partition(hd, MKDEV(hd->major, minor)); printk(" >"); + } +#endif +#ifdef CONFIG_SOLARIS_X86_PARTITION + + /* james@bpgc.com: Solaris has a nasty indicator: 0x82 + * which also means linux swap. For that reason, all + * of the prints are done inside the + * solaris_x86_partition routine */ + + if(SYS_IND(p) == SOLARIS_X86_PARTITION) { + solaris_x86_partition(hd, MKDEV(hd->major, minor), + first_sector+START_SECT(p)); } #endif } diff -u --recursive --new-file v2.1.77/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.1.77/linux/drivers/block/ide-cd.c Sun Dec 21 16:17:44 1997 +++ linux/drivers/block/ide-cd.c Mon Jan 5 00:06:25 1998 @@ -27,10 +27,8 @@ * unless you have a patch to fix it. I am working on it...) * -Implement ide_cdrom_select_speed using the generic cdrom interface * -Fix ide_cdrom_reset so that it works (it does nothing right now) - * - * MOSTLY DONE LIST: - * Query the drive to find what features are available - * before trying to use them. + * -Query the drive to find what features are available before trying to + * use them (like trying to close the tray in drives that can't). * * * ---------------------------------- @@ -182,10 +180,12 @@ * 4.07 Dec 17, 1997 -- fallback to set pc->stat on "tray open" * 4.08 Dec 18, 1997 -- spew less noise when tray is empty * -- fix speed display for ACER 24X, 18X + * 4.09 Jan 04, 1998 -- fix handling of the last block so we return + * an end of file instead of an I/O error (Gadi) * *************************************************************************/ -#define IDECD_VERSION "4.07" +#define IDECD_VERSION "4.09" #include #include @@ -1663,7 +1663,7 @@ if (stat) toc->capacity = 0x1fffff; HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] - = toc->capacity * SECTORS_PER_FRAME; + = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; /* Remember that we've read this stuff. */ diff -u --recursive --new-file v2.1.77/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.1.77/linux/drivers/block/xd.c Sat Nov 29 11:25:09 1997 +++ linux/drivers/block/xd.c Sun Jan 4 10:40:15 1998 @@ -20,13 +20,14 @@ * * Modularized: 04/10/96 by Todd Fries, tfries@umr.edu * - * Revised: 13/09/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl + * Revised: 13/12/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl * Fixed some problems with disk initialization and module initiation. * Added support for manual geometry setting (except Seagate controllers) * in form: * xd_geo=,,[,,,] - * Recovered DMA access. Abridged messages. Added support for DTC5051CX & - * WD1002-27X controllers. Added alternate jumper geometry setting. + * Recovered DMA access. Abridged messages. Added support for DTC5051CX, + * WD1002-27X & XEBEC controllers. Driver uses now some jumper settings. + * Extended ioctl() support. */ #include @@ -38,6 +39,7 @@ #include #include #include +#include #include #include @@ -114,12 +116,15 @@ { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */ { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */ { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */ + { 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */ }; static unsigned int xd_bases[] __initdata = { 0xC8000, 0xCA000, 0xCC000, - 0xCE000, 0xD0000, 0xD8000, + 0xCE000, 0xD0000, 0xD2000, + 0xD4000, 0xD6000, 0xD8000, + 0xDA000, 0xDC000, 0xDE000, 0xE0000 }; @@ -219,6 +224,11 @@ if (xd_detect(&controller,&address)) { printk("Detected a%s controller (type %d) at address %06x\n",xd_sigs[controller].name,controller,address); + if (check_region(xd_iobase,4)) { + printk("xd: Ports at 0x%x are not available\n",xd_iobase); + return; + } + request_region(xd_iobase,4,"xd"); if (controller) xd_sigs[controller].init_controller(address); xd_drives = xd_initdrives(xd_sigs[controller].init_drive); @@ -331,6 +341,8 @@ if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; + case BLKRAGET: + return put_user(read_ahead[MAJOR(inode->i_rdev)], (long*) arg); case BLKGETSIZE: if (!arg) return -EINVAL; return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg); @@ -339,6 +351,19 @@ fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; + case HDIO_SET_DMA: + if (!suser()) return -EACCES; + if (xdc_busy) return -EBUSY; + nodma = !arg; + if (nodma && xd_dma_buffer) { + xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200); + xd_dma_buffer = 0; + } + return 0; + case HDIO_GET_DMA: + return put_user(!nodma, (long *) arg); + case HDIO_GET_MULTCOUNT: + return put_user(xd_maxsectors, (long *) arg); case BLKRRPART: return xd_reread_partitions(inode->i_rdev); RO_IOCTLS(inode->i_rdev,arg); @@ -929,6 +954,81 @@ xd_info[drive].control = 2; } +/* Xebec support (AK) */ +__initfunc(static void xd_xebec_init_controller (unsigned int address)) +{ +/* iobase may be set manually in range 0x300 - 0x33C + irq may be set manually to 2(9),3,4,5,6,7 + dma may be set manually to 1,2,3 + (How to detect them ???) +BIOS address may be set manually in range 0x0 - 0xF8000 +If you need non-standard settings use the xd=... command */ + + switch (address) { + case 0x00000: + case 0xC8000: /* initially: xd_iobase==0x320 */ + case 0xD0000: + case 0xD2000: + case 0xD4000: + case 0xD6000: + case 0xD8000: + case 0xDA000: + case 0xDC000: + case 0xDE000: + case 0xE0000: break; + default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address); + break; + } + + xd_maxsectors = 0x01; + outb(0,XD_RESET); /* reset the controller */ + + xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; + add_timer(&xd_timer); + sleep_on(&xdc_wait); +} + +__initfunc(static void xd_xebec_init_drive (u_char drive)) +{ + /* values from controller's BIOS - BIOS chip may be removed */ + static u_short geometry_table[][5] = { + {0x132,4,0x080,0x080,0x7}, + {0x132,4,0x080,0x080,0x17}, + {0x264,2,0x100,0x100,0x7}, + {0x264,2,0x100,0x100,0x17}, + {0x132,8,0x080,0x080,0x7}, + {0x132,8,0x080,0x080,0x17}, + {0x264,4,0x100,0x100,0x6}, + {0x264,4,0x100,0x100,0x17}, + {0x2BC,5,0x2BC,0x12C,0x6}, + {0x3A5,4,0x3A5,0x3A5,0x7}, + {0x26C,6,0x26C,0x26C,0x7}, + {0x200,8,0x200,0x100,0x17}, + {0x400,5,0x400,0x400,0x7}, + {0x400,6,0x400,0x400,0x7}, + {0x264,8,0x264,0x200,0x17}, + {0x33E,7,0x33E,0x200,0x7}}; + u_char n; + + n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry + is assumed for BOTH drives */ + if (xd_geo[3*drive]) + xd_manual_geo_set(drive); + else { + xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */ + xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */ + xd_info[drive].sectors = 17; /* sectors */ +#if 0 + xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */ + xd_info[drive].precomp = geometry_table[n][3] /* write precomp */ + xd_info[drive].ecc = 0x0B; /* ecc length */ +#endif /* 0 */ + } + xd_info[drive].control = geometry_table[n][4]; /* control byte */ + xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B); + xd_recalibrate(drive); +} + /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */ __initfunc(static void xd_override_init_drive (u_char drive)) @@ -1008,7 +1108,9 @@ cmdblk[12] = (u_char) (wprecomp & 0xFF); cmdblk[13] = ecc; - if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) + /* Some controllers require geometry info as data, not command */ + + if (xd_command(cmdblk,PIO_MODE,0,&cmdblk[6],0,XD_TIMEOUT * 2)) printk("xd: error setting characteristics for xd%c\n", 'a'+drive); } @@ -1020,6 +1122,23 @@ MODULE_PARM(xd_geo, "3-6i"); MODULE_PARM(nodma, "i"); +static void xd_done (void) +{ + struct gendisk ** gdp; + + blksize_size[MAJOR_NR] = NULL; + blk_dev[MAJOR_NR].request_fn = NULL; + blk_size[MAJOR_NR] = NULL; + hardsect_size[MAJOR_NR] = NULL; + read_ahead[MAJOR_NR] = 0; + for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) + if (*gdp == &xd_gendisk) + break; + if (*gdp) + *gdp = (*gdp)->next; + release_region(xd_iobase,4); +} + int init_module(void) { int i,count = 0; @@ -1036,6 +1155,7 @@ if (!xd_drives) { /* no drives detected - unload module */ unregister_blkdev(MAJOR_NR, "xd"); + xd_done(); return (-1); } for (i = 0; i < xd_drives; i++) @@ -1047,7 +1167,20 @@ void cleanup_module(void) { + int partition,dev,start; + unregister_blkdev(MAJOR_NR, "xd"); + for (dev = 0; dev < xd_drives; dev++) { + start = dev << xd_gendisk.minor_shift; + for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) { + int minor = (start | partition); + kdev_t devp = MKDEV(MAJOR_NR, minor); + start = dev << xd_gendisk.minor_shift; + sync_dev(devp); + invalidate_buffers(devp); + } + } + xd_done(); if (xd_drives) { free_irq(xd_irq, NULL); free_dma(xd_dma); diff -u --recursive --new-file v2.1.77/linux/drivers/block/xd.h linux/drivers/block/xd.h --- v2.1.77/linux/drivers/block/xd.h Sat Nov 29 11:25:09 1997 +++ linux/drivers/block/xd.h Sun Jan 4 10:40:15 1998 @@ -46,6 +46,7 @@ #define CMD_DTCGETGEOM 0xFF /* get geometry data (DTC 5150X only?) */ #define CMD_ST11GETGEOM 0xF8 /* get geometry data (Seagate ST11R/M only?) */ #define CMD_WDSETPARAM 0x0C /* set drive parameters (WD 1004A27X only?) */ +#define CMD_XBSETPARAM 0x0C /* set drive parameters (XEBEC only?) */ /* Bits for command status byte */ #define CSB_ERROR 0x02 /* error */ @@ -136,6 +137,8 @@ static void xd_seagate_init_drive (u_char drive); static void xd_omti_init_controller (unsigned int address); static void xd_omti_init_drive (u_char drive); +static void xd_xebec_init_controller (unsigned int address); +static void xd_xebec_init_drive (u_char drive); static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc); static void xd_override_init_drive (u_char drive); diff -u --recursive --new-file v2.1.77/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.1.77/linux/drivers/cdrom/cdrom.c Fri Jan 2 14:37:01 1998 +++ linux/drivers/cdrom/cdrom.c Mon Jan 5 00:06:26 1998 @@ -1,6 +1,6 @@ /* linux/drivers/cdrom/cdrom.c. Copyright (c) 1996, 1997 David A. van Leeuwen. - Copyright (c) 1997 Erik Andersen (andersee@debian.org) + Copyright (c) 1997, 1998 Erik Andersen (andersee@debian.org) May be copied or modified under the terms of the GNU General Public License. See linux/COPYING for more information. @@ -68,14 +68,10 @@ #include -#define VERSION "$Id: cdrom.c,v 2.1 1997/12/28 15:11:47 david Exp $" -#define REVISION "$Revision: 2.1 $" +#define VERSION "$Id: cdrom.c,v 2.11 1998/01/04 01:11:18 erik Exp $" +#define REVISION "Revision: 2.11" #define FM_WRITE 0x2 /* file mode write bit */ -/* When VERBOSE_STATUS_INFO is not defined, the debugging printks don't - get compiled in */ -#define VERBOSE_STATUS_INFO - /* I use an error-log mask to give fine grain control over the type of error messages dumped to the system logs. The available masks include: */ #define CD_WARNING 0x1 @@ -83,9 +79,14 @@ #define CD_DO_IOCTL 0x4 #define CD_OPEN 0x8 #define CD_CLOSE 0x10 +#define CD_COUNT_TRACKS 0x20 + +/* When VERBOSE_STATUS_INFO is not defined, the debugging printks don't + get compiled in at all */ +#define VERBOSE_STATUS_INFO #define ERRLOGMASK (CD_WARNING) -/* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_CLOSE) */ +/* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE) */ #ifdef VERBOSE_STATUS_INFO @@ -480,7 +481,7 @@ tracks->cdi=0; tracks->xa=0; tracks->error=0; - cdinfo(CD_OPEN, "entering cdrom_count_tracks\n"); + cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); if (!(cdi->ops->capability & CDC_PLAY_AUDIO)) { tracks->error=CDS_NO_INFO; return; @@ -508,10 +509,10 @@ tracks->data++; } else tracks->audio++; - cdinfo(CD_OPEN, "track %d: format=%d, ctrl=%d\n", + cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", i, entry.cdte_format, entry.cdte_ctrl); } - cdinfo(CD_OPEN, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", + cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", header.cdth_trk1, tracks->audio, tracks->data, tracks->cdi, tracks->xa); } diff -u --recursive --new-file v2.1.77/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c --- v2.1.77/linux/drivers/cdrom/cdu31a.c Tue Dec 2 16:45:18 1997 +++ linux/drivers/cdrom/cdu31a.c Mon Jan 5 00:06:26 1998 @@ -416,7 +416,8 @@ return -EINVAL; } - return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY; + /*return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;*/ + return sony_spun_up ? CDS_DISC_OK : CDS_TRAY_OPEN; } static inline void @@ -1085,7 +1086,7 @@ volatile int val; -#if DEBUG +#if 0*DEBUG printk("Entering handle_sony_cd_attention\n"); #endif if (is_attention()) @@ -1166,7 +1167,7 @@ } num_consecutive_attentions = 0; -#if DEBUG +#if 0*DEBUG printk("Leaving handle_sony_cd_attention at %d\n", __LINE__); #endif return(0); @@ -2835,8 +2836,11 @@ sony_audio_status = CDROM_AUDIO_INVALID; return do_sony_cd_cmd_chk("EJECT",SONY_EJECT_CMD, NULL, 0, res_reg, &res_size); - } else - return 0; + } else { + if (0 == scd_spinup()) + sony_spun_up = 1; + return 0; + } } /* @@ -3230,7 +3234,6 @@ printk("CDU31A: Unable to set XA params: 0x%2.2x\n", res_reg[1]); } sony_xa_mode = 1; -printk("sony_xa_mode is set\n"); } /* A non-XA disk. Set the parms back if necessary. */ else if (sony_xa_mode) @@ -3247,7 +3250,6 @@ printk("CDU31A: Unable to reset XA params: 0x%2.2x\n", res_reg[1]); } sony_xa_mode = 0; -printk("sony_xa_mode is reset\n"); } sony_spun_up = 1; @@ -3293,7 +3295,7 @@ scd_reset, /* hard reset */ scd_audio_ioctl, /* audio ioctl */ scd_dev_ioctl, /* device-specific ioctl */ - CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_MULTI_SESSION | + CDC_OPEN_TRAY | CDC_CLOSE_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_MULTI_SESSION | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS, /* capability */ 1, /* number of minor devices */ @@ -3571,6 +3573,7 @@ cdu31a_abort_timer.function = handle_abort_timeout; scd_info.mask = deficiency; + strncpy(scd_info.name, "cdu31a", sizeof(scd_info.name)); if (register_cdrom(&scd_info)) { diff -u --recursive --new-file v2.1.77/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c --- v2.1.77/linux/drivers/cdrom/cm206.c Fri Jan 2 14:37:01 1998 +++ linux/drivers/cdrom/cm206.c Sun Jan 4 10:55:08 1998 @@ -887,7 +887,7 @@ uch * q = cd->q; uch ct; /* current track */ int binary=0; - const skip = 3*60*75; /* 3 minutes */ + const int skip = 3*60*75; /* 3 minutes */ for (i=track; i>0; i--) if (cd->toc[i].track) { min = fsm2lba(cd->toc[i].fsm); diff -u --recursive --new-file v2.1.77/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c --- v2.1.77/linux/drivers/cdrom/mcdx.c Tue Dec 2 16:45:18 1997 +++ linux/drivers/cdrom/mcdx.c Mon Jan 5 00:06:26 1998 @@ -75,9 +75,6 @@ #define mcdx_drive_map mcdx #include "mcdx.h" -#define MCDX_QUIET 0 - - #ifndef HZ #error HZ not defined #endif @@ -288,7 +285,7 @@ NULL, /* hard reset */ mcdx_audio_ioctl, /* audio ioctl */ NULL, /* device-specific ioctl */ - CDC_OPEN_TRAY | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO + CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_DRIVE_STATUS, /* capability */ 0, /* number of minor devices */ }; diff -u --recursive --new-file v2.1.77/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.1.77/linux/drivers/cdrom/sbpcd.c Tue Dec 2 16:45:18 1997 +++ linux/drivers/cdrom/sbpcd.c Mon Jan 5 00:06:26 1998 @@ -550,7 +550,6 @@ static struct cdrom_subchnl SC; static struct cdrom_volctrl volctrl; static struct cdrom_read_audio read_audio; -static struct cdrom_multisession ms_info; static unsigned char msgnum=0; static char msgbuf[80]; @@ -2297,12 +2296,52 @@ } i=cmd_out(); msg(DBG_LCS,"p_door_closed bit %d after\n", st_door_closed); + + i=cc_ReadError(); + flags_cmd_out |= f_respo2; + cc_ReadStatus(); /* command: give 1-byte status */ + i=ResponseStatus(); + if (famT_drive&&(i<0)) + { + cc_DriveReset(); + i=ResponseStatus(); +#if 0 + sbp_sleep(HZ); +#endif 0 + i=ResponseStatus(); + } + if (i<0) + { + msg(DBG_INF,"sbpcd cc_CloseTray: ResponseStatus timed out (%d).\n",i); + } + if (!(famT_drive)) + { + if (!st_spinning) + { + cc_SpinUp(); + if (st_check) i=cc_ReadError(); + flags_cmd_out |= f_respo2; + cc_ReadStatus(); + i=ResponseStatus(); + } else { + } + } + i=DiskInfo(); return (i); } static int sbpcd_tray_move(struct cdrom_device_info *cdi, int position) { - return position ? cc_CloseTray() : 0; + int i; + i = MINOR(cdi->dev); + + switch_drive(i); + if (position == 1) { + cc_SpinDown(); + } else { + return cc_CloseTray(); + } + return 0; } /*==========================================================================*/ @@ -2768,11 +2807,13 @@ if (famLV_drive) D_S[d].CDsize_frm=D_S[d].size_blk+1; } D_S[d].diskstate_flags |= toc_bit; - msg(DBG_TOC,"TocDesc: %02X %02X %02X %08X\n", + msg(DBG_TOC,"TocDesc: xa %02X firstt %02X lastt %02X size %08X firstses %02X lastsess %02X\n", D_S[d].xa_byte, D_S[d].n_first_track, D_S[d].n_last_track, - D_S[d].size_msf); + D_S[d].size_msf, + D_S[d].first_session, + D_S[d].last_session); return (0); } /*==========================================================================*/ @@ -3886,6 +3927,7 @@ msg(DBG_000,"DiskInfo entered.\n"); for (j=1;j=0) break; msg(DBG_INF,"DiskInfo: ReadCapacity #%d returns %d\n", j, i); +#if 0 i=cc_DriveReset(); +#endif + if (!fam0_drive && j == 2) break; } if (j==LOOP_COUNT) return (-33); /* give up */ @@ -3946,12 +3992,36 @@ static int sbpcd_drive_status(struct cdrom_device_info *cdi, int slot_nr) { - if (CDSL_CURRENT != slot_nr) { - /* we have no changer support */ - return -EINVAL; - } + int st; + + if (CDSL_CURRENT != slot_nr) { + /* we have no changer support */ + return -EINVAL; + } + + cc_ReadStatus(); + st=ResponseStatus(); + if (st<0) + { + msg(DBG_INF,"sbpcd_drive_status: timeout.\n"); + return (0); + } + msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); + msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); + msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); + msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); + msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); + msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); +#if 0 + if (!(D_S[MINOR(cdi->dev)].status_bits & p_door_closed)) return CDS_TRAY_OPEN; + if (D_S[MINOR(cdi->dev)].status_bits & p_disk_ok) return CDS_DISC_OK; + if (D_S[MINOR(cdi->dev)].status_bits & p_disk_in) return CDS_DRIVE_NOT_READY; - return D_S[d].status_bits & p1_disk_ok ? CDS_DISC_OK : CDS_DRIVE_NOT_READY; + return CDS_NO_DISC; +#else + if (D_S[MINOR(cdi->dev)].status_bits & p_spinning) return CDS_DISC_OK; + return CDS_TRAY_OPEN; +#endif } @@ -4082,13 +4152,13 @@ static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_infp) { ms_infp->addr_format = CDROM_LBA; - ms_infp->addr.lba = D_S[d].lba_multi; - if (D_S[d].f_multisession) + ms_infp->addr.lba = D_S[MINOR(cdi->dev)].lba_multi; + if (D_S[MINOR(cdi->dev)].f_multisession) ms_infp->xa_flag=1; /* valid redirection address */ else ms_infp->xa_flag=0; /* invalid redirection address */ - return 1; + return 0; } /*==========================================================================*/ @@ -4304,8 +4374,30 @@ error_flag=0; p = D_S[d].aud_buf; if (sbpro_type==1) OUT(CDo_sel_i_d,1); - if (do_16bit) insw(CDi_data, p, read_audio.nframes*(CD_FRAMESIZE_RAW>>1)); - else insb(CDi_data, p, read_audio.nframes*CD_FRAMESIZE_RAW); + if (do_16bit) + { + u_short *p2 = (u_short *) p; + + for (; (u_char *) p2 < D_S[d].aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) + { + if ((inb_p(CDi_status)&s_not_data_ready)) continue; + + /* get one sample */ + *p2++ = inw_p(CDi_data); + *p2++ = inw_p(CDi_data); + } + } else { + for (; p < D_S[d].aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) + { + if ((inb_p(CDi_status)&s_not_data_ready)) continue; + + /* get one sample */ + *p++ = inb_p(CDi_data); + *p++ = inb_p(CDi_data); + *p++ = inb_p(CDi_data); + *p++ = inb_p(CDi_data); + } + } if (sbpro_type==1) OUT(CDo_sel_i_d,0); data_retrying = 0; } @@ -4388,28 +4480,6 @@ if(arg > 0xff) RETURN_UP(-EINVAL); read_ahead[MAJOR(cdi->dev)] = arg; RETURN_UP(0); -#if 0 - case CDROMEJECT: - msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n"); - if (fam0_drive) return (0); - if (D_S[d].open_count>1) RETURN_UP(-EBUSY); - i=UnLockDoor(); - D_S[d].open_count=-9; /* to get it locked next time again */ - i=cc_SpinDown(); - msg(DBG_IOX,"ioctl: cc_SpinDown returned %d.\n", i); - msg(DBG_TEA,"ioctl: cc_SpinDown returned %d.\n", i); - if (i<0) RETURN_UP(-EIO); - D_S[d].CD_changed=0xFF; - D_S[d].diskstate_flags=0; - D_S[d].audio_state=0; - RETURN_UP(0); - - case CDROMEJECT_SW: - msg(DBG_IOC,"ioctl: CDROMEJECT_SW entered.\n"); - if (fam0_drive) RETURN_UP(0); - D_S[d].f_eject=arg; - RETURN_UP(0); -#endif default: msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); RETURN_UP(-EINVAL); @@ -5242,54 +5312,13 @@ static int sbpcd_open(struct cdrom_device_info *cdi, int purpose) { int i; - + i = MINOR(cdi->dev); - if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) - { - msg(DBG_INF, "open: bad device: %04X\n", cdi->dev); - return (-ENXIO); /* no such drive */ - } - + MOD_INC_USE_COUNT; down(&ioctl_read_sem); switch_drive(i); - - i=cc_ReadError(); - flags_cmd_out |= f_respo2; - cc_ReadStatus(); /* command: give 1-byte status */ - i=ResponseStatus(); - if (famT_drive&&(i<0)) - { - cc_DriveReset(); - i=ResponseStatus(); -#if 0 - sbp_sleep(HZ); -#endif 0 - i=ResponseStatus(); - } - if (i<0) - { - msg(DBG_INF,"sbpcd_open: ResponseStatus timed out (%d).\n",i); - MOD_DEC_USE_COUNT; - RETURN_UP(-EIO); /* drive doesn't respond */ - } - if (famT_drive) msg(DBG_TEA,"sbpcd_open: ResponseStatus=%02X\n", i); - if (!(famT_drive)) - if (!st_spinning) - { - cc_SpinUp(); - flags_cmd_out |= f_respo2; - cc_ReadStatus(); - i=ResponseStatus(); - } - if (famT_drive) msg(DBG_TEA,"sbpcd_open: status %02X\n", D_S[d].status_bits); - if (!st_door_closed||!st_caddy_in) - { - msg(DBG_INF, "sbpcd_open: no disk in drive.\n"); - D_S[d].open_count=0; - MOD_DEC_USE_COUNT; - RETURN_UP(-ENXIO); - } + /* * try to keep an "open" counter here and lock the door if 0->1. */ @@ -5360,24 +5389,6 @@ /* * */ -#if 0 -static struct file_operations sbpcd_fops = -{ - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - sbpcd_ioctl, /* ioctl */ - NULL, /* mmap */ - sbpcd_open, /* open */ - sbpcd_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - sbpcd_chk_disk_change, /* media_change */ - NULL /* revalidate */ -}; -#endif static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr); static struct cdrom_device_ops sbpcd_dops = { sbpcd_open, /* open */ @@ -5394,7 +5405,7 @@ sbpcd_audio_ioctl, /* audio ioctl */ sbpcd_dev_ioctl, /* device-specific ioctl */ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION | - CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */ + CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO | CDC_IOCTLS, /* capability */ 1, /* number of minor devices */ }; @@ -5556,7 +5567,7 @@ int i=0, j=0; int addr[2]={1, CDROM_PORT}; int port_index; - + sti(); msg(DBG_INF,"sbpcd.c %s\n", VERSION); @@ -5630,14 +5641,6 @@ check_datarate(); msg(DBG_INI,"check_datarate done.\n"); -#if 0 - if (!famL_drive) - { - OUT(CDo_reset,0); - sbp_sleep(HZ); - } -#endif 0 - for (j=0;j=NR_SBPCD) || (D_S[i].drv_id==-1) ) - { - msg(DBG_INF, "media_check: invalid device %04X.\n", full_dev); - return (-1); - } if (D_S[i].CD_changed==0xFF) { diff -u --recursive --new-file v2.1.77/linux/drivers/cdrom/sbpcd.h linux/drivers/cdrom/sbpcd.h --- v2.1.77/linux/drivers/cdrom/sbpcd.h Tue Dec 2 16:45:18 1997 +++ linux/drivers/cdrom/sbpcd.h Mon Jan 5 00:06:26 1998 @@ -119,14 +119,14 @@ #define JUKEBOX 0 #else #define JUKEBOX 1 -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ /* tray control: eject tray after last use */ #if DISTRIBUTION #define EJECT 0 #else #define EJECT 1 -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ /* max. number of audio frames to read with one */ /* request (allocates n* 2352 bytes kernel memory!) */ @@ -570,7 +570,7 @@ resume (pr=80) audio playing Mode Select: - 84 00 nn-nn ??-?? 00 (0) nn-nn: 2048 or 2340 + 84 00 nn-nn ??.?? 00 (0) nn-nn: 2048 or 2340 possibly defines transfer size set_vol: 84 83 00 00 sw le 00. (0) sw(itch): lrxxxxxx (off=1) @@ -604,12 +604,12 @@ seek: 01 02 mm-ss-ff 00 00. (0) Read Data: -read: 02 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2048 bytes, +read: 02 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2048 bytes, starting at block xx-xx-xx fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx Read XA-Data: -read: 03 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2340 bytes, +read: 03 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2340 bytes, starting at block xx-xx-xx fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx @@ -838,7 +838,7 @@ /*==========================================================================*/ /*==========================================================================*/ -#endif _LINUX_SBPCD_H +#endif /* _LINUX_SBPCD_H */ /*==========================================================================*/ /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --recursive --new-file v2.1.77/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.77/linux/drivers/char/bttv.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/char/bttv.c Sun Jan 4 10:40:15 1998 @@ -1712,6 +1712,12 @@ memcpy(&btv->video_dev,&bttv_template,sizeof(bttv_template)); idcard(btv); + + btv->picture.brightness=0x90<<8; + btv->picture.contrast = 0x70 << 8; + btv->picture.colour = 0x70<<8; + btv->picture.hue = 0x8000; + if(video_register_device(&btv->video_dev)<0) return -1; return 0; diff -u --recursive --new-file v2.1.77/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.1.77/linux/drivers/char/bw-qcam.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/char/bw-qcam.c Sun Jan 4 10:41:52 1998 @@ -1,8 +1,6 @@ /* * QuickCam Driver For Video4Linux. * - * This version only works as a module. - * * Video4Linux conversion work by Alan Cox. */ @@ -297,7 +295,7 @@ /* Be liberal in what you accept... */ - if (count > 30 && count < 200) + if (count > 20 && count < 250) return 1; /* found */ else return 0; /* not found */ @@ -744,6 +742,7 @@ qcam->bpp = p.depth; qc_setscanmode(qcam); + qc_set(qcam); return 0; } case VIDIOCSWIN: @@ -842,6 +841,8 @@ }; +#ifdef MODULE + int io=0x378; MODULE_PARM(io,"i"); @@ -859,6 +860,7 @@ if(qc_detect(qcam)==0) { kfree(qcam); + printk(KERN_ERR "bw_qcam: No quickcam detected at 0x%03X\n", io); return -ENODEV; } qc_calibrate(qcam); @@ -875,3 +877,35 @@ video_unregister_device(&qcam->vdev); kfree(qcam); } + +#else + +void init_bw_qcams(void) +{ + int io_ports[3]={0x278,0x378, 0x3BC}; + struct qcam_device *qcam; + int i; + + for(i=0;i<3;i++) + { + qcam=qcam_init(io_ports[i]); + if(qcam==NULL) + continue; + + qc_reset(qcam); + + if(qc_detect(qcam)==0) + { + kfree(qcam); + continue; + } + qc_calibrate(qcam); + + printk(KERN_INFO "Connectix Quickcam at 0x%03X\n", qcam->port); + + if(video_register_device(&qcam->vdev)==-1) + return -ENODEV; + } +} + +#endif diff -u --recursive --new-file v2.1.77/linux/drivers/char/ftape/compressor/Makefile linux/drivers/char/ftape/compressor/Makefile --- v2.1.77/linux/drivers/char/ftape/compressor/Makefile Wed Nov 26 16:24:01 1997 +++ linux/drivers/char/ftape/compressor/Makefile Mon Jan 5 01:41:01 1998 @@ -38,11 +38,6 @@ M_OBJS = $(O_TARGET) -include $(TOPDIR)/Rules.make - -# -# sorry, a special rule. -# -lzrw3.o: lzrw3.c - $(CC) $(CFLAGS) -O6 -funroll-all-loops -c $< +CFLAGS_lzrw3.o := -O6 -funroll-all-loops +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.77/linux/drivers/char/pms.c linux/drivers/char/pms.c --- v2.1.77/linux/drivers/char/pms.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/char/pms.c Sun Jan 4 10:40:15 1998 @@ -612,7 +612,7 @@ int dw = 2*dev->width; char *src = (char *)bus_to_virt((void *)mem_base); - char tmp[dw+16]; /* using a temp buffer is faster than direct */ + char tmp[dw+32]; /* using a temp buffer is faster than direct */ int cnt = 0; int len=0; unsigned char r8 = 0x5; /* value for reg8 */ @@ -626,7 +626,7 @@ for (y = 0; y < dev->height; y++ ) { *src = 0; /* synchronisiert neue Zeile */ - memcpy(tmp, src, dw+16); /* discard 8 word */ + memcpy(tmp, src, dw+32); /* discard 16 word */ cnt -= dev->height; while (cnt <= 0) { @@ -637,7 +637,7 @@ if(dt+len>count) dt=count-len; cnt += dev->height; - copy_to_user(buf, tmp+16, dt); + copy_to_user(buf, tmp+32, dt); buf += dt; len += dt; } @@ -814,10 +814,10 @@ * Now load the card. */ - pms_brightness(p.brightness); - pms_hue(p.hue); - pms_colour(p.colour); - pms_contrast(p.contrast); + pms_brightness(p.brightness>>8); + pms_hue(p.hue>>8); + pms_colour(p.colour>>8); + pms_contrast(p.contrast>>8); return 0; } case VIDIOCSWIN: diff -u --recursive --new-file v2.1.77/linux/drivers/char/rocket.c linux/drivers/char/rocket.c --- v2.1.77/linux/drivers/char/rocket.c Tue Dec 2 09:49:39 1997 +++ linux/drivers/char/rocket.c Sun Jan 4 10:55:08 1998 @@ -637,7 +637,10 @@ { unsigned cflag; unsigned long flags; - int i, bits, baud; + int bits, baud; +#if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */ + int i; +#endif CHANNEL_t *cp; if (!info->tty || !info->tty->termios) diff -u --recursive --new-file v2.1.77/linux/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h --- v2.1.77/linux/drivers/isdn/hisax/isdnl1.h Thu May 29 21:53:06 1997 +++ linux/drivers/isdn/hisax/isdnl1.h Sun Jan 4 10:55:08 1998 @@ -44,7 +44,7 @@ extern void hscx_sched_event(struct HscxState *hsp, int event); extern void isac_sched_event(struct IsdnCardState *sp, int event); extern void isac_new_ph(struct IsdnCardState *sp); -extern get_irq(int cardnr, void *routine); +extern int get_irq(int cardnr, void *routine); #ifdef L2FRAME_DEBUG extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir); diff -u --recursive --new-file v2.1.77/linux/drivers/isdn/sc/interrupt.c linux/drivers/isdn/sc/interrupt.c --- v2.1.77/linux/drivers/isdn/sc/interrupt.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/sc/interrupt.c Sun Jan 4 10:55:08 1998 @@ -32,7 +32,7 @@ #include "message.h" #include "card.h" -extern indicate_status(int, int, ulong, char *); +extern int indicate_status(int, int, ulong, char *); extern void check_phystat(unsigned long); extern void dump_messages(int); extern int receivemessage(int, RspMessage *); diff -u --recursive --new-file v2.1.77/linux/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c --- v2.1.77/linux/drivers/isdn/sc/message.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/sc/message.c Sun Jan 4 10:55:08 1998 @@ -33,6 +33,7 @@ #include "hardware.h" #include "message.h" #include "card.h" +#include extern board *adapter[]; extern unsigned int cinst; @@ -202,7 +203,7 @@ * wait for an empty slot in the queue */ while (!(inb(adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL)) - SLOW_DOWN_IO; + __SLOW_DOWN_IO; /* * Disable interrupts and map in shared memory diff -u --recursive --new-file v2.1.77/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v2.1.77/linux/drivers/net/3c503.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/3c503.c Sun Jan 4 10:55:08 1998 @@ -76,7 +76,7 @@ static void el2_reset_8390(struct device *dev); static void el2_init_card(struct device *dev); static void el2_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, int start_page); static void el2_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void el2_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, @@ -432,7 +432,7 @@ */ static void el2_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page) + const unsigned char *buf, int start_page) { unsigned short int *wrd; int boguscount; /* timeout counter */ diff -u --recursive --new-file v2.1.77/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.77/linux/drivers/net/3c59x.c Fri Dec 19 15:52:58 1997 +++ linux/drivers/net/3c59x.c Sun Jan 4 10:55:08 1998 @@ -20,9 +20,9 @@ /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1512 effectively disables this feature. */ -static const rx_copybreak = 200; +static const int rx_copybreak = 200; /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ -static const mtu = 1500; +static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; diff -u --recursive --new-file v2.1.77/linux/drivers/net/CONFIG linux/drivers/net/CONFIG --- v2.1.77/linux/drivers/net/CONFIG Tue Dec 23 16:30:59 1997 +++ linux/drivers/net/CONFIG Mon Jan 5 01:41:01 1998 @@ -74,17 +74,6 @@ # The 8390 drivers share the EI_DEBUG setting. # General options for Space.c -OPTS = # -DETH0_ADDR=0x300 -DETH0_IRQ=11 - -WD_OPTS = #-DWD_SHMEM=0xDD000 -EL2_OPTS = #-DEL2_AUI -NE_OPTS = -HP_OPTS = -PLIP_OPTS = -DEPCA_OPTS = -EWRK3_OPTS = -DE4X5_OPTS = -DEFXX_OPTS = -ELP_OPTS = -TULIP_OPTS = -CS89x0_OPTS = +CONFIG_Space.o = # -DETH0_ADDR=0x300 -DETH0_IRQ=11 +CONFIG_3c503.o = # -DEL2_AUI +CONFIG_wd.o = # -DWD_SHMEM=0xDD000 diff -u --recursive --new-file v2.1.77/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.77/linux/drivers/net/Config.in Fri Jan 2 14:37:02 1998 +++ linux/drivers/net/Config.in Sun Jan 4 10:40:16 1998 @@ -15,7 +15,7 @@ tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_NETLINK_DEV" != "n" ]; then + if [ "$CONFIG_NETLINK_DEV" = "y" -o "$CONFIG_NETLINK_DEV" = "m" ]; then dep_tristate 'Ethertap network tap' CONFIG_ETHERTAP $CONFIG_NETLINK_DEV fi fi diff -u --recursive --new-file v2.1.77/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.77/linux/drivers/net/Makefile Tue Dec 23 16:30:59 1997 +++ linux/drivers/net/Makefile Mon Jan 5 01:41:01 1998 @@ -735,80 +735,5 @@ clean: rm -f core *.o *.a *.s -wd.o: wd.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $< - -3c503.o: 3c503.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $< - -3c505.o: 3c505.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(ELP_OPTS) -c $< - -de4x5.o: de4x5.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(DE4X5_OPTS) -c $< - -ewrk3.o: ewrk3.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $< - -depca.o: depca.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $< - -Space.o: Space.c ../../include/linux/autoconf.h CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(OPTS) -c $< - -net_init.o: ../../include/linux/autoconf.h - -ne.o: ne.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c $< - -hp.o: hp.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $< - -plip.o: plip.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $< - -slip.o: slip.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< - -strip.o: strip.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< - -dummy.o: dummy.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< - -de600.o: de600.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(DE600_OPTS) -c $< - -de620.o: de620.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(DE620_OPTS) -c $< - -lance.o: lance.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(LANCE_OPTS) -c $< - -8390.o: 8390.c 8390.h CONFIG - -sdla.o: sdla.c CONFIG - -dlci.o: dlci.c CONFIG - -sdladrv.o: sdladrv.c CONFIG - wanpipe.o: $(WANPIPE_OBJS) ld -r -o $@ $(WANPIPE_OBJS) - -sdlamain.o: sdlamain.c CONFIG - -sdla_x25.o: sdla_x25.c CONFIG - -sdla_fr.o: sdla_fr.c CONFIG - -sdla_ppp.o: sdla_ppp.c CONFIG - -dgrs.o: dgrs.c dgrs.h CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< - -ltpc.o: ltpc.c ltpc.h CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< - -tulip.o: tulip.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(TULIP_OPTS) -c $< diff -u --recursive --new-file v2.1.77/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.1.77/linux/drivers/net/dgrs.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/net/dgrs.c Sun Jan 4 10:55:08 1998 @@ -406,7 +406,7 @@ */ udelay(1); - csr = (volatile) priv->vplxdma[PLX_DMA_CSR/4]; + csr = (volatile unsigned long) priv->vplxdma[PLX_DMA_CSR/4]; if (csr & PLX_DMA_CSR_0_DONE) break; @@ -871,7 +871,7 @@ /* Wait for old command to finish */ for (i = 0; i < 1000; ++i) { - if ( (volatile) privN->bcomm->bc_filter_cmd <= 0 ) + if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 ) break; udelay(1); } diff -u --recursive --new-file v2.1.77/linux/drivers/net/e2100.c linux/drivers/net/e2100.c --- v2.1.77/linux/drivers/net/e2100.c Wed Dec 10 11:12:43 1997 +++ linux/drivers/net/e2100.c Sun Jan 4 10:55:08 1998 @@ -103,7 +103,7 @@ static void e21_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void e21_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, int start_page); static void e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); diff -u --recursive --new-file v2.1.77/linux/drivers/net/es3210.c linux/drivers/net/es3210.c --- v2.1.77/linux/drivers/net/es3210.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/es3210.c Sun Jan 4 10:55:08 1998 @@ -71,7 +71,7 @@ static void es_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void es_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); -static void es_block_output(struct device *dev, int count, const unsigned char *buf, const start_page); +static void es_block_output(struct device *dev, int count, const unsigned char *buf, int start_page); #define ES_START_PG 0x00 /* First page of TX buffer */ #define ES_STOP_PG 0x40 /* Last page +1 of RX ring */ diff -u --recursive --new-file v2.1.77/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.1.77/linux/drivers/net/eth16i.c Fri Dec 19 15:52:58 1997 +++ linux/drivers/net/eth16i.c Sun Jan 4 10:55:08 1998 @@ -97,6 +97,7 @@ #include #include #include +#include /* Few macros */ #define BIT(a) ( (1 << (a)) ) @@ -724,7 +725,7 @@ creg[0] &= 0x0F; /* Mask collision cnr */ creg[2] &= 0x7F; /* Mask DCLEN bit */ -#ifdef 0 +#if 0 /* This was removed because the card was sometimes left to state from which it couldn't be find anymore. If there is need diff -u --recursive --new-file v2.1.77/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in --- v2.1.77/linux/drivers/net/hamradio/Config.in Fri Dec 19 15:52:59 1997 +++ linux/drivers/net/hamradio/Config.in Sun Jan 4 10:40:16 1998 @@ -26,7 +26,7 @@ # tristate 'Serial port 6PACK driver' CONFIG_6PACK tristate 'BPQ Ethernet driver' CONFIG_BPQETHER - tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25 + dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25 tristate 'Z8530 SCC driver' CONFIG_SCC if [ "$CONFIG_SCC" != "n" ]; then bool ' additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY diff -u --recursive --new-file v2.1.77/linux/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile --- v2.1.77/linux/drivers/net/hamradio/Makefile Thu Dec 4 14:53:55 1997 +++ linux/drivers/net/hamradio/Makefile Sun Jan 4 10:40:16 1998 @@ -21,6 +21,14 @@ CONFIG_HDLCDRV_BUILTIN := CONFIG_HDLCDRV_MODULE := +ifeq ($(CONFIG_DMASCC),y) +L_OBJS += dmascc.o +else + ifeq ($(CONFIG_DMASCC),m) + M_OBJS += dmascc.o + endif +endif + ifeq ($(CONFIG_SCC),y) L_OBJS += scc.o else diff -u --recursive --new-file v2.1.77/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c --- v2.1.77/linux/drivers/net/hamradio/dmascc.c Fri Dec 19 15:52:59 1997 +++ linux/drivers/net/hamradio/dmascc.c Sun Jan 4 10:40:16 1998 @@ -1,5 +1,5 @@ /* - * $Id: dmascc.c,v 1.2 1997/12/02 16:49:49 oe1kib Exp $ + * $Id: dmascc.c,v 1.2.1.3 1997/12/19 13:40:15 oe1kib Exp $ * * Driver for high-speed SCC boards (those with DMA support) * Copyright (C) 1997 Klaus Kudielka @@ -21,11 +21,11 @@ #include +#include #include #include #include #include -#include #include #include #include @@ -40,12 +40,56 @@ #include #include #include -#include #include #include #include "z8530.h" +/* Linux 2.0 compatibility */ + +#if LINUX_VERSION_CODE < 0x20100 + + +#define __init +#define __initdata +#define __initfunc(x) x + +#define MODULE_AUTHOR(x) +#define MODULE_DESCRIPTION(x) +#define MODULE_PARM(x,y) + +#define copy_to_user(x,y,z) memcpy_tofs(x,y,z) +#define copy_from_user(x,y,z) memcpy_fromfs(x,y,z) +#define test_and_set_bit(x,y) set_bit(x,y) +#define register_netdevice(x) register_netdev(x) +#define unregister_netdevice(x) unregister_netdev(x) + +static int dmascc_dev_init(struct device *dev) +{ + return 0; +} + +static void dev_init_buffers(struct device *dev) +{ + int i; + + for (i = 0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); +} + + +#else + + +#include +#include + +#define dmascc_dev_init NULL + + +#endif + + /* Number of buffers per channel */ #define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (2 recommended) */ @@ -89,7 +133,7 @@ #define SCCA_CMD 0x02 #define SCCA_DATA 0x03 -/* 8254 registers relative to card base */ +/* 8253/8254 registers relative to card base */ #define TMR_CNT0 0x00 #define TMR_CNT1 0x01 #define TMR_CNT2 0x02 @@ -265,7 +309,7 @@ /* Unregister devices */ for (i = 0; i < 2; i++) { if (info->dev[i].name) - unregister_netdev(&info->dev[i]); + unregister_netdevice(&info->dev[i]); } /* Reset board */ @@ -301,14 +345,19 @@ __initfunc(int dmascc_init(void)) { - int h, i, j, n, base[MAX_NUM_DEVS], tcmd, t0, t1, status; - unsigned long time, start[MAX_NUM_DEVS], stop[MAX_NUM_DEVS]; + int h, i, j, n; + int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS], + t1[MAX_NUM_DEVS]; + unsigned t_val; + unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS], + counting[MAX_NUM_DEVS]; /* Initialize random number generator */ rand = jiffies; - /* Cards found = 0 */ n = 0; + /* Warning message */ + if (!io[0]) printk("dmascc: autoprobing (dangerous)\n"); /* Run autodetection for each card type */ for (h = 0; h < NUM_TYPES; h++) { @@ -320,63 +369,66 @@ j = (io[i] - hw[h].io_region) / hw[h].io_delta; if (j >= 0 && j < hw[h].num_devs && - hw[h].io_region + j * hw[h].io_delta == io[i]) + hw[h].io_region + j * hw[h].io_delta == io[i]) { base[j] = io[i]; + } } } else { /* Default I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) + for (i = 0; i < hw[h].num_devs; i++) { base[i] = hw[h].io_region + i * hw[h].io_delta; + } } /* Check valid I/O address regions */ for (i = 0; i < hw[h].num_devs; i++) - if (base[i] && check_region(base[i], hw[h].io_size)) - base[i] = 0; + if (base[i]) + if (check_region(base[i], hw[h].io_size)) + base[i] = 0; + else { + tcmd[i] = base[i] + hw[h].tmr_offset + TMR_CTRL; + t0[i] = base[i] + hw[h].tmr_offset + TMR_CNT0; + t1[i] = base[i] + hw[h].tmr_offset + TMR_CNT1; + } /* Start timers */ for (i = 0; i < hw[h].num_devs; i++) if (base[i]) { - tcmd = base[i] + hw[h].tmr_offset + TMR_CTRL; - t0 = base[i] + hw[h].tmr_offset + TMR_CNT0; - t1 = base[i] + hw[h].tmr_offset + TMR_CNT1; /* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */ - outb_p(0x36, tcmd); - outb_p((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0); - outb_p((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0); + outb_p(0x36, tcmd[i]); + outb_p((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0[i]); + outb_p((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0[i]); /* Timer 1: LSB+MSB, Mode 0, HZ/10 */ - outb_p(0x70, tcmd); - outb_p((TMR_0_HZ/HZ*10) & 0xFF, t1); - outb_p((TMR_0_HZ/HZ*10) >> 8, t1); + outb_p(0x70, tcmd[i]); + outb_p((TMR_0_HZ/HZ*10) & 0xFF, t1[i]); + outb_p((TMR_0_HZ/HZ*10) >> 8, t1[i]); + start[i] = jiffies; + delay[i] = 0; + counting[i] = 1; /* Timer 2: LSB+MSB, Mode 0 */ - outb_p(0xb0, tcmd); + outb_p(0xb0, tcmd[i]); } - - /* Initialize start values in case we miss the null count bit */ time = jiffies; - for (i = 0; i < hw[h].num_devs; i++) start[i] = time; + /* Wait until counter registers are loaded */ + udelay(2000000/TMR_0_HZ); /* Timing loop */ - while (jiffies - time < 12) { + while (jiffies - time < 13) { for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - /* Read back Timer 1: Status */ - outb_p(0xE4, base[i] + hw[h].tmr_offset + TMR_CTRL); - status = inb_p(base[i] + hw[h].tmr_offset + TMR_CNT1); - if ((status & 0x3F) != 0x30) base[i] = 0; - if (status & 0x40) start[i] = jiffies; - if (~status & 0x80) stop[i] = jiffies; + if (base[i] && counting[i]) { + /* Read back Timer 1: latch; read LSB; read MSB */ + outb_p(0x40, tcmd[i]); + t_val = inb_p(t1[i]) + (inb_p(t1[i]) << 8); + /* Also check whether counter did wrap */ + if (t_val == 0 || t_val > TMR_0_HZ/HZ*10) counting[i] = 0; + delay[i] = jiffies - start[i]; } } /* Evaluate measurements */ for (i = 0; i < hw[h].num_devs; i++) if (base[i]) { - time = stop[i] - start[i]; - if (time < 9 || time > 11) - /* The time expired doesn't match */ - base[i] = 0; - else { + if (delay[i] >= 9 && delay[i] <= 11) { /* Ok, we have found an adapter */ if (setup_adapter(base[i], h, n) == 0) n++; @@ -523,6 +575,7 @@ dev->hard_header = ax25_encapsulate; dev->rebuild_header = ax25_rebuild_header; dev->set_mac_address = scc_set_mac_address; + dev->init = dmascc_dev_init; dev->type = ARPHRD_AX25; dev->hard_header_len = 73; dev->mtu = 1500; @@ -530,9 +583,8 @@ dev->tx_queue_len = 64; memcpy(dev->broadcast, ax25_broadcast, 7); memcpy(dev->dev_addr, ax25_test, 7); - dev->flags = 0; dev_init_buffers(dev); - if (register_netdev(dev)) { + if (register_netdevice(dev)) { printk("dmascc: could not register %s\n", dev->name); dev->name = NULL; } diff -u --recursive --new-file v2.1.77/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c --- v2.1.77/linux/drivers/net/hp-plus.c Mon Dec 1 12:04:13 1997 +++ linux/drivers/net/hp-plus.c Sun Jan 4 10:55:08 1998 @@ -103,13 +103,13 @@ static void hpp_mem_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void hpp_mem_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, int start_page); static void hpp_mem_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void hpp_io_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void hpp_io_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, int start_page); static void hpp_io_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -385,7 +385,7 @@ It's always safe to round up, so we do. */ static void hpp_io_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page) + const unsigned char *buf, int start_page) { int ioaddr = dev->base_addr - NIC_OFFSET; outw(start_page << 8, ioaddr + HPP_OUT_ADDR); @@ -395,7 +395,7 @@ static void hpp_mem_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page) + const unsigned char *buf, int start_page) { int ioaddr = dev->base_addr - NIC_OFFSET; int option_reg = inw(ioaddr + HPP_OPTION); diff -u --recursive --new-file v2.1.77/linux/drivers/net/hp.c linux/drivers/net/hp.c --- v2.1.77/linux/drivers/net/hp.c Mon Dec 1 12:04:13 1997 +++ linux/drivers/net/hp.c Sun Jan 4 10:55:08 1998 @@ -66,7 +66,7 @@ static void hp_block_input(struct device *dev, int count, struct sk_buff *skb , int ring_offset); static void hp_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, int start_page); static void hp_init_card(struct device *dev); @@ -309,7 +309,7 @@ static void hp_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page) + const unsigned char *buf, int start_page) { int nic_base = dev->base_addr; int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE); diff -u --recursive --new-file v2.1.77/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.1.77/linux/drivers/net/plip.c Mon Dec 1 12:04:13 1997 +++ linux/drivers/net/plip.c Sun Jan 4 10:24:27 1998 @@ -12,11 +12,11 @@ * Modularization and ifreq/ifmap support by Alan Cox. * Rewritten by Niibe Yutaka. * parport-sharing awareness code by Philip Blundell. + * SMP locking by Niibe Yutaka. * * Fixes: * Niibe Yutaka - * - Module initialization. You can specify I/O addr and IRQ: - * # insmod plip.o io=0x3bc irq=7 + * - Module initialization. * - MTU fix. * - Make sure other end is OK, before sending a packet. * - Fix immediate timer problem. @@ -45,7 +45,7 @@ * To use with DOS box, please do (Turn on ARP switch): * # ifconfig plip[0-2] arp */ -static const char *version = "NET3 PLIP version 2.2-parport gniibe@mri.co.jp\n"; +static const char *version = "NET3 PLIP version 2.3-parport gniibe@mri.co.jp\n"; /* Sources: @@ -108,6 +108,7 @@ #include #include #include +#include #include @@ -214,6 +215,7 @@ int port_owner; int should_relinquish; int (*orig_rebuild_header)(struct sk_buff *skb); + spinlock_t lock; }; /* Entry point of PLIP driver. @@ -238,7 +240,7 @@ printk(KERN_INFO "plip: %s has no IRQ.\n", pb->name); return -ENODEV; } - + pardev = parport_register_device(pb, dev->name, plip_preempt, plip_wakeup, plip_interrupt, PARPORT_DEV_LURK, dev); @@ -291,6 +293,7 @@ nl->deferred.sync = 0; nl->deferred.routine = (void *)(void *)plip_kick_bh; nl->deferred.data = dev; + spin_lock_init(&nl->lock); return 0; } @@ -367,7 +370,7 @@ { unsigned char c0; - cli(); + spin_lock_irq(&nl->lock); if (nl->connection == PLIP_CN_SEND) { if (error != ERROR) { /* Timeout */ @@ -375,7 +378,7 @@ if ((snd->state == PLIP_PK_TRIGGER && nl->timeout_count <= 10) || nl->timeout_count <= 3) { - sti(); + spin_unlock_irq(&nl->lock); /* Try again later */ return TIMEOUT; } @@ -388,12 +391,12 @@ } else if (nl->connection == PLIP_CN_RECEIVE) { if (rcv->state == PLIP_PK_TRIGGER) { /* Transmission was interrupted. */ - sti(); + spin_unlock_irq(&nl->lock); return OK; } if (error != ERROR) { /* Timeout */ if (++nl->timeout_count <= 3) { - sti(); + spin_unlock_irq(&nl->lock); /* Try again later */ return TIMEOUT; } @@ -413,12 +416,13 @@ dev_kfree_skb(snd->skb, FREE_WRITE); snd->skb = NULL; } + spin_unlock_irq(&nl->lock); disable_irq(dev->irq); + synchronize_irq(); outb(PAR_INTR_OFF, PAR_CONTROL(dev)); dev->tbusy = 1; nl->connection = PLIP_CN_ERROR; outb(0x00, PAR_DATA(dev)); - sti(); return TIMEOUT; } @@ -493,6 +497,7 @@ switch (rcv->state) { case PLIP_PK_TRIGGER: disable_irq(dev->irq); + /* Don't need to synchronize irq, as we can safely ignore it */ outb(PAR_INTR_OFF, PAR_CONTROL(dev)); dev->interrupt = 0; outb(0x01, PAR_DATA(dev)); /* send ACK */ @@ -577,10 +582,10 @@ /* Close the connection. */ outb (0x00, PAR_DATA(dev)); - cli(); + spin_lock_irq(&nl->lock); if (snd->state != PLIP_PK_DONE) { nl->connection = PLIP_CN_SEND; - sti(); + spin_unlock_irq(&nl->lock); queue_task(&nl->immediate, &tq_immediate); mark_bh(IMMEDIATE_BH); outb(PAR_INTR_ON, PAR_CONTROL(dev)); @@ -588,7 +593,7 @@ return OK; } else { nl->connection = PLIP_CN_NONE; - sti(); + spin_unlock_irq(&nl->lock); outb(PAR_INTR_ON, PAR_CONTROL(dev)); enable_irq(dev->irq); return OK; @@ -673,28 +678,34 @@ cx = nl->trigger; while (1) { udelay(PLIP_DELAY_UNIT); - cli(); + spin_lock_irq(&nl->lock); if (nl->connection == PLIP_CN_RECEIVE) { - sti(); - /* interrupted */ + spin_unlock_irq(&nl->lock); + /* Interrupted. */ nl->enet_stats.collisions++; - if (net_debug > 1) - printk("%s: collision.\n", dev->name); return OK; } c0 = inb(PAR_STATUS(dev)); if (c0 & 0x08) { + spin_unlock_irq(&nl->lock); disable_irq(dev->irq); + synchronize_irq(); + if (nl->connection == PLIP_CN_RECEIVE) { + /* Interrupted. + We don't need to enable irq, + as it is soon disabled. */ + nl->enet_stats.collisions++; + return OK; + } outb(PAR_INTR_OFF, PAR_CONTROL(dev)); if (net_debug > 2) printk("%s: send start\n", dev->name); snd->state = PLIP_PK_LENGTH_LSB; snd->nibble = PLIP_NB_BEGIN; nl->timeout_count = 0; - sti(); break; } - sti(); + spin_unlock_irq(&nl->lock); if (--cx == 0) { outb(0x00, data_addr); return TIMEOUT; @@ -755,13 +766,13 @@ plip_connection_close(struct device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) { - cli(); + spin_lock_irq(&nl->lock); if (nl->connection == PLIP_CN_CLOSING) { nl->connection = PLIP_CN_NONE; dev->tbusy = 0; mark_bh(NET_BH); } - sti(); + spin_unlock_irq(&nl->lock); if (nl->should_relinquish) { nl->should_relinquish = nl->port_owner = 0; parport_release(nl->pardev); @@ -805,7 +816,7 @@ unsigned char c0; if (dev == NULL) { - printk ("plip_interrupt: irq %d for unknown device.\n", irq); + printk("plip_interrupt: irq %d for unknown device.\n", irq); return; } @@ -825,7 +836,7 @@ if (net_debug > 3) printk("%s: interrupt.\n", dev->name); - cli(); + spin_lock_irq(&nl->lock); switch (nl->connection) { case PLIP_CN_CLOSING: dev->tbusy = 0; @@ -837,16 +848,18 @@ nl->timeout_count = 0; queue_task(&nl->immediate, &tq_immediate); mark_bh(IMMEDIATE_BH); - sti(); + spin_unlock_irq(&nl->lock); break; case PLIP_CN_RECEIVE: - sti(); - printk("%s: receive interrupt when receiving packet\n", dev->name); + /* May occur because there is race condition + around test and set of dev->interrupt. + Ignore this interrupt. */ + spin_unlock_irq(&nl->lock); break; case PLIP_CN_ERROR: - sti(); + spin_unlock_irq(&nl->lock); printk("%s: receive interrupt in error state\n", dev->name); break; } @@ -898,7 +911,7 @@ if (net_debug > 2) printk("%s: send request\n", dev->name); - cli(); + spin_lock_irq(&nl->lock); dev->trans_start = jiffies; snd->skb = skb; snd->length.h = skb->len; @@ -909,7 +922,7 @@ } queue_task(&nl->immediate, &tq_immediate); mark_bh(IMMEDIATE_BH); - sti(); + spin_unlock_irq(&nl->lock); return 0; } @@ -946,24 +959,25 @@ nl->connection = PLIP_CN_NONE; nl->is_deferred = 0; - /* Fill in the MAC-level header. */ + /* Fill in the MAC-level header. + (ab)Use "dev->broadcast" to store point-to-point MAC address. + PLIP doesn't have a real mac address, but we need to create one + to be DOS compatible. */ memset(dev->dev_addr, 0xfc, ETH_ALEN); + memset(dev->broadcast, 0xfc, ETH_ALEN); - /* Now PLIP doesnt have a real mac addr which is a pain.. - we need to create one, and to be DOS compatible its a good - idea to use the same rules. Layering purists please look away */ - - if((in_dev=dev->ip_ptr)!=NULL) - { + if ((in_dev=dev->ip_ptr) != NULL) { /* - * Any address wil do - we take the first + * Any address will do - we take the first */ struct in_ifaddr *ifa=in_dev->ifa_list; - if(ifa!=NULL) - memcpy(dev->dev_addr+2,&ifa->ifa_local,4); + if (ifa != NULL) { + memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); + memcpy(dev->broadcast+2, &ifa->ifa_address, 4); + } } - + dev->interrupt = 0; dev->start = 1; dev->tbusy = 0; @@ -982,8 +996,9 @@ dev->tbusy = 1; dev->start = 0; - cli(); - sti(); + disable_irq(dev->irq); + synchronize_irq(); + #ifdef NOTDEF outb(0x00, PAR_DATA(dev)); #endif @@ -1070,15 +1085,21 @@ static int plip_config(struct device *dev, struct ifmap *map) { + struct net_local *nl = (struct net_local *) dev->priv; + struct pardevice *pardev = nl->pardev; + if (dev->flags & IFF_UP) return -EBUSY; - if (map->base_addr != (unsigned long)-1 - && map->base_addr != dev->base_addr) - printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name); + printk(KERN_WARNING "plip: Warning, changing irq with ifconfig will be obsoleted.\n"); + printk("plip: Next time, please set with /proc/parport/*/irq instead.\n"); - if (map->irq != (unsigned char)-1) - dev->irq = map->irq; + if (map->irq != (unsigned char)-1) { + pardev->port->irq = dev->irq = map->irq; + /* Dummy request */ + request_irq(dev->irq, plip_interrupt, SA_INTERRUPT, + pardev->name, NULL); + } return 0; } @@ -1233,6 +1254,6 @@ /* * Local variables: - * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c" + * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -c plip.c" * End: */ diff -u --recursive --new-file v2.1.77/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- v2.1.77/linux/drivers/net/smc-ultra.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/smc-ultra.c Sun Jan 4 10:55:08 1998 @@ -75,13 +75,13 @@ static void ultra_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void ultra_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, int start_page); static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void ultra_pio_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void ultra_pio_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, int start_page); static int ultra_close_card(struct device *dev); @@ -385,7 +385,7 @@ } static void ultra_pio_output(struct device *dev, int count, - const unsigned char *buf, const start_page) + const unsigned char *buf, int start_page) { int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ diff -u --recursive --new-file v2.1.77/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.1.77/linux/drivers/net/tlan.c Mon Dec 1 12:04:13 1997 +++ linux/drivers/net/tlan.c Sun Jan 4 10:55:09 1998 @@ -2184,7 +2184,6 @@ { TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; u16 gen_ctl; - int i; u32 io; u16 phy; u16 value; diff -u --recursive --new-file v2.1.77/linux/drivers/net/wd.c linux/drivers/net/wd.c --- v2.1.77/linux/drivers/net/wd.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/wd.c Sun Jan 4 10:55:09 1998 @@ -55,7 +55,7 @@ static void wd_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void wd_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, int start_page); static int wd_close_card(struct device *dev); diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.1.77/linux/drivers/scsi/Makefile Fri Jan 2 14:37:02 1998 +++ linux/drivers/scsi/Makefile Mon Jan 5 01:41:01 1998 @@ -13,8 +13,9 @@ MOD_LIST_NAME := SCSI_MODULES SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c)) -AHA152X = -DDEBUG_AHA152X -DAUTOCONF -GDTH = #-DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS +CFLAGS_aha152x.o = -DDEBUG_AHA152X -DAUTOCONF +CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS +CFLAGS_seagate.o = -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY .SUFFIXES: .SUFFIXES: .c .o .h .a @@ -455,23 +456,13 @@ include $(TOPDIR)/Rules.make -BusLogic.o: BusLogic.c FlashPoint.c +# This gives correct output but uses old-style "excessive compilation". +# This will be fixed soon (about December 1997 or January 1998). +BusLogic.o: BusLogic.c FlashPoint.c ../../include/linux/autoconf.h $(CC) $(CFLAGS) -c BusLogic.c -o BusLogic.O $(CC) $(CFLAGS) -c FlashPoint.c -o FlashPoint.O $(LD) -r -o BusLogic.o BusLogic.O FlashPoint.O rm -f BusLogic.O FlashPoint.O - -aha152x.o: aha152x.c - $(CC) $(CFLAGS) $(AHA152X) -c aha152x.c - -gdth.o: gdth.c gdth.h gdth_proc.c gdth_proc.h - $(CC) $(CFLAGS) $(GDTH) -c gdth.c - -aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h - $(CC) $(CFLAGS) -c -o $@ aic7xxx.c - -seagate.o: seagate.c - $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY -c seagate.c 53c8xx_d.h 53c8xx_u.h : 53c7,8xx.scr script_asm.pl ln -sf 53c7,8xx.scr fake.c diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.1.77/linux/drivers/scsi/aha1542.c Sun Dec 21 22:36:14 1997 +++ linux/drivers/scsi/aha1542.c Sun Jan 4 10:55:09 1998 @@ -133,8 +133,8 @@ #define aha1542_intr_reset(base) outb(IRST, CONTROL(base)) #define WAIT(port, mask, allof, noneof) \ - { register WAITbits; \ - register WAITtimeout = WAITnexttimeout; \ + { register int WAITbits; \ + register int WAITtimeout = WAITnexttimeout; \ while (1) { \ WAITbits = inb(port) & (mask); \ if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ @@ -146,8 +146,8 @@ /* Similar to WAIT, except we use the udelay call to regulate the amount of time we wait. */ #define WAITd(port, mask, allof, noneof, timeout) \ - { register WAITbits; \ - register WAITtimeout = timeout; \ + { register int WAITbits; \ + register int WAITtimeout = timeout; \ while (1) { \ WAITbits = inb(port) & (mask); \ if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.1.77/linux/drivers/scsi/aic7xxx.c Thu Dec 4 14:53:56 1997 +++ linux/drivers/scsi/aic7xxx.c Sun Jan 4 10:55:09 1998 @@ -6953,7 +6953,7 @@ channel = cmd->channel ? 'B': 'A'; tindex = TARGET_INDEX(cmd); -#ifdef 0 /* AIC7XXX_DEBUG_ABORT */ +#if 0 /* AIC7XXX_DEBUG_ABORT */ if (scb != NULL) { printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n", diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/dc390.h linux/drivers/scsi/dc390.h --- v2.1.77/linux/drivers/scsi/dc390.h Sun Dec 21 22:36:14 1997 +++ linux/drivers/scsi/dc390.h Mon Jan 5 01:44:46 1998 @@ -65,7 +65,7 @@ #define DC390_T { \ proc_dir: &proc_scsi_tmscsim, \ - proc_info: tmscsim_proc_info + proc_info: tmscsim_proc_info, \ name: "Tekram DC390(T) V1.10 Dec-05-1996",\ detect: DC390_detect, \ release: DC390_release, \ diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c --- v2.1.77/linux/drivers/scsi/pas16.c Wed Apr 23 19:01:22 1997 +++ linux/drivers/scsi/pas16.c Sun Jan 4 10:55:09 1998 @@ -516,7 +516,7 @@ register unsigned char *d = dst; register unsigned short reg = (unsigned short) (instance->io_port + P_DATA_REG_OFFSET); - register i = len; + register int i = len; int ii = 0; while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) ) @@ -552,7 +552,7 @@ int len) { register unsigned char *s = src; register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET); - register i = len; + register int i = len; int ii = 0; while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) ) diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.77/linux/drivers/scsi/scsi.c Sun Dec 21 22:36:15 1997 +++ linux/drivers/scsi/scsi.c Sun Jan 4 10:55:09 1998 @@ -607,7 +607,7 @@ { SCSI_LOG_SCAN_BUS(4,printk("%p ", scmd)); } - SCSI_LOG_SCAN_BUS(4,printk("\n", scmd)); + SCSI_LOG_SCAN_BUS(4,printk("\n")); } } } diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.1.77/linux/drivers/scsi/scsi.h Sun Dec 21 22:36:15 1997 +++ linux/drivers/scsi/scsi.h Mon Jan 5 01:44:46 1998 @@ -617,8 +617,8 @@ #define SCSI_MLQUEUE_HOST_BUSY 0x1055 #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 -extern scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason); -extern scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device); +extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason); +extern int scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device); #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR) diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c --- v2.1.77/linux/drivers/scsi/sd_ioctl.c Sun Dec 21 22:36:15 1997 +++ linux/drivers/scsi/sd_ioctl.c Sun Jan 4 10:40:16 1998 @@ -104,6 +104,9 @@ case BLKRRPART: /* Re-read partition tables */ return revalidate_scsidisk(dev, 1); + + RO_IOCTLS(dev, arg); + default: return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg); } diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c --- v2.1.77/linux/drivers/scsi/t128.c Wed Apr 23 19:01:22 1997 +++ linux/drivers/scsi/t128.c Sun Jan 4 10:55:09 1998 @@ -328,7 +328,7 @@ int len) { register unsigned char *reg = (unsigned char *) (instance->base + T_DATA_REG_OFFSET), *d = dst; - register i = len; + register int i = len; #if 0 @@ -372,7 +372,7 @@ int len) { register unsigned char *reg = (unsigned char *) (instance->base + T_DATA_REG_OFFSET), *s = src; - register i = len; + register int i = len; #if 0 for (; i; --i) { diff -u --recursive --new-file v2.1.77/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.1.77/linux/drivers/scsi/wd7000.c Mon Mar 17 14:54:30 1997 +++ linux/drivers/scsi/wd7000.c Sun Jan 4 10:55:09 1998 @@ -473,7 +473,7 @@ typedef struct icbUnsMask { /* I'm totally guessing here */ unchar op; volatile unchar mask[14]; /* mask bits */ -#ifdef 0 +#if 0 unchar rsvd[12]; /* reserved */ #endif volatile unchar vue; /* vendor-unique error code */ diff -u --recursive --new-file v2.1.77/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.77/linux/drivers/sound/Config.in Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/Config.in Sun Jan 4 10:40:16 1998 @@ -149,7 +149,8 @@ if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then dep_tristate 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND dep_tristate 'AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND - bool 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 + dep_tristate 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 + if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then hex ' I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 fi @@ -193,6 +194,11 @@ AEDSP16_MPU_IRQ $MPU_IRQ fi fi + fi + + if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then + comment 'SC-6600 Audio Cards have no jumper switches at all' + bool 'SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600 if [ "$CONFIG_SC6600" = "y" ]; then comment 'SC-6600 specific configuration' @@ -201,7 +207,6 @@ CONFIG_SC6600_CDROM 4 hex 'SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0 fi - fi fi diff -u --recursive --new-file v2.1.77/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.77/linux/drivers/sound/Makefile Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/Makefile Sun Jan 4 10:40:16 1998 @@ -45,7 +45,7 @@ else ifeq ($(CONFIG_SOUND),m) M_OBJS += sound.o - MX_OBJS += sound_syms.o + MIX_OBJS += sound_syms.o endif endif @@ -242,7 +242,6 @@ ld -r -o sound.o soundcard.o dev_table.o audio.o dmabuf.o \ sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o \ midi_synth.o midibuf.o sound_firmware.o - rm sound_syms.o gus.o: gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o ld -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o diff -u --recursive --new-file v2.1.77/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.77/linux/drivers/sound/ad1848.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/ad1848.c Mon Jan 5 09:39:52 1998 @@ -532,7 +532,7 @@ int val; if (cmd == SOUND_MIXER_PRIVATE1) { - if (__get_user(val, (int *)arg)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val != 0xffff) { @@ -546,22 +546,22 @@ ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ } val = devc->mixer_output_port; - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); } if (((cmd >> 8) & 0xff) == 'M') { if (_SIOC_DIR(cmd) & _SIOC_WRITE) switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: - if (__get_user(val, (int *)arg)) + if (get_user(val, (int *)arg)) return -EFAULT; val = ad1848_set_recmask(devc, val); - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); default: - if (__get_user(val, (int *)arg)) + if (get_user(val, (int *)arg)) return -EFAULT; val = ad1848_mixer_set(devc, cmd & 0xff, val); - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); } else switch (cmd & 0xff) { @@ -571,28 +571,28 @@ case SOUND_MIXER_RECSRC: val = devc->recmask; - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); case SOUND_MIXER_DEVMASK: val = devc->supported_devices; - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); case SOUND_MIXER_STEREODEVS: val = devc->supported_devices; if (devc->model != MD_C930) val &= ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); case SOUND_MIXER_RECMASK: val = devc->supported_rec_devices; - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); case SOUND_MIXER_CAPS: - return __put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); + return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); default: val = ad1848_mixer_get(devc, cmd & 0xff); - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); } } else return -EINVAL; @@ -2566,7 +2566,6 @@ SOUND_LOCK_END; if(loaded) unload_ms_sound(&hw_config); -/* unregister_symtab(&ad1848_syms); */ } #else @@ -2574,7 +2573,6 @@ void export_ad1848_syms(void) { - register_symtab(&ad1848_syms); } #endif diff -u --recursive --new-file v2.1.77/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.1.77/linux/drivers/sound/dev_table.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/sound/dev_table.c Sun Jan 4 10:40:16 1998 @@ -73,9 +73,7 @@ { extern void sound_preinit_lowlevel_drivers(void); -#ifdef FIXME sound_preinit_lowlevel_drivers(); -#endif } #endif diff -u --recursive --new-file v2.1.77/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.77/linux/drivers/sound/gus_wave.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/gus_wave.c Mon Jan 5 10:09:36 1998 @@ -2834,117 +2834,128 @@ int gus_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - int vol, voice, val; + int vol, val; - if (((cmd >> 8) & 0xff) == 'M') { - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - if (__get_user(gus_recmask, (int *)arg)) - return -EFAULT; - gus_recmask &= MIX_DEVS; - if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) - gus_recmask = SOUND_MASK_MIC; - /* Note! Input volumes are updated during next open for recording */ - return __put_user(gus_recmask, (int *)arg); - - case SOUND_MIXER_MIC: - if (__get_user(vol, (int *)arg)) - return -EFAULT; - vol &= 0xff; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_mic_vol = vol; - set_input_volumes(); - vol |= (vol << 8); - return __put_user(vol, (int *)arg); + if (((cmd >> 8) & 0xff) != 'M') + return -EINVAL; + + if (!access_ok(VERIFY_WRITE, (int *)arg, sizeof(int))) + return -EFAULT; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) { + if (__get_user(val, (int *) arg)) + return -EFAULT; + + switch (cmd & 0xff) { + case SOUND_MIXER_RECSRC: + gus_recmask = val & MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* Note! Input volumes are updated during next open for recording */ + val = gus_recmask; + break; + + case SOUND_MIXER_MIC: + vol = val & 0xff; + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_mic_vol = vol; + set_input_volumes(); + vol |= (vol << 8); + val = vol; + break; - case SOUND_MIXER_LINE: - if (__get_user(vol, (int *)arg)) - return -EFAULT; - vol &= 0xff; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_line_vol = vol; - set_input_volumes(); - vol |= (vol << 8); - return __put_user(vol, (int *)arg); - - case SOUND_MIXER_PCM: - if (__get_user(gus_pcm_volume, (int *)arg)) - return -EFAULT; - gus_pcm_volume &= 0xff; - if (gus_pcm_volume < 0) - gus_pcm_volume = 0; - if (gus_pcm_volume > 100) - gus_pcm_volume = 100; - gus_audio_update_volume(); - gus_pcm_volume |= (gus_pcm_volume << 8); - return __put_user(gus_pcm_volume, (int *)arg); - - case SOUND_MIXER_SYNTH: - if (__get_user(gus_wave_volume, (int *)arg)) - return -EFAULT; - gus_wave_volume &= 0xff; - if (gus_wave_volume < 0) - gus_wave_volume = 0; - if (gus_wave_volume > 100) - gus_wave_volume = 100; - if (active_device == GUS_DEV_WAVE) - for (voice = 0; voice < nr_voices; voice++) - dynamic_volume_change(voice); /* Apply the new vol */ - gus_wave_volume |= (gus_wave_volume << 8); - return __put_user(gus_wave_volume, (int *)arg); - - default: - return -EINVAL; - } else - switch (cmd & 0xff) { - /* - * Return parameters - */ - case SOUND_MIXER_RECSRC: - return __put_user(gus_recmask, (int *)arg); + case SOUND_MIXER_LINE: + vol = val & 0xff; + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_line_vol = vol; + set_input_volumes(); + vol |= (vol << 8); + val = vol; + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = val & 0xff; + if (gus_pcm_volume < 0) + gus_pcm_volume = 0; + if (gus_pcm_volume > 100) + gus_pcm_volume = 100; + gus_audio_update_volume(); + gus_pcm_volume |= (gus_pcm_volume << 8); + val = gus_pcm_volume; + break; + + case SOUND_MIXER_SYNTH: + gus_wave_volume = val & 0xff; + if (gus_wave_volume < 0) + gus_wave_volume = 0; + if (gus_wave_volume > 100) + gus_wave_volume = 100; + if (active_device == GUS_DEV_WAVE) { + int voice; + for (voice = 0; voice < nr_voices; voice++) + dynamic_volume_change(voice); /* Apply the new vol */ + } + gus_wave_volume |= (gus_wave_volume << 8); + val = gus_wave_volume; + break; + + default: + return -EINVAL; + } + + } else { + switch (cmd & 0xff) { + /* + * Return parameters + */ + case SOUND_MIXER_RECSRC: + val = gus_recmask; + break; - case SOUND_MIXER_DEVMASK: - return __put_user(MIX_DEVS, (int *)arg); + case SOUND_MIXER_DEVMASK: + val = MIX_DEVS; + break; + + case SOUND_MIXER_STEREODEVS: + val = 0; + break; + + case SOUND_MIXER_RECMASK: + val = SOUND_MASK_MIC | SOUND_MASK_LINE; + break; + + case SOUND_MIXER_CAPS: + val = 0; + break; + + case SOUND_MIXER_MIC: + val = gus_mic_vol | (gus_mic_vol << 8); + break; + + case SOUND_MIXER_LINE: + val = gus_line_vol | (gus_line_vol << 8); + break; + + case SOUND_MIXER_PCM: + val = gus_pcm_volume | (gus_pcm_volume << 8); + break; + + case SOUND_MIXER_SYNTH: + val = gus_wave_volume | (gus_wave_volume << 8); + break; + + default: + return -EINVAL; + } + } - case SOUND_MIXER_STEREODEVS: - return __put_user(0, (int *)arg); - - case SOUND_MIXER_RECMASK: - val = SOUND_MASK_MIC | SOUND_MASK_LINE; - return __put_user(val, (int *)arg); - - case SOUND_MIXER_CAPS: - return __put_user(0, (int *)arg); - - case SOUND_MIXER_MIC: - val = gus_mic_vol | (gus_mic_vol << 8); - return __put_user(val, (int *)arg); - - case SOUND_MIXER_LINE: - val = gus_line_vol | (gus_line_vol << 8); - return __put_user(val, (int *)arg); - - case SOUND_MIXER_PCM: - val = ; - return __put_user(, (int *)arg); - return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); - break; - - case SOUND_MIXER_SYNTH: - return __put_user(gus_wave_volume | (gus_wave_volume << 8), (int *)arg); - - default: - return -EINVAL; - } - } else - return -EINVAL; + return __put_user(val, (int *)arg); } static struct mixer_operations gus_mixer_operations = diff -u --recursive --new-file v2.1.77/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c --- v2.1.77/linux/drivers/sound/ics2101.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/ics2101.c Mon Jan 5 09:39:52 1998 @@ -118,11 +118,12 @@ static int ics2101_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { + int val; + if (((cmd >> 8) & 0xff) == 'M') { if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - int val; - if (__get_user(val, (int *)arg)) + if (get_user(val, (int *)arg)) return -EFAULT; switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: @@ -151,7 +152,7 @@ default: return -EINVAL; } - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); } else { switch (cmd & 0xff) { /* @@ -199,7 +200,7 @@ default: return -EINVAL; } - return __put_user(val, (int *)arg); + return put_user(val, (int *)arg); } } return -EINVAL; @@ -220,7 +221,6 @@ if ((n = sound_alloc_mixerdev()) != -1) { - n = num_mixers; mixer_devs[n] = &ics2101_mixer_operations; /* diff -u --recursive --new-file v2.1.77/linux/drivers/sound/lowlevel/Makefile linux/drivers/sound/lowlevel/Makefile --- v2.1.77/linux/drivers/sound/lowlevel/Makefile Sat Nov 29 11:25:11 1997 +++ linux/drivers/sound/lowlevel/Makefile Mon Jan 5 01:41:01 1998 @@ -16,15 +16,16 @@ endif ifeq ($(CONFIG_AEDSP16),y) OBJS := $(OBJS) aedsp16.o +else + ifeq ($(CONFIG_AEDSP16),m) + MX_OBJS := $(MX_OBJS) aedsp16.o + endif endif endif ifndef TOPDIR TOPDIR=/usr/src/linux endif - -.c.o: - $(CC) $(CFLAGS) -c $< lowlevel.o: $(OBJS) $(LD) -r -o lowlevel.o $(OBJS) diff -u --recursive --new-file v2.1.77/linux/drivers/sound/lowlevel/README.aedsp16 linux/drivers/sound/lowlevel/README.aedsp16 --- v2.1.77/linux/drivers/sound/lowlevel/README.aedsp16 Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/lowlevel/README.aedsp16 Sun Jan 4 10:40:16 1998 @@ -20,6 +20,37 @@ If you want to change the configuration of the sound board, be sure to check off all the configuration items before re-configure it. +Module parameters +----------------- +To use this driver as a module, you must configure some module parameters, to +set up I/O addresses, IRQ lines and DMA channels. Some parameters are +mandatory while some others are optional. Here a list of parameters you can +use with this module: + +Name Description +==== =========== +MANDATORY +io I/O base address (0x220 or 0x240) +irq irq line (5, 7, 9, 10 or 11) +dma dma channel (0, 1 or 3) + +OPTIONAL +mss_base I/O base address for activate MSS mode (default SBPRO) + (0x530 or 0xE80) +mpu_base I/O base address for activate MPU-401 mode + (0x300, 0x310, 0x320 or 0x330) +mpu_irq MPU-401 irq line (5, 7, 9, 10 or 0) + +The /etc/conf.modules will have a line like this: + +options aedsp16 io=0x220 irq=10 dma=3 mss_base=0x530 + +Of course, you must write the 'options' for all other subsequent modules, +opl3, ad1848, adlib_card, sb + +Then you must load the sound modules stack in this order: +sound -> aedsp16 -> [ ad1848, opl3 ] + Sound cards supported --------------------- This driver supports the SC-6000 and SC-6600 based Gallant's sound card. diff -u --recursive --new-file v2.1.77/linux/drivers/sound/lowlevel/aedsp16.c linux/drivers/sound/lowlevel/aedsp16.c --- v2.1.77/linux/drivers/sound/lowlevel/aedsp16.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/lowlevel/aedsp16.c Sun Jan 4 10:40:16 1998 @@ -1,8 +1,8 @@ /* - sound/aedsp16.c + drivers/sound/lowlevel/aedsp16.c Audio Excel DSP 16 software configuration routines - Copyright (C) 1995 Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it) + Copyright (C) 1995,1996,1997,1998 Riccardo Facchetti (fizban@tin.it) 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 @@ -24,13 +24,24 @@ * headers needed by this source. */ #include -#include "../sound_config.h" #include +#include +#include "../sound_config.h" +#include "../soundmodule.h" + +/* + * Sanity checks + */ -#ifndef AEDSP16_BASE -#undef CONFIG_AEDSP16 +#if !defined(AEDSP16_BASE) +# undef CONFIG_AEDSP16 +#else +# if defined(MODULE) && defined(CONFIG_AEDSP16_MODULE) +# define CONFIG_AEDSP16 1 +# endif #endif + #if defined(CONFIG_AEDSP16) #if defined(CONFIG_AEDSP16_SBPRO) && defined(CONFIG_AEDSP16_MSS) @@ -232,6 +243,11 @@ - Prep for merging with OSS Lite and Linux kernel 2.1.13 - Corrected a bug in request/check/release region calls (thanks to the new kernel exception handling). + v1.1 + - Revamped for integration with new modularized sound drivers: to enhance + the flexibility of modular version, I have removed all the conditional + compilation for SBPRO, MPU and MSS code. Now it is all managed with + the ae_config structure. Known Problems: - Audio Excel DSP 16 III don't work with this driver. @@ -243,7 +259,7 @@ */ -#define VERSION "1.0.0" /* Version of Audio Excel DSP 16 driver */ +#define VERSION "1.1" /* Version of Audio Excel DSP 16 driver */ #undef AEDSP16_DEBUG 1 /* Define this to enable debug code */ #undef AEDSP16_DEBUG_MORE 1 /* Define this to enable more debug */ @@ -439,6 +455,8 @@ int irq; /* irq value for DSP I/O */ int mpu_irq; /* irq for mpu401 interface I/O */ int dma; /* dma value for DSP I/O */ + int mss_base; /* base I/O for Microsoft Sound System */ + int mpu_base; /* base I/O for MPU-401 emulation */ int init; /* Initialization status of the card */ }; @@ -477,6 +495,8 @@ DEF_AEDSP16_IRQ, DEF_AEDSP16_MRQ, DEF_AEDSP16_DMA, + -1, + -1, INIT_NONE }; @@ -619,13 +639,9 @@ /* * Now set up the real kernel configuration. */ - decoded_hcfg.iobase = AEDSP16_BASE; -#if defined(CONFIG_AEDSP16_MSS) - decoded_hcfg.wssbase = MSS_BASE; -#endif -#if defined(CONFIG_AEDSP16_MPU401) - decoded_hcfg.mpubase = MPU_BASE; -#endif + decoded_hcfg.iobase = ae_config.base_io; + decoded_hcfg.wssbase = ae_config.mss_base; + decoded_hcfg.mpubase = ae_config.mpu_base; #if defined(CONFIG_SC6600_JOY) decoded_hcfg.joystick = CONFIG_SC6600_JOY; /* Enable */ @@ -805,8 +821,6 @@ return TRUE; } -#if defined(CONFIG_AEDSP16_MSS) - static int aedsp16_init_mss(int port) { DBG(("aedsp16_init_mss:\n")); @@ -824,15 +838,13 @@ if (aedsp16_cfg_write(port) == FALSE) return FALSE; - outb(soft_cfg_1, MSS_BASE); + outb(soft_cfg_1, ae_config.mss_base); DBG(("success.\n")); return TRUE; } -#endif /* CONFIG_AEDSP16_MSS */ - static int aedsp16_setup_board(int port) { int loop = RETRY; @@ -1082,15 +1094,15 @@ return FALSE; } -#if defined(CONFIG_AEDSP16_MSS) - if (ae_config.init & INIT_MSS) { - if (aedsp16_init_mss(ae_config.base_io) == FALSE) { - printk( - "[AEDSP16] Can not initialize Microsoft Sound System mode.\n"); - return FALSE; + if (ae_config.mss_base != -1) { + if (ae_config.init & INIT_MSS) { + if (aedsp16_init_mss(ae_config.base_io) == FALSE) { + printk("[AEDSP16] Can not initialize" + "Microsoft Sound System mode.\n"); + return FALSE; + } } } -#endif #if !defined(MODULE) || defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG) @@ -1098,27 +1110,26 @@ VERSION, DSPCopyright, DSPVersion); -#if defined(CONFIG_AEDSP16_MPU401) - if (ae_config.init & INIT_MPU401) { - printk("MPU401"); - if ((ae_config.init & INIT_MSS) || - (ae_config.init & INIT_SBPRO)) - printk(" "); + if (ae_config.mpu_base != -1) { + if (ae_config.init & INIT_MPU401) { + printk("MPU401"); + if ((ae_config.init & INIT_MSS) || + (ae_config.init & INIT_SBPRO)) + printk(" "); + } } -#endif -#if defined(CONFIG_AEDSP16_SBPRO) - if (ae_config.init & INIT_SBPRO) { - printk("SBPro"); - if (ae_config.init & INIT_MSS) - printk(" "); + if (ae_config.mss_base == -1) { + if (ae_config.init & INIT_SBPRO) { + printk("SBPro"); + if (ae_config.init & INIT_MSS) + printk(" "); + } } -#endif -#if defined(CONFIG_AEDSP16_MSS) - if (ae_config.init & INIT_MSS) - printk("MSS"); -#endif + if (ae_config.mss_base != -1) + if (ae_config.init & INIT_MSS) + printk("MSS"); printk("]\n"); #endif /* MODULE || AEDSP16_INFO || AEDSP16_DEBUG */ @@ -1128,8 +1139,6 @@ return TRUE; } -#if defined(CONFIG_AEDSP16_SBPRO) - static int init_aedsp16_sb(void) { DBG(("init_aedsp16_sb: ")); @@ -1158,9 +1167,6 @@ DBG(("done.\n")); } -#endif - -#if defined(CONFIG_AEDSP16_MSS) static int init_aedsp16_mss(void) { @@ -1214,9 +1220,6 @@ ae_config.init &= ~INIT_MSS; DBG(("done.\n")); } -#endif - -#if defined(CONFIG_AEDSP16_MPU401) static int init_aedsp16_mpu(void) { @@ -1262,43 +1265,45 @@ DBG(("done.\n")); } -#endif int init_aedsp16(void) { int initialized = FALSE; +#if !defined(MODULE) ae_config.base_io = AEDSP16_BASE; #if defined(CONFIG_AEDSP16_SBPRO) ae_config.irq = AEDSP16_SBC_IRQ; ae_config.dma = AEDSP16_SBC_DMA; #endif #if defined(CONFIG_AEDSP16_MSS) + ae_config.mss_base = MSS_BASE; ae_config.irq = AEDSP16_MSS_IRQ; ae_config.dma = AEDSP16_MSS_DMA; #endif #if defined(CONFIG_AEDSP16_MPU401) + ae_config.mpu_base = MPU_BASE; ae_config.mpu_irq = AEDSP16_MPU_IRQ; #endif - +#endif /* !MODULE */ DBG(("Initializing BASE[0x%x] IRQ[%d] DMA[%d] MIRQ[%d]\n", ae_config.base_io,ae_config.irq,ae_config.dma,ae_config.mpu_irq)); -#if defined(CONFIG_AEDSP16_SBPRO) - if (init_aedsp16_sb() == FALSE) - uninit_aedsp16_sb(); - else - initialized = TRUE; -#endif - -#if defined(CONFIG_AEDSP16_MPU401) - if (init_aedsp16_mpu() == FALSE) - uninit_aedsp16_mpu(); - else - initialized = TRUE; -#endif + if (ae_config.mss_base == -1) { + if (init_aedsp16_sb() == FALSE) { + uninit_aedsp16_sb(); + } else { + initialized = TRUE; + } + } -#if defined(CONFIG_AEDSP16_MSS) + if (ae_config.mpu_base != -1) { + if (init_aedsp16_mpu() == FALSE) { + uninit_aedsp16_mpu(); + } else { + initialized = TRUE; + } + } /* * In the sequence of init routines, the MSS init MUST be the last! @@ -1306,11 +1311,13 @@ * A board reset would disable the MSS mode restoring the default SBPRO * mode. */ - if (init_aedsp16_mss() == FALSE) - uninit_aedsp16_mss(); - else - initialized = TRUE; -#endif + if (ae_config.mss_base != -1) { + if (init_aedsp16_mss() == FALSE) { + uninit_aedsp16_mss(); + } else { + initialized = TRUE; + } + } if (initialized) initialized = aedsp16_init_board(); @@ -1319,16 +1326,62 @@ void uninit_aedsp16(void) { -#if defined(CONFIG_AEDSP16_MSS) - uninit_aedsp16_mss(); -#endif + if (ae_config.mss_base != -1) + uninit_aedsp16_mss(); + else + uninit_aedsp16_sb(); + if (ae_config.mpu_base != -1) + uninit_aedsp16_mpu(); +} -#if defined(CONFIG_AEDSP16_SBPRO) - uninit_aedsp16_sb(); -#endif +#if defined(MODULE) -#if defined(CONFIG_AEDSP16_MPU401) - uninit_aedsp16_mpu(); -#endif +int io = -1; +int irq = -1; +int dma = -1; +int mpu_irq = -1; +int mss_base = -1; +int mpu_base = -1; + + +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(mpu_irq,"i"); +MODULE_PARM(mss_base,"i"); +MODULE_PARM(mpu_base,"i"); + +int init_module(void) { + printk("Audio Excel DSP 16 init driver Copyright (C) Riccardo Facchetti 1995-98\n"); + if (io == -1 || dma == -1 || irq == -1) { + printk(KERN_INFO "aedsp16: I/O, IRQ and DMA are mandatory\n"); + return -EINVAL; + } + + ae_config.base_io = io; + ae_config.irq = irq; + ae_config.dma = dma; + + ae_config.mss_base = mss_base; + ae_config.mpu_base = mpu_base; + ae_config.mpu_irq = mpu_irq; + + if (init_aedsp16() == FALSE) { + printk(KERN_ERR "aedsp16: initialization failed\n"); + /* + * XXX + * What error should we return here ? + */ + return -EINVAL; + } + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) { + uninit_aedsp16(); + SOUND_LOCK_END; } -#endif /* CONFIG_AEDSP16 */ +#endif /* MODULE */ + +#endif /* CONFIG_AEDSP16 */ diff -u --recursive --new-file v2.1.77/linux/drivers/sound/lowlevel/awe_version.h linux/drivers/sound/lowlevel/awe_version.h --- v2.1.77/linux/drivers/sound/lowlevel/awe_version.h Sat Nov 29 11:25:11 1997 +++ linux/drivers/sound/lowlevel/awe_version.h Sun Jan 4 10:40:16 1998 @@ -10,15 +10,4 @@ #define AWE_TINY_VERSION(id) ((id) & 0xff) #endif -/* AWE32 driver version number */ -#ifndef AWE_VERSION_H_DEF -#define AWE_VERSION_H_DEF - -#define AWE_VERSION_NUMBER 0x00040202 -#define AWEDRV_VERSION "0.4.2b" -#define AWE_MAJOR_VERSION(id) (((id) >> 16) & 0xff) -#define AWE_MINOR_VERSION(id) (((id) >> 8) & 0xff) -#define AWE_TINY_VERSION(id) ((id) & 0xff) - -#endif diff -u --recursive --new-file v2.1.77/linux/drivers/sound/lowlevel/init.c linux/drivers/sound/lowlevel/init.c --- v2.1.77/linux/drivers/sound/lowlevel/init.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/lowlevel/init.c Sun Jan 4 10:40:16 1998 @@ -28,7 +28,7 @@ void sound_preinit_lowlevel_drivers(void) { -#ifdef CONFIG_AEDSP16 +#if defined(CONFIG_AEDSP16) && !defined(MODULE) init_aedsp16(); #endif } diff -u --recursive --new-file v2.1.77/linux/drivers/sound/os.h linux/drivers/sound/os.h --- v2.1.77/linux/drivers/sound/os.h Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/os.h Mon Jan 5 10:13:36 1998 @@ -50,6 +50,8 @@ extern void sound_free_dma(int chn); extern void sound_close_dma(int chn); +extern void reprogram_timer(void); + #define RUNTIME_DMA_ALLOC #define USE_AUTOINIT_DMA diff -u --recursive --new-file v2.1.77/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v2.1.77/linux/drivers/sound/pas2_mixer.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/pas2_mixer.c Mon Jan 5 09:50:22 1998 @@ -216,11 +216,11 @@ static int pas_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - int level, v; + int level,v ; DEB(printk("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); if (cmd == SOUND_MIXER_PRIVATE1) { /* Set loudness bit */ - if (__get_user(level, (int *)arg)) + if (get_user(level, (int *)arg)) return -EFAULT; if (level == -1) /* Return current settings */ level = (mode_control & 0x04); @@ -231,10 +231,10 @@ set_mode(mode_control); } level = !!level; - return __put_user(level, (int *)arg); + return put_user(level, (int *)arg); } if (cmd == SOUND_MIXER_PRIVATE2) { /* Set enhance bit */ - if (__get_user(level, (int *)arg)) + if (get_user(level, (int *)arg)) return -EFAULT; if (level == -1) { /* Return current settings */ if (!(mode_control & 0x03)) @@ -254,13 +254,13 @@ i = (i + 1) * 20; level = i; } - return __put_user(level, (int *)arg); + return put_user(level, (int *)arg); } if (cmd == SOUND_MIXER_PRIVATE3) { /* Set mute bit */ - if (__get_user(level, (int *)arg)) + if (get_user(level, (int *)arg)) return -EFAULT; if (level == -1) /* Return current settings */ - level = = !(pas_read(0x0B8A) & 0x20); + level = !(pas_read(0x0B8A) & 0x20); else { if (level) pas_write(pas_read(0x0B8A) & (~0x20), 0x0B8A); @@ -269,10 +269,10 @@ level = !(pas_read(0x0B8A) & 0x20); } - return __put_user(level, (int *)arg); + return put_user(level, (int *)arg); } if (((cmd >> 8) & 0xff) == 'M') { - if (__get_user(v, (int *)arg)) + if (get_user(v, (int *)arg)) return -EFAULT; if (_SIOC_DIR(cmd) & _SIOC_WRITE) { v = pas_mixer_set(cmd & 0xff, v); @@ -303,7 +303,7 @@ break; } } - return __put_user(v, (int *)arg); + return put_user(v, (int *)arg); } return -EINVAL; } diff -u --recursive --new-file v2.1.77/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c --- v2.1.77/linux/drivers/sound/sb_audio.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/sb_audio.c Sun Jan 4 10:40:16 1998 @@ -982,7 +982,7 @@ sb_audio_close, sb_set_output_parms, sb_set_input_parms, - sb_audio_ioctl, + NULL, sb1_audio_prepare_for_input, sb1_audio_prepare_for_output, sb1_audio_halt_xfer, @@ -1002,7 +1002,7 @@ sb_audio_close, sb_set_output_parms, sb_set_input_parms, - sb_audio_ioctl, + NULL, sb1_audio_prepare_for_input, sb1_audio_prepare_for_output, sb1_audio_halt_xfer, @@ -1022,7 +1022,7 @@ sb_audio_close, sb_set_output_parms, sb_set_input_parms, - sb_audio_ioctl, + NULL, sbpro_audio_prepare_for_input, sbpro_audio_prepare_for_output, sb1_audio_halt_xfer, @@ -1042,7 +1042,7 @@ sb_audio_close, sb_set_output_parms, sb_set_input_parms, - sb_audio_ioctl, + NULL, sbpro_audio_prepare_for_input, sbpro_audio_prepare_for_output, sb1_audio_halt_xfer, @@ -1062,7 +1062,7 @@ sb_audio_close, sb_set_output_parms, sb_set_input_parms, - sb_audio_ioctl, + NULL, sb16_audio_prepare_for_input, sb16_audio_prepare_for_output, sb1_audio_halt_xfer, @@ -1082,7 +1082,7 @@ sb_audio_close, sb_set_output_parms, sb_set_input_parms, - sb_audio_ioctl, + NULL, ess_audio_prepare_for_input, ess_audio_prepare_for_output, sb1_audio_halt_xfer, diff -u --recursive --new-file v2.1.77/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.1.77/linux/drivers/sound/sb_mixer.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/sb_mixer.c Mon Jan 5 09:39:52 1998 @@ -293,14 +293,14 @@ * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1). */ if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) { - if (__get_user(val, (int *)arg)) + if (get_user(val, (int *)arg)) return -EFAULT; sb_setmixer(devc, 0x43, (~val) & 0x01); return 0; } if (((cmd >> 8) & 0xff) == 'M') { if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - if (__get_user(val, (int *)arg)) + if (get_user(val, (int *)arg)) return -EFAULT; switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: @@ -338,7 +338,7 @@ ret = sb_mixer_get(devc, cmd & 0xff); break; } - return __put_user(ret, (int *)arg); + return put_user(ret, (int *)arg); } else return -EINVAL; } diff -u --recursive --new-file v2.1.77/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.1.77/linux/drivers/sound/sequencer.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/sequencer.c Sun Jan 4 10:40:16 1998 @@ -12,6 +12,7 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Alan Cox : reformatted and fixed a pair of null pointer bugs */ #include @@ -89,12 +90,11 @@ #error Too many synthesizer devices enabled. #endif -int -sequencer_read(int dev, struct fileinfo *file, char *buf, int count) +int sequencer_read(int dev, struct fileinfo *file, char *buf, int count) { - int c = count, p = 0; - int ev_len; - unsigned long flags; + int c = count, p = 0; + int ev_len; + unsigned long flags; dev = dev >> 4; @@ -103,70 +103,65 @@ save_flags(flags); cli(); if (!iqlen) - { - if ((file->flags & (O_NONBLOCK) ? - 1 : 0)) - { - restore_flags(flags); - return -EAGAIN; - } - { - unsigned long tlimit; - - if (pre_event_timeout) - current->timeout = tlimit = jiffies + (pre_event_timeout); - else - tlimit = (unsigned long) -1; - midi_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&midi_sleeper); - if (!(midi_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag.opts |= WK_TIMEOUT; - } - midi_sleep_flag.opts &= ~WK_SLEEP; - }; - - if (!iqlen) - { - restore_flags(flags); - return 0; - } - } - while (iqlen && c >= ev_len) - { + { + if ((file->flags & (O_NONBLOCK) ? 1 : 0)) + { + restore_flags(flags); + return -EAGAIN; + } + { + unsigned long tlimit; - { - char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; + if (pre_event_timeout) + current->timeout = tlimit = jiffies + (pre_event_timeout); + else + tlimit = (unsigned long) -1; + midi_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper); + if (!(midi_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag.opts |= WK_TIMEOUT; + } + midi_sleep_flag.opts &= ~WK_SLEEP; + }; + + if (!iqlen) + { + restore_flags(flags); + return 0; + } + } + while (iqlen && c >= ev_len) + { + { + char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; + copy_to_user(&(buf)[p], fixit, ev_len); + }; + p += ev_len; + c -= ev_len; - copy_to_user(&(buf)[p], fixit, ev_len); - }; - p += ev_len; - c -= ev_len; - - iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; - iqlen--; - } + iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; + iqlen--; + } restore_flags(flags); return count - c; } -static void -sequencer_midi_output(int dev) +static void sequencer_midi_output(int dev) { /* * Currently NOP */ } -void -seq_copy_to_input(unsigned char *event_rec, int len) +void seq_copy_to_input(unsigned char *event_rec, int len) { unsigned long flags; /* - * Verify that the len is valid for the current mode. + * Verify that the len is valid for the current mode. */ if (len != 4 && len != 8) @@ -184,20 +179,17 @@ iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; if ((midi_sleep_flag.opts & WK_SLEEP)) - { - { - midi_sleep_flag.opts = WK_WAKEUP; - wake_up(&midi_sleeper); - }; - } + { + midi_sleep_flag.opts = WK_WAKEUP; + wake_up(&midi_sleeper); + } restore_flags(flags); } -static void -sequencer_midi_input(int dev, unsigned char data) +static void sequencer_midi_input(int dev, unsigned char data) { - unsigned int tstamp; - unsigned char event_rec[4]; + unsigned int tstamp; + unsigned char event_rec[4]; if (data == 0xfe) /* Ignore active sensing */ return; @@ -208,12 +200,12 @@ tstamp = jiffies - seq_time; if (tstamp != prev_input_time) - { - tstamp = (tstamp << 8) | SEQ_WAIT; + { + tstamp = (tstamp << 8) | SEQ_WAIT; - seq_copy_to_input((unsigned char *) &tstamp, 4); - prev_input_time = tstamp; - } + seq_copy_to_input((unsigned char *) &tstamp, 4); + prev_input_time = tstamp; + } event_rec[0] = SEQ_MIDIPUTC; event_rec[1] = data; event_rec[2] = dev; @@ -222,10 +214,9 @@ seq_copy_to_input(event_rec, 4); } -void -seq_input_event(unsigned char *event_rec, int len) +void seq_input_event(unsigned char *event_rec, int len) { - unsigned long this_time; + unsigned long this_time; if (seq_mode == SEQ_2) this_time = tmr->get_time(tmr_no); @@ -235,28 +226,27 @@ this_time = jiffies - seq_time; if (this_time != prev_input_time) - { - unsigned char tmp_event[8]; + { + unsigned char tmp_event[8]; + + tmp_event[0] = EV_TIMING; + tmp_event[1] = TMR_WAIT_ABS; + tmp_event[2] = 0; + tmp_event[3] = 0; + *(unsigned int *) &tmp_event[4] = this_time; - tmp_event[0] = EV_TIMING; - tmp_event[1] = TMR_WAIT_ABS; - tmp_event[2] = 0; - tmp_event[3] = 0; - *(unsigned int *) &tmp_event[4] = this_time; - - seq_copy_to_input(tmp_event, 8); - prev_input_time = this_time; - } + seq_copy_to_input(tmp_event, 8); + prev_input_time = this_time; + } seq_copy_to_input(event_rec, len); } -int -sequencer_write(int dev, struct fileinfo *file, const char *buf, int count) +int sequencer_write(int dev, struct fileinfo *file, const char *buf, int count) { - unsigned char event_rec[EV_SZ], ev_code; - int p = 0, c, ev_size; - int err; - int mode = file->mode & O_ACCMODE; + unsigned char event_rec[EV_SZ], ev_code; + int p = 0, c, ev_size; + int err; + int mode = file->mode & O_ACCMODE; dev = dev >> 4; @@ -268,100 +258,98 @@ c = count; while (c >= 4) - { - copy_from_user((char *) event_rec, &(buf)[p], 4); - ev_code = event_rec[0]; - - if (ev_code == SEQ_FULLSIZE) - { - int err, fmt; - - dev = *(unsigned short *) &event_rec[2]; - if (dev < 0 || dev >= max_synthdev || synth_devs[dev] == NULL) - return -ENXIO; - - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; - - fmt = (*(short *) &event_rec[0]) & 0xffff; - err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0); - if (err < 0) - return err; - - return err; - } - if (ev_code >= 128) - { - if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) - { - printk("Sequencer: Invalid level 2 event %x\n", ev_code); - return -EINVAL; - } - ev_size = 8; - - if (c < ev_size) - { - if (!seq_playing) - seq_startplay(); - return count - c; - } - copy_from_user((char *) &event_rec[4], &(buf)[p + 4], 4); - - } else - { - if (seq_mode == SEQ_2) - { - printk("Sequencer: 4 byte event in level 2 mode\n"); - return -EINVAL; - } - ev_size = 4; - - if (event_rec[0] != SEQ_MIDIPUTC) - obsolete_api_used = 1; - } - - if (event_rec[0] == SEQ_MIDIPUTC) - { - - if (!midi_opened[event_rec[2]]) - { - int mode; - int dev = event_rec[2]; + { + copy_from_user((char *) event_rec, &(buf)[p], 4); + ev_code = event_rec[0]; - if (dev >= max_mididev) - { - printk("Sequencer Error: Nonexistent MIDI device %d\n", dev); - return -ENXIO; - } - mode = file->mode & O_ACCMODE; + if (ev_code == SEQ_FULLSIZE) + { + int err, fmt; + + dev = *(unsigned short *) &event_rec[2]; + if (dev < 0 || dev >= max_synthdev || synth_devs[dev] == NULL) + return -ENXIO; + + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; + + fmt = (*(short *) &event_rec[0]) & 0xffff; + err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0); + if (err < 0) + return err; - if ((err = midi_devs[dev]->open(dev, mode, - sequencer_midi_input, sequencer_midi_output)) < 0) - { - seq_reset(); - printk("Sequencer Error: Unable to open Midi #%d\n", dev); - return err; - } - midi_opened[dev] = 1; - } - } - if (!seq_queue(event_rec, (file->flags & (O_NONBLOCK) ? - 1 : 0))) - { - int processed = count - c; - - if (!seq_playing) - seq_startplay(); - - if (!processed && (file->flags & (O_NONBLOCK) ? - 1 : 0)) - return -EAGAIN; - else - return processed; - } - p += ev_size; - c -= ev_size; - } + return err; + } + if (ev_code >= 128) + { + if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) + { + printk(KERN_WARNING "Sequencer: Invalid level 2 event %x\n", ev_code); + return -EINVAL; + } + ev_size = 8; + + if (c < ev_size) + { + if (!seq_playing) + seq_startplay(); + return count - c; + } + copy_from_user((char *) &event_rec[4], &(buf)[p + 4], 4); + + } + else + { + if (seq_mode == SEQ_2) + { + printk(KERN_WARNING "Sequencer: 4 byte event in level 2 mode\n"); + return -EINVAL; + } + ev_size = 4; + + if (event_rec[0] != SEQ_MIDIPUTC) + obsolete_api_used = 1; + } + + if (event_rec[0] == SEQ_MIDIPUTC) + { + if (!midi_opened[event_rec[2]]) + { + int mode; + int dev = event_rec[2]; + + if (dev >= max_mididev || midi_devs[dev]==NULL) + { + /*printk("Sequencer Error: Nonexistent MIDI device %d\n", dev);*/ + return -ENXIO; + } + mode = file->mode & O_ACCMODE; + + if ((err = midi_devs[dev]->open(dev, mode, + sequencer_midi_input, sequencer_midi_output)) < 0) + { + seq_reset(); + printk(KERN_WARNING "Sequencer Error: Unable to open Midi #%d\n", dev); + return err; + } + midi_opened[dev] = 1; + } + } + if (!seq_queue(event_rec, (file->flags & (O_NONBLOCK) ? 1 : 0))) + { + int processed = count - c; + + if (!seq_playing) + seq_startplay(); + + if (!processed && (file->flags & (O_NONBLOCK) ? 1 : 0)) + return -EAGAIN; + else + return processed; + } + p += ev_size; + c -= ev_size; + } if (!seq_playing) seq_startplay(); @@ -369,8 +357,7 @@ return count; } -static int -seq_queue(unsigned char *note, char nonblock) +static int seq_queue(unsigned char *note, char nonblock) { /* @@ -384,21 +371,21 @@ */ if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.opts & WK_SLEEP)) - { - /* - * Sleep until there is enough space on the queue - */ - - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - seq_sleep_flag.opts &= ~WK_SLEEP;; - } + { + /* + * Sleep until there is enough space on the queue + */ + + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + seq_sleep_flag.opts &= ~WK_SLEEP;; + } if (qlen >= SEQ_MAX_QUEUE) - { - return 0; /* + { + return 0; /* * To be sure */ - } + } memcpy(&queue[qtail * EV_SZ], note, EV_SZ); qtail = (qtail + 1) % SEQ_MAX_QUEUE; @@ -407,8 +394,7 @@ return 1; } -static int -extended_event(unsigned char *q) +static int extended_event(unsigned char *q) { int dev = q[2]; @@ -419,53 +405,51 @@ return -ENXIO; switch (q[1]) - { - case SEQ_NOTEOFF: - synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); - break; - - case SEQ_NOTEON: - if (q[4] > 127 && q[4] != 255) - return 0; - - if (q[5] == 0) - { - synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); - break; - } - synth_devs[dev]->start_note(dev, q[3], q[4], q[5]); - break; - - case SEQ_PGMCHANGE: - synth_devs[dev]->set_instr(dev, q[3], q[4]); - break; - - case SEQ_AFTERTOUCH: - synth_devs[dev]->aftertouch(dev, q[3], q[4]); - break; - - case SEQ_BALANCE: - synth_devs[dev]->panning(dev, q[3], (char) q[4]); - break; - - case SEQ_CONTROLLER: - synth_devs[dev]->controller(dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); - break; - - case SEQ_VOLMODE: - if (synth_devs[dev]->volume_method != NULL) - synth_devs[dev]->volume_method(dev, q[3]); - break; - - default: - return -EINVAL; - } + { + case SEQ_NOTEOFF: + synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); + break; + + case SEQ_NOTEON: + if (q[4] > 127 && q[4] != 255) + return 0; + + if (q[5] == 0) + { + synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); + break; + } + synth_devs[dev]->start_note(dev, q[3], q[4], q[5]); + break; + + case SEQ_PGMCHANGE: + synth_devs[dev]->set_instr(dev, q[3], q[4]); + break; + + case SEQ_AFTERTOUCH: + synth_devs[dev]->aftertouch(dev, q[3], q[4]); + break; + + case SEQ_BALANCE: + synth_devs[dev]->panning(dev, q[3], (char) q[4]); + break; + + case SEQ_CONTROLLER: + synth_devs[dev]->controller(dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); + break; + + case SEQ_VOLMODE: + if (synth_devs[dev]->volume_method != NULL) + synth_devs[dev]->volume_method(dev, q[3]); + break; + default: + return -EINVAL; + } return 0; } -static int -find_voice(int dev, int chn, int note) +static int find_voice(int dev, int chn, int note) { unsigned short key; int i; @@ -479,8 +463,7 @@ return -1; } -static int -alloc_voice(int dev, int chn, int note) +static int alloc_voice(int dev, int chn, int note) { unsigned short key; int voice; @@ -495,8 +478,7 @@ return voice; } -static void -seq_chn_voice_event(unsigned char *event_rec) +static void seq_chn_voice_event(unsigned char *event_rec) { #define dev event_rec[1] #define cmd event_rec[2] @@ -504,7 +486,7 @@ #define note event_rec[4] #define parm event_rec[5] - int voice = -1; + int voice = -1; if ((int) dev > max_synthdev || synth_devs[dev] == NULL) return; @@ -514,60 +496,62 @@ return; if (seq_mode == SEQ_2) - { - if (synth_devs[dev]->alloc_voice) - voice = find_voice(dev, chn, note); - - if (cmd == MIDI_NOTEON && parm == 0) - { - cmd = MIDI_NOTEOFF; - parm = 64; - } - } + { + if (synth_devs[dev]->alloc_voice) + voice = find_voice(dev, chn, note); + + if (cmd == MIDI_NOTEON && parm == 0) + { + cmd = MIDI_NOTEOFF; + parm = 64; + } + } + switch (cmd) - { - case MIDI_NOTEON: - if (note > 127 && note != 255) /* Not a seq2 feature */ - return; - - if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) - { /* Internal synthesizer (FM, GUS, etc) */ - voice = alloc_voice(dev, chn, note); - } - if (voice == -1) - voice = chn; - - if (seq_mode == SEQ_2 && (int) dev < num_synths) - { - /* - * The MIDI channel 10 is a percussive channel. Use the note - * number to select the proper patch (128 to 255) to play. - */ - - if (chn == 9) - { - synth_devs[dev]->set_instr(dev, voice, 128 + note); - synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; - } - synth_devs[dev]->setup_voice(dev, voice, chn); - } - synth_devs[dev]->start_note(dev, voice, note, parm); - break; - - case MIDI_NOTEOFF: - if (voice == -1) - voice = chn; - synth_devs[dev]->kill_note(dev, voice, note, parm); - break; - - case MIDI_KEY_PRESSURE: - if (voice == -1) - voice = chn; - synth_devs[dev]->aftertouch(dev, voice, parm); - break; + { + case MIDI_NOTEON: + if (note > 127 && note != 255) /* Not a seq2 feature */ + return; + + if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) + { + /* Internal synthesizer (FM, GUS, etc) */ + voice = alloc_voice(dev, chn, note); + } + if (voice == -1) + voice = chn; + + if (seq_mode == SEQ_2 && (int) dev < num_synths) + { + /* + * The MIDI channel 10 is a percussive channel. Use the note + * number to select the proper patch (128 to 255) to play. + */ + + if (chn == 9) + { + synth_devs[dev]->set_instr(dev, voice, 128 + note); + synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; + } + synth_devs[dev]->setup_voice(dev, voice, chn); + } + synth_devs[dev]->start_note(dev, voice, note, parm); + break; + + case MIDI_NOTEOFF: + if (voice == -1) + voice = chn; + synth_devs[dev]->kill_note(dev, voice, note, parm); + break; + + case MIDI_KEY_PRESSURE: + if (voice == -1) + voice = chn; + synth_devs[dev]->aftertouch(dev, voice, parm); + break; - default:; - } + default: + } #undef dev #undef cmd #undef chn @@ -576,8 +560,7 @@ } -static void -seq_chn_common_event(unsigned char *event_rec) +static void seq_chn_common_event(unsigned char *event_rec) { unsigned char dev = event_rec[1]; unsigned char cmd = event_rec[2]; @@ -595,208 +578,208 @@ return; switch (cmd) - { - case MIDI_PGM_CHANGE: - if (seq_mode == SEQ_2) - { - synth_devs[dev]->chn_info[chn].pgm_num = p1; - if ((int) dev >= num_synths) - synth_devs[dev]->set_instr(dev, chn, p1); - } else - synth_devs[dev]->set_instr(dev, chn, p1); - - break; - - case MIDI_CTL_CHANGE: - if (seq_mode == SEQ_2) - { - if (chn > 15 || p1 > 127) - break; - - synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; - - if (p1 < 32) /* Setting MSB should clear LSB to 0 */ - synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; - - if ((int) dev < num_synths) - { - int val = w14 & 0x7f; - int i, key; + { + case MIDI_PGM_CHANGE: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].pgm_num = p1; + if ((int) dev >= num_synths) + synth_devs[dev]->set_instr(dev, chn, p1); + } + else + synth_devs[dev]->set_instr(dev, chn, p1); + + break; + + case MIDI_CTL_CHANGE: + if (seq_mode == SEQ_2) + { + if (chn > 15 || p1 > 127) + break; + + synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; + + if (p1 < 32) /* Setting MSB should clear LSB to 0 */ + synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; + + if ((int) dev < num_synths) + { + int val = w14 & 0x7f; + int i, key; - if (p1 < 64) /* Combine MSB and LSB */ + if (p1 < 64) /* Combine MSB and LSB */ { val = ((synth_devs[dev]-> chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) - | (synth_devs[dev]-> - chn_info[chn].controllers[p1 | 32] & 0x7f); + | (synth_devs[dev]-> + chn_info[chn].controllers[p1 | 32] & 0x7f); p1 &= ~32; } - /* Handle all playing notes on this channel */ + /* Handle all playing notes on this channel */ - key = ((int) chn << 8); + key = ((int) chn << 8); - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) - synth_devs[dev]->controller(dev, i, p1, val); - } else - synth_devs[dev]->controller(dev, chn, p1, w14); - } else /* Mode 1 */ - synth_devs[dev]->controller(dev, chn, p1, w14); - break; - - case MIDI_PITCH_BEND: - if (seq_mode == SEQ_2) - { - synth_devs[dev]->chn_info[chn].bender_value = w14; - - if ((int) dev < num_synths) - { /* Handle all playing notes on this channel */ - int i, key; - - key = (chn << 8); - - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) - synth_devs[dev]->bender(dev, i, w14); - } else - synth_devs[dev]->bender(dev, chn, w14); - } else /* MODE 1 */ - synth_devs[dev]->bender(dev, chn, w14); - break; + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->controller(dev, i, p1, val); + } + else + synth_devs[dev]->controller(dev, chn, p1, w14); + } + else /* Mode 1 */ + synth_devs[dev]->controller(dev, chn, p1, w14); + break; + + case MIDI_PITCH_BEND: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].bender_value = w14; + + if ((int) dev < num_synths) + { + /* Handle all playing notes on this channel */ + int i, key; + + key = (chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->bender(dev, i, w14); + } + else + synth_devs[dev]->bender(dev, chn, w14); + } + else /* MODE 1 */ + synth_devs[dev]->bender(dev, chn, w14); + break; - default:; - } + default: + } } -static int -seq_timing_event(unsigned char *event_rec) +static int seq_timing_event(unsigned char *event_rec) { unsigned char cmd = event_rec[1]; unsigned int parm = *(int *) &event_rec[4]; if (seq_mode == SEQ_2) - { - int ret; + { + int ret; - if ((ret = tmr->event(tmr_no, event_rec)) == TIMER_ARMED) - { - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags(flags); - cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - }; - } - restore_flags(flags); - } - } - return ret; - } + if ((ret = tmr->event(tmr_no, event_rec)) == TIMER_ARMED) + { + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + } + restore_flags(flags); + } + } + return ret; + } switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - - /* - * NOTE! No break here. Execution of TMR_WAIT_REL continues in the - * next case (TMR_WAIT_ABS) - */ - - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - time = parm; - prev_event_time = time; - - seq_playing = 1; - if (softsynthp != NULL) - softsynthp(SSYN_REQUEST, time, 0, 0); - else - request_sound_timer(time); - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags(flags); - cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) + { + case TMR_WAIT_REL: + parm += prev_event_time; + + /* + * NOTE! No break here. Execution of TMR_WAIT_REL continues in the + * next case (TMR_WAIT_ABS) + */ + + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + time = parm; + prev_event_time = time; + + seq_playing = 1; + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, time, 0, 0); + else + request_sound_timer(time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - }; + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); } - restore_flags(flags); - } - return TIMER_ARMED; - } - break; - - case TMR_START: - if (softsynthp != NULL) - { - softsynthp(SSYN_START, 0, 0, 0); - seq_time = 0; - } else - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - break; - - case TMR_STOP: - break; - - case TMR_CONTINUE: - break; - - case TMR_TEMPO: - break; - - case TMR_ECHO: - if (seq_mode == SEQ_2) - seq_copy_to_input(event_rec, 8); - else - { - parm = (parm << 8 | SEQ_ECHO); - seq_copy_to_input((unsigned char *) &parm, 4); - } - break; + restore_flags(flags); + } + return TIMER_ARMED; + } + break; + + case TMR_START: + if (softsynthp != NULL) + { + softsynthp(SSYN_START, 0, 0, 0); + seq_time = 0; + } + else + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + break; + + case TMR_STOP: + break; + + case TMR_CONTINUE: + break; + + case TMR_TEMPO: + break; + + case TMR_ECHO: + if (seq_mode == SEQ_2) + seq_copy_to_input(event_rec, 8); + else + { + parm = (parm << 8 | SEQ_ECHO); + seq_copy_to_input((unsigned char *) &parm, 4); + } + break; - default:; - } + default: + } return TIMER_NOT_ARMED; } -static void -seq_local_event(unsigned char *event_rec) +static void seq_local_event(unsigned char *event_rec) { unsigned char cmd = event_rec[1]; unsigned int parm = *((unsigned int *) &event_rec[4]); switch (cmd) - { - case LOCL_STARTAUDIO: + { + case LOCL_STARTAUDIO: #ifdef CONFIG_AUDIO - DMAbuf_start_devices(parm); + DMAbuf_start_devices(parm); #endif - break; + break; - default:; - } + default: + } } -static void -seq_sysex_message(unsigned char *event_rec) +static void seq_sysex_message(unsigned char *event_rec) { int dev = event_rec[1]; int i, l = 0; @@ -819,261 +802,259 @@ synth_devs[dev]->send_sysex(dev, buf, l); } -static int -play_event(unsigned char *q) +static int play_event(unsigned char *q) { /* - * NOTE! This routine returns - * 0 = normal event played. - * 1 = Timer armed. Suspend playback until timer callback. - * 2 = MIDI output buffer full. Restore queue and suspend until timer + * NOTE! This routine returns + * 0 = normal event played. + * 1 = Timer armed. Suspend playback until timer callback. + * 2 = MIDI output buffer full. Restore queue and suspend until timer */ - unsigned int *delay; + unsigned int *delay; switch (q[0]) - { - case SEQ_NOTEOFF: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->kill_note(0, q[1], 255, q[3]); - break; - - case SEQ_NOTEON: - if (q[4] < 128 || q[4] == 255) - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->start_note(0, q[1], q[2], q[3]); - break; - - case SEQ_WAIT: - delay = (unsigned int *) q; /* - * Bytes 1 to 3 are containing the * - * delay in 'ticks' - */ - *delay = (*delay >> 8) & 0xffffff; + { + case SEQ_NOTEOFF: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->kill_note(0, q[1], 255, q[3]); + break; + + case SEQ_NOTEON: + if (q[4] < 128 || q[4] == 255) + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->start_note(0, q[1], q[2], q[3]); + break; + + case SEQ_WAIT: + delay = (unsigned int *) q; /* + * Bytes 1 to 3 are containing the * + * delay in 'ticks' + */ + *delay = (*delay >> 8) & 0xffffff; - if (*delay > 0) - { - long time; - - seq_playing = 1; - time = *delay; - prev_event_time = time; - - if (softsynthp != NULL) - softsynthp(SSYN_REQUEST, time, 0, 0); - else - request_sound_timer(time); - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags(flags); - cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) + if (*delay > 0) + { + long time; + + seq_playing = 1; + time = *delay; + prev_event_time = time; + + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, time, 0, 0); + else + request_sound_timer(time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) { { seq_sleep_flag.opts = WK_WAKEUP; wake_up(&seq_sleeper); }; } - restore_flags(flags); - } - /* - * The timer is now active and will reinvoke this function - * after the timer expires. Return to the caller now. - */ - return 1; - } - break; - - case SEQ_PGMCHANGE: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->set_instr(0, q[1], q[2]); - break; - - case SEQ_SYNCTIMER: /* - * Reset timer - */ - if (softsynthp != NULL) - seq_time = 0; - else - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - if (softsynthp != NULL) - softsynthp(SSYN_START, 0, 0, 0); - break; - - case SEQ_MIDIPUTC: /* - * Put a midi character + restore_flags(flags); + } + /* + * The timer is now active and will reinvoke this function + * after the timer expires. Return to the caller now. */ - if (midi_opened[q[2]]) - { - int dev; - - dev = q[2]; - - if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - break; - - if (!midi_devs[dev]->outputc(dev, q[1])) - { - /* - * Output FIFO is full. Wait one timer cycle and try again. - */ - - seq_playing = 1; - if (softsynthp != NULL) - softsynthp(SSYN_REQUEST, -1, 0, 0); - else - request_sound_timer(-1); - return 2; - } else - midi_written[dev] = 1; - } - break; - - case SEQ_ECHO: - seq_copy_to_input(q, 4); /* - * Echo back to the process - */ - break; + return 1; + } + break; + + case SEQ_PGMCHANGE: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->set_instr(0, q[1], q[2]); + break; + + case SEQ_SYNCTIMER: /* + * Reset timer + */ + if (softsynthp != NULL) + seq_time = 0; + else + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + if (softsynthp != NULL) + softsynthp(SSYN_START, 0, 0, 0); + break; + + case SEQ_MIDIPUTC: /* + * Put a midi character + */ + if (midi_opened[q[2]]) + { + int dev; + + dev = q[2]; + + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + break; + + if (!midi_devs[dev]->outputc(dev, q[1])) + { + /* + * Output FIFO is full. Wait one timer cycle and try again. + */ + + seq_playing = 1; + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, -1, 0, 0); + else + request_sound_timer(-1); + return 2; + } + else + midi_written[dev] = 1; + } + break; + + case SEQ_ECHO: + seq_copy_to_input(q, 4); /* + * Echo back to the process + */ + break; - case SEQ_PRIVATE: - if ((int) q[1] < max_synthdev) - synth_devs[q[1]]->hw_control(q[1], q); - break; - - case SEQ_EXTENDED: - extended_event(q); - break; - - case EV_CHN_VOICE: - seq_chn_voice_event(q); - break; - - case EV_CHN_COMMON: - seq_chn_common_event(q); - break; - - case EV_TIMING: - if (seq_timing_event(q) == TIMER_ARMED) - { - return 1; - } - break; - - case EV_SEQ_LOCAL: - seq_local_event(q); - break; - - case EV_SYSEX: - seq_sysex_message(q); - break; + case SEQ_PRIVATE: + if ((int) q[1] < max_synthdev) + synth_devs[q[1]]->hw_control(q[1], q); + break; + + case SEQ_EXTENDED: + extended_event(q); + break; + + case EV_CHN_VOICE: + seq_chn_voice_event(q); + break; + + case EV_CHN_COMMON: + seq_chn_common_event(q); + break; + + case EV_TIMING: + if (seq_timing_event(q) == TIMER_ARMED) + { + return 1; + } + break; + + case EV_SEQ_LOCAL: + seq_local_event(q); + break; + + case EV_SYSEX: + seq_sysex_message(q); + break; - default:; - } + default:; + } return 0; } -static void -seq_startplay(void) +static void seq_startplay(void) { - unsigned long flags; - int this_one, action; + unsigned long flags; + int this_one, action; while (qlen > 0) - { + { + + save_flags(flags); + cli(); + qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; + qlen--; + restore_flags(flags); - save_flags(flags); - cli(); - qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; - qlen--; - restore_flags(flags); - - seq_playing = 1; - - if ((action = play_event(&queue[this_one * EV_SZ]))) - { /* Suspend playback. Next timer routine invokes this routine again */ - if (action == 2) - { - qlen++; - qhead = this_one; - } - return; - } - } + seq_playing = 1; + + if ((action = play_event(&queue[this_one * EV_SZ]))) + { /* Suspend playback. Next timer routine invokes this routine again */ + if (action == 2) + { + qlen++; + qhead = this_one; + } + return; + } + } seq_playing = 0; if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; + { + unsigned long flags; - save_flags(flags); - cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - }; - } - restore_flags(flags); - } + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } } static void reset_controllers(int dev, unsigned char *controller, int update_dev) { - int i; + int i; for (i = 0; i < 128; i++) controller[i] = ctrl_def_values[i]; } -static void -setup_mode2(void) +static void setup_mode2(void) { - int dev; + int dev; max_synthdev = num_synths; for (dev = 0; dev < num_midis; dev++) + { if (midi_devs[dev] && midi_devs[dev]->converter != NULL) - { - synth_devs[max_synthdev++] = - midi_devs[dev]->converter; - } + { + synth_devs[max_synthdev++] = midi_devs[dev]->converter; + } + } + for (dev = 0; dev < max_synthdev; dev++) - { - int chn; + { + int chn; - synth_devs[dev]->sysex_ptr = 0; - synth_devs[dev]->emulation = 0; + synth_devs[dev]->sysex_ptr = 0; + synth_devs[dev]->emulation = 0; - for (chn = 0; chn < 16; chn++) - { - synth_devs[dev]->chn_info[chn].pgm_num = 0; - reset_controllers(dev, - synth_devs[dev]->chn_info[chn].controllers, - 0); - synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ - synth_devs[dev]->chn_info[chn].bender_range = 200; - } - } + for (chn = 0; chn < 16; chn++) + { + synth_devs[dev]->chn_info[chn].pgm_num = 0; + reset_controllers(dev, + synth_devs[dev]->chn_info[chn].controllers,0); + synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ + synth_devs[dev]->chn_info[chn].bender_range = 200; + } + } max_mididev = 0; seq_mode = SEQ_2; } -int -sequencer_open(int dev, struct fileinfo *file) +int sequencer_open(int dev, struct fileinfo *file) { int retval, mode, i; int level, tmp; @@ -1090,28 +1071,30 @@ DEB(printk("sequencer_open(dev=%d)\n", dev)); if (!sequencer_ok) - { - printk("Soundcard: Sequencer not initialized\n"); - return -ENXIO; - } + { +/* printk("Soundcard: Sequencer not initialized\n");*/ + return -ENXIO; + } if (dev) /* Patch manager device (obsolete) */ - { + { return -ENXIO; - } + } if (mode == OPEN_READ) + { if (!num_midis) - { - printk("Sequencer: No MIDI devices. Input not possible\n"); + { + /*printk("Sequencer: No MIDI devices. Input not possible\n");*/ sequencer_busy = 0; return -ENXIO; - } + } + } save_flags(flags); cli(); if (sequencer_busy) - { - restore_flags(flags); - return -EBUSY; - } + { + restore_flags(flags); + return -EBUSY; + } sequencer_busy = 1; obsolete_api_used = 0; restore_flags(flags); @@ -1122,61 +1105,65 @@ seq_mode = SEQ_1; if (pending_timer != -1) - { - tmr_no = pending_timer; - pending_timer = -1; - } + { + tmr_no = pending_timer; + pending_timer = -1; + } if (tmr_no == -1) /* Not selected yet */ - { - int i, best; + { + int i, best; - best = -1; - for (i = 0; i < num_sound_timers; i++) - if (sound_timer_devs[i] && sound_timer_devs[i]->priority > best) - { + best = -1; + for (i = 0; i < num_sound_timers; i++) + if (sound_timer_devs[i] && sound_timer_devs[i]->priority > best) + { tmr_no = i; best = sound_timer_devs[i]->priority; - } - if (tmr_no == -1) /* Should not be */ - tmr_no = 0; - } + } + if (tmr_no == -1) /* Should not be */ + tmr_no = 0; + } tmr = sound_timer_devs[tmr_no]; if (level == 2) - { - if (tmr == NULL) - { - printk("sequencer: No timer for level 2\n"); - sequencer_busy = 0; - return -ENXIO; - } - setup_mode2(); - } + { + if (tmr == NULL) + { + /*printk("sequencer: No timer for level 2\n");*/ + sequencer_busy = 0; + return -ENXIO; + } + setup_mode2(); + } if (!max_synthdev && !max_mididev) return -ENXIO; synth_open_mask = 0; for (i = 0; i < max_mididev; i++) - { - midi_opened[i] = 0; - midi_written[i] = 0; - } + { + midi_opened[i] = 0; + midi_written[i] = 0; + } for (i = 0; i < max_synthdev; i++) - { - if ((tmp = synth_devs[i]->open(i, mode)) < 0) - { - printk("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); - if (synth_devs[i]->midi_dev) - printk("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); - } else - { - synth_open_mask |= (1 << i); - if (synth_devs[i]->midi_dev) - midi_opened[synth_devs[i]->midi_dev] = 1; - } - } + { + if (synth_devs[i]==NULL) + continue; + + if ((tmp = synth_devs[i]->open(i, mode)) < 0) + { + printk(KERN_WARNING "Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); + if (synth_devs[i]->midi_dev) + printk(KERN_WARNING "(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); + } + else + { + synth_open_mask |= (1 << i); + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 1; + } + } if (softsynthp != NULL) seq_time = 0; @@ -1189,21 +1176,25 @@ softsynthp(SSYN_START, 0, 0, 0); if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) - { /* - * Initialize midi input devices - */ - for (i = 0; i < max_mididev; i++) - if (!midi_opened[i]) - { - if ((retval = midi_devs[i]->open(i, mode, - sequencer_midi_input, sequencer_midi_output)) >= 0) - midi_opened[i] = 1; - } - } + { + /* + * Initialize midi input devices + */ + + for (i = 0; i < max_mididev; i++) + if (!midi_opened[i]) + { + if ((retval = midi_devs[i]->open(i, mode, + sequencer_midi_input, sequencer_midi_output)) >= 0) + { + midi_opened[i] = 1; + } + } + } if (seq_mode == SEQ_2) - { - tmr->open(tmr_no, seq_mode); - } + { + tmr->open(tmr_no, seq_mode); + } seq_sleep_flag.opts = WK_NONE; midi_sleep_flag.opts = WK_NONE; output_threshold = SEQ_MAX_QUEUE / 2; @@ -1211,8 +1202,7 @@ return 0; } -void -seq_drain_midi_queues(void) +void seq_drain_midi_queues(void) { int i, n; @@ -1223,43 +1213,42 @@ n = 1; while (!signal_pending(current) && n) - { - n = 0; + { + n = 0; + + for (i = 0; i < max_mididev; i++) + if (midi_opened[i] && midi_written[i]) + if (midi_devs[i]->buffer_status != NULL) + if (midi_devs[i]->buffer_status(i)) + n++; - for (i = 0; i < max_mididev; i++) - if (midi_opened[i] && midi_written[i]) - if (midi_devs[i]->buffer_status != NULL) - if (midi_devs[i]->buffer_status(i)) - n++; - - /* - * Let's have a delay - */ - if (n) - { - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - } - } + /* + * Let's have a delay + */ + + if (n) + { + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; + } + } } -void -sequencer_release(int dev, struct fileinfo *file) +void sequencer_release(int dev, struct fileinfo *file) { int i; int mode = file->mode & O_ACCMODE; @@ -1274,27 +1263,30 @@ if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ? 1 : 0)) + { while (!signal_pending(current) && qlen > 0) - { - seq_sync(); + { + seq_sync(); - { - unsigned long tlimit; + { + unsigned long tlimit; - if (3 * HZ) - current->timeout = tlimit = jiffies + (3 * HZ); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; /* Extra delay */ - } + if (3 * HZ) + current->timeout = tlimit = jiffies + (3 * HZ); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; /* Extra delay */ + } + } + if (mode != OPEN_READ) seq_drain_midi_queues(); /* * Ensure the output queues are empty @@ -1306,35 +1298,34 @@ */ for (i = 0; i < max_synthdev; i++) - { - if (synth_open_mask & (1 << i)) /* - * Actually opened - */ - if (synth_devs[i]) - { - synth_devs[i]->close(i); - - if (synth_devs[i]->midi_dev) - midi_opened[synth_devs[i]->midi_dev] = 0; - } - } + { + if (synth_open_mask & (1 << i)) /* + * Actually opened + */ + if (synth_devs[i]) + { + synth_devs[i]->close(i); + + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 0; + } + } for (i = 0; i < max_mididev; i++) - { - if (midi_opened[i]) + { + if (midi_opened[i]) midi_devs[i]->close(i); - } + } if (seq_mode == SEQ_2) tmr->close(tmr_no); if (obsolete_api_used) - printk("/dev/music: Obsolete (4 byte) API was used by this program\n"); + printk(KERN_WARNING "/dev/music: Obsolete (4 byte) API was used by %s\n", current->comm); sequencer_busy = 0; } -static int -seq_sync(void) +static int seq_sync(void) { unsigned long flags; @@ -1344,32 +1335,30 @@ save_flags(flags); cli(); if (qlen > 0) - { - - { - unsigned long tlimit; + { + { + unsigned long tlimit; - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - } + if (HZ) + current->timeout = tlimit = jiffies + (HZ); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; + } restore_flags(flags); return qlen; } -static void -midi_outc(int dev, unsigned char data) +static void midi_outc(int dev, unsigned char data) { /* * NOTE! Calls sleep(). Don't call this from interrupt. @@ -1389,31 +1378,29 @@ save_flags(flags); cli(); while (n && !midi_devs[dev]->outputc(dev, data)) - { - - { - unsigned long tlimit; + { + { + unsigned long tlimit; - if (4) - current->timeout = tlimit = jiffies + (4); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - n--; - } + if (4) + current->timeout = tlimit = jiffies + (4); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; + n--; + } restore_flags(flags); } -static void -seq_reset(void) +static void seq_reset(void) { /* * NOTE! Calls sleep(). Don't call this from interrupt. @@ -1441,82 +1428,79 @@ synth_devs[i]->reset(i); if (seq_mode == SEQ_2) - { - - for (chn = 0; chn < 16; chn++) - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - { - synth_devs[i]->controller(i, chn, 123, 0); /* All notes off */ - synth_devs[i]->controller(i, chn, 121, 0); /* Reset all ctl */ - synth_devs[i]->bender(i, chn, 1 << 13); /* Bender off */ - } - } else - /* seq_mode == SEQ_1 */ - { - for (i = 0; i < max_mididev; i++) - if (midi_written[i]) /* + { + for (chn = 0; chn < 16; chn++) + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + { + synth_devs[i]->controller(i, chn, 123, 0); /* All notes off */ + synth_devs[i]->controller(i, chn, 121, 0); /* Reset all ctl */ + synth_devs[i]->bender(i, chn, 1 << 13); /* Bender off */ + } + } + else /* seq_mode == SEQ_1 */ + { + for (i = 0; i < max_mididev; i++) + if (midi_written[i]) /* * Midi used. Some notes may still be playing */ - { - /* - * Sending just a ACTIVE SENSING message should be enough to stop all - * playing notes. Since there are devices not recognizing the - * active sensing, we have to send some all notes off messages also. - */ - midi_outc(i, 0xfe); - - for (chn = 0; chn < 16; chn++) - { - midi_outc(i, - (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ - midi_outc(i, 0x7b); /* All notes off */ - midi_outc(i, 0); /* Dummy parameter */ - } - - midi_devs[i]->close(i); - - midi_written[i] = 0; - midi_opened[i] = 0; - } - } + { + /* + * Sending just a ACTIVE SENSING message should be enough to stop all + * playing notes. Since there are devices not recognizing the + * active sensing, we have to send some all notes off messages also. + */ + midi_outc(i, 0xfe); + + for (chn = 0; chn < 16; chn++) + { + midi_outc(i, (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ + midi_outc(i, 0x7b); /* All notes off */ + midi_outc(i, 0); /* Dummy parameter */ + } + + midi_devs[i]->close(i); + + midi_written[i] = 0; + midi_opened[i] = 0; + } + } seq_playing = 0; save_flags(flags); cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) - { - /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - }; - } + { + /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } restore_flags(flags); - } -static void -seq_panic(void) +static void seq_panic(void) { /* - * This routine is called by the application in case the user - * wants to reset the system to the default state. + * This routine is called by the application in case the user + * wants to reset the system to the default state. */ seq_reset(); /* - * Since some of the devices don't recognize the active sensing and - * all notes off messages, we have to shut all notes manually. - * - * TO BE IMPLEMENTED LATER + * Since some of the devices don't recognize the active sensing and + * all notes off messages, we have to shut all notes manually. + * + * TO BE IMPLEMENTED LATER */ /* - * Also return the controllers to their default states + * Also return the controllers to their default states */ } @@ -1724,69 +1708,61 @@ return -EINVAL; } -int -sequencer_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) +int sequencer_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) { unsigned long flags; dev = dev >> 4; switch (sel_type) - { - case SEL_IN: - save_flags(flags); - cli(); - if (!iqlen) - { - - midi_sleep_flag.opts = WK_SLEEP; - poll_wait(&midi_sleeper, wait); - restore_flags(flags); - return 0; - } - restore_flags(flags); - return 1; - break; - - case SEL_OUT: - save_flags(flags); - cli(); - if ((SEQ_MAX_QUEUE - qlen) < output_threshold) - { - - seq_sleep_flag.opts = WK_SLEEP; - poll_wait(&seq_sleeper, wait); - restore_flags(flags); - return 0; - } - restore_flags(flags); - return 1; - break; - - case SEL_EX: - return 0; - } + { + case SEL_IN: + save_flags(flags); + cli(); + if (!iqlen) + { + midi_sleep_flag.opts = WK_SLEEP; + poll_wait(&midi_sleeper, wait); + restore_flags(flags); + return 0; + } + restore_flags(flags); + return 1; + + case SEL_OUT: + save_flags(flags); + cli(); + if ((SEQ_MAX_QUEUE - qlen) < output_threshold) + { + seq_sleep_flag.opts = WK_SLEEP; + poll_wait(&seq_sleeper, wait); + restore_flags(flags); + return 0; + } + restore_flags(flags); + return 1; + case SEL_EX: + return 0; + } return 0; } -void -sequencer_timer(unsigned long dummy) +void sequencer_timer(unsigned long dummy) { seq_startplay(); } -int -note_to_freq(int note_num) +int note_to_freq(int note_num) { /* * This routine converts a midi note to a frequency (multiplied by 1000) */ - int note, octave, note_freq; - static int notes[] = + int note, octave, note_freq; + static int notes[] = { 261632, 277189, 293671, 311132, 329632, 349232, 369998, 391998, 415306, 440000, 466162, 493880 @@ -1811,12 +1787,11 @@ return note_freq; } -unsigned long -compute_finetune(unsigned long base_freq, int bend, int range, +unsigned long compute_finetune(unsigned long base_freq, int bend, int range, int vibrato_cents) { - unsigned long amount; - int negative, semitones, cents, multiplier = 1; + unsigned long amount; + int negative, semitones, cents, multiplier = 1; if (!bend) return base_freq; @@ -1847,18 +1822,17 @@ bend = 2399; */ while (bend > 2399) - { + { multiplier *= 4; bend -= 2400; - } + } semitones = bend / 100; if (semitones > 99) semitones = 99; cents = bend % 100; - amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) - / 10000; + amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) / 10000; if (negative) return (base_freq * 10000) / amount; /* Bend down */ @@ -1867,8 +1841,7 @@ } -void -sequencer_init(void) +void sequencer_init(void) { if (sequencer_ok) return; @@ -1883,19 +1856,19 @@ if (sound_nblocks < 1024) sound_nblocks++;; if (queue == NULL) - { - printk("Sound: Can't allocate memory for sequencer output queue\n"); + { + printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n"); return; - } + } iqueue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc(SEQ_MAX_QUEUE * IEV_SZ)); sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * IEV_SZ; if (sound_nblocks < 1024) - sound_nblocks++;; + sound_nblocks++; if (iqueue == NULL) - { - printk("Sound: Can't allocate memory for sequencer input queue\n"); - return; - } + { + printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n"); + return; + } sequencer_ok = 1; } diff -u --recursive --new-file v2.1.77/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c --- v2.1.77/linux/drivers/sound/softoss.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/softoss.c Sun Jan 4 10:40:16 1998 @@ -106,7 +106,7 @@ static struct softsyn_devc sdev_info = {0}; -softsyn_devc *devc = &sdev_info; +static softsyn_devc *devc = &sdev_info; static struct voice_alloc_info *voice_alloc; diff -u --recursive --new-file v2.1.77/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v2.1.77/linux/drivers/sound/sound_timer.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/sound_timer.c Sun Jan 4 10:46:19 1998 @@ -46,8 +46,7 @@ return (tmp + (scale / 2)) / scale; } -static void -reprogram_timer(void) +void reprogram_timer(void) { unsigned long usecs_per_tick; diff -u --recursive --new-file v2.1.77/linux/drivers/sound/soundmodule.h linux/drivers/sound/soundmodule.h --- v2.1.77/linux/drivers/sound/soundmodule.h Fri Jan 2 14:37:02 1998 +++ linux/drivers/sound/soundmodule.h Sun Jan 4 10:45:55 1998 @@ -1,13 +1,13 @@ #ifndef _SOUNDMODULE_H #define _SOUNDMODULE_H -#ifdef MODULE - #include extern struct notifier_block *sound_locker; extern void sound_notifier_chain_register(struct notifier_block *); extern int lock_depth; + +#ifdef MODULE #ifdef SOUND_CORE diff -u --recursive --new-file v2.1.77/linux/fs/Config.in linux/fs/Config.in --- v2.1.77/linux/fs/Config.in Sun Dec 21 22:36:15 1997 +++ linux/fs/Config.in Sun Jan 4 10:40:16 1998 @@ -57,6 +57,7 @@ tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS +tristate 'Apple Macintosh filesystem support (experimental)' CONFIG_HFS_FS tristate 'ROM filesystem support' CONFIG_ROMFS_FS tristate 'Kernel automounter support (experimental)' CONFIG_AUTOFS_FS if [ "$CONFIG_AFFS_FS" != "n" ]; then @@ -66,6 +67,7 @@ if [ "$CONFIG_UFS_FS" != "n" ]; then bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL + bool 'Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION fi bool 'Macintosh partition map support' CONFIG_MAC_PARTITION endmenu diff -u --recursive --new-file v2.1.77/linux/fs/Makefile linux/fs/Makefile --- v2.1.77/linux/fs/Makefile Sun Dec 21 16:17:44 1997 +++ linux/fs/Makefile Sun Jan 4 10:40:16 1998 @@ -17,7 +17,7 @@ MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ - hpfs sysv smbfs ncpfs ufs affs romfs autofs lockd nfsd nls + hpfs sysv smbfs ncpfs ufs affs romfs autofs hfs lockd nfsd nls ifeq ($(CONFIG_QUOTA),y) O_OBJS += dquot.o @@ -90,6 +90,14 @@ else ifeq ($(CONFIG_ISO9660_FS),m) MOD_SUB_DIRS += isofs + endif +endif + +ifeq ($(CONFIG_HFS_FS),y) +SUB_DIRS += hfs +else + ifeq ($(CONFIG_HFS_FS),m) + MOD_SUB_DIRS += hfs endif endif diff -u --recursive --new-file v2.1.77/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v2.1.77/linux/fs/affs/inode.c Thu Dec 4 14:53:56 1997 +++ linux/fs/affs/inode.c Sun Jan 4 00:53:42 1998 @@ -220,8 +220,9 @@ } int -affs_notify_change(struct inode *inode, struct iattr *attr) +affs_notify_change(struct dentry *dentry, struct iattr *attr) { + struct inode *inode = dentry->d_inode; int error; pr_debug("AFFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid); diff -u --recursive --new-file v2.1.77/linux/fs/affs/symlink.c linux/fs/affs/symlink.c --- v2.1.77/linux/fs/affs/symlink.c Thu Dec 4 14:53:56 1997 +++ linux/fs/affs/symlink.c Sun Jan 4 00:53:42 1998 @@ -19,8 +19,8 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) -static int affs_readlink(struct inode *, char *, int); -static struct dentry *affs_follow_link(struct inode *inode, struct dentry *base); +static int affs_readlink(struct dentry *, char *, int); +static struct dentry *affs_follow_link(struct dentry *dentry, struct dentry *base); struct inode_operations affs_symlink_inode_operations = { NULL, /* no file-operations */ @@ -44,8 +44,9 @@ }; static int -affs_readlink(struct inode *inode, char *buffer, int buflen) +affs_readlink(struct inode *dentry, char *buffer, int buflen) { + struct inode *inode = dentry->d_inode; struct buffer_head *bh; struct slink_front *lf; int i, j; @@ -97,8 +98,9 @@ } static struct dentry * -affs_follow_link(struct inode *inode, struct dentry *base) +affs_follow_link(struct dentry *dentry, struct dentry *base) { + struct inode *inode = dentry->d_inode; struct buffer_head *bh; struct slink_front *lf; char *buffer; diff -u --recursive --new-file v2.1.77/linux/fs/attr.c linux/fs/attr.c --- v2.1.77/linux/fs/attr.c Sun Dec 21 22:36:15 1997 +++ linux/fs/attr.c Sun Jan 4 00:53:41 1998 @@ -81,8 +81,9 @@ mark_inode_dirty(inode); } -int notify_change(struct inode * inode, struct iattr * attr) +int notify_change(struct dentry * dentry, struct iattr * attr) { + struct inode *inode = dentry->d_inode; int error; time_t now = CURRENT_TIME; unsigned int ia_valid = attr->ia_valid; @@ -93,11 +94,13 @@ if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; - if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change) - return inode->i_sb->s_op->notify_change(inode, attr); - - error = inode_change_ok(inode, attr); - if (!error) - inode_setattr(inode, attr); + if (inode->i_sb && inode->i_sb->s_op && + inode->i_sb->s_op->notify_change) + error = inode->i_sb->s_op->notify_change(dentry, attr); + else { + error = inode_change_ok(inode, attr); + if (!error) + inode_setattr(inode, attr); + } return error; } diff -u --recursive --new-file v2.1.77/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c --- v2.1.77/linux/fs/autofs/symlink.c Mon Aug 4 16:25:38 1997 +++ linux/fs/autofs/symlink.c Sun Jan 4 00:53:43 1998 @@ -14,23 +14,24 @@ #include #include "autofs_i.h" -static int autofs_readlink(struct inode *inode, char *buffer, int buflen) +static int autofs_readlink(struct dentry *dentry, char *buffer, int buflen) { struct autofs_symlink *sl; int len; - sl = (struct autofs_symlink *)inode->u.generic_ip; + sl = (struct autofs_symlink *)dentry->d_inode->u.generic_ip; len = sl->len; if (len > buflen) len = buflen; - copy_to_user(buffer,sl->data,len); + copy_to_user(buffer, sl->data, len); return len; } -static struct dentry * autofs_follow_link(struct inode *inode, struct dentry *base) +static struct dentry * autofs_follow_link(struct dentry *dentry, + struct dentry *base) { struct autofs_symlink *sl; - sl = (struct autofs_symlink *)inode->u.generic_ip; + sl = (struct autofs_symlink *)dentry->d_inode->u.generic_ip; return lookup_dentry(sl->data, base, 1); } diff -u --recursive --new-file v2.1.77/linux/fs/bad_inode.c linux/fs/bad_inode.c --- v2.1.77/linux/fs/bad_inode.c Wed Oct 15 16:04:23 1997 +++ linux/fs/bad_inode.c Sun Jan 4 00:53:41 1998 @@ -13,7 +13,7 @@ /* * The follow_symlink operation must dput() the base. */ -static struct dentry * bad_follow_link(struct inode * ino, struct dentry *base) +static struct dentry * bad_follow_link(struct dentry *dent, struct dentry *base) { dput(base); return ERR_PTR(-EIO); diff -u --recursive --new-file v2.1.77/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.77/linux/fs/buffer.c Tue Dec 23 16:31:00 1997 +++ linux/fs/buffer.c Sun Jan 4 00:53:57 1998 @@ -1522,8 +1522,9 @@ * mark_buffer_uptodate() functions propagate buffer state into the * page struct once IO has completed. */ -int generic_readpage(struct inode * inode, struct page * page) +int generic_readpage(struct dentry * dentry, struct page * page) { + struct inode *inode = dentry->d_inode; unsigned long block; int *p, nr[PAGE_SIZE/512]; int i; diff -u --recursive --new-file v2.1.77/linux/fs/coda/file.c linux/fs/coda/file.c --- v2.1.77/linux/fs/coda/file.c Sun Dec 21 22:36:16 1997 +++ linux/fs/coda/file.c Sun Jan 4 00:53:43 1998 @@ -25,10 +25,10 @@ #include /* file operations */ -static int coda_readpage(struct inode * inode, struct page * page); -static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *off); -static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off); -static int coda_file_mmap(struct file * file, struct vm_area_struct * vma); +static int coda_readpage(struct dentry *, struct page *); +static ssize_t coda_file_read(struct file *, char *, size_t, loff_t *); +static ssize_t coda_file_write(struct file *, const char *, size_t, loff_t *); +static int coda_file_mmap(struct file *, struct vm_area_struct *); /* exported from this file */ int coda_fsync(struct file *, struct dentry *dentry); @@ -74,9 +74,9 @@ }; /* File file operations */ -static int coda_readpage(struct inode * inode, struct page * page) +static int coda_readpage(struct dentry *dentry, struct page * page) { - struct inode *open_inode; + struct inode *open_inode, *inode = dentry->d_inode; struct cnode *cnp; ENTRY; @@ -93,6 +93,7 @@ CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, open_inode->i_ino, page->offset); + /* N.B. This needs the dentry for open_inode */ generic_readpage(open_inode, page); EXIT; return 0; diff -u --recursive --new-file v2.1.77/linux/fs/coda/super.c linux/fs/coda/super.c --- v2.1.77/linux/fs/coda/super.c Sun Dec 21 22:36:16 1997 +++ linux/fs/coda/super.c Sun Jan 4 00:53:43 1998 @@ -41,7 +41,7 @@ /* VFS super_block ops */ static struct super_block *coda_read_super(struct super_block *, void *, int); static void coda_read_inode(struct inode *); -static int coda_notify_change(struct inode *inode, struct iattr *attr); +static int coda_notify_change(struct dentry *, struct iattr *); static void coda_put_inode(struct inode *); static void coda_delete_inode(struct inode *); static void coda_put_super(struct super_block *); @@ -133,6 +133,7 @@ printk("coda_read_super: rootinode is %ld dev %d\n", root->i_ino, root->i_dev); sbi->sbi_root = root; + /* N.B. check this for failure */ sb->s_root = d_alloc_root(root, NULL); unlock_super(sb); EXIT; @@ -140,7 +141,6 @@ error: EXIT; - MOD_DEC_USE_COUNT; if (sbi) { sbi->sbi_vcomm = NULL; sbi->sbi_root = NULL; @@ -154,6 +154,7 @@ coda_cnode_free(ITOC(root)); } sb->s_dev = 0; + MOD_DEC_USE_COUNT; return NULL; } @@ -224,8 +225,9 @@ EXIT; } -static int coda_notify_change(struct inode *inode, struct iattr *iattr) +static int coda_notify_change(struct dentry *dentry, struct iattr *iattr) { + struct inode *inode = dentry->d_inode; struct cnode *cnp; struct coda_vattr vattr; int error; diff -u --recursive --new-file v2.1.77/linux/fs/coda/symlink.c linux/fs/coda/symlink.c --- v2.1.77/linux/fs/coda/symlink.c Sun Dec 21 22:36:16 1997 +++ linux/fs/coda/symlink.c Sun Jan 4 00:53:43 1998 @@ -24,8 +24,8 @@ #include #include -static int coda_readlink(struct inode *inode, char *buffer, int length); -static struct dentry *coda_follow_link(struct inode *, struct dentry *); +static int coda_readlink(struct dentry *dentry, char *buffer, int length); +static struct dentry *coda_follow_link(struct dentry *, struct dentry *); struct inode_operations coda_symlink_inode_operations = { NULL, /* no file-operations */ @@ -50,8 +50,9 @@ NULL /* revalidate */ }; -static int coda_readlink(struct inode *inode, char *buffer, int length) +static int coda_readlink(struct inode *dentry, char *buffer, int length) { + struct inode *inode = dentry->d_inode; int len; int error; char *buf; @@ -83,14 +84,15 @@ return error; } -static struct dentry *coda_follow_link(struct inode *inode, - struct dentry *base) +static struct dentry *coda_follow_link(struct dentry *dentry, + struct dentry *base) { + struct inode *inode = dentry->d_inode; int error; struct cnode *cnp; unsigned int len; - char mem[CFS_MAXPATHLEN]; char *path; + char mem[CFS_MAXPATHLEN]; /* N.B. too big for the stack? */ ENTRY; CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino); diff -u --recursive --new-file v2.1.77/linux/fs/dcache.c linux/fs/dcache.c --- v2.1.77/linux/fs/dcache.c Fri Dec 19 15:53:00 1997 +++ linux/fs/dcache.c Sun Jan 4 00:54:04 1998 @@ -52,6 +52,8 @@ static inline void d_free(struct dentry *dentry) { + if (dentry->d_op && dentry->d_op->d_release) + dentry->d_op->d_release(dentry); kfree(dentry->d_name.name); kfree(dentry); } @@ -502,6 +504,7 @@ dentry->d_name.len = name->len; dentry->d_name.hash = name->hash; dentry->d_op = NULL; + dentry->d_fsdata = NULL; return dentry; } diff -u --recursive --new-file v2.1.77/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.1.77/linux/fs/ext2/inode.c Sun Dec 21 22:36:16 1997 +++ linux/fs/ext2/inode.c Sun Jan 4 00:53:41 1998 @@ -631,23 +631,25 @@ return ext2_update_inode (inode, 1); } -int ext2_notify_change(struct inode *inode, struct iattr *iattr) +int ext2_notify_change(struct dentry *dentry, struct iattr *iattr) { + struct inode *inode = dentry->d_inode; int retval; unsigned int flags; + retval = -EPERM; if ((iattr->ia_attr_flags & (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^ (inode->u.ext2_i.i_flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { if (securelevel > 0 || !fsuser()) - return -EPERM; - } else - if ((current->fsuid != inode->i_uid) && !fsuser()) - return -EPERM; + goto out; + } else if ((current->fsuid != inode->i_uid) && !fsuser()) + goto out; - if ((retval = inode_change_ok(inode, iattr)) != 0) - return retval; + retval = inode_change_ok(inode, iattr); + if (retval != 0) + goto out; inode_setattr(inode, iattr); @@ -681,7 +683,7 @@ inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL; } mark_inode_dirty(inode); - - return 0; +out: + return retval; } diff -u --recursive --new-file v2.1.77/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v2.1.77/linux/fs/ext2/namei.c Sat Nov 29 11:25:12 1997 +++ linux/fs/ext2/namei.c Sun Jan 4 00:53:41 1998 @@ -793,8 +793,10 @@ goto out; } -int ext2_link (struct inode * inode, struct inode * dir, struct dentry *dentry) +int ext2_link (struct dentry * old_dentry, + struct inode * dir, struct dentry *dentry) { + struct inode *inode = old_dentry->d_inode; struct ext2_dir_entry * de; struct buffer_head * bh; int err; diff -u --recursive --new-file v2.1.77/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c --- v2.1.77/linux/fs/ext2/symlink.c Thu Jul 17 10:06:06 1997 +++ linux/fs/ext2/symlink.c Sun Jan 4 00:53:41 1998 @@ -24,8 +24,8 @@ #include #include -static int ext2_readlink (struct inode *, char *, int); -static struct dentry *ext2_follow_link(struct inode *, struct dentry *); +static int ext2_readlink (struct dentry *, char *, int); +static struct dentry *ext2_follow_link(struct dentry *, struct dentry *); /* * symlinks can't do much... @@ -51,10 +51,12 @@ NULL /* smap */ }; -static struct dentry * ext2_follow_link(struct inode * inode, struct dentry *base) +static struct dentry * ext2_follow_link(struct dentry * dentry, + struct dentry *base) { - int error; + struct inode *inode = dentry->d_inode; struct buffer_head * bh = NULL; + int error; char * link; link = (char *) inode->u.ext2_i.i_data; @@ -72,8 +74,9 @@ return base; } -static int ext2_readlink (struct inode * inode, char * buffer, int buflen) +static int ext2_readlink (struct dentry * dentry, char * buffer, int buflen) { + struct inode *inode = dentry->d_inode; struct buffer_head * bh = NULL; char * link; int i; diff -u --recursive --new-file v2.1.77/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v2.1.77/linux/fs/fat/inode.c Sun Dec 21 22:36:16 1997 +++ linux/fs/fat/inode.c Sun Jan 4 00:53:42 1998 @@ -783,9 +783,10 @@ } -int fat_notify_change(struct inode * inode,struct iattr * attr) +int fat_notify_change(struct dentry * dentry, struct iattr * attr) { - struct super_block *sb = inode->i_sb; + struct super_block *sb = dentry->d_sb; + struct inode *inode = dentry->d_inode; int error; error = inode_change_ok(inode, attr); diff -u --recursive --new-file v2.1.77/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.1.77/linux/fs/filesystems.c Sun Dec 21 22:36:16 1997 +++ linux/fs/filesystems.c Sun Jan 4 10:41:52 1998 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,10 @@ #ifdef CONFIG_NTFS_FS init_ntfs_fs(); +#endif + +#ifdef CONFIG_HFS_FS + init_hfs_fs(); #endif #ifdef CONFIG_AFFS_FS diff -u --recursive --new-file v2.1.77/linux/fs/hfs/COPYING linux/fs/hfs/COPYING --- v2.1.77/linux/fs/hfs/COPYING Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/COPYING Sun Jan 4 10:40:16 1998 @@ -0,0 +1,339 @@ + 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 + + 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. + + + Copyright (C) 19yy + + 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. + + , 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. diff -u --recursive --new-file v2.1.77/linux/fs/hfs/ChangeLog linux/fs/hfs/ChangeLog --- v2.1.77/linux/fs/hfs/ChangeLog Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/ChangeLog Sun Jan 4 10:40:17 1998 @@ -0,0 +1,2294 @@ +Sun Dec 28 22:48:53 1997 a sun + + * sysdep.c, catalog.c, hfs.h + as a temporary workaround until catalog.c gets re-written, + i flush the dcache if we need more entries. + +Fri Dec 19 15:11:21 1997 a sun + + * dir_dbl.c + statically allocate tmp_name instead of doing it dynamically. + + NOTE: well, those pesky hfs_cat_put messages still aren't gone. in + addition, catalog.c needs to be modified to free up some entries + when the cache gets filled up. + +Sun Dec 14 11:51:11 1997 a sun + + * linux/hfs_fs.h + moved the dentry stuff into within the #ifdef __KERNEL__ + part of hfs_fs.h and cleaned up a little. + +Sun Dec 14 11:24:54 1997 a sun + + * dir.c + changed hfs_rename to delete all old dentries. hfs_cat_put + messages on umount should be a thing of the past now. + +Sun Dec 14 01:12:58 1997 a sun + + * dir.c + changed mark_inodes_deleted to dget/d_delete/dput the dentry + instead of just dropping it. the bytes available should now + be updated updated properly upon deletion. + +Wed Dec 10 00:01:25 1997 a sun + + * dir.c + changed mark_inodes_deleted to drop the dentry instead of + just deleting it. + + TODO: bytes available aren't being properly updated when a + resource fork gets deleted. + +Mon Dec 8 23:22:40 1997 a sun + + * dir_cap.c, dir_nat.c, dir_dbl.c, dir.c + * hfs.h, linux/hfs_sysdep.h, linux/hfs_fs_i.h + Added code to drop ({dbl,cap,nat}_drop_dentry) invalid + dentries when creating or moving a file. + + * inode.c + Added code to delete cached dentries when a file gets deleted. + + * current yuckiness: there's an extra hfs_cat_put somewhere. it's + harmless but bothersome. + +Thu Dec 4 00:14:03 1997 a sun + + * dir.c, dir_cap.c, dir_nat.c, file.c, file_hdr.c, inode.c, + * linux/{hfs_sysdep.h, hfs_fs.h}, version.c: + Completed first code dentrification sweep. It mounts! It copies! + It dcaches! + +Mon Apr 28 06:58:44 1997 Paul H. Hargrove + + * version.c, INSTALL.sgml, HFS.sgml: + Bump version to 0.95 (Woohoo! We're beta!) + + * linux/hfs_fs.h: + Modify HFS_SB() and HFS_I() when compiled into the kernel. + + * FAQ.sgml: + Add a new question (and its answer): + Why does my Macintosh show generic application and document icons? + + * HFS.sgml: + Add some URLs and remove the (now empty) FAQ section. + +Sun Apr 27 22:17:01 1997 Paul H. Hargrove + + * HFS.sgml: + Don't call the version 1 headers "slightly modified". + + * file_hdr.c, dir_nat.c: + Comment some AFPD compatibility stuff. + + * FAQ.sgml: + Update for version 0.95. + + * BUG_INFO: + Remove the BIG_INFO script since we no longer mention it. + + * README.sgml, INSTALL.sgml, HFS.sgml, Makefile: + Split README.sgml into HFS.sgml and INSTALL.sgml. + Stop including the document sources in snapshots. + + * file_hdr.c: + Fix hdr_truncate() not to truncate the data fork. + +Wed Apr 16 23:56:25 1997 Paul H. Hargrove + + * FAQ.sgml: + Bump version to 0.8.4 and add two answers: + How to fsck an HFS filesystem. + How to generate linux/version.h. + + * version.c, README.sgml: + Bump version to 0.8.4. + + * README.sgml, FAQ.sgml, Makefile: + Separate the FAQ from the README. + + * linux/hfs_fs.h: + Add (struct hfs_fork) to the forward declarations. + +Thu Apr 10 05:47:16 1997 Paul H. Hargrove + + * linux/hfs_sysdep.h: + Work around the non-const declaration of test_bit()'s second argument. + + * Makefile: + Use .config from the kernel source to check for MODVERSIONS. + +Wed Apr 9 07:57:17 1997 Paul H. Hargrove + + * bnode.c: + Check the record table in each bnode as we read it from disk. + + * super.c, mdb.c, hfs.h: + Deal with the ATTRIB_CLEAN bit of the MDB properly (in mdb.c). + + * super.c, hfs.h, mdb.c: + Search for the alt-MDB rather than using the device size to find it. + +Wed Apr 9 03:39:05 1997 Paul H. Hargrove + + * version.c, README.sgml: + Bump version to 0.8.3. + +Mon Apr 7 20:09:56 1997 Paul H. Hargrove + + * part_tbl.c: + Fix to allow bootable CDROMs (which have blocksize != 512) to mount. + + * super.c: + Check that blk_size[MAJOR(dev)] is non-NULL before dereferencing. + +Sat Apr 5 10:44:42 1997 Paul H. Hargrove + + * hfs_btree.h, binsert.c, brec.c, bfind.c, bins_del.c, bdelete.c: + Make btree operations less likely to do + nasty things if the tree is corrupted. + + * part_tbl.c, README.sgml: + Count partitions from 0 rather than from 1. + +Wed Apr 2 23:26:51 1997 Paul H. Hargrove + + * bdelete.c: + Don't bother checking for oversized keys in hfs_bdelete(). + + * bdelete.c, bfind.c, binsert.c: + Verify key lengths against the maximum given for the tree. + + * Makefile: + Check that /usr/include/linux/modversions.h exists before including it. + This allows compilation without CONFIG_MODVERSIONS enabled. + +Sat Mar 29 13:17:53 1997 Paul H. Hargrove + + * linux/hfs_fs.h, super.c, file_hdr.c, hfs.h, extent.c, file_cap.c, + dir_dbl.c, dir_nat.c, dir.c, dir_cap.c, binsert.c, catalog.c, + bfind.c: + Make (struct hfs_bkey) and (struct hfs_brec) more "abstract". + + * binsert.c: + Remove redundant test in hfs_binsert(). + +Sat Mar 29 05:24:23 1997 Paul H. Hargrove + + * version.c, README.sgml: + Fix formatting problems in README.sgml and bump version to 0.8.2. + + * extent.c: + Fix bug that caused serious headaches with fragmented files. + +Fri Mar 28 00:23:18 1997 Paul H. Hargrove + + * version.c, README.sgml: + Bump version to 0.8.1. + + * btree.c, balloc.c: + Commit map nodes to buffers when new map nodes are added. + +Thu Mar 27 22:41:07 1997 Paul H. Hargrove + + * Makefile: + Include linux/modversions.h from the gcc command line. + + * mdb.c: + Was updating modified date twice in hfs_mdb_commit(). + + * linux/hfs_sysdep.h, linux/hfs_fs.h, linux/hfs_fs_i.h, + linux/hfs_fs_sb.h, sysdep.c, trans.c, super.c, hfs_sysdep.h, inode.c, + hfs_fs_i.h, hfs_fs_sb.h, hfs_fs.h, hfs.h, file_cap.c, file_hdr.c, + file.c, dir_nat.c, dir_cap.c, dir_dbl.c, Makefile, dir.c: + Rearrange headers in preparation for inclusion in the kernel. + + * hfs_fs_sb.h, hfs_fs.h: + Add forward declarations so other code can include these headers. + + * hfs_sysdep.h: + Include __constant_hton[ls]() for little-endian machines. + + * hfs_fs.h, hfs_sysdep.h, hfs.h: + Move typedefs of hfs_{byte,word,lword}_t from hfs.h to hfs_sysdep.h. + Include hfs_sysdep.h from hfs_fs.h. + + * trans.c, super.c, part_tbl.c, string.c, inode.c, mdb.c, hfs_fs_sb.h, + hfs_sysdep.h, hfs_fs.h, hfs.h, hfs_btree.h, file_cap.c, file_hdr.c, + file.c, dir_nat.c, extent.c, dir_dbl.c, dir.c, dir_cap.c, catalog.c, + btree.c, bnode.c, brec.c, bitmap.c, bitops.c, bins_del.c, binsert.c, + bdelete.c, bfind.c, balloc.c: + Big type system changes in preparation for kernel inclusion: + '[US](8|16|32)' -> 'hfs_[us](8|16|32)' (avoids name space pollution) + 'hfs_name_t' -> 'struct hfs_name' (allows forward declaration) + + * super.c, hfs_fs.h: + Add init_hfs_fs() to super.c for non-module compilation. + +Wed Mar 26 07:53:59 1997 Paul H. Hargrove + + * version.c, README.sgml: + Bump version to 0.8. + + * README.sgml: + Special compilation note for DEC Alpha. + + * README.sgml: + Note status on non-Intel processors. + + * hfs_fs.h: + Use long's for read() and write() on the Alpha. + + * README.sgml: + Document the afpd mount option. + + * inode.c: + Make files always writable for owner in afpd mode. + +Tue Mar 25 23:21:39 1997 Paul H. Hargrove + + * part_tbl.c: + Clean up the error checking code a bit. + +Sat Mar 22 19:43:40 1997 Paul H. Hargrove + + * part_tbl.c: + Fixed uninitialized variable in old-style partition code. + + * bins_del.c, bdelete.c: + Fix extraneous "bad argument to shift_{left,right}" messages. + + * bitops.c: + Note that these routines are now tested on Intel, PPC and Alpha. + + * Makefile: + Add -fno-builtin the the CFLAGS. + +Fri Feb 14 10:50:14 1997 Paul H. Hargrove + + * hfs_sysdep.h: + Don't include until after . + + * catalog.c: + Use volume create date in hashfn() rather than casting pointer to int. + + * hfs.h, mdb.c: + Maintaing volume create, modify and backup dates in struct hfs_mdb. + + * hfs_fs.h: + Include the header for put_user BEFORE using it! + + * string.c, hfs.h: + Make hfs_strhash() return an unsigned int. + + * trans.c, version.c, super.c, mdb.c, part_tbl.c, string.c, inode.c, + hfs_sysdep.h, hfs_fs.h, hfs_fs_sb.h, hfs_btree.h, hfs.h, file_cap.c, + file_hdr.c, extent.c, dir_dbl.c, dir_nat.c, dir_cap.c, dir.c, + catalog.c, btree.c, bnode.c, brec.c, bitmap.c, binsert.c, + bins_del.c, bdelete.c, balloc.c, README.sgml, Makefile: + Updated copyright notices. + + * trans.c, part_tbl.c, string.c, super.c, inode.c, mdb.c, hfs_fs.h, + hfs_fs_sb.h, hfs_sysdep.h, hfs_btree.h, hfs.h, file_cap.c, + file_hdr.c, dir_nat.c, extent.c, dir_cap.c, dir_dbl.c, catalog.c, + dir.c, brec.c, btree.c, bitmap.c, bnode.c, bdelete.c, bins_del.c, + binsert.c, Makefile, TODO, balloc.c: + First shot at portability to the DEC Alpha and non-gcc compilers. + This invloved a significant overhaul of the type system. + +Tue Feb 4 04:26:54 1997 Paul H. Hargrove + + * version.c, README.sgml: + Bump version to "pre-0.8-4". + + * dir_nat.c: + Allow creat() in Netatalk .AppleDouble directories. + + * dir_dbl.c: + Make local functions static. + + * dir_dbl.c: + Removed unnecessary 'extern' qualifiers from forward declarations. + + * file_hdr.c, TODO: + Fixed the 30-year time warp with afpd. + + * TODO, trans.c: + Don't mangle the name .AppleDesktop under fork=netatalk. + +Mon Feb 3 23:18:45 1997 Paul H. Hargrove + + * inode.c: + Make header files always writable when the afpd mount option is given. + Otherwise it is impossible to unlock a locked file. + + * TODO, inode.c: + Let afpd think chmod() always succeeds, so "New Folder" works right. + + * super.c: + The 'afpd' mount option now makes 'fork=n,names=n' the default. + + * TODO: + List the current known afpd-compatibility problems as bugs. + + * file_hdr.c: + Make certain date changes through header files get written to disk. + +Sat Feb 1 02:24:12 1997 Paul H. Hargrove + + * mdb.c: + Work around for Linux rounding device sizes to 1k increments. + + * README.sgml: + Fixed a typo: "the a". + +Sat Dec 28 20:41:01 1996 Paul H. Hargrove + + * TODO: + Add ioctl() interface as a "missing feature." + + * dir_nat.c: + Finish implementing the afpd-compatibility + mode using the new 'afpd' mount option. + + * hfs_fs_sb.h, super.c: + Add new 'afpd' mount option. + + * file_cap.c: + Spelling fix. + +Wed Dec 11 23:16:08 1996 Paul H. Hargrove + + * TODO, README.sgml: + Optimistically document the hybrid CD problem as fixed. + + * part_tbl.c: + Fix the partition code so at least some of the hybrid + CDROMs that were previously rejected are now accepted. + + * hfs.h: + Make fs_start a 32-bit integer rather than 16-bits. + The 16-bit value would overflow if a partition started + beyond the 32M mark (e.g. the Executor 2 Beta 1 CDROM). + + * extent.c: + Fixed a typo in an error message. + +Tue Dec 10 14:43:46 1996 Paul H. Hargrove + + * dir_nat.c: + Merge in the (still dormant) afpd-compatibility changes. + + * inode.c: + Make the .AppleDouble directory writable (again). + + * version.c, README.sgml: + Bump version up to "pre-0.8-3". + + * hfs_fs.h, file_cap.c, file_hdr.c: + Move AFP constants to hfs_fs.h and prefix them with "HFS_". + + * dir_nat.c, inode.c: + Back-out changes that allowed writing to the .AppleDouble directory. + + * Makefile: + Update rules for linuxdoc-sgml v1.5. + + * extent.c: + Fixed serious bug in decode_extent() with handling of empty extents. + + * file.c: + Rewrote hfs_getblk(). + It will no longer hang if hfs_extent_map() is buggy. + Also halves the worst-case number of calls to hfs_extent_map(). + + * extent.c: + Fixed serious bug in decode_extent() with handling of empty extents. + + * hfs_fs.h: + Small change so the PPC (and maybe other architectures?) + pick up the prototypes for the user-space access functions. + + * super.c, file_cap.c, file_hdr.c, hfs_fs.h, file.c: + Updated for new user-space memory interface. + +Sun Dec 8 11:49:36 1996 Paul H. Hargrove + + * dir_nat.c: + Add special code for unlink(), and rename() in the .AppleDouble + directory and rmdir() of the .AppleDouble directory. + + * inode.c: + Make the .AppleDouble directory writable. + + * file_hdr.c: + Use AFP flags in version 1 headers (for Netatalk compatibility). + + * trans.c: + Fixed bug with long names causing kernel Oops. + +Mon Oct 7 06:05:01 1996 Paul H. Hargrove + + * hfs_fs.h, file_cap.c, file_hdr.c, hfs.h, extent.c, file.c, dir.c: + Fix types for various read/write/truncate computations. + Also allows compilation with 2.1.x kernels. + +Thu Sep 19 10:28:43 1996 Paul H. Hargrove + + * README.sgml, version.c: + Bump version up to "pre-0.8-2". + + * TODO: + Reformat the To Do list introducing prioritized categories. + + * file_hdr.c, file.c: + Move comments about mmap() for headers from file.c to file_hdr.c. + Also revise the reasoning for not yet having it implemented. + + * dir_nat.c, dir_cap.c, dir_dbl.c: + Remove 'hfs_' prefix from names of some purely local functions. + + * dir_dbl.c, TODO: + Under AppleDouble make create(), mkdir(), mknod(), unlink(), rename() + and rename() check against header files when arguments start with '%'. + + * super.c, hfs_fs_sb.h, hfs_fs.h, dir_dbl.c, dir_nat.c, dir_cap.c, + dir.c, README.sgml: + Fix problem that prevented creating %RootInfo or .rootinfo in all + directories in addition to preventing deletion from the root directory. + + * TODO: + Remove writable header files from the To Do list. + + * README.sgml: + Add extensive discussion of writing to HFS filesystems and + the format of the special files. + + * file_hdr.c: + Generate the 'homefs' field for version 1 header files. + +Wed Sep 18 23:07:45 1996 Paul H. Hargrove + + * hfs_fs.h, file_cap.c: + Comment the definition of (struct hfs_cap_info). + + * version.c, README.sgml: + Bump version up to "pre-0.8-1" and update the "How can I write?" FAQ. + + * file_hdr.c: + Implement hdr_write() and hdr_truncate()!! + + * hfs_fs_i.h, inode.c: + Make hdr_layout per-inode (not per-file) so hdr_truncate() will work. + + * file.c, hfs.h, catalog.c, extent.c, balloc.c: + hfs_extent_adj() now uses fork->lsize to determine the target file size. + +Sun Sep 15 07:55:24 1996 Paul H. Hargrove + + * README.sgml, trans.c: + Prevent creation of files & directories with '\0' or ':' in their names. + + * string.c, hfs_fs.h, hfs.h, dir_dbl.c, dir_nat.c, dir_cap.c: + With case=lower could have run off end of string. + +Tue Sep 10 12:05:47 1996 Paul H. Hargrove + + * inode.c: + Small clean up of HFS_FIL_LOCK handling. + + * inode.c: + Fix notify_change() not to accidentally make metadata executable. + + * hfs_fs.h: + AppleSingle files should have HFS_ITYPE_NORM. + + * inode.c: + Return to old behavior where MdDat = i_mtime. + + * dir_dbl.c: + Fix serious bug in hfs_dbl_readdir() that would lock-up access to a + directory if one tried to write to a directory they had previously read. + + * file.c: + Fix hfs_do_write() to adjust the fork's 'lsize' if it changed. + + * inode.c, file_cap.c: + Allow truncate() to be called even on metadata. + Any size changes will last only until the next iput() of the inode. + Truncating a header file doesn't yet truncate the resource fork. + + * inode.c: + Allow chmod() on a directory if it doesn't actually change i_mode. + + * hfs_fs.h, trans.c, super.c: + Rename hfs_cap2mac() to hfs_colon2mac(). + Rename hfs_apl2mac() to hfs_prcnt2mac(). + + * file_hdr.c: + Move header construction out of hdr_read() to create hdr_build_meta(). + + * hfs.h: + Add byte-order independent conversions: U32->U16, U32->U8 and U16->U8. + + * file.c, file_cap.c, hfs_fs.h: + Rename fix_perms() to hfs_file_fix_mode() and + move it from from file_cap.c to file.c. + + * README.sgml, super.c: + Make the default for the names mount option vary with the fork option. + + * file_cap.c: + The umask was applied incorrectly in fix_perms(). + +Mon Sep 9 13:11:28 1996 Paul H. Hargrove + + * README.sgml: + Note that it compiles on m68k machines, but needs more testing. + + * hfs_sysdep.h, Makefile: + Changes to compile unmodified on m68k (and possibly other machines). + + * dir_cap.c: + hfs_cap_readdir() was mistakenly producing .rootinfo entries for + the .finderinfo and .resource subdirectories of the root directory. + + * inode.c: + A directory's i_size was too small by 1 under CAP, so hfs_cap_readdir() + would omit the last directory entry. i_nlink was also too large by 1. + +Sun Sep 8 12:56:06 1996 Paul H. Hargrove + + * file_hdr.c: + Rewrite hdr_read() to be more efficient and to deal correctly with + descriptors having lengths that differ from the actual size of the data. + + * file_cap.c: + Add write support for CAP finderinfo files!! + + * super.c, inode.c, hfs_fs.h, hfs_fs_i.h, hfs_fs_sb.h, file_dbl.c, + file_nat.c, file_hdr.c, file.c, file_cap.c, Makefile, dir.c: + Generate metadata (header files and CAP finderinfo files) on-the-fly. + The files file_{dbl,nat}.c are merged into file_hdr.c as a result. + +Sat Sep 7 08:09:24 1996 Paul H. Hargrove + + * README.sgml: + Fix silly grammatical error. + +Fri Sep 6 09:17:12 1996 Paul H. Hargrove + + * hfs_fs_sb.h, super.c: + No need to cast type of s_reserved. + + * file_dbl.c, file_nat.c, dir_dbl.c, dir_nat.c, file_cap.c, dir_cap.c: + Add the missing NULL readpage and writepage entries to the inode_ops. + + * file_dbl.c, file_nat.c, file.c, file_cap.c: + Cleanup error checking for read() and write(). + +Thu Sep 5 05:29:53 1996 Paul H. Hargrove + + * version.c, README.sgml: + Bump version up to "0.7.2". + User-visible changes from 0.7.0: + + Corrected CAP finderinfo file format. + + Support for more features of CAP finderinfo files. + + No longer requires gcc 2.7.0 or newer. + + Now implements mknod() system call. + + * hfs_fs.h, dir_nat.c, file_cap.c, file_nat.c, README.sgml, dir_cap.c: + Include the CAP and Netatalk copyright notices. + + * hfs_fs.h, file_cap.c: + Repair and improve CAP support. + + * catalog.c: + Oops! The BkDat for new files and directories was in 1972 when + it should have been in 1904 (not that it matters that much). + + * inode.c: + The HFS MdDat should be the larger of the i_mtime and i_ctime. + + * README.sgml: + Change 'm_time' to 'i_mtime'. + +Wed Sep 4 13:27:35 1996 Paul H. Hargrove + + * version.c, README.sgml: + Bump version up to "0.7.1". + User-visible changes from 0.7.0: + + Minor bug in CAP finderinfo file format fixed. + + No longer requires gcc 2.7.0 or newer. + + Now implements mknod() system call. + + * README.sgml: + Removed note about needing gcc 2.7.0 or newer. + + * file.c: + Optimize hfs_do_read() based on the fact that HFS has no holes in files. + Minor code formatting changes. + + * hfs.h, hfs_sysdep.h, mdb.c, extent.c, file.c, btree.c, catalog.c, + balloc.c, bnode.c: + Reorganize memory management routines. + hfs_malloc() and hfs_free() are the main routines. + The macros FREE() and MALLOC() are gone. + HFS_NEW() and HFS_DELETE() are new 'shorthand' macros. + + * btree.c: + Fix broken debugging code. + + * super.c, hfs.h, mdb.c, part_tbl.c, Makefile: + Separate partition table handling into its own file. + + * dir.c: + Spelling fixes. + + * sysdep.c: + Oops! Error check got sense reversed while editing. + + * mdb.c, sysdep.c, hfs.h, hfs_btree.h, hfs_sysdep.h, btree.c, extent.c, + bfind.c, bnode.c, balloc.c: + Make hfs_buffer a pointer to a buffer_head, rather than a buffer_head. + + * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c, dir.c: + Add a mknod() entry to the inode_operations for normal directories. + All it is good for is letting root create regular files. + + * file_dbl.c, file_nat.c, file.c, file_cap.c, dir_cap.c, dir_dbl.c, + dir_nat.c: + Add the missing NULL entries to the end of the file_operations. + + * super.c, hfs_btree.h, hfs_fs.h, mdb.c, extent.c, hfs.h, catalog.c: + Make the remainder of the (untested) changes + to allow compilation with gcc 2.6.3. + + * hfs_fs.h: + Fix hfs_fs.h to work with gcc 2.6.3. + + * hfs_fs.h: + (struct hfs_cap_info) should never have been 'packed'. + + * BUG_INFO: + Use -V for getting version of module utilities. + + * super.c, sysdep.c, trans.c, hfs_fs_sb.h, inode.c, hfs_fs.h, + hfs_fs_i.h, file_cap.c, file_dbl.c, file_nat.c, dir_dbl.c, + dir_nat.c, file.c, dir.c, dir_cap.c: + Fix up hfs_fs{,_i,_sb}.h in preparation for inclusion in kernel. + +Tue Sep 3 23:58:03 1996 Paul H. Hargrove + + * hfs.h: + Change eventual destination to linux/fs/hfs rather than include/linux. + + * super.c, inode.c, mdb.c, hfs_btree.h, hfs_fs.h, hfs_sysdep.h, + file_dbl.c, file_nat.c, hfs.h, dir_nat.c, extent.c, dir_dbl.c, + catalog.c, dir_cap.c, brec.c, btree.c, binsert.c, bnode.c, bdelete.c, + bfind.c, bins_del.c, balloc.c: + Replace all the swap{16,32}() stuff w/ ntohl() and friends. + +Fri Aug 30 09:51:23 1996 Paul H. Hargrove + + * version.c, README.sgml: + Rewrite installation instructions and bump version up to "0.7.0". + + * Makefile: + Remove the INCDIR variable; we now rely on the + user to have the correct links in /usr/include. + +Mon Aug 26 12:25:41 1996 Paul H. Hargrove + + * version.c, README.sgml: + Reformat the documentation and bump version up to "pre-0.7-9". + Hopefully this will become version 0.7 in a few days. + +Thu Aug 22 08:00:44 1996 Paul H. Hargrove + + * README.sgml, version.c: + Bump version up to "pre-0.7-8". + + * file_nat.c, file_dbl.c: + AppleDouble headers had resource fork size in wrong byte order. + +Wed Aug 21 05:22:28 1996 Paul H. Hargrove + + * version.c, README.sgml: + Bump version up to "pre-0.7-7". + + * bnode.c: + Fixed a long-standing bug in hfs_bnode_lock(). + This bug occasionally caused lock-up under heavy load. + +Tue Aug 20 09:15:10 1996 Paul H. Hargrove + + * README.sgml, version.c: + Bump version up to "pre-0.7-6". + + * catalog.c: + Fix a deadlock problem in catalog readers/writers locking. + + * bins_del.c: + hfs_bnode_update_key() was still corrupting the header node sometimes. + + * catalog.c, dir.c: + Fix problem with extending the catalog B-tree hanging hfs_cat_commit(). + Fix a race that could delete a non-empty directory. + +Sun Aug 18 23:16:43 1996 Paul H. Hargrove + + * version.c, README.sgml: + Bump version to "pre-0.7-5" for test release. + + * dir_cap.c, README.sgml: + Change ".:rootinfo:" to ".rootinfo". + + * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c: + Mangle the names as first step in hfs_{cap,dbl,nat}_lookup(). + Use the new hfs_streq() to catch mixed case matches to the special + files and directories in hfs_{cap,dbl,nat}_lookup(). + Store reserved names only once. + + * dir.c, hfs.h, string.c: + Implement hfs_streq() which tests for string equality more + rapidly than hfs_strcmp() by checking for equal length first, + and use it when checking for reserved names. + + * inode.c, TODO, dir_cap.c, dir_dbl.c, README.sgml: + Provide the metadata for the root directory for the CAP and AppleDouble + schemes in the files ".:rootinfo:" and "%RootInfo", respectively. + + * TODO, super.c: + Add (untested) support for the old Mac Plus style of partition map. + + * bdelete.c, TODO: + Note the possibility of bdelete() to hanging on a corrupted B-tree. + + * TODO: + Add items corresponding to some of the 'XXX' comments in the sources. + + * dir_dbl.c, dir_cap.c: + Update comments, removing ref. to a comment that once existed in inode.c + + * catalog.c: + Remove some redundant locking and error checks + that had been previously marked as questionable. + +Sat Aug 17 08:06:56 1996 Paul H. Hargrove + + * binsert.c, bfind.c, bins_del.c, balloc.c, bdelete.c: + Edited some comments for correctness. + + * README.sgml, version.c: + Bump version up to "pre-0.7-4" in preparation for snapshot release. + + * Makefile: + Have 'make dep' delete the *.o and *.s files. + + * catalog.c, hfs.h, TODO, bfind.c: + Move looping from hfs_cat_next() into hfs_bsucc(), + where it can be done an entire node at a time. + +Fri Aug 16 05:02:59 1996 Paul H. Hargrove + + * TODO: + Add AppleShare support to the list of goals. + + * trans.c, super.c, hfs_fs.h, README.sgml: + Add a "names=netatalk" mount option, since + Netatalk quotes initial periods and CAP doesn't. + + * Makefile: + Oops! Had removed the 'include .depend' from Makefile. + + * inode.c, hfs_fs.h, file_nat.c, file_dbl.c, file.c, dir_nat.c, + dir_dbl.c, dir_cap.c, dir.c, README.sgml: + Update for 2.0.1 and newer kernels. + + * Makefile: + Get rid of ifeq stuff and use a .tmpdepend file to make sure + a failed 'make depend' doesn't allow a 'make hfs.o'. + +Wed Aug 14 01:03:01 1996 Paul H. Hargrove + + * version.c, README.sgml: + Bump version up to "pre-0.7-3" in preparation for snapshot release. + + * btree.c, extent.c, bnode.c: + Fix up some debugging code. + +Tue Aug 13 12:42:12 1996 Paul H. Hargrove + + * version.c, README.sgml: + Bump revision to "pre-0.7-2". + + * super.c, sysdep.c, mdb.c, file_nat.c, inode.c, file_cap.c, + file_dbl.c, file.c, extent.c, dir.c, catalog.c, btree.c, bnode.c, + balloc.c: + Added the remaining missing function comments. + + * Makefile, README.sgml: + Simplify the default make rule to build the dependency file AND hfs.o. + Change the installation instructions to reflect the change. + + * hfs.h: + Added missing structure comments. + + * bdelete.c: + Merge bdelete_brec() back into hfs_bdelete(). + Add missing function comments. + + + * extent.c: + Insignificant code change removing an unneeded indirection. + + * btree.c, hfs_btree.h, balloc.c, bnode.c: + Add a 'sys_mdb' field to (struct hfs_btree). + + * extent.c, hfs_sysdep.h, sysdep.c, bnode.c, balloc.c, bfind.c, + Makefile: + Move hfs_buffer_read() from hfs_sysdep.h to sysdep.c so it can use + the symbol HFS_SECTOR_SIZE rather than the manifest constant 512. + Have hfs_buffer_read() print an error message, + and remove redundant errors from the callers. + + * hfs_sysdep.h, mdb.c, super.c, file.c, hfs.h, hfs_btree.h, catalog.c, + extent.c, btree.c, balloc.c, bfind.c, bnode.c: + Get rid of the type hfs_device and the fields of that type, + using the type hfs_sysmdb and the 'sys_mdb' field in its place. + + * Makefile: + Fix definition of HDRS variable. + + * README.sgml, version.c: + Bump version up to "pre-0.7-1". + + * Makefile: + Separate sources and headers into three groups: + B-tree code, HFS code and Linux code. + + * bitmap.c, bitops.c, hfs.h, hfs_sysdep.h, balloc.c: + Implemented portable set of bit operations in hfs_sysdep.h + + * mdb.c, hfs_sysdep.h, hfs_btree.h, extent.c, btree.c, bitmap.c, + bnode.c, balloc.c: + Implement a portable set of buffer operations in hfs_sysdep.h + + * TODO: + Remove note about separating header files into two parts. + + * catalog.c: + Remove call to hfs_mdb_dirty(), since the hfs_brec_relse() does it. + + * hfs.h, extent.c, file.c: + Move hfs_getblk() from extent.c to file.c, since that is now the + only file that actually uses it. + + * balloc.c: + Replace use of hfs_getblk() in balloc.c with a local function + (get_new_node()) that doesn't retry, since B-trees can't shrink. + + * hfs.h, hfs_btree.h, hfs_sysdep.h, mdb.c, extent.c: + Make hfs_buffer a typedef. + + * inode.c, hfs.h, hfs_sysdep.h, dir.c: + Change hfs_sysentry to a typedef. + Rename 'sysentry' field of (struct hfs_cat_entry) to 'sys_entry'. + + * super.c, mdb.c, catalog.c: + Rename hfs_cat_sync() to hfs_cat_commit() and call it + from hfs_mdb_commit() rather than from hfs_write_super(). + + * catalog.c, file.c: + Minimize the calls to hfs_mdb_dirty(). Now called when: + 1) A buffer holding a volume bitmap block is dirtied. + 2) A dirty B-tree node is written back to the buffers. + 3) A dirty catalog entry is written back to the buffers. + + * hfs_sysdep.h, hfs.h: + Make hfs_sysmdb a typedef. + +Sun Aug 11 08:46:10 1996 Paul H. Hargrove + + * hfs_sysdep.h, extent.c, hfs.h: + Replace hfs_mdb_{lock,unlock} with more portable + scheme using a wait queue in the MDB. + + * hfs.h, hfs_btree.h, hfs_sysdep.h, bnode.c, catalog.c, binsert.c: + Make hfs_wait_queue a typedef'd pointer to a (struct wait_queue). + Rename hfs_wait_on() to hfs_sleep_on(). + + * catalog.c, hfs_sysdep.h, super.c, bfind.c, bnode.c, balloc.c: + Implemented hfs_dev_name() in hfs_sysdep.h + as a portable call to produce a device name. + + * super.c, hfs.h, mdb.c: + Rename hfs_mdb_read() to hfs_mdb_get(), and don't take a + 'sys_mdb' argument. That's the callers responsibility. + + * sysdep.c, Makefile: + Remove the pointless file sysdep.c + + * README.sgml: + Clean up the "System Requirements" section. + +Sat Aug 10 22:41:24 1996 Paul H. Hargrove + + * sysdep.h, sysdep.c, super.c, hfs_sysdep.h, mdb.c, string.c, + hfs_fs.h, hfs_fs_i.h, hfs_fs_sb.h, hfs_btree_private.h, hfs_btree.h, + file_cap.c, file_dbl.c, file_nat.c, hfs.h, file.c, dir_nat.c, + extent.c, dir.c, dir_cap.c, dir_dbl.c, catalog.c, bnode.c, brec.c, + btree.c, binsert.c, bitmap.c, bitops.c, bfind.c, bins_del.c, + Makefile, balloc.c, bdelete.c: + Includes the hfs.h that was missing from the previous check in. + MAJOR include-file cleanup: + hfs_btree.h merged into hfs.h + hfs_btree_private.h renamed hfs_btree.h + sysdep.h renamed hfs_sysdep.h + Fixed some minor portability fixes shown up by the header split. + + * README.sgml: + Add instructions for a dealing with a missing linux/version.h + + * hfs_fs.h, mdb.c, string.c, catalog.c, extent.c, btree.c, bitmap.c, + bitops.c, bnode.c, brec.c, bins_del.c, binsert.c, bdelete.c, bfind.c, + balloc.c: + Major split of hfs_fs.h into Linux-specific + part (hfs_fs.h) and HFS-specific part (hfs.h). + + * file.c, extent.c: + Move hfs_getblk() from file.c to extent.c + + * sysdep.h, super.c, mdb.c, hfs_fs_sb.h, hfs_fs.h, file.c, extent.c, + catalog.c, bnode.c, bitmap.c: + Make the field 's_mdb' in (struct hfs_sb_info) a pointer to + the MDB, rather than the actual MDB. This allowed the definition + of (struct hfs_mdb) to be moved from hfs_fs_sb.h to hfs_fs.h. + + * ccache.c, hfs_fs.h, Makefile, catalog.c: + Merged ccache.c and catalog.c into the latter. + Moved definition of (struct hfs_cat_rec) into catalog.c + + * extent.c: + Oops! Last set of changes didn't compile but they're OK now. + + * hfs_btree.h, hfs_fs.h, mdb.c, ccache.c, extent.c, btree.c: + Move the definition of (struct hfs_raw_extent) inside + extent.c and treat it as simple array of U16's elsewhere. + + * hfs_fs.h, dir_dbl.c, dir_nat.c, ccache.c, catalog.c, dir_cap.c: + Make hfs_cat_next() return the CNID and cdrType of the entry. + Now catalog.c and ccache.c are the only files which + depend on the structure of a catalog record on disk. + + * dir.c, hfs_fs.h, catalog.c: + Replace hfs_cat_new_{file,dir}() with hfs_cat_{create,mkdir}() + which are wrappers for what used to be hfs_cat_create(). + + * hfs_fs.h, mdb.c, super.c, Makefile: + Split super.c into super.c (Linux stuff) and mdb.c (MDB stuff). + + * super.c, hfs_fs_sb.h: + Add the MDB field 'drAtrb' to (struct hfs_mdb) as the field 'attrib'. + + * hfs_fs_sb.h, super.c: + Split hfs_read_super() into hfs_read_super() and hfs_mdb_read(). + + * super.c, hfs_fs_sb.h: + Remove the unneeded 'hs' field from (struct hfs_mdb). + + * TODO: + Remove item about hfs_notify_change() needing to update metadata. + + * inode.c, hfs_fs.h, hfs_fs_sb.h, file_cap.c, file_dbl.c, file_nat.c, + file.c, dir.c: + Add a flags argument to hfs_{cap,dbl,nat}_buildmeta() so that + it only builds the parts that are currently out-of-date. + Call hfs_{cap,dbl,nat}_buildmeta() through hfs_update_meta() + in hfs_notify_change() and hfs_rename() to update the metadata. + + * dir.c: + Make test for normal dir in update_dirs_{plus,minus}() more explicit. + + * inode.c, file_cap.c, file_dbl.c, file_nat.c, dir_dbl.c, dir_nat.c, + file.c, README.sgml, dir_cap.c: + Resolve the "meta-data" vs. "metadata" rivalry in favor of the latter. + + * btree.c: + Simplify some debugging code. + + * hfs_btree_private.h, bnode.c, btree.c, balloc.c: + Put the in-core copy of the header node IN the + B-tree structure rather than just a pointer to it. + + * hfs_btree_private.h, btree.c, bnode.c: + Have hfs_btree_commit() call hfs_bnode_commit() + to commit the header and root nodes. + + * hfs_fs.h, super.c, hfs_btree_private.h, btree.c, hfs_btree.h, + balloc.c: + Change hfs_commit_mdb() to hfs_mdb_commit(). + Make hfs_mdb_commit() call hfs_btree_commit(). + Move code to update B-tree size and extent + from hfs_btree_extend() to hfs_btree_commit(). + Make hfs_btree_extend() call hfs_mdb_commit(). + + * super.c: + Change hfs_commit_super() to hfs_commit_mdb(). + + * btree.c, bnode.c, bfind.c: + Fixed up broken debugging code and error messages. + + * super.c, hfs_btree_private.h, btree.c, hfs_btree.h, bdelete.c, + binsert.c, balloc.c: + Now use write-back caching of B-tree header fields. + + * hfs_fs.h: + Get rid of the add{16,32}() inlines as they are no longer used. + + * hfs_btree_private.h, binsert.c, btree.c, bdelete.c, bfind.c, balloc.c: + All the needed fields of the B-tree header are + now cached for reading, but not yet writing. + + * TODO: + Remove "Implement write count" from TODO list. + + * file.c, super.c, bnode.c: + Implement write count. + + * catalog.c: + Fix directory entry counting in hfs_cat_move(). + + * balloc.c: + Simplify hfs_btree_extend(), since the allocation + request will get rounded up to the clumpsize. + + * extent.c: + Honor clumpsize when allocating blocks to files. + + * file_cap.c, file_dbl.c, file_nat.c, super.c, dir.c, file.c, + ccache.c, catalog.c, balloc.c: + Mark 44 functions in need of commenting. + + * hfs_fs_sb.h, super.c, extent.c, hfs_fs.h, ccache.c, btree.c, balloc.c: + Record clumpsize in allocation blocks rather than 512-byte blocks. + + * sysdep.h, super.c, TODO, balloc.c, hfs_fs_sb.h: + Now updates the backup MDB when a B-tree grows. + + * extent.c: + hfs_extent_free() had test against NULL backward. + The result is that access to a file with extents in the extents + B-tree would result in an infinite loop in hfs_cat_put(). + + * hfs_fs_sb.h, super.c, hfs_fs.h: + Reorganize partition map code to get size of partition + in preparation for dealing with the alternate MDB. + +Fri Aug 9 03:25:13 1996 Paul H. Hargrove + + * Makefile: + Add make rules for README.{ps,info} + + * README, README.sgml, DOC, FAQ, Makefile, .cvsignore, + Merge CHANGES into ChangeLog. + Merge DOC, FAQ and README into README.sgml. + Add make rules for building README.{txt,dvi} + + * BUG_INFO, Makefile: + Added a BUG_INFO script which attempts to collect some useful + information which I'd like to see in every bug report I receive. + + * Makefile, version.c: + Added version.c which contains a version string. + +Thu Aug 8 21:48:24 1996 Paul H. Hargrove + + * trans.c: + Fix Latin-1 -> Macintosh filename mapping to change colons to pipes. + + * trans.c: + Fixed Mac->Latin-1 translation to behave as documented for the + extended 8-bit characters without corresponding Latin-1 characters. + + * inode.c, super.c, file.c, hfs_fs_i.h, hfs_fs_sb.h, DOC: + Added a conv={binary,text,auto} mount option similar to that of the + msdos, hpfs and iso9660 filesystems, but applying only to data forks. + As compared to those filesystems, HFS has the advantage that only a + single CR need be converted to a NL, rather than a CR/NL sequence, so + it is quite safe to seek in the file. + Additionally the 'Type' field is far more reliable indicator of text + files than a file extension. + + * super.c: + Simplified parsing of mount options. + + * super.c: + Oops! The part= mount option was being parsed in octal! + + * TODO: + Remove "case=lower" from the list of goals. + + * super.c, hfs_fs.h, hfs_fs_sb.h, string.c, dir_dbl.c, dir_nat.c, + dir_cap.c, DOC: + Resurrect the case={asis,lower} mount option. + + * dir.c: + Simpler test for "normal" directory in update_dirs_{plus,minus}(). + + * hfs_fs_sb.h, super.c, dir.c, hfs_fs.h, catalog.c, DOC: + Add mount options to specify what Type and Creator will be used for + new files and change the default from NULLs to "????". + +Wed Aug 7 11:32:22 1996 Paul H. Hargrove + + * catalog.c: + In hfs_cat_next() use entry->cnid rather than the key of the initial + brec to identify the end of the directory. + + * README: + Update for pre-0.7 version. + + * hfs_fs.h: + Create versioned module if CONFIG_MODVERSIONS is set in linux/config.h + + * TODO: + Note need for special steps for unaligned accesses on some machines. + + * FAQ: + Added Q0: What is HFS? + Added Q7: Does hfs_fs work w/ 400k and 800k diskettes? + Brought Q6 (about writability) up to date. + Made a few other answers more verbose. + +Tue Aug 6 00:58:46 1996 Paul H. Hargrove + + * Makefile: + Changed 'snapshot' rule to include cvs tag command. + + * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c, ccache.c: + Implemented readers half of dir locking scheme so readdir() should + produce consistent results and count_dir_entries() is not race prone. + + * catalog.c: + hfs_cat_move() was calling hfs_cat_decache() after changing + the key rather than before, corrupting the hash lists. + +Mon Aug 5 14:03:46 1996 Paul H. Hargrove + + * hfs_fs.h, catalog.c: + Implemented the writers half of a locking scheme for directories. + + * inode.c: + Fixed a serious bug in hfs_notify_change() that would allow a chmod() + on directory meta-data and would cause the directory inode (if it was + in memory at the time) to change into a file inode. + + * inode.c: + Fixed a problem with write permissions on directory meta-data. + + * dir_dbl.c, dir_nat.c, dir_cap.c: + hfs_{cap,dbl,nat}_readdir() now return the correct value in the 'd_ino' + field of the dirent for all cases, something I think has always been + done incorrectly until now. + + * dir_nat.c, inode.c, dir_cap.c: + In hfs_{cap,nat}_lookup() take advantage of the + 'file_type' field of (struct hfs_inode_info). + + * TODO: + Removed two accomplished goals (rename() and improved readdir()). + + * inode.c, dir_dbl.c, dir_nat.c, hfs_fs_i.h, dir.c, dir_cap.c: + Rewrite hfs_{cap,dbl,nat}_readdir() to take advantage of hfs_cat_next(). + They now use a uniform 'i_size' for all inodes for a given directory. + This simplifies update_dirs_{plus,minus}() and eliminates the need for + the 'file_size' and 'dir_link' fields of (struct hfs_inode_info). + For the CAP and Netatalk schemes the meta-data directories are now the + last entries rather than coming just after '.' and '..'. This is in + preparation for the day when we can write to the files in those + directories, and ensures that when using 'tar' to copy HFS filesystems + the file or directory will be created before the meta-data is written. + Otherwise we could be stuck writing meta-data and not knowing if it is + for a file or a directory! + + * ccache.c: + Updated count_dir_entries() for new hfs_cat_next(). + + * hfs_fs.h, catalog.c: + hfs_cat{nth,next}() no longer take a 'types' argument, + so they now return all entries. + hfs_cat_next() now uses the ParID of the key to detect + the end of the directory. + hfs_cat_nth() now accepts n=0 as a valid input, requesting the thread. + + * trans.c, string.c, super.c, dir_nat.c, hfs_fs.h, dir.c, dir_cap.c, + dir_dbl.c, catalog.c: + Rename (struct hfs_cname) to the more appropriate (struct hfs_pstr). + + * hfs_fs.h, hfs_btree.h: + Move some constants from hfs_fs.h to hfs_btree.h + + * bdelete.c, hfs_btree.h: + Remove hfs_bdelete_brec() from public B-tree interface. + + * hfs_btree_private.h, hfs_fs.h, btree.c, hfs_btree.h, bnode.c, brec.c, + bfind.c, bins_del.c, binsert.c, balloc.c, bdelete.c, Makefile: + Split B-tree stuff into public and private parts: + brec.c split into bfind.c and brec.c + hfs_btree.h split into hfs_btree.h and hfs_btree_private.c + + * inode.c: + The tests and sets of the HFS_FIL_LOCK bit where all reversed! + + * hfs_fs.h, ccache.c: + Redo some ccache stuff, removing the 'error' field from + (struct hfs_cat_entry) and ensuring that hfs_cat_put() + will not sleep on an uninitialized entry. + +Sun Aug 4 23:43:28 1996 Paul H. Hargrove + + * sysdep.h: + Change swap{16,32}() back to macros since hton[ls]() are functions. + + * hfs_fs.h, ccache.c: + Use only lowest order byte of parent CNID in hashing a catalog key. + + * bdelete.c: + The "improved" bdelete() was TOO paranoid looking for missing parents. + + * ccache.c: + Get rid of pointless swap16const(0). + + * hfs_fs.h, inode.c, extent.c, ccache.c, dir_cap.c, dir_nat.c, + binsert.c, catalog.c: + Store cnid and associated constants in big-endian byte order. + This reduces the number of byte-order swaps required. + + * sysdep.h: + Make swap32() and swap16() inline functions. + + * dir_nat.c, dir_cap.c, dir_dbl.c: + Added hfs_rename() to the inode_operations for normal directories. + + * dir.c, hfs_fs.h: + Added hfs_rename() and cleaned up hfs_{create,mkdir,unlink,rmdir}(). + + * catalog.c: + Added the missing check for moving a directory into itself. + + * catalog.c, ccache.c, hfs_fs.h: + Implement a nearly ideal hfs_cat_move(). + It still needs to prevent moving a directory into itself. + The functions hfs_cat_{create,delete,move}() still need work with + respect to their atomicity (especially vs. readdir). + + * bdelete.c: + Fixed a serious bug in hfs_bdelete_brec() that would yield a corrupted + b-tree when the first record in a bnode was deleted. + Made bdelete() more aggressive when checking for missing parents. + +Sat Aug 3 06:11:50 1996 Paul H. Hargrove + + * btree.c, super.c: + Fixed a problem that caused a kernel oops when no HFS filesystem + is found. + +Wed Jul 24 13:06:12 1996 Paul H. Hargrove + + * catalog.c: + Remove race in hfs_cat_create() that could overflow directory valence. + + * catalog.c: + Fix hfs_cat_create() so the parent directory doesn't get deleted + out from under it. Otherwise we could have created files and + directories in deleted directories. + + * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c, ccache.c: + Redo hfs_cat_{next,nth}() in terms of which entry types to + allow, rather than which to skip. + + * catalog.c: + The function hfs_cat_create() would fail to hfs_cat_put(entry) if + the 'record' argument was invalid or if the 'result' argument was NULL. + + * dir.c: + The functions hfs_{create,mkdir,unlink,rmdir} all failed to + call iput() when their arguments conflicted with a reserved name. + + * catalog.c, hfs_fs_sb.h: + Start over on rename(). Still unfinished. + Fix silly bug in hfs_cat_create() that made it always fail. + + * ccache.c: + Fix byte-order bug in write_entry(). + +Tue Jul 23 12:12:58 1996 Paul H. Hargrove + + * dir_dbl.c, dir_nat.c, hfs_fs.h, dir.c, dir_cap.c: + Remove the macros KEY() and PARENT() since the key is now easy + to access through the catalog entry. + Replace the macros NAME{IN,OUT}() with inline functions + hfs_name{in,out}() to gain type checking of arguments. + + * catalog.c: + Remove the macro TYPE(). + + * inode.c, file_dbl.c, file_nat.c, file.c, file_cap.c: + Remove the #define's of the unused macro KEY(). + + * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c, dir.c: + Replace hfs_lookup_parent() in dir.c with hfs_cat_parent() in catalog.c. + This new function performs locking to protect against rename() changing + the parent during I/O. + It is also intended for use with files as well as directories. + Change hfs_{cap,dbl,nat}_lookup() to use the new function. + + * dir.c, hfs_fs.h, catalog.c: + Remerge hfs_cat_{create,mkdir}() into hfs_cat_create() and resurrect + hfs_cat_new_{file,dir}(). + Fix hfs_cat_{create,delete} to use the improved catalog cache for + locking in place of directory-level create/delete locks. + Fix hfs_{create,mkdir}() to use the new hfs_cat_create(). + + * hfs_fs.h, ccache.c: + Rewrite parts to remove need for specialized create/delete locking. + Use new case-independent hash function. + Fix bug in hfs_cat_get() that would read an entry w/o locking it. + Call hfs_relinquish() before retrying a deleted entry in hfs_cat_get. + If there is a read error, then don't retry in hfs_cat_get(). + Remove unused 'version' field from (struct hfs_cat_entry). + + * sysdep.h: + Add hfs_relinquish(), a system-independent alias for schedule(). + + * hfs_fs.h, string.c: + Add hfs_strhash(), a simplistic case-independent hash function. + + * hfs_fs.h, inode.c: + Make hfs_iget() an inline function. + + * TODO: + Add a few goals and removed those that have been achieved. + + * Makefile: + Add ccache.c to list of source files. + Add rule for *.s files and include them in the 'clean' rule. + +Wed Jul 17 17:22:45 1996 Paul H. Hargrove + + * sysdep.h, trans.c, string.c, super.c, hfs_fs_i.h, hfs_fs_sb.h, + inode.c, hfs_btree.h, hfs_fs.h, file_dbl.c, file_nat.c, extent.c, + file.c, file_cap.c, dir_dbl.c, dir_nat.c, ccache.c, dir.c, + dir_cap.c, btree.c, catalog.c, bnode.c, brec.c, balloc.c: + Total rewrite of the inode-handling stuff to be centered around + a catalog entry cache (ccache.c). This results not only in a far + more sensible way of doing things, but also removed many race + conditions. (The source and object code both got smaller too!) + Many small "undocumented features" were also fixed. + Replace HFS_CNAME with (struct hfs_cname). + rename() has been temporarily abandoned. + +Thu Jul 11 01:14:38 1996 Paul H. Hargrove + + * dir.c: + As written hfs_lookup_parent() had two overlapping read requests + in the catalog tree. This could have led to deadlock. + +Wed Jul 10 09:27:00 1996 Paul H. Hargrove + + * catalog.c, hfs_fs.h, bdelete.c: + More work on getting rename() fleshed out. Still not done. + Before I can finish it looks like I'll need to build a + mechanism for exclusive access to the catalog tree. There + just doesn't seem to be any other way to get proper POSIX + semantics without a bunch of race conditions elsewhere. + + * hfs_fs.h, inode.c, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c: + More work on the still incomplete rename() code. + Merge hfs_cat_add_{dir,file}() into hfs_cat_create(). + Add file-thread support to hfs_cat_{create,delete,rename}. + +Tue Jul 9 09:43:15 1996 Paul H. Hargrove + + * inode.c, dir_dbl.c, dir_nat.c, extent.c, dir_cap.c: + The indirect (struct hfs_file) was causing blocks not to be freed + when files where deleted, and an omission in hfs_put_inode() was + preventing the inode from getting freed. Both are now fixed. + + * hfs_fs.h, dir_dbl.c, dir_nat.c, hfs_btree.h, catalog.c, dir_cap.c, + bdelete.c: + Made unlink() and rmdir() more race resistant and did some more + work on the still incomplete code for rename(). + + * btree.c, bnode.c: + There was a serious race condition in the bnode cache, so + hfs_bnode_find() is now modeled after Linus's inode cache. + +Mon Jul 8 10:33:38 1996 Paul H. Hargrove + + * hfs_fs_i.h, inode.c, file_cap.c, file_dbl.c, file_nat.c, dir_dbl.c, + dir_nat.c, file.c, dir.c, dir_cap.c: + More changes to layout of (struct hfs_inode_info). + + * super.c, inode_cap.c, inode_dbl.c, inode_nat.c, inode.c, hfs_fs_i.h, + hfs_fs_sb.h, file_nat.c, hfs_fs.h, file.c, file_cap.c, file_dbl.c, + Makefile, catalog.c: + Implemented new layout for (struct hfs_inode_info) resulting in the + elimination of lots of duplicated code for hfs_*_write_inode(), + hfs_*_put_inode() and *_open() functions. + Merged inode_*.c files back into inode.c. + Not fully tested. + + * TODO: + Add a few more of my goals to the list. + + * README: + Documentation updates. + + * inode_nat.c, inode_cap.c, inode_dbl.c, inode.c, hfs_fs.h, hfs_fs_i.h, + file.c, file_cap.c, file_dbl.c, file_nat.c, catalog.c: + (struct hfs_file) and metadata are read when file is opened or + truncated and are released by iput(). + +Sun Jul 7 23:55:43 1996 Paul H. Hargrove + + * inode_nat.c, inode_cap.c, inode_dbl.c, inode.c, dir_nat.c, hfs_fs.h, + hfs_fs_i.h, dir_cap.c, dir_dbl.c, catalog.c, dir.c: + (struct hfs_dir) is now inside (struct hfs_inode_info) once again. + + * inode_nat.c, super.c, inode_cap.c, inode_dbl.c, inode.c, file_nat.c, + hfs_btree.h, hfs_fs.h, extent.c, file_cap.c, file_dbl.c, dir_nat.c, + dir_cap.c, dir_dbl.c, btree.c, catalog.c, dir.c, bpath.c, brec.c, + bins_del.c, binsert.c, bnode.c, bfind.c, balloc.c, bdelete.c, + Makefile: + Remerged (struct hfs_bpath) and (struct hfs_brec), merging the + files bfind.c and bpath.c as a resurrected brec.c. + +Sat Jul 6 21:47:05 1996 Paul H. Hargrove + + * inode_cap.c, inode_dbl.c, inode_nat.c, inode.c, hfs_fs.h, hfs_fs_i.h, + file_cap.c, file_dbl.c, file_nat.c, hfs_btree.h, dir_nat.c, extent.c, + dir.c, dir_cap.c, dir_dbl.c, btree.c, catalog.c, bfind.c, bpath.c, + binsert.c, bdelete.c: + Renamed (struct hfs_brec_key) to (struct hfs_bkey). + +Tue May 28 07:53:24 1996 Paul H. Hargrove + + * inode_cap.c, catalog.c: + Spelling fixes. + + * inode_nat.c, super.c, inode_cap.c, inode_dbl.c, inode.c, hfs_fs.h, + hfs_fs_i.h, hfs_fs_sb.h, file.c, file_dbl.c, file_nat.c, dir_dbl.c, + dir_nat.c, extent.c, dir.c, dir_cap.c, catalog.c: + Structures got too big, so I had to add a layer of indirection + to (struct hfs_inode_info). + This means we must clear_inode() in inode_put(). + +Mon May 27 01:32:42 1996 Paul H. Hargrove + + * catalog.c, file_cap.c: + Some sizeof() stuff now uses variable not type. + + * hfs_fs.h: + Make HFS_I() and HFS_SB() inline to gain type checking. + +Sun May 26 13:34:17 1996 Paul H. Hargrove + + * dir_nat.c: + Oops. Had left some debugging printk()s in place. + + * file_dbl.c, file_nat.c, file_cap.c: + Cleaned up variable names for consistency. + + * hfs_fs_sb.h: + Add a couple 'const's to function typedefs. + + * hfs_fs.h: + Add and update function prototypes. + Cleaned up type names. + Fix debugging malloc code. + Add hfs_iget_by_name() as an inline function. + + * sysdep.h: + Remove extra semicolon from macro definitions. + + * super.c: + Use new hfs_iget_by_name() to get root inode. + + * extent.c: + Cleaned up some variable naming for consistency. + + * catalog.c: + Added (untested) code for hfs_cat_move_file(). + + * catalog.c: + Fix one missed call to hfs_cat_build_key(). + Make hfs_cat_add_{file,dir}() take a cat_entry as an argument. + Add hfs_cat_new_{file,dir}() to generate new cat_entry's. + + * dir_dbl.c, dir_nat.c, dir.c, dir_cap.c: + Cleaned up type and variable names. + Updated calls to hfs_cat_build_key() and NAMEOUT() + Use new hfs_iget_by_*() calls. + + * inode_cap.c, inode_dbl.c, inode_nat.c: + Cleaned up type and variable names. + + * inode.c: + Update calls to hfs_cat_build_key(). + Cleaned up type and variable names. + Implemented a hierarchy of hfs_iget_by*() calls. + + * catalog.c: + Change hfs_cat_build_key() to take a HFS_CNAME as input. + + * btree.c: + Initialize lsize and psize fields of file. + + * trans.c: + Now passes type HFS_CNAME and has name/len in "normal" order. + +Tue May 21 07:02:34 1996 Paul H. Hargrove + + * bnode.c: + Attempt to read invalid bnode would have led to an infinite loop under + certain circumstances. One way to cause this was with an invalid + partition table which points beyond the end of the device. + +Sat May 11 12:38:42 1996 Paul H. Hargrove + + * sysdep.h, sysdep.c, inode_dbl.c, inode_nat.c, super.c, inode_cap.c, + inode.c, hfs_fs.h, hfs_fs_i.h, hfs_fs_sb.h, file_dbl.c, file_nat.c, + hfs_btree.h, extent.c, file.c, file_cap.c, dir_nat.c, dir.c, + dir_cap.c, dir_dbl.c, btree.c, catalog.c, bitmap.c, bitops.c, + bnode.c, bfind.c, bins_del.c, binsert.c, balloc.c, bdelete.c: + Another big wave of portability-oriented changes. + +Tue May 7 11:28:35 1996 Paul H. Hargrove + + * super.c, sysdep.c, sysdep.h, inode_cap.c, inode_dbl.c, inode_nat.c, + hfs_fs_i.h, inode.c, file_nat.c, hfs_btree.h, hfs_fs.h, file.c, + file_cap.c, file_dbl.c, dir_nat.c, extent.c, dir_cap.c, dir_dbl.c, + btree.c, catalog.c, dir.c, bnode.c, bpath.c, binsert.c, bitmap.c, + bitops.c, bdelete.c, bfind.c, bins_del.c, Makefile, balloc.c: + Start a big move to abstract all the Linux-specific stuff + out of the lower levels. Created sysdep.[ch] to hold it. + + * FAQ, TODO: + Bring some documentation up-to-date. + +Fri May 3 20:15:29 1996 Paul H. Hargrove + + * super.c, inode_dbl.c, inode_nat.c, inode.c, inode_cap.c, extent.c, + hfs_fs.h, hfs_fs_i.h, dir_dbl.c, dir_nat.c, catalog.c, dir.c, + dir_cap.c, bpath.c, btree.c, binsert.c, bnode.c: + "FID reform": 'fid' became 'cnid' (Catalog Node ID), and is now + a field in (struct hfs_file). The new name is more consistent + with Apple's documentation. The presence of 'cnid' in (struct + hfs_file) help move more of the code toward OS-independence. + + * inode_nat.c, super.c, trans.c, inode.c, inode_cap.c, inode_dbl.c, + hfs_fs.h, file_cap.c, file_dbl.c, file_nat.c, dir_nat.c, extent.c, + file.c, dir.c, dir_cap.c, dir_dbl.c, btree.c, catalog.c, bnode.c, + bpath.c, bins_del.c, binsert.c, bitmap.c, bitops.c, bdelete.c, + bfind.c, balloc.c: + A lot of changes in what headers are included and in what order. + +Sat Apr 27 12:28:54 1996 Paul H. Hargrove + + * FAQ: + Updated for current writability status. + + * .cvsignore: + Added ChangeLog. + + * file_dbl.c, file_nat.c, file_cap.c, file.c, dir_dbl.c, dir_nat.c, + dir_cap.c: + Added the default fsync() to all file_operations structures. + + * dir_nat.c, hfs_fs.h, dir.c, dir_cap.c, dir_dbl.c: + Add rmdir() for normal directories. + + * binsert.c: + I had messed up insertion so that is would sometime fail to + split the root, but its OK now. + + * dir.c: + hfs_do_unlink() decremented directory counts rather than file counts. + +Wed Apr 24 13:20:08 1996 Paul H. Hargrove + + * hfs_fs.h, bnode.c, hfs_btree.h: + Fixed a couple more type size assumptions. + + * hfs_fs.h, balloc.c, bitmap.c, bitops.c: + "Portable" bitmap handling was wrong for just about everything but + the i386 and the "inverse big-endian" bit ordering that I thought + the m68k port was using. It seems the m68k port is now using standard + big-endian bit-numbering conventions. + This code is now correct for the standard big- and little-endian bit + orderings. (which should cover all Linux systems?) + Also no longer assumes sizeof(long) == 4, though that might still be + a problem in other parts of the code. + +Tue Apr 23 19:19:27 1996 Paul H. Hargrove + + * FAQ: + Bring uptodate for this snapshot. + + * Makefile: + Add FAQ to $(MISC) + + * README, TODO: + Documentation updates. + + * bdelete.c: + Spelling fixes. + + * dir_cap.c: + In unlink() don't force metadata into memory if not present. + + * bdelete.c: + Some function comments and some clean up. + + * bins_del.c: + Added missing function comment for hfs_bnode_update_key(). + + * binsert.c, bitmap.c: + Spelling and grammar corrections to comments. + + * hfs_btree.h, hfs_fs.h, bins_del.c, binsert.c, Makefile, bdelete.c: + Clean up of hfs_bdelete(), splitting bins_del.c into three files: + bins_del.c, binsert.c and bdelete.c + + * bpath.c, bins_del.c: + hfs_bdelete() is now working "correctly", but needs some cleaning up. + +Mon Apr 22 05:35:41 1996 Paul H. Hargrove + + * hfs_fs.h, bpath.c, hfs_btree.h, bins_del.c, bnode.c, balloc.c, + bfind.c: + Rewrite bnode handling, heading toward a more write-behind approach. + Have done away with HFS_LOCK_BLIND. + + * inode_dbl.c, inode_nat.c, extent.c, hfs_fs_i.h, inode_cap.c: + Was trying to truncate resource fork of directories! + +Sun Apr 21 08:15:43 1996 Paul H. Hargrove + + * balloc.c: + Updated to use truncate() to grow full trees. + + * extent.c, hfs_fs.h, file.c, inode.c: + Added truncate() for normal files. + + * bins_del.c: + hfs_bdelete() fixes for handling removal of root. + + * inode_cap.c, inode_dbl.c, inode_nat.c: + Release storage for deleted files in hfs_*_put_inode(). + + * bitmap.c: + Make len=0 valid for hfs_{set,clear}_vbm_bits(). + + * super.c, inode.c, hfs_fs_i.h, hfs_fs_sb.h, btree.c, balloc.c: + Changed from clumpsize to clumpblks. + + * inode_nat.c, hfs_fs.h, inode_cap.c, inode_dbl.c, btree.c, extent.c, + balloc.c: + Some extent-related changes in preparation for truncate() support. + +Sat Apr 20 10:59:13 1996 Paul H. Hargrove + + * inode_nat.c, hfs_fs_i.h, inode.c, inode_cap.c, inode_dbl.c, + dir_nat.c, hfs_fs.h, dir.c, dir_cap.c, dir_dbl.c: + Removed dir.valence from hfs inode. + Added unlink(), but still need truncate() and some more support + in hfs_*_put_inode() to free the disk space used by deleted files. + + * bnode.c: + Check for NULL bnode in hfs_bnode_relse(). + + * bins_del.c: + Fixed a byte-order problem in bdelete_nonempty(). + + * hfs_fs.h, bnode.c, bpath.c, hfs_btree.h, balloc.c, bins_del.c: + First attempt at hfs_bdelete(). + + * dir.c: + The Finder would display strange things if it couldn't set frView. + Therefore initialize frView field for new directories. + + * file_cap.c, file_dbl.c, file_nat.c, hfs_fs.h: + Define User/Finder info fields of catalog entry in more detail. + + * hfs_fs.h: + HFS_BFIND_DELETE should require exact match. + + * dir.c: + Set "record in use" bit of filFlags for new files. + + * inode.c: + Was doing the wrong thing with i_ctime. + + * dir_nat.c, dir_cap.c, dir_dbl.c: + Added some missing updates to the inode in hfs_*_{create,mkdir}(). + +Sun Apr 14 00:10:52 1996 Paul H. Hargrove + + * hfs_fs.h, file_dbl.c, file_nat.c, file.c: + Work around the ever-changing type of f_reada. + +Sat Apr 13 00:43:41 1996 Paul H. Hargrove + + * bpath.c, bfind.c: + Spelling corrections in comments. + + * bins_del.c: + ifdef out shift_left() until it is actually used. + + * hfs_btree.h, hfs_fs.h, bins_del.c, bpath.c, bfind.c: + Cleaned up code related to 'flags' argument to hfs_bpath_find(). + +Fri Apr 12 23:30:01 1996 Paul H. Hargrove + + * bpath.c: + Updated comments. + Rewrote hfs_bpath_init() and hfs_bpath_next(). + + * hfs_btree.h: + Updated prototype for hfs_bpath_init(). + + * bins_del.c: + Updated call to hfs_bpath_init(). + + * inode.c, inode_cap.c, inode_dbl.c, inode_nat.c, extent.c, file_cap.c, + file_dbl.c, file_nat.c, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c, + dir.c: + Renamed hfs_brec_relse() to hfs_brelse(). + + * hfs_fs.h, hfs_btree.h: + Updated prototypes to reflect new names in bpath.c + + * bins_del.c: + Updated calls to functions in bpath.c + Updated comments. + + * Makefile: + Renamed brec.c to bpath.c + + * bfind.c: + Updated calls to functions in bpath.c + Added hfs_brelse() which was previously hfs_brec_relse() in brec.c + + * bpath.c: + brec.c renamed to bpath.c + Functions renamed to reflect their current actions. + Comments are still out of date. + hfs_brec_relse() renamed to hfs_brelse() and moved to bfind.c + + * brec.c: + brec.c renamed to bpath.c + +Wed Apr 10 07:20:28 1996 Paul H. Hargrove + + * hfs_fs.h, extent.c, hfs_btree.h, brec.c, dir.c, bfind.c, + bins_del.c: + Backed-out changes to hfs_binsert() that added the ability to + return the new record, since it will probably not ever be needed. + + * extent.c: + Since 1.3.45 truncate() has locked the file, so there is no need + for all the things I've been doing to hfs_file_extend() & new_extent(). + Those two functions have been cleaned up a bit (similar to older forms). + + * extent.c: + hfs_file_extend() now more "robust", but new_extent() is still + not fully "concurrency safe." + +Tue Apr 9 09:01:18 1996 Paul H. Hargrove + + * bins_del.c: + Made split() inline. + + * inode.c, dir_nat.c, hfs_fs.h, dir_cap.c: + Added hfs_itry() to get in-core inodes. + + * inode_dbl.c, inode_nat.c, hfs_fs.h, inode.c, inode_cap.c, file_dbl.c, + file_nat.c, hfs_btree.h, extent.c, file_cap.c, dir_cap.c, dir_dbl.c, + dir_nat.c, brec.c, catalog.c, dir.c, bins_del.c, bnode.c, + bfind.c: + Rewrite of all the (struct hfs_brec) stuff. + +Mon Apr 8 21:50:01 1996 Paul H. Hargrove + + * btree.c, extent.c, bnode.c: + Fixed format strings in a few debugging printk()'s. + + * brec.c, hfs_fs.h: + Removed hfs_brec_relse_one(). + + * hfs_fs.h, bnode.c, brec.c, hfs_btree.h, bfind.c, bins_del.c, balloc.c: + (struct hfs_bnode_ref)s are now returned by value rather than reference + and they are in (struct hfs_brec) rather than pointed to. Cuts down on + a lot of kmalloc() and kfree() traffic. + + * hfs_fs.h, dir.c, extent.c, bins_del.c: + Modified hfs_binsert() to be able to return the new record. + + * bins_del.c, hfs_btree.h: + Added shift_left(), still untested. + + * bins_del.c: + new_root() was missing its comment. + + * super.c, trans.c, hfs_fs_i.h, inode.c, inode_dbl.c, inode_nat.c, + file_nat.c, hfs_btree.h, hfs_fs.h, file.c, file_dbl.c, dir_dbl.c, + dir_nat.c, extent.c, dir.c, dir_cap.c, bitops.c, bnode.c, brec.c, + bfind.c, bins_del.c, bitmap.c, balloc.c: + Fixed lines over 80 characters and tabified files. + + * bins_del.c: + Fixed line(s) over 80 columns. + + * trans.c, inode_nat.c, string.c, super.c, inode.c, inode_cap.c, + inode_dbl.c, hfs_fs_i.h, hfs_fs_sb.h, hfs_btree.h, hfs_fs.h, file.c, + file_cap.c, file_dbl.c, file_nat.c, dir_dbl.c, extent.c, btree.c, + dir_cap.c, bitops.c, bnode.c, brec.c, bfind.c, bins_del.c, bitmap.c, + DOC, README, TODO, balloc.c, CHANGES: + About 150 spelling corrections. + +Sun Apr 7 23:14:28 1996 Paul H. Hargrove + + * dir_cap.c, dir_dbl.c, dir_nat.c, dir.c: + Cleaned-up check for special names in mkdir(). + + * extent.c: + More verbose error message. + + * inode_dbl.c, inode_nat.c, hfs_fs_i.h, inode.c, inode_cap.c, dir.c, + hfs_fs.h: + Limit directories to 32767 entries, since Mac uses 16-bit integer. + +Fri Apr 5 07:27:57 1996 Paul H. Hargrove + + * FAQ: + Initial version. + + * dir_dbl.c, dir_nat.c, bins_del.c, dir.c, dir_cap.c: + Added missing function comments. + +Wed Apr 3 06:38:36 1996 Paul H. Hargrove + + * brec.c: + Cleaned-up code for brec->flags. + + * extent.c: + Added function comments. + + * bins_del.c: + Added function comments. + hfs_binsert() was incrementing record count even on failure. + +Mon Apr 1 08:35:51 1996 Paul H. Hargrove + + * extent.c: + Rewrote find_ext() and new_extent() for new hfs_btree_extend(). + Moved hfs_btree_extend() to balloc.c + Fixed potential kernel OOPS in new_extent(). + + * brec.c: + Fixed potential kernel OOPS in hfs_brec_get_root(). + Removed hfs_brec_find_first(). + Fixed return value of hfs_brec_find(). + + * bins_del.c: + Updated call to hfs_btree_extend(). + + * balloc.c: + Merged hfs_bnode_add() and hfs_btree_extend() into the later. + Commented init_mapnode(). + + * bfind.c: + Removed hfs_bfind_first(). + + * hfs_fs.h, hfs_btree.h: + Updated prototypes. + +Sat Mar 30 22:56:47 1996 Paul H. Hargrove + + * CHANGES, README, TODO: + Updated documentation in preparation for 0.6 release. + + * inode.c, hfs_fs.h: + Got rid of HFS_FAKE_EXEC in favor of noexec mount option. + + * inode.c, super.c, DOC, hfs_fs_sb.h: + Added "quiet" mount option, like the fat filesystem. + + * inode.c, dir_cap.c, dir_nat.c: + Pseudo-directories are read-only (at least for now). + + * hfs_fs.h, dir_dbl.c, dir_nat.c, dir.c, dir_cap.c: + mkdir() updated to check against reserved names, but the + AppleDouble scheme still has problems with names starting with '%'. + + * dir_dbl.c, dir_nat.c, hfs_fs.h, dir.c, dir_cap.c: + Added mkdir(). (It only took 2 tries to get it right!!) + Only works in "normal" directories and doesn't yet stop + one from creating dirs with the reserved names. + + * brec.c, extent.c, bins_del.c: + Now have a way to get an EEXIST back from hfs_binsert(). + + * btree.c, inode.c, hfs_fs_i.h, file.c, bfind.c, bnode.c, balloc.c: + Added 'dev' field to struct hfs_file. + + * hfs_fs_i.h, inode.c, btree.c, extent.c, file.c, bnode.c, brec.c, + balloc.c: + Removed duplicated fields from struct hfs_file since + even B*-trees now have that information in the inode. + + * extent.c: + zero_blocks() neglected allocation block size in computing start. + +Fri Mar 29 16:04:37 1996 Paul H. Hargrove + + * super.c: + hfs_statfs(): f_files and f_ffree fields are now -1, which is + documented as the value for "undefined" fields in struct statfs. + + * trans.c, inode_nat.c, string.c, super.c, inode_dbl.c, inode_cap.c, + inode.c, file_nat.c, file_dbl.c, file_cap.c, file.c, dir_dbl.c, + extent.c, dir_cap.c, catalog.c, btree.c, brec.c, bnode.c, bitops.c, + bitmap.c, bins_del.c, balloc.c: + Stylistic editing: {} for all 'for', 'while' and 'if' blocks. + I hope I didn't screw-up anything. + + * hfs_fs.h, dir.c, dir_cap.c, dir_dbl.c, dir_nat.c: + Added creation of normal files to all three fork schemes! + Strange things may happen when trying to create "non-normal" files. + + * brec.c: + Cleaned up some debugging code. + + * hfs_fs_i.h: + File and directory counts could have overflown 16-bit integer. + + * hfs_btree.h: + Added HFS_BREC_RIGHT to help fix insertion problem. + + * extent.c: + Various fixes to hfs_{file,btree}_extend(). + + * catalog.c: + Made hfs_build_cat_key() more "correct". + + * btree.c: + Added and fixed debugging code. + + * brec.c: + Fixed overflow detection. + Added some debugging code. + + * bnode.c: + Dirtied some buffers in places that might have been missed. + Fixed some debugging code that had broken. + + * bitops.c: + hfs_count_free_bits() was running off end of bitmap. + + * bins_del.c: + Fixed various bugs, mostly related to variable-length keys. + + * balloc.c: + Had forgotten to set a bit in new mapnodes. + Node counts were overflowing 16-bit integers. + + * bitmap.c: + Oops! clear/set did opposite operation on full words. + +Wed Mar 27 10:59:07 1996 Paul H. Hargrove + + * hfs_fs_i.h: + Updated struct hfs_extent for concurrent access. + Also caused a slight modification to struct hfs_file. + + * hfs_fs.h, hfs_btree.h: + Added/updated prototypes. + + * balloc.c: + hfs_bnode_alloc() finished but still untested. + + * bins_del.c: + Fixed up deadlock avoidance in hfs_binsert() again. + Perhaps I even got it right this time. + + * extent.c: + hfs_file_extend() now safe under concurrent operations? + + * file.c: + hfs_getblk() now safe under concurrent operations? + +Tue Mar 26 23:26:35 1996 Paul H. Hargrove + + * btree.c: + Added call to hfs_extent_trim() to fix memory leak. + + * extent.c: + Oops, had left a "#define static" in from debugging. + + * bins_del.c: + hfs_binsert() rewritten to avoid deadlock when extending + the extents B*-tree. + + * btree.c: + Moved hfs_btree_extend() to extent.c + + * inode_nat.c, inode_cap.c, inode_dbl.c: + hfs_*_put_inode() rewritten to call hfs_extent_trim(). + + * extent.c: + Big rewrite for new struct hfs_extent: + Now keep linked list of extents. + Cache is now a pointer to a list element. + Now have 'end' field to aid decode_extent(). + New functions: + hfs_extent_trim(): frees linked list. + hfs_btree_extend(): for extending B*-trees. + Improved debugging output. + + * balloc.c: + Added hfs_bnode_add() (incomplete and uncommented). + + * btree.c: + Moved some work from hfs_btree_extend() to hfs_bnode_add(). + + * bfind.c: + Added hfs_bfind_first() as wrapper for hfs_brec_find_first(). + + * brec.c: + Added hfs_brec_find_first() to search first leaf node. + + * bins_del.c: + Added error returns to hfs_binsert() and binsert(). + + * bins_del.c: + Check to see that we really need ancestors before starting. + Check that hfs_btree_alloc() gave us enough nodes. + binsert() uses info precomputed by hfs_binsert(). + +Mon Mar 25 11:33:53 1996 Paul H. Hargrove + + * bnode.c: + Collected together the error returns in hfs_bnode_lock(). + + * Makefile: + Added ChangeLog to $(MISC). + +Wed Mar 20 19:41:45 1996 Paul H. Hargrove + + * super.c, hfs_fs.h, file.c, dir_dbl.c, dir_nat.c, dir.c, dir_cap.c: + Removed support for kernels older than about 1.3.70 + Most of that support had been broken recently anyway. + + * super.c: + Fixed so DEBUG_MEM works w/o DEBUG_ALL. + Updated call to hfs_btree_init(). + + * hfs_fs.h: + Updated/added prototypes. + + * hfs_btree.h: + HFS_BFIND_CHAIN removed. + struct hfs_brec gets new 'flags' field with bits: + HFS_BREC_{FIRST,OVERFLOW,UNDERFLOW,UNINITIALIZED} + Removed bitmap size constants. + Changes to struct hfs_btree: + 'file' and 'cache' now structs rather than pointers. + Added 'reserved' field (used during insertion). + Added pointers to size and extent in MDB. + + * file.c: + Made hfs_getblk() public. + Removed (fil->inode == NULL) special cases. + + * extent.c: + {find,update}_ext() are no longer inline. + new_extent() fails when called for the extents tree; + previously it would hanging calling hfs_binsert(). + extend_file(): + renamed to hfs_file_extend() and made public. + fixed to work for B*-trees. + zeros-out blocks as they are allocated. + fixed bugs for (allocation block) != (physical block). + + * btree.c: + hfs_btree_{init,free}() modified for changes to struct: + 'file' and 'cache' moved back into structure + file.inode initialized to reduce special cases + hfs_btree_init() gets pointer to size in MDB instead of size. + Added hfs_btree_extend() (incomplete and uncommented). + + * bnode.c: + hfs_bnode_{alloc,free}() moved to separate file. + Removed 'const' from some function arguments + due to change in struct hfs_btree. + hfs_bnode_lock(): added WRITE/RESRV->READ transition. + + * brec.c: + hfs_brec_get_{root,child}() now take a 'keep_mask' argument + indicating when to keep ancestor nodes, and store + information about why ancestors were kept. + HFS_BFIND_CHAIN eliminated in favor of HFS_BFIND_{INSERT,DELETE} + which are now implemented using 'keep_mask'. + Added hfs_brec_relse_one() that doesn't release ancestors. + + * bins_del.c: + Lots of rewrites to cleanup insertion. + Now tries to extend tree before insertion starts. + binsert() iterative rather than recursive. + No point in keeping track as it is still not "stable". + + * balloc.c: + New file: started with hfs_bnode_{free,alloc}() + Added hfs_bnode_init() to initialize a newly allocated bnode. + hfs_bnode_free(): + Renamed hfs_bnode_bitop(). + Can set or clear a specified bit. + Gets bitmap sizes from nodes directly. + hfs_bnode_alloc(): + Returns actual node, calling hfs_bnode_init(). + Gets bitmap sizes from nodes directly. + + * bfind.c: + Removed obsolete comment from hfs_bsucc() + Removed 'const' from tree arg of hfs_bfind() + due to changes in struct hfs_btree. + + * Makefile: + Added new file: balloc.c + +Sat Mar 9 22:03:53 1996 Paul H. Hargrove + + * Start of detailed CVS logging. + +Mar 09, 1996: snapshot-09Mar96 hargrove@sccm.stanford.edu (Paul H. Hargrove) + NOT AN OFFICIAL RELEASE + Fixed up debugging code that was broken by split of btree.c + Added debugging kmalloc/kfree + Fixed memory leak in hfs_bnode_relse() + +Mar 08, 1996: snapshot-08Mar96 hargrove@sccm.stanford.edu (Paul H. Hargrove) + NOT AN OFFICIAL RELEASE + now reset blocksize on device when done. + hfs_binsert done (except for the full tree case). + btree.c split up into manageable pieces (need to sort out hfs_btree.h) + +Feb 26, 1996: snapshot-26Feb96 hargrove@sccm.stanford.edu (Paul H. Hargrove) + NOT AN OFFICIAL RELEASE + Some writability. + Bug with multiple opens of meta data fixed. + Netatalk support no longer considered experimental. + +Virtually everything has changed, so I've lost track here. + +Nov 16, 1995: snapshot-16Nov95 hargrove@sccm.stanford.edu (Paul H. Hargrove) + NOT AN OFFICIAL RELEASE + Still more comments. + btree.c back to 80 columns. will do same to other files soon. + Starting with btree.c have begun to put file contents into some + sort of standard order. + Moved metadata reading to VFS open() routine and now free it in + the VFS release() routine. Much cleaner than the old way. + Unified hfs_iget by shifting scheme-dependent code into a function + pointer in the superblock. This could/should be shifted to + a VFS read_inode() routine if that can be done cleanly. + Probably lots of other changes; I've lost track. + +Nov 05, 1995: version 0.5.3 hargrove@sccm.stanford.edu (Paul H. Hargrove) + NOT AN OFFICIAL RELEASE + 1.2.x compatibility removed + Added lots of comments to btree.c and cleanup some code. The result + is that the source file doubled in size while the object + file dropped in size by 20%. + Added some comments to super.c and dir.c as well. + Cleaned up some stuff in dir.c adding some additional error checking + and moving closer to using a unified hfs_iget by migrating + common code into lookup_parent(). + Changed btree.c to use a separate bnode cache per filesystem. + Renamed a bunch of the bnode functions in btree.c + +Jun 29, 1995: version 0.5.2 hargrove@sccm.stanford.edu (Paul H. Hargrove) + BUG FIX and 1.3.x-compatibility release. + Will compile under 1.2.x or 1.3.x by changing one line in Makefile. + Started adding magic numbers to structures for "safety". + Don't strip internal symbols when linking or loading, as this made + good bug reports rather difficult. + Fixed a bug that could cause the fs to lock-up after trying to open + a non-existent file. + Fixed a bug that allowed files to appear truncated, when in fact it + is still not possible to truncate a file. + Added more/better comments to header files. + Deal with volume and b-tree bitmaps in preparation for writing. + Fixed readdir() to deal properly with the case where the directory + changes while writing to user-space. (which can't yet + actually happen, until directories are writable). + +Jun 23, 1995: version 0.5.1 hargrove@sccm.stanford.edu (Paul H. Hargrove) + BUG FIX RELEASE + Removed two debugging messages that didn't belong. + Fixed a typo that prevented modified inodes from being written to disk. + Added a missing line which prevented rmmod'ing sometimes. + Added a missing line which caused errors when modifying .finderinfo or + .resource under the CAP system. + Added a notify_change() to keep mode bits sensible, and to cause + changes to an inode to affect the data fork and resource fork + of a file together. + +Jun 22, 1995: version 0.5 hargrove@sccm.stanford.edu (Paul H. Hargrove) + Fixed a bug that was giving wrong values for i_blocks + Partly writable (can only 'touch' existing files, so far) + Removed case= mount option. It will be back eventually. + Can now deal with CDROMs (and hard disks?), many thanks to + Holger Schemel for this work. + Latin-1 filename conversion also due to Holger Schemel. + Rewritten btree operations. + +Feb 28, 1995: version 0.4 hargrove@sccm.stanford.edu (Paul H. Hargrove) + Requires Linux >= 1.1.94: depends on changes made to asm/byteorder.h + Now using string comparison code donated by ARDI (see string.c) + Code reorganized to use data structures more like ARDI's. + More code reorganization to abstract the btree operations. + Added the fork= mount option. + Added AppleDouble support. Executor, from ARDI, can now run programs + from HFS filesystems mounted w/ the HFS module. + +Jan 28, 1995: version 0.3 hargrove@sccm.stanford.edu (Paul H. Hargrove) + Major code reorganization. + Known for certain to work ONLY on floppies. + Started caching extents, so got faster on long file reads. + Now compiles separate from kernel tree. + Supports 5 filename conversion methods. + Supports forks, using the method from CAP. + All external symbols now start with HFS_ or hfs_ + +Jan 12, 1995: version 0.2 hargrove@sccm.stanford.edu (Paul H. Hargrove) + Should now work on all HFS volumes, but still only tested on floppies. + Got smaller and faster with some code reorganization. + Since Linus moved htons() and friends to an asm file, should now be + truly endian-independent, but still only tested on Intel machines. + Requires Linux >= 1.1.77, since Linus moved htons(). + +Jan 05, 1995: version 0.1 hargrove@sccm.stanford.edu (Paul H. Hargrove) + First release. + 1.44Mb floppies only + no resource forks + trivial name mangling only + read only + for Linux >= 1.1.75 diff -u --recursive --new-file v2.1.77/linux/fs/hfs/FAQ.txt linux/fs/hfs/FAQ.txt --- v2.1.77/linux/fs/hfs/FAQ.txt Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/FAQ.txt Sun Jan 4 10:40:17 1998 @@ -0,0 +1,342 @@ + Frequently Asked Questions about the HFS filesystem for + Linux + Paul H. Hargrove, hargrove@sccm.Stanford.EDU + version 1.0.3, 27 Apr 1997 + + This document provides answers to some of the most frequently asked + questions about the HFS filesystem for Linux. It is currently pretty + rough and totally unorganized. Corrections, additions and clarifica- + tions are appreciated. The most current version of this document is + kept on The HFS for Linux Page . + ______________________________________________________________________ + + Table of Contents: + + 1. What is this FAQ about? + + 2. What is HFS? + + 3. How I mount AppleShare volumes? + + 4. What is the current version of the HFS filesystem. + + 5. How stable is the current version? + + 6. Is there a mailing list for discussion of the HFS filesystem? + + 7. What version of Linux do I need to be running? + + 8. Will it run on my (your processor type here)? + + 9. Will it run under (your non-Linux operating system here)? + + 10. Why can I mount some HFS CDROMs but not others? + + 11. What does ``only 1024-char blocks implemented (512)'' mean? + + 12. Why do I get a message about a bad or unknown partition table? + + 13. Can I mount multiple HFS partitions from the same Macintosh + disk? + + 14. In what ways can I write to HFS filesystems? + + 15. Does the HFS filesystem work with 400k or 800k Macintosh + diskettes? + + 16. How can I format an HFS filesystem? + + 17. How can I fsck an HFS filesystem? + + 18. Why do I get ``error -50'' messages from my Mac when using + netatalk? + + 19. Why does my Macintosh show generic application and document + icons? + + 20. How owns all the copyrights and trademarks? ;-) + + 20.1. This Document + + 20.2. The Software + + 20.3. Trademarks + ______________________________________________________________________ + + 11.. WWhhaatt iiss tthhiiss FFAAQQ aabboouutt?? + + This FAQ is about the HFS filesystem for Linux, which is available in + two forms. The stand-alone version (called hfs_fs) is a Linux kernel + loadable module implementing the Macintosh HFS filesystem. The HFS + filesystem is also included in some distributions of the Linux kernel + source (in the directory linux/fs/hfs). This version can be compiled + as a loadable module or compiled into the kernel. + + Either version allows a machine running Linux to read and write disks + from a Macintosh (almost) as though they were native Linux disks. + + 22.. WWhhaatt iiss HHFFSS?? + + HFS stands for ``Hierarchical File System'' and is the filesystem used + by the Mac Plus and all later Macintosh models. Earlier Macintosh + models used MFS (``Macintosh File System''), which is not supported. + + 33.. HHooww II mmoouunntt AApppplleeSShhaarree vvoolluummeess?? + + The HFS filesystem is for mounting local filesystems only. There is + an experimental afpfs by Ben Hekster heksterb@acm.org available from + http://www.odyssey.co.il/~heksterb/Software/afpfs/. + + 44.. WWhhaatt iiss tthhee ccuurrrreenntt vveerrssiioonn ooff tthhee HHFFSS ffiilleessyysstteemm.. + + As of version 1.0.3 of this FAQ, version 0.95 is the most recent. You + can always find the most recent version on The HFS for Linux Page + . Announcements of new + versions are made to the comp.os.linux.announce newsgroup. + + 55.. HHooww ssttaabbllee iiss tthhee ccuurrrreenntt vveerrssiioonn?? + + Version 0.95 is considered to be ``beta'' software, so I recommend + making backups of anything important before you start playing. It is + relatively free of bugs due to lots of testing of the previous + releases. + + After a suitable period without new bugs the I will consider the + software to be ``stable'' and the version number will jump to 1.0. + + 66.. IIss tthheerree aa mmaaiilliinngg lliisstt ffoorr ddiissccuussssiioonn ooff tthhee HHFFSS ffiilleessyysstteemm?? + + There is no mailing list devoted exclusively to the HFS filesystem. + However, announcements of new versions are posted to the ``linux- + atalk'' and ``hfs-interest'' lists. I will see bug reports sent to + those lists but e-mail is more reliable (hargrove@sccm.Stanford.EDU). + + To subscribe to hfs-interest send e-mail with a body of ``subscribe + hfs-interest (your e-mail address)'' to majordomo@ccs.neu.edu. + + To subscribe to linux-atalk send e-mail with a body of ``SUBSCRIBE + LINUX-ATALK (Your full name)'' to listserv@netspace.org. + + 77.. WWhhaatt vveerrssiioonn ooff LLiinnuuxx ddoo II nneeeedd ttoo bbee rruunnnniinngg?? + + To compile and use the stand-alone distribution of the HFS filesystem + you will need Linux kernel version 2.0.1 or newer compiled with + modules enabled (CONFIG_MODULES). To compile you will need the kernel + headers which match the kernel you are running. This is covered in + more detail in the installation instructions in INSTALL.txt. + + If your kernel came with HFS in the kernel source tree then HFS should + work with your Linux version. There may be small problems with a few + of the development kernel releases. For these releases check the HFS + for Linux Page for + patches. + + 88.. WWiillll iitt rruunn oonn mmyy ((yyoouurr pprroocceessssoorr ttyyppee hheerree))?? + + The code is carefully written to be independent of your processor's + word size and byte-order, so if your machine runs Linux it can run the + HFS filesystem. However some younger ports don't yet have support for + loadable modules. + + Note that HFS is tested most extensively on Intel platforms. So there + could be subtle compilation problems on other platforms. If you + encounter any that are not addressed by the documentation then please + let me know. + + 99.. WWiillll iitt rruunn uunnddeerr ((yyoouurr nnoonn--LLiinnuuxx ooppeerraattiinngg ssyysstteemm hheerree))?? + + No. There is a port in progress to NetBSD. I know of no other active + porting attempts. If you are interested in porting the HFS filesystem + to another Unix-like operating system, I am interested in providing + what guidance I can. + + 1100.. WWhhyy ccaann II mmoouunntt ssoommee HHFFSS CCDDRROOMMss bbuutt nnoott ootthheerrss?? + + In the past there was a known incompatibility with some ``hybrid'' + CDROMs that appear as HFS disks on Macs and as ISO9660 disks on other + systems. I think I have fixed the problem. So, if you encounter this + particular problem or have problems with specific non-hybrid CDROMs + please e-mail me with the title and manufacturer of the CD. + + 1111.. WWhhaatt ddooeess ````oonnllyy 11002244--cchhaarr bblloocckkss iimmpplleemmeenntteedd ((551122))'''' mmeeaann?? + + This message comes from the kernel and indicates that an attempt was + made to read a 512-byte block from a device that doesn't support + 512-byte blocks. The HFS filesystem only works with 512-byte blocks, + and therefore doesn't function with these devices. Eventually it may + be able to use 1024-byte (or even 2048-byte) blocks when necessary. + Ideally the device driver should be enhanced to support 512-byte + blocks so that the various filesystems which need 512-byte blocks + don't each need to work around it. + + 1122.. WWhhyy ddoo II ggeett aa mmeessssaaggee aabboouutt aa bbaadd oorr uunnkknnoowwnn ppaarrttiittiioonn ttaabbllee?? + + If your Linux kernel doesn't understand Macintosh partition tables it + gives this warning when it can't find a partition table it recognizes. + To support partitioned media with such kernels, decoding of Mac + partition tables is done by the HFS filesystem so you should still be + able to mount the disk. However, to do so you will need to mount the + raw device (such as /dev/sdb instead of /dev/sdb4) and use the part + mount option to indicate which partition you want. + + 1133.. CCaann II mmoouunntt mmuullttiippllee HHFFSS ppaarrttiittiioonnss ffrroomm tthhee ssaammee MMaacciinnttoosshh ddiisskk?? + + Only if your kernel understands Macintosh partition tables. It the + kernel doesn't understand the Macintosh partition table, the HFS + filesystem must access the raw device. Therefore, the kernel thinks + the entire drive is in use and prevents additional mounts on it. + + 1144.. IInn wwhhaatt wwaayyss ccaann II wwrriittee ttoo HHFFSS ffiilleessyysstteemmss?? + + The HFS filesystem is as capable as the MS-DOS or VFAT filesystems, + except that certain things can only be done with a file's data fork. + + You ccaann: + + +o Create, delete and rename directories and data forks of files with + the caveat that names are case insensitive (so foo and Foo are the + same file or directory). + + +o Run Linux executables or shared libraries on an HFS disk if they + are stored in the data fork of a file. + + +o Read, write and truncate both forks of files and the Finder's + metadata of files and directories. + + +o Mmap data forks of files (and the resource fork if the filesystem + is mounted with the fork=cap option). + + +o Toggle the 'w' permission bits (as a group) of data forks. + + +o Change the i_mtime of files and directories. + + You ccaannnnoott: + + +o Create, delete or rename resource forks of files or the Finder's + metadata. Note, however, that they are created (with defaults + values), deleted and renamed along with the corresponding data fork + or directory. + + +o Run Linux executables or shared libraries on an HFS disk if they + are stored in the resource fork of a file. + + +o Mmap the Finder's metadata (when fork=cap) or AppleDouble header + files (when fork=double or fork=netatalk). + + +o Change permissions on directories. + + +o Change the uid or gid of files or directories. + + +o Set the set-uid, set-gid or sticky permission bits. + + +o Create multiple links to files. + + +o Create symlinks, device files, sockets or FIFOs. + + 1155.. DDooeess tthhee HHFFSS ffiilleessyysstteemm wwoorrkk wwiitthh 440000kk oorr 880000kk MMaacciinnttoosshh + ddiisskkeetttteess?? + + Yes and no. The software is fully capable of dealing with HFS disks + of any size. However, the 400k and 800k diskettes are written in a + physical format that is incompatible with most non-Macintosh floppy + drives. Note also that almost all 400k Macintosh diskettes are MFS, + not HFS. + + 1166.. HHooww ccaann II ffoorrmmaatt aann HHFFSS ffiilleessyysstteemm?? + + Robert Leslie (rob@mars.org) has written a package for working with + HFS filesystems (like mtools plus a graphical interface). One program + in the package is hformat which can format HFS filesystems. The + latest version can be found on the HFS Utilities home page + . + + 1177.. HHooww ccaann II ffsscckk aann HHFFSS ffiilleessyysstteemm?? + + Right now you'll have to use a Macintosh to do this. However, Rob + Leslie is working on an fsck for HFS filesystems. + + 1188.. WWhhyy ddoo II ggeett ````eerrrroorr --5500'''' mmeessssaaggeess ffrroomm mmyy MMaacc wwhheenn uussiinngg + nneettaattaallkk?? + + To be compatible with netatalk's afpd you will need to use netatalk + version 1.4b1 or newer and mount the HFS filesystem with the ``afpd'' + mount option. More information is provided in the ``afpd'' subsection + of the ``Mount Options'' section of the HFS documentation (HFS.txt if + you have the stand-alone HFS distribution or + linux/Documentation/filesystems/hfs.txt if HFS is in your kernel + source tree.) + + 1199.. WWhhyy ddooeess mmyy MMaacciinnttoosshh sshhooww ggeenneerriicc aapppplliiccaattiioonn aanndd ddooccuummeenntt + iiccoonnss?? + + When using the ``afpd'' mount option the Desktop database on the disk + is not made available to Netatalk's afpd. Because of this mounting an + HFS filesystem across the network to a Macintosh may result in the + Finder showing generic application and document icons. Additionally + double clicking on a document will fail to start the correct + application. + + If the disk is writable you can make Netatalk build a new Desktop + database in its own format by holding down the Option key while + selecting the volume in the Chooser. If the disk is not writable then + these problems can be worked around by copying the application to a + local disk on the Macintosh. + + 2200.. HHooww oowwnnss aallll tthhee ccooppyyrriigghhttss aanndd ttrraaddeemmaarrkkss?? ;;--)) + + 2200..11.. TThhiiss DDooccuummeenntt + + This document is Copyright (c) 1996, 1997 by Paul H. Hargrove. + + Permission is granted to make and distribute verbatim copies of this + document provided the copyright notice and this permission notice are + preserved on all copies. + + Permission is granted to copy and distribute modified versions of this + document under the conditions for verbatim copies above, provided a + notice clearly stating that the document is a modified version is also + included in the modified document. + + Permission is granted to copy and distribute translations of this + document into another language, under the conditions specified above + for modified versions. + + Permission is granted to convert this document into another media + under the conditions specified above for modified versions provided + the requirement to acknowledge the source document is fulfilled by + inclusion of an obvious reference to the source document in the new + media. Where there is any doubt as to what defines ``obvious'' the + copyright owner reserves the right to decide. + + 2200..22.. TThhee SSooffttwwaarree + + The HFS filesystem software is Copyright (c) 1994-1997 by Paul H. + Hargrove. + + The software 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, or (at your option) + any later version. + + The software 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 the software in the file ``COPYING''; if not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + USA. + + 2200..33.. TTrraaddeemmaarrkkss + + +o ``Finder'' is a trademark of Apple Computer, Inc. + + +o ``Apple'', ``AppleShare'', and ``Macintosh'' are registered + trademarks of Apple Computer, Inc. + + +o ``MS-DOS'' is a registered trademarks of Microsoft Corporation. + + +o All other trademarks are the property of their respective owners. + diff -u --recursive --new-file v2.1.77/linux/fs/hfs/HFS.txt linux/fs/hfs/HFS.txt --- v2.1.77/linux/fs/hfs/HFS.txt Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/HFS.txt Sun Jan 4 10:40:17 1998 @@ -0,0 +1,1042 @@ + Macintosh HFS Filesystem for Linux + Paul H. Hargrove, hargrove@sccm.Stanford.EDU + version 0.95, 28 Apr 1997 + + This document describes version 0.95 of the Macintosh HFS filesystem + for Linux. The most current versions of this document and the + software are kept at The HFS for Linux Page + . + ______________________________________________________________________ + + Table of Contents: + + 1. Introduction + + 2. Mounting HFS Filesystems + + 2.1. afpd + + 2.2. case={asis, lower} + + 2.3. conv={auto, binary, text} + + 2.4. creator=cccc + + 2.5. fork={cap, double, netatalk} + + 2.6. gid=n + + 2.7. names={7bit, 8bit, alpha, cap, latin, netatalk, trivial} + + 2.8. part=n + + 2.9. quiet + + 2.10. type=cccc + + 2.11. uid=n + + 2.12. umask=n + + 3. Writing to HFS Filesystems + + 3.1. Writing with fork=cap + + 3.2. Writing with fork=double + + 3.3. Writing with fork=netatalk + + 4. A Guide to Special File Formats + + 4.1. CAP .finderinfo Files + + 4.2. AppleDouble Header Files + + 5. Reporting Bugs + + 5.1. What Goes in a Bug Report + + 5.2. How to Report a Kernel Oops or GPF + + 6. Legal Notices + + 6.1. This Document + + 6.2. The Software + + 6.2.1. The Columbia AppleTalk Package for UNIX + + 6.2.2. Netatalk + + 6.3. Trademarks + ______________________________________________________________________ + + 11.. IInnttrroodduuccttiioonn + + This software implements the Macintosh HFS filesystem under Linux. It + allows you to read and write HFS filesystems on floppy disks, CDROMs, + hard drives, ZIP drives, etc. It is _n_o_t an AppleShare client. + + If you use this software, please send me a note telling of your + success or failure with it. Your feedback lets me know that this + project is not a waste of my time. + + This code is still experimental, so backup anything important before + you start playing. I'd like you to know that I've never lost any + files while using this software, or I would not release it. However, + a ``better safe than sorry'' attitude is probably best. + + If, for instance, the buffer cache were to become corrupted you could + start losing things on other disks. Because of this, if you get a + General Protection Fault, or a kernel Oops, I _s_t_r_o_n_g_l_y recommend that + you reboot before writing any files. + + 22.. MMoouunnttiinngg HHFFSS FFiilleessyysstteemmss + + Once you have the HFS filesystem compiled into the kernel or installed + as a loadable module, you will be able to use hfs as a filesystem type + option to mount. For instance, to mount a Macintosh floppy disk on + the directory /mnt using the default mount options you would execute + ``mount -t hfs /dev/fd0 /mnt''. + + The remainder of this section describes the several mount options + available to control how the HFS filesystem is mapped onto a Linux + filesystem structure. The values for the multiple-choice options + (case, conv, fork and names) can be abbreviated by their first + character. + + 22..11.. aaffppdd + + If included in the options, then the behavior of the filesystem is + changed to make it fully read-write compatible with Netatalk's afpd. + In this mode you should not use normal user-level tools to modify the + filesystem, though reading from it is acceptable. This is because the + return codes from some system calls are changed to fool afpd. These + changes will confuse many user-level tools. In particular ``rm -r'' + will loop forever. + + This option implies fork=netatalk, which in turn implies + names=netatalk. If either of these options are explicitly set to + something else they will take precedence and will confuse afpd. The + quiet option has no effect. The case= option functions normally, but + afpd usually does the same thing for you. The conv= and part= options + also function normally. + + You will probably want to use the uid=, gid= and umask= mount options. + Note that because all the files on an HFS filesystem belong to a + single user and group and have a single umask, the full AppleShare + permission scheme will not work through Netatalk. + + One additional limitation is that the Desktop database on the disk is + stored in afpd's format and is separate from any existing database + maintained by the Finder when the volume is used on a Macintosh. + Because of this mounting an HFS CDROM across the network to a + Macintosh may result in applications and documents showing up with + default application and document icons. Additionally double clicking + on a document will fail to start the correct application. Both of + these problems can be worked around by copying the application to a + local disk on the Macintosh. + + This mode is known to be compatible with afpd from Netatalk versions + 1.4b1 and 1.4b2, and known to be incompatible with the afpd from + version 1.3.3. As of this writing Netatalk version 1.4 has not yet + been released. However, it is expected that this mode will be + compatible with afpd from Netatalk version 1.4 when it is released. + + 22..22.. ccaassee=={{aassiiss,, lloowweerr}} + + default value: asis + + This option determines if Macintosh filenames are presented in their + original case or in all lowercase. Filename lookup is always case + insensitive, so either way foo and Foo refer to the same file but ls + will list Foo with case=asis, and foo with case=lower. (Same as for + the HPFS filesystem.) + + aassiiss + Filenames are reported in the case they were created with. + + lloowweerr + Filenames are reported in lowercase. + + 22..33.. ccoonnvv=={{aauuttoo,, bbiinnaarryy,, tteexxtt}} + + default value: binary + + This option controls CR<->NL conversion of Macintosh _d_a_t_a _f_o_r_k_s. Any + translation takes place only for files accessed with the read() and + write() system calls (either directly or through the stdio functions). + Access through mmap() is unaffected. (Similar to the conv= option for + the MS-DOS filesystem.) + + aauuttoo + If the Finder's type for a file is TEXT or ttro, then CR + characters are converted to NL characters when read, and NL + characters are converted to CR characters when written. + + Be warned that some Macintosh applications create files with + type TEXT even though the contents is clearly binary. + + bbiinnaarryy + No CR<->NL conversion is done. + + tteexxtt + In all data forks, regardless of the Finder's type for the file, + CR characters are converted to NL characters when read, and NL + characters are converted to CR characters when written. + + 22..44.. ccrreeaattoorr==cccccccc + + default value: ``????'' + + Specifies the 4-character string specifying the Finder's Creator for + new files. + + 22..55.. ffoorrkk=={{ccaapp,, ddoouubbllee,, nneettaattaallkk}} + + default value: cap + + This option determines how resource forks and the Finder's metadata + are represented within the structure of the Linux filesystem. + + ccaapp + The scheme used by the Columbia AppleTalk Package's AUFS. + + Associated with each directory are two special directories and a + metadata file. The directory ./bar is represented by: + + ..//bbaarr + The directory itself, containing subdirectories, the data + forks of files, and the following two special directories. + + ..//bbaarr//..rreessoouurrccee + A special directory holding resource forks of the files in + ./bar. + + ..//bbaarr//..ffiinnddeerriinnffoo + A special directory holding metadata files for the files and + subdirectories in ./bar. + + ..//..ffiinnddeerriinnffoo//bbaarr + The metadata file for the directory ./bar. + + The files in a directory are represented as three files: + + ..//ffoooo + The data fork of the file ./foo. + + ..//..rreessoouurrccee//ffoooo + The resource fork of the file ./foo. + + ..//..ffiinnddeerriinnffoo//ffoooo + The metadata file for the file ./foo. + + Additionally, the file .rootinfo in the root directory of the + HFS filesystem is a metadata file for the root directory. + + Brief documentation on the format of file containing the + Finder's metadata is included in the section ``A Guide to + Special File Formats'' in this document. More detailed + information is available in the Columbia AppleTalk Package. + + ddoouubbllee + The ``AppleDouble'' format recommended by Apple. (Apple's other + recommended format, ``AppleSingle'', is not yet implemented.) + + Associated with each directory is an AppleDouble ``header + file''. The directory ./bar is represented by: + + ..//bbaarr + The directory itself, containing subdirectories, the data + forks for files, and the header files for files and + subdirectories. + + ..//%%bbaarr + The header file for the directory ./bar, containing the + Finder's metadata for the directory. + + The files in a directory are represented as two files: + + ..//ffoooo + The data fork of the file ./foo. + + ..//%%ffoooo + The header file for the file ./foo, containing the resource + fork and the Finder's metadata for the file. + + Additionally, the file %RootInfo in the root directory of the + HFS filesystem is a header file for the root directory. This is + not quite the %RootInfo file referred to in the AppleDouble + specification. + + The header files used in this scheme are version 2 AppleDouble + header files. Their format is described briefly in the section + ``A Guide to Special File Formats'' in this document. They are + documented in detail in ``AppleSingle/AppleDouble Formats: + Developer's Note (9/94)'', available from from Apple's Developer + Services Page . + + Note that the naming convention for the header file can cause + name conflicts. For instance, using Apple's 7-bit ASCII name + conversion (see the names mount option) the name %Desktop could + be interpreted either as the header file for the file Desktop or + as the file with 0xDE as the hexadecimal representation of its + first character, and "sktop" as the remaining 5 characters. The + problem arises when both files exist, since only one will be + accessible. The behavior of the HFS filesystem in the case of + such a conflict is undefined, and may change in future releases. + (If this causes problems for you, please don't report it as a + bug; I didn't design this ``standard'', Apple did.) + + nneettaattaallkk + The scheme used by the Netatalk afpd. + + Associated with each directory is a special directory and a + metadata file. The directory ./bar is represented by: + + ..//bbaarr + The directory itself, containing subdirectories, the data + forks of files, and the following special directory. + + ..//bbaarr//..AApppplleeDDoouubbllee + A special directory holding AppleDouble header files for + ./bar and the files it contains, but not for the + subdirectories it contains. + + ..//bbaarr//..AApppplleeDDoouubbllee//..PPaarreenntt + The header file for the directory ./bar, containing the + Finder's metadata for the directory. + + The files in a directory are represented as two files: + + ..//ffoooo + The data fork of the file ./foo. + + ..//..AApppplleeDDoouubbllee//ffoooo + The header file for file ./foo, containing the resource fork + and the Finder's metadata. + + The header files used in this scheme are version 1 AppleDouble + header files. They are described briefly in the section ``A + Guide to Special File Formats'' in this document. The format is + documented in detail in the ``Apple II File Type Notes'' under + the type ``$E0.0002/$E0.0003-AppleDouble'', and in Appendix B of + the ``A/UX Toolbox: Macintosh ROM Interface'' manual. + + 22..66.. ggiidd==nn + + default value: gid of the mounting process + + Specifies the group that owns all files and directories on the + filesystem. (Same as for the MS-DOS and HPFS filesystems.) + + 22..77.. nnaammeess=={{77bbiitt,, 88bbiitt,, aallpphhaa,, ccaapp,, llaattiinn,, nneettaattaallkk,, ttrriivviiaall}} + + default value: varies as follows + + +o If the fork option is set to double, then names defaults to alpha. + + +o If the fork option is set to netatalk, then names defaults to + netatalk. + + +o If the fork option is set to cap (or has taken that value by + default), then names defaults to cap. + + This option determines how to convert between valid Macintosh + filenames and valid Linux filenames. The 7bit, 8bit and alpha options + correspond to Apple's recommended conventions named ``7-bit ASCII'', + ``8-bit'' and ``7-bit alphanumeric''. + + 77bbiitt + When converting from Macintosh filenames to Linux filenames the + NULL (0x00), slash (/) and percent (%) characters and the + extended 8-bit characters (hexadecimal codes 0x80-0xff) are + replaced by a percent character (%) followed by the two-digit + hexadecimal code for the character. + + When converting from Linux filenames to Macintosh filenames the + string "%YZ" is replaced by the character with hexadecimal code + 0xYZ. If 0xYZ is not a valid hexadecimal number or is the code + for NULL or colon (:) then the string "%YZ" is unchanged. A + colon (:) is replaced by a pipe character (|). + + 88bbiitt + When converting from Macintosh filenames to Linux filenames the + NULL (0x00), slash (/) and percent (%) characters are replaced + by a percent character (%) followed by the two-digit hexadecimal + code for the character. + + When converting from Linux filenames to Macintosh filenames the + string "%YZ" is replaced by the character with hexadecimal code + 0xYZ. If 0xYZ is not a valid hexadecimal number or is the code + for NULL or colon (:) then the string "%YZ" is unchanged. A + colon (:) is replaced by a pipe character (|). + + aallpphhaa + When converting from Macintosh filenames to Linux filenames only + the alphanumeric characters (a-z, A-Z and 0-9), the underscore + (_) and the last period (.) in the filename are unchanged. The + remaining characters are replaced by a percent character (%) + followed by the two-digit hexadecimal code for the character. + + When converting from Linux filenames to Macintosh filenames the + string "%YZ" is replaced by the character with hexadecimal code + 0xYZ. If 0xYZ is not a valid hexadecimal number or is the code + for NULL or colon (:) then the string "%YZ" is unchanged. A + colon (:) is replaced by a pipe character (|). + + ccaapp + The convention used by the Columbia AppleTalk Package's AUFS. + + When converting from Macintosh filenames to Linux filenames the + characters from space ( ) through tilde (~) (ASCII 32-126) are + unchanged, with the exception of slash (/). The slash (/) and + all characters outside the range 32-126 are replaced by a colon + (:) followed by the two-digit hexadecimal code for the + character. + + When converting from Linux filenames to Macintosh filenames the + string ":YZ" is replaced by the character with hexadecimal code + 0xYZ. If 0xYZ is not a valid hexadecimal number or is the code + for NULL or colon (:) then the colon is replaced by a pipe + character (|). + + llaattiinn + When converting from Macintosh filenames to Linux filenames the + characters from space ( ) through tilde (~) (ASCII 32-126) are + unchanged, with the exception of slash (/) and percent (%). The + extended 8-bit Macintosh characters with equivalents in the + Latin-1 character set are replaced by those equivalents. The + remaining characters are replaced by a percent character (%) + followed by the two-digit hexadecimal code for the character. + + When converting from Linux filenames to Macintosh filenames the + string "%YZ" is replaced by the character with hexadecimal code + 0xYZ. If 0xYZ is not a valid hexadecimal number or is the code + for NULL or colon (:) then the string "%YZ" is unchanged. The + Latin-1 characters with equivalents in the extended 8-bit + Macintosh character set are replaced by those equivalents. A + colon (:) is replaced by a pipe character (|). + + Thanks to Holger Schemel (aeglos@valinor.owl.de) for + contributing this conversion mode. + + nneettaattaallkk + The convention used by the Netatalk afpd. + + When converting from Macintosh filenames to Linux filenames the + characters from space ( ) through tilde (~) (ASCII 32-126) are + unchanged, with the exception of slash (/) and any initial + period (.). The slash (/) and any initial period (.) and all + characters outside the range 32-126 are replaced by a colon (:) + followed by the two-digit hexadecimal code for the character. + + When converting from Linux filenames to Macintosh filenames the + string ":YZ" is replaced by the character with hexadecimal code + 0xYZ. If 0xYZ is not a valid hexadecimal number or is the code + for NULL or colon (:) then the colon is replaced by a pipe + character (|). + + ttrriivviiaall + When converting from Macintosh filenames to Linux filenames a + slash character (/) is replaced by a colon (:). + + When converting from Linux filenames to Macintosh filenames a + colon (:) is replaced by a slash character (/). + + 22..88.. ppaarrtt==nn + + default value: 0 + + Specifies which HFS partition to mount from a Macintosh CDROM or hard + drive. Partitions are numbered from 0 and count only those identified + in the partition table as containing HFS filesystems. This option is + only useful when the Linux platform doesn't fully support Macintosh + partition tables. In particular on MkLinux and Linux-Pmac this option + is useless. + + Note that in versions before 0.8.3 partitions were numbered from 1. + + 22..99.. qquuiieett + + If included in the options, then chown and chmod operations will not + return errors, but will instead fail silently. (Same as for the MS- + DOS and HPFS filesystems.) + + 22..1100.. ttyyppee==cccccccc + + default value: ``????'' + + Specifies the 4-character string specifying the Finder's Type for new + files. + + 22..1111.. uuiidd==nn + + default value: uid of the mounting process + + Specifies the user that owns all files and directories on the + filesystem. (Same as for the MS-DOS and HPFS filesystems.) + + 22..1122.. uummaasskk==nn + + default value: umask of the mounting process + + Specifies (in octal) the umask used for all files and directories. + (Same as for the MS-DOS and HPFS filesystems.) + + 33.. WWrriittiinngg ttoo HHFFSS FFiilleessyysstteemmss + + Each of the values of the fork mount option yields a different + representation of the Macintosh-specific parts of a file within the + structure of the Linux filesystem. There are, therefore, slightly + different steps involved in copying files if you want to preserve the + resource forks and the Finder's metadata. + + It is important to remember not to use normal user-level tools to + modify a filesystem mounted with the afpd mount option. + + Regardless of the value of the fork mount option you can do virtually + everything to the data fork of a file that you can to a file on any + other filesystem. The limitations are essentially the same as those + imposed by the MS-DOS filesystem: + + +o You can't change the uid or gid of files. + + +o You can't set the set-uid, set-gid or sticky permission bits. + + +o You can't clear the execute permission bits. + + Likewise you can do virtually everything to a directory that you can + to a directory on another file system with the following exceptions: + + +o You can't create, delete or rename resource forks of files or the + Finder's metadata. Note, however, that they are created (with + defaults values), deleted and renamed along with the corresponding + data fork or directory. + + +o You can't change permissions on directories. + + +o You can't change the uid or gid of directories. + + +o You can't create multiple links to files. + + +o You can't create symlinks, device files, sockets or FIFOs. + + 33..11.. WWrriittiinngg wwiitthh ffoorrkk==ccaapp + + Unlike the other schemes for representing forked files, the CAP scheme + presents the resource fork as an independent file; the resource fork + of ./foo is ./.resource/foo. Therefore, you can treat it as a normal + file. You can do anything to a resource fork that you can do to a + data fork, except that you cannot enable execute permissions on a + resource fork. Therefore, resource forks are not suitable for holding + Linux executables or shared libraries. + + If you plan to use the resource fork on a Macintosh then you must obey + the format of a valid resource fork. This format is documented in + Chapter 1 of Apple's _I_n_s_i_d_e _M_a_c_i_n_t_o_s_h_: _M_o_r_e _M_a_c_i_n_t_o_s_h _T_o_o_l_b_o_x. The + filesystem knows nothing about this format and so does nothing to + enforce it. + + The current support for reading and writing is sufficient to allow + copying of entire directories with tar, as long as both the source and + destination are mounted with fork=cap. tar may complain about being + unable to change the uid, gid or mode of files. This is normal and is + an unavoidable side effect of the having a single uid, gid and umask + for the entire filesystem. + + It is impossible to create a resource fork or a Finder metadata file. + However, they are created automatically when the data fork is created. + Therefore, if you wish to copy a single file including both forks and + the Finder's metadata then you must create the data fork first. Then + you can copy the resource fork and the Finder's metadata. For + instance to copy the file foo to dir/bar you should do the following: + + 1. cp foo dir/bar + + 2. cp .resource/foo dir/.resource/bar + + 3. cp .finderinfo/foo dir/.finderinfo/bar + + You may get ``Operation not permitted'' errors from cp when it tries + to change the permissions on files. These errors can safely be + ignored. This method will work even if the file dir/bar exists. + + If you wish to move foo to dir/bar and foo and dir are on the same + filesystem then you only need to execute ``mv foo dir/bar'' and the + resource fork and the Finder's metadata will move too. However, if + foo and dir are on different filesystem then this will lose the + resource fork and metadata. Therefore, it is safest to always move + files as follows: + + 1. cp foo dir/bar + + 2. cp .resource/foo dir/.resource/bar + + 3. cp .finderinfo/foo dir/.finderinfo/bar + + 4. rm foo + + You may get ``Operation not permitted'' errors from cp when it tries + to change the permissions on files. These errors can safely be + ignored. This method will work even if the file dir/bar exists. + + Directories have no resource fork but you may wish to create a + directory which has the same location and view on the Finder's screen + as an existing one. This can be done by copying the Finder metadata + file. To give the directory bar the same location, layout, creation + date and modify date as foo you simply execute ``cp .finderinfo/foo + .finderinfo/bar''. + + When copying an entire directory with ``cp -R'' you may also wish to + copy the metadata for the directory: + + 1. cp -R foo bar + + 2. cp .finderinfo/foo .finderinfo/bar + + You may get ``Operation not permitted'' errors from cp when it tries + to change the permissions on files. These errors can safely be + ignored. + + 33..22.. WWrriittiinngg wwiitthh ffoorrkk==ddoouubbllee + + The current support for reading and writing header files is sufficient + to allow copying of entire directories with tar, as long as both the + source and destination are mounted with fork=double. tar may complain + about being unable to change the uid, gid or mode of files. This is + normal and is an unavoidable side effect of the having a single uid, + gid and umask for the entire filesystem. + + It is impossible to create a header file. However, they are created + automatically when the data fork is created. Therefore, if you wish + to copy a single file including both forks and the Finder's metadata + then you must create the data fork first. Then you can copy the + header file. instance to copy the file foo to dir/bar you should do + the following: + + 1. cp foo dir/bar + + 2. cp %foo dir/%bar + + You may get ``Operation not permitted'' errors from cp when it tries + to change the permissions on files. These errors can safely be + ignored. This method will work even if the file dir/bar exists. + + If you wish to move foo to dir/bar and foo and dir are on the same + filesystem then you only need to execute ``mv foo dir/bar'' and the + header file will move too. However, if foo and dir are on different + filesystem then this will lose the header file. Therefore, it is + safest to always move files as follows: + + 1. cp foo dir/bar + + 2. cp %foo dir/%bar + + 3. rm foo + + You may get ``Operation not permitted'' errors from cp when it tries + to change the permissions on files. These errors can safely be + ignored. This method will work even if the file dir/bar exists. + + Directories have no resource fork but you may wish to create a + directory which has the same location and view on the Finder's screen + as an existing one. This can be done by copying the corresponding + header file. To give the directory bar the same location, layout, + creation date and modify date as foo simply execute ``cp %foo %bar''. + + When copying an entire directory with ``cp -R'' you may also wish to + copy the header file for the directory as well: + + 1. cp -R foo bar + + 2. cp %foo %bar + + You may get ``Operation not permitted'' errors from cp when it tries + to change the permissions on files. These errors can safely be + ignored. + + 33..33.. WWrriittiinngg wwiitthh ffoorrkk==nneettaattaallkk + + The current support for reading and writing header files is sufficient + to allow copying of entire directories with tar, as long as both the + source and destination are mounted fork=netatalk. tar may complain + about being unable to change the uid, gid or mode of files. This is + normal and is an unavoidable side effect of the having a single uid, + gid and umask for the entire filesystem. + + It is impossible to create a header file. However, they are created + automatically when the data fork is created. Therefore, if you wish + to copy a single file including both forks and the Finder's metadata + then you must create the data fork first. Then you can copy the + header file. instance to copy the file foo to dir/bar you should do + the following: + + 1. cp foo dir/bar + + 2. cp .AppleDouble/foo dir/.AppleDouble/bar + + You may get ``Operation not permitted'' errors from cp when it tries + to change the permissions on files. These errors can safely be + ignored. This method will work even if the file dir/bar exists. + + If you wish to move foo to dir/bar and foo and dir are on the same + filesystem then you only need to execute ``mv foo dir/bar'' and the + header file will move too. However, if foo and dir are on different + filesystem then this will lose the header file. Therefore, it is + safest to always move files as follows: + + 1. cp foo dir/bar + + 2. cp .AppleDouble/foo dir/.AppleDouble/bar + + 3. rm foo + + You may get ``Operation not permitted'' errors from cp when it tries + to change the permissions on files. These errors can safely be + ignored. This method will work even if the file dir/bar exists. + + Directories have no resource fork but you may wish to create a + directory which has the same location and view on the Finder's screen + as an existing one. This can be done by copying the corresponding + header file. To give the directory bar the same location, layout, + creation date and modify date as foo you simply execute ``cp + foo/.AppleDouble/.Parent bar/.AppleDouble/.Parent''. + + Because the fork=netatalk scheme holds the header file for a directory + within that directory, directories can safely be copied with ``cp -R + foo bar'' with no loss of information. However, you may get + ``Operation not permitted'' errors from cp when it tries to change the + permissions on files. These errors can safely be ignored. + + 44.. AA GGuuiiddee ttoo SSppeecciiaall FFiillee FFoorrmmaattss + + Each of the values of the fork mount option yields different special + files to represent the Macintosh-specific parts of a file within the + structure of the Linux filesystem. You can write to these special + files to change things such as the Creator and Type of a file. + However, to do so safely you must follow certain rules to avoid + corrupting the data. Additionally, there are certain fields in the + special files that you can't change (writes to them will fail + silently). + + 44..11.. CCAAPP ..ffiinnddeerriinnffoo FFiilleess + + The Finder's metadata for the file ./foo in held in the file + ./.finderinfo/foo. The file has a fixed format defined in hfs_fs.h as + follows: + + ______________________________________________________________________ + struct hfs_cap_info { + __u8 fi_fndr[32]; /* Finder's info */ + __u16 fi_attr; /* AFP attributes */ + __u8 fi_magic1; /* Magic number: */ + #define HFS_CAP_MAGIC1 0xFF + __u8 fi_version; /* Version of this structure: */ + #define HFS_CAP_VERSION 0x10 + __u8 fi_magic; /* Another magic number: */ + #define HFS_CAP_MAGIC 0xDA + __u8 fi_bitmap; /* Bitmap of which names are valid: */ + #define HFS_CAP_SHORTNAME 0x01 + #define HFS_CAP_LONGNAME 0x02 + __u8 fi_shortfilename[12+1]; /* "short name" (unused) */ + __u8 fi_macfilename[32+1]; /* Original (Macintosh) name */ + __u8 fi_comln; /* Length of comment (always 0) */ + __u8 fi_comnt[200]; /* Finder comment (unused) */ + /* optional: used by aufs only if compiled with USE_MAC_DATES */ + __u8 fi_datemagic; /* Magic number for dates extension: */ + #define HFS_CAP_DMAGIC 0xDA + __u8 fi_datevalid; /* Bitmap of which dates are valid: */ + #define HFS_CAP_MDATE 0x01 + #define HFS_CAP_CDATE 0x02 + __u8 fi_ctime[4]; /* Creation date (in AFP format) */ + __u8 fi_mtime[4]; /* Modify date (in AFP format) */ + __u8 fi_utime[4]; /* Un*x time of last mtime change */ + }; + ______________________________________________________________________ + + The type __u8 is an unsigned character, and __u16 is an unsigned + 16-bit integer. + + Currently only the fields fi_fndr, fi_attr, fi_ctime and fi_mtime can + be changed. Writes to the other fields are silently ignored. + However, you shouldn't write random bytes to the other fields, since + they may be writable in the future. + + The fi_fndr field is the ``Finder info'' and ``Extended Finder info'' + for a file or directory. These structures are described in various + books on Macintosh programming. The portion of the most interest is + probably the first 8 bytes which, for a file, give the 4-byte Type + followed by the 4-byte Creator. + + The fi_attr field is the AFP attributes of the file or directory. + While you can write any value to this field, only the ``write- + inhibit'' bit is significant. Setting or clearing this bit will clear + or set the write bits in the file's permissions. When you read from + this field anything you may have written is lost. If the file has + write permissions enabled then you will read zero from this field. + With write permission disabled you will read back 0x01 0xA0, which + corresponds to setting the ``write-inhibit'', ``rename-inhibit'' and + ``delete-inhibit'' bits. + + The fi_ctime and fi_mtime are the Macintosh created and modified time + for the file or directory, and are 32-bit signed integers in network + byteorder giving seconds from 00:00 GMT Jan. 1, 2000. + + 44..22.. AApppplleeDDoouubbllee HHeeaaddeerr FFiilleess + + Both the fork=double and fork=netatalk schemes for representing forked + files use AppleDouble header files to contain the resource fork and + the Finder's metadata together in a single file. + + The AppleDouble format specifies a fixed-format header which describes + which fields are contained in the remainder of the file, where they + are located in the file and how long they are. A full description of + the version 1 format used when fork=netatalk is available from ??????. + The version 2 format used when fork=double is documented in ??????. + The discussion that follows assumes you have read and understood these + documents, which may be difficult until I've replaced the ``??????''s + above with something more informative :-). + + Due to the variable structure of an AppleDouble header file you must + not use buffered I/O when reading or writing them; you should only use + the read() and write() system calls. It is also important that you + make some effort to coordinate processes that are reading and writing + the same header file, since a reader will receive the wrong data if + the location of a given entry has changed since it read the descriptor + for the entry. If a process tries to read the descriptor table while + it is changing then it is possible to read totally meaningless data. + + When a header file is opened it is initially presented with a default + header layout. You may write to the header to change the layout, but + when all file descriptors for the file or directory have been closed + the change in format is lost and subsequent opens will yield the + default layout. Changes to supported entries are made directly to the + filesystem and are thus preserved when the file is closed and + reopened. + + The HFS filesystem currently uses a fixed-size table to hold the + descriptors. Therefore you are limited to HFS_HDR_MAX (currently 10) + descriptors. In the unlikely event that you try to write a header + with more descriptors, a warning will be issued by the kernel, and + extra descriptors will be ignored. This should be considered a bug + and will hopefully change sooner rather than later. + + The results of specifying overlapping entries is undefined and should + not be relied upon to remain unchanged from one version of the HFS + filesystem to the next. There is no valid reason to define + overlapping entries, so just don't do it! + + Changes to the magic number and version fields are preserved until all + file descriptors are closed, however the only significance given to + them internally is that the 16 bytes following the version changes + meaning according to the version. For version 1 header files these 16 + bytes contain the string ``Macintosh'' followed by 7 spaces. For any + other value of the version field these 16 bytes are all zeros. In + either case writes to these 16 bytes are silently ignored. + + Since the magic number and version are given no other significance + internally, you are free to do many things that violate the official + formats. For instance you can create an entry for the data fork in a + header file with an AppleDouble magic number or create ``File Info'' + (id=7) entries in version 2 header files and ``File Dates Info'' + (id=8) entries in version 1 header files. However, future versions of + the filesystem may enforce the format more strictly. + + Entry id 1 (``Data Fork'') is read-only. You should use the data file + to modify the data fork. The data fork is, of course, not supported + for directories. + + Entry ids 2, 7, 8, 9 and 10 (``Resource Fork'', ``File Info'', ``File + Dates Info'', ``Finder Info'' and ``Macintosh File Info'') are fully + supported, meaning that their contents may be read and written and + that data written is preserved when the file is closed and reopened. + The resource fork is, of course, not supported for directories. + + Entry id 7 specifies some of the same data given by ids 8 and 10. If + you create a header file with an entry for id 7 and for ids 8 or 10, + then the behavior with respect to their interaction is undefined. A + header that contains an entry for id 7 and for ids 8 or 10 is not + valid as either a version 1 or a version 2 header file, so there is no + reason to do this and future versions may prevent it. + + Entry id 3 (``Real Name'') is read-only, since it will change + automatically when a file is renamed. Writes to the corresponding + entry are silently ignored. + + All other entry ids are ignored. You may create descriptors for them; + in fact the default header layout when fork=netatalk includes a + descriptor for id 4 (``Comment''). However writes to the entries + corresponding to the ignored ids fail silently and reads from the + entries always return zeros. However, you shouldn't write random + bytes to unsupported entries, since they may be supported in the + future. + + All of the supported entry types except the data and resource forks + have a fixed length. If you give them a smaller length in the + descriptor then you are unable to access part of the corresponding + entry. If you give them a larger length in the descriptor, then the + corresponding entry is padded with zeros and writes to the extra space + are silently ignored. + + Writes to the length field of descriptors for the data and resource + forks will cause the corresponding fork to grow (with zero padding) or + shrink to the indicated length. + + If you have an entry for the data fork then the descriptor's length + field does not change automatically to reflect any modification of the + data fork directly (the data does change however). If the data fork + is longer than the descriptor indicates, then a portion of it is + inaccessible. If the data fork is shorter than the descriptor + indicates then reads will be padded with zeros. + + Writes beyond the end of the resource fork that extend into empty + space between entries or beyond the end of the file will extend the + fork, automatically changing the length field of the corresponding + descriptor. Writes to any other space between entries are silently + ignored and read of such spaces always return zeros. + + Calling truncate() on a header file can change the length of the + resource fork and such a change will automatically be reflected in the + length field of the corresponding descriptor. If truncate() shortens + the file so that the entry for the resource fork would extend beyond + the new end of the file then the fork is shortened to fit in the space + that remains, or to zero bytes if the entry is now entirely beyond the + end of the file. If the last entry in a header file is the resource + fork then a call to truncate() that extends the header file will + extend the fork with zeros. Note that this happens even if there was + previously space between the end of the fork and the end of the file. + + 55.. RReeppoorrttiinngg BBuuggss + + If you'd like any problems you encounter fixed, you'll need to provide + a detailed bug report. However, you should check the FAQ (available + from the HFS for Linux Page ) + first to be certain that your problem is not a known limitation of the + filesystem. If your bug doesn't appear in the FAQ then you should e-mail + me at hargrove@sccm.Stanford.EDU. + + 55..11.. WWhhaatt GGooeess iinn aa BBuugg RReeppoorrtt + + When writing your bug report, include any facts you think might be + relevant; I'd much rather have a bunch of extra facts than need to + e-mail you to get the information. At a minimum the following + information should be included: + + +o The version of the HFS filesystem you are using (see + linux/fs/hfs/version.h). + + +o The kernel version you are using. + + +o Any unofficial kernel patches or loadable modules you are using. + + +o If you are loading the HFS filesystem as a module, then version of + the module utilities used to load hfs.o. + + +o The type of media you are working with (floppy, CDROM, ZIP Drive, + etc.). + + +o The steps required to reproduce the bug, including mount options + used. (If you can't reproduce the bug tell me everything you did + the one time it did occur, but be warned that non-reproducible bugs + can only rarely be fixed.) + + 55..22.. HHooww ttoo RReeppoorrtt aa KKeerrnneell OOooppss oorr GGPPFF + + If you encounter a bug that causes a kernel Oops or a General + Protection Fault then you'll need to collect some additional + information for the bug report. If you are loading the HFS filesystem + as a module, then is important that you do this before rebooting, + since the module is unlikely to be loaded at the same address after + the reboot. + + You should include all the information that the kernel prints to the + console or to the system logs. However, the EIP and Stack Trace are + addresses in _y_o_u_r kernel and mean nothing to me without more + information. Using your System.map file (or either ksymoops or klogd) + determine which functions the EIP and Stack Trace are in. If you do + this by hand using your System.map file then the correct symbol is the + one of type t or T with the largest address less than or equal to the + one you are resolving. + + If you are loading the HFS filesystem as a module and the Oops or GPF + was in the HFS code then the EIP and the top levels of the Stack Trace + will be in a loadable module, rather than in the kernel proper. So, + their symbols will not be in the file System.map. Therefore, you will + need to use /proc/ksyms, or a loadmap produced by passing the -m + option to insmod, to locate those symbols. + + 66.. LLeeggaall NNoottiicceess + + 66..11.. TThhiiss DDooccuummeenntt + + This document is Copyright (c) 1996, 1997 by Paul H. Hargrove. + + Permission is granted to make and distribute verbatim copies of this + document provided the copyright notice and this permission notice are + preserved on all copies. + + Permission is granted to copy and distribute modified versions of this + document under the conditions for verbatim copies above, provided a + notice clearly stating that the document is a modified version is also + included in the modified document. + + Permission is granted to copy and distribute translations of this + document into another language, under the conditions specified above + for modified versions. + + Permission is granted to convert this document into another media + under the conditions specified above for modified versions provided + the requirement to acknowledge the source document is fulfilled by + inclusion of an obvious reference to the source document in the new + media. Where there is any doubt as to what defines ``obvious'' the + copyright owner reserves the right to decide. + + 66..22.. TThhee SSooffttwwaarree + + The HFS filesystem for Linux is Copyright (c) 1994-1997 by Paul H. + Hargrove. + + This software 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, or (at your option) + any later version. + + This software 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 software in the file ``COPYING''; if not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + USA. + + 66..22..11.. TThhee CCoolluummbbiiaa AApppplleeTTaallkk PPaacckkaaggee ffoorr UUNNIIXX + + The source code distribution of the Columbia AppleTalk Package for + UNIX, version 6.0, (CAP) was used as a _s_p_e_c_i_f_i_c_a_t_i_o_n of the location + and format of files used by CAP's Aufs. No code from CAP appears in + the HFS filesystem. The HFS filesystem is not a work ``derived'' from + CAP in the sense of intellectual property law. + + 66..22..22.. NNeettaattaallkk + + The source code distributions of Netatalk, versions 1.3.3b2 and 1.4b2, + were used as a _s_p_e_c_i_f_i_c_a_t_i_o_n of the location and format of files used + by Netatalk's afpd. No code from Netatalk appears in the HFS + filesystem. The HFS filesystem is not a work ``derived'' from + Netatalk in the sense of intellectual property law. + + 66..33.. TTrraaddeemmaarrkkss + + +o ``Finder'' is a trademarks of Apple Computer, Inc. + + +o ``Apple'', ``AppleShare'', ``AppleTalk'' and ``Macintosh'' are + registered trademarks of Apple Computer, Inc. + + +o ``Microsoft'' and ``MS-DOS'' are registered trademarks of Microsoft + Corporation. + + +o All other trademarks are the property of their respective owners. + diff -u --recursive --new-file v2.1.77/linux/fs/hfs/INSTALL.txt linux/fs/hfs/INSTALL.txt --- v2.1.77/linux/fs/hfs/INSTALL.txt Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/INSTALL.txt Sun Jan 4 10:40:17 1998 @@ -0,0 +1,126 @@ + Installation instructions for the HFS Filesystem for Linux + Paul H. Hargrove, hargrove@sccm.Stanford.EDU + version 0.95 28 Apr 1997 + + This document explains how to compile and install version 0.95 of + hfs_fs, the HFS filesystem for Linux. + + 11.. SSyysstteemm RReeqquuiirreemmeennttss + + You will need the following to compile and use this release of hfs_fs: + + +o Kernel version 2.0.1 or newer compiled with modules enabled + (CONFIG_MODULES). + + +o The kernel sources (or at least the header files) available online. + + +o The module utilities package current for your kernel version and an + understanding of how to use it. (The file + Documentation/modules.txt in the kernel source directory provides a + brief introduction.) + + 22.. IInnssttaallllaattiioonn + + This release of the HFS filesystem is not part of the official kernel + distribution. Therefore, it is compiled as a module and then loaded + into the kernel using the module utilities. Therefore, your kernel + must be compiled with CONFIG_MODULES enabled. + + 22..11.. CCoommppiilliinngg tthhee llooaaddaabbllee mmoodduullee + + To compile hfs.o you should only need to execute ``make'' in the + hfs_fs source directory. + + If gcc complains about not finding a large number of header files with + names beginning with ``linux/'' then you probably don't have the + kernel header files installed correctly. Either /usr/include/linux, + /usr/include/asm and /usr/include/scsi should be symbolic links to + include/linux, include/asm and include/scsi in the kernel source tree + for the kernel you wish to use hfs_fs with, or else they should be + directories containing the header files for the kernel you wish to use + hfs_fs with. + + If gcc complains about not finding linux/version.h, then you will need + to run ``make dep'' in the kernel source directory to build it. Under + MkLinux, run ``make include/linux/version.h'' instead. + + If gcc complains about not finding the files linux/config.h or + linux/autoconf.h, then you will need to run ``make config'' and ``make + dep'' in the kernel source directory to build these two files. + + If you are compiling on a DEC Alpha and receive messages saying + assignment from incompatible pointer type when compiling files dir_*.c + and file_*.c, then you need to change a single line in the file + linux/hfs_fs.h. Remove the text ``&& !defined(__alpha__)'' from the + end of line 217. + + 22..22.. IInnssttaalllliinngg tthhee mmoodduullee iinn tthhee mmoodduulleess ddiirreeccttoorryy ((ooppttiioonnaall)) + + If you plan to use kerneld to automatically load the module or if you + wish to use modprobe or insmod without supplying a complete path to + hfs.o, then you will need to copy hfs.o into a directory where the + module utilities expect to find it. + + The proper directory may depend slightly on your configuration. + However, /lib/modules/default/fs/ is a common one for filesystem + modules. Once hfs.o is in the proper directory you should run depmod + -a to update the dependency list used by kerneld and modprobe. + + 22..33.. LLooaaddiinngg tthhee mmoodduullee iinnttoo tthhee rruunnnniinngg kkeerrnneell + + There are three ways to accomplish this: + + 1. If you are running kerneld and have installed hfs.o in the modules + directory then you don't need to issue any commands; the module + will be loaded when you attempt to mount an HFS filesystem. + + 2. If you are _n_o_t running kerneld then you can load hfs.o manually by + running modprobe hfs.o. If you have not installed hfs.o in one of + the standard module directories, then you will need provide a full + path to the file hfs.o. + + 3. If you have been experiencing kernel crashes with hfs_fs, then you + should file a bug report including the names of the functions which + the EIP and Stack Trace point into. To help with this you can ask + for relocation map for the module when you load it. To do this + load the module with ``insmod -m hfs.o >loadmap''. Again, you may + need a full path to the file hfs.o if you have not placed it in one + of the standard module directories. + + 22..44.. UUssiinngg tthhee mmoodduullee wwiitthh vveerrssiioonneedd ssyymmbboollss + + All the interface between the module and the kernel take place through + very stable (since the mid-1.3.x kernels) parts of the kernel. If you + enabled versioned symbols (CONFIG_MODVERSIONS) when you compiled your + kernel you should often be able to compile this module once and then + use it with many kernels newer than the one you compiled it for. + + In any case, it is unlikely that this module will need changes with + each new kernel patch; simple recompilation should usually suffice. + + 33.. LLeeggaall NNoottiicceess + + 33..11.. TThhiiss DDooccuummeenntt + + This document is Copyright (c) 1996, 1997 by Paul H. Hargrove. + + Permission is granted to make and distribute verbatim copies of this + document provided the copyright notice and this permission notice are + preserved on all copies. + + Permission is granted to copy and distribute modified versions of this + document under the conditions for verbatim copies above, provided a + notice clearly stating that the document is a modified version is also + included in the modified document. + + Permission is granted to copy and distribute translations of this + document into another language, under the conditions specified above + for modified versions. + + Permission is granted to convert this document into another media + under the conditions specified above for modified versions provided + the requirement to acknowledge the source document is fulfilled by + inclusion of an obvious reference to the source document in the new + media. Where there is any doubt as to what defines ``obvious'' the + copyright owner reserves the right to decide. + diff -u --recursive --new-file v2.1.77/linux/fs/hfs/Makefile linux/fs/hfs/Makefile --- v2.1.77/linux/fs/hfs/Makefile Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/Makefile Sun Jan 4 10:40:17 1998 @@ -0,0 +1,18 @@ +# +# Makefile for the linux nfs-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := hfs.o +O_OBJS := balloc.o bdelete.o bfind.o bins_del.o binsert.o bitmap.o bitops.o \ + bnode.o brec.o btree.o catalog.o dir.o dir_cap.o dir_dbl.o \ + dir_nat.o extent.o file.o file_cap.o file_hdr.o inode.o mdb.o \ + part_tbl.o string.o super.o sysdep.o trans.o version.o + +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.77/linux/fs/hfs/TODO linux/fs/hfs/TODO --- v2.1.77/linux/fs/hfs/TODO Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/TODO Sun Jan 4 10:40:17 1998 @@ -0,0 +1,54 @@ +The hfs_fs "to do" list. +------------------------ +Items are broken down into groups and the groups are listed in order +from most important to least important. The items within each group +are not placed in any particular order. The order in which items are +listed probably doesn't correlate well with the order they will be +addressed. + +Genuine bugs: +1. Header files have compiled-in limit (currently 10) on descriptors. + +Missing features: +1. The partition code should be migrated into the kernel to allow + simultaneous access to multiple partitions on a single disk. +2. 1k block support is needed for some devices. +3. An ioctl()-based interface is needed to provide a consistent way + to do things under all of the representations of forked files. + +Possible additional "fork" mount options: +1. AppleSingle. +2. The scheme MacOS uses on FAT disks (PC Exchange). +3. "Flat" (no resource forks or metadata). + +Performance issues: +1. Use drAllocPtr to speed block allocations. +2. Keep a real cache of bnodes, rather than just a hash table of + the ones that are currently in use. +3. Keep a real cache of extent records, rather than just a linked + list of the ones that are currently in use and the one most + recently used. This is particularly needed to get acceptable + performance with multiple readers on a file. Perhaps simply + keep them in memory once they've been read until the file is + closed. + +Implementation details: +1. Allocation scheme could/should be closer to that used by Apple. +2. B*-tree insertion could/should be closer to that used by Apple. +3. Magic-number checks on data structures are rarely done. +4. Error recovery is needed for failed binsert(), bdelete() and rename(). +5. Deadlock detection is needed to make insert_empty_bnode() and + bdelete() less likely to hang on a corrupted B-tree. +6. Metadata for covered directories shouldn't appear in the filesystem. + Under CAP and AppleDouble it currently does. However, the obvious + solution is a real performance killer and is not worth implementing. + +Fantasy features: +1. Access Desktop file/database for comment and icon. +2. Implement mmap() for AppleDouble header files and CAP info files. +3. Implement AppleShare client support. + +Suggestions/comments/questions are welcome. +Code addressing any of the issues listed above is especially welcome. +Paul H. Hargrove +hargrove@sccm.Stanford.EDU diff -u --recursive --new-file v2.1.77/linux/fs/hfs/balloc.c linux/fs/hfs/balloc.c --- v2.1.77/linux/fs/hfs/balloc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/balloc.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,437 @@ +/* + * linux/fs/hfs/balloc.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * hfs_bnode_alloc() and hfs_bnode_bitop() are based on GPLed code + * Copyright (C) 1995 Michael Dreher + * + * This file contains the code to create and destroy nodes + * in the B-tree structure. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + * + * The code in this file initializes some structures which contain + * pointers by calling memset(&foo, 0, sizeof(foo)). + * This produces the desired behavior only due to the non-ANSI + * assumption that the machine representation of NULL is all zeros. + */ + +#include "hfs_btree.h" + +/*================ File-local functions ================*/ + +/* + * get_new_node() + * + * Get a buffer for a new node with out reading it from disk. + */ +static hfs_buffer get_new_node(struct hfs_btree *tree, hfs_u32 node) +{ + int tmp; + hfs_buffer retval = HFS_BAD_BUFFER; + + tmp = hfs_extent_map(&tree->entry.u.file.data_fork, node, 0); + if (tmp) { + retval = hfs_buffer_get(tree->sys_mdb, tmp, 0); + } + return retval; +} + +/* + * hfs_bnode_init() + * + * Description: + * Initialize a newly allocated bnode. + * Input Variable(s): + * struct hfs_btree *tree: Pointer to a B-tree + * hfs_u32 node: the node number to allocate + * Output Variable(s): + * NONE + * Returns: + * struct hfs_bnode_ref for the new node + * Preconditions: + * 'tree' points to a "valid" (struct hfs_btree) + * 'node' exists and has been allocated in the bitmap of bnodes. + * Postconditions: + * On success: + * The node is not read from disk, nor added to the bnode cache. + * The 'sticky' and locking-related fields are all zero/NULL. + * The bnode's nd{[FB]Link, Type, NHeight} fields are uninitialized. + * The bnode's ndNRecs field and offsets table indicate an empty bnode. + * On failure: + * The node is deallocated. + */ +static struct hfs_bnode_ref hfs_bnode_init(struct hfs_btree * tree, + hfs_u32 node) +{ +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + extern int bnode_count; +#endif + struct hfs_bnode_ref retval; + + retval.lock_type = HFS_LOCK_NONE; + if (!HFS_NEW(retval.bn)) { + hfs_warn("hfs_bnode_init: out of memory.\n"); + goto bail2; + } + + /* Partially initialize the in-core structure */ + memset(retval.bn, 0, sizeof(*retval.bn)); + retval.bn->magic = HFS_BNODE_MAGIC; + retval.bn->tree = tree; + retval.bn->node = node; + hfs_bnode_lock(&retval, HFS_LOCK_WRITE); + + retval.bn->buf = get_new_node(tree, node); + if (!hfs_buffer_ok(retval.bn->buf)) { + goto bail1; + } + +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + ++bnode_count; +#endif + + /* Partially initialize the on-disk structure */ + memset(hfs_buffer_data(retval.bn->buf), 0, HFS_SECTOR_SIZE); + hfs_put_hs(sizeof(struct NodeDescriptor), RECTBL(retval.bn, 1)); + + return retval; + +bail1: + HFS_DELETE(retval.bn); +bail2: + /* clear the bit in the bitmap */ + hfs_bnode_bitop(tree, node, 0); + return retval; +} + +/* + * init_mapnode() + * + * Description: + * Initializes a given node as a mapnode in the given tree. + * Input Variable(s): + * struct hfs_bnode *bn: the node to add the mapnode after. + * hfs_u32: the node to use as a mapnode. + * Output Variable(s): + * NONE + * Returns: + * struct hfs_bnode *: the new mapnode or NULL + * Preconditions: + * 'tree' is a valid (struct hfs_btree). + * 'node' is the number of the first node in 'tree' that is not + * represented by a bit in the existing mapnodes. + * Postconditions: + * On failure 'tree' is unchanged and NULL is returned. + * On success the node given by 'node' has been added to the linked + * list of mapnodes attached to 'tree', and has been initialized as + * a valid mapnode with its first bit set to indicate itself as + * allocated. + */ +static struct hfs_bnode *init_mapnode(struct hfs_bnode *bn, hfs_u32 node) +{ +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + extern int bnode_count; +#endif + struct hfs_bnode *retval; + + if (!HFS_NEW(retval)) { + hfs_warn("hfs_bnode_add: out of memory.\n"); + return NULL; + } + + memset(retval, 0, sizeof(*retval)); + retval->magic = HFS_BNODE_MAGIC; + retval->tree = bn->tree; + retval->node = node; + retval->sticky = HFS_STICKY; + retval->buf = get_new_node(bn->tree, node); + if (!hfs_buffer_ok(retval->buf)) { + HFS_DELETE(retval); + return NULL; + } + +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + ++bnode_count; +#endif + + /* Initialize the bnode data structure */ + memset(hfs_buffer_data(retval->buf), 0, HFS_SECTOR_SIZE); + retval->ndFLink = 0; + retval->ndBLink = bn->node; + retval->ndType = ndMapNode; + retval->ndNHeight = 0; + retval->ndNRecs = 1; + hfs_put_hs(sizeof(struct NodeDescriptor), RECTBL(retval, 1)); + hfs_put_hs(0x1fa, RECTBL(retval, 2)); + *((hfs_u8 *)bnode_key(retval, 1)) = 0x80; /* set first bit of bitmap */ + retval->prev = bn; + hfs_bnode_commit(retval); + + bn->ndFLink = node; + bn->next = retval; + hfs_bnode_commit(bn); + + return retval; +} + +/*================ Global functions ================*/ + +/* + * hfs_bnode_bitop() + * + * Description: + * Allocate/free the requested node of a B-tree of the hfs filesystem + * by setting/clearing the corresponding bit in the B-tree bitmap. + * The size of the B-tree will not be changed. + * Input Variable(s): + * struct hfs_btree *tree: Pointer to a B-tree + * hfs_u32 bitnr: The node number to free + * int set: 0 to clear the bit, non-zero to set it. + * Output Variable(s): + * None + * Returns: + * 0: no error + * -1: The node was already allocated/free, nothing has been done. + * -2: The node is out of range of the B-tree. + * -4: not enough map nodes to hold all the bits + * Preconditions: + * 'tree' points to a "valid" (struct hfs_btree) + * 'bitnr' is a node number within the range of the btree, which is + * currently free/allocated. + * Postconditions: + * The bit number 'bitnr' of the node bitmap is set/cleared and the + * number of free nodes in the btree is decremented/incremented by one. + */ +int hfs_bnode_bitop(struct hfs_btree *tree, hfs_u32 bitnr, int set) +{ + struct hfs_bnode *bn; /* the current bnode */ + hfs_u16 start; /* the start (in bits) of the bitmap in node */ + hfs_u16 len; /* the len (in bits) of the bitmap in node */ + hfs_u32 *u32; /* address of the u32 containing the bit */ + + if (bitnr >= tree->bthNNodes) { + hfs_warn("hfs_bnode_bitop: node number out of range.\n"); + return -2; + } + + bn = &tree->head; + for (;;) { + start = bnode_offset(bn, bn->ndNRecs) << 3; + len = (bnode_offset(bn, bn->ndNRecs + 1) << 3) - start; + + if (bitnr < len) { + break; + } + + /* continue on to next map node if available */ + if (!(bn = bn->next)) { + hfs_warn("hfs_bnode_bitop: too few map nodes.\n"); + return -4; + } + bitnr -= len; + } + + /* Change the correct bit */ + bitnr += start; + u32 = (hfs_u32 *)hfs_buffer_data(bn->buf) + (bitnr >> 5); + bitnr %= 32; + if ((set && hfs_set_bit(bitnr, u32)) || + (!set && !hfs_clear_bit(bitnr, u32))) { + hfs_warn("hfs_bnode_bitop: bitmap corruption.\n"); + return -1; + } + hfs_buffer_dirty(bn->buf); + + /* adjust the free count */ + tree->bthFree += (set ? -1 : 1); + tree->dirt = 1; + + return 0; +} + +/* + * hfs_bnode_alloc() + * + * Description: + * Find a cleared bit in the B-tree node bitmap of the hfs filesystem, + * set it and return the corresponding bnode, with its contents zeroed. + * When there is no free bnode in the tree, an error is returned, no + * new nodes will be added by this function! + * Input Variable(s): + * struct hfs_btree *tree: Pointer to a B-tree + * Output Variable(s): + * NONE + * Returns: + * struct hfs_bnode_ref for the new bnode + * Preconditions: + * 'tree' points to a "valid" (struct hfs_btree) + * There is at least one free bnode. + * Postconditions: + * On success: + * The corresponding bit in the btree bitmap is set. + * The number of free nodes in the btree is decremented by one. + * The node is not read from disk, nor added to the bnode cache. + * The 'sticky' field is uninitialized. + */ +struct hfs_bnode_ref hfs_bnode_alloc(struct hfs_btree *tree) +{ + struct hfs_bnode *bn; /* the current bnode */ + hfs_u32 bitnr = 0; /* which bit are we examining */ + hfs_u16 first; /* the first clear bit in this bnode */ + hfs_u16 start; /* the start (in bits) of the bitmap in node */ + hfs_u16 end; /* the end (in bits) of the bitmap in node */ + hfs_u32 *data; /* address of the data in this bnode */ + + bn = &tree->head; + for (;;) { + start = bnode_offset(bn, bn->ndNRecs) << 3; + end = bnode_offset(bn, bn->ndNRecs + 1) << 3; + data = (hfs_u32 *)hfs_buffer_data(bn->buf); + + /* search the current node */ + first = hfs_find_zero_bit(data, end, start); + if (first < end) { + break; + } + + /* continue search in next map node */ + bn = bn->next; + + if (!bn) { + hfs_warn("hfs_bnode_alloc: too few map nodes.\n"); + goto bail; + } + bitnr += (end - start); + } + + if ((bitnr += (first - start)) >= tree->bthNNodes) { + hfs_warn("hfs_bnode_alloc: no free nodes found, " + "count wrong?\n"); + goto bail; + } + + if (hfs_set_bit(first % 32, data + (first>>5))) { + hfs_warn("hfs_bnode_alloc: bitmap corruption.\n"); + goto bail; + } + hfs_buffer_dirty(bn->buf); + + /* decrement the free count */ + --tree->bthFree; + tree->dirt = 1; + + return hfs_bnode_init(tree, bitnr); + +bail: + return (struct hfs_bnode_ref){NULL, HFS_LOCK_NONE}; +} + +/* + * hfs_btree_extend() + * + * Description: + * Adds nodes to a B*-tree if possible. + * Input Variable(s): + * struct hfs_btree *tree: the btree to add nodes to. + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'tree' is a valid (struct hfs_btree *). + * Postconditions: + * If possible the number of nodes indicated by the tree's clumpsize + * have been added to the tree, updating all in-core and on-disk + * allocation information. + * If insufficient disk-space was available then fewer nodes may have + * been added than would be expected based on the clumpsize. + * In the case of the extents B*-tree this function will add fewer + * nodes than expected if adding more would result in an extent + * record for the extents tree being added to the extents tree. + * The situation could be dealt with, but doing so confuses Macs. + */ +void hfs_btree_extend(struct hfs_btree *tree) +{ + struct hfs_bnode_ref head; + struct hfs_bnode *bn, *tmp; + struct hfs_cat_entry *entry = &tree->entry; + struct hfs_mdb *mdb = entry->mdb; + hfs_u32 old_nodes, new_nodes, total_nodes, new_mapnodes, seen; + + old_nodes = entry->u.file.data_fork.psize; + + entry->u.file.data_fork.lsize += 1; /* rounded up to clumpsize */ + hfs_extent_adj(&entry->u.file.data_fork); + + total_nodes = entry->u.file.data_fork.psize; + entry->u.file.data_fork.lsize = total_nodes << HFS_SECTOR_SIZE_BITS; + new_nodes = total_nodes - old_nodes; + if (!new_nodes) { + return; + } + + head = hfs_bnode_find(tree, 0, HFS_LOCK_WRITE); + if (!(bn = head.bn)) { + hfs_warn("hfs_btree_extend: header node not found.\n"); + return; + } + + seen = 0; + new_mapnodes = 0; + for (;;) { + seen += bnode_rsize(bn, bn->ndNRecs) << 3; + + if (seen >= total_nodes) { + break; + } + + if (!bn->next) { + tmp = init_mapnode(bn, seen); + if (!tmp) { + hfs_warn("hfs_btree_extend: " + "can't build mapnode.\n"); + hfs_bnode_relse(&head); + return; + } + ++new_mapnodes; + } + bn = bn->next; + } + hfs_bnode_relse(&head); + + tree->bthNNodes = total_nodes; + tree->bthFree += (new_nodes - new_mapnodes); + tree->dirt = 1; + + /* write the backup MDB, not returning until it is written */ + hfs_mdb_commit(mdb, 1); + + return; +} + +/* + * hfs_bnode_free() + * + * Remove a node from the cache and mark it free in the bitmap. + */ +int hfs_bnode_free(struct hfs_bnode_ref *bnr) +{ + hfs_u32 node = bnr->bn->node; + struct hfs_btree *tree = bnr->bn->tree; + + if (bnr->bn->count != 1) { + hfs_warn("hfs_bnode_free: count != 1.\n"); + return -EIO; + } + + hfs_bnode_relse(bnr); + hfs_bnode_bitop(tree, node, 0); + return 0; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/bdelete.c linux/fs/hfs/bdelete.c --- v2.1.77/linux/fs/hfs/bdelete.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/bdelete.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,483 @@ +/* + * linux/fs/hfs/bdelete.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the code to delete records in a B-tree. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs_btree.h" + +/*================ Variable-like macros ================*/ + +#define FULL (HFS_SECTOR_SIZE - sizeof(struct NodeDescriptor)) +#define NO_SPACE (HFS_SECTOR_SIZE+1) + +/*================ File-local functions ================*/ + +/* + * bdelete_nonempty() + * + * Description: + * Deletes a record from a given bnode without regard to it becoming empty. + * Input Variable(s): + * struct hfs_brec* brec: pointer to the brec for the deletion + * struct hfs_belem* belem: which node in 'brec' to delete from + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'brec' points to a valid (struct hfs_brec). + * 'belem' points to a valid (struct hfs_belem) in 'brec'. + * Postconditions: + * The record has been inserted in the position indicated by 'brec'. + */ +static void bdelete_nonempty(struct hfs_brec *brec, struct hfs_belem *belem) +{ + int i, rec, nrecs, tomove; + hfs_u16 size; + hfs_u8 *start; + struct hfs_bnode *bnode = belem->bnr.bn; + + rec = belem->record; + nrecs = bnode->ndNRecs; + size = bnode_rsize(bnode, rec); + tomove = bnode_offset(bnode, nrecs+1) - bnode_offset(bnode, rec+1); + + /* adjust the record table */ + for (i = rec+1; i <= nrecs; ++i) { + hfs_put_hs(bnode_offset(bnode,i+1) - size, RECTBL(bnode,i)); + } + + /* move it down */ + start = bnode_key(bnode, rec); + memmove(start, start + size, tomove); + + /* update record count */ + --bnode->ndNRecs; +} + +/* + * del_root() + * + * Description: + * Delete the current root bnode. + * Input Variable(s): + * struct hfs_bnode_ref *root: reference to the root bnode + * Output Variable(s): + * NONE + * Returns: + * int: 0 on success, error code on failure + * Preconditions: + * 'root' refers to the root bnode with HFS_LOCK_WRITE access. + * None of 'root's children are held with HFS_LOCK_WRITE access. + * Postconditions: + * The current 'root' node is removed from the tree and the depth + * of the tree is reduced by one. + * If 'root' is an index node with exactly one child, then that + * child becomes the new root of the tree. + * If 'root' is an empty leaf node the tree becomes empty. + * Upon return access to 'root' is relinquished. + */ +static int del_root(struct hfs_bnode_ref *root) +{ + struct hfs_btree *tree = root->bn->tree; + struct hfs_bnode_ref child; + hfs_u32 node; + + if (root->bn->ndNRecs > 1) { + return 0; + } else if (root->bn->ndNRecs == 0) { + /* tree is empty */ + tree->bthRoot = 0; + tree->root = NULL; + tree->bthRoot = 0; + tree->bthFNode = 0; + tree->bthLNode = 0; + --tree->bthDepth; + tree->dirt = 1; + if (tree->bthDepth) { + hfs_warn("hfs_bdelete: empty tree with bthDepth=%d\n", + tree->bthDepth); + goto bail; + } + return hfs_bnode_free(root); + } else if (root->bn->ndType == ndIndxNode) { + /* tree is non-empty */ + node = hfs_get_hl(bkey_record(bnode_datastart(root->bn))); + + child = hfs_bnode_find(tree, node, HFS_LOCK_READ); + if (!child.bn) { + hfs_warn("hfs_bdelete: can't read child node.\n"); + goto bail; + } + + child.bn->sticky = HFS_STICKY; + if (child.bn->next) { + child.bn->next->prev = child.bn->prev; + } + if (child.bn->prev) { + child.bn->prev->next = child.bn->next; + } + if (bhash(tree, child.bn->node) == child.bn) { + bhash(tree, child.bn->node) = child.bn->next; + } + child.bn->next = NULL; + child.bn->prev = NULL; + + tree->bthRoot = child.bn->node; + tree->root = child.bn; + hfs_bnode_relse(&child); + + tree->bthRoot = node; + tree->bthFNode = node; + tree->bthLNode = node; + --tree->bthDepth; + tree->dirt = 1; + if (!tree->bthDepth) { + hfs_warn("hfs_bdelete: non-empty tree with " + "bthDepth == 0\n"); + goto bail; + } + return hfs_bnode_free(root); /* marks tree dirty */ + } + hfs_bnode_relse(root); + return 0; + +bail: + hfs_bnode_relse(root); + return -EIO; +} + + +/* + * delete_empty_bnode() + * + * Description: + * Removes an empty non-root bnode from between 'left' and 'right' + * Input Variable(s): + * hfs_u32 left_node: node number of 'left' or zero if 'left' is invalid + * struct hfs_bnode_ref *left: reference to the left neighbor of the + * bnode to remove, or invalid if no such neighbor exists. + * struct hfs_bnode_ref *center: reference to the bnode to remove + * hfs_u32 right_node: node number of 'right' or zero if 'right' is invalid + * struct hfs_bnode_ref *right: reference to the right neighbor of the + * bnode to remove, or invalid if no such neighbor exists. + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'left_node' is as described above. + * 'left' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE + * access and referring to the left neighbor of 'center' if such a + * neighbor exists, or invalid if no such neighbor exists. + * 'center' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE + * access and referring to the bnode to delete. + * 'right_node' is as described above. + * 'right' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE + * access and referring to the right neighbor of 'center' if such a + * neighbor exists, or invalid if no such neighbor exists. + * Postconditions: + * If 'left' is valid its 'ndFLink' field becomes 'right_node'. + * If 'right' is valid its 'ndBLink' field becomes 'left_node'. + * If 'center' was the first leaf node then the tree's 'bthFNode' + * field becomes 'right_node' + * If 'center' was the last leaf node then the tree's 'bthLNode' + * field becomes 'left_node' + * 'center' is NOT freed and access to the nodes is NOT relinquished. + */ +static void delete_empty_bnode(hfs_u32 left_node, struct hfs_bnode_ref *left, + struct hfs_bnode_ref *center, + hfs_u32 right_node, struct hfs_bnode_ref *right) +{ + struct hfs_bnode *bnode = center->bn; + + if (left_node) { + left->bn->ndFLink = right_node; + } else if (bnode->ndType == ndLeafNode) { + bnode->tree->bthFNode = right_node; + bnode->tree->dirt = 1; + } + + if (right_node) { + right->bn->ndBLink = left_node; + } else if (bnode->ndType == ndLeafNode) { + bnode->tree->bthLNode = left_node; + bnode->tree->dirt = 1; + } +} + +/* + * balance() + * + * Description: + * Attempt to equalize space usage in neighboring bnodes. + * Input Variable(s): + * struct hfs_bnode *left: the left bnode. + * struct hfs_bnode *right: the right bnode. + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'left' and 'right' point to valid (struct hfs_bnode)s obtained + * with HFS_LOCK_WRITE access, and are neighbors. + * Postconditions: + * Records are shifted either left or right to make the space usage + * nearly equal. When exact equality is not possible the break + * point is chosen to reduce data movement. + * The key corresponding to 'right' in its parent is NOT updated. + */ +static void balance(struct hfs_bnode *left, struct hfs_bnode *right) +{ + int index, left_free, right_free, half; + + left_free = bnode_freespace(left); + right_free = bnode_freespace(right); + half = (left_free + right_free)/2; + + if (left_free < right_free) { + /* shift right to balance */ + index = left->ndNRecs + 1; + while (right_free >= half) { + --index; + right_free -= bnode_rsize(left,index)+sizeof(hfs_u16); + } + if (index < left->ndNRecs) { +#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE) + hfs_warn("shifting %d of %d recs right to balance: ", + left->ndNRecs - index, left->ndNRecs); +#endif + hfs_bnode_shift_right(left, right, index+1); +#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE) + hfs_warn("%d,%d\n", left->ndNRecs, right->ndNRecs); +#endif + } + } else { + /* shift left to balance */ + index = 0; + while (left_free >= half) { + ++index; + left_free -= bnode_rsize(right,index)+sizeof(hfs_u16); + } + if (index > 1) { +#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE) + hfs_warn("shifting %d of %d recs left to balance: ", + index-1, right->ndNRecs); +#endif + hfs_bnode_shift_left(left, right, index-1); +#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE) + hfs_warn("%d,%d\n", left->ndNRecs, right->ndNRecs); +#endif + } + } +} + +/* + * bdelete() + * + * Delete the given record from a B-tree. + */ +static int bdelete(struct hfs_brec *brec) +{ + struct hfs_btree *tree = brec->tree; + struct hfs_belem *belem = brec->bottom; + struct hfs_belem *parent = (belem-1); + struct hfs_bnode *bnode; + hfs_u32 left_node, right_node; + struct hfs_bnode_ref left, right; + int left_space, right_space, min_space; + int fix_right_key; + int fix_key; + + while ((belem > brec->top) && + (belem->flags & (HFS_BPATH_UNDERFLOW | HFS_BPATH_FIRST))) { + bnode = belem->bnr.bn; + fix_key = belem->flags & HFS_BPATH_FIRST; + fix_right_key = 0; + + bdelete_nonempty(brec, belem); + + if (bnode->node == tree->root->node) { + del_root(&belem->bnr); + --brec->bottom; + goto done; + } + + /* check for btree corruption which could lead to deadlock */ + left_node = bnode->ndBLink; + right_node = bnode->ndFLink; + if ((left_node && hfs_bnode_in_brec(left_node, brec)) || + (right_node && hfs_bnode_in_brec(right_node, brec)) || + (left_node == right_node)) { + hfs_warn("hfs_bdelete: corrupt btree\n"); + hfs_brec_relse(brec, NULL); + return -EIO; + } + + /* grab the left neighbor if it exists */ + if (left_node) { + hfs_bnode_lock(&belem->bnr, HFS_LOCK_RESRV); + left = hfs_bnode_find(tree,left_node,HFS_LOCK_WRITE); + if (!left.bn) { + hfs_warn("hfs_bdelete: unable to read left " + "neighbor.\n"); + hfs_brec_relse(brec, NULL); + return -EIO; + } + hfs_bnode_lock(&belem->bnr, HFS_LOCK_WRITE); + if (parent->record != 1) { + left_space = bnode_freespace(left.bn); + } else { + left_space = NO_SPACE; + } + } else { + left.bn = NULL; + left_space = NO_SPACE; + } + + /* grab the right neighbor if it exists */ + if (right_node) { + right = hfs_bnode_find(tree,right_node,HFS_LOCK_WRITE); + if (!right.bn) { + hfs_warn("hfs_bdelete: unable to read right " + "neighbor.\n"); + hfs_bnode_relse(&left); + hfs_brec_relse(brec, NULL); + return -EIO; + } + if (parent->record < parent->bnr.bn->ndNRecs) { + right_space = bnode_freespace(right.bn); + } else { + right_space = NO_SPACE; + } + } else { + right.bn = NULL; + right_space = NO_SPACE; + } + + if (left_space < right_space) { + min_space = left_space; + } else { + min_space = right_space; + } + + if (min_space == NO_SPACE) { + hfs_warn("hfs_bdelete: no siblings?\n"); + hfs_brec_relse(brec, NULL); + return -EIO; + } + + if (bnode->ndNRecs == 0) { + delete_empty_bnode(left_node, &left, &belem->bnr, + right_node, &right); + } else if (min_space + bnode_freespace(bnode) >= FULL) { + if ((right_space == NO_SPACE) || + ((right_space == min_space) && + (left_space != NO_SPACE))) { + hfs_bnode_shift_left(left.bn, bnode, + bnode->ndNRecs); + } else { + hfs_bnode_shift_right(bnode, right.bn, 1); + fix_right_key = 1; + } + delete_empty_bnode(left_node, &left, &belem->bnr, + right_node, &right); + } else if (min_space == right_space) { + balance(bnode, right.bn); + fix_right_key = 1; + } else { + balance(left.bn, bnode); + fix_key = 1; + } + + if (fix_right_key) { + hfs_bnode_update_key(brec, belem, right.bn, 1); + } + + hfs_bnode_relse(&left); + hfs_bnode_relse(&right); + + if (bnode->ndNRecs) { + if (fix_key) { + hfs_bnode_update_key(brec, belem, bnode, 0); + } + goto done; + } + + hfs_bnode_free(&belem->bnr); + --brec->bottom; + belem = parent; + --parent; + } + + if (belem < brec->top) { + hfs_warn("hfs_bdelete: Missing parent.\n"); + hfs_brec_relse(brec, NULL); + return -EIO; + } + + bdelete_nonempty(brec, belem); + +done: + hfs_brec_relse(brec, NULL); + return 0; +} + +/*================ Global functions ================*/ + +/* + * hfs_bdelete() + * + * Delete the requested record from a B-tree. + */ +int hfs_bdelete(struct hfs_btree *tree, const struct hfs_bkey *key) +{ + struct hfs_belem *belem; + struct hfs_bnode *bnode; + struct hfs_brec brec; + int retval; + + if (!tree || (tree->magic != HFS_BTREE_MAGIC) || !key) { + hfs_warn("hfs_bdelete: invalid arguments.\n"); + return -EINVAL; + } + + retval = hfs_bfind(&brec, tree, key, HFS_BFIND_DELETE); + if (!retval) { + belem = brec.bottom; + bnode = belem->bnr.bn; + + belem->flags = 0; + if ((bnode->ndNRecs * sizeof(hfs_u16) + bnode_end(bnode) - + bnode_rsize(bnode, belem->record)) < FULL/2) { + belem->flags |= HFS_BPATH_UNDERFLOW; + } + if (belem->record == 1) { + belem->flags |= HFS_BPATH_FIRST; + } + + if (!belem->flags) { + hfs_brec_lock(&brec, brec.bottom); + } else { + hfs_brec_lock(&brec, NULL); + } + + retval = bdelete(&brec); + if (!retval) { + --brec.tree->bthNRecs; + brec.tree->dirt = 1; + } + hfs_brec_relse(&brec, NULL); + } + return retval; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/bfind.c linux/fs/hfs/bfind.c --- v2.1.77/linux/fs/hfs/bfind.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/bfind.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,322 @@ +/* + * linux/fs/hfs/bfind.c + * + * Copyright (C) 1995, 1996 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the code to access records in a btree. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs_btree.h" + +/*================ Global functions ================*/ + +/* + * hfs_brec_relse() + * + * Description: + * This function releases some of the nodes associated with a brec. + * Input Variable(s): + * struct hfs_brec *brec: pointer to the brec to release some nodes from. + * struct hfs_belem *elem: the last node to release or NULL for all + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'brec' points to a "valid" (struct hfs_brec) + * Postconditions: + * All nodes between the indicated node and the beginning of the path + * are released. + */ +void hfs_brec_relse(struct hfs_brec *brec, struct hfs_belem *elem) +{ + if (!elem) { + elem = brec->bottom; + } + + while (brec->top <= elem) { + hfs_bnode_relse(&brec->top->bnr); + ++brec->top; + } +} + +/* + * hfs_bfind() + * + * Description: + * This function has sole responsibility for locating existing + * records in a B-tree. Given a B-tree and a key it locates the + * "greatest" record "less than or equal to" the given key. The + * exact behavior is determined by the bits of the flags variable as + * follows: + * ('flags' & HFS_LOCK_MASK): + * The lock_type argument to be used when calling hfs_bnode_find(). + * HFS_BFIND_EXACT: only accept an exact match, otherwise take the + * "largest" record less than 'target' as a "match" + * HFS_BFIND_LOCK: request HFS_LOCK_WRITE access to the node containing + * the "matching" record when it is located + * HFS_BPATH_FIRST: keep access to internal nodes when accessing their + * first child. + * HFS_BPATH_OVERFLOW: keep access to internal nodes when the accessed + * child is too full to insert another pointer record. + * HFS_BPATH_UNDERFLOW: keep access to internal nodes when the accessed + * child is would be less than half full upon removing a pointer record. + * Input Variable(s): + * struct hfs_brec *brec: pointer to the (struct hfs_brec) to hold + * the search results. + * struct hfs_bkey *target: pointer to the (struct hfs_bkey) + * to search for + * int flags: bitwise OR of flags which determine the function's behavior + * Output Variable(s): + * 'brec' contains the results of the search on success or is invalid + * on failure. + * Returns: + * int: 0 or 1 on success or an error code on failure: + * -EINVAL: one of the input variables was NULL. + * -ENOENT: tree is valid but empty or no "matching" record was located. + * If the HFS_BFIND_EXACT bit of 'flags' is not set then the case of no + * matching record will give a 'brec' with a 'record' field of zero + * rather than returning this error. + * -EIO: an I/O operation or an assertion about the structure of a + * valid B-tree failed indicating corruption of either the B-tree + * structure on the disk or one of the in-core structures representing + * the B-tree. + * (This could also be returned if a kmalloc() call failed in a + * subordinate routine that is intended to get the data from the + * disk or the buffer cache.) + * Preconditions: + * 'brec' is NULL or points to a (struct hfs_brec) with a 'tree' field + * which points to a valid (struct hfs_btree). + * 'target' is NULL or points to a "valid" (struct hfs_bkey) + * Postconditions: + * If 'brec', 'brec->tree' or 'target' is NULL then -EINVAL is returned. + * If 'brec', 'brec->tree' and 'target' are non-NULL but the tree + * is empty then -ENOENT is returned. + * If 'brec', 'brec->tree' and 'target' are non-NULL but the call to + * hfs_brec_init() fails then '*brec' is NULL and -EIO is returned. + * If 'brec', 'brec->tree' and 'target' are non-NULL and the tree is + * non-empty then the tree is searched as follows: + * If any call to hfs_brec_next() fails or returns a node that is + * neither an index node nor a leaf node then -EIO is returned to + * indicate that the B-tree or buffer-cache are corrupted. + * If every record in the tree is "greater than" the given key + * and the HFS_BFIND_EXACT bit of 'flags' is set then -ENOENT is returned. + * If every record in the tree is "greater than" the given key + * and the HFS_BFIND_EXACT bit of 'flags' is clear then 'brec' refers + * to the first leaf node in the tree and has a 'record' field of + * zero, and 1 is returned. + * If a "matching" record is located with key "equal to" 'target' + * then the return value is 0 and 'brec' indicates the record. + * If a "matching" record is located with key "greater than" 'target' + * then the behavior is determined as follows: + * If the HFS_BFIND_EXACT bit of 'flags' is not set then 1 is returned + * and 'brec' refers to the "matching" record. + * If the HFS_BFIND_EXACT bit of 'flags' is set then -ENOENT is returned. + * If the return value is non-negative and the HFS_BFIND_LOCK bit of + * 'flags' is set then hfs_brec_lock() is called on the bottom element + * of 'brec' before returning. + */ +int hfs_bfind(struct hfs_brec *brec, struct hfs_btree *tree, + const struct hfs_bkey *target, int flags) +{ + struct hfs_belem *curr; + struct hfs_bkey *key; + struct hfs_bnode *bn; + int result, ntype; + + /* check for invalid arguments */ + if (!brec || (tree->magic != HFS_BTREE_MAGIC) || !target) { + return -EINVAL; + } + + /* check for empty tree */ + if (!tree->root || !tree->bthNRecs) { + return -ENOENT; + } + + /* start search at root of tree */ + if (!(curr = hfs_brec_init(brec, tree, flags))) { + return -EIO; + } + + /* traverse the tree */ + do { + bn = curr->bnr.bn; + + if (!curr->record) { + hfs_warn("hfs_bfind: empty bnode\n"); + hfs_brec_relse(brec, NULL); + return -EIO; + } + + /* reverse linear search yielding largest key "less + than or equal to" 'target'. + It is questionable whether a binary search would be + significantly faster */ + do { + key = belem_key(curr); + if (!key->KeyLen) { + hfs_warn("hfs_bfind: empty key\n"); + hfs_brec_relse(brec, NULL); + return -EIO; + } + result = (tree->compare)(target, key); + } while ((result<0) && (--curr->record)); + + ntype = bn->ndType; + + /* see if all keys > target */ + if (!curr->record) { + if (bn->ndBLink) { + /* at a node other than the left-most at a + given level it means the parent had an + incorrect key for this child */ + hfs_brec_relse(brec, NULL); + hfs_warn("hfs_bfind: corrupted b-tree %d.\n", + (int)ntohl(tree->entry.cnid)); + return -EIO; + } + if (flags & HFS_BFIND_EXACT) { + /* we're not going to find it */ + hfs_brec_relse(brec, NULL); + return -ENOENT; + } + if (ntype == ndIndxNode) { + /* since we are at the left-most node at + the current level and looking for the + predecessor of 'target' keep going down */ + curr->record = 1; + } else { + /* we're at first leaf so fall through */ + } + } + + /* get next node if necessary */ + if ((ntype == ndIndxNode) && !(curr = hfs_brec_next(brec))) { + return -EIO; + } + } while (ntype == ndIndxNode); + + if (key->KeyLen > tree->bthKeyLen) { + hfs_warn("hfs_bfind: oversized key\n"); + hfs_brec_relse(brec, NULL); + return -EIO; + } + + if (ntype != ndLeafNode) { + hfs_warn("hfs_bfind: invalid node type %02x in node %d of " + "btree %d\n", bn->ndType, bn->node, + (int)ntohl(tree->entry.cnid)); + hfs_brec_relse(brec, NULL); + return -EIO; + } + + if ((flags & HFS_BFIND_EXACT) && result) { + hfs_brec_relse(brec, NULL); + return -ENOENT; + } + + if (!(flags & HFS_BPATH_MASK)) { + hfs_brec_relse(brec, brec->bottom-1); + } + + if (flags & HFS_BFIND_LOCK) { + hfs_brec_lock(brec, brec->bottom); + } + + brec->key = brec_key(brec); + brec->data = bkey_record(brec->key); + + return result ? 1 : 0; +} + +/* + * hfs_bsucc() + * + * Description: + * This function overwrites '*brec' with its successor in the B-tree, + * obtaining the same type of access. + * Input Variable(s): + * struct hfs_brec *brec: address of the (struct hfs_brec) to overwrite + * with its successor + * Output Variable(s): + * struct hfs_brec *brec: address of the successor of the original + * '*brec' or to invalid data + * Returns: + * int: 0 on success, or one of -EINVAL, -EIO, or -EINVAL on failure + * Preconditions: + * 'brec' pointers to a "valid" (struct hfs_brec) + * Postconditions: + * If the given '*brec' is not "valid" -EINVAL is returned and + * '*brec' is unchanged. + * If the given 'brec' is "valid" but has no successor then -ENOENT + * is returned and '*brec' is invalid. + * If a call to hfs_bnode_find() is necessary to find the successor, + * but fails then -EIO is returned and '*brec' is invalid. + * If none of the three previous conditions prevents finding the + * successor of '*brec', then 0 is returned, and '*brec' is overwritten + * with the (struct hfs_brec) for its successor. + * In the cases when '*brec' is invalid, the old records is freed. + */ +int hfs_bsucc(struct hfs_brec *brec, int count) +{ + struct hfs_belem *belem; + struct hfs_bnode *bn; + + if (!brec || !(belem = brec->bottom) || (belem != brec->top) || + !(bn = belem->bnr.bn) || (bn->magic != HFS_BNODE_MAGIC) || + !bn->tree || (bn->tree->magic != HFS_BTREE_MAGIC) || + !hfs_buffer_ok(bn->buf)) { + hfs_warn("hfs_bsucc: invalid/corrupt arguments.\n"); + return -EINVAL; + } + + while (count) { + int left = bn->ndNRecs - belem->record; + + if (left < count) { + struct hfs_bnode_ref old; + hfs_u32 node; + + /* Advance to next node */ + if (!(node = bn->ndFLink)) { + hfs_brec_relse(brec, belem); + return -ENOENT; + } + if (node == bn->node) { + hfs_warn("hfs_bsucc: corrupt btree\n"); + hfs_brec_relse(brec, belem); + return -EIO; + } + old = belem->bnr; + belem->bnr = hfs_bnode_find(brec->tree, node, + belem->bnr.lock_type); + hfs_bnode_relse(&old); + if (!(bn = belem->bnr.bn)) { + return -EIO; + } + belem->record = 1; + count -= (left + 1); + } else { + belem->record += count; + break; + } + } + brec->key = belem_key(belem); + brec->data = bkey_record(brec->key); + + if (brec->key->KeyLen > brec->tree->bthKeyLen) { + hfs_warn("hfs_bsucc: oversized key\n"); + hfs_brec_relse(brec, NULL); + return -EIO; + } + + return 0; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/bins_del.c linux/fs/hfs/bins_del.c --- v2.1.77/linux/fs/hfs/bins_del.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/bins_del.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,231 @@ +/* + * linux/fs/hfs/bins_del.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the code common to inserting and deleting records + * in a B-tree. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs_btree.h" + +/*================ File-local functions ================*/ + +/* + * hfs_bnode_update_key() + * + * Description: + * Updates the key for a bnode in its parent. + * The key change is propagated up the tree as necessary. + * Input Variable(s): + * struct hfs_brec *brec: the search path to update keys in + * struct hfs_belem *belem: the search path element with the changed key + * struct hfs_bnode *bnode: the bnode with the changed key + * int offset: the "distance" from 'belem->bn' to 'bnode': + * 0 if the change is in 'belem->bn', + * 1 if the change is in its right sibling, etc. + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'brec' points to a valid (struct hfs_brec) + * 'belem' points to a valid (struct hfs_belem) in 'brec'. + * 'bnode' points to a valid (struct hfs_bnode) which is non-empty + * and is 'belem->bn' or one of its siblings. + * 'offset' is as described above. + * Postconditions: + * The key change is propagated up the tree as necessary. + */ +void hfs_bnode_update_key(struct hfs_brec *brec, struct hfs_belem *belem, + struct hfs_bnode *bnode, int offset) +{ + int record = (--belem)->record + offset; + void *key = bnode_datastart(bnode) + 1; + int keysize = brec->tree->bthKeyLen; + struct hfs_belem *limit; + + memcpy(1+bnode_key(belem->bnr.bn, record), key, keysize); + + /* don't trash the header */ + if (brec->top > &brec->elem[1]) { + limit = brec->top; + } else { + limit = &brec->elem[1]; + } + + while ((belem > limit) && (record == 1)) { + record = (--belem)->record; + memcpy(1+belem_key(belem), key, keysize); + } +} + +/* + * hfs_bnode_shift_right() + * + * Description: + * Shifts some records from a node to its right neighbor. + * Input Variable(s): + * struct hfs_bnode* left: the node to shift records from + * struct hfs_bnode* right: the node to shift records to + * hfs_u16 first: the number of the first record in 'left' to move to 'right' + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'left' and 'right' point to valid (struct hfs_bnode)s. + * 'left' contains at least 'first' records. + * 'right' has enough free space to hold the records to be moved from 'left' + * Postconditions: + * The record numbered 'first' and all records after it in 'left' are + * placed at the beginning of 'right'. + * The key corresponding to 'right' in its parent is NOT updated. + */ +void hfs_bnode_shift_right(struct hfs_bnode *left, struct hfs_bnode *right, + int first) +{ + int i, adjust, nrecs; + unsigned size; + hfs_u16 *to, *from; + + if ((first <= 0) || (first > left->ndNRecs)) { + hfs_warn("bad argument to shift_right: first=%d, nrecs=%d\n", + first, left->ndNRecs); + return; + } + + /* initialize variables */ + nrecs = left->ndNRecs + 1 - first; + size = bnode_end(left) - bnode_offset(left, first); + + /* move (possibly empty) contents of right node forward */ + memmove(bnode_datastart(right) + size, + bnode_datastart(right), + bnode_end(right) - sizeof(struct NodeDescriptor)); + + /* copy in new records */ + memcpy(bnode_datastart(right), bnode_key(left,first), size); + + /* fix up offsets in right node */ + i = right->ndNRecs + 1; + from = RECTBL(right, i); + to = from - nrecs; + while (i--) { + hfs_put_hs(hfs_get_hs(from++) + size, to++); + } + adjust = sizeof(struct NodeDescriptor) - bnode_offset(left, first); + i = nrecs-1; + from = RECTBL(left, first+i); + while (i--) { + hfs_put_hs(hfs_get_hs(from++) + adjust, to++); + } + + /* fix record counts */ + left->ndNRecs -= nrecs; + right->ndNRecs += nrecs; +} + +/* + * hfs_bnode_shift_left() + * + * Description: + * Shifts some records from a node to its left neighbor. + * Input Variable(s): + * struct hfs_bnode* left: the node to shift records to + * struct hfs_bnode* right: the node to shift records from + * hfs_u16 last: the number of the last record in 'right' to move to 'left' + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'left' and 'right' point to valid (struct hfs_bnode)s. + * 'right' contains at least 'last' records. + * 'left' has enough free space to hold the records to be moved from 'right' + * Postconditions: + * The record numbered 'last' and all records before it in 'right' are + * placed at the end of 'left'. + * The key corresponding to 'right' in its parent is NOT updated. + */ +void hfs_bnode_shift_left(struct hfs_bnode *left, struct hfs_bnode *right, + int last) +{ + int i, adjust, nrecs; + unsigned size; + hfs_u16 *to, *from; + + if ((last <= 0) || (last > right->ndNRecs)) { + hfs_warn("bad argument to shift_left: last=%d, nrecs=%d\n", + last, right->ndNRecs); + return; + } + + /* initialize variables */ + size = bnode_offset(right, last + 1) - sizeof(struct NodeDescriptor); + + /* copy records to left node */ + memcpy(bnode_dataend(left), bnode_datastart(right), size); + + /* move (possibly empty) remainder of right node backward */ + memmove(bnode_datastart(right), bnode_datastart(right) + size, + bnode_end(right) - bnode_offset(right, last + 1)); + + /* fix up offsets */ + nrecs = left->ndNRecs; + i = last; + from = RECTBL(right, 2); + to = RECTBL(left, nrecs + 2); + adjust = bnode_offset(left, nrecs + 1) - sizeof(struct NodeDescriptor); + while (i--) { + hfs_put_hs(hfs_get_hs(from--) + adjust, to--); + } + i = right->ndNRecs + 1 - last; + ++from; + to = RECTBL(right, 1); + while (i--) { + hfs_put_hs(hfs_get_hs(from--) - size, to--); + } + + /* fix record counts */ + left->ndNRecs += last; + right->ndNRecs -= last; +} + +/* + * hfs_bnode_in_brec() + * + * Description: + * Determines whethet a given bnode is part of a given brec. + * This is used to avoid deadlock in the case of a corrupted b-tree. + * Input Variable(s): + * hfs_u32 node: the number of the node to check for. + * struct hfs_brec* brec: the brec to check in. + * Output Variable(s): + * NONE + * Returns: + * int: 1 it found, 0 if not + * Preconditions: + * 'brec' points to a valid struct hfs_brec. + * Postconditions: + * 'brec' is unchanged. + */ +int hfs_bnode_in_brec(hfs_u32 node, const struct hfs_brec *brec) +{ + const struct hfs_belem *belem = brec->bottom; + + while (belem && (belem >= brec->top)) { + if (belem->bnr.bn && (belem->bnr.bn->node == node)) { + return 1; + } + --belem; + } + return 0; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/binsert.c linux/fs/hfs/binsert.c --- v2.1.77/linux/fs/hfs/binsert.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/binsert.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,541 @@ +/* + * linux/fs/hfs/binsert.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the code to insert records in a B-tree. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs_btree.h" + +/*================ File-local functions ================*/ + +/* + * binsert_nonfull() + * + * Description: + * Inserts a record in a given bnode known to have sufficient space. + * Input Variable(s): + * struct hfs_brec* brec: pointer to the brec for the insertion + * struct hfs_belem* belem: the element in the search path to insert in + * struct hfs_bkey* key: pointer to the key for the record to insert + * void* data: pointer to the record to insert + * hfs_u16 keysize: size of the key to insert + * hfs_u16 datasize: size of the record to insert + * Output Variable(s): + * NONE + * Returns: + * NONE + * Preconditions: + * 'brec' points to a valid (struct hfs_brec). + * 'belem' points to a valid (struct hfs_belem) in 'brec', the node + * of which has enough free space to insert 'key' and 'data'. + * 'key' is a pointer to a valid (struct hfs_bkey) of length 'keysize' + * which, in sorted order, belongs at the location indicated by 'brec'. + * 'data' is non-NULL an points to appropriate data of length 'datasize' + * Postconditions: + * The record has been inserted in the position indicated by 'brec'. + */ +static void binsert_nonfull(struct hfs_brec *brec, struct hfs_belem *belem, + const struct hfs_bkey *key, const void *data, + hfs_u8 keysize, hfs_u16 datasize) +{ + int i, rec, nrecs, size, tomove; + hfs_u8 *start; + struct hfs_bnode *bnode = belem->bnr.bn; + + rec = ++(belem->record); + size = ROUND(keysize+1) + datasize; + nrecs = bnode->ndNRecs + 1; + tomove = bnode_offset(bnode, nrecs) - bnode_offset(bnode, rec); + + /* adjust the record table */ + for (i = nrecs; i >= rec; --i) { + hfs_put_hs(bnode_offset(bnode,i) + size, RECTBL(bnode,i+1)); + } + + /* make room */ + start = bnode_key(bnode, rec); + memmove(start + size, start, tomove); + + /* copy in the key and the data*/ + *start = keysize; + keysize = ROUND(keysize+1); + memcpy(start + 1, (hfs_u8 *)key + 1, keysize-1); + memcpy(start + keysize, data, datasize); + + /* update record count */ + ++bnode->ndNRecs; +} + +/* + * add_root() + * + * Description: + * Adds a new root to a B*-tree, increasing its height. + * Input Variable(s): + * struct hfs_btree *tree: the tree to add a new root to + * struct hfs_bnode *left: the new root's first child or NULL + * struct hfs_bnode *right: the new root's second child or NULL + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'tree' points to a valid (struct hfs_btree). + * 'left' and 'right' point to valid (struct hfs_bnode)s, which + * resulted from splitting the old root node, or are both NULL + * if there was no root node before. + * Postconditions: + * Upon success a new root node is added to 'tree' with either + * two children ('left' and 'right') or none. + */ +static void add_root(struct hfs_btree *tree, + struct hfs_bnode *left, + struct hfs_bnode *right) +{ + struct hfs_bnode_ref bnr; + struct hfs_bnode *root; + struct hfs_bkey *key; + int keylen = tree->bthKeyLen; + + if (left && !right) { + hfs_warn("add_root: LEFT but no RIGHT\n"); + return; + } + + bnr = hfs_bnode_alloc(tree); + if (!(root = bnr.bn)) { + return; + } + + root->sticky = HFS_STICKY; + tree->root = root; + tree->bthRoot = root->node; + ++tree->bthDepth; + + root->ndNHeight = tree->bthDepth; + root->ndFLink = 0; + root->ndBLink = 0; + + if (!left) { + /* tree was empty */ + root->ndType = ndLeafNode; + root->ndNRecs = 0; + + tree->bthFNode = root->node; + tree->bthLNode = root->node; + } else { + root->ndType = ndIndxNode; + root->ndNRecs = 2; + + hfs_put_hs(sizeof(struct NodeDescriptor) + ROUND(1+keylen) + + sizeof(hfs_u32), RECTBL(root, 2)); + key = bnode_key(root, 1); + key->KeyLen = keylen; + memcpy(key->value, + ((struct hfs_bkey *)bnode_key(left, 1))->value, keylen); + hfs_put_hl(left->node, bkey_record(key)); + + hfs_put_hs(sizeof(struct NodeDescriptor) + 2*ROUND(1+keylen) + + 2*sizeof(hfs_u32), RECTBL(root, 3)); + key = bnode_key(root, 2); + key->KeyLen = keylen; + memcpy(key->value, + ((struct hfs_bkey *)bnode_key(right, 1))->value, keylen); + hfs_put_hl(right->node, bkey_record(key)); + + /* the former root (left) is now just a normal node */ + left->sticky = HFS_NOT_STICKY; + if ((left->next = bhash(tree, left->node))) { + left->next->prev = left; + } + bhash(tree, left->node) = left; + } + hfs_bnode_relse(&bnr); + tree->dirt = 1; +} + +/* + * insert_empty_bnode() + * + * Description: + * Adds an empty node to the right of 'left'. + * Input Variable(s): + * struct hfs_btree *tree: the tree to add a node to + * struct hfs_bnode *left: the node to add a node after + * Output Variable(s): + * NONE + * Returns: + * struct hfs_bnode_ref *: reference to the new bnode. + * Preconditions: + * 'tree' points to a valid (struct hfs_btree) with at least 1 free node. + * 'left' points to a valid (struct hfs_bnode) belonging to 'tree'. + * Postconditions: + * If NULL is returned then 'tree' and 'left' are unchanged. + * Otherwise a node with 0 records is inserted in the tree to the right + * of the node 'left'. The 'ndFLink' of 'left' and the 'ndBLink' of + * the former right-neighbor of 'left' (if one existed) point to the + * new node. If 'left' had no right neighbor and is a leaf node the + * the 'bthLNode' of 'tree' points to the new node. The free-count and + * bitmap for 'tree' are kept current by hfs_bnode_alloc() which supplies + * the required node. + */ +static struct hfs_bnode_ref insert_empty_bnode(struct hfs_btree *tree, + struct hfs_bnode *left) +{ + struct hfs_bnode_ref retval; + struct hfs_bnode_ref right; + + retval = hfs_bnode_alloc(tree); + if (!retval.bn) { + hfs_warn("hfs_binsert: out of bnodes?.\n"); + goto done; + } + retval.bn->sticky = HFS_NOT_STICKY; + if ((retval.bn->next = bhash(tree, retval.bn->node))) { + retval.bn->next->prev = retval.bn; + } + bhash(tree, retval.bn->node) = retval.bn; + + if (left->ndFLink) { + right = hfs_bnode_find(tree, left->ndFLink, HFS_LOCK_WRITE); + if (!right.bn) { + hfs_warn("hfs_binsert: corrupt btree.\n"); + hfs_bnode_bitop(tree, retval.bn->node, 0); + hfs_bnode_relse(&retval); + goto done; + } + right.bn->ndBLink = retval.bn->node; + hfs_bnode_relse(&right); + } else if (left->ndType == ndLeafNode) { + tree->bthLNode = retval.bn->node; + tree->dirt = 1; + } + + retval.bn->ndFLink = left->ndFLink; + retval.bn->ndBLink = left->node; + retval.bn->ndType = left->ndType; + retval.bn->ndNHeight = left->ndNHeight; + retval.bn->ndNRecs = 0; + + left->ndFLink = retval.bn->node; + + done: + return retval; +} + +/* + * split() + * + * Description: + * Splits an over full node during insertion. + * Picks the split point that results in the most-nearly equal + * space usage in the new and old nodes. + * Input Variable(s): + * struct hfs_belem *elem: the over full node. + * int size: the number of bytes to be used by the new record and its key. + * Output Variable(s): + * struct hfs_belem *elem: changed to indicate where the new record + * should be inserted. + * Returns: + * struct hfs_bnode_ref: reference to the new bnode. + * Preconditions: + * 'elem' points to a valid path element corresponding to the over full node. + * 'size' is positive. + * Postconditions: + * The records in the node corresponding to 'elem' are redistributed across + * the old and new nodes so that after inserting the new record, the space + * usage in these two nodes is as equal as possible. + * 'elem' is updated so that a call to binsert_nonfull() will insert the + * new record in the correct location. + */ +static inline struct hfs_bnode_ref split(struct hfs_belem *elem, int size) +{ + struct hfs_bnode *bnode = elem->bnr.bn; + int nrecs, cutoff, index, tmp, used, in_right; + struct hfs_bnode_ref right; + + right = insert_empty_bnode(bnode->tree, bnode); + if (right.bn) { + nrecs = bnode->ndNRecs; + cutoff = (size + bnode_end(bnode) - + sizeof(struct NodeDescriptor) + + (nrecs+1)*sizeof(hfs_u16))/2; + used = 0; + in_right = 1; + /* note that this only works because records sizes are even */ + for (index=1; index <= elem->record; ++index) { + tmp = (sizeof(hfs_u16) + bnode_rsize(bnode, index))/2; + used += tmp; + if (used > cutoff) { + goto found; + } + used += tmp; + } + tmp = (size + sizeof(hfs_u16))/2; + used += tmp; + if (used > cutoff) { + goto found; + } + in_right = 0; + used += tmp; + for (; index <= nrecs; ++index) { + tmp = (sizeof(hfs_u16) + bnode_rsize(bnode, index))/2; + used += tmp; + if (used > cutoff) { + goto found; + } + used += tmp; + } + /* couldn't find the split point! */ + hfs_bnode_relse(&right); + } + return right; + +found: + if (in_right) { + elem->bnr = right; + elem->record -= index-1; + } + hfs_bnode_shift_right(bnode, right.bn, index); + + return right; +} + +/* + * binsert() + * + * Description: + * Inserts a record in a tree known to have enough room, even if the + * insertion requires the splitting of nodes. + * Input Variable(s): + * struct hfs_brec *brec: partial path to the node to insert in + * const struct hfs_bkey *key: key for the new record + * const void *data: data for the new record + * hfs_u8 keysize: size of the key + * hfs_u16 datasize: size of the data + * int reserve: number of nodes reserved in case of splits + * Output Variable(s): + * *brec = NULL + * Returns: + * int: 0 on success, error code on failure + * Preconditions: + * 'brec' points to a valid (struct hfs_brec) corresponding to a + * record in a leaf node, after which a record is to be inserted, + * or to "record 0" of the leaf node if the record is to be inserted + * before all existing records in the node. The (struct hfs_brec) + * includes all ancestors of the leaf node that are needed to + * complete the insertion including the parents of any nodes that + * will be split. + * 'key' points to a valid (struct hfs_bkey) which is appropriate + * to this tree, and which belongs at the insertion point. + * 'data' points data appropriate for the indicated node. + * 'keysize' gives the size in bytes of the key. + * 'datasize' gives the size in bytes of the data. + * 'reserve' gives the number of nodes that have been reserved in the + * tree to allow for splitting of nodes. + * Postconditions: + * All 'reserve'd nodes have been either used or released. + * *brec = NULL + * On success the key and data have been inserted at the indicated + * location in the tree, all appropriate fields of the in-core data + * structures have been changed and updated versions of the on-disk + * data structures have been scheduled for write-back to disk. + * On failure the B*-tree is probably invalid both on disk and in-core. + * + * XXX: Some attempt at repair might be made in the event of failure, + * or the fs should be remounted read-only so things don't get worse. + */ +static int binsert(struct hfs_brec *brec, const struct hfs_bkey *key, + const void *data, hfs_u8 keysize, hfs_u16 datasize, + int reserve) +{ + struct hfs_bnode_ref left, right, other; + struct hfs_btree *tree = brec->tree; + struct hfs_belem *belem = brec->bottom; + int tmpsize = 1 + tree->bthKeyLen; + struct hfs_bkey *tmpkey = hfs_malloc(tmpsize); + hfs_u32 node; + + while ((belem >= brec->top) && (belem->flags & HFS_BPATH_OVERFLOW)) { + left = belem->bnr; + if (left.bn->ndFLink && + hfs_bnode_in_brec(left.bn->ndFLink, brec)) { + hfs_warn("hfs_binsert: corrupt btree\n"); + tree->reserved -= reserve; + hfs_free(tmpkey, tmpsize); + return -EIO; + } + + right = split(belem, ROUND(keysize+1) + ROUND(datasize)); + --reserve; + --tree->reserved; + if (!right.bn) { + hfs_warn("hfs_binsert: unable to split node!\n"); + tree->reserved -= reserve; + hfs_free(tmpkey, tmpsize); + return -ENOSPC; + } + binsert_nonfull(brec, belem, key, data, keysize, datasize); + + if (belem->bnr.bn == left.bn) { + other = right; + if (belem->record == 1) { + hfs_bnode_update_key(brec, belem, left.bn, 0); + } + } else { + other = left; + } + + if (left.bn->node == tree->root->node) { + add_root(tree, left.bn, right.bn); + hfs_bnode_relse(&other); + goto done; + } + + data = &node; + datasize = sizeof(node); + node = htonl(right.bn->node); + key = tmpkey; + keysize = tree->bthKeyLen; + memcpy(tmpkey, bnode_key(right.bn, 1), keysize+1); + hfs_bnode_relse(&other); + + --belem; + } + + if (belem < brec->top) { + hfs_warn("hfs_binsert: Missing parent.\n"); + tree->reserved -= reserve; + hfs_free(tmpkey, tmpsize); + return -EIO; + } + + binsert_nonfull(brec, belem, key, data, keysize, datasize); + +done: + tree->reserved -= reserve; + hfs_free(tmpkey, tmpsize); + return 0; +} + +/*================ Global functions ================*/ + +/* + * hfs_binsert() + * + * Description: + * This function inserts a new record into a b-tree. + * Input Variable(s): + * struct hfs_btree *tree: pointer to the (struct hfs_btree) to insert in + * struct hfs_bkey *key: pointer to the (struct hfs_bkey) to insert + * void *data: pointer to the data to associate with 'key' in the b-tree + * unsigned int datasize: the size of the data + * Output Variable(s): + * NONE + * Returns: + * int: 0 on success, error code on failure + * Preconditions: + * 'tree' points to a valid (struct hfs_btree) + * 'key' points to a valid (struct hfs_bkey) + * 'data' points to valid memory of length 'datasize' + * Postconditions: + * If zero is returned then the record has been inserted in the + * indicated location updating all in-core data structures and + * scheduling all on-disk data structures for write-back. + */ +int hfs_binsert(struct hfs_btree *tree, const struct hfs_bkey *key, + const void *data, hfs_u16 datasize) +{ + struct hfs_brec brec; + struct hfs_belem *belem; + int err, reserve, retval; + hfs_u8 keysize; + + if (!tree || (tree->magic != HFS_BTREE_MAGIC) || !key || !data) { + hfs_warn("hfs_binsert: invalid arguments.\n"); + return -EINVAL; + } + + if (key->KeyLen > tree->bthKeyLen) { + hfs_warn("hfs_binsert: oversized key\n"); + return -EINVAL; + } + +restart: + if (!tree->bthNRecs) { + /* create the root bnode */ + add_root(tree, NULL, NULL); + if (!hfs_brec_init(&brec, tree, HFS_BFIND_INSERT)) { + hfs_warn("hfs_binsert: failed to create root.\n"); + return -ENOSPC; + } + } else { + err = hfs_bfind(&brec, tree, key, HFS_BFIND_INSERT); + if (err < 0) { + hfs_warn("hfs_binsert: hfs_brec_find failed.\n"); + return err; + } else if (err == 0) { + hfs_brec_relse(&brec, NULL); + return -EEXIST; + } + } + + keysize = key->KeyLen; + datasize = ROUND(datasize); + belem = brec.bottom; + belem->flags = 0; + if (bnode_freespace(belem->bnr.bn) < + (sizeof(hfs_u16) + ROUND(keysize+1) + datasize)) { + belem->flags |= HFS_BPATH_OVERFLOW; + } + if (belem->record == 0) { + belem->flags |= HFS_BPATH_FIRST; + } + + if (!belem->flags) { + hfs_brec_lock(&brec, brec.bottom); + reserve = 0; + } else { + reserve = brec.bottom - brec.top; + if (brec.top == 0) { + ++reserve; + } + /* make certain we have enough nodes to proceed */ + if ((tree->bthFree - tree->reserved) < reserve) { + hfs_brec_relse(&brec, NULL); + while (tree->lock) { + hfs_sleep_on(&tree->wait); + } + tree->lock = 1; + if ((tree->bthFree - tree->reserved) < reserve) { + hfs_btree_extend(tree); + } + tree->lock = 0; + hfs_wake_up(&tree->wait); + if ((tree->bthFree - tree->reserved) < reserve) { + return -ENOSPC; + } else { + goto restart; + } + } + tree->reserved += reserve; + hfs_brec_lock(&brec, NULL); + } + + retval = binsert(&brec, key, data, keysize, datasize, reserve); + hfs_brec_relse(&brec, NULL); + if (!retval) { + ++tree->bthNRecs; + tree->dirt = 1; + } + return retval; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/bitmap.c linux/fs/hfs/bitmap.c --- v2.1.77/linux/fs/hfs/bitmap.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/bitmap.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,412 @@ +/* + * linux/fs/hfs/bitmap.c + * + * Copyright (C) 1996-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * Based on GPLed code Copyright (C) 1995 Michael Dreher + * + * This file contains the code to modify the volume bitmap: + * search/set/clear bits. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" + +/*================ Global functions ================*/ + +/* + * hfs_vbm_count_free() + * + * Description: + * Count the number of consecutive cleared bits in the bitmap blocks of + * the hfs MDB starting at bit number 'start'. 'mdb' had better + * be locked or the indicated number of blocks may be no longer free, + * when this functions returns! + * Input Variable(s): + * struct hfs_mdb *mdb: Pointer to the hfs MDB + * hfs_u16 start: bit number to start at + * Output Variable(s): + * NONE + * Returns: + * The number of consecutive cleared bits starting at bit 'start' + * Preconditions: + * 'mdb' points to a "valid" (struct hfs_mdb). + * Postconditions: + * NONE + */ +hfs_u16 hfs_vbm_count_free(const struct hfs_mdb *mdb, hfs_u16 start) +{ + hfs_u16 block_nr; /* index of the current bitmap block */ + hfs_u16 bit_nr; /* index of the current bit in block */ + hfs_u16 count; /* number of bits found so far */ + hfs_u16 len; /* number of bits found in this block */ + hfs_u16 max_block; /* index of last bitmap block */ + hfs_u16 max_bits; /* index of last bit in block */ + + /* is this a valid HFS MDB? */ + if (!mdb) { + return 0; + } + + block_nr = start / HFS_BM_BPB; + bit_nr = start % HFS_BM_BPB; + max_block = (mdb->fs_ablocks + HFS_BM_BPB - 1) / HFS_BM_BPB - 1; + + count = 0; + while (block_nr <= max_block) { + if (block_nr != max_block) { + max_bits = HFS_BM_BPB; + } else { + max_bits = mdb->fs_ablocks % HFS_BM_BPB; + } + + len=hfs_count_zero_bits(hfs_buffer_data(mdb->bitmap[block_nr]), + max_bits, bit_nr); + count += len; + + /* see if we fell short of the end of this block */ + if ((len + bit_nr) < max_bits) { + break; + } + + ++block_nr; + bit_nr = 0; + } + return count; +} + +/* + * hfs_vbm_search_free() + * + * Description: + * Search for 'num_bits' consecutive cleared bits in the bitmap blocks of + * the hfs MDB. 'mdb' had better be locked or the returned range + * may be no longer free, when this functions returns! + * XXX Currently the search starts from bit 0, but it should start with + * the bit number stored in 's_alloc_ptr' of the MDB. + * Input Variable(s): + * struct hfs_mdb *mdb: Pointer to the hfs MDB + * hfs_u16 *num_bits: Pointer to the number of cleared bits + * to search for + * Output Variable(s): + * hfs_u16 *num_bits: The number of consecutive clear bits of the + * returned range. If the bitmap is fragmented, this will be less than + * requested and it will be zero, when the disk is full. + * Returns: + * The number of the first bit of the range of cleared bits which has been + * found. When 'num_bits' is zero, this is invalid! + * Preconditions: + * 'mdb' points to a "valid" (struct hfs_mdb). + * 'num_bits' points to a variable of type (hfs_u16), which contains + * the number of cleared bits to find. + * Postconditions: + * 'num_bits' is set to the length of the found sequence. + */ +hfs_u16 hfs_vbm_search_free(const struct hfs_mdb *mdb, hfs_u16 *num_bits) +{ + hfs_u16 block_nr; /* index of the current bitmap block */ + + /* position and length of current portion of a run */ + hfs_u16 cur_pos, cur_len; + + /* position and length of current complete run */ + hfs_u16 pos=0, len=0; + + /* position and length of longest complete run */ + hfs_u16 longest_pos=0, longest_len=0; + + void *bitmap; /* contents of the current bitmap block */ + hfs_u16 max_block; /* upper limit of outer loop */ + hfs_u16 max_bits; /* upper limit of inner loop */ + + /* is this a valid HFS MDB? */ + if (!mdb) { + *num_bits = 0; + hfs_warn("hfs_vbm_search_free: not a valid MDB\n"); + return 0; + } + + /* make sure we have actual work to perform */ + if (!(*num_bits)) { + return 0; + } + + max_block = (mdb->fs_ablocks+HFS_BM_BPB-1) / HFS_BM_BPB - 1; + + /* search all bitmap blocks */ + for (block_nr = 0; block_nr <= max_block; block_nr++) { + bitmap = hfs_buffer_data(mdb->bitmap[block_nr]); + + if (block_nr != max_block) { + max_bits = HFS_BM_BPB; + } else { + max_bits = mdb->fs_ablocks % HFS_BM_BPB; + } + + cur_pos = 0; + do { + cur_len = hfs_count_zero_bits(bitmap, max_bits, + cur_pos); + len += cur_len; + if (len > longest_len) { + longest_pos = pos; + longest_len = len; + if (len >= *num_bits) { + goto search_end; + } + } + if ((cur_pos + cur_len) == max_bits) { + break; /* zeros may continue into next block */ + } + + /* find start of next run of zeros */ + cur_pos = hfs_find_zero_bit(bitmap, max_bits, + cur_pos + cur_len); + pos = cur_pos + HFS_BM_BPB*block_nr; + len = 0; + } while (cur_pos < max_bits); + } + +search_end: + *num_bits = longest_len; + return longest_pos; +} + + +/* + * hfs_set_vbm_bits() + * + * Description: + * Set the requested bits in the volume bitmap of the hfs filesystem + * Input Variable(s): + * struct hfs_mdb *mdb: Pointer to the hfs MDB + * hfs_u16 start: The offset of the first bit + * hfs_u16 count: The number of bits + * Output Variable(s): + * None + * Returns: + * 0: no error + * -1: One of the bits was already set. This is a strange + * error and when it happens, the filesystem must be repaired! + * -2: One or more of the bits are out of range of the bitmap. + * -3: The 's_magic' field of the MDB does not match + * Preconditions: + * 'mdb' points to a "valid" (struct hfs_mdb). + * Postconditions: + * Starting with bit number 'start', 'count' bits in the volume bitmap + * are set. The affected bitmap blocks are marked "dirty", the free + * block count of the MDB is updated and the MDB is marked dirty. + */ +int hfs_set_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count) +{ + hfs_u16 block_nr; /* index of the current bitmap block */ + hfs_u16 u32_nr; /* index of the current hfs_u32 in block */ + hfs_u16 bit_nr; /* index of the current bit in hfs_u32 */ + hfs_u16 left = count; /* number of bits left to be set */ + hfs_u32 *bitmap; /* the current bitmap block's contents */ + + /* is this a valid HFS MDB? */ + if (!mdb) { + return -3; + } + + /* is there any actual work to be done? */ + if (!count) { + return 0; + } + + /* are all of the bits in range? */ + if ((start + count) > mdb->fs_ablocks) { + return -2; + } + + block_nr = start / HFS_BM_BPB; + u32_nr = (start % HFS_BM_BPB) / 32; + bit_nr = start % 32; + + /* bitmap is always on a 32-bit boundary */ + bitmap = (hfs_u32 *)hfs_buffer_data(mdb->bitmap[block_nr]); + + /* do any partial hfs_u32 at the start */ + if (bit_nr != 0) { + while ((bit_nr < 32) && left) { + if (hfs_set_bit(bit_nr, bitmap + u32_nr)) { + hfs_buffer_dirty(mdb->bitmap[block_nr]); + return -1; + } + ++bit_nr; + --left; + } + bit_nr=0; + + /* advance u32_nr and check for end of this block */ + if (++u32_nr > 127) { + u32_nr = 0; + hfs_buffer_dirty(mdb->bitmap[block_nr]); + ++block_nr; + /* bitmap is always on a 32-bit boundary */ + bitmap = (hfs_u32 *) + hfs_buffer_data(mdb->bitmap[block_nr]); + } + } + + /* do full hfs_u32s */ + while (left > 31) { + if (bitmap[u32_nr] != ((hfs_u32)0)) { + hfs_buffer_dirty(mdb->bitmap[block_nr]); + return -1; + } + bitmap[u32_nr] = ~((hfs_u32)0); + left -= 32; + + /* advance u32_nr and check for end of this block */ + if (++u32_nr > 127) { + u32_nr = 0; + hfs_buffer_dirty(mdb->bitmap[block_nr]); + ++block_nr; + /* bitmap is always on a 32-bit boundary */ + bitmap = (hfs_u32 *) + hfs_buffer_data(mdb->bitmap[block_nr]); + } + } + + + /* do any partial hfs_u32 at end */ + while (left) { + if (hfs_set_bit(bit_nr, bitmap + u32_nr)) { + hfs_buffer_dirty(mdb->bitmap[block_nr]); + return -1; + } + ++bit_nr; + --left; + } + + hfs_buffer_dirty(mdb->bitmap[block_nr]); + mdb->free_ablocks -= count; + + /* successful completion */ + hfs_mdb_dirty(mdb->sys_mdb); + return 0; +} + +/* + * hfs_clear_vbm_bits() + * + * Description: + * Clear the requested bits in the volume bitmap of the hfs filesystem + * Input Variable(s): + * struct hfs_mdb *mdb: Pointer to the hfs MDB + * hfs_u16 start: The offset of the first bit + * hfs_u16 count: The number of bits + * Output Variable(s): + * None + * Returns: + * 0: no error + * -1: One of the bits was already clear. This is a strange + * error and when it happens, the filesystem must be repaired! + * -2: One or more of the bits are out of range of the bitmap. + * -3: The 's_magic' field of the MDB does not match + * Preconditions: + * 'mdb' points to a "valid" (struct hfs_mdb). + * Postconditions: + * Starting with bit number 'start', 'count' bits in the volume bitmap + * are cleared. The affected bitmap blocks are marked "dirty", the free + * block count of the MDB is updated and the MDB is marked dirty. + */ +int hfs_clear_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count) +{ + hfs_u16 block_nr; /* index of the current bitmap block */ + hfs_u16 u32_nr; /* index of the current hfs_u32 in block */ + hfs_u16 bit_nr; /* index of the current bit in hfs_u32 */ + hfs_u16 left = count; /* number of bits left to be set */ + hfs_u32 *bitmap; /* the current bitmap block's contents */ + + /* is this a valid HFS MDB? */ + if (!mdb) { + return -3; + } + + /* is there any actual work to be done? */ + if (!count) { + return 0; + } + + /* are all of the bits in range? */ + if ((start + count) > mdb->fs_ablocks) { + return -2; + } + + block_nr = start / HFS_BM_BPB; + u32_nr = (start % HFS_BM_BPB) / 32; + bit_nr = start % 32; + + /* bitmap is always on a 32-bit boundary */ + bitmap = (hfs_u32 *)hfs_buffer_data(mdb->bitmap[block_nr]); + + /* do any partial hfs_u32 at the start */ + if (bit_nr != 0) { + while ((bit_nr < 32) && left) { + if (!hfs_clear_bit(bit_nr, bitmap + u32_nr)) { + hfs_buffer_dirty(mdb->bitmap[block_nr]); + return -1; + } + ++bit_nr; + --left; + } + bit_nr=0; + + /* advance u32_nr and check for end of this block */ + if (++u32_nr > 127) { + u32_nr = 0; + hfs_buffer_dirty(mdb->bitmap[block_nr]); + ++block_nr; + /* bitmap is always on a 32-bit boundary */ + bitmap = (hfs_u32 *) + hfs_buffer_data(mdb->bitmap[block_nr]); + } + } + + /* do full hfs_u32s */ + while (left > 31) { + if (bitmap[u32_nr] != ~((hfs_u32)0)) { + hfs_buffer_dirty(mdb->bitmap[block_nr]); + return -1; + } + bitmap[u32_nr] = ((hfs_u32)0); + left -= 32; + + /* advance u32_nr and check for end of this block */ + if (++u32_nr > 127) { + u32_nr = 0; + hfs_buffer_dirty(mdb->bitmap[block_nr]); + ++block_nr; + /* bitmap is always on a 32-bit boundary */ + bitmap = (hfs_u32 *) + hfs_buffer_data(mdb->bitmap[block_nr]); + } + } + + + /* do any partial hfs_u32 at end */ + while (left) { + if (!hfs_clear_bit(bit_nr, bitmap + u32_nr)) { + hfs_buffer_dirty(mdb->bitmap[block_nr]); + return -1; + } + ++bit_nr; + --left; + } + + hfs_buffer_dirty(mdb->bitmap[block_nr]); + mdb->free_ablocks += count; + + /* successful completion */ + hfs_mdb_dirty(mdb->sys_mdb); + return 0; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/bitops.c linux/fs/hfs/bitops.c --- v2.1.77/linux/fs/hfs/bitops.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/bitops.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,124 @@ +/* + * linux/fs/hfs/bitops.c + * + * Copyright (C) 1996 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains functions to handle bitmaps in "left-to-right" + * bit-order such that the MSB of a 32-bit big-endian word is bit 0. + * (This corresponds to bit 7 of a 32-bit little-endian word.) + * + * I have tested and confirmed that the results are identical on the + * Intel x86, PowerPC and DEC Alpha processors. + * + * "XXX" in a comment is a note to myself to consider changing something. + */ + +#include "hfs.h" + +/*================ Global functions ================*/ + +/* + * hfs_find_zero_bit() + * + * Description: + * Given a block of memory, its length in bits, and a starting bit number, + * determine the number of the first zero bits (in left-to-right ordering) + * in that range. + * + * Returns >= 'size' if no zero bits are found in the range. + * + * Accesses memory in 32-bit aligned chunks of 32-bits and thus + * may read beyond the 'size'th bit. + */ +hfs_u32 hfs_find_zero_bit(const hfs_u32 *start, hfs_u32 size, hfs_u32 offset) +{ + const hfs_u32 *end = start + ((size + 31) >> 5); + const hfs_u32 *curr = start + (offset >> 5); + int bit = offset % 32; + + if (offset < size) { + /* scan the first partial hfs_u32 for zero bits */ + if (bit != 0) { + do { + if (!hfs_test_bit(bit, curr)) { + goto done; + } + ++bit; + } while (bit < 32); + bit = 0; + ++curr; + } + + /* scan complete hfs_u32s for the first zero bit */ + while (curr < end) { + if (*curr == ~((hfs_u32)0)) { + ++curr; + } else { + while (hfs_test_bit(bit, curr)) { + ++bit; + } + break; + } + } + +done: + bit |= (curr - start) << 5; + return bit; + } else { + return size; + } +} + +/* + * hfs_count_zero_bits() + * + * Description: + * Given a block of memory, its length in bits, and a starting bit number, + * determine the number of consecutive zero bits (in left-to-right ordering) + * in that range. + * + * Accesses memory in 32-bit aligned chunks of 32-bits and thus + * may read beyond the 'size'th bit. + */ +hfs_u32 hfs_count_zero_bits(const hfs_u32 *start, hfs_u32 size, hfs_u32 offset) +{ + const hfs_u32 *end = start + ((size + 31) >> 5); + const hfs_u32 *curr = start + (offset >> 5); + int bit = offset % 32; + + if (offset < size) { + /* scan the first partial hfs_u32 for one bits */ + if (bit != 0) { + do { + if (hfs_test_bit(bit, curr)) { + goto done; + } + ++bit; + } while (bit < 32); + bit = 0; + ++curr; + } + + /* scan complete hfs_u32s for the first one bit */ + while (curr < end) { + if (*curr == ((hfs_u32)0)) { + ++curr; + } else { + while (!hfs_test_bit(bit, curr)) { + ++bit; + } + break; + } + } + +done: + bit |= (curr - start) << 5; + if (bit > size) { + bit = size; + } + return bit - offset; + } else { + return 0; + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/bnode.c linux/fs/hfs/bnode.c --- v2.1.77/linux/fs/hfs/bnode.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/bnode.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,540 @@ +/* + * linux/fs/hfs/bnode.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the code to access nodes in the B-tree structure. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + * + * The code in this file initializes some structures which contain + * pointers by calling memset(&foo, 0, sizeof(foo)). + * This produces the desired behavior only due to the non-ANSI + * assumption that the machine representation of NULL is all zeros. + */ + +#include "hfs_btree.h" + +/*================ File-local variables ================*/ + +/* debugging statistics */ +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) +int bnode_count = 0; +#endif + +/*================ Global functions ================*/ + +/* + * hfs_bnode_delete() + * + * Description: + * This function is called to remove a bnode from the cache and + * release its resources. + * Input Variable(s): + * struct hfs_bnode *bn: Pointer to the (struct hfs_bnode) to be + * removed from the cache. + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'bn' points to a "valid" (struct hfs_bnode). + * Postconditions: + * The node 'bn' is removed from the cache, its memory freed and its + * buffer (if any) released. + */ +void hfs_bnode_delete(struct hfs_bnode *bn) +{ +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + --bnode_count; +#endif + /* join neighbors */ + if (bn->next) { + bn->next->prev = bn->prev; + } + if (bn->prev) { + bn->prev->next = bn->next; + } + /* fix cache slot if necessary */ + if (bhash(bn->tree, bn->node) == bn) { + bhash(bn->tree, bn->node) = bn->next; + } + /* release resources */ + hfs_buffer_put(bn->buf); /* safe: checks for NULL argument */ + HFS_DELETE(bn); +} + + +/* + * hfs_bnode_read() + * + * Description: + * This function creates a (struct hfs_bnode) and, if appropriate, + * inserts it in the cache. + * Input Variable(s): + * struct hfs_bnode *bnode: pointer to the new bnode. + * struct hfs_btree *tree: pointer to the (struct hfs_btree) + * containing the desired node + * hfs_u32 node: the number of the desired node. + * int sticky: the value to assign to the 'sticky' field. + * Output Variable(s): + * NONE + * Returns: + * (struct hfs_bnode *) pointing to the newly created bnode or NULL. + * Preconditions: + * 'bnode' points to a "valid" (struct hfs_bnode). + * 'tree' points to a "valid" (struct hfs_btree). + * 'node' is an existing node number in the B-tree. + * Postconditions: + * The following are true of 'bnode' upon return: + * The 'magic' field is set to indicate a valid (struct hfs_bnode). + * The 'sticky', 'tree' and 'node' fields are initialized to the + * values of the of the corresponding arguments. + * If the 'sticky' argument is zero then the fields 'prev' and + * 'next' are initialized by inserting the (struct hfs_bnode) in the + * linked list of the appropriate cache slot; otherwise they are + * initialized to NULL. + * The data is read from disk (or buffer cache) and the 'buf' field + * points to the buffer for that data. + * If no other processes tried to access this node while this + * process was waiting on disk I/O (if necessary) then the + * remaining fields are zero ('count', 'resrv', 'lock') or NULL + * ('wqueue', 'rqueue') corresponding to no accesses. + * If there were access attempts during I/O then they were blocked + * until the I/O was complete, and the fields 'count', 'resrv', + * 'lock', 'wqueue' and 'rqueue' reflect the results of unblocking + * those processes when the I/O was completed. + */ +void hfs_bnode_read(struct hfs_bnode *bnode, struct hfs_btree *tree, + hfs_u32 node, int sticky) +{ + struct NodeDescriptor *nd; + int block, lcv; + hfs_u16 curr, prev, limit; + + /* Initialize the structure */ + memset(bnode, 0, sizeof(*bnode)); + bnode->magic = HFS_BNODE_MAGIC; + bnode->tree = tree; + bnode->node = node; + bnode->sticky = sticky; + + if (sticky == HFS_NOT_STICKY) { + /* Insert it in the cache if appropriate */ + if ((bnode->next = bhash(tree, node))) { + bnode->next->prev = bnode; + } + bhash(tree, node) = bnode; + } + + /* Make the bnode look like it is being + modified so other processes will wait for + the I/O to complete */ + bnode->count = bnode->resrv = bnode->lock = 1; + + /* Read in the node, possibly causing a schedule() + call. If the I/O fails then emit a warning. Each + process that was waiting on the bnode (including + the current one) will notice the failure and + hfs_bnode_relse() the node. The last hfs_bnode_relse() + will call hfs_bnode_delete() and discard the bnode. */ + + block = hfs_extent_map(&tree->entry.u.file.data_fork, node, 0); + if (!block) { + hfs_warn("hfs_bnode_read: bad node number 0x%08x\n", node); + } else if (hfs_buffer_ok(bnode->buf = + hfs_buffer_get(tree->sys_mdb, block, 1))) { + /* read in the NodeDescriptor */ + nd = (struct NodeDescriptor *)hfs_buffer_data(bnode->buf); + bnode->ndFLink = hfs_get_hl(nd->ndFLink); + bnode->ndBLink = hfs_get_hl(nd->ndBLink); + bnode->ndType = nd->ndType; + bnode->ndNHeight = nd->ndNHeight; + bnode->ndNRecs = hfs_get_hs(nd->ndNRecs); + + /* verify the integrity of the node */ + prev = sizeof(struct NodeDescriptor); + limit = HFS_SECTOR_SIZE - sizeof(hfs_u16)*(bnode->ndNRecs + 1); + for (lcv=1; lcv <= (bnode->ndNRecs + 1); ++lcv) { + curr = hfs_get_hs(RECTBL(bnode, lcv)); + if ((curr < prev) || (curr > limit)) { + hfs_warn("hfs_bnode_read: corrupt node " + "number 0x%08x\n", node); + hfs_buffer_put(bnode->buf); + bnode->buf = NULL; + break; + } + prev = curr; + } + } + + /* Undo our fakery with the lock state and + hfs_wake_up() anyone who we managed to trick */ + --bnode->count; + bnode->resrv = bnode->lock = 0; + hfs_wake_up(&bnode->rqueue); +} + +/* + * hfs_bnode_lock() + * + * Description: + * This function does the locking of a bnode. + * Input Variable(s): + * struct hfs_bnode *bn: pointer to the (struct hfs_bnode) to lock + * int lock_type: the type of lock desired + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'bn' points to a "valid" (struct hfs_bnode). + * 'lock_type' is a valid hfs_lock_t + * Postconditions: + * The 'count' field of 'bn' is incremented by one. If 'lock_type' + * is HFS_LOCK_RESRV the 'resrv' field is also incremented. + */ +void hfs_bnode_lock(struct hfs_bnode_ref *bnr, int lock_type) +{ + struct hfs_bnode *bn = bnr->bn; + + if ((lock_type == bnr->lock_type) || !bn) { + return; + } + + if (bnr->lock_type == HFS_LOCK_WRITE) { + hfs_bnode_commit(bnr->bn); + } + + switch (lock_type) { + default: + goto bail; + break; + + case HFS_LOCK_READ: + /* We may not obtain read access if any process is + currently modifying or waiting to modify this node. + If we can't obtain access we wait on the rqueue + wait queue to be woken up by the modifying process + when it relinquishes its lock. */ + switch (bnr->lock_type) { + default: + goto bail; + break; + + case HFS_LOCK_NONE: + while (bn->lock || bn->wqueue) { + hfs_sleep_on(&bn->rqueue); + } + ++bn->count; + break; + } + break; + + case HFS_LOCK_RESRV: + /* We may not obtain a reservation (read access with + an option to write later), if any process currently + holds a reservation on this node. That includes + any process which is currently modifying this node. + If we can't obtain access, then we wait on the + rqueue wait queue to e woken up by the + reservation-holder when it calls hfs_bnode_relse. */ + switch (bnr->lock_type) { + default: + goto bail; + break; + + case HFS_LOCK_NONE: + while (bn->resrv) { + hfs_sleep_on(&bn->rqueue); + } + bn->resrv = 1; + ++bn->count; + break; + + case HFS_LOCK_WRITE: + bn->lock = 0; + hfs_wake_up(&bn->rqueue); + break; + } + break; + + case HFS_LOCK_WRITE: + switch (bnr->lock_type) { + default: + goto bail; + break; + + case HFS_LOCK_NONE: + while (bn->resrv) { + hfs_sleep_on(&bn->rqueue); + } + bn->resrv = 1; + ++bn->count; + case HFS_LOCK_RESRV: + while (bn->count > 1) { + hfs_sleep_on(&bn->wqueue); + } + bn->lock = 1; + break; + } + break; + + case HFS_LOCK_NONE: + switch (bnr->lock_type) { + default: + goto bail; + break; + + case HFS_LOCK_READ: + /* This process was reading this node. If + there is now exactly one other process using + the node then hfs_wake_up() a (potentially + nonexistent) waiting process. Note that I + refer to "a" process since the reservation + system ensures that only one process can + get itself on the wait queue. */ + if (bn->count == 2) { + hfs_wake_up(&bn->wqueue); + } + break; + + case HFS_LOCK_WRITE: + /* This process was modifying this node. + Unlock the node and fall-through to the + HFS_LOCK_RESRV case, since a 'reservation' + is a prerequisite for HFS_LOCK_WRITE. */ + bn->lock = 0; + case HFS_LOCK_RESRV: + /* This process had placed a 'reservation' on + this node, indicating an intention to + possibly modify the node. We can get to + this spot directly (if the 'reservation' + not converted to a HFS_LOCK_WRITE), or by + falling through from the above case if the + reservation was converted. + Since HFS_LOCK_RESRV and HFS_LOCK_WRITE + both block processes that want access + (HFS_LOCK_RESRV blocks other processes that + want reservations but allow HFS_LOCK_READ + accesses, while HFS_LOCK_WRITE must have + exclusive access and thus blocks both + types) we hfs_wake_up() any processes that + might be waiting for access. If multiple + processes are waiting for a reservation + then the magic of process scheduling will + settle the dispute. */ + bn->resrv = 0; + hfs_wake_up(&bn->rqueue); + break; + } + --bn->count; + break; + } + bnr->lock_type = lock_type; + return; + +bail: + hfs_warn("hfs_bnode_lock: invalid lock change: %d->%d.\n", + bnr->lock_type, lock_type); + return; +} + +/* + * hfs_bnode_relse() + * + * Description: + * This function is called when a process is done using a bnode. If + * the proper conditions are met then we call hfs_bnode_delete() to remove + * it from the cache. If it is not deleted then we update its state + * to reflect one less process using it. + * Input Variable(s): + * struct hfs_bnode *bn: pointer to the (struct hfs_bnode) to release. + * int lock_type: The type of lock held by the process releasing this node. + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'bn' is NULL or points to a "valid" (struct hfs_bnode). + * Postconditions: + * If 'bn' meets the appropriate conditions (see below) then it is + * kept in the cache and all fields are set to consistent values + * which reflect one less process using the node than upon entry. + * If 'bn' does not meet the conditions then it is deleted (see + * hfs_bnode_delete() for postconditions). + * In either case, if 'lock_type' is HFS_LOCK_WRITE + * then the corresponding buffer is dirtied. + */ +void hfs_bnode_relse(struct hfs_bnode_ref *bnr) +{ + struct hfs_bnode *bn; + + if (!bnr || !(bn = bnr->bn)) { + return; + } + + /* We update the lock state of the node if it is still in use + or if it is "sticky" (such as the B-tree head and root). + Otherwise we just delete it. */ + if ((bn->count > 1) || (bn->rqueue) || (bn->sticky != HFS_NOT_STICKY)) { + hfs_bnode_lock(bnr, HFS_LOCK_NONE); + } else { + /* dirty buffer if we (might) have modified it */ + if (bnr->lock_type == HFS_LOCK_WRITE) { + hfs_bnode_commit(bn); + } + hfs_bnode_delete(bn); + bnr->lock_type = HFS_LOCK_NONE; + } + bnr->bn = NULL; +} + +/* + * hfs_bnode_find() + * + * Description: + * This function is called to obtain a bnode. The cache is + * searched for the node. If it not found there it is added to + * the cache by hfs_bnode_read(). There are two special cases node=0 + * (the header node) and node='tree'->bthRoot (the root node), in + * which the nodes are obtained from fields of 'tree' without + * consulting or modifying the cache. + * Input Variable(s): + * struct hfs_tree *tree: pointer to the (struct hfs_btree) from + * which to get a node. + * int node: the node number to get from 'tree'. + * int lock_type: The kind of access (HFS_LOCK_READ, or + * HFS_LOCK_RESRV) to obtain to the node + * Output Variable(s): + * NONE + * Returns: + * (struct hfs_bnode_ref) Reference to the requested node. + * Preconditions: + * 'tree' points to a "valid" (struct hfs_btree). + * Postconditions: + * If 'node' refers to a valid node in 'tree' and 'lock_type' has + * one of the values listed above and no I/O errors occur then the + * value returned refers to a valid (struct hfs_bnode) corresponding + * to the requested node with the requested access type. The node + * is also added to the cache if not previously present and not the + * root or header. + * If the conditions given above are not met, the bnode in the + * returned reference is NULL. + */ +struct hfs_bnode_ref hfs_bnode_find(struct hfs_btree *tree, + hfs_u32 node, int lock_type) +{ + struct hfs_bnode *bn; + struct hfs_bnode *empty = NULL; + struct hfs_bnode_ref bnr; + + bnr.lock_type = HFS_LOCK_NONE; + bnr.bn = NULL; + +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + hfs_warn("hfs_bnode_find: %c %d:%d\n", + lock_type==HFS_LOCK_READ?'R': + (lock_type==HFS_LOCK_RESRV?'V':'W'), + (int)ntohl(tree->entry.cnid), node); +#endif + + /* check special cases */ + if (!node) { + bn = &tree->head; + goto return_it; + } else if (node == tree->bthRoot) { + bn = tree->root; + goto return_it; + } + +restart: + /* look for the node in the cache. */ + bn = bhash(tree, node); + while (bn && (bn->magic == HFS_BNODE_MAGIC)) { + if (bn->node == node) { + goto found_it; + } + bn = bn->next; + } + + if (!empty) { +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + ++bnode_count; +#endif + if (HFS_NEW(empty)) { + goto restart; + } + return bnr; + } + bn = empty; + hfs_bnode_read(bn, tree, node, HFS_NOT_STICKY); + goto return_it; + +found_it: + /* check validity */ + if (bn->magic != HFS_BNODE_MAGIC) { + /* If we find a corrupt bnode then we return + NULL. However, we don't try to remove it + from the cache or release its resources + since we have no idea what kind of trouble + we could get into that way. */ + hfs_warn("hfs_bnode_find: bnode cache is corrupt.\n"); + return bnr; + } + if (empty) { +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + --bnode_count; +#endif + HFS_DELETE(empty); + } + +return_it: + /* Wait our turn */ + bnr.bn = bn; + hfs_bnode_lock(&bnr, lock_type); + + /* Check for failure to read the node from disk */ + if (!hfs_buffer_ok(bn->buf)) { + hfs_bnode_relse(&bnr); + } + +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + if (!bnr.bn) { + hfs_warn("hfs_bnode_find: failed\n"); + } else { + hfs_warn("hfs_bnode_find: use %d(%d) lvl %d [%d]\n", bn->count, + bn->buf->b_count, bn->ndNHeight, bnode_count); + } +#endif + + return bnr; +} + +/* + * hfs_bnode_commit() + * + * Called to write a possibly dirty bnode back to disk. + */ +void hfs_bnode_commit(struct hfs_bnode *bn) +{ + if (hfs_buffer_ok(bn->buf)) { + struct NodeDescriptor *nd; + nd = (struct NodeDescriptor *)hfs_buffer_data(bn->buf); + + hfs_put_hl(bn->ndFLink, nd->ndFLink); + hfs_put_hl(bn->ndBLink, nd->ndBLink); + nd->ndType = bn->ndType; + nd->ndNHeight = bn->ndNHeight; + hfs_put_hs(bn->ndNRecs, nd->ndNRecs); + hfs_buffer_dirty(bn->buf); + + /* increment write count */ + hfs_mdb_dirty(bn->tree->sys_mdb); + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/brec.c linux/fs/hfs/brec.c --- v2.1.77/linux/fs/hfs/brec.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/brec.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,239 @@ +/* + * linux/fs/hfs/brec.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the code to access records in a btree. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs_btree.h" + +/*================ File-local functions ================*/ + +/* + * first() + * + * returns HFS_BPATH_FIRST if elem->record == 1, 0 otherwise + */ +static inline int first(const struct hfs_belem *elem) +{ + return (elem->record == 1) ? HFS_BPATH_FIRST : 0; +} + +/* + * overflow() + * + * return HFS_BPATH_OVERFLOW if the node has no room for an + * additional pointer record, 0 otherwise. + */ +static inline int overflow(const struct hfs_btree *tree, + const struct hfs_bnode *bnode) +{ + /* there is some algebra involved in getting this form */ + return ((HFS_SECTOR_SIZE - sizeof(hfs_u32)) < + (bnode_end(bnode) + (2+bnode->ndNRecs)*sizeof(hfs_u16) + + ROUND(tree->bthKeyLen+1))) ? HFS_BPATH_OVERFLOW : 0; +} + +/* + * underflow() + * + * return HFS_BPATH_UNDERFLOW if the node will be less that 1/2 full + * upon removal of a pointer record, 0 otherwise. + */ +static inline int underflow(const struct hfs_btree *tree, + const struct hfs_bnode *bnode) +{ + return ((bnode->ndNRecs * sizeof(hfs_u16) + + bnode_offset(bnode, bnode->ndNRecs)) < + (HFS_SECTOR_SIZE - sizeof(struct NodeDescriptor))/2) ? + HFS_BPATH_UNDERFLOW : 0; +} + +/*================ Global functions ================*/ + +/* + * hfs_brec_next() + * + * Description: + * Obtain access to a child of an internal node in a B-tree. + * Input Variable(s): + * struct hfs_brec *brec: pointer to the (struct hfs_brec) to + * add an element to. + * Output Variable(s): + * NONE + * Returns: + * struct hfs_belem *: pointer to the new path element or NULL + * Preconditions: + * 'brec' points to a "valid" (struct hfs_brec), the last element of + * which corresponds to a record in a bnode of type ndIndxNode and the + * 'record' field indicates the index record for the desired child. + * Postconditions: + * If the call to hfs_bnode_find() fails then 'brec' is released + * and a NULL is returned. + * Otherwise: + * Any ancestors in 'brec' that are not needed (as determined by the + * 'keep_flags' field of 'brec) are released from 'brec'. + * A new element is added to 'brec' corresponding to the desired + * child. + * The child is obtained with the same 'lock_type' field as its + * parent. + * The 'record' field is initialized to the last record. + * A pointer to the new path element is returned. + */ +struct hfs_belem *hfs_brec_next(struct hfs_brec *brec) +{ + struct hfs_belem *elem = brec->bottom; + hfs_u32 node; + int lock_type; + + /* release unneeded ancestors */ + elem->flags = first(elem) | + overflow(brec->tree, elem->bnr.bn) | + underflow(brec->tree, elem->bnr.bn); + if (!(brec->keep_flags & elem->flags)) { + hfs_brec_relse(brec, brec->bottom-1); + } else if ((brec->bottom-2 >= brec->top) && + !(elem->flags & (elem-1)->flags)) { + hfs_brec_relse(brec, brec->bottom-2); + } + + node = hfs_get_hl(belem_record(elem)); + lock_type = elem->bnr.lock_type; + + if (!node || hfs_bnode_in_brec(node, brec)) { + hfs_warn("hfs_bfind: corrupt btree\n"); + hfs_brec_relse(brec, NULL); + return NULL; + } + + ++elem; + ++brec->bottom; + + elem->bnr = hfs_bnode_find(brec->tree, node, lock_type); + if (!elem->bnr.bn) { + hfs_brec_relse(brec, NULL); + return NULL; + } + elem->record = elem->bnr.bn->ndNRecs; + + return elem; +} + +/* + * hfs_brec_lock() + * + * Description: + * This function obtains HFS_LOCK_WRITE access to the bnode + * containing this hfs_brec. All descendents in the path from this + * record to the leaf are given HFS_LOCK_WRITE access and all + * ancestors in the path from the root to here are released. + * Input Variable(s): + * struct hfs_brec *brec: pointer to the brec to obtain + * HFS_LOCK_WRITE access to some of the nodes of. + * struct hfs_belem *elem: the first node to lock or NULL for all + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'brec' points to a "valid" (struct hfs_brec) + * Postconditions: + * All nodes between the indicated node and the beginning of the path + * are released. hfs_bnode_lock() is called in turn on each node + * from the indicated node to the leaf node of the path, with a + * lock_type argument of HFS_LOCK_WRITE. If one of those calls + * results in deadlock, then this function will never return. + */ +void hfs_brec_lock(struct hfs_brec *brec, struct hfs_belem *elem) +{ + if (!elem) { + elem = brec->top; + } else if (elem > brec->top) { + hfs_brec_relse(brec, elem-1); + } + + while (elem <= brec->bottom) { + hfs_bnode_lock(&elem->bnr, HFS_LOCK_WRITE); + ++elem; + } +} + +/* + * hfs_brec_init() + * + * Description: + * Obtain access to the root node of a B-tree. + * Note that this first must obtain access to the header node. + * Input Variable(s): + * struct hfs_brec *brec: pointer to the (struct hfs_brec) to + * initialize + * struct hfs_btree *btree: pointer to the (struct hfs_btree) + * int lock_type: the type of access to get to the nodes. + * Output Variable(s): + * NONE + * Returns: + * struct hfs_belem *: pointer to the root path element or NULL + * Preconditions: + * 'brec' points to a (struct hfs_brec). + * 'tree' points to a valid (struct hfs_btree). + * Postconditions: + * If the two calls to brec_bnode_find() succeed then the return value + * points to a (struct hfs_belem) which corresponds to the root node + * of 'brec->tree'. + * Both the root and header nodes are obtained with the type of lock + * given by (flags & HFS_LOCK_MASK). + * The fields 'record' field of the root is set to its last record. + * If the header node is not needed to complete the appropriate + * operation (as determined by the 'keep_flags' field of 'brec') then + * it is released before this function returns. + * If either call to brec_bnode_find() fails, NULL is returned and the + * (struct hfs_brec) pointed to by 'brec' is invalid. + */ +struct hfs_belem *hfs_brec_init(struct hfs_brec *brec, struct hfs_btree *tree, + int flags) +{ + struct hfs_belem *head = &brec->elem[0]; + struct hfs_belem *root = &brec->elem[1]; + int lock_type = flags & HFS_LOCK_MASK; + + brec->tree = tree; + + head->bnr = hfs_bnode_find(tree, 0, lock_type); + if (!head->bnr.bn) { + return NULL; + } + + root->bnr = hfs_bnode_find(tree, tree->bthRoot, lock_type); + if (!root->bnr.bn) { + hfs_bnode_relse(&head->bnr); + return NULL; + } + + root->record = root->bnr.bn->ndNRecs; + + brec->top = head; + brec->bottom = root; + + brec->keep_flags = flags & HFS_BPATH_MASK; + + /* HFS_BPATH_FIRST not applicable for root */ + /* and HFS_BPATH_UNDERFLOW is different */ + root->flags = overflow(tree, root->bnr.bn); + if (root->record < 3) { + root->flags |= HFS_BPATH_UNDERFLOW; + } + + if (!(root->flags & brec->keep_flags)) { + hfs_brec_relse(brec, head); + } + + return root; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/btree.c linux/fs/hfs/btree.c --- v2.1.77/linux/fs/hfs/btree.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/btree.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,316 @@ +/* + * linux/fs/hfs/btree.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the code to manipulate the B-tree structure. + * The catalog and extents files are both B-trees. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + * + * The code in this file initializes some structures which contain + * pointers by calling memset(&foo, 0, sizeof(foo)). + * This produces the desired behavior only due to the non-ANSI + * assumption that the machine representation of NULL is all zeros. + */ + +#include "hfs_btree.h" + +/*================ File-local functions ================*/ + +/* + * hfs_bnode_ditch() + * + * Description: + * This function deletes an entire linked list of bnodes, so it + * does not need to keep the linked list consistent as + * hfs_bnode_delete() does. + * Called by hfs_btree_init() for error cleanup and by hfs_btree_free(). + * Input Variable(s): + * struct hfs_bnode *bn: pointer to the first (struct hfs_bnode) in + * the linked list to be deleted. + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'bn' is NULL or points to a "valid" (struct hfs_bnode) with a 'prev' + * field of NULL. + * Postconditions: + * 'bn' and all (struct hfs_bnode)s in the chain of 'next' pointers + * are deleted, freeing the associated memory and hfs_buffer_put()ing + * the associated buffer. + */ +static void hfs_bnode_ditch(struct hfs_bnode *bn) { + struct hfs_bnode *tmp; +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + extern int bnode_count; +#endif + + while (bn != NULL) { + tmp = bn->next; +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + hfs_warn("deleting node %d from tree %d with count %d\n", + bn->node, (int)ntohl(bn->tree->entry.cnid), bn->count); + --bnode_count; +#endif + hfs_buffer_put(bn->buf); /* safe: checks for NULL argument */ + + /* free all but the header */ + if (bn->node) { + HFS_DELETE(bn); + } + bn = tmp; + } +} + +/*================ Global functions ================*/ + +/* + * hfs_btree_free() + * + * Description: + * This function frees a (struct hfs_btree) obtained from hfs_btree_init(). + * Called by hfs_put_super(). + * Input Variable(s): + * struct hfs_btree *bt: pointer to the (struct hfs_btree) to free + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'bt' is NULL or points to a "valid" (struct hfs_btree) + * Postconditions: + * If 'bt' points to a "valid" (struct hfs_btree) then all (struct + * hfs_bnode)s associated with 'bt' are freed by calling + * hfs_bnode_ditch() and the memory associated with the (struct + * hfs_btree) is freed. + * If 'bt' is NULL or not "valid" an error is printed and nothing + * is changed. + */ +void hfs_btree_free(struct hfs_btree *bt) +{ + int lcv; + + if (bt && (bt->magic == HFS_BTREE_MAGIC)) { + hfs_extent_free(&bt->entry.u.file.data_fork); + + for (lcv=0; lcvcache[lcv]); + } + +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + hfs_warn("deleting header and bitmap nodes\n"); +#endif + hfs_bnode_ditch(&bt->head); + +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + hfs_warn("deleting root node\n"); +#endif + hfs_bnode_ditch(bt->root); + + HFS_DELETE(bt); + } else if (bt) { + hfs_warn("hfs_btree_free: corrupted hfs_btree.\n"); + } +} + +/* + * hfs_btree_init() + * + * Description: + * Given some vital information from the MDB (HFS superblock), + * initializes the fields of a (struct hfs_btree). + * Input Variable(s): + * struct hfs_mdb *mdb: pointer to the MDB + * ino_t cnid: the CNID (HFS_CAT_CNID or HFS_EXT_CNID) of the B-tree + * hfs_u32 tsize: the size, in bytes, of the B-tree + * hfs_u32 csize: the size, in bytes, of the clump size for the B-tree + * Output Variable(s): + * NONE + * Returns: + * (struct hfs_btree *): pointer to the initialized hfs_btree on success, + * or NULL on failure + * Preconditions: + * 'mdb' points to a "valid" (struct hfs_mdb) + * Postconditions: + * Assuming the inputs are what they claim to be, no errors occur + * reading from disk, and no inconsistencies are noticed in the data + * read from disk, the return value is a pointer to a "valid" + * (struct hfs_btree). If there are errors reading from disk or + * inconsistencies are noticed in the data read from disk, then and + * all resources that were allocated are released and NULL is + * returned. If the inputs are not what they claim to be or if they + * are unnoticed inconsistencies in the data read from disk then the + * returned hfs_btree is probably going to lead to errors when it is + * used in a non-trivial way. + */ +struct hfs_btree * hfs_btree_init(struct hfs_mdb *mdb, ino_t cnid, + hfs_byte_t ext[12], + hfs_u32 tsize, hfs_u32 csize) +{ + struct hfs_btree * bt; + struct BTHdrRec * th; + struct hfs_bnode * tmp; + unsigned int next; +#if defined(DEBUG_HEADER) || defined(DEBUG_ALL) + unsigned char *p, *q; +#endif + + if (!mdb || !ext || !HFS_NEW(bt)) { + goto bail3; + } + + bt->magic = HFS_BTREE_MAGIC; + bt->sys_mdb = mdb->sys_mdb; + bt->reserved = 0; + bt->lock = 0; + bt->wait = NULL; + bt->dirt = 0; + memset(bt->cache, 0, sizeof(bt->cache)); + bt->entry.mdb = mdb; + bt->entry.cnid = cnid; + bt->entry.type = HFS_CDR_FIL; + bt->entry.u.file.magic = HFS_FILE_MAGIC; + bt->entry.u.file.clumpablks = (csize / mdb->alloc_blksz) + >> HFS_SECTOR_SIZE_BITS; + bt->entry.u.file.data_fork.entry = &bt->entry; + bt->entry.u.file.data_fork.lsize = tsize; + bt->entry.u.file.data_fork.psize = tsize >> HFS_SECTOR_SIZE_BITS; + bt->entry.u.file.data_fork.fork = HFS_FK_DATA; + hfs_extent_in(&bt->entry.u.file.data_fork, ext); + + hfs_bnode_read(&bt->head, bt, 0, HFS_STICKY); + if (!hfs_buffer_ok(bt->head.buf)) { + goto bail2; + } + th = (struct BTHdrRec *)((char *)hfs_buffer_data(bt->head.buf) + + sizeof(struct NodeDescriptor)); + + /* read in the bitmap nodes (if any) */ + tmp = &bt->head; + while ((next = tmp->ndFLink)) { + if (!HFS_NEW(tmp->next)) { + goto bail2; + } + hfs_bnode_read(tmp->next, bt, next, HFS_STICKY); + if (!hfs_buffer_ok(tmp->next->buf)) { + goto bail2; + } + tmp->next->prev = tmp; + tmp = tmp->next; + } + + if (hfs_get_ns(th->bthNodeSize) != htons(HFS_SECTOR_SIZE)) { + hfs_warn("hfs_btree_init: bthNodeSize!=512 not supported\n"); + goto bail2; + } + + if (cnid == htonl(HFS_CAT_CNID)) { + bt->compare = (hfs_cmpfn)hfs_cat_compare; + } else if (cnid == htonl(HFS_EXT_CNID)) { + bt->compare = (hfs_cmpfn)hfs_ext_compare; + } else { + goto bail2; + } + bt->bthDepth = hfs_get_hs(th->bthDepth); + bt->bthRoot = hfs_get_hl(th->bthRoot); + bt->bthNRecs = hfs_get_hl(th->bthNRecs); + bt->bthFNode = hfs_get_hl(th->bthFNode); + bt->bthLNode = hfs_get_hl(th->bthLNode); + bt->bthNNodes = hfs_get_hl(th->bthNNodes); + bt->bthFree = hfs_get_hl(th->bthFree); + bt->bthKeyLen = hfs_get_hs(th->bthKeyLen); + +#if defined(DEBUG_HEADER) || defined(DEBUG_ALL) + hfs_warn("bthDepth %d\n", bt->bthDepth); + hfs_warn("bthRoot %d\n", bt->bthRoot); + hfs_warn("bthNRecs %d\n", bt->bthNRecs); + hfs_warn("bthFNode %d\n", bt->bthFNode); + hfs_warn("bthLNode %d\n", bt->bthLNode); + hfs_warn("bthKeyLen %d\n", bt->bthKeyLen); + hfs_warn("bthNNodes %d\n", bt->bthNNodes); + hfs_warn("bthFree %d\n", bt->bthFree); + p = (unsigned char *)hfs_buffer_data(bt->head.buf); + q = p + HFS_SECTOR_SIZE; + while (p < q) { + hfs_warn("%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++, + *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++); + } +#endif + + /* Read in the root if it exists. + The header always exists, but the root exists only if the + tree is non-empty */ + if (bt->bthDepth && bt->bthRoot) { + if (!HFS_NEW(bt->root)) { + goto bail2; + } + hfs_bnode_read(bt->root, bt, bt->bthRoot, HFS_STICKY); + if (!hfs_buffer_ok(bt->root->buf)) { + goto bail1; + } + } else { + bt->root = NULL; + } + + return bt; + + bail1: + hfs_bnode_ditch(bt->root); + bail2: + hfs_bnode_ditch(&bt->head); + HFS_DELETE(bt); + bail3: + return NULL; +} + +/* + * hfs_btree_commit() + * + * Called to write a possibly dirty btree back to disk. + */ +void hfs_btree_commit(struct hfs_btree *bt, hfs_byte_t ext[12], hfs_lword_t size) +{ + if (bt->dirt) { + struct BTHdrRec *th; + th = (struct BTHdrRec *)((char *)hfs_buffer_data(bt->head.buf) + + sizeof(struct NodeDescriptor)); + + hfs_put_hs(bt->bthDepth, th->bthDepth); + hfs_put_hl(bt->bthRoot, th->bthRoot); + hfs_put_hl(bt->bthNRecs, th->bthNRecs); + hfs_put_hl(bt->bthFNode, th->bthFNode); + hfs_put_hl(bt->bthLNode, th->bthLNode); + hfs_put_hl(bt->bthNNodes, th->bthNNodes); + hfs_put_hl(bt->bthFree, th->bthFree); + hfs_buffer_dirty(bt->head.buf); + + /* + * Commit the bnodes which are not cached. + * The map nodes don't need to be committed here because + * they are committed every time they are changed. + */ + hfs_bnode_commit(&bt->head); + if (bt->root) { + hfs_bnode_commit(bt->root); + } + + + hfs_put_hl(bt->bthNNodes << HFS_SECTOR_SIZE_BITS, size); + hfs_extent_out(&bt->entry.u.file.data_fork, ext); + /* hfs_buffer_dirty(mdb->buf); (Done by caller) */ + + bt->dirt = 0; + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/catalog.c linux/fs/hfs/catalog.c --- v2.1.77/linux/fs/hfs/catalog.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/catalog.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,1604 @@ +/* + * linux/fs/hfs/catalog.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the functions related to the catalog B-tree. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * Cache code shamelessly stolen from + * linux/fs/inode.c Copyright (C) 1991, 1992 Linus Torvalds + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + * + * The code in this file initializes some structures by calling + * memset(&foo, 0, sizeof(foo)). This produces the desired behavior + * only due to the non-ANSI assumption that the machine representation + */ + +#include "hfs.h" + +/*================ Variable-like macros ================*/ + +#define NUM_FREE_ENTRIES 8 + +/* Number of hash table slots */ +#define CCACHE_NR 128 + +/* Max number of entries in memory */ +#define CCACHE_MAX 1024 + +/* Number of entries to fit in a single page on an i386 */ +#define CCACHE_INC ((4080-sizeof(void *))/sizeof(struct hfs_cat_entry)) + +/*================ File-local data types ================*/ + +/* The catalog record for a file */ +typedef struct { + hfs_byte_t Flags; /* Flags such as read-only */ + hfs_byte_t Typ; /* file version number = 0 */ + hfs_finfo_t UsrWds; /* data used by the Finder */ + hfs_lword_t FlNum; /* The CNID */ + hfs_word_t StBlk; /* obsolete */ + hfs_lword_t LgLen; /* The logical EOF of the data fork*/ + hfs_lword_t PyLen; /* The physical EOF of the data fork */ + hfs_word_t RStBlk; /* obsolete */ + hfs_lword_t RLgLen; /* The logical EOF of the rsrc fork */ + hfs_lword_t RPyLen; /* The physical EOF of the rsrc fork */ + hfs_lword_t CrDat; /* The creation date */ + hfs_lword_t MdDat; /* The modified date */ + hfs_lword_t BkDat; /* The last backup date */ + hfs_fxinfo_t FndrInfo; /* more data for the Finder */ + hfs_word_t ClpSize; /* number of bytes to allocate + when extending files */ + hfs_byte_t ExtRec[12]; /* first extent record + for the data fork */ + hfs_byte_t RExtRec[12]; /* first extent record + for the resource fork */ + hfs_lword_t Resrv; /* reserved by Apple */ +} FIL_REC; + +/* the catalog record for a directory */ +typedef struct { + hfs_word_t Flags; /* flags */ + hfs_word_t Val; /* Valence: number of files and + dirs in the directory */ + hfs_lword_t DirID; /* The CNID */ + hfs_lword_t CrDat; /* The creation date */ + hfs_lword_t MdDat; /* The modification date */ + hfs_lword_t BkDat; /* The last backup date */ + hfs_dinfo_t UsrInfo; /* data used by the Finder */ + hfs_dxinfo_t FndrInfo; /* more data used by Finder */ + hfs_byte_t Resrv[16]; /* reserved by Apple */ +} DIR_REC; + +/* the catalog record for a thread */ +typedef struct { + hfs_byte_t Reserv[8]; /* reserved by Apple */ + hfs_lword_t ParID; /* CNID of parent directory */ + struct hfs_name CName; /* The name of this entry */ +} THD_REC; + +/* A catalog tree record */ +struct hfs_cat_rec { + hfs_byte_t cdrType; /* The type of entry */ + hfs_byte_t cdrResrv2; /* padding */ + union { + FIL_REC fil; + DIR_REC dir; + THD_REC thd; + } u; +}; + +typedef struct hfs_cat_entry *hfs_cat_entry_ptr; + +struct allocation_unit { + struct allocation_unit *next; + struct hfs_cat_entry entries[CCACHE_INC]; +}; + +/*================ File-local variables ================*/ + +static hfs_cat_entry_ptr hash_table[CCACHE_NR] = {NULL, }; + +static struct hfs_cat_entry *first_entry = NULL; +static hfs_wait_queue entry_wait; +static int nr_entries = 0, nr_free_entries = 0; + +static struct allocation_unit *allocation = NULL; + +/*================ File-local functions ================*/ + +/* + * brec_to_id + * + * Get the CNID from a brec + */ +static inline hfs_u32 brec_to_id(struct hfs_brec *brec) +{ + struct hfs_cat_rec *rec = brec->data; + + return hfs_get_nl((rec->cdrType==HFS_CDR_FIL) ? + rec->u.fil.FlNum : rec->u.dir.DirID); +} + +/* + * hashfn() + * + * hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer. + */ +static inline unsigned int hashfn(const struct hfs_mdb *mdb, + const struct hfs_cat_key *key) +{ +#define LSB(X) (((unsigned char *)(&X))[3]) + return ((unsigned int)LSB(mdb->create_date) ^ + (unsigned int)key->ParID[3] ^ + hfs_strhash(&key->CName)) % CCACHE_NR; +#undef LSB +} + +/* + * hash() + * + * hash an (struct mdb *) and a (struct hfs_cat_key *) + * to a pointer to a slot in the hash table. + */ +static inline struct hfs_cat_entry **hash(struct hfs_mdb *mdb, + const struct hfs_cat_key *key) +{ + return hash_table + hashfn(mdb, key); +} + +/* + * insert_free() + * + * Add an entry to the front of the free list. + */ +static inline void insert_free(struct hfs_cat_entry *entry) +{ + struct hfs_cat_entry * prev, * next = first_entry; + + first_entry = entry; + prev = next->prev; + entry->next = next; + entry->prev = prev; + prev->next = entry; + next->prev = entry; +} + +/* + * remove_free() + * + * Remove an entry from the free list. + */ +static inline void remove_free(struct hfs_cat_entry *entry) +{ + if (first_entry == entry) { + first_entry = first_entry->next; + } + if (entry->next) { + entry->next->prev = entry->prev; + } + if (entry->prev) { + entry->prev->next = entry->next; + } + entry->next = entry->prev = NULL; +} + +/* + * insert_hash() + * + * Add an entry to the front of the appropriate hash list + */ +static void insert_hash(struct hfs_cat_entry *entry) +{ + struct hfs_cat_entry **h; + h = hash(entry->mdb, &entry->key); + + entry->hash_next = *h; + entry->hash_prev = NULL; + if (entry->hash_next) { + entry->hash_next->hash_prev = entry; + } + *h = entry; +} + +/* + * remove_hash + * + * Remove an entry from its hash list (if any). + */ +static void remove_hash(struct hfs_cat_entry *entry) +{ + struct hfs_cat_entry **h; + + if (entry->mdb) { + h = hash(entry->mdb, &entry->key); + + if (*h == entry) { + *h = entry->hash_next; + } + if (entry->hash_next) { + entry->hash_next->hash_prev = entry->hash_prev; + } + if (entry->hash_prev) { + entry->hash_prev->hash_next = entry->hash_next; + } + entry->hash_prev = entry->hash_next = NULL; + } +} + +/* + * put_last_free() + * + * Move an entry to the end of the free list. + */ +static inline void put_last_free(struct hfs_cat_entry *entry) +{ + remove_free(entry); + entry->prev = first_entry->prev; + entry->prev->next = entry; + entry->next = first_entry; + entry->next->prev = entry; +} + +/* + * grow_entries() + * + * Try to allocate more entries, adding them to the free list. + */ +static int grow_entries(void) +{ + struct allocation_unit *tmp; + struct hfs_cat_entry * entry; + int i; + + if (!HFS_NEW(tmp)) { + return -ENOMEM; + } + + memset(tmp, 0, sizeof(*tmp)); + + tmp->next = allocation; + allocation = tmp; + entry = tmp->entries; + + i = CCACHE_INC; + + nr_entries += i; + nr_free_entries += i; + + if (!first_entry) { + entry->next = entry->prev = first_entry = entry++; + --i; + } + + for ( i = CCACHE_INC - 1; i ; --i ) { + insert_free(entry++); + } + return 0; +} + +/* + * wait_on_entry() + * + * Sleep until a locked entry is unlocked. + */ +static inline void wait_on_entry(struct hfs_cat_entry * entry) +{ + while (entry->lock) { + hfs_sleep_on(&entry->wait); + } +} + +/* + * lock_entry() + * + * Obtain an exclusive lock on an entry. + */ +static void lock_entry(struct hfs_cat_entry * entry) +{ + wait_on_entry(entry); + entry->lock = 1; +} + +/* + * lock_entry() + * + * Relinquish an exclusive lock on an entry. + */ +static void unlock_entry(struct hfs_cat_entry * entry) +{ + entry->lock = 0; + hfs_wake_up(&entry->wait); +} + +/* + * clear_entry() + * + * Zero all the fields of an entry and place it on the free list. + */ +static void clear_entry(struct hfs_cat_entry * entry) +{ + wait_on_entry(entry); + remove_hash(entry); + remove_free(entry); + if (entry->count) { + nr_free_entries++; + } + /* zero all but the wait queue */ + memset(&entry->next, 0, + sizeof(*entry) - offsetof(struct hfs_cat_entry, next)); + insert_free(entry); +} + +/* + * __read_entry() + * + * Convert a (struct hfs_cat_rec) to a (struct hfs_cat_entry). + */ +static void __read_entry(struct hfs_cat_entry *entry, + const struct hfs_cat_rec *cat) +{ + entry->type = cat->cdrType; + + if (cat->cdrType == HFS_CDR_DIR) { + struct hfs_dir *dir = &entry->u.dir; + + entry->cnid = hfs_get_nl(cat->u.dir.DirID); + + dir->magic = HFS_DIR_MAGIC; + dir->flags = hfs_get_ns(cat->u.dir.Flags); + memcpy(&entry->info.dir.dinfo, &cat->u.dir.UsrInfo, 16); + memcpy(&entry->info.dir.dxinfo, &cat->u.dir.FndrInfo, 16); + entry->create_date = hfs_get_nl(cat->u.dir.CrDat); + entry->modify_date = hfs_get_nl(cat->u.dir.MdDat); + entry->backup_date = hfs_get_nl(cat->u.dir.BkDat); + dir->dirs = dir->files = 0; + } else if (cat->cdrType == HFS_CDR_FIL) { + struct hfs_file *fil = &entry->u.file; + + entry->cnid = hfs_get_nl(cat->u.fil.FlNum); + + fil->magic = HFS_FILE_MAGIC; + + fil->data_fork.fork = HFS_FK_DATA; + fil->data_fork.entry = entry; + fil->data_fork.lsize = hfs_get_hl(cat->u.fil.LgLen); + fil->data_fork.psize = hfs_get_hl(cat->u.fil.PyLen) >> + HFS_SECTOR_SIZE_BITS; + hfs_extent_in(&fil->data_fork, cat->u.fil.ExtRec); + + fil->rsrc_fork.fork = HFS_FK_RSRC; + fil->rsrc_fork.entry = entry; + fil->rsrc_fork.lsize = hfs_get_hl(cat->u.fil.RLgLen); + fil->rsrc_fork.psize = hfs_get_hl(cat->u.fil.RPyLen) >> + HFS_SECTOR_SIZE_BITS; + hfs_extent_in(&fil->rsrc_fork, cat->u.fil.RExtRec); + + memcpy(&entry->info.file.finfo, &cat->u.fil.UsrWds, 16); + memcpy(&entry->info.file.fxinfo, &cat->u.fil.FndrInfo, 16); + + entry->create_date = hfs_get_nl(cat->u.fil.CrDat); + entry->modify_date = hfs_get_nl(cat->u.fil.MdDat); + entry->backup_date = hfs_get_nl(cat->u.fil.BkDat); + fil->clumpablks = (hfs_get_hs(cat->u.fil.ClpSize) + / entry->mdb->alloc_blksz) + >> HFS_SECTOR_SIZE_BITS; + fil->flags = cat->u.fil.Flags; + } else { + hfs_warn("hfs_fs: entry is neither file nor directory!\n"); + } +} + +/* + * count_dir_entries() + * + * Count the number of files and directories in a given directory. + */ +static inline void count_dir_entries(struct hfs_cat_entry *entry, + struct hfs_brec *brec) +{ + int error = 0; + hfs_u32 cnid; + hfs_u8 type; + + if (!hfs_cat_open(entry, brec)) { + while (!(error = hfs_cat_next(entry, brec, 1, &cnid, &type))) { + if (type == HFS_CDR_FIL) { + ++entry->u.dir.files; + } else if (type == HFS_CDR_DIR) { + ++entry->u.dir.dirs; + } + } /* -ENOENT is normal termination */ + } + if (error != -ENOENT) { + entry->cnid = 0; + } +} + +/* + * read_entry() + * + * Convert a (struct hfs_brec) to a (struct hfs_cat_entry). + */ +static inline void read_entry(struct hfs_cat_entry *entry, + struct hfs_brec *brec) +{ + int need_count; + struct hfs_cat_rec *rec = brec->data; + + __read_entry(entry, rec); + + need_count = (rec->cdrType == HFS_CDR_DIR) && rec->u.dir.Val; + + hfs_brec_relse(brec, NULL); + + if (need_count) { + count_dir_entries(entry, brec); + } +} + +/* + * __write_entry() + * + * Convert a (struct hfs_cat_entry) to a (struct hfs_cat_rec). + */ +static void __write_entry(const struct hfs_cat_entry *entry, + struct hfs_cat_rec *cat) +{ + if (entry->type == HFS_CDR_DIR) { + const struct hfs_dir *dir = &entry->u.dir; + + hfs_put_ns(dir->flags, cat->u.dir.Flags); + hfs_put_hs(dir->dirs + dir->files, cat->u.dir.Val); + hfs_put_nl(entry->cnid, cat->u.dir.DirID); + hfs_put_nl(entry->create_date, cat->u.dir.CrDat); + hfs_put_nl(entry->modify_date, cat->u.dir.MdDat); + hfs_put_nl(entry->backup_date, cat->u.dir.BkDat); + memcpy(&cat->u.dir.UsrInfo, &entry->info.dir.dinfo, 16); + memcpy(&cat->u.dir.FndrInfo, &entry->info.dir.dxinfo, 16); + } else if (entry->type == HFS_CDR_FIL) { + const struct hfs_file *fil = &entry->u.file; + + cat->u.fil.Flags = fil->flags; + hfs_put_nl(entry->cnid, cat->u.fil.FlNum); + memcpy(&cat->u.fil.UsrWds, &entry->info.file.finfo, 16); + hfs_put_hl(fil->data_fork.lsize, cat->u.fil.LgLen); + hfs_put_hl(fil->data_fork.psize << HFS_SECTOR_SIZE_BITS, + cat->u.fil.PyLen); + hfs_put_hl(fil->rsrc_fork.lsize, cat->u.fil.RLgLen); + hfs_put_hl(fil->rsrc_fork.psize << HFS_SECTOR_SIZE_BITS, + cat->u.fil.RPyLen); + hfs_put_nl(entry->create_date, cat->u.fil.CrDat); + hfs_put_nl(entry->modify_date, cat->u.fil.MdDat); + hfs_put_nl(entry->backup_date, cat->u.fil.BkDat); + memcpy(&cat->u.fil.FndrInfo, &entry->info.file.fxinfo, 16); + hfs_put_hs((fil->clumpablks * entry->mdb->alloc_blksz) + << HFS_SECTOR_SIZE_BITS, cat->u.fil.ClpSize); + hfs_extent_out(&fil->data_fork, cat->u.fil.ExtRec); + hfs_extent_out(&fil->rsrc_fork, cat->u.fil.RExtRec); + } else { + hfs_warn("__write_entry: invalid entry\n"); + } +} + +/* + * write_entry() + * + * Write a modified entry back to the catalog B-tree. + */ +static void write_entry(struct hfs_cat_entry * entry) +{ + struct hfs_brec brec; + int error; + + wait_on_entry(entry); + if (!entry->dirt) { + return; + } + if (!entry->deleted) { + entry->lock = 1; + error = hfs_bfind(&brec, entry->mdb->cat_tree, + HFS_BKEY(&entry->key), HFS_BFIND_WRITE); + if (!error) { + if (entry->key_dirt) { + /* key may have changed case due to a rename */ + entry->key_dirt = 0; + if (brec.key->KeyLen != entry->key.KeyLen) { + hfs_warn("hfs_write_entry: key length " + "changed!\n"); + error = 1; + } else { + memcpy(brec.key, &entry->key, + entry->key.KeyLen); + } + } else if (entry->cnid != brec_to_id(&brec)) { + hfs_warn("hfs_write_entry: CNID " + "changed unexpectedly!\n"); + error = 1; + } + if (!error) { + __write_entry(entry, brec.data); + } + hfs_brec_relse(&brec, NULL); + } + if (error) { + hfs_warn("hfs_write_entry: unable to write " + "entry %08x\n", entry->cnid); + } + unlock_entry(entry); + } + entry->dirt = 0; +} + +/* + */ +#define CAN_UNUSE(tmp) ((tmp)->count < 3 && !((tmp)->lock || (tmp)->dirt)) +static inline int try_to_free_entries(const int goal) +{ + hfs_prune_entry(first_entry); + return 1; +} + + +/* + * get_empty_entry() + * + * Allocate an unused entry. + */ +static inline struct hfs_cat_entry *get_empty_entry(void) +{ + struct hfs_cat_entry * entry, * best; + int i, try = 0; + + if ((nr_entries < CCACHE_MAX) && + (nr_free_entries <= (nr_entries >> 1))) { + grow_entries(); + } +repeat: + entry = first_entry; + best = NULL; + for (i = nr_entries/2; i > 0; i--,entry = entry->next) { + if (!entry->count) { + if (!best) { + best = entry; + } + if (!entry->dirt && !entry->lock) { + best = entry; + break; + } + + } + } + if (!best || best->dirt || best->lock) { + if (nr_entries < CCACHE_MAX) { + if (grow_entries() == 0) { + goto repeat; + } + } + } + entry = best; + if (!entry) { + if (try++ < 4 && try_to_free_entries(NUM_FREE_ENTRIES)) { + goto repeat; + } + + hfs_warn("hfs_cat_get: No free entries\n"); + hfs_sleep_on(&entry_wait); + goto repeat; + } + if (entry->lock) { + wait_on_entry(entry); + goto repeat; + } + if (entry->dirt) { + write_entry(entry); + goto repeat; + } + if (entry->count) { + goto repeat; + } + + clear_entry(entry); + entry->count = 1; + entry->dirt = 0; + entry->deleted = 1; /* so it gets cleared if discarded */ + + nr_free_entries--; + if (nr_free_entries < 0) { + hfs_warn ("hfs_get_empty_entry: bad free entry count.\n"); + nr_free_entries = 0; + } + return entry; +} + +/* + * get_entry() + * + * Try to return an entry for the indicated file or directory. + * If ('read' == 0) then no attempt will be made to read it from disk + * and a locked, but uninitialized, entry is returned. + */ +static struct hfs_cat_entry *get_entry(struct hfs_mdb *mdb, + const struct hfs_cat_key *key, int read) +{ + struct hfs_cat_entry **h; + struct hfs_cat_entry * entry; + struct hfs_cat_entry * empty = NULL; + struct hfs_brec brec; + + h = hash(mdb, key); +repeat: + for (entry = *h; entry ; entry = entry->hash_next) { + if (entry->mdb == mdb && !hfs_cat_compare(&entry->key, key)) { + goto found_it; + } + } + if (!empty) { + empty = get_empty_entry(); + if (empty && read && + hfs_bfind(&brec, mdb->cat_tree, + HFS_BKEY(key), HFS_BFIND_READ_EQ)) { + /* If we get here then: + 1) We got an empty entry. + 2) We want to read the record. + 3) We failed to find the record. */ + hfs_cat_put(empty); + empty = NULL; + } + if (empty) { + goto repeat; + } + return NULL; + } + entry = empty; + entry->deleted = 0; + entry->mdb = mdb; + memcpy(&entry->key, key, sizeof(*key)); + put_last_free(entry); + insert_hash(entry); + + entry->lock = 1; + if (!read) { + /* Return a locked but incomplete entry. Note that the + caller can tell it is incomplete since entry->cnid = 0. */ + return entry; + } + read_entry(entry, &brec); + unlock_entry(entry); + + goto return_it; + +found_it: + if (!entry->count) { + nr_free_entries--; + } + entry->count++; + if (empty) { + if (read) { + hfs_brec_relse(&brec, NULL); + } + hfs_cat_put(empty); + } + wait_on_entry(entry); + if (entry->deleted) { + /* The entry was deleted while we slept */ + hfs_cat_put(entry); + hfs_relinquish(); + goto repeat; + } + +return_it: + if (!entry->cnid) { + /* There was an error reading the entry */ + hfs_cat_put(entry); + entry = NULL; + } + return entry; +} + +/* + * new_cnid() + * + * Allocate a CNID to use for a new file or directory. + */ +static inline hfs_u32 new_cnid(struct hfs_mdb *mdb) +{ + /* If the create succeeds then the mdb will get dirtied */ + return htonl(mdb->next_id++); +} + +/* + * update_dir() + * + * Update counts, times and dirt on a changed directory + */ +static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir, + int is_dir, int count) +{ + /* update counts */ + if (is_dir) { + mdb->dir_count += count; + dir->u.dir.dirs += count; + if (dir->cnid == htonl(HFS_ROOT_CNID)) { + mdb->root_dirs += count; + } + } else { + mdb->file_count += count; + dir->u.dir.files += count; + if (dir->cnid == htonl(HFS_ROOT_CNID)) { + mdb->root_files += count; + } + } + + /* update times and dirt */ + dir->modify_date = hfs_time(); + dir->dirt = 1; +} + +/* + * Add a writer to dir, excluding readers. + */ +static inline void start_write(struct hfs_cat_entry *dir) +{ + if (dir->u.dir.readers || dir->u.dir.read_wait) { + hfs_sleep_on(&dir->u.dir.write_wait); + } + ++dir->u.dir.writers; +} + +/* + * Add a reader to dir, excluding writers. + */ +static inline void start_read(struct hfs_cat_entry *dir) +{ + if (dir->u.dir.writers || dir->u.dir.write_wait) { + hfs_sleep_on(&dir->u.dir.read_wait); + } + ++dir->u.dir.readers; +} + +/* + * Remove a writer from dir, possibly admitting readers. + */ +static inline void end_write(struct hfs_cat_entry *dir) +{ + if (!(--dir->u.dir.writers)) { + hfs_wake_up(&dir->u.dir.read_wait); + } +} + +/* + * Remove a reader from dir, possibly admitting writers. + */ +static inline void end_read(struct hfs_cat_entry *dir) +{ + if (!(--dir->u.dir.readers)) { + hfs_wake_up(&dir->u.dir.write_wait); + } +} + +/* + * create_entry() + * + * Add a new file or directory to the catalog B-tree and + * return a (struct hfs_cat_entry) for it in '*result'. + */ +static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key, + const struct hfs_cat_rec *record, int is_dir, + hfs_u32 cnid, struct hfs_cat_entry **result) +{ + struct hfs_mdb *mdb = parent->mdb; + struct hfs_cat_entry *entry; + struct hfs_cat_key thd_key; + struct hfs_cat_rec thd_rec; + int error, has_thread; + + if (result) { + *result = NULL; + } + + /* keep readers from getting confused by changing dir size */ + start_write(parent); + + /* create a locked entry in the cache */ + entry = get_entry(mdb, key, 0); + if (!entry) { + /* The entry exists but can't be read */ + error = -EIO; + goto done; + } + if (entry->cnid) { + /* The (unlocked) entry exists in the cache */ + error = -EEXIST; + goto bail2; + } + + /* limit directory valence to signed 16-bit integer */ + if ((parent->u.dir.dirs + parent->u.dir.files) >= HFS_MAX_VALENCE) { + error = -ENOSPC; + goto bail1; + } + + has_thread = is_dir || (record->u.fil.Flags & HFS_FIL_THD); + + if (has_thread) { + /* init some fields for the thread record */ + memset(&thd_rec, 0, sizeof(thd_rec)); + thd_rec.cdrType = is_dir ? HFS_CDR_THD : HFS_CDR_FTH; + memcpy(&thd_rec.u.thd.ParID, &key->ParID, + sizeof(hfs_u32) + sizeof(struct hfs_name)); + + /* insert the thread record */ + hfs_cat_build_key(cnid, NULL, &thd_key); + error = hfs_binsert(mdb->cat_tree, HFS_BKEY(&thd_key), + &thd_rec, 2 + sizeof(THD_REC)); + if (error) { + goto bail1; + } + } + + /* insert the record */ + error = hfs_binsert(mdb->cat_tree, HFS_BKEY(key), record, + is_dir ? 2 + sizeof(DIR_REC) : + 2 + sizeof(FIL_REC)); + if (error) { + if (has_thread && (error != -EIO)) { + /* at least TRY to remove the thread record */ + (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&thd_key)); + } + goto bail1; + } + + /* update the parent directory */ + update_dir(mdb, parent, is_dir, 1); + + /* complete the cache entry and return success */ + __read_entry(entry, record); + unlock_entry(entry); + if (result) { + *result = entry; + } else { + hfs_cat_put(entry); + } + goto done; + +bail1: + entry->deleted = 1; + remove_hash(entry); + unlock_entry(entry); +bail2: + hfs_cat_put(entry); +done: + end_write(parent); + return error; +} + +/*================ Global functions ================*/ + +/* + * hfs_cat_put() + * + * Release an entry we aren't using anymore. + * + * NOTE: We must be careful any time we sleep on a non-deleted + * entry that the entry is in a consistent state, since another + * process may get the entry while we sleep. That is why we + * 'goto repeat' after each operation that might sleep. + */ +void hfs_cat_put(struct hfs_cat_entry * entry) +{ + if (!entry) { + return; + } + wait_on_entry(entry); + if (!entry->count) { + hfs_warn("hfs_cat_put: trying to free free entry\n"); + return; + } +repeat: + if (entry->count > 1) { + entry->count--; + return; + } + + if (!entry->cnid) { + clear_entry(entry); + return; + } + + if (entry->type == HFS_CDR_FIL) { + if (entry->deleted) { + /* free all extents */ + entry->u.file.data_fork.lsize = 0; + hfs_extent_adj(&entry->u.file.data_fork); + entry->u.file.rsrc_fork.lsize = 0; + hfs_extent_adj(&entry->u.file.rsrc_fork); + } else { + /* clear out any cached extents */ + if (entry->u.file.data_fork.first.next) { + hfs_extent_free(&entry->u.file.data_fork); + wait_on_entry(entry); + goto repeat; + } + if (entry->u.file.rsrc_fork.first.next) { + hfs_extent_free(&entry->u.file.rsrc_fork); + wait_on_entry(entry); + goto repeat; + } + } + } + + if (entry->deleted) { + clear_entry(entry); + return; + } + + if (entry->dirt) { + write_entry(entry); + goto repeat; + } + + entry->count--; + nr_free_entries++; + + /* get_empty_entry() could be blocked waiting for more entries */ + hfs_wake_up(&entry_wait); + + return; +} + +/* + * hfs_cat_get() + * + * Wrapper for get_entry() which always calls with ('read'==1). + * Used for access to get_entry() from outside this file. + */ +struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *mdb, + const struct hfs_cat_key *key) +{ + return get_entry(mdb, key, 1); +} + +/* + * hfs_cat_invalidate() + * + * Called by hfs_mdb_put() to remove all the entries + * in the cache which are associated with a given MDB. + */ +void hfs_cat_invalidate(struct hfs_mdb *mdb) +{ + struct hfs_cat_entry * entry, * next; + int i; + + next = first_entry; + for (i = nr_entries ; i > 0 ; i--) { + entry = next; + next = entry->next; /* clear_entry() changes the queues.. */ + if (entry->mdb != mdb) { + continue; + } + if (entry->count || entry->dirt || entry->lock) { + hfs_warn("hfs_fs: entry busy on removed device %s.\n", + hfs_mdb_name(entry->mdb->sys_mdb)); + continue; + } + clear_entry(entry); + } +} + +/* + * hfs_cat_commit() + * + * Called by hfs_mdb_commit() to write dirty entries to the disk buffers. + */ +void hfs_cat_commit(struct hfs_mdb *mdb) +{ + int i; + struct hfs_cat_entry * entry; + + entry = first_entry; + for(i = 0; i < nr_entries*2; i++, entry = entry->next) { + if (mdb && entry->mdb != mdb) { + continue; + } + if (!entry->cnid || entry->deleted) { + continue; + } + wait_on_entry(entry); + if (entry->dirt) { + write_entry(entry); + } + } +} + +/* + * hfs_cat_free() + * + * Releases all the memory allocated in grow_entries(). + * Must call hfs_cat_invalidate() on all MDBs before calling this. + */ +void hfs_cat_free(void) +{ + struct allocation_unit *tmp; + + while (allocation) { + tmp = allocation->next; + HFS_DELETE(allocation); + allocation = tmp; + } +} + +/* + * hfs_cat_compare() + * + * Description: + * This is the comparison function used for the catalog B-tree. In + * comparing catalog B-tree entries, the parent id is the most + * significant field (compared as unsigned ints). The name field is + * the least significant (compared in "Macintosh lexical order", + * see hfs_strcmp() in string.c) + * Input Variable(s): + * struct hfs_cat_key *key1: pointer to the first key to compare + * struct hfs_cat_key *key2: pointer to the second key to compare + * Output Variable(s): + * NONE + * Returns: + * int: negative if key1key2, and 0 if key1==key2 + * Preconditions: + * key1 and key2 point to "valid" (struct hfs_cat_key)s. + * Postconditions: + * This function has no side-effects + */ +int hfs_cat_compare(const struct hfs_cat_key *key1, + const struct hfs_cat_key *key2) +{ + unsigned int parents; + int retval; + + parents = hfs_get_hl(key1->ParID) - hfs_get_hl(key2->ParID); + if (parents != 0) { + retval = (int)parents; + } else { + retval = hfs_strcmp(&key1->CName, &key2->CName); + } + return retval; +} + +/* + * hfs_cat_build_key() + * + * Given the ID of the parent and the name build a search key. + */ +void hfs_cat_build_key(hfs_u32 parent, const struct hfs_name *cname, + struct hfs_cat_key *key) +{ + hfs_put_nl(parent, key->ParID); + + if (cname) { + key->KeyLen = 6 + cname->Len; + memcpy(&key->CName, cname, sizeof(*cname)); + } else { + key->KeyLen = 6; + memset(&key->CName, 0, sizeof(*cname)); + } +} + +/* + * hfs_cat_open() + * + * Given a directory on an HFS filesystem get its thread and + * lock the directory against insertions and deletions. + * Return 0 on success or an error code on failure. + */ +int hfs_cat_open(struct hfs_cat_entry *dir, struct hfs_brec *brec) +{ + struct hfs_cat_key key; + int error; + + if (dir->type != HFS_CDR_DIR) { + return -EINVAL; + } + + /* Block writers */ + start_read(dir); + + /* Find the directory */ + hfs_cat_build_key(dir->cnid, NULL, &key); + error = hfs_bfind(brec, dir->mdb->cat_tree, + HFS_BKEY(&key), HFS_BFIND_READ_EQ); + + if (error) { + end_read(dir); + } + + return error; +} + +/* + * hfs_cat_next() + * + * Given a catalog brec structure, replace it with the count'th next brec + * in the same directory. + * Return an error code if there is a problem, 0 if OK. + * Note that an error code of -ENOENT means there are no more entries + * in this directory. + * The directory is "closed" on an error. + */ +int hfs_cat_next(struct hfs_cat_entry *dir, struct hfs_brec *brec, + hfs_u16 count, hfs_u32 *cnid, hfs_u8 *type) +{ + int error; + + if (!dir || !brec) { + return -EINVAL; + } + + /* Get the count'th next catalog tree entry */ + error = hfs_bsucc(brec, count); + if (!error) { + struct hfs_cat_key *key = (struct hfs_cat_key *)brec->key; + if (hfs_get_nl(key->ParID) != dir->cnid) { + hfs_brec_relse(brec, NULL); + error = -ENOENT; + } + } + if (!error) { + *type = ((struct hfs_cat_rec *)brec->data)->cdrType; + *cnid = brec_to_id(brec); + } else { + end_read(dir); + } + return error; +} + +/* + * hfs_cat_close() + * + * Given a catalog brec structure, replace it with the count'th next brec + * in the same directory. + * Return an error code if there is a problem, 0 if OK. + * Note that an error code of -ENOENT means there are no more entries + * in this directory. + */ +void hfs_cat_close(struct hfs_cat_entry *dir, struct hfs_brec *brec) +{ + if (dir && brec) { + hfs_brec_relse(brec, NULL); + end_read(dir); + } +} + +/* + * hfs_cat_parent() + * + * Given a catalog entry, return the entry for its parent. + * Uses catalog key for the entry to get its parent's ID + * and then uses the parent's thread record to locate the + * parent's actual catalog entry. + */ +struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *entry) +{ + struct hfs_cat_entry *retval = NULL; + struct hfs_mdb *mdb = entry->mdb; + struct hfs_brec brec; + struct hfs_cat_key key; + int error; + + lock_entry(entry); + if (!entry->deleted) { + hfs_cat_build_key(hfs_get_nl(entry->key.ParID), NULL, &key); + error = hfs_bfind(&brec, mdb->cat_tree, + HFS_BKEY(&key), HFS_BFIND_READ_EQ); + if (!error) { + /* convert thread record to key */ + struct hfs_cat_rec *rec = brec.data; + key.KeyLen = 6 + rec->u.thd.CName.Len; + memcpy(&key.ParID, &rec->u.thd.ParID, + sizeof(hfs_u32) + sizeof(struct hfs_name)); + + hfs_brec_relse(&brec, NULL); + + retval = hfs_cat_get(mdb, &key); + } + } + unlock_entry(entry); + return retval; +} + +/* + * hfs_cat_create() + * + * Create a new file with the indicated name in the indicated directory. + * The file will have the indicated flags, type and creator. + * If successful an (struct hfs_cat_entry) is returned in '*result'. + */ +int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key, + hfs_u8 flags, hfs_u32 type, hfs_u32 creator, + struct hfs_cat_entry **result) +{ + struct hfs_cat_rec record; + hfs_u32 id = new_cnid(parent->mdb); + hfs_u32 mtime = hfs_time(); + + /* init some fields for the file record */ + memset(&record, 0, sizeof(record)); + record.cdrType = HFS_CDR_FIL; + record.u.fil.Flags = flags | HFS_FIL_USED; + hfs_put_nl(id, record.u.fil.FlNum); + hfs_put_nl(mtime, record.u.fil.CrDat); + hfs_put_nl(mtime, record.u.fil.MdDat); + hfs_put_nl(0, record.u.fil.BkDat); + hfs_put_nl(type, record.u.fil.UsrWds.fdType); + hfs_put_nl(creator, record.u.fil.UsrWds.fdCreator); + + return create_entry(parent, key, &record, 0, id, result); +} + +/* + * hfs_cat_mkdir() + * + * Create a new directory with the indicated name in the indicated directory. + * If successful an (struct hfs_cat_entry) is returned in '*result'. + */ +int hfs_cat_mkdir(struct hfs_cat_entry *parent, struct hfs_cat_key *key, + struct hfs_cat_entry **result) +{ + struct hfs_cat_rec record; + hfs_u32 id = new_cnid(parent->mdb); + hfs_u32 mtime = hfs_time(); + + /* init some fields for the directory record */ + memset(&record, 0, sizeof(record)); + record.cdrType = HFS_CDR_DIR; + hfs_put_nl(id, record.u.dir.DirID); + hfs_put_nl(mtime, record.u.dir.CrDat); + hfs_put_nl(mtime, record.u.dir.MdDat); + hfs_put_nl(0, record.u.dir.BkDat); + hfs_put_hs(0xff, record.u.dir.UsrInfo.frView); + + return create_entry(parent, key, &record, 1, id, result); +} + +/* + * hfs_cat_delete() + * + * Delete the indicated file or directory. + * The associated thread is also removed unless ('with_thread'==0). + */ +int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, + int with_thread) +{ + struct hfs_cat_key key; + struct hfs_mdb *mdb = parent->mdb; + int is_dir, error = 0; + + if (parent->mdb != entry->mdb) { + return -EINVAL; + } + + if (entry->type == HFS_CDR_FIL) { + with_thread = (entry->u.file.flags&HFS_FIL_THD) && with_thread; + is_dir = 0; + } else { + is_dir = 1; + } + + /* keep readers from getting confused by changing dir size */ + start_write(parent); + + /* don't delete a busy directory */ + if (entry->type == HFS_CDR_DIR) { + start_read(entry); + + if (entry->u.dir.files || entry->u.dir.dirs) { + error = -ENOTEMPTY; + } + } + + /* try to delete the file or directory */ + if (!error) { + lock_entry(entry); + if (entry->deleted) { + /* somebody beat us to it */ + error = -ENOENT; + } else { + error = hfs_bdelete(mdb->cat_tree, + HFS_BKEY(&entry->key)); + } + unlock_entry(entry); + } + + if (!error) { + /* Mark the entry deleted and remove it from the cache */ + entry->deleted = 1; + remove_hash(entry); + + /* try to delete the thread entry if it exists */ + if (with_thread) { + hfs_cat_build_key(entry->cnid, NULL, &key); + (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key)); + } + + update_dir(mdb, parent, is_dir, -1); + } + + if (entry->type == HFS_CDR_DIR) { + end_read(entry); + } + end_write(parent); + return error; +} + +/* + * hfs_cat_move() + * + * Rename a file or directory, possibly to a new directory. + * If the destination exists it is removed and a + * (struct hfs_cat_entry) for it is returned in '*result'. + */ +int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir, + struct hfs_cat_entry *entry, struct hfs_cat_key *new_key, + struct hfs_cat_entry **removed) +{ + struct hfs_cat_entry *dest; + struct hfs_mdb *mdb; + int error = 0; + int is_dir, has_thread; + + if (removed) { + *removed = NULL; + } + + /* sanity checks */ + if (!old_dir || !new_dir) { + return -EINVAL; + } + mdb = old_dir->mdb; + if (mdb != new_dir->mdb) { + return -EXDEV; + } + + /* precompute a few things */ + if (entry->type == HFS_CDR_DIR) { + is_dir = 1; + has_thread = 1; + } else if (entry->type == HFS_CDR_FIL) { + is_dir = 0; + has_thread = entry->u.file.flags & HFS_FIL_THD; + } else { + return -EINVAL; + } + + while (mdb->rename_lock) { + hfs_sleep_on(&mdb->rename_wait); + } + mdb->rename_lock = 1; + + /* keep readers from getting confused by changing dir size */ + start_write(new_dir); + if (old_dir != new_dir) { + start_write(old_dir); + } + + /* Don't move a directory inside itself */ + if (is_dir) { + struct hfs_cat_key thd_key; + struct hfs_brec brec; + + hfs_u32 id = new_dir->cnid; + while (id != htonl(HFS_ROOT_CNID)) { + if (id == entry->cnid) { + error = -EINVAL; + } else { + hfs_cat_build_key(id, NULL, &thd_key); + error = hfs_bfind(&brec, mdb->cat_tree, + HFS_BKEY(&thd_key), + HFS_BFIND_READ_EQ); + } + if (error) { + goto done; + } else { + struct hfs_cat_rec *rec = brec.data; + id = hfs_get_nl(rec->u.thd.ParID); + hfs_brec_relse(&brec, NULL); + } + } + } + +restart: + /* see if the destination exists, getting it if it does */ + dest = hfs_cat_get(mdb, new_key); + + if (!dest) { + /* destination doesn't exist, so create it */ + struct hfs_cat_rec new_record; + + /* create a locked entry in the cache */ + dest = get_entry(mdb, new_key, 0); + if (!dest) { + error = -EIO; + goto done; + } + if (dest->cnid) { + /* The (unlocked) entry exists in the cache */ + goto have_distinct; + } + + /* limit directory valence to signed 16-bit integer */ + if ((new_dir->u.dir.dirs + new_dir->u.dir.files) >= + HFS_MAX_VALENCE) { + error = -ENOSPC; + goto bail3; + } + + /* build the new record */ + new_record.cdrType = entry->type; + __write_entry(entry, &new_record); + + /* insert the new record */ + error = hfs_binsert(mdb->cat_tree, HFS_BKEY(new_key), + &new_record, is_dir ? 2 + sizeof(DIR_REC) : + 2 + sizeof(FIL_REC)); + if (error == -EEXIST) { + dest->deleted = 1; + remove_hash(dest); + unlock_entry(dest); + hfs_cat_put(dest); + goto restart; + } else if (error) { + goto bail3; + } + + /* update the destination directory */ + update_dir(mdb, new_dir, is_dir, 1); + } else if (entry != dest) { +have_distinct: + /* The destination exists and is not same as source */ + lock_entry(dest); + if (dest->deleted) { + unlock_entry(dest); + hfs_cat_put(dest); + goto restart; + } + if (dest->type != entry->type) { + /* can't move a file on top + of a dir nor vice versa. */ + error = is_dir ? -ENOTDIR : -EISDIR; + } else if (is_dir && (dest->u.dir.dirs || dest->u.dir.files)) { + /* directory to replace is not empty */ + error = -ENOTEMPTY; + } + + if (error) { + goto bail2; + } + } else { + /* The destination exists but is same as source */ + /*--entry->count;*/ + hfs_cat_put(dest); + dest = NULL; + } + + /* lock the entry */ + lock_entry(entry); + if (entry->deleted) { + error = -ENOENT; + goto bail1; + } + + if (dest) { + /* remove the old entry */ + error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key)); + + if (error) { + /* We couldn't remove the entry for the + original file, so nothing has changed. */ + goto bail1; + } + update_dir(mdb, old_dir, is_dir, -1); + } + + /* update the thread of the dir/file we're moving */ + if (has_thread) { + struct hfs_cat_key thd_key; + struct hfs_brec brec; + + hfs_cat_build_key(entry->cnid, NULL, &thd_key); + error = hfs_bfind(&brec, mdb->cat_tree, + HFS_BKEY(&thd_key), HFS_BFIND_WRITE); + if (error == -ENOENT) { + if (is_dir) { + /* directory w/o a thread! */ + error = -EIO; + } else { + /* We were lied to! */ + entry->u.file.flags &= ~HFS_FIL_THD; + entry->dirt = 1; + } + } + if (!error) { + struct hfs_cat_rec *rec = brec.data; + memcpy(&rec->u.thd.ParID, &new_key->ParID, + sizeof(hfs_u32) + sizeof(struct hfs_name)); + hfs_brec_relse(&brec, NULL); + } else if (error == -ENOENT) { + error = 0; + } else if (!dest) { + /* Nothing was changed */ + unlock_entry(entry); + goto done; + } else { + /* Something went seriously wrong. + The dir/file has been deleted. */ + /* XXX try some recovery? */ + entry->deleted = 1; + remove_hash(entry); + goto bail1; + } + } + + /* TRY to remove the thread for the pre-existing entry */ + if (dest && dest->cnid && + (is_dir || (dest->u.file.flags & HFS_FIL_THD))) { + struct hfs_cat_key thd_key; + + hfs_cat_build_key(dest->cnid, NULL, &thd_key); + (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&thd_key)); + } + + /* update directories */ + new_dir->modify_date = hfs_time(); + new_dir->dirt = 1; + + /* update key */ + remove_hash(entry); + memcpy(&entry->key, new_key, sizeof(*new_key)); + entry->key_dirt = 1; /* Since case might differ */ + entry->dirt = 1; + insert_hash(entry); + unlock_entry(entry); + + /* delete any pre-existing or place-holder entry */ + if (dest) { + dest->deleted = 1; + remove_hash(dest); + unlock_entry(dest); + if (removed && dest->cnid) { + *removed = dest; + } else { + hfs_cat_put(dest); + } + } + goto done; + +bail1: + unlock_entry(entry); +bail2: + if (dest) { + if (!dest->cnid) { + /* TRY to remove the new entry */ + (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(new_key)); + update_dir(mdb, new_dir, is_dir, -1); +bail3: + dest->deleted = 1; + remove_hash(dest); + } + unlock_entry(dest); + hfs_cat_put(dest); + } +done: + if (new_dir != old_dir) { + end_write(old_dir); + } + end_write(new_dir); + mdb->rename_lock = 0; + hfs_wake_up(&mdb->rename_wait); + + return error; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/dir.c linux/fs/hfs/dir.c --- v2.1.77/linux/fs/hfs/dir.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/dir.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,400 @@ +/* + * linux/fs/hfs/dir.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains directory-related functions independent of which + * scheme is being used to represent forks. + * + * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ File-local functions ================*/ + +/* + * build_key() + * + * Build a key for a file by the given name in the given directory. + * If the name matches one of the reserved names returns 1 otherwise 0. + */ +static int build_key(struct hfs_cat_key *key, struct inode *dir, + const char *name, int len) +{ + struct hfs_name cname; + const struct hfs_name *reserved; + + /* mangle the name */ + hfs_nameout(dir, &cname, name, len); + + /* check against reserved names */ + reserved = HFS_SB(dir->i_sb)->s_reserved1; + while (reserved->Len) { + if (hfs_streq(reserved, &cname)) { + return 1; + } + ++reserved; + } + + /* check against the names reserved only in the root directory */ + if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) { + reserved = HFS_SB(dir->i_sb)->s_reserved2; + while (reserved->Len) { + if (hfs_streq(reserved, &cname)) { + return 1; + } + ++reserved; + } + } + + /* build the key */ + hfs_cat_build_key(HFS_I(dir)->entry->cnid, &cname, key); + + return 0; +} + +/* + * update_dirs_plus() + * + * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and + * 'i_version' of the inodes associated with a directory that has + * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it. + */ +static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir) +{ + int i; + + for (i = 0; i < 4; ++i) { + struct dentry *de = dir->sys_entry[i]; + if (de) { + struct inode *tmp = de->d_inode; + if (S_ISDIR(tmp->i_mode)) { + if (is_dir && + (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) { + /* In "normal" directory only */ + ++(tmp->i_nlink); + } + tmp->i_size += HFS_I(tmp)->dir_size; + tmp->i_version = ++event; + } + tmp->i_ctime = tmp->i_mtime = CURRENT_TIME; + mark_inode_dirty(tmp); + } + } +} + +/* + * update_dirs_plus() + * + * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and + * 'i_version' of the inodes associated with a directory that has + * had a file ('is_dir'==0) or directory ('is_dir'!=0) removed. + */ +static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir) +{ + int i; + + for (i = 0; i < 4; ++i) { + struct dentry *de = dir->sys_entry[i]; + if (de) { + struct inode *tmp = de->d_inode; + if (S_ISDIR(tmp->i_mode)) { + if (is_dir && + (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) { + /* In "normal" directory only */ + --(tmp->i_nlink); + } + tmp->i_size -= HFS_I(tmp)->dir_size; + tmp->i_version = ++event; + } + tmp->i_ctime = tmp->i_mtime = CURRENT_TIME; + mark_inode_dirty(tmp); + } + } +} + +/* + * mark_inodes_deleted() + * + * Update inodes associated with a deleted entry to reflect its deletion. + * Well, we really just drop the dentry. + */ +static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, + struct dentry *dentry) +{ + struct dentry *de; + int i; + + for (i = 0; i < 4; ++i) { + if ((de = entry->sys_entry[i]) && (dentry != de)) { + entry->sys_entry[i] = NULL; + dget(de); + d_delete(de); + dput(de); + } + } +} + +/*================ Global functions ================*/ + +/* + * hfs_dir_read() + * + * This is the read() entry in the file_operations structure for HFS + * directories. It simply returns an error code, since reading is not + * supported. + */ +hfs_rwret_t hfs_dir_read(struct file * filp, char *buf, + hfs_rwarg_t count, loff_t *ppos) +{ + return -EISDIR; +} + +/* + * hfs_create() + * + * This is the create() entry in the inode_operations structure for + * regular HFS directories. The purpose is to create a new file in + * a directory and return a corresponding inode, given the inode for + * the directory and the name (and its length) of the new file. + */ +int hfs_create(struct inode * dir, struct dentry *dentry, int mode) +{ + struct hfs_cat_entry *entry = HFS_I(dir)->entry; + struct hfs_cat_entry *new; + struct hfs_cat_key key; + struct inode *inode; + int error; + + /* build the key, checking against reserved names */ + if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) { + error = -EEXIST; + } else { + /* try to create the file */ + error = hfs_cat_create(entry, &key, + (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK, + HFS_SB(dir->i_sb)->s_type, + HFS_SB(dir->i_sb)->s_creator, &new); + } + + if (!error) { + update_dirs_plus(entry, 0); + + /* create an inode for the new file */ + inode = hfs_iget(new, HFS_I(dir)->file_type, dentry); + if (!inode) { + /* XXX correct error? */ + error = -EIO; + } else { + if (HFS_I(dir)->d_drop_op) + HFS_I(dir)->d_drop_op(HFS_I(dir)->file_type, dentry); + d_instantiate(dentry, inode); + } + } + + return error; +} + +/* + * hfs_mkdir() + * + * This is the mkdir() entry in the inode_operations structure for + * regular HFS directories. The purpose is to create a new directory + * in a directory, given the inode for the parent directory and the + * name (and its length) of the new directory. + */ +int hfs_mkdir(struct inode * parent, struct dentry *dentry, int mode) +{ + struct hfs_cat_entry *entry = HFS_I(parent)->entry; + struct hfs_cat_entry *new; + struct hfs_cat_key key; + struct inode *inode; + int error; + + /* build the key, checking against reserved names */ + if (build_key(&key, parent, dentry->d_name.name, + dentry->d_name.len)) { + error = -EEXIST; + } else { + /* try to create the directory */ + error = hfs_cat_mkdir(entry, &key, &new); + } + + if (!error) { + update_dirs_plus(entry, 1); + inode = hfs_iget(new, HFS_I(parent)->file_type, dentry); + if (!inode) { + error = -EIO; + } else + d_instantiate(dentry, inode); + } + + return error; +} + +/* + * hfs_mknod() + * + * This is the mknod() entry in the inode_operations structure for + * regular HFS directories. The purpose is to create a new entry + * in a directory, given the inode for the parent directory and the + * name (and its length) and the mode of the new entry (and the device + * number if the entry is to be a device special file). + * + * HFS only supports regular files and directories and Linux disallows + * using mknod() to create directories. Thus we just check the arguments + * and call hfs_create(). + */ +int hfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) +{ + int error; + + if (!dir) { + error = -ENOENT; + } else if (S_ISREG(mode)) { + error = hfs_create(dir, dentry, mode); + } else { + error = -EPERM; + } + return error; +} + +/* + * hfs_unlink() + * + * This is the unlink() entry in the inode_operations structure for + * regular HFS directories. The purpose is to delete an existing + * file, given the inode for the parent directory and the name + * (and its length) of the existing file. + */ +int hfs_unlink(struct inode * dir, struct dentry *dentry) +{ + struct hfs_cat_entry *entry = HFS_I(dir)->entry; + struct hfs_cat_entry *victim = NULL; + struct hfs_cat_key key; + int error; + + if (build_key(&key, dir, dentry->d_name.name, + dentry->d_name.len)) { + error = -EPERM; + } else if (!(victim = hfs_cat_get(entry->mdb, &key))) { + error = -ENOENT; + } else if (victim->type != HFS_CDR_FIL) { + error = -EPERM; + } else if (!(error = hfs_cat_delete(entry, victim, 1))) { + mark_inodes_deleted(victim, dentry); + d_delete(dentry); + update_dirs_minus(entry, 0); + } + + hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ + return error; +} + +/* + * hfs_rmdir() + * + * This is the rmdir() entry in the inode_operations structure for + * regular HFS directories. The purpose is to delete an existing + * directory, given the inode for the parent directory and the name + * (and its length) of the existing directory. + */ +int hfs_rmdir(struct inode * parent, struct dentry *dentry) +{ + struct hfs_cat_entry *entry = HFS_I(parent)->entry; + struct hfs_cat_entry *victim = NULL; + struct hfs_cat_key key; + int error; + + if (build_key(&key, parent, dentry->d_name.name, + dentry->d_name.len)) { + error = -EPERM; + } else if (!(victim = hfs_cat_get(entry->mdb, &key))) { + error = -ENOENT; + } else if (victim->type != HFS_CDR_DIR) { + error = -ENOTDIR; + } else if (/* we only have to worry about 2 and 3 for mount points */ + (victim->sys_entry[2] && + (victim->sys_entry[2] != + victim->sys_entry[2]->d_mounts)) || + (victim->sys_entry[3] && + (victim->sys_entry[3] != + victim->sys_entry[3]->d_mounts)) + ) { + error = -EBUSY; + } else if (!(error = hfs_cat_delete(entry, victim, 1))) { + mark_inodes_deleted(victim, dentry); + d_delete(dentry); + update_dirs_minus(entry, 1); + } + + hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ + return error; +} + +/* + * hfs_rename() + * + * This is the rename() entry in the inode_operations structure for + * regular HFS directories. The purpose is to rename an existing + * file or directory, given the inode for the current directory and + * the name (and its length) of the existing file/directory and the + * inode for the new directory and the name (and its length) of the + * new file/directory. + * XXX: how do you handle must_be dir? + */ +int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct hfs_cat_entry *old_parent = HFS_I(old_dir)->entry; + struct hfs_cat_entry *new_parent = HFS_I(new_dir)->entry; + struct hfs_cat_entry *victim = NULL; + struct hfs_cat_entry *deleted; + struct hfs_cat_key key; + int error; + + if (build_key(&key, old_dir, old_dentry->d_name.name, + old_dentry->d_name.len) || + (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) { + error = -EPERM; + } else if (!(victim = hfs_cat_get(old_parent->mdb, &key))) { + error = -ENOENT; + } else if (build_key(&key, new_dir, new_dentry->d_name.name, + new_dentry->d_name.len)) { + error = -EPERM; + } else if (!(error = hfs_cat_move(old_parent, new_parent, + victim, &key, &deleted))) { + int is_dir = (victim->type == HFS_CDR_DIR); + + /* drop the old dentries */ + mark_inodes_deleted(victim, old_dentry); + update_dirs_minus(old_parent, is_dir); + if (deleted) { + mark_inodes_deleted(deleted, new_dentry); + hfs_cat_put(deleted); + } else { + /* no existing inodes. just drop negative dentries */ + if (HFS_I(new_dir)->d_drop_op) + HFS_I(new_dir)->d_drop_op(HFS_I(new_dir)->file_type, + new_dentry); + update_dirs_plus(new_parent, is_dir); + } + + /* update dcache */ + d_move(old_dentry, new_dentry); + } + + hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ + return error; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/dir_cap.c linux/fs/hfs/dir_cap.c --- v2.1.77/linux/fs/hfs/dir_cap.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/dir_cap.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,402 @@ +/* + * linux/fs/hfs/dir_cap.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the inode_operations and file_operations + * structures for HFS directories under the CAP scheme. + * + * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds + * + * The source code distribution of the Columbia AppleTalk Package for + * UNIX, version 6.0, (CAP) was used as a specification of the + * location and format of files used by CAP's Aufs. No code from CAP + * appears in hfs_fs. hfs_fs is not a work ``derived'' from CAP in + * the sense of intellectual property law. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ Forward declarations ================*/ + +static int cap_lookup(struct inode *, struct dentry *); +static int cap_readdir(struct file *, void *, filldir_t); + +/*================ Global variables ================*/ + +#define DOT_LEN 1 +#define DOT_DOT_LEN 2 +#define DOT_RESOURCE_LEN 9 +#define DOT_FINDERINFO_LEN 11 +#define DOT_ROOTINFO_LEN 9 + +const struct hfs_name hfs_cap_reserved1[] = { + {DOT_LEN, "."}, + {DOT_DOT_LEN, ".."}, + {DOT_RESOURCE_LEN, ".resource"}, + {DOT_FINDERINFO_LEN, ".finderinfo"}, + {0, ""}, +}; + +const struct hfs_name hfs_cap_reserved2[] = { + {DOT_ROOTINFO_LEN, ".rootinfo"}, + {0, ""}, +}; + +#define DOT (&hfs_cap_reserved1[0]) +#define DOT_DOT (&hfs_cap_reserved1[1]) +#define DOT_RESOURCE (&hfs_cap_reserved1[2]) +#define DOT_FINDERINFO (&hfs_cap_reserved1[3]) +#define DOT_ROOTINFO (&hfs_cap_reserved2[0]) + +static struct file_operations hfs_cap_dir_operations = { + NULL, /* lseek - default */ + hfs_dir_read, /* read - invalid */ + NULL, /* write - bad */ + cap_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap - none */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync, /* fsync - default */ + NULL, /* fasync - default */ + NULL, /* check_media_change - none */ + NULL /* revalidate - none */ +}; + +struct inode_operations hfs_cap_ndir_inode_operations = { + &hfs_cap_dir_operations,/* default directory file-ops */ + hfs_create, /* create */ + cap_lookup, /* lookup */ + NULL, /* link */ + hfs_unlink, /* unlink */ + NULL, /* symlink */ + hfs_mkdir, /* mkdir */ + hfs_rmdir, /* rmdir */ + hfs_mknod, /* mknod */ + hfs_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + +struct inode_operations hfs_cap_fdir_inode_operations = { + &hfs_cap_dir_operations,/* default directory file-ops */ + NULL, /* create */ + cap_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + +struct inode_operations hfs_cap_rdir_inode_operations = { + &hfs_cap_dir_operations,/* default directory file-ops */ + hfs_create, /* create */ + cap_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + +/*================ File-local functions ================*/ + +/* + * cap_lookup() + * + * This is the lookup() entry in the inode_operations structure for + * HFS directories in the CAP scheme. The purpose is to generate the + * inode corresponding to an entry in a directory, given the inode for + * the directory and the name (and its length) of the entry. + */ +static int cap_lookup(struct inode * dir, struct dentry *dentry) +{ + ino_t dtype; + struct hfs_name cname; + struct hfs_cat_entry *entry; + struct hfs_cat_key key; + struct inode *inode = NULL; + + if (!dir || !S_ISDIR(dir->i_mode)) { + goto done; + } + + entry = HFS_I(dir)->entry; + dtype = HFS_ITYPE(dir->i_ino); + + /* Perform name-mangling */ + hfs_nameout(dir, &cname, dentry->d_name.name, + dentry->d_name.len); + + /* Check for "." */ + if (hfs_streq(&cname, DOT)) { + /* this little trick skips the iget and iput */ + d_add(dentry, dir); + return 0; + } + + /* Check for "..". */ + if (hfs_streq(&cname, DOT_DOT)) { + struct hfs_cat_entry *parent; + + if (dtype != HFS_CAP_NDIR) { + /* Case for ".." in ".finderinfo" or ".resource" */ + parent = entry; + ++entry->count; /* __hfs_iget() eats one */ + } else { + /* Case for ".." in a normal directory */ + parent = hfs_cat_parent(entry); + } + inode = hfs_iget(parent, HFS_CAP_NDIR, dentry); + goto done; + } + + /* Check for special directories if in a normal directory. + Note that cap_dupdir() does an iput(dir). */ + if (dtype==HFS_CAP_NDIR) { + /* Check for ".resource", ".finderinfo" and ".rootinfo" */ + if (hfs_streq(&cname, DOT_RESOURCE)) { + ++entry->count; /* __hfs_iget() eats one */ + inode = hfs_iget(entry, HFS_CAP_RDIR, dentry); + goto done; + } else if (hfs_streq(&cname, DOT_FINDERINFO)) { + ++entry->count; /* __hfs_iget() eats one */ + inode = hfs_iget(entry, HFS_CAP_FDIR, dentry); + goto done; + } else if ((entry->cnid == htonl(HFS_ROOT_CNID)) && + hfs_streq(&cname, DOT_ROOTINFO)) { + ++entry->count; /* __hfs_iget() eats one */ + inode = hfs_iget(entry, HFS_CAP_FNDR, dentry); + goto done; + } + } + + /* Do an hfs_iget() on the mangled name. */ + hfs_cat_build_key(entry->cnid, &cname, &key); + inode = hfs_iget(hfs_cat_get(entry->mdb, &key), + HFS_I(dir)->file_type, dentry); + + /* Don't return a resource fork for a directory */ + if (inode && (dtype == HFS_CAP_RDIR) && + (HFS_I(inode)->entry->type == HFS_CDR_DIR)) { + inode = NULL; + } + +done: + d_add(dentry, inode); + return 0; +} + +/* + * cap_readdir() + * + * This is the readdir() entry in the file_operations structure for + * HFS directories in the CAP scheme. The purpose is to enumerate the + * entries in a directory, given the inode of the directory and a + * (struct file *), the 'f_pos' field of which indicates the location + * in the directory. The (struct file *) is updated so that the next + * call with the same 'dir' and 'filp' arguments will produce the next + * directory entry. The entries are returned in 'dirent', which is + * "filled-in" by calling filldir(). This allows the same readdir() + * function be used for different dirent formats. We try to read in + * as many entries as we can before filldir() refuses to take any more. + * + * XXX: In the future it may be a good idea to consider not generating + * metadata files for covered directories since the data doesn't + * correspond to the mounted directory. However this requires an + * iget() for every directory which could be considered an excessive + * amount of overhead. Since the inode for a mount point is always + * in-core this is another argument for a call to get an inode if it + * is in-core or NULL if it is not. + */ +static int cap_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + ino_t type; + int skip_dirs; + struct hfs_brec brec; + struct hfs_cat_entry *entry; + struct inode *dir = filp->f_dentry->d_inode; + + if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) { + return -EBADF; + } + + entry = HFS_I(dir)->entry; + type = HFS_ITYPE(dir->i_ino); + skip_dirs = (type == HFS_CAP_RDIR); + + if (filp->f_pos == 0) { + /* Entry 0 is for "." */ + if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) { + return 0; + } + filp->f_pos = 1; + } + + if (filp->f_pos == 1) { + /* Entry 1 is for ".." */ + hfs_u32 cnid; + + if (type == HFS_CAP_NDIR) { + cnid = hfs_get_nl(entry->key.ParID); + } else { + cnid = entry->cnid; + } + + if (filldir(dirent, DOT_DOT->Name, + DOT_DOT_LEN, 1, ntohl(cnid))) { + return 0; + } + filp->f_pos = 2; + } + + if (filp->f_pos < (dir->i_size - 3)) { + hfs_u32 cnid; + hfs_u8 type; + + if (hfs_cat_open(entry, &brec) || + hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) { + return 0; + } + while (filp->f_pos < (dir->i_size - 3)) { + if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) { + return 0; + } + if (!skip_dirs || (type != HFS_CDR_DIR)) { + ino_t ino; + unsigned int len; + unsigned char tmp_name[HFS_NAMEMAX]; + + ino = ntohl(cnid) | HFS_I(dir)->file_type; + len = hfs_namein(dir, tmp_name, + &((struct hfs_cat_key *)brec.key)->CName); + if (filldir(dirent, tmp_name, len, + filp->f_pos, ino)) { + hfs_cat_close(entry, &brec); + return 0; + } + } + ++filp->f_pos; + } + hfs_cat_close(entry, &brec); + } + + if (filp->f_pos == (dir->i_size - 3)) { + if ((entry->cnid == htonl(HFS_ROOT_CNID)) && + (type == HFS_CAP_NDIR)) { + /* In root dir last-2 entry is for ".rootinfo" */ + if (filldir(dirent, DOT_ROOTINFO->Name, + DOT_ROOTINFO_LEN, filp->f_pos, + ntohl(entry->cnid) | HFS_CAP_FNDR)) { + return 0; + } + } + ++filp->f_pos; + } + + if (filp->f_pos == (dir->i_size - 2)) { + if (type == HFS_CAP_NDIR) { + /* In normal dirs last-1 entry is for ".finderinfo" */ + if (filldir(dirent, DOT_FINDERINFO->Name, + DOT_FINDERINFO_LEN, filp->f_pos, + ntohl(entry->cnid) | HFS_CAP_FDIR)) { + return 0; + } + } + ++filp->f_pos; + } + + if (filp->f_pos == (dir->i_size - 1)) { + if (type == HFS_CAP_NDIR) { + /* In normal dirs last entry is for ".resource" */ + if (filldir(dirent, DOT_RESOURCE->Name, + DOT_RESOURCE_LEN, filp->f_pos, + ntohl(entry->cnid) | HFS_CAP_RDIR)) { + return 0; + } + } + ++filp->f_pos; + } + + return 0; +} + + +/* due to the dcache caching negative dentries for non-existent files, + * we need to drop those entries when a file silently gets created. + * as far as i can tell, the calls that need to do this are the file + * related calls (create, rename, and mknod). the directory calls + * should be immune. the relevant calls in dir.c call drop_dentry + * upon successful completion. */ +void hfs_cap_drop_dentry(const ino_t type, struct dentry *dentry) +{ + if (type == HFS_CAP_DATA) { /* given name */ + hfs_drop_special(DOT_FINDERINFO, dentry->d_parent, dentry); + hfs_drop_special(DOT_RESOURCE, dentry->d_parent, dentry); + } else { + struct dentry *de; + + /* look for name */ + if ((de = hfs_lookup_dentry(dentry->d_name.name, + dentry->d_name.len, + dentry->d_parent->d_parent))) { + if (!de->d_inode) + d_drop(de); + dput(de); + } + + switch (type) { + case HFS_CAP_RSRC: /* given .resource/name */ + /* look for .finderinfo/name */ + hfs_drop_special(DOT_FINDERINFO, dentry->d_parent->d_parent, + dentry); + break; + case HFS_CAP_FNDR: /* given .finderinfo/name. i don't this + * happens. */ + /* look for .resource/name */ + hfs_drop_special(DOT_RESOURCE, dentry->d_parent->d_parent, + dentry); + break; + } + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/dir_dbl.c linux/fs/hfs/dir_dbl.c --- v2.1.77/linux/fs/hfs/dir_dbl.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/dir_dbl.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,463 @@ +/* + * linux/fs/hfs/dir_dbl.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the inode_operations and file_operations + * structures for HFS directories. + * + * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ Forward declarations ================*/ + +static int dbl_lookup(struct inode *, struct dentry *); +static int dbl_readdir(struct file *, void *, filldir_t); +static int dbl_create(struct inode *, struct dentry *, int); +static int dbl_mkdir(struct inode *, struct dentry *, int); +static int dbl_mknod(struct inode *, struct dentry *, int, int); +static int dbl_unlink(struct inode *, struct dentry *); +static int dbl_rmdir(struct inode *, struct dentry *); +static int dbl_rename(struct inode *, struct dentry *, + struct inode *, struct dentry *); + +/*================ Global variables ================*/ + +#define DOT_LEN 1 +#define DOT_DOT_LEN 2 +#define ROOTINFO_LEN 8 +#define PCNT_ROOTINFO_LEN 9 + +const struct hfs_name hfs_dbl_reserved1[] = { + {DOT_LEN, "."}, + {DOT_DOT_LEN, ".."}, + {0, ""}, +}; + +const struct hfs_name hfs_dbl_reserved2[] = { + {ROOTINFO_LEN, "RootInfo"}, + {PCNT_ROOTINFO_LEN, "%RootInfo"}, + {0, ""}, +}; + +#define DOT (&hfs_dbl_reserved1[0]) +#define DOT_DOT (&hfs_dbl_reserved1[1]) +#define ROOTINFO (&hfs_dbl_reserved2[0]) +#define PCNT_ROOTINFO (&hfs_dbl_reserved2[1]) + +static struct file_operations hfs_dbl_dir_operations = { + NULL, /* lseek - default */ + hfs_dir_read, /* read - invalid */ + NULL, /* write - bad */ + dbl_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap - none */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync, /* fsync - default */ + NULL, /* fasync - default */ + NULL, /* check_media_change - none */ + NULL /* revalidate - none */ +}; + +struct inode_operations hfs_dbl_dir_inode_operations = { + &hfs_dbl_dir_operations,/* default directory file-ops */ + dbl_create, /* create */ + dbl_lookup, /* lookup */ + NULL, /* link */ + dbl_unlink, /* unlink */ + NULL, /* symlink */ + dbl_mkdir, /* mkdir */ + dbl_rmdir, /* rmdir */ + dbl_mknod, /* mknod */ + dbl_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + + +/*================ File-local functions ================*/ + +/* + * is_hdr() + */ +static int is_hdr(struct inode *dir, const char *name, int len) +{ + int retval = 0; + + if (name[0] == '%') { + struct hfs_cat_entry *entry = HFS_I(dir)->entry; + struct hfs_cat_entry *victim; + struct hfs_name cname; + struct hfs_cat_key key; + + hfs_nameout(dir, &cname, name+1, len-1); + hfs_cat_build_key(entry->cnid, &cname, &key); + if ((victim = hfs_cat_get(entry->mdb, &key))) { + hfs_cat_put(victim); + retval = 1; + } + } + return retval; +} + +/* + * dbl_lookup() + * + * This is the lookup() entry in the inode_operations structure for + * HFS directories in the AppleDouble scheme. The purpose is to + * generate the inode corresponding to an entry in a directory, given + * the inode for the directory and the name (and its length) of the + * entry. + */ +static int dbl_lookup(struct inode * dir, struct dentry *dentry) +{ + struct hfs_name cname; + struct hfs_cat_entry *entry; + struct hfs_cat_key key; + struct inode *inode = NULL; + + if (!dir || !S_ISDIR(dir->i_mode)) { + goto done; + } + + entry = HFS_I(dir)->entry; + + /* Perform name-mangling */ + hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len); + + /* Check for "." */ + if (hfs_streq(&cname, DOT)) { + /* this little trick skips the iget and iput */ + d_add(dentry, dir); + return 0; + } + + /* Check for "..". */ + if (hfs_streq(&cname, DOT_DOT)) { + inode = hfs_iget(hfs_cat_parent(entry), HFS_DBL_DIR, dentry); + goto done; + } + + /* Check for "%RootInfo" if in the root directory. */ + if ((entry->cnid == htonl(HFS_ROOT_CNID)) && + hfs_streq(&cname, PCNT_ROOTINFO)) { + ++entry->count; /* __hfs_iget() eats one */ + inode = hfs_iget(entry, HFS_DBL_HDR, dentry); + goto done; + } + + /* Do an hfs_iget() on the mangled name. */ + hfs_cat_build_key(entry->cnid, &cname, &key); + inode = hfs_iget(hfs_cat_get(entry->mdb, &key), HFS_DBL_NORM, dentry); + + /* Try as a header if not found and first character is '%' */ + if (!inode && (dentry->d_name.name[0] == '%')) { + hfs_nameout(dir, &cname, dentry->d_name.name+1, + dentry->d_name.len-1); + hfs_cat_build_key(entry->cnid, &cname, &key); + inode = hfs_iget(hfs_cat_get(entry->mdb, &key), + HFS_DBL_HDR, dentry); + } + +done: + d_add(dentry, inode); + return 0; +} + +/* + * dbl_readdir() + * + * This is the readdir() entry in the file_operations structure for + * HFS directories in the AppleDouble scheme. The purpose is to + * enumerate the entries in a directory, given the inode of the + * directory and a (struct file *), the 'f_pos' field of which + * indicates the location in the directory. The (struct file *) is + * updated so that the next call with the same 'dir' and 'filp' + * arguments will produce the next directory entry. The entries are + * returned in 'dirent', which is "filled-in" by calling filldir(). + * This allows the same readdir() function be used for different + * formats. We try to read in as many entries as we can before + * filldir() refuses to take any more. + * + * XXX: In the future it may be a good idea to consider not generating + * metadata files for covered directories since the data doesn't + * correspond to the mounted directory. However this requires an + * iget() for every directory which could be considered an excessive + * amount of overhead. Since the inode for a mount point is always + * in-core this is another argument for a call to get an inode if it + * is in-core or NULL if it is not. + */ +static int dbl_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + struct hfs_brec brec; + struct hfs_cat_entry *entry; + struct inode *dir = filp->f_dentry->d_inode; + + if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) { + return -EBADF; + } + + entry = HFS_I(dir)->entry; + + if (filp->f_pos == 0) { + /* Entry 0 is for "." */ + if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) { + return 0; + } + filp->f_pos = 1; + } + + if (filp->f_pos == 1) { + /* Entry 1 is for ".." */ + if (filldir(dirent, DOT_DOT->Name, DOT_DOT_LEN, 1, + hfs_get_hl(entry->key.ParID))) { + return 0; + } + filp->f_pos = 2; + } + + if (filp->f_pos < (dir->i_size - 1)) { + hfs_u32 cnid; + hfs_u8 type; + + if (hfs_cat_open(entry, &brec) || + hfs_cat_next(entry, &brec, (filp->f_pos - 1) >> 1, + &cnid, &type)) { + return 0; + } + + while (filp->f_pos < (dir->i_size - 1)) { + unsigned char tmp_name[HFS_NAMEMAX + 1]; + ino_t ino; + int is_hdr = (filp->f_pos & 1); + unsigned int len; + + if (is_hdr) { + ino = ntohl(cnid) | HFS_DBL_HDR; + tmp_name[0] = '%'; + len = 1 + hfs_namein(dir, tmp_name + 1, + &((struct hfs_cat_key *)brec.key)->CName); + } else { + if (hfs_cat_next(entry, &brec, 1, + &cnid, &type)) { + return 0; + } + ino = ntohl(cnid); + len = hfs_namein(dir, tmp_name, + &((struct hfs_cat_key *)brec.key)->CName); + } + + if (filldir(dirent, tmp_name, len, filp->f_pos, ino)) { + hfs_cat_close(entry, &brec); + return 0; + } + ++filp->f_pos; + } + hfs_cat_close(entry, &brec); + } + + if (filp->f_pos == (dir->i_size - 1)) { + if (entry->cnid == htonl(HFS_ROOT_CNID)) { + /* In root dir last entry is for "%RootInfo" */ + if (filldir(dirent, PCNT_ROOTINFO->Name, + PCNT_ROOTINFO_LEN, filp->f_pos, + ntohl(entry->cnid) | HFS_DBL_HDR)) { + return 0; + } + } + ++filp->f_pos; + } + + return 0; +} + +/* + * dbl_create() + * + * This is the create() entry in the inode_operations structure for + * AppleDouble directories. The purpose is to create a new file in + * a directory and return a corresponding inode, given the inode for + * the directory and the name (and its length) of the new file. + */ +static int dbl_create(struct inode * dir, struct dentry *dentry, + int mode) +{ + int error; + + if (is_hdr(dir, dentry->d_name.name, dentry->d_name.len)) { + error = -EEXIST; + } else { + error = hfs_create(dir, dentry, mode); + } + return error; +} + +/* + * dbl_mkdir() + * + * This is the mkdir() entry in the inode_operations structure for + * AppleDouble directories. The purpose is to create a new directory + * in a directory, given the inode for the parent directory and the + * name (and its length) of the new directory. + */ +static int dbl_mkdir(struct inode * parent, struct dentry *dentry, + int mode) +{ + int error; + + if (is_hdr(parent, dentry->d_name.name, dentry->d_name.len)) { + error = -EEXIST; + } else { + error = hfs_mkdir(parent, dentry, mode); + } + return error; +} + +/* + * dbl_mknod() + * + * This is the mknod() entry in the inode_operations structure for + * regular HFS directories. The purpose is to create a new entry + * in a directory, given the inode for the parent directory and the + * name (and its length) and the mode of the new entry (and the device + * number if the entry is to be a device special file). + */ +static int dbl_mknod(struct inode *dir, struct dentry *dentry, + int mode, int rdev) +{ + int error; + + if (is_hdr(dir, dentry->d_name.name, dentry->d_name.len)) { + error = -EEXIST; + } else { + error = hfs_mknod(dir, dentry, mode, rdev); + } + return error; +} + +/* + * dbl_unlink() + * + * This is the unlink() entry in the inode_operations structure for + * AppleDouble directories. The purpose is to delete an existing + * file, given the inode for the parent directory and the name + * (and its length) of the existing file. + */ +static int dbl_unlink(struct inode * dir, struct dentry *dentry) +{ + int error; + + error = hfs_unlink(dir, dentry); + if ((error == -ENOENT) && is_hdr(dir, dentry->d_name.name, + dentry->d_name.len)) { + error = -EPERM; + } + return error; +} + +/* + * dbl_rmdir() + * + * This is the rmdir() entry in the inode_operations structure for + * AppleDouble directories. The purpose is to delete an existing + * directory, given the inode for the parent directory and the name + * (and its length) of the existing directory. + */ +static int dbl_rmdir(struct inode * parent, struct dentry *dentry) +{ + int error; + + error = hfs_rmdir(parent, dentry); + if ((error == -ENOENT) && is_hdr(parent, dentry->d_name.name, + dentry->d_name.len)) { + error = -ENOTDIR; + } + return error; +} + +/* + * dbl_rename() + * + * This is the rename() entry in the inode_operations structure for + * AppleDouble directories. The purpose is to rename an existing + * file or directory, given the inode for the current directory and + * the name (and its length) of the existing file/directory and the + * inode for the new directory and the name (and its length) of the + * new file/directory. + * + * XXX: how do we handle must_be_dir? + */ +static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + int error; + + if (is_hdr(new_dir, new_dentry->d_name.name, + new_dentry->d_name.len)) { + error = -EPERM; + } else { + error = hfs_rename(old_dir, old_dentry, + new_dir, new_dentry); + if ((error == -ENOENT) /*&& !must_be_dir*/ && + is_hdr(old_dir, old_dentry->d_name.name, + old_dentry->d_name.len)) { + error = -EPERM; + } + } + return error; +} + + +/* due to the dcache caching negative dentries for non-existent files, + * we need to drop those entries when a file silently gets created. + * as far as i can tell, the calls that need to do this are the file + * related calls (create, rename, and mknod). the directory calls + * should be immune. the relevant calls in dir.c call drop_dentry + * upon successful completion. this allocates an array for %name + * on the first attempt to access it. */ +void hfs_dbl_drop_dentry(const ino_t type, struct dentry *dentry) +{ + unsigned char tmp_name[HFS_NAMEMAX + 1]; + struct dentry *de = NULL; + + switch (type) { + case HFS_DBL_HDR: + /* given %name, look for name. i don't think this happens. */ + de = hfs_lookup_dentry(dentry->d_name.name + 1, dentry->d_name.len - 1, + dentry->d_parent); + break; + case HFS_DBL_DATA: + /* given name, look for %name */ + tmp_name[0] = '%'; + strncpy(tmp_name + 1, dentry->d_name.name, HFS_NAMELEN - 1); + de = hfs_lookup_dentry(tmp_name, dentry->d_name.len + 1, + dentry->d_parent); + } + + if (de) { + if (!de->d_inode) + d_drop(de); + dput(de); + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/dir_nat.c linux/fs/hfs/dir_nat.c --- v2.1.77/linux/fs/hfs/dir_nat.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/dir_nat.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,486 @@ +/* + * linux/fs/hfs/dir_nat.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the inode_operations and file_operations + * structures for HFS directories. + * + * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds + * + * The source code distributions of Netatalk, versions 1.3.3b2 and + * 1.4b2, were used as a specification of the location and format of + * files used by Netatalk's afpd. No code from Netatalk appears in + * hfs_fs. hfs_fs is not a work ``derived'' from Netatalk in the + * sense of intellectual property law. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ Forward declarations ================*/ + +static int nat_lookup(struct inode *, struct dentry *); +static int nat_readdir(struct file *, void *, filldir_t); +static int nat_rmdir(struct inode *, struct dentry *); +static int nat_hdr_unlink(struct inode *, struct dentry *); +static int nat_hdr_rename(struct inode *, struct dentry *, + struct inode *, struct dentry *); + +/*================ Global variables ================*/ + +#define DOT_LEN 1 +#define DOT_DOT_LEN 2 +#define DOT_APPLEDOUBLE_LEN 12 +#define DOT_PARENT_LEN 7 + +const struct hfs_name hfs_nat_reserved1[] = { + {DOT_LEN, "."}, + {DOT_DOT_LEN, ".."}, + {DOT_APPLEDOUBLE_LEN, ".AppleDouble"}, + {DOT_PARENT_LEN, ".Parent"}, + {0, ""}, +}; + +const struct hfs_name hfs_nat_reserved2[] = { + {0, ""}, +}; + +#define DOT (&hfs_nat_reserved1[0]) +#define DOT_DOT (&hfs_nat_reserved1[1]) +#define DOT_APPLEDOUBLE (&hfs_nat_reserved1[2]) +#define DOT_PARENT (&hfs_nat_reserved1[3]) + +static struct file_operations hfs_nat_dir_operations = { + NULL, /* lseek - default */ + hfs_dir_read, /* read - invalid */ + NULL, /* write - bad */ + nat_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap - none */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync, /* fsync - default */ + NULL, /* fasync - default */ + NULL, /* check_media_change - none */ + NULL, /* revalidate - none */ + NULL /* lock - none */ +}; + +struct inode_operations hfs_nat_ndir_inode_operations = { + &hfs_nat_dir_operations,/* default directory file-ops */ + hfs_create, /* create */ + nat_lookup, /* lookup */ + NULL, /* link */ + hfs_unlink, /* unlink */ + NULL, /* symlink */ + hfs_mkdir, /* mkdir */ + nat_rmdir, /* rmdir */ + hfs_mknod, /* mknod */ + hfs_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ +}; + +struct inode_operations hfs_nat_hdir_inode_operations = { + &hfs_nat_dir_operations,/* default directory file-ops */ + hfs_create, /* create */ + nat_lookup, /* lookup */ + NULL, /* link */ + nat_hdr_unlink, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + nat_hdr_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ +}; + +/*================ File-local functions ================*/ + +/* + * nat_lookup() + * + * This is the lookup() entry in the inode_operations structure for + * HFS directories in the Netatalk scheme. The purpose is to generate + * the inode corresponding to an entry in a directory, given the inode + * for the directory and the name (and its length) of the entry. + */ +static int nat_lookup(struct inode * dir, struct dentry *dentry) +{ + ino_t dtype; + struct hfs_name cname; + struct hfs_cat_entry *entry; + struct hfs_cat_key key; + struct inode *inode = NULL; + + if (!dir || !S_ISDIR(dir->i_mode)) { + goto done; + } + + entry = HFS_I(dir)->entry; + dtype = HFS_ITYPE(dir->i_ino); + + /* Perform name-mangling */ + hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len); + + /* Check for "." */ + if (hfs_streq(&cname, DOT)) { + /* this little trick skips the iget and iput */ + d_add(dentry, dir); + return 0; + } + + /* Check for "..". */ + if (hfs_streq(&cname, DOT_DOT)) { + struct hfs_cat_entry *parent; + + if (dtype != HFS_NAT_NDIR) { + /* Case for ".." in ".AppleDouble" */ + parent = entry; + ++entry->count; /* __hfs_iget() eats one */ + } else { + /* Case for ".." in a normal directory */ + parent = hfs_cat_parent(entry); + } + inode = hfs_iget(parent, HFS_NAT_NDIR, dentry); + goto done; + } + + /* Check for ".AppleDouble" if in a normal directory, + and for ".Parent" in ".AppleDouble". */ + if (dtype==HFS_NAT_NDIR) { + /* Check for ".AppleDouble" */ + if (hfs_streq(&cname, DOT_APPLEDOUBLE)) { + ++entry->count; /* __hfs_iget() eats one */ + inode = hfs_iget(entry, HFS_NAT_HDIR, dentry); + goto done; + } + } else if (dtype==HFS_NAT_HDIR) { + if (hfs_streq(&cname, DOT_PARENT)) { + ++entry->count; /* __hfs_iget() eats one */ + inode = hfs_iget(entry, HFS_NAT_HDR, dentry); + goto done; + } + } + + /* Do an hfs_iget() on the mangled name. */ + hfs_cat_build_key(entry->cnid, &cname, &key); + inode = hfs_iget(hfs_cat_get(entry->mdb, &key), + HFS_I(dir)->file_type, dentry); + + /* Don't return a header file for a directory other than .Parent */ + if (inode && (dtype == HFS_NAT_HDIR) && + (HFS_I(inode)->entry != entry) && + (HFS_I(inode)->entry->type == HFS_CDR_DIR)) { + iput(inode); + inode = NULL; + } + +done: + d_add(dentry, inode); + return 0; +} + +/* + * nat_readdir() + * + * This is the readdir() entry in the file_operations structure for + * HFS directories in the netatalk scheme. The purpose is to + * enumerate the entries in a directory, given the inode of the + * directory and a struct file which indicates the location in the + * directory. The struct file is updated so that the next call with + * the same dir and filp will produce the next directory entry. The + * entries are returned in dirent, which is "filled-in" by calling + * filldir(). This allows the same readdir() function be used for + * different dirent formats. We try to read in as many entries as we + * can before filldir() refuses to take any more. + * + * Note that the Netatalk format doesn't have the problem with + * metadata for covered directories that exists in the other formats, + * since the metadata is contained within the directory. + */ +static int nat_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + ino_t type; + int skip_dirs; + struct hfs_brec brec; + struct hfs_cat_entry *entry; + struct inode *dir = filp->f_dentry->d_inode; + + if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) { + return -EBADF; + } + + entry = HFS_I(dir)->entry; + type = HFS_ITYPE(dir->i_ino); + skip_dirs = (type == HFS_NAT_HDIR); + + if (filp->f_pos == 0) { + /* Entry 0 is for "." */ + if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) { + return 0; + } + filp->f_pos = 1; + } + + if (filp->f_pos == 1) { + /* Entry 1 is for ".." */ + hfs_u32 cnid; + + if (type == HFS_NAT_NDIR) { + cnid = hfs_get_nl(entry->key.ParID); + } else { + cnid = entry->cnid; + } + + if (filldir(dirent, DOT_DOT->Name, + DOT_DOT_LEN, 1, ntohl(cnid))) { + return 0; + } + filp->f_pos = 2; + } + + if (filp->f_pos < (dir->i_size - 1)) { + hfs_u32 cnid; + hfs_u8 type; + + if (hfs_cat_open(entry, &brec) || + hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) { + return 0; + } + while (filp->f_pos < (dir->i_size - 1)) { + if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) { + return 0; + } + if (!skip_dirs || (type != HFS_CDR_DIR)) { + ino_t ino; + unsigned int len; + unsigned char tmp_name[HFS_NAMEMAX]; + + ino = ntohl(cnid) | HFS_I(dir)->file_type; + len = hfs_namein(dir, tmp_name, + &((struct hfs_cat_key *)brec.key)->CName); + if (filldir(dirent, tmp_name, len, + filp->f_pos, ino)) { + hfs_cat_close(entry, &brec); + return 0; + } + } + ++filp->f_pos; + } + hfs_cat_close(entry, &brec); + } + + if (filp->f_pos == (dir->i_size - 1)) { + if (type == HFS_NAT_NDIR) { + /* In normal dirs entry 2 is for ".AppleDouble" */ + if (filldir(dirent, DOT_APPLEDOUBLE->Name, + DOT_APPLEDOUBLE_LEN, filp->f_pos, + ntohl(entry->cnid) | HFS_NAT_HDIR)) { + return 0; + } + } else if (type == HFS_NAT_HDIR) { + /* In .AppleDouble entry 2 is for ".Parent" */ + if (filldir(dirent, DOT_PARENT->Name, + DOT_PARENT_LEN, filp->f_pos, + ntohl(entry->cnid) | HFS_NAT_HDR)) { + return 0; + } + } + ++filp->f_pos; + } + + return 0; +} + +/* due to the dcache caching negative dentries for non-existent files, + * we need to drop those entries when a file silently gets created. + * as far as i can tell, the calls that need to do this are the file + * related calls (create, rename, and mknod). the directory calls + * should be immune. the relevant calls in dir.c call drop_dentry + * upon successful completion. */ +void hfs_nat_drop_dentry(const ino_t type, struct dentry *dentry) +{ + struct dentry *de; + + switch (type) { + case HFS_NAT_HDR: /* given .AppleDouble/name */ + /* look for name */ + de = hfs_lookup_dentry(dentry->d_name.name, + dentry->d_name.len, + dentry->d_parent->d_parent); + if (de) { + if (!de->d_inode) + d_drop(de); + dput(de); + } + break; + case HFS_NAT_DATA: /* given name */ + /* look for .AppleDouble/name */ + hfs_drop_special(DOT_APPLEDOUBLE, dentry->d_parent, dentry); + break; + } +} + +/* + * nat_rmdir() + * + * This is the rmdir() entry in the inode_operations structure for + * Netatalk directories. The purpose is to delete an existing + * directory, given the inode for the parent directory and the name + * (and its length) of the existing directory. + * + * We handle .AppleDouble and call hfs_rmdir() for all other cases. + */ +static int nat_rmdir(struct inode *parent, struct dentry *dentry) +{ + struct hfs_cat_entry *entry = HFS_I(parent)->entry; + struct hfs_name cname; + int error; + + hfs_nameout(parent, &cname, dentry->d_name.name, dentry->d_name.len); + if (hfs_streq(&cname, DOT_APPLEDOUBLE)) { + if (!HFS_SB(parent->i_sb)->s_afpd) { + /* Not in AFPD compatibility mode */ + error = -EPERM; + } else if (entry->u.dir.files || entry->u.dir.dirs) { + /* AFPD compatible, but the directory is not empty */ + error = -ENOTEMPTY; + } else { + /* AFPD compatible, so pretend to succeed */ + error = 0; + } + } else { + error = hfs_rmdir(parent, dentry); + } + return error; +} + +/* + * nat_hdr_unlink() + * + * This is the unlink() entry in the inode_operations structure for + * Netatalk .AppleDouble directories. The purpose is to delete an + * existing file, given the inode for the parent directory and the name + * (and its length) of the existing file. + * + * WE DON'T ACTUALLY DELETE HEADER THE FILE. + * In non-afpd-compatible mode: + * We return -EPERM. + * In afpd-compatible mode: + * We return success if the file exists or is .Parent. + * Otherwise we return -ENOENT. + */ +static int nat_hdr_unlink(struct inode *dir, struct dentry *dentry) +{ + struct hfs_cat_entry *entry = HFS_I(dir)->entry; + int error = 0; + + if (!HFS_SB(dir->i_sb)->s_afpd) { + /* Not in AFPD compatibility mode */ + error = -EPERM; + } else { + struct hfs_name cname; + + hfs_nameout(dir, &cname, dentry->d_name.name, + dentry->d_name.len); + if (!hfs_streq(&cname, DOT_PARENT)) { + struct hfs_cat_entry *victim; + struct hfs_cat_key key; + + hfs_cat_build_key(entry->cnid, &cname, &key); + victim = hfs_cat_get(entry->mdb, &key); + + if (victim) { + /* pretend to succeed */ + hfs_cat_put(victim); + } else { + error = -ENOENT; + } + } + } + return error; +} + +/* + * nat_hdr_rename() + * + * This is the rename() entry in the inode_operations structure for + * Netatalk header directories. The purpose is to rename an existing + * file given the inode for the current directory and the name + * (and its length) of the existing file and the inode for the new + * directory and the name (and its length) of the new file/directory. + * + * WE NEVER MOVE ANYTHING. + * In non-afpd-compatible mode: + * We return -EPERM. + * In afpd-compatible mode: + * If the source header doesn't exist, we return -ENOENT. + * If the destination is not a header directory we return -EPERM. + * We return success if the destination is also a header directory + * and the header exists or is ".Parent". + */ +static int nat_hdr_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct hfs_cat_entry *entry = HFS_I(old_dir)->entry; + int error = 0; + + if (!HFS_SB(old_dir->i_sb)->s_afpd) { + /* Not in AFPD compatibility mode */ + error = -EPERM; + } else { + struct hfs_name cname; + + hfs_nameout(old_dir, &cname, old_dentry->d_name.name, + old_dentry->d_name.len); + if (!hfs_streq(&cname, DOT_PARENT)) { + struct hfs_cat_entry *victim; + struct hfs_cat_key key; + + hfs_cat_build_key(entry->cnid, &cname, &key); + victim = hfs_cat_get(entry->mdb, &key); + + if (victim) { + /* pretend to succeed */ + hfs_cat_put(victim); + } else { + error = -ENOENT; + } + } + + if (!error && (HFS_ITYPE(new_dir->i_ino) != HFS_NAT_HDIR)) { + error = -EPERM; + } + } + return error; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/extent.c linux/fs/hfs/extent.c --- v2.1.77/linux/fs/hfs/extent.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/extent.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,811 @@ +/* + * linux/fs/hfs/extent.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the functions related to the extents B-tree. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" + +/*================ File-local data type ================*/ + +/* An extent record on disk*/ +struct hfs_raw_extent { + hfs_word_t block1; + hfs_word_t length1; + hfs_word_t block2; + hfs_word_t length2; + hfs_word_t block3; + hfs_word_t length3; +}; + +/*================ File-local functions ================*/ + +/* + * build_key + */ +static inline void build_key(struct hfs_ext_key *key, + const struct hfs_fork *fork, hfs_u16 block) +{ + key->KeyLen = 7; + key->FkType = fork->fork; + hfs_put_nl(fork->entry->cnid, key->FNum); + hfs_put_hs(block, key->FABN); +} + + +/* + * lock_bitmap() + * + * Get an exclusive lock on the B-tree bitmap. + */ +static inline void lock_bitmap(struct hfs_mdb *mdb) { + while (mdb->bitmap_lock) { + hfs_sleep_on(&mdb->bitmap_wait); + } + mdb->bitmap_lock = 1; +} + +/* + * unlock_bitmap() + * + * Relinquish an exclusive lock on the B-tree bitmap. + */ +static inline void unlock_bitmap(struct hfs_mdb *mdb) { + mdb->bitmap_lock = 0; + hfs_wake_up(&mdb->bitmap_wait); +} + +/* + * dump_ext() + * + * prints the content of a extent for debugging purposes. + */ +#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL) +static void dump_ext(const char *msg, const struct hfs_extent *e) { + if (e) { + hfs_warn("%s (%d-%d) (%d-%d) (%d-%d)\n", msg, + e->start, + e->start + e->length[0] - 1, + e->start + e->length[0], + e->start + e->length[0] + e->length[1] - 1, + e->start + e->length[0] + e->length[1], + e->end); + } else { + hfs_warn("%s NULL\n", msg); + } +} +#else +#define dump_ext(A,B) {} +#endif + +/* + * read_extent() + * + * Initializes a (struct hfs_extent) from a (struct hfs_raw_extent) and + * the number of the starting block for the extent. + * + * Note that the callers must check that to,from != NULL + */ +static void read_extent(struct hfs_extent *to, + const struct hfs_raw_extent *from, + hfs_u16 start) +{ + to->start = start; + to->block[0] = hfs_get_hs(from->block1); + to->length[0] = hfs_get_hs(from->length1); + to->block[1] = hfs_get_hs(from->block2); + to->length[1] = hfs_get_hs(from->length2); + to->block[2] = hfs_get_hs(from->block3); + to->length[2] = hfs_get_hs(from->length3); + to->end = start + to->length[0] + to->length[1] + to->length[2] - 1; + to->next = to->prev = NULL; + to->count = 0; +} + +/* + * write_extent() + * + * Initializes a (struct hfs_raw_extent) from a (struct hfs_extent). + * + * Note that the callers must check that to,from != NULL + */ +static void write_extent(struct hfs_raw_extent *to, + const struct hfs_extent *from) +{ + hfs_put_hs(from->block[0], to->block1); + hfs_put_hs(from->length[0], to->length1); + hfs_put_hs(from->block[1], to->block2); + hfs_put_hs(from->length[1], to->length2); + hfs_put_hs(from->block[2], to->block3); + hfs_put_hs(from->length[2], to->length3); +} + +/* + * decode_extent() + * + * Given an extent record and allocation block offset into the file, + * return the number of the corresponding allocation block on disk, + * or -1 if the desired block is not mapped by the given extent. + * + * Note that callers must check that extent != NULL + */ +static int decode_extent(const struct hfs_extent * extent, int block) +{ + if (!extent || (block < extent->start) || (block > extent->end) || + (extent->end == (hfs_u16)(extent->start - 1))) { + return -1; + } + block -= extent->start; + if (block < extent->length[0]) { + return block + extent->block[0]; + } + block -= extent->length[0]; + if (block < extent->length[1]) { + return block + extent->block[1]; + } + return block + extent->block[2] - extent->length[1]; +} + +/* + * relse_ext() + * + * Reduce the reference count of an in-core extent record by one, + * removing it from memory if the count falls to zero. + */ +static void relse_ext(struct hfs_extent *ext) +{ + if (--ext->count || !ext->start) { + return; + } + ext->prev->next = ext->next; + if (ext->next) { + ext->next->prev = ext->prev; + } + HFS_DELETE(ext); +} + +/* + * set_cache() + * + * Changes the 'cache' field of the fork. + */ +static inline void set_cache(struct hfs_fork *fork, struct hfs_extent *ext) +{ + struct hfs_extent *tmp = fork->cache; + + ++ext->count; + fork->cache = ext; + relse_ext(tmp); +} + +/* + * find_ext() + * + * Given a pointer to a (struct hfs_file) and an allocation block + * number in the file, find the extent record containing that block. + * Returns a pointer to the extent record on success or NULL on failure. + * The 'cache' field of 'fil' also points to the extent so it has a + * reference count of at least 2. + * + * Callers must check that fil != NULL + */ +static struct hfs_extent * find_ext(struct hfs_fork *fork, int alloc_block) +{ + struct hfs_cat_entry *entry = fork->entry; + struct hfs_btree *tr= entry->mdb->ext_tree; + struct hfs_ext_key target, *key; + struct hfs_brec brec; + struct hfs_extent *ext, *ptr; + int tmp; + + if (alloc_block < 0) { + ext = &fork->first; + goto found; + } + + ext = fork->cache; + if (!ext || (alloc_block < ext->start)) { + ext = &fork->first; + } + while (ext->next && (alloc_block > ext->end)) { + ext = ext->next; + } + if ((alloc_block <= ext->end) && (alloc_block >= ext->start)) { + goto found; + } + + /* time to read more extents */ + if (!HFS_NEW(ext)) { + goto bail3; + } + + build_key(&target, fork, alloc_block); + + tmp = hfs_bfind(&brec, tr, HFS_BKEY(&target), HFS_BFIND_READ_LE); + if (tmp < 0) { + goto bail2; + } + + key = (struct hfs_ext_key *)brec.key; + if ((hfs_get_nl(key->FNum) != hfs_get_nl(target.FNum)) || + (key->FkType != fork->fork)) { + goto bail1; + } + + read_extent(ext, brec.data, hfs_get_hs(key->FABN)); + hfs_brec_relse(&brec, NULL); + + if ((alloc_block > ext->end) && (alloc_block < ext->start)) { + /* something strange happened */ + goto bail2; + } + + ptr = fork->cache; + if (!ptr || (alloc_block < ptr->start)) { + ptr = &fork->first; + } + while (ptr->next && (alloc_block > ptr->end)) { + ptr = ptr->next; + } + if (ext->start == ptr->start) { + /* somebody beat us to it. */ + HFS_DELETE(ext); + ext = ptr; + } else if (ext->start < ptr->start) { + /* insert just before ptr */ + ptr->prev->next = ext; + ext->prev = ptr->prev; + ext->next = ptr; + ptr->prev = ext; + } else { + /* insert at end */ + ptr->next = ext; + ext->prev = ptr; + } + found: + ++ext->count; /* for return value */ + set_cache(fork, ext); + return ext; + + bail1: + hfs_brec_relse(&brec, NULL); + bail2: + HFS_DELETE(ext); + bail3: + return NULL; +} + +/* + * delete_extent() + * + * Description: + * Deletes an extent record from a fork, reducing its physical length. + * Input Variable(s): + * struct hfs_fork *fork: the fork + * struct hfs_extent *ext: the current last extent for 'fork' + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'fork' points to a valid (struct hfs_fork) + * 'ext' point to a valid (struct hfs_extent) which is the last in 'fork' + * and which is not also the first extent in 'fork'. + * Postconditions: + * The extent record has been removed if possible, and a warning has been + * printed otherwise. + */ +static void delete_extent(struct hfs_fork *fork, struct hfs_extent *ext) +{ + struct hfs_mdb *mdb = fork->entry->mdb; + struct hfs_ext_key key; + int error; + + if (fork->cache == ext) { + set_cache(fork, ext->prev); + } + ext->prev->next = NULL; + if (ext->count != 1) { + hfs_warn("hfs_truncate: extent has count %d.\n", ext->count); + } + + lock_bitmap(mdb); + error = hfs_clear_vbm_bits(mdb, ext->block[2], ext->length[2]); + if (error) { + hfs_warn("hfs_truncate: error %d freeing blocks.\n", error); + } + error = hfs_clear_vbm_bits(mdb, ext->block[1], ext->length[1]); + if (error) { + hfs_warn("hfs_truncate: error %d freeing blocks.\n", error); + } + error = hfs_clear_vbm_bits(mdb, ext->block[0], ext->length[0]); + if (error) { + hfs_warn("hfs_truncate: error %d freeing blocks.\n", error); + } + unlock_bitmap(mdb); + + build_key(&key, fork, ext->start); + + error = hfs_bdelete(mdb->ext_tree, HFS_BKEY(&key)); + if (error) { + hfs_warn("hfs_truncate: error %d deleting an extent.\n", error); + } + HFS_DELETE(ext); +} + +/* + * new_extent() + * + * Description: + * Adds a new extent record to a fork, extending its physical length. + * Input Variable(s): + * struct hfs_fork *fork: the fork to extend + * struct hfs_extent *ext: the current last extent for 'fork' + * hfs_u16 ablock: the number of allocation blocks in 'fork'. + * hfs_u16 start: first allocation block to add to 'fork'. + * hfs_u16 len: the number of allocation blocks to add to 'fork'. + * hfs_u16 ablksz: number of sectors in an allocation block. + * Output Variable(s): + * NONE + * Returns: + * (struct hfs_extent *) the new extent or NULL + * Preconditions: + * 'fork' points to a valid (struct hfs_fork) + * 'ext' point to a valid (struct hfs_extent) which is the last in 'fork' + * 'ablock', 'start', 'len' and 'ablksz' are what they claim to be. + * Postconditions: + * If NULL is returned then no changes have been made to 'fork'. + * If the return value is non-NULL that it is the extent that has been + * added to 'fork' both in memory and on disk. The 'psize' field of + * 'fork' has been updated to reflect the new physical size. + */ +static struct hfs_extent *new_extent(struct hfs_fork *fork, + struct hfs_extent *ext, + hfs_u16 ablock, hfs_u16 start, + hfs_u16 len, hfs_u16 ablksz) +{ + struct hfs_raw_extent raw; + struct hfs_ext_key key; + int error; + + if (fork->entry->cnid == htonl(HFS_EXT_CNID)) { + /* Limit extents tree to the record in the MDB */ + return NULL; + } + + if (!HFS_NEW(ext->next)) { + return NULL; + } + ext->next->prev = ext; + ext->next->next = NULL; + ext = ext->next; + relse_ext(ext->prev); + + ext->start = ablock; + ext->block[0] = start; + ext->length[0] = len; + ext->block[1] = 0; + ext->length[1] = 0; + ext->block[2] = 0; + ext->length[2] = 0; + ext->end = ablock + len - 1; + ext->count = 1; + + write_extent(&raw, ext); + + build_key(&key, fork, ablock); + + error = hfs_binsert(fork->entry->mdb->ext_tree, + HFS_BKEY(&key), &raw, sizeof(raw)); + if (error) { + ext->prev->next = NULL; + HFS_DELETE(ext); + return NULL; + } + set_cache(fork, ext); + return ext; +} + +/* + * update_ext() + * + * Given a (struct hfs_fork) write an extent record back to disk. + */ +static void update_ext(struct hfs_fork *fork, struct hfs_extent *ext) +{ + struct hfs_ext_key target; + struct hfs_brec brec; + + if (ext->start) { + build_key(&target, fork, ext->start); + + if (!hfs_bfind(&brec, fork->entry->mdb->ext_tree, + HFS_BKEY(&target), HFS_BFIND_WRITE)) { + write_extent(brec.data, ext); + hfs_brec_relse(&brec, NULL); + } + } +} + +/* + * zero_blocks() + * + * Zeros-out 'num' allocation blocks beginning with 'start'. + */ +static int zero_blocks(struct hfs_mdb *mdb, int start, int num) { + hfs_buffer buf; + int end; + int j; + + start = mdb->fs_start + start * mdb->alloc_blksz; + end = start + num * mdb->alloc_blksz; + + for (j=start; jsys_mdb, j, 0))) { + memset(hfs_buffer_data(buf), 0, HFS_SECTOR_SIZE); + hfs_buffer_dirty(buf); + hfs_buffer_put(buf); + } + } + return 0; +} + +/* + * shrink_fork() + * + * Try to remove enough allocation blocks from 'fork' + * so that it is 'ablocks' allocation blocks long. + */ +static void shrink_fork(struct hfs_fork *fork, int ablocks) +{ + struct hfs_mdb *mdb = fork->entry->mdb; + struct hfs_extent *ext; + int i, error, next, count; + hfs_u16 ablksz = mdb->alloc_blksz; + + next = (fork->psize / ablksz) - 1; + ext = find_ext(fork, next); + while (ext && ext->start && (ext->start >= ablocks)) { + next = ext->start - 1; + delete_extent(fork, ext); + ext = find_ext(fork, next); + } + if (!ext) { + fork->psize = (next + 1) * ablksz; + return; + } + + if ((count = next + 1 - ablocks) > 0) { + for (i=2; (i>=0) && !ext->length[i]; --i) {}; + while (count && (ext->length[i] <= count)) { + ext->end -= ext->length[i]; + count -= ext->length[i]; + error = hfs_clear_vbm_bits(mdb, ext->block[i], + ext->length[i]); + if (error) { + hfs_warn("hfs_truncate: error %d freeing " + "blocks.\n", error); + } + ext->block[i] = ext->length[i] = 0; + --i; + } + if (count) { + ext->end -= count; + ext->length[i] -= count; + error = hfs_clear_vbm_bits(mdb, ext->block[i] + + ext->length[i], count); + if (error) { + hfs_warn("hfs_truncate: error %d freeing " + "blocks.\n", error); + } + } + update_ext(fork, ext); + } + + fork->psize = ablocks * ablksz; +} + +/* + * grow_fork() + * + * Try to add enough allocation blocks to 'fork' + * so that it is 'ablock' allocation blocks long. + */ +static void grow_fork(struct hfs_fork *fork, int ablocks) +{ + struct hfs_cat_entry *entry = fork->entry; + struct hfs_mdb *mdb = entry->mdb; + struct hfs_extent *ext; + int i, start, err; + hfs_u16 need, len=0; + hfs_u16 ablksz = mdb->alloc_blksz; + hfs_u32 blocks, clumpablks; + + blocks = fork->psize; + need = ablocks - blocks/ablksz; + if (need < 1) { + return; + } + + /* round up to clumpsize */ + if (entry->u.file.clumpablks) { + clumpablks = entry->u.file.clumpablks; + } else { + clumpablks = mdb->clumpablks; + } + need = ((need + clumpablks - 1) / clumpablks) * clumpablks; + + /* find last extent record and try to extend it */ + if (!(ext = find_ext(fork, blocks/ablksz - 1))) { + /* somehow we couldn't find the end of the file! */ + return; + } + + /* determine which is the last used extent in the record */ + /* then try to allocate the blocks immediately following it */ + for (i=2; (i>=0) && !ext->length[i]; --i) {}; + if (i>=0) { + /* try to extend the last extent */ + start = ext->block[i] + ext->length[i]; + + err = 0; + lock_bitmap(mdb); + len = hfs_vbm_count_free(mdb, start); + if (!len) { + unlock_bitmap(mdb); + goto more_extents; + } + if (need < len) { + len = need; + } + err = hfs_set_vbm_bits(mdb, start, len); + unlock_bitmap(mdb); + if (err) { + relse_ext(ext); + return; + } + + zero_blocks(mdb, start, len); + + ext->length[i] += len; + ext->end += len; + blocks = (fork->psize += len * ablksz); + need -= len; + update_ext(fork, ext); + } + +more_extents: + /* add some more extents */ + while (need) { + len = need; + err = 0; + lock_bitmap(mdb); + start = hfs_vbm_search_free(mdb, &len); + if (need < len) { + len = need; + } + err = hfs_set_vbm_bits(mdb, start, len); + unlock_bitmap(mdb); + if (!len || err) { + relse_ext(ext); + return; + } + zero_blocks(mdb, start, len); + + /* determine which is the first free extent in the record */ + for (i=0; (i<3) && ext->length[i]; ++i) {}; + if (i < 3) { + ext->block[i] = start; + ext->length[i] = len; + ext->end += len; + update_ext(fork, ext); + } else { + if (!(ext = new_extent(fork, ext, blocks/ablksz, + start, len, ablksz))) { + hfs_clear_vbm_bits(mdb, start, len); + return; + } + } + blocks = (fork->psize += len * ablksz); + need -= len; + } + set_cache(fork, ext); + relse_ext(ext); + return; +} + +/*================ Global functions ================*/ + +/* + * hfs_ext_compare() + * + * Description: + * This is the comparison function used for the extents B-tree. In + * comparing extent B-tree entries, the file id is the most + * significant field (compared as unsigned ints); the fork type is + * the second most significant field (compared as unsigned chars); + * and the allocation block number field is the least significant + * (compared as unsigned ints). + * Input Variable(s): + * struct hfs_ext_key *key1: pointer to the first key to compare + * struct hfs_ext_key *key2: pointer to the second key to compare + * Output Variable(s): + * NONE + * Returns: + * int: negative if key1key2, and 0 if key1==key2 + * Preconditions: + * key1 and key2 point to "valid" (struct hfs_ext_key)s. + * Postconditions: + * This function has no side-effects */ +int hfs_ext_compare(const struct hfs_ext_key *key1, + const struct hfs_ext_key *key2) +{ + unsigned int tmp; + int retval; + + tmp = hfs_get_hl(key1->FNum) - hfs_get_hl(key2->FNum); + if (tmp != 0) { + retval = (int)tmp; + } else { + tmp = (unsigned char)key1->FkType - (unsigned char)key2->FkType; + if (tmp != 0) { + retval = (int)tmp; + } else { + retval = (int)(hfs_get_hs(key1->FABN) + - hfs_get_hs(key2->FABN)); + } + } + return retval; +} + +/* + * hfs_extent_adj() + * + * Given an hfs_fork shrink or grow the fork to hold the + * forks logical size. + */ +void hfs_extent_adj(struct hfs_fork *fork) +{ + if (fork) { + hfs_u32 blks, ablocks; + hfs_u16 ablksz; + + if (fork->lsize > HFS_FORK_MAX) { + fork->lsize = HFS_FORK_MAX; + } + + blks = (fork->lsize+HFS_SECTOR_SIZE-1) >> HFS_SECTOR_SIZE_BITS; + ablksz = fork->entry->mdb->alloc_blksz; + ablocks = (blks + ablksz - 1) / ablksz; + + if (blks > fork->psize) { + grow_fork(fork, ablocks); + if (blks > fork->psize) { + fork->lsize = + fork->psize >> HFS_SECTOR_SIZE_BITS; + } + fork->entry->dirt = 1; + } else if (blks < fork->psize) { + shrink_fork(fork, ablocks); + fork->entry->dirt = 1; + } + } +} + +/* + * hfs_extent_map() + * + * Given an hfs_fork and a block number within the fork, return the + * number of the corresponding physical block on disk, or zero on + * error. + */ +int hfs_extent_map(struct hfs_fork *fork, int block, int create) +{ + int ablksz, ablock, offset, tmp; + struct hfs_extent *ext; + + if (!fork || !fork->entry || !fork->entry->mdb) { + return 0; + } + +#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL) + hfs_warn("hfs_extent_map: ablock %d of file %d, fork %d\n", + block, fork->entry->cnid, fork->fork); +#endif + + if (block < 0) { + hfs_warn("hfs_extent_map: block < 0\n"); + return 0; + } + if (block > (HFS_FORK_MAX >> HFS_SECTOR_SIZE_BITS)) { + hfs_warn("hfs_extent_map: block(0x%08x) > big; cnid=%d " + "fork=%d\n", block, fork->entry->cnid, fork->fork); + return 0; + } + ablksz = fork->entry->mdb->alloc_blksz; + offset = fork->entry->mdb->fs_start + (block % ablksz); + ablock = block / ablksz; + + if (block >= fork->psize) { + if (create) { + grow_fork(fork, ablock + 1); + fork->entry->dirt = 1; + } else { + return 0; + } + } + +#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL) + hfs_warn("(lblock %d offset %d)\n", ablock, offset); +#endif + + if ((ext = find_ext(fork, ablock))) { + dump_ext("trying new: ", ext); + tmp = decode_extent(ext, ablock); + relse_ext(ext); + if (tmp >= 0) { + return tmp*ablksz + offset; + } + } + + return 0; +} + +/* + * hfs_extent_out() + * + * Copy the first extent record from a (struct hfs_fork) to a (struct + * raw_extent), record (normally the one in the catalog entry). + */ +void hfs_extent_out(const struct hfs_fork *fork, hfs_byte_t dummy[12]) +{ + struct hfs_raw_extent *ext = (struct hfs_raw_extent *)dummy; + + if (fork && ext) { + write_extent(ext, &fork->first); + dump_ext("extent out: ", &fork->first); + } +} + +/* + * hfs_extent_in() + * + * Copy an raw_extent to the 'first' and 'cache' fields of an hfs_fork. + */ +void hfs_extent_in(struct hfs_fork *fork, const hfs_byte_t dummy[12]) +{ + const struct hfs_raw_extent *ext = + (const struct hfs_raw_extent *)dummy; + + if (fork && ext) { + read_extent(&fork->first, ext, 0); + fork->cache = &fork->first; + fork->first.count = 2; + dump_ext("extent in: ", &fork->first); + } +} + +/* + * hfs_extent_free() + * + * Removes from memory all extents associated with 'fil'. + */ +void hfs_extent_free(struct hfs_fork *fork) +{ + if (fork) { + set_cache(fork, &fork->first); + + if (fork->first.next) { + hfs_warn("hfs_extent_free: extents in use!\n"); + } + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/file.c linux/fs/hfs/file.c --- v2.1.77/linux/fs/hfs/file.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/file.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,525 @@ +/* + * linux/fs/hfs/file.c + * + * Copyright (C) 1995, 1996 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the file-related functions which are independent of + * which scheme is being used to represent forks. + * + * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ Forward declarations ================*/ + +static hfs_rwret_t hfs_file_read(struct file *, char *, hfs_rwarg_t, + loff_t *); +static hfs_rwret_t hfs_file_write(struct file *, const char *, hfs_rwarg_t, + loff_t *); +static void hfs_file_truncate(struct inode *); +static int hfs_bmap(struct inode *, int); + +/*================ Global variables ================*/ + +static struct file_operations hfs_file_operations = { + NULL, /* lseek - default */ + hfs_file_read, /* read */ + hfs_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + generic_file_mmap, /* mmap */ + NULL, /* open */ + NULL, /* release */ + file_fsync, /* fsync - default */ + NULL, /* fasync - default */ + NULL, /* check_media_change - none */ + NULL, /* revalidate - none */ + NULL /* lock - none */ +}; + +struct inode_operations hfs_file_inode_operations = { + &hfs_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + generic_readpage, /* readpage */ + NULL, /* writepage */ + hfs_bmap, /* bmap */ + hfs_file_truncate, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ +}; + +/*================ Variable-like macros ================*/ + +/* maximum number of blocks to try to read in at once */ +#define NBUF 32 + +/*================ File-local functions ================*/ + +/* + * hfs_getblk() + * + * Given an hfs_fork and a block number return the buffer_head for + * that block from the fork. If 'create' is non-zero then allocate + * the necessary block(s) to the fork. + */ +struct buffer_head *hfs_getblk(struct hfs_fork *fork, int block, int create) +{ + int tmp; + kdev_t dev = fork->entry->mdb->sys_mdb->s_dev; + + tmp = hfs_extent_map(fork, block, create); + + if (create) { + /* If writing the block, then we have exclusive access + to the file until we return, so it can't have moved. + */ + return tmp ? getblk(dev, tmp, HFS_SECTOR_SIZE) : NULL; + } else { + /* If reading the block, then retry since the + location on disk could have changed while + we waited on the I/O in getblk to complete. + */ + do { + struct buffer_head *bh = + getblk(dev, tmp, HFS_SECTOR_SIZE); + int tmp2 = hfs_extent_map(fork, block, 0); + + if (tmp2 == tmp) { + return bh; + } else { + /* The block moved or no longer exists. */ + brelse(bh); + tmp = tmp2; + } + } while (tmp != 0); + + /* The block no longer exists. */ + return NULL; + } +} + +/* + * hfs_bmap() + * + * This is the bmap() field in the inode_operations structure for + * "regular" (non-header) files. The purpose is to translate an inode + * and a block number within the corresponding file into a physical + * block number. This function just calls hfs_extent_map() to do the + * real work. + */ +static int hfs_bmap(struct inode * inode, int block) +{ + return hfs_extent_map(HFS_I(inode)->fork, block, 0); +} + +/* + * hfs_file_read() + * + * This is the read field in the inode_operations structure for + * "regular" (non-header) files. The purpose is to transfer up to + * 'count' bytes from the file corresponding to 'inode', beginning at + * 'filp->offset' bytes into the file. The data is transfered to + * user-space at the address 'buf'. Returns the number of bytes + * successfully transfered. This function checks the arguments, does + * some setup and then calls hfs_do_read() to do the actual transfer. + */ +static hfs_rwret_t hfs_file_read(struct file * filp, char * buf, + hfs_rwarg_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + hfs_s32 read, left, pos, size; + + if (!S_ISREG(inode->i_mode)) { + hfs_warn("hfs_file_read: mode = %07o\n",inode->i_mode); + return -EINVAL; + } + pos = *ppos; + if (pos >= HFS_FORK_MAX) { + return 0; + } + size = inode->i_size; + if (pos > size) { + left = 0; + } else { + left = size - pos; + } + if (left > count) { + left = count; + } + if (left <= 0) { + return 0; + } + if ((read = hfs_do_read(inode, HFS_I(inode)->fork, pos, + buf, left, filp->f_reada != 0)) > 0) { + *ppos += read; + filp->f_reada = 1; + } + + return read; +} + +/* + * hfs_file_write() + * + * This is the write() entry in the file_operations structure for + * "regular" files. The purpose is to transfer up to 'count' bytes + * to the file corresponding to 'inode' beginning at offset + * 'file->f_pos' from user-space at the address 'buf'. The return + * value is the number of bytes actually transferred. + */ +static hfs_rwret_t hfs_file_write(struct file * filp, const char * buf, + hfs_rwarg_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct hfs_fork *fork = HFS_I(inode)->fork; + hfs_s32 written, pos; + + if (!S_ISREG(inode->i_mode)) { + hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode); + return -EINVAL; + } + + pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos; + + if (pos >= HFS_FORK_MAX) { + return 0; + } + if (count > HFS_FORK_MAX) { + count = HFS_FORK_MAX; + } + if ((written = hfs_do_write(inode, fork, pos, buf, count)) > 0) + pos += written; + + *ppos = pos; + if (*ppos > inode->i_size) + inode->i_size = *ppos; + + return written; +} + +/* + * hfs_file_truncate() + * + * This is the truncate() entry in the file_operations structure for + * "regular" files. The purpose is to change the length of the file + * corresponding to the given inode. Changes can either lengthen or + * shorten the file. + */ +static void hfs_file_truncate(struct inode * inode) +{ + struct hfs_fork *fork = HFS_I(inode)->fork; + + fork->lsize = inode->i_size; + hfs_extent_adj(fork); + + inode->i_size = fork->lsize; + inode->i_blocks = fork->psize; +} + +/* + * xlate_to_user() + * + * Like copy_to_user() while translating CR->NL. + */ +static inline void xlate_to_user(char *buf, const char *data, int count) +{ + char ch; + + while (count--) { + ch = *(data++); + put_user((ch == '\r') ? '\n' : ch, buf++); + } +} + +/* + * xlate_from_user() + * + * Like copy_from_user() while translating NL->CR; + */ +static inline void xlate_from_user(char *data, const char *buf, int count) +{ + copy_from_user(data, buf, count); + while (count--) { + if (*data == '\n') { + *data = '\r'; + } + ++data; + } +} + +/*================ Global functions ================*/ + +/* + * hfs_do_read() + * + * This function transfers actual data from disk to user-space memory, + * returning the number of bytes successfully transfered. 'fork' tells + * which file on the disk to read from. 'pos' gives the offset into + * the Linux file at which to begin the transfer. Note that this will + * differ from 'filp->offset' in the case of an AppleDouble header file + * due to the block of metadata at the beginning of the file, which has + * no corresponding place in the HFS file. 'count' tells how many + * bytes to transfer. 'buf' gives an address in user-space to transfer + * the data to. + * + * This is based on Linus's minix_file_read(). + * It has been changed to take into account that HFS files have no holes. + */ +hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, + char * buf, hfs_u32 count, int reada) +{ + kdev_t dev = inode->i_dev; + hfs_s32 size, chars, offset, block, blocks, read = 0; + int bhrequest, uptodate; + int convert = HFS_I(inode)->convert; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * bhreq[NBUF]; + struct buffer_head * buflist[NBUF]; + + /* split 'pos' in to block and (byte) offset components */ + block = pos >> HFS_SECTOR_SIZE_BITS; + offset = pos & (HFS_SECTOR_SIZE-1); + + /* compute the logical size of the fork in blocks */ + size = (fork->lsize + (HFS_SECTOR_SIZE-1)) >> HFS_SECTOR_SIZE_BITS; + + /* compute the number of physical blocks to be transferred */ + blocks = (count+offset+HFS_SECTOR_SIZE-1) >> HFS_SECTOR_SIZE_BITS; + + bhb = bhe = buflist; + if (reada) { + if (blocks < read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9)) { + blocks = read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9); + } + if (block + blocks > size) { + blocks = size - block; + } + } + + /* We do this in a two stage process. We first try and + request as many blocks as we can, then we wait for the + first one to complete, and then we try and wrap up as many + as are actually done. + + This routine is optimized to make maximum use of the + various buffers and caches. */ + + do { + bhrequest = 0; + uptodate = 1; + while (blocks) { + --blocks; + *bhb = hfs_getblk(fork, block++, 0); + + if (!(*bhb)) { + /* Since there are no holes in HFS files + we must have encountered an error. + So, stop adding blocks to the queue. */ + blocks = 0; + break; + } + + if (!buffer_uptodate(*bhb)) { + uptodate = 0; + bhreq[bhrequest++] = *bhb; + } + + if (++bhb == &buflist[NBUF]) { + bhb = buflist; + } + + /* If the block we have on hand is uptodate, + go ahead and complete processing. */ + if (uptodate) { + break; + } + if (bhb == bhe) { + break; + } + } + + /* If the only block in the queue is bad then quit */ + if (!(*bhe)) { + break; + } + + /* Now request them all */ + if (bhrequest) { + ll_rw_block(READ, bhrequest, bhreq); + } + + do { /* Finish off all I/O that has actually completed */ + char *p; + + wait_on_buffer(*bhe); + + if (!buffer_uptodate(*bhe)) { + /* read error? */ + brelse(*bhe); + if (++bhe == &buflist[NBUF]) { + bhe = buflist; + } + count = 0; + break; + } + + if (count < HFS_SECTOR_SIZE - offset) { + chars = count; + } else { + chars = HFS_SECTOR_SIZE - offset; + } + count -= chars; + read += chars; + p = (*bhe)->b_data + offset; + if (convert) { + xlate_to_user(buf, p, chars); + } else { + copy_to_user(buf, p, chars); + } + brelse(*bhe); + buf += chars; + offset = 0; + if (++bhe == &buflist[NBUF]) { + bhe = buflist; + } + } while (count && (bhe != bhb) && !buffer_locked(*bhe)); + } while (count); + + /* Release the read-ahead blocks */ + while (bhe != bhb) { + brelse(*bhe); + if (++bhe == &buflist[NBUF]) { + bhe = buflist; + } + } + if (!read) { + return -EIO; + } + return read; +} + +/* + * hfs_do_write() + * + * This function transfers actual data from user-space memory to disk, + * returning the number of bytes successfully transfered. 'fork' tells + * which file on the disk to write to. 'pos' gives the offset into + * the Linux file at which to begin the transfer. Note that this will + * differ from 'filp->offset' in the case of an AppleDouble header file + * due to the block of metadata at the beginning of the file, which has + * no corresponding place in the HFS file. 'count' tells how many + * bytes to transfer. 'buf' gives an address in user-space to transfer + * the data from. + * + * This is just a minor edit of Linus's minix_file_write(). + */ +hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, + const char * buf, hfs_u32 count) +{ + hfs_s32 written, c; + struct buffer_head * bh; + char * p; + int convert = HFS_I(inode)->convert; + + written = 0; + while (written < count) { + bh = hfs_getblk(fork, pos/HFS_SECTOR_SIZE, 1); + if (!bh) { + if (!written) { + written = -ENOSPC; + } + break; + } + c = HFS_SECTOR_SIZE - (pos % HFS_SECTOR_SIZE); + if (c > count - written) { + c = count - written; + } + if (c != HFS_SECTOR_SIZE && !buffer_uptodate(bh)) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + brelse(bh); + if (!written) { + written = -EIO; + } + break; + } + } + p = (pos % HFS_SECTOR_SIZE) + bh->b_data; + if (convert) { + xlate_from_user(p, buf, c); + } else { + copy_from_user(p, buf, c); + } + update_vm_cache(inode,pos,p,c); + pos += c; + written += c; + buf += c; + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh, 0); + brelse(bh); + } + if (written > 0) { + struct hfs_cat_entry *entry = fork->entry; + + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + if (pos > fork->lsize) { + fork->lsize = pos; + } + entry->modify_date = hfs_u_to_mtime(CURRENT_TIME); + entry->dirt = 1; + } + return written; +} + +/* + * hfs_file_fix_mode() + * + * Fixes up the permissions on a file after changing the write-inhibit bit. + */ +void hfs_file_fix_mode(struct hfs_cat_entry *entry) +{ + struct dentry **de = entry->sys_entry; + int i; + + if (entry->u.file.flags & HFS_FIL_LOCK) { + for (i = 0; i < 4; ++i) { + if (de[i]) { + de[i]->d_inode->i_mode &= ~S_IWUGO; + } + } + } else { + for (i = 0; i < 4; ++i) { + if (de[i]) { + struct inode *inode = de[i]->d_inode; + inode->i_mode |= S_IWUGO; + inode->i_mode &= + ~HFS_SB(inode->i_sb)->s_umask; + } + } + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/file_cap.c linux/fs/hfs/file_cap.c --- v2.1.77/linux/fs/hfs/file_cap.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/file_cap.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,297 @@ +/* + * linux/fs/hfs/file_cap.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the file_ops and inode_ops for the metadata + * files under the CAP representation. + * + * The source code distribution of the Columbia AppleTalk Package for + * UNIX, version 6.0, (CAP) was used as a specification of the + * location and format of files used by CAP's Aufs. No code from CAP + * appears in hfs_fs. hfs_fs is not a work ``derived'' from CAP in + * the sense of intellectual property law. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ Forward declarations ================*/ + +static hfs_rwret_t cap_info_read(struct file *, char *, + hfs_rwarg_t, loff_t *); +static hfs_rwret_t cap_info_write(struct file *, const char *, + hfs_rwarg_t, loff_t *); +static void cap_info_truncate(struct inode *); + +/*================ Function-like macros ================*/ + +/* + * OVERLAPS() + * + * Determines if a given range overlaps the specified structure member + */ +#define OVERLAPS(START, END, TYPE, MEMB) \ + ((END > offsetof(TYPE, MEMB)) && \ + (START < offsetof(TYPE, MEMB) + sizeof(((TYPE *)0)->MEMB))) + +/*================ Global variables ================*/ + +static struct file_operations hfs_cap_info_operations = { + NULL, /* lseek - default */ + cap_info_read, /* read */ + cap_info_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap - not yet */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync, /* fsync - default */ + NULL, /* fasync - default */ + NULL, /* check_media_change - none */ + NULL, /* revalidate - none */ + NULL /* lock - none */ +}; + +struct inode_operations hfs_cap_info_inode_operations = { + &hfs_cap_info_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap - none */ + cap_info_truncate, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidata */ +}; + +/*================ File-local functions ================*/ + +/* + * cap_build_meta() + * + * Build the metadata structure. + */ +static void cap_build_meta(struct hfs_cap_info *meta, + struct hfs_cat_entry *entry) +{ + memset(meta, 0, sizeof(*meta)); + memcpy(meta->fi_fndr, &entry->info, 32); + if ((entry->type == HFS_CDR_FIL) && + (entry->u.file.flags & HFS_FIL_LOCK)) { + /* Couple the locked bit of the file to the + AFP {write,rename,delete} inhibit bits. */ + hfs_put_hs(HFS_AFP_RDONLY, meta->fi_attr); + } + meta->fi_magic1 = HFS_CAP_MAGIC1; + meta->fi_version = HFS_CAP_VERSION; + meta->fi_magic = HFS_CAP_MAGIC; + meta->fi_bitmap = HFS_CAP_LONGNAME; + memcpy(meta->fi_macfilename, entry->key.CName.Name, + entry->key.CName.Len); + meta->fi_datemagic = HFS_CAP_DMAGIC; + meta->fi_datevalid = HFS_CAP_MDATE | HFS_CAP_CDATE; + hfs_put_nl(hfs_m_to_htime(entry->create_date), meta->fi_ctime); + hfs_put_nl(hfs_m_to_htime(entry->modify_date), meta->fi_mtime); + hfs_put_nl(CURRENT_TIME, meta->fi_utime); +} + +/* + * cap_info_read() + * + * This is the read() entry in the file_operations structure for CAP + * metadata files. The purpose is to transfer up to 'count' bytes + * from the file corresponding to 'inode' beginning at offset + * 'file->f_pos' to user-space at the address 'buf'. The return value + * is the number of bytes actually transferred. + */ +static hfs_rwret_t cap_info_read(struct file *filp, char *buf, + hfs_rwarg_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + hfs_s32 left, size, read = 0; + hfs_u32 pos; + + if (!S_ISREG(inode->i_mode)) { + hfs_warn("hfs_cap_info_read: mode = %07o\n", inode->i_mode); + return -EINVAL; + } + + pos = *ppos; + if (pos > HFS_FORK_MAX) { + return 0; + } + size = inode->i_size; + if (pos > size) { + left = 0; + } else { + left = size - pos; + } + if (left > count) { + left = count; + } + if (left <= 0) { + return 0; + } + + if (pos < sizeof(struct hfs_cap_info)) { + int memcount = sizeof(struct hfs_cap_info) - pos; + struct hfs_cap_info meta; + + if (memcount > left) { + memcount = left; + } + cap_build_meta(&meta, entry); + /* is copy_to_user guaranteed to write memcount? */ + copy_to_user(buf, ((char *)&meta) + pos, memcount); + left -= memcount; + read += memcount; + pos += memcount; + buf += memcount; + } + + if (left > 0) { + clear_user(buf, left); + pos += left; + } + + if (read) { + inode->i_atime = CURRENT_TIME; + *ppos = pos; + } + + return read; +} + +/* + * cap_info_write() + * + * This is the write() entry in the file_operations structure for CAP + * metadata files. The purpose is to transfer up to 'count' bytes + * to the file corresponding to 'inode' beginning at offset + * '*ppos' from user-space at the address 'buf'. + * The return value is the number of bytes actually transferred. + */ +static hfs_rwret_t cap_info_write(struct file *filp, const char *buf, + hfs_rwarg_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + hfs_u32 pos; + + if (!S_ISREG(inode->i_mode)) { + hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode); + return -EINVAL; + } + if (count <= 0) { + return 0; + } + + pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos; + + if (pos > HFS_FORK_MAX) { + return 0; + } + + *ppos += count; + if (*ppos > HFS_FORK_MAX) { + *ppos = HFS_FORK_MAX; + count = HFS_FORK_MAX - pos; + } + + if (*ppos > inode->i_size) + inode->i_size = *ppos; + + /* Only deal with the part we store in memory */ + if (pos < sizeof(struct hfs_cap_info)) { + int end, mem_count; + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + struct hfs_cap_info meta; + + mem_count = sizeof(struct hfs_cap_info) - pos; + if (mem_count > count) { + mem_count = count; + } + end = pos + mem_count; + + cap_build_meta(&meta, entry); + copy_from_user(((char *)&meta) + pos, buf, mem_count); + + /* Update finder attributes if changed */ + if (OVERLAPS(pos, end, struct hfs_cap_info, fi_fndr)) { + memcpy(&entry->info, meta.fi_fndr, 32); + entry->dirt = 1; + } + + /* Update file flags if changed */ + if (OVERLAPS(pos, end, struct hfs_cap_info, fi_attr) && + (entry->type == HFS_CDR_FIL)) { + int locked = hfs_get_ns(&meta.fi_attr) & + htons(HFS_AFP_WRI); + hfs_u8 new_flags; + + if (locked) { + new_flags = entry->u.file.flags | HFS_FIL_LOCK; + } else { + new_flags = entry->u.file.flags & ~HFS_FIL_LOCK; + } + + if (new_flags != entry->u.file.flags) { + entry->u.file.flags = new_flags; + entry->dirt = 1; + hfs_file_fix_mode(entry); + } + } + + /* Update CrDat if changed */ + if (OVERLAPS(pos, end, struct hfs_cap_info, fi_ctime)) { + entry->create_date = + hfs_h_to_mtime(hfs_get_nl(meta.fi_ctime)); + entry->dirt = 1; + } + + /* Update MdDat if changed */ + if (OVERLAPS(pos, end, struct hfs_cap_info, fi_mtime)) { + entry->modify_date = + hfs_h_to_mtime(hfs_get_nl(meta.fi_mtime)); + entry->dirt = 1; + } + } + + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + return count; +} + +/* + * cap_info_truncate() + * + * This is the truncate field in the inode_operations structure for + * CAP metadata files. + */ +static void cap_info_truncate(struct inode *inode) +{ + if (inode->i_size > HFS_FORK_MAX) { + inode->i_size = HFS_FORK_MAX; + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/file_hdr.c linux/fs/hfs/file_hdr.c --- v2.1.77/linux/fs/hfs/file_hdr.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/file_hdr.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,937 @@ +/* + * linux/fs/hfs/file_hdr.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the file_ops and inode_ops for the metadata + * files under the AppleDouble and Netatalk representations. + * + * The source code distributions of Netatalk, versions 1.3.3b2 and + * 1.4b2, were used as a specification of the location and format of + * files used by Netatalk's afpd. No code from Netatalk appears in + * hfs_fs. hfs_fs is not a work ``derived'' from Netatalk in the + * sense of intellectual property law. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + * + * XXX: Note the reason that there is not bmap() for AppleDouble + * header files is that dynamic nature of their structure make it + * very difficult to safely mmap them. Maybe in the distant future + * I'll get bored enough to implement it. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ Forward declarations ================*/ + +static hfs_rwret_t hdr_read(struct file *, char *, hfs_rwarg_t, loff_t *); +static hfs_rwret_t hdr_write(struct file *, const char *, + hfs_rwarg_t, loff_t *); +static void hdr_truncate(struct inode *); + +/*================ Global variables ================*/ + +static struct file_operations hfs_hdr_operations = { + NULL, /* lseek - default */ + hdr_read, /* read */ + hdr_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap - XXX: not yet */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync, /* fsync - default */ + NULL, /* fasync - default */ + NULL, /* check_media_change - none */ + NULL, /* revalidate - none */ + NULL /* lock - none */ +}; + +struct inode_operations hfs_hdr_inode_operations = { + &hfs_hdr_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap - XXX: not available since + header part has no disk block */ + hdr_truncate, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ +}; + +const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = { + __constant_htonl(HFS_DBL_MAGIC), /* magic */ + __constant_htonl(HFS_HDR_VERSION_2), /* version */ + 5, /* entries */ + { /* descr[] */ + {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16}, + {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo), 32}, + {HFS_HDR_MACI, offsetof(struct hfs_dbl_hdr, fileinfo), 4}, + {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name), ~0}, + {HFS_HDR_RSRC, HFS_DBL_HDR_LEN, ~0}, + }, + { /* order[] */ + (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[0], + (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[1], + (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[2], + (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[3], + (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[4], + } +}; + +const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout = { + __constant_htonl(HFS_DBL_MAGIC), /* magic */ + __constant_htonl(HFS_HDR_VERSION_2), /* version */ + 4, /* entries */ + { /* descr[] */ + {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16}, + {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo), 32}, + {HFS_HDR_MACI, offsetof(struct hfs_dbl_hdr, fileinfo), 4}, + {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name), ~0}, + }, + { /* order[] */ + (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[0], + (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[1], + (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[2], + (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[3], + } +}; + +const struct hfs_hdr_layout hfs_nat_hdr_layout = { + __constant_htonl(HFS_DBL_MAGIC), /* magic */ + __constant_htonl(HFS_HDR_VERSION_1), /* version */ + 5, /* entries */ + { /* descr[] */ + {HFS_HDR_RSRC, HFS_NAT_HDR_LEN, ~0}, + {HFS_HDR_FNAME, offsetof(struct hfs_nat_hdr, real_name), ~0}, + {HFS_HDR_COMNT, offsetof(struct hfs_nat_hdr, comment), 0}, + {HFS_HDR_OLDI, offsetof(struct hfs_nat_hdr, create_time), 16}, + {HFS_HDR_FINFO, offsetof(struct hfs_nat_hdr, finderinfo), 32}, + }, + { /* order[] */ + (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1], + (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2], + (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3], + (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4], + (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0], + } +}; + +/*================ File-local variables ================*/ + +static const char fstype[16] = + {'M','a','c','i','n','t','o','s','h',' ',' ',' ',' ',' ',' ',' '}; + +/*================ File-local data types ================*/ + +struct hdr_hdr { + hfs_lword_t magic; + hfs_lword_t version; + hfs_byte_t filler[16]; + hfs_word_t entries; + hfs_byte_t descrs[12*HFS_HDR_MAX]; +}; + +/*================ File-local functions ================*/ + +/* + * dlength() + */ +static int dlength(const struct hfs_hdr_descr *descr, + const struct hfs_cat_entry *entry) +{ + hfs_u32 length = descr->length; + + /* handle auto-sized entries */ + if (length == ~0) { + switch (descr->id) { + case HFS_HDR_DATA: + if (entry->type == HFS_CDR_FIL) { + length = entry->u.file.data_fork.lsize; + } else { + length = 0; + } + break; + + case HFS_HDR_RSRC: + if (entry->type == HFS_CDR_FIL) { + length = entry->u.file.rsrc_fork.lsize; + } else { + length = 0; + } + break; + + case HFS_HDR_FNAME: + length = entry->key.CName.Len; + break; + + default: + length = 0; + } + } + return length; +} + +/* + * hdr_build_meta() + */ +static void hdr_build_meta(struct hdr_hdr *meta, + const struct hfs_hdr_layout *layout, + const struct hfs_cat_entry *entry) +{ + const struct hfs_hdr_descr *descr; + hfs_byte_t *ptr; + int lcv; + + hfs_put_nl(layout->magic, meta->magic); + hfs_put_nl(layout->version, meta->version); + if (layout->version == htonl(HFS_HDR_VERSION_1)) { + memcpy(meta->filler, fstype, 16); + } else { + memset(meta->filler, 0, 16); + } + hfs_put_hs(layout->entries, meta->entries); + memset(meta->descrs, 0, sizeof(meta->descrs)); + for (lcv = 0, descr = layout->descr, ptr = meta->descrs; + lcv < layout->entries; ++lcv, ++descr, ptr += 12) { + hfs_put_hl(descr->id, ptr); + hfs_put_hl(descr->offset, ptr + 4); + hfs_put_hl(dlength(descr, entry), ptr + 8); + } +} + +/* + * dup_layout () + */ +static struct hfs_hdr_layout *dup_layout(const struct hfs_hdr_layout *old) +{ + struct hfs_hdr_layout *new; + int lcv; + + if (HFS_NEW(new)) { + memcpy(new, old, sizeof(*new)); + for (lcv = 0; lcv < new->entries; ++lcv) { + (char *)(new->order[lcv]) += (char *)new - (char *)old; + } + } + return new; +} + +/* + * init_layout() + */ +static inline void init_layout(struct hfs_hdr_layout *layout, + const hfs_byte_t *descrs) +{ + struct hfs_hdr_descr **base, **p, **q, *tmp; + int lcv, entries = layout->entries; + + for (lcv = 0; lcv < entries; ++lcv, descrs += 12) { + layout->order[lcv] = &layout->descr[lcv]; + layout->descr[lcv].id = hfs_get_hl(descrs); + layout->descr[lcv].offset = hfs_get_hl(descrs + 4); + layout->descr[lcv].length = hfs_get_hl(descrs + 8); + } + for (lcv = layout->entries; lcv < HFS_HDR_MAX; ++lcv) { + layout->order[lcv] = NULL; + layout->descr[lcv].id = 0; + layout->descr[lcv].offset = 0; + layout->descr[lcv].length = 0; + } + + /* Sort the 'order' array using an insertion sort */ + base = &layout->order[0]; + for (p = (base+1); p < (base+entries); ++p) { + q=p; + while ((*q)->offset < (*(q-1))->offset) { + tmp = *q; + *q = *(q-1); + *(--q) = tmp; + if (q == base) break; + } + } +} + +/* + * adjust_forks() + */ +static inline void adjust_forks(struct hfs_cat_entry *entry, + const struct hfs_hdr_layout *layout) +{ + int lcv; + + for (lcv = 0; lcv < layout->entries; ++lcv) { + const struct hfs_hdr_descr *descr = &layout->descr[lcv]; + + if ((descr->id == HFS_HDR_DATA) && + (descr->length != entry->u.file.data_fork.lsize)) { + entry->u.file.data_fork.lsize = descr->length; + hfs_extent_adj(&entry->u.file.data_fork); + } else if ((descr->id == HFS_HDR_RSRC) && + (descr->length != entry->u.file.rsrc_fork.lsize)) { + entry->u.file.rsrc_fork.lsize = descr->length; + hfs_extent_adj(&entry->u.file.rsrc_fork); + } + } +} + +/* + * get_dates() + */ +static void get_dates(const struct hfs_cat_entry *entry, + const struct inode *inode, hfs_u32 dates[3]) +{ + if (HFS_SB(inode->i_sb)->s_afpd) { + /* AFPD compatible: use un*x times */ + dates[0] = htonl(hfs_m_to_utime(entry->create_date)); + dates[1] = htonl(hfs_m_to_utime(entry->modify_date)); + dates[2] = htonl(hfs_m_to_utime(entry->backup_date)); + } else { + dates[0] = hfs_m_to_htime(entry->create_date); + dates[1] = hfs_m_to_htime(entry->modify_date); + dates[2] = hfs_m_to_htime(entry->backup_date); + } +} + +/* + * set_dates() + */ +static void set_dates(struct hfs_cat_entry *entry, struct inode *inode, + const hfs_u32 *dates) +{ + hfs_u32 tmp; + if (HFS_SB(inode->i_sb)->s_afpd) { + /* AFPD compatible: use un*x times */ + tmp = hfs_u_to_mtime(ntohl(dates[0])); + if (entry->create_date != tmp) { + entry->create_date = tmp; + entry->dirt = 1; + } + tmp = hfs_u_to_mtime(ntohl(dates[1])); + if (entry->modify_date != tmp) { + entry->modify_date = tmp; + inode->i_ctime = inode->i_atime = inode->i_mtime = + ntohl(dates[1]); + entry->dirt = 1; + } + tmp = hfs_u_to_mtime(ntohl(dates[2])); + if (entry->backup_date != tmp) { + entry->backup_date = tmp; + entry->dirt = 1; + } + } else { + tmp = hfs_h_to_mtime(dates[0]); + if (entry->create_date != tmp) { + entry->create_date = tmp; + entry->dirt = 1; + } + tmp = hfs_h_to_mtime(dates[1]); + if (entry->modify_date != tmp) { + entry->modify_date = tmp; + inode->i_ctime = inode->i_atime = inode->i_mtime = + hfs_h_to_utime(dates[1]); + entry->dirt = 1; + } + tmp = hfs_h_to_mtime(dates[2]); + if (entry->backup_date != tmp) { + entry->backup_date = tmp; + entry->dirt = 1; + } + } +} + +/* + * hdr_read() + * + * This is the read field in the inode_operations structure for + * header files. The purpose is to transfer up to 'count' bytes + * from the file corresponding to 'inode', beginning at + * 'filp->offset' bytes into the file. The data is transfered to + * user-space at the address 'buf'. Returns the number of bytes + * successfully transfered. + */ +/* XXX: what about the entry count changing on us? */ +static hfs_rwret_t hdr_read(struct file * filp, char * buf, + hfs_rwarg_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + const struct hfs_hdr_layout *layout; + off_t start, length, offset; + off_t pos = *ppos; + int left, lcv, read = 0; + + if (!S_ISREG(inode->i_mode)) { + hfs_warn("hfs_hdr_read: mode = %07o\n",inode->i_mode); + return -EINVAL; + } + + if (HFS_I(inode)->layout) { + layout = HFS_I(inode)->layout; + } else { + layout = HFS_I(inode)->default_layout; + } + + /* Adjust count to fit within the bounds of the file */ + if ((pos >= inode->i_size) || (count <= 0)) { + return 0; + } else if (count > inode->i_size - pos) { + count = inode->i_size - pos; + } + + /* Handle the fixed-location portion */ + length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + + sizeof(hfs_u16) + layout->entries * (3 * sizeof(hfs_u32)); + if (pos < length) { + struct hdr_hdr meta; + + left = length - pos; + if (left > count) { + left = count; + } + + hdr_build_meta(&meta, layout, entry); + copy_to_user(buf, ((char *)&meta) + pos, left); + count -= left; + read += left; + pos += left; + buf += left; + } + if (!count) { + goto done; + } + + /* Handle the actual data */ + for (lcv = 0; count && (lcv < layout->entries); ++lcv) { + const struct hfs_hdr_descr *descr = layout->order[lcv]; + struct hfs_fork *fork; + char tmp[16], *p; + off_t limit; + + /* stop reading if we run out of descriptors early */ + if (!descr) { + break; + } + + /* find start and length of this entry */ + start = descr->offset; + length = dlength(descr, entry); + + /* Skip to next entry if this one is empty or isn't needed */ + if (!length || (pos >= start + length)) { + continue; + } + + /* Pad with zeros to the start of this entry if needed */ + if (pos < start) { + left = start - pos; + if (left > count) { + left = count; + } + clear_user(buf, left); + count -= left; + read += left; + pos += left; + buf += left; + } + if (!count) { + goto done; + } + + /* locate and/or construct the data for this entry */ + fork = NULL; + p = NULL; + switch (descr->id) { + case HFS_HDR_DATA: + fork = &entry->u.file.data_fork; + limit = fork->lsize; + break; + + case HFS_HDR_RSRC: + fork = &entry->u.file.rsrc_fork; + limit = fork->lsize; + break; + + case HFS_HDR_FNAME: + p = entry->key.CName.Name; + limit = entry->key.CName.Len; + break; + + case HFS_HDR_OLDI: + case HFS_HDR_DATES: + get_dates(entry, inode, (hfs_u32 *)tmp); + if (descr->id == HFS_HDR_DATES) { + memcpy(tmp + 12, tmp + 4, 4); + } else if ((entry->type == HFS_CDR_FIL) && + (entry->u.file.flags & HFS_FIL_LOCK)) { + hfs_put_hl(HFS_AFP_RDONLY, tmp + 12); + } else { + hfs_put_nl(0, tmp + 12); + } + p = tmp; + limit = 16; + break; + + case HFS_HDR_FINFO: + p = (char *)&entry->info; + limit = 32; + break; + + case HFS_HDR_MACI: + hfs_put_ns(0, tmp); + if (entry->type == HFS_CDR_FIL) { + hfs_put_hs(entry->u.file.flags, tmp + 2); + } else { + hfs_put_ns(entry->u.dir.flags, tmp + 2); + } + p = tmp; + limit = 4; + break; + + default: + limit = 0; + } + + /* limit the transfer to the available data + of to the stated length of the entry. */ + if (length > limit) { + length = limit; + } + offset = pos - start; + left = length - offset; + if (left > count) { + left = count; + } + if (left <= 0) { + continue; + } + + /* transfer the data */ + if (p) { + copy_to_user(buf, p + offset, left); + } else if (fork) { + left = hfs_do_read(inode, fork, offset, buf, left, + filp->f_reada != 0); + if (left > 0) { + filp->f_reada = 1; + } else if (!read) { + return left; + } else { + goto done; + } + } + count -= left; + read += left; + pos += left; + buf += left; + } + + /* Pad the file out with zeros */ + if (count) { + clear_user(buf, count); + read += count; + pos += count; + } + +done: + if (read) { + inode->i_atime = CURRENT_TIME; + *ppos = pos; + } + return read; +} + +/* + * hdr_write() + * + * This is the write() entry in the file_operations structure for + * header files. The purpose is to transfer up to 'count' bytes + * to the file corresponding to 'inode' beginning at offset + * '*ppos' from user-space at the address 'buf'. + * The return value is the number of bytes actually transferred. + */ +static hfs_rwret_t hdr_write(struct file *filp, const char *buf, + hfs_rwarg_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + struct hfs_hdr_layout *layout; + off_t start, length, offset; + int left, lcv, written = 0; + struct hdr_hdr meta; + int built_meta = 0; + off_t pos; + + if (!S_ISREG(inode->i_mode)) { + hfs_warn("hfs_hdr_write: mode = %07o\n", inode->i_mode); + return -EINVAL; + } + if (count <= 0) { + return 0; + } + + pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos; + + if (!HFS_I(inode)->layout) { + HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout); + } + layout = HFS_I(inode)->layout; + + /* Handle the 'magic', 'version', 'filler' and 'entries' fields */ + length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + sizeof(hfs_u16); + if (pos < length) { + hdr_build_meta(&meta, layout, entry); + built_meta = 1; + + left = length - pos; + if (left > count) { + left = count; + } + + copy_from_user(((char *)&meta) + pos, buf, left); + layout->magic = hfs_get_nl(meta.magic); + layout->version = hfs_get_nl(meta.version); + layout->entries = hfs_get_hs(meta.entries); + if (layout->entries > HFS_HDR_MAX) { + /* XXX: should allocate slots dynamically */ + hfs_warn("hfs_hdr_write: TRUNCATING TO %d " + "DESCRIPTORS\n", HFS_HDR_MAX); + layout->entries = HFS_HDR_MAX; + } + + count -= left; + written += left; + pos += left; + buf += left; + } + if (!count) { + goto done; + } + + /* We know for certain how many entries we have, so process them */ + length += layout->entries * 3 * sizeof(hfs_u32); + if (pos < length) { + if (!built_meta) { + hdr_build_meta(&meta, layout, entry); + } + + left = length - pos; + if (left > count) { + left = count; + } + + copy_from_user(((char *)&meta) + pos, buf, left); + init_layout(layout, meta.descrs); + + count -= left; + written += left; + pos += left; + buf += left; + + /* Handle possible size changes for the forks */ + if (entry->type == HFS_CDR_FIL) { + adjust_forks(entry, layout); + } + } + + /* Handle the actual data */ + for (lcv = 0; count && (lcv < layout->entries); ++lcv) { + struct hfs_hdr_descr *descr = layout->order[lcv]; + struct hfs_fork *fork; + char tmp[16], *p; + off_t limit; + + /* stop writing if we run out of descriptors early */ + if (!descr) { + break; + } + + /* find start and length of this entry */ + start = descr->offset; + if ((descr->id == HFS_HDR_DATA) || + (descr->id == HFS_HDR_RSRC)) { + if (entry->type == HFS_CDR_FIL) { + length = 0x7fffffff - start; + } else { + continue; + } + } else { + length = dlength(descr, entry); + } + + /* Trim length to avoid overlap with the next entry */ + if (layout->order[lcv+1] && + ((start + length) > layout->order[lcv+1]->offset)) { + length = layout->order[lcv+1]->offset - start; + } + + /* Skip to next entry if this one is empty or isn't needed */ + if (!length || (pos >= start + length)) { + continue; + } + + /* Skip any padding that may exist between entries */ + if (pos < start) { + left = start - pos; + if (left > count) { + left = count; + } + count -= left; + written += left; + pos += left; + buf += left; + } + if (!count) { + goto done; + } + + /* locate and/or construct the data for this entry */ + fork = NULL; + p = NULL; + switch (descr->id) { + case HFS_HDR_DATA: +#if 0 +/* Can't yet write to the data fork via a header file, since there is the + * possibility to write via the data file, and the only locking is at the + * inode level. + */ + fork = &entry->u.file.data_fork; + limit = length; +#else + limit = 0; +#endif + break; + + case HFS_HDR_RSRC: + fork = &entry->u.file.rsrc_fork; + limit = length; + break; + + case HFS_HDR_OLDI: + case HFS_HDR_DATES: + get_dates(entry, inode, (hfs_u32 *)tmp); + if (descr->id == HFS_HDR_DATES) { + memcpy(tmp + 12, tmp + 4, 4); + } else if ((entry->type == HFS_CDR_FIL) && + (entry->u.file.flags & HFS_FIL_LOCK)) { + hfs_put_hl(HFS_AFP_RDONLY, tmp + 12); + } else { + hfs_put_nl(0, tmp + 12); + } + p = tmp; + limit = 16; + break; + + case HFS_HDR_FINFO: + p = (char *)&entry->info; + limit = 32; + break; + + case HFS_HDR_MACI: + hfs_put_ns(0, tmp); + if (entry->type == HFS_CDR_FIL) { + hfs_put_hs(entry->u.file.flags, tmp + 2); + } else { + hfs_put_ns(entry->u.dir.flags, tmp + 2); + } + p = tmp; + limit = 4; + break; + + case HFS_HDR_FNAME: /* Can't rename a file this way */ + default: + limit = 0; + } + + /* limit the transfer to the available data + of to the stated length of the entry. */ + if (length > limit) { + length = limit; + } + offset = pos - start; + left = length - offset; + if (left > count) { + left = count; + } + if (left <= 0) { + continue; + } + + /* transfer the data from user space */ + if (p) { + copy_from_user(p + offset, buf, left); + } else if (fork) { + left = hfs_do_write(inode, fork, offset, buf, left); + } + + /* process the data */ + switch (descr->id) { + case HFS_HDR_OLDI: + set_dates(entry, inode, (hfs_u32 *)tmp); + if (entry->type == HFS_CDR_FIL) { + hfs_u8 new_flags = entry->u.file.flags; + + if (hfs_get_nl(tmp+12) & htonl(HFS_AFP_WRI)) { + new_flags |= HFS_FIL_LOCK; + } else { + new_flags &= ~HFS_FIL_LOCK; + } + + if (new_flags != entry->u.file.flags) { + entry->u.file.flags = new_flags; + entry->dirt = 1; + hfs_file_fix_mode(entry); + } + } + break; + + case HFS_HDR_DATES: + set_dates(entry, inode, (hfs_u32 *)tmp); + break; + + case HFS_HDR_FINFO: + entry->dirt = 1; + break; + + case HFS_HDR_MACI: + if (entry->type == HFS_CDR_DIR) { + hfs_u16 new_flags = hfs_get_ns(tmp + 2); + + if (entry->u.dir.flags != new_flags) { + entry->u.dir.flags = new_flags; + entry->dirt = 1; + } + } else { + hfs_u8 new_flags = tmp[3]; + hfs_u8 changed = entry->u.file.flags^new_flags; + + if (changed) { + entry->u.file.flags = new_flags; + entry->dirt = 1; + if (changed & HFS_FIL_LOCK) { + hfs_file_fix_mode(entry); + } + } + } + break; + + case HFS_HDR_DATA: + case HFS_HDR_RSRC: + if (left <= 0) { + if (!written) { + return left; + } else { + goto done; + } + } else if (fork->lsize > descr->length) { + descr->length = fork->lsize; + } + break; + + case HFS_HDR_FNAME: /* Can't rename a file this way */ + default: + break; + } + + count -= left; + written += left; + pos += left; + buf += left; + } + + /* Skip any padding at the end */ + if (count) { + written += count; + pos += count; + } + +done: + *ppos = pos; + if (written > 0) { + if (pos > inode->i_size) + inode->i_size = pos; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + } + return written; +} + +/* + * hdr_truncate() + * + * This is the truncate field in the inode_operations structure for + * header files. The purpose is to allocate or release blocks as needed + * to satisfy a change in file length. + */ +static void hdr_truncate(struct inode *inode) +{ + struct hfs_hdr_layout *layout; + size_t size = inode->i_size; + int lcv, last; + + if (!HFS_I(inode)->layout) { + HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout); + } + layout = HFS_I(inode)->layout; + + last = layout->entries - 1; + for (lcv = 0; lcv <= last; ++lcv) { + struct hfs_hdr_descr *descr = layout->order[lcv]; + struct hfs_fork *fork; + hfs_u32 offset; + + if (!descr) { + break; + } + + if (descr->id == HFS_HDR_RSRC) { + fork = &HFS_I(inode)->entry->u.file.rsrc_fork; +#if 0 +/* Can't yet truncate the data fork via a header file, since there is the + * possibility to truncate via the data file, and the only locking is at + * the inode level. + */ + } else if (descr->id == HFS_HDR_DATA) { + fork = &HFS_I(inode)->entry->u.file.data_fork; +#endif + } else { + continue; + } + + offset = descr->offset; + + if ((lcv != last) && ((offset + descr->length) <= size)) { + continue; + } + + if (offset < size) { + descr->length = size - offset; + } else { + descr->length = 0; + } + if (fork->lsize != descr->length) { + fork->lsize = descr->length; + hfs_extent_adj(fork); + } + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/hfs.h linux/fs/hfs/hfs.h --- v2.1.77/linux/fs/hfs/hfs.h Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/hfs.h Sun Jan 4 10:40:17 1998 @@ -0,0 +1,490 @@ +/* + * linux/fs/hfs/hfs.h + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * "XXX" in a comment is a note to myself to consider changing something. + */ + +#ifndef _HFS_H +#define _HFS_H + +#include + +#define HFS_NEW(X) ((X) = hfs_malloc(sizeof(*(X)))) +#define HFS_DELETE(X) { hfs_free((X), sizeof(*(X))); (X) = NULL; } + +/* offsets to various blocks */ +#define HFS_DD_BLK 0 /* Driver Descriptor block */ +#define HFS_PMAP_BLK 1 /* First block of partition map */ +#define HFS_MDB_BLK 2 /* Block (w/i partition) of MDB */ + +/* magic numbers for various disk blocks */ +#define HFS_DRVR_DESC_MAGIC 0x4552 /* "ER": driver descriptor map */ +#define HFS_OLD_PMAP_MAGIC 0x5453 /* "TS": old-type partition map */ +#define HFS_NEW_PMAP_MAGIC 0x504D /* "PM": new-type partition map */ +#define HFS_SUPER_MAGIC 0x4244 /* "BD": HFS MDB (super block) */ +#define HFS_MFS_SUPER_MAGIC 0xD2D7 /* MFS MDB (super block) */ + +/* magic numbers for various internal structures */ +#define HFS_FILE_MAGIC 0x4801 +#define HFS_DIR_MAGIC 0x4802 +#define HFS_MDB_MAGIC 0x4803 +#define HFS_EXT_MAGIC 0x4804 /* XXX currently unused */ +#define HFS_BREC_MAGIC 0x4811 /* XXX currently unused */ +#define HFS_BTREE_MAGIC 0x4812 +#define HFS_BNODE_MAGIC 0x4813 + +/* various FIXED size parameters */ +#define HFS_SECTOR_SIZE 512 /* size of an HFS sector */ +#define HFS_SECTOR_SIZE_BITS 9 /* log_2(HFS_SECTOR_SIZE) */ +#define HFS_NAMELEN 31 /* maximum length of an HFS filename */ +#define HFS_NAMEMAX (3*31) /* max size of ENCODED filename */ +#define HFS_BM_MAXBLOCKS (16) /* max number of bitmap blocks */ +#define HFS_BM_BPB (8*HFS_SECTOR_SIZE) /* number of bits per bitmap block */ +#define HFS_MAX_VALENCE 32767U +#define HFS_FORK_MAX (0x7FFFFFFF) + +/* Meanings of the drAtrb field of the MDB, + * Reference: _Inside Macintosh: Files_ p. 2-61 + */ +#define HFS_SB_ATTRIB_HLOCK 0x0080 +#define HFS_SB_ATTRIB_CLEAN 0x0100 +#define HFS_SB_ATTRIB_SPARED 0x0200 +#define HFS_SB_ATTRIB_SLOCK 0x8000 + +/* 2**16 - 1 */ +#define HFS_USHRT_MAX 65535 + +/* Some special File ID numbers */ +#define HFS_POR_CNID 1 /* Parent Of the Root */ +#define HFS_ROOT_CNID 2 /* ROOT directory */ +#define HFS_EXT_CNID 3 /* EXTents B-tree */ +#define HFS_CAT_CNID 4 /* CATalog B-tree */ +#define HFS_BAD_CNID 5 /* BAD blocks file */ + +/* values for hfs_cat_rec.cdrType */ +#define HFS_CDR_DIR 0x01 +#define HFS_CDR_FIL 0x02 +#define HFS_CDR_THD 0x03 +#define HFS_CDR_FTH 0x04 + +/* legal values for hfs_ext_key.FkType and hfs_file.fork */ +#define HFS_FK_DATA 0x00 +#define HFS_FK_RSRC 0xFF + +/* bits in hfs_fil_entry.Flags */ +#define HFS_FIL_LOCK 0x01 +#define HFS_FIL_THD 0x02 +#define HFS_FIL_USED 0x80 + +/* Access types used when requesting access to a B-node */ +#define HFS_LOCK_NONE 0x0000 /* Illegal */ +#define HFS_LOCK_READ 0x0001 /* read-only access */ +#define HFS_LOCK_RESRV 0x0002 /* might potentially modify */ +#define HFS_LOCK_WRITE 0x0003 /* will modify now (exclusive access) */ +#define HFS_LOCK_MASK 0x000f + +/* Flags field of the hfs_path_elem */ +#define HFS_BPATH_FIRST 0x0100 +#define HFS_BPATH_OVERFLOW 0x0200 +#define HFS_BPATH_UNDERFLOW 0x0400 +#define HFS_BPATH_MASK 0x0f00 + +/* Flags for hfs_bfind() */ +#define HFS_BFIND_EXACT 0x0010 +#define HFS_BFIND_LOCK 0x0020 + +/* Modes for hfs_bfind() */ +#define HFS_BFIND_WRITE (HFS_LOCK_RESRV|HFS_BFIND_EXACT|HFS_BFIND_LOCK) +#define HFS_BFIND_READ_EQ (HFS_LOCK_READ|HFS_BFIND_EXACT) +#define HFS_BFIND_READ_LE (HFS_LOCK_READ) +#define HFS_BFIND_INSERT (HFS_LOCK_RESRV|HFS_BPATH_FIRST|HFS_BPATH_OVERFLOW) +#define HFS_BFIND_DELETE \ + (HFS_LOCK_RESRV|HFS_BFIND_EXACT|HFS_BPATH_FIRST|HFS_BPATH_UNDERFLOW) + +/*======== HFS structures as they appear on the disk ========*/ + +/* Pascal-style string of up to 31 characters */ +struct hfs_name { + hfs_byte_t Len; + hfs_byte_t Name[31]; +}; + +typedef struct { + hfs_word_t v; + hfs_word_t h; +} hfs_point_t; + +typedef struct { + hfs_word_t top; + hfs_word_t left; + hfs_word_t bottom; + hfs_word_t right; +} hfs_rect_t; + +typedef struct { + hfs_lword_t fdType; + hfs_lword_t fdCreator; + hfs_word_t fdFlags; + hfs_point_t fdLocation; + hfs_word_t fdFldr; +} hfs_finfo_t; + +typedef struct { + hfs_word_t fdIconID; + hfs_byte_t fdUnused[8]; + hfs_word_t fdComment; + hfs_lword_t fdPutAway; +} hfs_fxinfo_t; + +typedef struct { + hfs_rect_t frRect; + hfs_word_t frFlags; + hfs_point_t frLocation; + hfs_word_t frView; +} hfs_dinfo_t; + +typedef struct { + hfs_point_t frScroll; + hfs_lword_t frOpenChain; + hfs_word_t frUnused; + hfs_word_t frComment; + hfs_lword_t frPutAway; +} hfs_dxinfo_t; + +union hfs_finder_info { + struct { + hfs_finfo_t finfo; + hfs_fxinfo_t fxinfo; + } file; + struct { + hfs_dinfo_t dinfo; + hfs_dxinfo_t dxinfo; + } dir; +}; + +/* A btree record key on disk */ +struct hfs_bkey { + hfs_byte_t KeyLen; /* number of bytes in the key */ + hfs_byte_t value[1]; /* (KeyLen) bytes of key */ +}; + +/* Cast to a pointer to a generic bkey */ +#define HFS_BKEY(X) (((void)((X)->KeyLen)), ((struct hfs_bkey *)(X))) + +/* The key used in the catalog b-tree: */ +struct hfs_cat_key { + hfs_byte_t KeyLen; /* number of bytes in the key */ + hfs_byte_t Resrv1; /* padding */ + hfs_lword_t ParID; /* CNID of the parent dir */ + struct hfs_name CName; /* The filename of the entry */ +}; + +/* The key used in the extents b-tree: */ +struct hfs_ext_key { + hfs_byte_t KeyLen; /* number of bytes in the key */ + hfs_byte_t FkType; /* HFS_FK_{DATA,RSRC} */ + hfs_lword_t FNum; /* The File ID of the file */ + hfs_word_t FABN; /* allocation blocks number*/ +}; + +/*======== Data structures kept in memory ========*/ + +/* + * struct hfs_mdb + * + * The fields from the MDB of an HFS filesystem + */ +struct hfs_mdb { + int magic; /* A magic number */ + unsigned char vname[28]; /* The volume name */ + hfs_sysmdb sys_mdb; /* superblock */ + hfs_buffer buf; /* The hfs_buffer + holding the real + superblock (aka VIB + or MDB) */ + hfs_buffer alt_buf; /* The hfs_buffer holding + the alternate superblock */ + hfs_buffer bitmap[16]; /* The hfs_buffer holding the + allocation bitmap */ + struct hfs_btree * ext_tree; /* Information about + the extents b-tree */ + struct hfs_btree * cat_tree; /* Information about + the catalog b-tree */ + hfs_u32 file_count; /* The number of + regular files in + the filesystem */ + hfs_u32 dir_count; /* The number of + directories in the + filesystem */ + hfs_u32 next_id; /* The next available + file id number */ + hfs_u32 clumpablks; /* The number of allocation + blocks to try to add when + extending a file */ + hfs_u32 write_count; /* The number of MDB + writes (a sort of + version number) */ + hfs_u32 fs_start; /* The first 512-byte + block represented + in the bitmap */ + hfs_u32 create_date; /* In network byte-order */ + hfs_u32 modify_date; /* In network byte-order */ + hfs_u32 backup_date; /* In network byte-order */ + hfs_u16 root_files; /* The number of + regular + (non-directory) + files in the root + directory */ + hfs_u16 root_dirs; /* The number of + directories in the + root directory */ + hfs_u16 fs_ablocks; /* The number of + allocation blocks + in the filesystem */ + hfs_u16 free_ablocks; /* The number of unused + allocation blocks + in the filesystem */ + hfs_u16 alloc_blksz; /* The number of + 512-byte blocks per + "allocation block" */ + hfs_u16 attrib; /* Attribute word */ + hfs_wait_queue rename_wait; + int rename_lock; + hfs_wait_queue bitmap_wait; + int bitmap_lock; +}; + +/* + * struct hfs_extent + * + * The offset to allocation block mapping for a given file is + * contained in a series of these structures. Each (struct + * hfs_extent) records up to three runs of contiguous allocation + * blocks. An allocation block is a contiguous group of physical + * blocks. + */ +struct hfs_extent { + int magic; /* A magic number */ + unsigned short start; /* Where in the file this record + begins (in allocation blocks) */ + unsigned short end; /* Where in the file this record + ends (in allocation blocks) */ + unsigned short block[3]; /* The allocation block on disk which + begins this extent */ + unsigned short length[3]; /* The number of allocation blocks + in this extent */ + struct hfs_extent *next; /* Next extent record for this file */ + struct hfs_extent *prev; /* Previous extent record for this file */ + int count; /* Number of times it is used */ +}; + +/* + * struct hfs_dir + * + * This structure holds information specific + * to a directory in an HFS filesystem. + */ +struct hfs_dir { + int magic; /* A magic number */ + hfs_u16 flags; + hfs_u16 dirs; /* Number of directories in this one */ + hfs_u16 files; /* Number of files in this directory */ + int readers; + hfs_wait_queue read_wait; + int writers; + hfs_wait_queue write_wait; +}; + +/* + * struct hfs_fork + * + * This structure holds the information + * specific to a single fork of a file. + */ +struct hfs_fork { + struct hfs_cat_entry *entry; /* The file this fork is part of */ + struct hfs_extent first; /* The first extent record for + this fork */ + struct hfs_extent *cache; /* The most-recently accessed + extent record for this fork */ + hfs_u32 lsize; /* The logical size in bytes */ + hfs_u32 psize; /* The phys size (512-byte blocks) */ + hfs_u8 fork; /* Which fork is this? */ +}; + +/* + * struct hfs_file + * + * This structure holds information specific + * to a file in an HFS filesystem. + */ +struct hfs_file { + int magic; + struct hfs_fork data_fork; + struct hfs_fork rsrc_fork; + hfs_u16 clumpablks; + hfs_u8 flags; +}; + +/* + * struct hfs_file + * + * This structure holds information about a + * file or directory in an HFS filesystem. + * + * 'wait' must remain 1st and 'next' 2nd since we do some pointer arithmetic. + */ +struct hfs_cat_entry { + hfs_wait_queue wait; + struct hfs_cat_entry *next; + struct hfs_cat_entry *prev; + struct hfs_cat_entry *hash_next; + struct hfs_cat_entry *hash_prev; + struct hfs_mdb *mdb; + hfs_sysentry sys_entry; + struct hfs_cat_key key; + union hfs_finder_info info; + hfs_u32 cnid; /* In network byte-order */ + hfs_u32 create_date; /* In network byte-order */ + hfs_u32 modify_date; /* In network byte-order */ + hfs_u32 backup_date; /* In network byte-order */ + unsigned short count; + unsigned char lock; + unsigned char dirt; + unsigned char key_dirt; + unsigned char deleted; + hfs_u8 type; + union { + struct hfs_dir dir; + struct hfs_file file; + } u; +}; + +/* + * struct hfs_bnode_ref + * + * A pointer to a (struct hfs_bnode) and the type of lock held on it. + */ +struct hfs_bnode_ref { + struct hfs_bnode *bn; + int lock_type; +}; + +/* + * struct hfs_belem + * + * An element of the path from the root of a B-tree to a leaf. + * Includes the reference to a (struct hfs_bnode), the index of + * the appropriate record in that node, and some flags. + */ +struct hfs_belem { + struct hfs_bnode_ref bnr; + int record; + int flags; +}; + +/* + * struct hfs_brec + * + * The structure returned by hfs_bfind() to describe the requested record. + */ +struct hfs_brec { + int keep_flags; + struct hfs_btree *tree; + struct hfs_belem *top; + struct hfs_belem *bottom; + struct hfs_belem elem[9]; + struct hfs_bkey *key; + void *data; /* The actual data */ +}; + +/*================ Function prototypes ================*/ + +/* bdelete.c */ +extern int hfs_bdelete(struct hfs_btree *, const struct hfs_bkey *); + +/* bfind.c */ +extern void hfs_brec_relse(struct hfs_brec *, struct hfs_belem *); +extern int hfs_bsucc(struct hfs_brec *, int); +extern int hfs_bfind(struct hfs_brec *, struct hfs_btree *, + const struct hfs_bkey *, int); + +/* binsert.c */ +extern int hfs_binsert(struct hfs_btree *, const struct hfs_bkey *, + const void *, hfs_u16); + +/* bitmap.c */ +extern hfs_u16 hfs_vbm_count_free(const struct hfs_mdb *, hfs_u16); +extern hfs_u16 hfs_vbm_search_free(const struct hfs_mdb *, hfs_u16 *); +extern int hfs_set_vbm_bits(struct hfs_mdb *, hfs_u16, hfs_u16); +extern int hfs_clear_vbm_bits(struct hfs_mdb *, hfs_u16, hfs_u16); + +/* bitops.c */ +extern hfs_u32 hfs_find_zero_bit(const hfs_u32 *, hfs_u32, hfs_u32); +extern hfs_u32 hfs_count_zero_bits(const hfs_u32 *, hfs_u32, hfs_u32); + +/* btree.c */ +extern struct hfs_btree *hfs_btree_init(struct hfs_mdb *, ino_t, + hfs_byte_t *, hfs_u32, hfs_u32); +extern void hfs_btree_free(struct hfs_btree *); +extern void hfs_btree_commit(struct hfs_btree *, hfs_byte_t *, hfs_lword_t); + +/* catalog.c */ +extern void hfs_cat_put(struct hfs_cat_entry *); +extern struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *, + const struct hfs_cat_key *); + +extern void hfs_cat_invalidate(struct hfs_mdb *); +extern void hfs_cat_commit(struct hfs_mdb *); +extern void hfs_cat_free(void); + +extern int hfs_cat_compare(const struct hfs_cat_key *, + const struct hfs_cat_key *); +extern void hfs_cat_build_key(hfs_u32, const struct hfs_name *, + struct hfs_cat_key *); +extern struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *); + +extern int hfs_cat_open(struct hfs_cat_entry *, struct hfs_brec *); +extern int hfs_cat_next(struct hfs_cat_entry *, struct hfs_brec *, + hfs_u16, hfs_u32 *, hfs_u8 *); +extern void hfs_cat_close(struct hfs_cat_entry *, struct hfs_brec *); + +extern int hfs_cat_create(struct hfs_cat_entry *, struct hfs_cat_key *, + hfs_u8, hfs_u32, hfs_u32, struct hfs_cat_entry **); +extern int hfs_cat_mkdir(struct hfs_cat_entry *, struct hfs_cat_key *, + struct hfs_cat_entry **); +extern int hfs_cat_delete(struct hfs_cat_entry *, struct hfs_cat_entry *, int); +extern int hfs_cat_move(struct hfs_cat_entry *, struct hfs_cat_entry *, + struct hfs_cat_entry *, struct hfs_cat_key *, + struct hfs_cat_entry **); + +/* extent.c */ +extern int hfs_ext_compare(const struct hfs_ext_key *, + const struct hfs_ext_key *); +extern void hfs_extent_in(struct hfs_fork *, const hfs_byte_t *); +extern void hfs_extent_out(const struct hfs_fork *, hfs_byte_t *); +extern int hfs_extent_map(struct hfs_fork *, int, int); +extern void hfs_extent_adj(struct hfs_fork *); +extern void hfs_extent_free(struct hfs_fork *); + +/* mdb.c */ +extern struct hfs_mdb *hfs_mdb_get(hfs_sysmdb, int, hfs_s32); +extern void hfs_mdb_commit(struct hfs_mdb *, int); +extern void hfs_mdb_put(struct hfs_mdb *, int); + +/* part_tbl.c */ +extern int hfs_part_find(hfs_sysmdb, int, int, hfs_s32 *, hfs_s32 *); + +/* string.c */ +extern unsigned int hfs_strhash(const struct hfs_name *); +extern int hfs_strcmp(const struct hfs_name *, const struct hfs_name *); +extern int hfs_streq(const struct hfs_name *, const struct hfs_name *); +extern void hfs_tolower(unsigned char *, int); + +/* sysdep.c */ +extern int hfs_prune_entry(struct hfs_cat_entry *); + +#endif diff -u --recursive --new-file v2.1.77/linux/fs/hfs/hfs_btree.h linux/fs/hfs/hfs_btree.h --- v2.1.77/linux/fs/hfs/hfs_btree.h Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/hfs_btree.h Sun Jan 4 10:40:17 1998 @@ -0,0 +1,268 @@ +/* + * linux/fs/hfs/hfs_btree.h + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the declarations of the private B-tree + * structures and functions. + * + * "XXX" in a comment is a note to myself to consider changing something. + */ + +#ifndef _HFS_BTREE_H +#define _HFS_BTREE_H + +#include "hfs.h" + +/*================ Variable-like macros ================*/ + +/* The stickiness of a (struct hfs_bnode) */ +#define HFS_NOT_STICKY 0 +#define HFS_STICKY 1 + +/* The number of hash buckets in a B-tree's bnode cache */ +#define HFS_CACHELEN 17 /* primes are best? */ + +/* + * Legal values for the 'ndType' field of a (struct NodeDescriptor) + * + * Reference: _Inside Macintosh: Files_ p. 2-65 + */ +#define ndIndxNode 0x00 /* An internal (index) node */ +#define ndHdrNode 0x01 /* The tree header node (node 0) */ +#define ndMapNode 0x02 /* Holds part of the bitmap of used nodes */ +#define ndLeafNode 0xFF /* A leaf (ndNHeight==1) node */ + +/*================ Function-like macros ================*/ + +/* Access the cache slot which should contain the desired node */ +#define bhash(tree, node) ((tree)->cache[(node) % HFS_CACHELEN]) + +/* round up to multiple of sizeof(hfs_u16) */ +#define ROUND(X) ((X + sizeof(hfs_u16) - 1) & ~(sizeof(hfs_u16)-1)) + +/* Refer to the (base-1) array of offsets in a bnode */ +#define RECTBL(X,N) \ + (((hfs_u16 *)(hfs_buffer_data((X)->buf)+HFS_SECTOR_SIZE))-(N)) + +/*================ Private data types ================*/ + +/* + * struct BTHdrRec + * + * The B-tree header record + * + * This data structure is stored in the first node (512-byte block) of + * each B-tree file. It contains important information about the + * B-tree. Most fields vary over the life of the tree and are + * indicated by a 'V' in the comments. The other fields are fixed for + * the life of the tree and are indicated by a 'F'. + * + * Reference: _Inside Macintosh: Files_ pp. 2-68 through 2-69 */ +struct BTHdrRec { + hfs_word_t bthDepth; /* (V) The number of levels in this B-tree */ + hfs_lword_t bthRoot; /* (V) The node number of the root node */ + hfs_lword_t bthNRecs; /* (V) The number of leaf records */ + hfs_lword_t bthFNode; /* (V) The number of the first leaf node */ + hfs_lword_t bthLNode; /* (V) The number of the last leaf node */ + hfs_word_t bthNodeSize; /* (F) The number of bytes in a node (=512) */ + hfs_word_t bthKeyLen; /* (F) The length of a key in an index node */ + hfs_lword_t bthNNodes; /* (V) The total number of nodes */ + hfs_lword_t bthFree; /* (V) The number of unused nodes */ + hfs_byte_t bthResv[76]; /* Reserved */ +}; + +/* + * struct NodeDescriptor + * + * The B-tree node descriptor. + * + * This structure begins each node in the B-tree file. It contains + * important information about the node's contents. 'V' and 'F' in + * the comments indicate fields that are variable or fixed over the + * life of a node, where the 'life' of a node is defined as the period + * between leaving and reentering the free pool. + * + * Reference: _Inside Macintosh: Files_ p. 2-64 + */ +struct NodeDescriptor { + hfs_lword_t ndFLink; /* (V) Number of the next node at this level */ + hfs_lword_t ndBLink; /* (V) Number of the prev node at this level */ + hfs_byte_t ndType; /* (F) The type of node */ + hfs_byte_t ndNHeight; /* (F) The level of this node (leaves=1) */ + hfs_word_t ndNRecs; /* (V) The number of records in this node */ + hfs_word_t ndResv2; /* Reserved */ +}; + +/* + * typedef hfs_cmpfn + * + * The type 'hfs_cmpfn' is a comparison function taking 2 keys and + * returning a positive, negative or zero integer according to the + * ordering of the two keys (just like strcmp() does for strings). + */ +typedef int (*hfs_cmpfn)(const void *, const void *); + +/* + * struct hfs_bnode + * + * An in-core B-tree node + * + * This structure holds information from the NodeDescriptor in native + * byte-order, a pointer to the buffer which contains the actual + * node and fields necessary for locking access to the node during + * updates. The use of the locking fields is explained with the + * locking functions. + */ +struct hfs_bnode { + int magic; /* Magic number to guard against + wild pointers */ + hfs_buffer buf; /* The buffer containing the + actual node */ + struct hfs_btree *tree; /* The tree to which this node + belongs */ + struct hfs_bnode *prev; /* Next node in this hash bucket */ + struct hfs_bnode *next; /* Previous node in this hash + bucket */ + int sticky; /* Boolean: non-zero means keep + this node in-core (set for + root and head) */ + hfs_u32 node; /* Node number */ + /* locking related fields: */ + hfs_wait_queue wqueue; /* Wait queue for write access */ + hfs_wait_queue rqueue; /* Wait queue for read or reserve + access */ + int count; /* Number of processes accessing + this node */ + int resrv; /* Boolean, true means a process + had placed a 'reservation' on + this node */ + int lock; /* Boolean, true means some + process has exclusive access, + so KEEP OUT */ + /* fields from the NodeDescriptor in native byte-order: */ + hfs_u32 ndFLink; + hfs_u32 ndBLink; + hfs_u16 ndNRecs; + hfs_u8 ndType; + hfs_u8 ndNHeight; +}; + +/* + * struct hfs_btree + * + * An in-core B-tree. + * + * This structure holds information from the BTHdrRec, MDB + * (superblock) and other information needed to work with the B-tree. + */ +struct hfs_btree { + int magic; /* Magic number to + guard against wild + pointers */ + hfs_cmpfn compare; /* Comparison function + for this tree */ + struct hfs_bnode head; /* in-core copy of node 0 */ + struct hfs_bnode *root; /* Pointer to the in-core + copy of the root node */ + hfs_sysmdb sys_mdb; /* The "device" holding + the filesystem */ + int reserved; /* bnodes claimed but + not yet used */ + struct hfs_bnode /* The bnode cache */ + *cache[HFS_CACHELEN]; + struct hfs_cat_entry entry; /* Fake catalog entry */ + int lock; + hfs_wait_queue wait; + int dirt; + /* Fields from the BTHdrRec in native byte-order: */ + hfs_u32 bthRoot; + hfs_u32 bthNRecs; + hfs_u32 bthFNode; + hfs_u32 bthLNode; + hfs_u32 bthNNodes; + hfs_u32 bthFree; + hfs_u16 bthKeyLen; + hfs_u16 bthDepth; +}; + +/*================ Global functions ================*/ + +/* Convert a (struct hfs_bnode *) and an index to the value of the + n-th offset in the bnode (N >= 1) to the offset */ +extern inline hfs_u16 bnode_offset(const struct hfs_bnode *bnode, int n) +{ return hfs_get_hs(RECTBL(bnode,n)); } + +/* Convert a (struct hfs_bnode *) and an index to the size of the + n-th record in the bnode (N >= 1) */ +extern inline hfs_u16 bnode_rsize(const struct hfs_bnode *bnode, int n) +{ return bnode_offset(bnode, n+1) - bnode_offset(bnode, n); } + +/* Convert a (struct hfs_bnode *) to the offset of the empty part */ +extern inline hfs_u16 bnode_end(const struct hfs_bnode *bnode) +{ return bnode_offset(bnode, bnode->ndNRecs + 1); } + +/* Convert a (struct hfs_bnode *) to the number of free bytes it contains */ +extern inline hfs_u16 bnode_freespace(const struct hfs_bnode *bnode) +{ return HFS_SECTOR_SIZE - bnode_end(bnode) + - (bnode->ndNRecs + 1)*sizeof(hfs_u16); } + +/* Convert a (struct hfs_bnode *) X and an index N to + the address of the record N in the bnode (N >= 1) */ +extern inline void *bnode_datastart(const struct hfs_bnode *bnode) +{ return (void *)(hfs_buffer_data(bnode->buf)+sizeof(struct NodeDescriptor)); } + +/* Convert a (struct hfs_bnode *) to the address of the empty part */ +extern inline void *bnode_dataend(const struct hfs_bnode *bnode) +{ return (void *)(hfs_buffer_data(bnode->buf) + bnode_end(bnode)); } + +/* Convert various pointers to address of record's key */ +extern inline void *bnode_key(const struct hfs_bnode *bnode, int n) +{ return (void *)(hfs_buffer_data(bnode->buf) + bnode_offset(bnode, n)); } +extern inline void *belem_key(const struct hfs_belem *elem) +{ return bnode_key(elem->bnr.bn, elem->record); } +extern inline void *brec_key(const struct hfs_brec *brec) +{ return belem_key(brec->bottom); } + +/* Convert various pointers to the address of a record */ +extern inline void *bkey_record(const struct hfs_bkey *key) +{ return (void *)key + ROUND(key->KeyLen + 1); } +extern inline void *bnode_record(const struct hfs_bnode *bnode, int n) +{ return bkey_record(bnode_key(bnode, n)); } +extern inline void *belem_record(const struct hfs_belem *elem) +{ return bkey_record(belem_key(elem)); } +extern inline void *brec_record(const struct hfs_brec *brec) +{ return bkey_record(brec_key(brec)); } + +/*================ Function Prototypes ================*/ + +/* balloc.c */ +extern int hfs_bnode_bitop(struct hfs_btree *, hfs_u32, int); +extern struct hfs_bnode_ref hfs_bnode_alloc(struct hfs_btree *); +extern int hfs_bnode_free(struct hfs_bnode_ref *); +extern void hfs_btree_extend(struct hfs_btree *); + +/* bins_del.c */ +extern void hfs_bnode_update_key(struct hfs_brec *, struct hfs_belem *, + struct hfs_bnode *, int); +extern void hfs_bnode_shift_right(struct hfs_bnode *, struct hfs_bnode *, int); +extern void hfs_bnode_shift_left(struct hfs_bnode *, struct hfs_bnode *, int); +extern int hfs_bnode_in_brec(hfs_u32 node, const struct hfs_brec *brec); + +/* bnode.c */ +extern void hfs_bnode_read(struct hfs_bnode *, struct hfs_btree *, + hfs_u32, int); +extern void hfs_bnode_relse(struct hfs_bnode_ref *); +extern struct hfs_bnode_ref hfs_bnode_find(struct hfs_btree *, hfs_u32, int); +extern void hfs_bnode_lock(struct hfs_bnode_ref *, int); +extern void hfs_bnode_delete(struct hfs_bnode *); +extern void hfs_bnode_commit(struct hfs_bnode *); + +/* brec.c */ +extern void hfs_brec_lock(struct hfs_brec *, struct hfs_belem *); +extern struct hfs_belem *hfs_brec_init(struct hfs_brec *, struct hfs_btree *, + int); +extern struct hfs_belem *hfs_brec_next(struct hfs_brec *); + +#endif diff -u --recursive --new-file v2.1.77/linux/fs/hfs/inode.c linux/fs/hfs/inode.c --- v2.1.77/linux/fs/hfs/inode.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/inode.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,423 @@ +/* + * linux/fs/hfs/inode.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains inode-related functions which do not depend on + * which scheme is being used to represent forks. + * + * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ Variable-like macros ================*/ + +#define HFS_VALID_MODE_BITS (S_IFREG | S_IFDIR | S_IRWXUGO) + +/*================ File-local functions ================*/ + +/* + * init_file_inode() + * + * Given an HFS catalog entry initialize an inode for a file. + */ +static void init_file_inode(struct inode *inode, hfs_u8 fork) +{ + struct hfs_fork *fk; + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + + if (!IS_NOEXEC(inode) && (fork == HFS_FK_DATA)) { + inode->i_mode = S_IRWXUGO | S_IFREG; + } else { + inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG; + } + + if (fork == HFS_FK_DATA) { + hfs_u32 type = hfs_get_nl(entry->info.file.finfo.fdType); + + fk = &entry->u.file.data_fork; + HFS_I(inode)->convert = + ((HFS_SB(inode->i_sb)->s_conv == 't') || + ((HFS_SB(inode->i_sb)->s_conv == 'a') && + ((type == htonl(0x54455854)) || /* "TEXT" */ + (type == htonl(0x7474726f))))); /* "ttro" */ + } else { + fk = &entry->u.file.rsrc_fork; + HFS_I(inode)->convert = 0; + } + HFS_I(inode)->fork = fk; + inode->i_size = fk->lsize; + inode->i_blocks = fk->psize; + inode->i_nlink = 1; +} + +/*================ Global functions ================*/ + +/* + * hfs_put_inode() + * + * This is the put_inode() entry in the super_operations for HFS + * filesystems. The purpose is to perform any filesystem-dependent + * cleanup necessary when the use-count of an inode falls to zero. + */ +void hfs_put_inode(struct inode * inode) +{ + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + + entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL; + hfs_cat_put(entry); + + if (inode->i_count == 1) { + struct hfs_hdr_layout *tmp = HFS_I(inode)->layout; + if (tmp) { + HFS_I(inode)->layout = NULL; + HFS_DELETE(tmp); + } + } +} + +/* + * hfs_notify_change() + * + * Based very closely on fs/msdos/inode.c by Werner Almesberger + * + * This is the notify_change() field in the super_operations structure + * for HFS file systems. The purpose is to take that changes made to + * an inode and apply then in a filesystem-dependent manner. In this + * case the process has a few of tasks to do: + * 1) prevent changes to the i_uid and i_gid fields. + * 2) map file permissions to the closest allowable permissions + * 3) Since multiple Linux files can share the same on-disk inode under + * HFS (for instance the data and resource forks of a file) a change + * to permissions must be applied to all other in-core inodes which + * correspond to the same HFS file. + */ +int hfs_notify_change(struct inode * inode, struct iattr * attr) +{ + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + struct dentry **de = entry->sys_entry; + struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); + int error, i; + + error = inode_change_ok(inode, attr); /* basic permission checks */ + if (error) { + /* Let netatalk's afpd think chmod() always succeeds */ + if (hsb->s_afpd && + (attr->ia_valid == (ATTR_MODE | ATTR_CTIME))) { + return 0; + } else { + return error; + } + } + + /* no uig/gid changes and limit which mode bits can be set */ + if (((attr->ia_valid & ATTR_UID) && + (attr->ia_uid != hsb->s_uid)) || + ((attr->ia_valid & ATTR_GID) && + (attr->ia_gid != hsb->s_gid)) || + ((attr->ia_valid & ATTR_MODE) && + (((entry->type == HFS_CDR_DIR) && + (attr->ia_mode != inode->i_mode))|| + (attr->ia_mode & ~HFS_VALID_MODE_BITS)))) { + return hsb->s_quiet ? 0 : error; + } + + if (entry->type == HFS_CDR_DIR) { + attr->ia_valid &= ~ATTR_MODE; + } else if (attr->ia_valid & ATTR_MODE) { + /* Only the 'w' bits can ever change and only all together. */ + if (attr->ia_mode & S_IWUSR) { + attr->ia_mode = inode->i_mode | S_IWUGO; + } else { + attr->ia_mode = inode->i_mode & ~S_IWUGO; + } + attr->ia_mode &= ~hsb->s_umask; + } + inode_setattr(inode, attr); + + /* We wouldn't want to mess with the sizes of the other fork */ + attr->ia_valid &= ~ATTR_SIZE; + + /* We must change all in-core inodes corresponding to this file. */ + for (i = 0; i < 4; ++i) { + if (de[i] && (de[i]->d_inode != inode)) { + inode_setattr(de[i]->d_inode, attr); + } + } + + /* Change the catalog entry if needed */ + if (attr->ia_valid & ATTR_MTIME) { + entry->modify_date = hfs_u_to_mtime(inode->i_mtime); + entry->dirt = 1; + } + if (attr->ia_valid & ATTR_MODE) { + hfs_u8 new_flags; + + if (inode->i_mode & S_IWUSR) { + new_flags = entry->u.file.flags & ~HFS_FIL_LOCK; + } else { + new_flags = entry->u.file.flags | HFS_FIL_LOCK; + } + + if (new_flags != entry->u.file.flags) { + entry->u.file.flags = new_flags; + entry->dirt = 1; + } + } + /* size changes handled in hfs_extent_adj() */ + + return 0; +} + +/* + * __hfs_iget() + * + * Given the MDB for a HFS filesystem, a 'key' and an 'entry' in + * the catalog B-tree and the 'type' of the desired file return the + * inode for that file/directory or NULL. Note that 'type' indicates + * whether we want the actual file or directory, or the corresponding + * metadata (AppleDouble header file or CAP metadata file). + * + * In an ideal world we could call iget() and would not need this + * function. However, since there is no way to even know the inode + * number until we've found the file/directory in the catalog B-tree + * that simply won't happen. + * + * The main idea here is to look in the catalog B-tree to get the + * vital info about the file or directory (including the file id which + * becomes the inode number) and then to call iget() and return the + * inode if it is complete. If it is not then we use the catalog + * entry to fill in the missing info, by calling the appropriate + * 'fillin' function. Note that these fillin functions are + * essentially hfs_*_read_inode() functions, but since there is no way + * to pass the catalog entry through iget() to such a read_inode() + * function, we have to call them after iget() returns an incomplete + * inode to us. This is pretty much the same problem faced in the NFS + * code, and pretty much the same solution. The SMB filesystem deals + * with this in a different way: by using the address of the + * kmalloc()'d space which holds the data as the inode number. + * + * XXX: Both this function and NFS's corresponding nfs_fhget() would + * benefit from a way to pass an additional (void *) through iget() to + * the VFS read_inode() function. + */ +struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type, + struct dentry *dentry) +{ + struct dentry **sys_entry; + struct super_block *sb; + struct inode *inode; + + if (!entry) { + return NULL; + } + + /* If there are several processes all calling __iget() for + the same inode then they will all get the same one back. + The first one to return from __iget() will notice that the + i_mode field of the inode is blank and KNOW that it is + the first to return. Therefore, it will set the appropriate + 'sys_entry' field in the entry and initialize the inode. + All the initialization must be done without sleeping, + or else other processes could end up using a partially + initialized inode. */ + + sb = entry->mdb->sys_mdb; + sys_entry = &entry->sys_entry[HFS_ITYPE_TO_INT(type)]; + + if (*sys_entry && (inode = (*sys_entry)->d_inode)) { + /* There is an existing inode for this file/dir. Use it. */ + ++inode->i_count; + hfs_cat_put(entry); + } else if (!(inode = iget(sb, ntohl(entry->cnid) | type)) || + (inode->i_dev != sb->s_dev)) { + /* Something went wrong */ + hfs_cat_put(entry); + } else if (inode->i_mode) { + /* The inode has been initialized by another process. + Note that if hfs_put_inode() is sleeping in hfs_cat_put() + then we still need to attach it to the entry. */ + if (*sys_entry) { + hfs_cat_put(entry); + } else { + *sys_entry = dentry; /* cache dentry */ + } + } else { + /* Initialize the inode */ + struct hfs_sb_info *hsb = HFS_SB(sb); + + inode->i_rdev = 0; + inode->i_ctime = inode->i_atime = inode->i_mtime = + hfs_m_to_utime(entry->modify_date); + inode->i_blksize = HFS_SECTOR_SIZE; + inode->i_uid = hsb->s_uid; + inode->i_gid = hsb->s_gid; + + memset(HFS_I(inode), 0, sizeof(struct hfs_inode_info)); + HFS_I(inode)->magic = HFS_INO_MAGIC; + HFS_I(inode)->entry = entry; + + hsb->s_ifill(inode, type); + if (!hsb->s_afpd && (entry->type == HFS_CDR_FIL) && + (entry->u.file.flags & HFS_FIL_LOCK)) { + inode->i_mode &= ~S_IWUGO; + } + inode->i_mode &= ~hsb->s_umask; + + if (!inode->i_mode) { + clear_inode(inode); + inode = NULL; + } + + *sys_entry = dentry; /* cache dentry */ + } + + return inode; +} + +/*================ Scheme-specific functions ================*/ + +/* + * hfs_cap_ifill() + * + * This function serves the same purpose as a read_inode() function does + * in other filesystems. It is called by __hfs_iget() to fill in + * the missing fields of an uninitialized inode under the CAP scheme. + */ +void hfs_cap_ifill(struct inode * inode, ino_t type) +{ + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + + HFS_I(inode)->d_drop_op = hfs_cap_drop_dentry; + if (type == HFS_CAP_FNDR) { + inode->i_size = sizeof(struct hfs_cap_info); + inode->i_blocks = 0; + inode->i_nlink = 1; + inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG; + inode->i_op = &hfs_cap_info_inode_operations; + } else if (entry->type == HFS_CDR_FIL) { + init_file_inode(inode, (type == HFS_CAP_DATA) ? + HFS_FK_DATA : HFS_FK_RSRC); + inode->i_op = &hfs_file_inode_operations; + } else { /* Directory */ + struct hfs_dir *hdir = &entry->u.dir; + + inode->i_blocks = 0; + inode->i_size = hdir->files + hdir->dirs + 5; + HFS_I(inode)->dir_size = 1; + if (type == HFS_CAP_NDIR) { + inode->i_mode = S_IRWXUGO | S_IFDIR; + inode->i_nlink = hdir->dirs + 4; + inode->i_op = &hfs_cap_ndir_inode_operations; + HFS_I(inode)->file_type = HFS_CAP_NORM; + } else if (type == HFS_CAP_FDIR) { + inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; + inode->i_nlink = 2; + inode->i_op = &hfs_cap_fdir_inode_operations; + HFS_I(inode)->file_type = HFS_CAP_FNDR; + } else if (type == HFS_CAP_RDIR) { + inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; + inode->i_nlink = 2; + inode->i_op = &hfs_cap_rdir_inode_operations; + HFS_I(inode)->file_type = HFS_CAP_RSRC; + } + } +} + +/* + * hfs_dbl_ifill() + * + * This function serves the same purpose as a read_inode() function does + * in other filesystems. It is called by __hfs_iget() to fill in + * the missing fields of an uninitialized inode under the AppleDouble + * scheme. + */ +void hfs_dbl_ifill(struct inode * inode, ino_t type) +{ + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + + HFS_I(inode)->d_drop_op = hfs_dbl_drop_dentry; + if (type == HFS_DBL_HDR) { + if (entry->type == HFS_CDR_FIL) { + init_file_inode(inode, HFS_FK_RSRC); + inode->i_size += HFS_DBL_HDR_LEN; + HFS_I(inode)->default_layout = &hfs_dbl_fil_hdr_layout; + } else { + inode->i_size = HFS_DBL_HDR_LEN; + inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG; + inode->i_nlink = 1; + HFS_I(inode)->default_layout = &hfs_dbl_dir_hdr_layout; + } + inode->i_op = &hfs_hdr_inode_operations; + } else if (entry->type == HFS_CDR_FIL) { + init_file_inode(inode, HFS_FK_DATA); + inode->i_op = &hfs_file_inode_operations; + } else { /* Directory */ + struct hfs_dir *hdir = &entry->u.dir; + + inode->i_blocks = 0; + inode->i_nlink = hdir->dirs + 2; + inode->i_size = 3 + 2 * (hdir->dirs + hdir->files); + inode->i_mode = S_IRWXUGO | S_IFDIR; + inode->i_op = &hfs_dbl_dir_inode_operations; + HFS_I(inode)->file_type = HFS_DBL_NORM; + HFS_I(inode)->dir_size = 2; + } +} + +/* + * hfs_nat_ifill() + * + * This function serves the same purpose as a read_inode() function does + * in other filesystems. It is called by __hfs_iget() to fill in + * the missing fields of an uninitialized inode under the Netatalk + * scheme. + */ +void hfs_nat_ifill(struct inode * inode, ino_t type) +{ + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + + HFS_I(inode)->d_drop_op = hfs_nat_drop_dentry; + if (type == HFS_NAT_HDR) { + if (entry->type == HFS_CDR_FIL) { + init_file_inode(inode, HFS_FK_RSRC); + inode->i_size += HFS_NAT_HDR_LEN; + } else { + inode->i_size = HFS_NAT_HDR_LEN; + inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG; + inode->i_nlink = 1; + } + inode->i_op = &hfs_hdr_inode_operations; + HFS_I(inode)->default_layout = &hfs_nat_hdr_layout; + } else if (entry->type == HFS_CDR_FIL) { + init_file_inode(inode, HFS_FK_DATA); + inode->i_op = &hfs_file_inode_operations; + } else { /* Directory */ + struct hfs_dir *hdir = &entry->u.dir; + + inode->i_blocks = 0; + inode->i_size = hdir->files + hdir->dirs + 3; + inode->i_mode = S_IRWXUGO | S_IFDIR; + HFS_I(inode)->dir_size = 1; + if (type == HFS_NAT_NDIR) { + inode->i_nlink = hdir->dirs + 3; + inode->i_op = &hfs_nat_ndir_inode_operations; + HFS_I(inode)->file_type = HFS_NAT_NORM; + } else if (type == HFS_NAT_HDIR) { + inode->i_nlink = 2; + inode->i_op = &hfs_nat_hdir_inode_operations; + HFS_I(inode)->file_type = HFS_NAT_HDR; + } + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/mdb.c linux/fs/hfs/mdb.c --- v2.1.77/linux/fs/hfs/mdb.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/mdb.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,298 @@ +/* + * linux/fs/hfs/mdb.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains functions for reading/writing the MDB. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + * + * The code in this file initializes some structures which contain + * pointers by calling memset(&foo, 0, sizeof(foo)). + * This produces the desired behavior only due to the non-ANSI + * assumption that the machine representation of NULL is all zeros. + */ + +#include "hfs.h" + +/*================ File-local data types ================*/ + +/* + * The HFS Master Directory Block (MDB). + * + * Also known as the Volume Information Block (VIB), this structure is + * the HFS equivalent of a superblock. + * + * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62 + */ +struct raw_mdb { + hfs_word_t drSigWord; /* Signature word indicating fs type */ + hfs_lword_t drCrDate; /* fs creation date/time */ + hfs_lword_t drLsMod; /* fs modification date/time */ + hfs_word_t drAtrb; /* fs attributes */ + hfs_word_t drNmFls; /* number of files in root directory */ + hfs_word_t drVBMSt; /* location (in 512-byte blocks) + of the volume bitmap */ + hfs_word_t drAllocPtr; /* location (in allocation blocks) + to begin next allocation search */ + hfs_word_t drNmAlBlks; /* number of allocation blocks */ + hfs_lword_t drAlBlkSiz; /* bytes in an allocation block */ + hfs_lword_t drClpSiz; /* clumpsize, the number of bytes to + allocate when extending a file */ + hfs_word_t drAlBlSt; /* location (in 512-byte blocks) + of the first allocation block */ + hfs_lword_t drNxtCNID; /* CNID to assign to the next + file or directory created */ + hfs_word_t drFreeBks; /* number of free allocation blocks */ + hfs_byte_t drVN[28]; /* the volume label */ + hfs_lword_t drVolBkUp; /* fs backup date/time */ + hfs_word_t drVSeqNum; /* backup sequence number */ + hfs_lword_t drWrCnt; /* fs write count */ + hfs_lword_t drXTClpSiz; /* clumpsize for the extents B-tree */ + hfs_lword_t drCTClpSiz; /* clumpsize for the catalog B-tree */ + hfs_word_t drNmRtDirs; /* number of directories in + the root directory */ + hfs_lword_t drFilCnt; /* number of files in the fs */ + hfs_lword_t drDirCnt; /* number of directories in the fs */ + hfs_byte_t drFndrInfo[32]; /* data used by the Finder */ + hfs_word_t drVCSize; /* MacOS caching parameter */ + hfs_word_t drVCBMSize; /* MacOS caching parameter */ + hfs_word_t drCtlCSize; /* MacOS caching parameter */ + hfs_lword_t drXTFlSize; /* bytes in the extents B-tree */ + hfs_byte_t drXTExtRec[12]; /* extents B-tree's first 3 extents */ + hfs_lword_t drCTFlSize; /* bytes in the catalog B-tree */ + hfs_byte_t drCTExtRec[12]; /* catalog B-tree's first 3 extents */ +}; + +/*================ Global functions ================*/ + +/* + * hfs_mdb_get() + * + * Build the in-core MDB for a filesystem, including + * the B-trees and the volume bitmap. + */ +struct hfs_mdb *hfs_mdb_get(hfs_sysmdb sys_mdb, int readonly, + hfs_s32 part_start) +{ + struct hfs_mdb *mdb; + hfs_buffer buf; + struct raw_mdb *raw; + unsigned int bs, block; + int lcv, limit; + hfs_buffer *bmbuf; + + if (!HFS_NEW(mdb)) { + hfs_warn("hfs_fs: out of memory\n"); + return NULL; + } + + memset(mdb, 0, sizeof(*mdb)); + mdb->magic = HFS_MDB_MAGIC; + mdb->sys_mdb = sys_mdb; + + /* See if this is an HFS filesystem */ + buf = hfs_buffer_get(sys_mdb, part_start + HFS_MDB_BLK, 1); + if (!hfs_buffer_ok(buf)) { + hfs_warn("hfs_fs: Unable to read superblock\n"); + goto bail2; + } + raw = (struct raw_mdb *)hfs_buffer_data(buf); + if (hfs_get_ns(raw->drSigWord) != htons(HFS_SUPER_MAGIC)) { + hfs_buffer_put(buf); + goto bail2; + } + mdb->buf = buf; + + bs = hfs_get_hl(raw->drAlBlkSiz); + if (!bs || bs > HFS_USHRT_MAX || (bs & (HFS_SECTOR_SIZE-1))) { + hfs_warn("hfs_fs: bad allocation block size %d != 512\n", bs); + goto bail1; + } + mdb->alloc_blksz = bs >> HFS_SECTOR_SIZE_BITS; + + /* These parameters are read from the MDB, and never written */ + mdb->create_date = hfs_get_hl(raw->drCrDate); + mdb->fs_ablocks = hfs_get_hs(raw->drNmAlBlks); + mdb->fs_start = hfs_get_hs(raw->drAlBlSt) + part_start; + mdb->backup_date = hfs_get_hl(raw->drVolBkUp); + mdb->clumpablks = (hfs_get_hl(raw->drClpSiz) / mdb->alloc_blksz) + >> HFS_SECTOR_SIZE_BITS; + memcpy(mdb->vname, raw->drVN, 28); + + /* These parameters are read from and written to the MDB */ + mdb->modify_date = hfs_get_nl(raw->drLsMod); + mdb->attrib = hfs_get_ns(raw->drAtrb); + mdb->free_ablocks = hfs_get_hs(raw->drFreeBks); + mdb->next_id = hfs_get_hl(raw->drNxtCNID); + mdb->write_count = hfs_get_hl(raw->drWrCnt); + mdb->root_files = hfs_get_hs(raw->drNmFls); + mdb->root_dirs = hfs_get_hs(raw->drNmRtDirs); + mdb->file_count = hfs_get_hl(raw->drFilCnt); + mdb->dir_count = hfs_get_hl(raw->drDirCnt); + + /* TRY to get the alternate (backup) MDB */ + lcv = mdb->fs_start + mdb->fs_ablocks * mdb->alloc_blksz; + limit = lcv + mdb->alloc_blksz; + for (; lcv < limit; ++lcv) { + buf = hfs_buffer_get(sys_mdb, lcv, 1); + if (hfs_buffer_ok(buf)) { + struct raw_mdb *tmp = + (struct raw_mdb *)hfs_buffer_data(buf); + + if (hfs_get_ns(tmp->drSigWord) == + htons(HFS_SUPER_MAGIC)) { + mdb->alt_buf = buf; + break; + } + hfs_buffer_put(buf); + } + } + if (mdb->alt_buf == NULL) { + hfs_warn("hfs_fs: unable to locate alternate MDB\n"); + hfs_warn("hfs_fs: continuing without an alternate MDB\n"); + } + + /* read in the bitmap */ + block = hfs_get_hs(raw->drVBMSt) + part_start; + bmbuf = mdb->bitmap; + lcv = (mdb->fs_ablocks + 4095) / 4096; + for ( ; lcv; --lcv, ++bmbuf, ++block) { + if (!hfs_buffer_ok(*bmbuf = + hfs_buffer_get(sys_mdb, block, 1))) { + hfs_warn("hfs_fs: unable to read volume bitmap\n"); + goto bail1; + } + } + + if (!(mdb->ext_tree = hfs_btree_init(mdb, htonl(HFS_EXT_CNID), + raw->drXTExtRec, + hfs_get_hl(raw->drXTFlSize), + hfs_get_hl(raw->drXTClpSiz))) || + !(mdb->cat_tree = hfs_btree_init(mdb, htonl(HFS_CAT_CNID), + raw->drCTExtRec, + hfs_get_hl(raw->drCTFlSize), + hfs_get_hl(raw->drCTClpSiz)))) { + hfs_warn("hfs_fs: unable to initialize data structures\n"); + goto bail1; + } + + if (!(mdb->attrib & htons(HFS_SB_ATTRIB_CLEAN))) { + hfs_warn("hfs_fs: WARNING: mounting unclean filesystem.\n"); + } else if (!readonly) { + /* Mark the volume uncleanly unmounted in case we crash */ + hfs_put_ns(mdb->attrib & htons(~HFS_SB_ATTRIB_CLEAN), + raw->drAtrb); + hfs_buffer_dirty(mdb->buf); + hfs_buffer_sync(mdb->buf); + } + + return mdb; + +bail1: + hfs_mdb_put(mdb, readonly); +bail2: + return NULL; +} + +/* + * hfs_mdb_commit() + * + * Description: + * This updates the MDB on disk (look also at hfs_write_super()). + * It does not check, if the superblock has been modified, or + * if the filesystem has been mounted read-only. It is mainly + * called by hfs_write_super() and hfs_btree_extend(). + * Input Variable(s): + * struct hfs_mdb *mdb: Pointer to the hfs MDB + * int backup; + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'mdb' points to a "valid" (struct hfs_mdb). + * Postconditions: + * The HFS MDB and on disk will be updated, by copying the possibly + * modified fields from the in memory MDB (in native byte order) to + * the disk block buffer. + * If 'backup' is non-zero then the alternate MDB is also written + * and the function doesn't return until it is actually on disk. + */ +void hfs_mdb_commit(struct hfs_mdb *mdb, int backup) +{ + struct raw_mdb *raw = (struct raw_mdb *)hfs_buffer_data(mdb->buf); + + /* Commit catalog entries to buffers */ + hfs_cat_commit(mdb); + + /* Commit B-tree data to buffers */ + hfs_btree_commit(mdb->cat_tree, raw->drCTExtRec, raw->drCTFlSize); + hfs_btree_commit(mdb->ext_tree, raw->drXTExtRec, raw->drXTFlSize); + + /* Update write_count and modify_date */ + ++mdb->write_count; + mdb->modify_date = hfs_time(); + + /* These parameters may have been modified, so write them back */ + hfs_put_nl(mdb->modify_date, raw->drLsMod); + hfs_put_hs(mdb->free_ablocks, raw->drFreeBks); + hfs_put_hl(mdb->next_id, raw->drNxtCNID); + hfs_put_hl(mdb->write_count, raw->drWrCnt); + hfs_put_hs(mdb->root_files, raw->drNmFls); + hfs_put_hs(mdb->root_dirs, raw->drNmRtDirs); + hfs_put_hl(mdb->file_count, raw->drFilCnt); + hfs_put_hl(mdb->dir_count, raw->drDirCnt); + + /* write MDB to disk */ + hfs_buffer_dirty(mdb->buf); + + /* write the backup MDB, not returning until it is written */ + if (backup && hfs_buffer_ok(mdb->alt_buf)) { + memcpy(hfs_buffer_data(mdb->alt_buf), + hfs_buffer_data(mdb->buf), HFS_SECTOR_SIZE); + hfs_buffer_dirty(mdb->alt_buf); + hfs_buffer_sync(mdb->alt_buf); + } +} + +/* + * hfs_mdb_put() + * + * Release the resources associated with the in-core MDB. + */ +void hfs_mdb_put(struct hfs_mdb *mdb, int readonly) { + int lcv; + + /* invalidate cached catalog entries */ + hfs_cat_invalidate(mdb); + + /* free the B-trees */ + hfs_btree_free(mdb->ext_tree); + hfs_btree_free(mdb->cat_tree); + + /* free the volume bitmap */ + for (lcv = 0; lcv < HFS_BM_MAXBLOCKS; ++lcv) { + hfs_buffer_put(mdb->bitmap[lcv]); + } + + /* update volume attributes */ + if (!readonly) { + struct raw_mdb *raw = + (struct raw_mdb *)hfs_buffer_data(mdb->buf); + hfs_put_ns(mdb->attrib, raw->drAtrb); + hfs_buffer_dirty(mdb->buf); + } + + /* free the buffers holding the primary and alternate MDBs */ + hfs_buffer_put(mdb->buf); + hfs_buffer_put(mdb->alt_buf); + + /* free the MDB */ + HFS_DELETE(mdb); +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/part_tbl.c linux/fs/hfs/part_tbl.c --- v2.1.77/linux/fs/hfs/part_tbl.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/part_tbl.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,244 @@ +/* + * linux/fs/hfs/part_tbl.c + * + * Copyright (C) 1996-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * Original code to handle the new style Mac partition table based on + * a patch contributed by Holger Schemel (aeglos@valinor.owl.de). + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + * + * The code in this file initializes some structures which contain + * pointers by calling memset(&foo, 0, sizeof(foo)). + * This produces the desired behavior only due to the non-ANSI + * assumption that the machine representation of NULL is all zeros. + */ + +#include "hfs.h" + +/*================ File-local data types ================*/ + +/* + * The Macintosh Driver Descriptor Block + * + * On partitioned Macintosh media this is block 0. + * We really only need the "magic number" to check for partitioned media. + */ +struct hfs_drvr_desc { + hfs_word_t ddSig; /* The signature word */ + /* a bunch more stuff we don't need */ +}; + +/* + * The new style Mac partition map + * + * For each partition on the media there is a physical block (512-byte + * block) containing one of these structures. These blocks are + * contiguous starting at block 1. + */ +struct new_pmap { + hfs_word_t pmSig; /* Signature bytes to verify + that this is a partition + map block */ + hfs_word_t reSigPad; /* padding */ + hfs_lword_t pmMapBlkCnt; /* (At least in block 1) this + is the number of partition + map blocks */ + hfs_lword_t pmPyPartStart; /* The physical block number + of the first block in this + partition */ + hfs_lword_t pmPartBlkCnt; /* The number of physical + blocks in this partition */ + hfs_byte_t pmPartName[32]; /* (null terminated?) string + giving the name of this + partition */ + hfs_byte_t pmPartType[32]; /* (null terminated?) string + giving the type of this + partition */ + /* a bunch more stuff we don't need */ +}; + +/* + * The old style Mac partition map + * + * The partition map consists for a 2-byte signature followed by an + * array of these structures. The map is terminated with an all-zero + * one of these. + */ +struct old_pmap { + hfs_word_t pdSig; /* Signature bytes */ + struct old_pmap_entry { + hfs_lword_t pdStart; + hfs_lword_t pdSize; + hfs_lword_t pdFSID; + } pdEntry[42]; +}; + +/*================ File-local functions ================*/ + +/* + * parse_new_part_table() + * + * Parse a new style partition map looking for the + * start and length of the 'part'th HFS partition. + */ +static int parse_new_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf, + int part, hfs_s32 *size, hfs_s32 *start) +{ + struct new_pmap *pm = (struct new_pmap *)hfs_buffer_data(buf); + hfs_u32 pmap_entries = hfs_get_hl(pm->pmMapBlkCnt); + int hfs_part = 0; + int entry; + + for (entry = 0; (entry < pmap_entries) && !(*start); ++entry) { + if (entry) { + /* read the next partition map entry */ + buf = hfs_buffer_get(sys_mdb, HFS_PMAP_BLK + entry, 1); + if (!hfs_buffer_ok(buf)) { + hfs_warn("hfs_fs: unable to " + "read partition map.\n"); + goto bail; + } + pm = (struct new_pmap *)hfs_buffer_data(buf); + if (hfs_get_ns(pm->pmSig) != + htons(HFS_NEW_PMAP_MAGIC)) { + hfs_warn("hfs_fs: invalid " + "entry in partition map\n"); + hfs_buffer_put(buf); + goto bail; + } + } + + /* look for an HFS partition */ + if (!memcmp(pm->pmPartType,"Apple_HFS",9) && + ((hfs_part++) == part)) { + /* Found it! */ + *start = hfs_get_hl(pm->pmPyPartStart); + *size = hfs_get_hl(pm->pmPartBlkCnt); + } + + hfs_buffer_put(buf); + } + + return 0; + +bail: + return 1; +} + +/* + * parse_old_part_table() + * + * Parse a old style partition map looking for the + * start and length of the 'part'th HFS partition. + */ +static int parse_old_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf, + int part, hfs_s32 *size, hfs_s32 *start) +{ + struct old_pmap *pm = (struct old_pmap *)hfs_buffer_data(buf); + struct old_pmap_entry *p = &pm->pdEntry[0]; + int hfs_part = 0; + + while ((p->pdStart || p->pdSize || p->pdFSID) && !(*start)) { + /* look for an HFS partition */ + if ((hfs_get_nl(p->pdFSID) == htonl(0x54465331)/*"TFS1"*/) && + ((hfs_part++) == part)) { + /* Found it! */ + *start = hfs_get_hl(p->pdStart); + *size = hfs_get_hl(p->pdSize); + } + ++p; + } + hfs_buffer_put(buf); + + return 0; +} + +/*================ Global functions ================*/ + +/* + * hfs_part_find() + * + * Parse the partition map looking for the + * start and length of the 'part'th HFS partition. + */ +int hfs_part_find(hfs_sysmdb sys_mdb, int part, int silent, + hfs_s32 *size, hfs_s32 *start) +{ + hfs_buffer buf; + hfs_u16 sig; + int dd_found = 0; + int retval = 1; + + /* Read block 0 to see if this media is partitioned */ + buf = hfs_buffer_get(sys_mdb, HFS_DD_BLK, 1); + if (!hfs_buffer_ok(buf)) { + hfs_warn("hfs_fs: Unable to read block 0.\n"); + goto done; + } + sig = hfs_get_ns(((struct hfs_drvr_desc *)hfs_buffer_data(buf))->ddSig); + hfs_buffer_put(buf); + + if (sig == htons(HFS_DRVR_DESC_MAGIC)) { + /* We are definitely on partitioned media. */ + dd_found = 1; + } + + buf = hfs_buffer_get(sys_mdb, HFS_PMAP_BLK, 1); + if (!hfs_buffer_ok(buf)) { + hfs_warn("hfs_fs: Unable to read block 1.\n"); + goto done; + } + + *size = *start = 0; + + switch (hfs_get_ns(hfs_buffer_data(buf))) { + case __constant_htons(HFS_OLD_PMAP_MAGIC): + retval = parse_old_part_table(sys_mdb, buf, part, size, start); + break; + + case __constant_htons(HFS_NEW_PMAP_MAGIC): + retval = parse_new_part_table(sys_mdb, buf, part, size, start); + break; + + default: + if (dd_found) { + /* The media claimed to have a partition map */ + if (!silent) { + hfs_warn("hfs_fs: This disk has an " + "unrecognized partition map type.\n"); + } + } else { + /* Conclude that the media is not partitioned */ + retval = 0; + } + goto done; + } + + if (!retval) { + if (*start == 0) { + if (part) { + hfs_warn("hfs_fs: unable to locate " + "HFS partition number %d.\n", part); + } else { + hfs_warn("hfs_fs: unable to locate any " + "HFS partitions.\n"); + } + retval = 1; + } else if (*size < 0) { + hfs_warn("hfs_fs: Partition size > 1 Terabyte.\n"); + retval = 1; + } else if (*start < 0) { + hfs_warn("hfs_fs: Partition begins beyond 1 " + "Terabyte.\n"); + retval = 1; + } + } +done: + return retval; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/string.c linux/fs/hfs/string.c --- v2.1.77/linux/fs/hfs/string.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/string.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,152 @@ +/* + * linux/fs/hfs/string.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the string comparison function for the + * Macintosh character set. + * + * The code in this file is derived from code which is copyright + * 1986, 1989, 1990 by Abacus Research and Development, Inc. (ARDI) + * It is used here by the permission of ARDI's president Cliff Matthews. + * + * If you discover bugs in this code please notify both the author of the + * Linux HFS file system: hargrove@sccm.stanford.edu (Paul H. Hargrove) + * and the author of ARDI's HFS code: ctm@ardi.com (Clifford T. Matthews) + * + * "XXX" in a comment is a note to myself to consider changing something. + */ + +#include "hfs.h" + +/*================ File-local variables ================*/ + +/* + * unsigned char caseorder[] + * + * Defines the lexical ordering of characters on the Macintosh + * + * Composition of the 'casefold' and 'order' tables from ARDI's code + * with the entry for 0x20 changed to match that for 0xCA to remove + * special case for those two characters. + */ +static unsigned char caseorder[256] = { +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, +0x20,0x22,0x23,0x28,0x29,0x2A,0x2B,0x2C,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36, +0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46, +0x47,0x48,0x57,0x59,0x5D,0x5F,0x66,0x68,0x6A,0x6C,0x72,0x74,0x76,0x78,0x7A,0x7E, +0x8C,0x8E,0x90,0x92,0x95,0x97,0x9E,0xA0,0xA2,0xA4,0xA7,0xA9,0xAA,0xAB,0xAC,0xAD, +0x4E,0x48,0x57,0x59,0x5D,0x5F,0x66,0x68,0x6A,0x6C,0x72,0x74,0x76,0x78,0x7A,0x7E, +0x8C,0x8E,0x90,0x92,0x95,0x97,0x9E,0xA0,0xA2,0xA4,0xA7,0xAF,0xB0,0xB1,0xB2,0xB3, +0x4A,0x4C,0x5A,0x60,0x7B,0x7F,0x98,0x4F,0x49,0x51,0x4A,0x4B,0x4C,0x5A,0x60,0x63, +0x64,0x65,0x6E,0x6F,0x70,0x71,0x7B,0x84,0x85,0x86,0x7F,0x80,0x9A,0x9B,0x9C,0x98, +0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0x94,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0x4D,0x81, +0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0x55,0x8A,0xCC,0x4D,0x81, +0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0x26,0x27,0xD4,0x20,0x49,0x4B,0x80,0x82,0x82, +0xD5,0xD6,0x24,0x25,0x2D,0x2E,0xD7,0xD8,0xA6,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, +0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, +0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF +}; + +/* + * unsigned char casefold[] + * + * Defines the mapping to lowercase characters on the Macintosh + * + * "Inverse" of the 'casefold' from ARDI's code. + */ +static unsigned char casefold[256] = { +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, +0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, +0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F, +0x41,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, +0x8A,0x8C,0x8D,0x8E,0x96,0x9A,0x9F,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, +0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, +0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xBE,0xBF, +0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, +0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0x88,0x8B,0x9B,0xCF,0xCF, +0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, +0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, +0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF +}; + +/*================ Global functions ================*/ + +/* + * Hash a string to an integer in a case-independent way + */ +unsigned int hfs_strhash(const struct hfs_name *cname) +{ + /* Currently just sum of the 'order' of first and last characters */ + return ((unsigned int)caseorder[cname->Name[0]] + + (unsigned int)caseorder[cname->Name[cname->Len - 1]]); +} + +/* + * Compare two strings in the HFS filename character ordering + * Returns positive, negative, or zero, not just 0 or (+/-)1 + * + * Equivalent to ARDI's call: + * ROMlib_RelString(s1+1, s2+1, true, false, (s1[0]<<16) | s2[0]) + */ +int hfs_strcmp(const struct hfs_name *s1, const struct hfs_name *s2) +{ + int len, tmp; + const unsigned char *p1, *p2; + + if (!s1 || !s2) { + return 0; + } + + len = (s1->Len > s2->Len) ? s2->Len : s1->Len; + p1 = s1->Name; + p2 = s2->Name; + + while (len--) { + if ((tmp = (int)caseorder[*(p1++)]-(int)caseorder[*(p2++)])) { + return tmp; + } + } + return s1->Len - s2->Len; +} + +/* + * Test for equality of two strings in the HFS filename character ordering. + */ +int hfs_streq(const struct hfs_name *s1, const struct hfs_name *s2) +{ + int len; + const unsigned char *p1, *p2; + + if (!s1 || !s2 || (s1->Len != s2->Len)) { + return 0; + } + + len = s1->Len; + p1 = s1->Name; + p2 = s2->Name; + + while (len--) { + if (caseorder[*(p1++)] != caseorder[*(p2++)]) { + return 0; + } + } + return 1; +} + +/* + * Convert a string to the Macintosh version of lower case. + */ +void hfs_tolower(unsigned char *p, int len) +{ + while (len--) { + *p = casefold[*p]; + ++p; + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/super.c linux/fs/hfs/super.c --- v2.1.77/linux/fs/hfs/super.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/super.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,517 @@ +/* + * linux/fs/hfs/super.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains hfs_read_super() some of the the super_ops and + * init_module() and cleanup_module(). The remaining super_ops are in + * inode.c since they deal with inodes. + * + * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + * + * The code in this file initializes some structures which contain + * pointers by calling memset(&foo, 0, sizeof(foo)). + * This produces the desired behavior only due to the non-ANSI + * assumption that the machine representation of NULL is all zeros. + */ + +#include "hfs.h" +#include +#include +#include + +#include +#include +#include + +/*================ Forward declarations ================*/ + +static void hfs_read_inode(struct inode *inode); +static void hfs_put_super(struct super_block *); +static int hfs_statfs(struct super_block *, struct statfs *, int); +static void hfs_write_super(struct super_block *); + +/*================ Global variables ================*/ + +static struct super_operations hfs_super_operations = { + hfs_read_inode, /* read_inode */ + NULL, /* write_inode */ + hfs_put_inode, /* put_inode - in inode.c */ + NULL, /* delete inode */ + hfs_notify_change, /* notify_change - in inode.c */ + hfs_put_super, /* put_super */ + hfs_write_super, /* write_super */ + hfs_statfs, /* statfs */ + NULL /* remount_fs */ +}; + +/*================ File-local variables ================*/ + +static struct file_system_type hfs_fs = { + "hfs", + FS_REQUIRES_DEV, + hfs_read_super, + NULL}; + +/*================ File-local functions ================*/ + +/* + * hfs_read_inode() + * + * this doesn't actually do much. hfs_iget actually fills in the + * necessary inode information. + */ +static void hfs_read_inode(struct inode *inode) +{ + inode->i_mode = 0; + inode->i_op = NULL; +} + + +/* + * hfs_write_super() + * + * Description: + * This function is called by the VFS only. When the filesystem + * is mounted r/w it updates the MDB on disk. + * Input Variable(s): + * struct super_block *sb: Pointer to the hfs superblock + * Output Variable(s): + * NONE + * Returns: + * void + * Preconditions: + * 'sb' points to a "valid" (struct super_block). + * Postconditions: + * The MDB is marked 'unsuccessfully unmounted' by clearing bit 8 of drAtrb + * (hfs_put_super() must set this flag!). Some MDB fields are updated + * and the MDB buffer is written to disk by calling hfs_mdb_commit(). + */ +static void hfs_write_super(struct super_block *sb) +{ + struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb; + + /* is this a valid hfs superblock? */ + if (!sb || sb->s_magic != HFS_SUPER_MAGIC) { + return; + } + + if (!(sb->s_flags & MS_RDONLY)) { + /* sync everything to the buffers */ + hfs_mdb_commit(mdb, 0); + } + sb->s_dirt = 0; +} + +/* + * hfs_put_super() + * + * This is the put_super() entry in the super_operations structure for + * HFS filesystems. The purpose is to release the resources + * associated with the superblock sb. + */ +static void hfs_put_super(struct super_block *sb) +{ + struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb; + + lock_super(sb); + + if (!(sb->s_flags & MS_RDONLY)) { + hfs_mdb_commit(mdb, 0); + sb->s_dirt = 0; + } + + /* release the MDB's resources */ + hfs_mdb_put(mdb, sb->s_flags & MS_RDONLY); + + /* restore default blocksize for the device */ + set_blocksize(sb->s_dev, BLOCK_SIZE); + + /* invalidate the superblock */ + sb->s_dev = 0; + + MOD_DEC_USE_COUNT; + + unlock_super(sb); + return; +} + +/* + * hfs_statfs() + * + * This is the statfs() entry in the super_operations structure for + * HFS filesystems. The purpose is to return various data about the + * filesystem. + */ +static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len) +{ + struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb; + struct statfs tmp; + + tmp.f_type = HFS_SUPER_MAGIC; + tmp.f_bsize = HFS_SECTOR_SIZE; + tmp.f_blocks = mdb->alloc_blksz * mdb->fs_ablocks; + tmp.f_bfree = mdb->alloc_blksz * mdb->free_ablocks; + tmp.f_bavail = tmp.f_bfree; + tmp.f_files = -1; /* According to the statfs manual page, -1 is the */ + tmp.f_ffree = -1; /* correct value when the meaning is undefined. */ + tmp.f_namelen = HFS_NAMELEN; + + return copy_to_user(buf, &tmp, len) ? -EFAULT : 0; +} + +/* + * parse_options() + * + * adapted from linux/fs/msdos/inode.c written 1992,93 by Werner Almesberger + * This function is called by hfs_read_super() to parse the mount options. + */ +static int parse_options(char *options, struct hfs_sb_info *hsb, int *part) +{ + char *this_char, *value; + char names, fork; + + /* initialize the sb with defaults */ + memset(hsb, 0, sizeof(*hsb)); + hsb->magic = HFS_SB_MAGIC; + hsb->s_uid = current->uid; + hsb->s_gid = current->gid; + hsb->s_umask = current->fs->umask; + hsb->s_type = 0x3f3f3f3f; /* == '????' */ + hsb->s_creator = 0x3f3f3f3f; /* == '????' */ + hsb->s_lowercase = 0; + hsb->s_quiet = 0; + hsb->s_afpd = 0; + hsb->s_conv = 'b'; + names = '?'; + fork = '?'; + *part = 0; + + if (!options) { + goto done; + } + for (this_char = strtok(options,","); this_char; + this_char = strtok(NULL,",")) { + if ((value = strchr(this_char,'=')) != NULL) { + *value++ = 0; + } + /* Numeric-valued options */ + if (!strcmp(this_char,"uid")) { + if (!value || !*value) { + return 0; + } + hsb->s_uid = simple_strtoul(value,&value,0); + if (*value) { + return 0; + } + } else if (!strcmp(this_char,"gid")) { + if (!value || !*value) { + return 0; + } + hsb->s_gid = simple_strtoul(value,&value,0); + if (*value) { + return 0; + } + } else if (!strcmp(this_char,"umask")) { + if (!value || !*value) { + return 0; + } + hsb->s_umask = simple_strtoul(value,&value,8); + if (*value) { + return 0; + } + } else if (!strcmp(this_char,"part")) { + if (!value || !*value) { + return 0; + } + *part = simple_strtoul(value,&value,0); + if (*value) { + return 0; + } + /* String-valued options */ + } else if (!strcmp(this_char,"type") && value) { + if (strlen(value) != 4) { + return 0; + } + hsb->s_type = hfs_get_nl(value); + } else if (!strcmp(this_char,"creator") && value) { + if (strlen(value) != 4) { + return 0; + } + hsb->s_creator = hfs_get_nl(value); + /* Boolean-valued options */ + } else if (!strcmp(this_char,"quiet")) { + if (value) { + return 0; + } + hsb->s_quiet = 1; + } else if (!strcmp(this_char,"afpd")) { + if (value) { + return 0; + } + hsb->s_afpd = 1; + /* Multiple choice options */ + } else if (!strcmp(this_char,"names") && value) { + if ((*value && !value[1] && strchr("ntal78c",*value)) || + !strcmp(value,"netatalk") || + !strcmp(value,"trivial") || + !strcmp(value,"alpha") || + !strcmp(value,"latin") || + !strcmp(value,"7bit") || + !strcmp(value,"8bit") || + !strcmp(value,"cap")) { + names = *value; + } else { + return 0; + } + } else if (!strcmp(this_char,"fork") && value) { + if ((*value && !value[1] && strchr("nsdc",*value)) || + !strcmp(value,"netatalk") || + !strcmp(value,"single") || + !strcmp(value,"double") || + !strcmp(value,"cap")) { + fork = *value; + } else { + return 0; + } + } else if (!strcmp(this_char,"case") && value) { + if ((*value && !value[1] && strchr("la",*value)) || + !strcmp(value,"lower") || + !strcmp(value,"asis")) { + hsb->s_lowercase = (*value == 'l'); + } else { + return 0; + } + } else if (!strcmp(this_char,"conv") && value) { + if ((*value && !value[1] && strchr("bta",*value)) || + !strcmp(value,"binary") || + !strcmp(value,"text") || + !strcmp(value,"auto")) { + hsb->s_conv = *value; + } else { + return 0; + } + } else { + return 0; + } + } + +done: + /* Parse the "fork" and "names" options */ + if (fork == '?') { + fork = hsb->s_afpd ? 'n' : 'c'; + } + switch (fork) { + default: + case 'c': + hsb->s_ifill = hfs_cap_ifill; + hsb->s_reserved1 = hfs_cap_reserved1; + hsb->s_reserved2 = hfs_cap_reserved2; + break; + + case 's': + hfs_warn("hfs_fs: AppleSingle not yet implemented.\n"); + return 0; + /* break; */ + + case 'd': + hsb->s_ifill = hfs_dbl_ifill; + hsb->s_reserved1 = hfs_dbl_reserved1; + hsb->s_reserved2 = hfs_dbl_reserved2; + break; + + case 'n': + hsb->s_ifill = hfs_nat_ifill; + hsb->s_reserved1 = hfs_nat_reserved1; + hsb->s_reserved2 = hfs_nat_reserved2; + break; + } + + if (names == '?') { + names = fork; + } + switch (names) { + default: + case 'n': + hsb->s_nameout = hfs_colon2mac; + hsb->s_namein = hfs_mac2nat; + break; + + case 'c': + hsb->s_nameout = hfs_colon2mac; + hsb->s_namein = hfs_mac2cap; + break; + + case 't': + hsb->s_nameout = hfs_triv2mac; + hsb->s_namein = hfs_mac2triv; + break; + + case '7': + hsb->s_nameout = hfs_prcnt2mac; + hsb->s_namein = hfs_mac2seven; + break; + + case '8': + hsb->s_nameout = hfs_prcnt2mac; + hsb->s_namein = hfs_mac2eight; + break; + + case 'l': + hsb->s_nameout = hfs_latin2mac; + hsb->s_namein = hfs_mac2latin; + break; + + case 'a': /* 's' and 'd' are unadvertised aliases for 'alpha', */ + case 's': /* since 'alpha' is the default if fork=s or fork=d. */ + case 'd': /* (It is also helpful for poor typists!) */ + hsb->s_nameout = hfs_prcnt2mac; + hsb->s_namein = hfs_mac2alpha; + break; + } + + return 1; +} + +/*================ Global functions ================*/ + +/* + * hfs_read_super() + * + * This is the function that is responsible for mounting an HFS + * filesystem. It performs all the tasks necessary to get enough data + * from the disk to read the root inode. This includes parsing the + * mount options, dealing with Macintosh partitions, reading the + * superblock and the allocation bitmap blocks, calling + * hfs_btree_init() to get the necessary data about the extents and + * catalog B-trees and, finally, reading the root inode into memory. + */ +struct super_block *hfs_read_super(struct super_block *s, void *data, + int silent) +{ + struct hfs_mdb *mdb; + struct hfs_cat_key key; + kdev_t dev = s->s_dev; +#ifndef CONFIG_MAC_PARTITION + hfs_s32 part_size, part_start; +#endif + struct inode *root_inode; + int part; + + if (!parse_options((char *)data, HFS_SB(s), &part)) { + hfs_warn("hfs_fs: unable to parse mount options.\n"); + goto bail3; + } + + /* in case someone tries to unload the module while we wait on I/O */ + MOD_INC_USE_COUNT; + + lock_super(s); + + /* set the device driver to 512-byte blocks */ + set_blocksize(dev, HFS_SECTOR_SIZE); + + /* look for a partition table and find the correct partition */ +#ifndef CONFIG_MAC_PARTITION + if (hfs_part_find(s, part, silent, &part_size, &part_start)) { + goto bail2; + } + + mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start); +#else + mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, 0); +#endif + if (!mdb) { + if (!silent) { + printk("VFS: Can't find a HFS filesystem on dev %s.\n", + kdevname(dev)); + } + goto bail2; + } + HFS_SB(s)->s_mdb = mdb; + + if (HFS_ITYPE(mdb->next_id) != 0) { + hfs_warn("hfs_fs: too many files.\n"); + goto bail1; + } + + s->s_magic = HFS_SUPER_MAGIC; + s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS; + s->s_blocksize = HFS_SECTOR_SIZE; + s->s_op = &hfs_super_operations; + + /* try to get the root inode */ + hfs_cat_build_key(htonl(HFS_POR_CNID), + (struct hfs_name *)(mdb->vname), &key); + + root_inode = hfs_iget(hfs_cat_get(mdb, &key), HFS_ITYPE_NORM, NULL); + if (!root_inode) + goto bail_no_root; + + /* cache the dentry in the inode */ + s->s_root = + HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] = + d_alloc_root(root_inode, NULL); + if (!s->s_root) + goto bail_no_root; + + /* everything's okay */ + unlock_super(s); + return s; + +bail_no_root: + hfs_warn("hfs_fs: get root inode failed.\n"); + iput(root_inode); +bail1: + hfs_mdb_put(mdb, s->s_flags & MS_RDONLY); +bail2: + set_blocksize(dev, BLOCK_SIZE); + MOD_DEC_USE_COUNT; + unlock_super(s); +bail3: + s->s_dev = 0; + return NULL; +} + +__initfunc(int init_hfs_fs(void)) +{ + return register_filesystem(&hfs_fs); +} + +#ifdef MODULE +int init_module(void) { + int error; + +#if defined(DEBUG_SIZES) || defined(DEBUG_ALL) + hfs_warn("HFS inode: %d bytes available\n", + sizeof(struct ext2_inode_info)-sizeof(struct hfs_inode_info)); + hfs_warn("HFS super_block: %d bytes available\n", + sizeof(struct ext2_sb_info)-sizeof(struct hfs_sb_info)); + if ((sizeof(struct hfs_inode_info)>sizeof(struct ext2_inode_info)) || + (sizeof(struct hfs_sb_info)>sizeof(struct ext2_sb_info))) { + return -ENOMEM; /* well sort of */ + } +#endif + error = init_hfs_fs(); + if (!error) { + /* register_symtab(NULL); */ + } + return error; +} + +void cleanup_module(void) { + hfs_cat_free(); + unregister_filesystem(&hfs_fs); +} +#endif + +#if defined(DEBUG_ALL) || defined(DEBUG_MEM) +long int hfs_alloc = 0; +#endif diff -u --recursive --new-file v2.1.77/linux/fs/hfs/sysdep.c linux/fs/hfs/sysdep.c --- v2.1.77/linux/fs/hfs/sysdep.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/sysdep.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,52 @@ +/* + * linux/fs/hfs/sysdep.c + * + * Copyright (C) 1996 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the code to do various system dependent things. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/* + * hfs_buffer_get() + * + * Return a buffer for the 'block'th block of the media. + * If ('read'==0) then the buffer is not read from disk. + */ +hfs_buffer hfs_buffer_get(hfs_sysmdb sys_mdb, int block, int read) { + hfs_buffer tmp = HFS_BAD_BUFFER; + + if (read) { + tmp = bread(sys_mdb->s_dev, block, HFS_SECTOR_SIZE); + } else { + tmp = getblk(sys_mdb->s_dev, block, HFS_SECTOR_SIZE); + if (tmp) { + mark_buffer_uptodate(tmp, 1); + } + } + if (!tmp) { + hfs_error("hfs_fs: unable to read block 0x%08x from dev %s\n", + block, hfs_mdb_name(sys_mdb)); + } + + return tmp; +} + +/* catalog.c needs a re-write. as a kludge, we throw away all of + * the dcache if we need more entries. */ +int hfs_prune_entry(struct hfs_cat_entry *entry) +{ + shrink_dcache_sb(entry->mdb->sys_mdb); + return 1; +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/trans.c linux/fs/hfs/trans.c --- v2.1.77/linux/fs/hfs/trans.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/trans.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,556 @@ +/* + * linux/fs/hfs/trans.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains routines for converting between the Macintosh + * character set and various other encodings. This includes dealing + * with ':' vs. '/' as the path-element separator. + * + * Latin-1 translation based on code contributed by Holger Schemel + * (aeglos@valinor.owl.de). + * + * The '8-bit', '7-bit ASCII' and '7-bit alphanumeric' encodings are + * implementations of the three encodings recommended by Apple in the + * document "AppleSingle/AppleDouble Formats: Developer's Note + * (9/94)". This document is available from Apple's Technical + * Information Library from the World Wide Web server + * www.info.apple.com. + * + * The 'CAP' encoding is an implementation of the naming scheme used + * by the Columbia AppleTalk Package, available for anonymous FTP from + * ????. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#include "hfs.h" +#include +#include +#include + +/*================ File-local variables ================*/ + +/* int->ASCII map for a single hex digit */ +static char hex[16] = {'0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f'}; +/* + * Latin-1 to Mac character set map + * + * For the sake of consistency this map is generated from the Mac to + * Latin-1 map the first time it is needed. This means there is just + * one map to maintain. + */ +static unsigned char latin2mac_map[128]; /* initially all zero */ + +/* + * Mac to Latin-1 map for the upper 128 characters (both have ASCII in + * the lower 128 positions) + */ +static unsigned char mac2latin_map[128] = { + 0xC4, 0xC5, 0xC7, 0xC9, 0xD1, 0xD6, 0xDC, 0xE1, + 0xE0, 0xE2, 0xE4, 0xE3, 0xE5, 0xE7, 0xE9, 0xE8, + 0xEA, 0xEB, 0xED, 0xEC, 0xEE, 0xEF, 0xF1, 0xF3, + 0xF2, 0xF4, 0xF6, 0xF5, 0xFA, 0xF9, 0xFB, 0xFC, + 0x00, 0xB0, 0xA2, 0xA3, 0xA7, 0xB7, 0xB6, 0xDF, + 0xAE, 0xA9, 0x00, 0xB4, 0xA8, 0x00, 0xC6, 0xD8, + 0x00, 0xB1, 0x00, 0x00, 0xA5, 0xB5, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0xAA, 0xBA, 0x00, 0xE6, 0xF8, + 0xBF, 0xA1, 0xAC, 0x00, 0x00, 0x00, 0x00, 0xAB, + 0xBB, 0x00, 0xA0, 0xC0, 0xC3, 0xD5, 0x00, 0x00, + 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0x00, + 0xFF, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xB8, 0x00, 0x00, 0xC2, 0xCA, 0xC1, + 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0xD3, 0xD4, + 0x00, 0xD2, 0xDA, 0xDB, 0xD9, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/*================ File-local functions ================*/ + +/* + * dehex() + * + * Given a hexadecimal digit in ASCII, return the integer representation. + */ +static inline const unsigned char dehex(char c) { + if ((c>='0')&&(c<='9')) { + return c-'0'; + } + if ((c>='a')&&(c<='f')) { + return c-'a'+10; + } + if ((c>='A')&&(c<='F')) { + return c-'A'+10; + } + return 0xff; +} + +/*================ Global functions ================*/ + +/* + * hfs_mac2nat() + * + * Given a 'Pascal String' (a string preceded by a length byte) in + * the Macintosh character set produce the corresponding filename using + * the Netatalk name-mangling scheme, returning the length of the + * mangled filename. Note that the output string is not NULL terminated. + * + * The name-mangling works as follows: + * Characters 32-126 (' '-'~') except '/' and any initial '.' are passed + * unchanged from input to output. The remaining characters are replaced + * by three characters: ':xx' where xx is the hexadecimal representation + * of the character, using lowercase 'a' through 'f'. + */ +int hfs_mac2nat(char *out, const struct hfs_name *in) { + unsigned char c; + const unsigned char *p = in->Name; + int len = in->Len; + int count = 0; + + /* Special case for .AppleDesktop which in the + distant future may be a pseudodirectory. */ + if (strncmp(".AppleDesktop", p, len) == 0) { + strncpy(out, p, 13); + return 13; + } + + while (len--) { + c = *p++; + if ((c<32) || (c=='/') || (c>126) || (!count && (c=='.'))) { + *out++ = ':'; + *out++ = hex[(c>>4) & 0xf]; + *out++ = hex[c & 0xf]; + count += 3; + } else { + *out++ = c; + count++; + } + } + return count; +} + +/* + * hfs_mac2cap() + * + * Given a 'Pascal String' (a string preceded by a length byte) in + * the Macintosh character set produce the corresponding filename using + * the CAP name-mangling scheme, returning the length of the mangled + * filename. Note that the output string is not NULL terminated. + * + * The name-mangling works as follows: + * Characters 32-126 (' '-'~') except '/' are passed unchanged from + * input to output. The remaining characters are replaced by three + * characters: ':xx' where xx is the hexadecimal representation of the + * character, using lowercase 'a' through 'f'. + */ +int hfs_mac2cap(char *out, const struct hfs_name *in) { + unsigned char c; + const unsigned char *p = in->Name; + int len = in->Len; + int count = 0; + + while (len--) { + c = *p++; + if ((c<32) || (c=='/') || (c>126)) { + *out++ = ':'; + *out++ = hex[(c>>4) & 0xf]; + *out++ = hex[c & 0xf]; + count += 3; + } else { + *out++ = c; + count++; + } + } + return count; +} + +/* + * hfs_mac2eight() + * + * Given a 'Pascal String' (a string preceded by a length byte) in + * the Macintosh character set produce the corresponding filename using + * the '8-bit' name-mangling scheme, returning the length of the + * mangled filename. Note that the output string is not NULL + * terminated. + * + * This is one of the three recommended naming conventions described + * in Apple's document "AppleSingle/AppleDouble Formats: Developer's + * Note (9/94)" + * + * The name-mangling works as follows: + * Characters 0, '%' and '/' are replaced by three characters: '%xx' + * where xx is the hexadecimal representation of the character, using + * lowercase 'a' through 'f'. All other characters are passed + * unchanged from input to output. Note that this format is mainly + * implemented for completeness and is rather hard to read. + */ +int hfs_mac2eight(char *out, const struct hfs_name *in) { + unsigned char c; + const unsigned char *p = in->Name; + int len = in->Len; + int count = 0; + + while (len--) { + c = *p++; + if (!c || (c=='/') || (c=='%')) { + *out++ = '%'; + *out++ = hex[(c>>4) & 0xf]; + *out++ = hex[c & 0xf]; + count += 3; + } else { + *out++ = c; + count++; + } + } + return count; +} + +/* + * hfs_mac2seven() + * + * Given a 'Pascal String' (a string preceded by a length byte) in + * the Macintosh character set produce the corresponding filename using + * the '7-bit ASCII' name-mangling scheme, returning the length of the + * mangled filename. Note that the output string is not NULL + * terminated. + * + * This is one of the three recommended naming conventions described + * in Apple's document "AppleSingle/AppleDouble Formats: Developer's + * Note (9/94)" + * + * The name-mangling works as follows: + * Characters 0, '%', '/' and 128-255 are replaced by three + * characters: '%xx' where xx is the hexadecimal representation of the + * character, using lowercase 'a' through 'f'. All other characters + * are passed unchanged from input to output. Note that control + * characters (including newline) and space are unchanged make reading + * these filenames difficult. + */ +int hfs_mac2seven(char *out, const struct hfs_name *in) { + unsigned char c; + const unsigned char *p = in->Name; + int len = in->Len; + int count = 0; + + while (len--) { + c = *p++; + if (!c || (c=='/') || (c=='%') || (c&0x80)) { + *out++ = '%'; + *out++ = hex[(c>>4) & 0xf]; + *out++ = hex[c & 0xf]; + count += 3; + } else { + *out++ = c; + count++; + } + } + return count; +} + +/* + * hfs_mac2alpha() + * + * Given a 'Pascal String' (a string preceded by a length byte) in + * the Macintosh character set produce the corresponding filename using + * the '7-bit alphanumeric' name-mangling scheme, returning the length + * of the mangled filename. Note that the output string is not NULL + * terminated. + * + * This is one of the three recommended naming conventions described + * in Apple's document "AppleSingle/AppleDouble Formats: Developer's + * Note (9/94)" + * + * The name-mangling works as follows: + * The characters 'a'-'z', 'A'-'Z', '0'-'9', '_' and the last '.' in + * the filename are passed unchanged from input to output. All + * remaining characters (including any '.'s other than the last) are + * replaced by three characters: '%xx' where xx is the hexadecimal + * representation of the character, using lowercase 'a' through 'f'. + */ +int hfs_mac2alpha(char *out, const struct hfs_name *in) { + unsigned char c; + const unsigned char *p = in->Name; + int len = in->Len; + int count = 0; + const unsigned char *lp; /* last period */ + + /* strrchr() would be good here, but 'in' is not null-terminated */ + for (lp=p+len-1; (lp>=p)&&(*lp!='.'); --lp) {} + ++lp; + + while (len--) { + c = *p++; + if ((p==lp) || ((c>='0')&&(c<='9')) || ((c>='A')&&(c<='Z')) || + ((c>='a')&&(c<='z')) || (c=='_')) { + *out++ = c; + count++; + } else { + *out++ = '%'; + *out++ = hex[(c>>4) & 0xf]; + *out++ = hex[c & 0xf]; + count += 3; + } + } + return count; +} + +/* + * hfs_mac2triv() + * + * Given a 'Pascal String' (a string preceded by a length byte) in + * the Macintosh character set produce the corresponding filename using + * the 'trivial' name-mangling scheme, returning the length of the + * mangled filename. Note that the output string is not NULL + * terminated. + * + * The name-mangling works as follows: + * The character '/', which is illegal in Linux filenames is replaced + * by ':' which never appears in HFS filenames. All other characters + * are passed unchanged from input to output. + */ +int hfs_mac2triv(char *out, const struct hfs_name *in) { + unsigned char c; + const unsigned char *p = in->Name; + int len = in->Len; + int count = 0; + + while (len--) { + c = *p++; + if (c=='/') { + *out++ = ':'; + } else { + *out++ = c; + } + count++; + } + return count; +} + +/* + * hfs_mac2latin() + * + * Given a 'Pascal String' (a string preceded by a length byte) in + * the Macintosh character set produce the corresponding filename using + * the 'Latin-1' name-mangling scheme, returning the length of the + * mangled filename. Note that the output string is not NULL + * terminated. + * + * The Macintosh character set and Latin-1 are both extensions of the + * ASCII character set. Some, but certainly not all, of the characters + * in the Macintosh character set are also in Latin-1 but not with the + * same encoding. This name-mangling scheme replaces the characters in + * the Macintosh character set that have Latin-1 equivalents by those + * equivalents; the characters 32-126, excluding '/' and '%', are + * passed unchanged from input to output. The remaining characters + * are replaced by three characters: '%xx' where xx is the hexadecimal + * representation of the character, using lowercase 'a' through 'f'. + * + * The array mac2latin_map[] indicates the correspondence between the + * two character sets. The byte in element x-128 gives the Latin-1 + * encoding of the character with encoding x in the Macintosh + * character set. A value of zero indicates Latin-1 has no + * corresponding character. + */ +int hfs_mac2latin(char *out, const struct hfs_name *in) { + unsigned char c; + const unsigned char *p = in->Name; + int len = in->Len; + int count = 0; + + while (len--) { + c = *p++; + + if ((c & 0x80) && mac2latin_map[c & 0x7f]) { + *out++ = mac2latin_map[c & 0x7f]; + count++; + } else if ((c>=32) && (c<=126) && (c!='/') && (c!='%')) { + *out++ = c; + count++; + } else { + *out++ = '%'; + *out++ = hex[(c>>4) & 0xf]; + *out++ = hex[c & 0xf]; + count += 3; + } + } + return count; +} + +/* + * hfs_colon2mac() + * + * Given an ASCII string (not null-terminated) and its length, + * generate the corresponding filename in the Macintosh character set + * using the 'CAP' name-mangling scheme, returning the length of the + * mangled filename. Note that the output string is not NULL + * terminated. + * + * This routine is a inverse to hfs_mac2cap() and hfs_mac2nat(). + * A ':' not followed by a 2-digit hexadecimal number (or followed + * by the codes for NULL or ':') is replaced by a '|'. + */ +void hfs_colon2mac(struct hfs_name *out, const char *in, int len) { + int hi, lo; + unsigned char code, c, *count; + unsigned char *p = out->Name; + + out->Len = 0; + count = &out->Len; + while (len-- && (*count < HFS_NAMELEN)) { + c = *in++; + (*count)++; + if (c!=':') { + *p++ = c; + } else if ((len<2) || + ((hi=dehex(in[0])) & 0xf0) || + ((lo=dehex(in[1])) & 0xf0) || + !(code = (hi << 4) | lo) || + (code == ':')) { + *p++ = '|'; + } else { + *p++ = code; + len -= 2; + in += 2; + } + } +} + +/* + * hfs_prcnt2mac() + * + * Given an ASCII string (not null-terminated) and its length, + * generate the corresponding filename in the Macintosh character set + * using Apple's three recommended name-mangling schemes, returning + * the length of the mangled filename. Note that the output string is + * not NULL terminated. + * + * This routine is a inverse to hfs_mac2alpha(), hfs_mac2seven() and + * hfs_mac2eight(). + * A '%' not followed by a 2-digit hexadecimal number (or followed + * by the code for NULL or ':') is unchanged. + * A ':' is replaced by a '|'. + */ +void hfs_prcnt2mac(struct hfs_name *out, const char *in, int len) { + int hi, lo; + unsigned char code, c, *count; + unsigned char *p = out->Name; + + out->Len = 0; + count = &out->Len; + while (len-- && (*count < HFS_NAMELEN)) { + c = *in++; + (*count)++; + if (c==':') { + *p++ = '|'; + } else if (c!='%') { + *p++ = c; + } else if ((len<2) || + ((hi=dehex(in[0])) & 0xf0) || + ((lo=dehex(in[1])) & 0xf0) || + !(code = (hi << 4) | lo) || + (code == ':')) { + *p++ = '%'; + } else { + *p++ = code; + len -= 2; + in += 2; + } + } +} + +/* + * hfs_triv2mac() + * + * Given an ASCII string (not null-terminated) and its length, + * generate the corresponding filename in the Macintosh character set + * using the 'trivial' name-mangling scheme, returning the length of + * the mangled filename. Note that the output string is not NULL + * terminated. + * + * This routine is a inverse to hfs_mac2triv(). + * A ':' is replaced by a '/'. + */ +void hfs_triv2mac(struct hfs_name *out, const char *in, int len) { + unsigned char c, *count; + unsigned char *p = out->Name; + + out->Len = 0; + count = &out->Len; + while (len-- && (*count < HFS_NAMELEN)) { + c = *in++; + (*count)++; + if (c==':') { + *p++ = '/'; + } else { + *p++ = c; + } + } +} + +/* + * hfs_latin2mac() + * + * Given an Latin-1 string (not null-terminated) and its length, + * generate the corresponding filename in the Macintosh character set + * using the 'Latin-1' name-mangling scheme, returning the length of + * the mangled filename. Note that the output string is not NULL + * terminated. + * + * This routine is a inverse to hfs_latin2cap(). + * A '%' not followed by a 2-digit hexadecimal number (or followed + * by the code for NULL or ':') is unchanged. + * A ':' is replaced by a '|'. + * + * Note that the character map is built the first time it is needed. + */ +void hfs_latin2mac(struct hfs_name *out, const char *in, int len) +{ + int hi, lo; + unsigned char code, c, *count; + unsigned char *p = out->Name; + static int map_initialized = 0; + + if (!map_initialized) { + int i; + + /* build the inverse mapping at run time */ + for (i = 0; i < 128; i++) { + if ((c = mac2latin_map[i])) { + latin2mac_map[(int)c - 128] = i + 128; + } + } + map_initialized = 1; + } + + out->Len = 0; + count = &out->Len; + while (len-- && (*count < HFS_NAMELEN)) { + c = *in++; + (*count)++; + + if (c==':') { + *p++ = '|'; + } else if (c!='%') { + if (c<128 || !(*p = latin2mac_map[c-128])) { + *p = c; + } + p++; + } else if ((len<2) || + ((hi=dehex(in[0])) & 0xf0) || + ((lo=dehex(in[1])) & 0xf0) || + !(code = (hi << 4) | lo) || + (code == ':')) { + *p++ = '%'; + } else { + *p++ = code; + len -= 2; + in += 2; + } + } +} diff -u --recursive --new-file v2.1.77/linux/fs/hfs/version.c linux/fs/hfs/version.c --- v2.1.77/linux/fs/hfs/version.c Wed Dec 31 16:00:00 1969 +++ linux/fs/hfs/version.c Sun Jan 4 10:40:17 1998 @@ -0,0 +1,10 @@ +/* + * linux/fs/hfs/version.c + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains the version string for this release. + */ + +const char hfs_version[]="0.96"; diff -u --recursive --new-file v2.1.77/linux/fs/inode.c linux/fs/inode.c --- v2.1.77/linux/fs/inode.c Tue Nov 18 17:22:08 1997 +++ linux/fs/inode.c Sun Jan 4 10:52:42 1998 @@ -215,7 +215,7 @@ /* * This is called by the filesystem to tell us * that the inode is no longer useful. We just - * terminate it with extreme predjudice. + * terminate it with extreme prejudice. */ void clear_inode(struct inode *inode) { diff -u --recursive --new-file v2.1.77/linux/fs/isofs/symlink.c linux/fs/isofs/symlink.c --- v2.1.77/linux/fs/isofs/symlink.c Mon Nov 17 18:47:21 1997 +++ linux/fs/isofs/symlink.c Sun Jan 4 00:53:41 1998 @@ -18,8 +18,8 @@ #include -static int isofs_readlink(struct inode *, char *, int); -static struct dentry * isofs_follow_link(struct inode * inode, struct dentry *base); +static int isofs_readlink(struct dentry *, char *, int); +static struct dentry * isofs_follow_link(struct dentry *, struct dentry *); /* * symlinks can't do much... @@ -44,14 +44,14 @@ NULL /* permission */ }; -static int isofs_readlink(struct inode * inode, char * buffer, int buflen) +static int isofs_readlink(struct dentry * dentry, char * buffer, int buflen) { char * pnt; int i; if (buflen > 1023) buflen = 1023; - pnt = get_rock_ridge_symlink(inode); + pnt = get_rock_ridge_symlink(dentry->d_inode); if (!pnt) return 0; @@ -65,12 +65,12 @@ return i; } -static struct dentry * isofs_follow_link(struct inode * inode, struct dentry *base) +static struct dentry * isofs_follow_link(struct dentry * dentry, + struct dentry *base) { char * pnt; - pnt = get_rock_ridge_symlink(inode); - + pnt = get_rock_ridge_symlink(dentry->d_inode); if(!pnt) { dput(base); return ERR_PTR(-ELOOP); diff -u --recursive --new-file v2.1.77/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c --- v2.1.77/linux/fs/lockd/clntproc.c Mon Dec 1 12:04:14 1997 +++ linux/fs/lockd/clntproc.c Sun Jan 4 00:53:43 1998 @@ -42,7 +42,7 @@ memset(argp, 0, sizeof(*argp)); argp->cookie = nlm_cookie++; argp->state = nsm_local_state; - lock->fh = *NFS_FH(fl->fl_file->f_dentry->d_inode); + lock->fh = *NFS_FH(fl->fl_file->f_dentry); lock->caller = system_utsname.nodename; lock->oh.data = req->a_owner; lock->oh.len = sprintf(req->a_owner, "%d@%s", diff -u --recursive --new-file v2.1.77/linux/fs/minix/symlink.c linux/fs/minix/symlink.c --- v2.1.77/linux/fs/minix/symlink.c Thu Jul 17 10:06:07 1997 +++ linux/fs/minix/symlink.c Sun Jan 4 00:53:41 1998 @@ -14,8 +14,8 @@ #include -static int minix_readlink(struct inode *, char *, int); -static struct dentry *minix_follow_link(struct inode *, struct dentry *); +static int minix_readlink(struct dentry *, char *, int); +static struct dentry *minix_follow_link(struct dentry *, struct dentry *); /* * symlinks can't do much... @@ -40,8 +40,10 @@ NULL /* permission */ }; -static struct dentry * minix_follow_link(struct inode * inode, struct dentry * base) +static struct dentry * minix_follow_link(struct dentry * dentry, + struct dentry * base) { + struct inode *inode = dentry->d_inode; struct buffer_head * bh; bh = minix_bread(inode, 0, 0); @@ -55,7 +57,7 @@ return base; } -static int minix_readlink(struct inode * inode, char * buffer, int buflen) +static int minix_readlink(struct dentry * dentry, char * buffer, int buflen) { struct buffer_head * bh; int i; @@ -63,7 +65,7 @@ if (buflen > 1023) buflen = 1023; - bh = minix_bread(inode, 0, 0); + bh = minix_bread(dentry->d_inode, 0, 0); if (!bh) return 0; i = 0; diff -u --recursive --new-file v2.1.77/linux/fs/namei.c linux/fs/namei.c --- v2.1.77/linux/fs/namei.c Sun Dec 21 22:36:16 1997 +++ linux/fs/namei.c Sun Jan 4 00:53:41 1998 @@ -221,33 +221,28 @@ } /* - * This is called when everything else fails, and we actually have - * to go to the low-level filesystem to find out what we should do.. - * - * We get the directory semaphore, and after getting that we also - * make sure that nobody added the entry to the dcache in the meantime.. + * "." and ".." are special - ".." especially so because it has to be able + * to know about the current root directory and parent relationships */ -static struct dentry * real_lookup(struct dentry * parent, struct qstr * name) +static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * name) { - struct dentry * result; - struct inode *dir = parent->d_inode; + struct dentry *result = NULL; + if (name->name[0] == '.') { + switch (name->len) { + default: + break; + case 2: + if (name->name[1] != '.') + break; - down(&dir->i_sem); - result = d_lookup(parent, name); - if (!result) { - struct dentry * dentry = d_alloc(parent, name); - result = ERR_PTR(-ENOMEM); - if (dentry) { - int error = dir->i_op->lookup(dir, dentry); - result = dentry; - if (error) { - dput(dentry); - result = ERR_PTR(error); - } + if (parent != current->fs->root) + parent = parent->d_covers->d_parent; + /* fallthrough */ + case 1: + result = parent; } } - up(&dir->i_sem); - return result; + return dget(result); } /* @@ -274,28 +269,40 @@ } /* - * "." and ".." are special - ".." especially so because it has to be able - * to know about the current root directory and parent relationships + * This is called when everything else fails, and we actually have + * to go to the low-level filesystem to find out what we should do.. + * + * We get the directory semaphore, and after getting that we also + * make sure that nobody added the entry to the dcache in the meantime.. */ -static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * name) +static struct dentry * real_lookup(struct dentry * parent, struct qstr * name) { - struct dentry *result = NULL; - if (name->name[0] == '.') { - switch (name->len) { - default: - break; - case 2: - if (name->name[1] != '.') - break; + struct dentry * result; + struct inode *dir = parent->d_inode; - if (parent != current->fs->root) - parent = parent->d_covers->d_parent; - /* fallthrough */ - case 1: - result = parent; + down(&dir->i_sem); + /* + * First re-do the cached lookup just in case it was created + * while we waited for the directory semaphore.. + * + * FIXME! This could use version numbering or similar to + * avoid unnecessary cache lookups. + */ + result = cached_lookup(parent, name); + if (!result) { + struct dentry * dentry = d_alloc(parent, name); + result = ERR_PTR(-ENOMEM); + if (dentry) { + int error = dir->i_op->lookup(dir, dentry); + result = dentry; + if (error) { + dput(dentry); + result = ERR_PTR(error); + } } } - return dget(result); + up(&dir->i_sem); + return result; } static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry) @@ -308,7 +315,7 @@ current->link_count++; /* This eats the base */ - result = inode->i_op->follow_link(inode, base); + result = inode->i_op->follow_link(dentry, base); current->link_count--; dput(dentry); return result; @@ -632,7 +639,7 @@ if (inode->i_sb && inode->i_sb->dq_op) inode->i_sb->dq_op->initialize(inode, -1); - error = do_truncate(inode, 0); + error = do_truncate(dentry, 0); } put_write_access(inode); if (error) @@ -1076,7 +1083,7 @@ if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op) dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1); - error = dir->d_inode->i_op->link(inode, dir->d_inode, new_dentry); + error = dir->d_inode->i_op->link(old_dentry, dir->d_inode, new_dentry); exit_lock: unlock_dir(dir); diff -u --recursive --new-file v2.1.77/linux/fs/ncpfs/Makefile linux/fs/ncpfs/Makefile --- v2.1.77/linux/fs/ncpfs/Makefile Thu Feb 22 05:20:19 1996 +++ linux/fs/ncpfs/Makefile Mon Jan 5 01:41:01 1998 @@ -12,10 +12,8 @@ M_OBJS := $(O_TARGET) # If you want debugging output, please uncomment the following line - # EXTRA_CFLAGS += -DDEBUG_NCP=1 -include $(TOPDIR)/Rules.make +CFLAGS_ncplib_kernel.o := -finline-functions -ncplib_kernel.o: ncplib_kernel.c ncplib_kernel.h - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -finline-functions -c -o $@ $< +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.77/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c --- v2.1.77/linux/fs/ncpfs/dir.c Mon Nov 17 18:47:21 1997 +++ linux/fs/ncpfs/dir.c Sun Jan 4 00:53:42 1998 @@ -105,10 +105,10 @@ /* * Dentry operations routines */ -static int ncp_lookup_validate(struct dentry *); -static void ncp_delete_dentry(struct dentry *); +static int ncp_lookup_validate(struct dentry *); static int ncp_hash_dentry(struct dentry *, struct qstr *); static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); +static void ncp_delete_dentry(struct dentry *); static struct dentry_operations ncp_dentry_operations = { @@ -125,19 +125,23 @@ */ #define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c)) - +/* + * Note: leave the hash unchanged if the directory + * is case-sensitive. + */ static int ncp_hash_dentry(struct dentry *dentry, struct qstr *this) { - unsigned long hash; - int i; + unsigned long hash; + int i; - hash = init_name_hash(); - for (i=0; ilen ; i++) - hash = partial_name_hash(tolower(this->name[i]),hash); - this->hash = end_name_hash(hash); - - return 0; + if (!ncp_case_sensitive(dentry->d_inode)) { + hash = init_name_hash(); + for (i=0; ilen ; i++) + hash = partial_name_hash(tolower(this->name[i]),hash); + this->hash = end_name_hash(hash); + } + return 0; } static int @@ -202,42 +206,14 @@ */ ino_t ncp_invent_inos(unsigned long n) { - static ino_t ino = 1; + static ino_t ino = 2; if (ino + 2*n < ino) { /* wrap around */ - ino += n; + ino = 2; } ino += n; - return ino; -} - -/* - * Check whether a dentry already exists for the given name, - * and return the inode number if it has an inode. This is - * needed to keep getcwd() working. - */ -static ino_t -find_inode_number(struct dentry *dir, struct qstr *name) -{ - unsigned long hash; - int i; - struct dentry * dentry; - ino_t ino = 0; - - hash = init_name_hash(); - for (i=0; ilen ; i++) - hash = partial_name_hash(tolower(name->name[i]),hash); - name->hash = end_name_hash(hash); - - dentry = d_lookup(dir, name); - if (dentry) - { - if (dentry->d_inode) - ino = dentry->d_inode->i_ino; - dput(dentry); - } return ino; } diff -u --recursive --new-file v2.1.77/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c --- v2.1.77/linux/fs/ncpfs/file.c Wed Nov 12 13:34:27 1997 +++ linux/fs/ncpfs/file.c Sun Jan 4 00:53:42 1998 @@ -15,11 +15,12 @@ #include #include #include -#include #include -#include "ncplib_kernel.h" #include +#include +#include "ncplib_kernel.h" + static inline int min(int a, int b) { return a < b ? a : b; @@ -65,7 +66,7 @@ result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), NULL, NULL, OC_MODE_OPEN, 0, AR_READ, &finfo); - if (!result) { + if (result) { #ifdef NCPFS_PARANOIA printk(KERN_DEBUG "ncp_make_open: failed, result=%d\n", result); #endif @@ -82,11 +83,7 @@ #ifdef NCPFS_PARANOIA printk(KERN_DEBUG "ncp_make_open: file open, access=%x\n", access); #endif - if (((right == O_RDONLY) && ((access == O_RDONLY) - || (access == O_RDWR))) - || ((right == O_WRONLY) && ((access == O_WRONLY) - || (access == O_RDWR))) - || ((right == O_RDWR) && (access == O_RDWR))) + if (access == right || access == O_RDWR) error = 0; out_unlock: @@ -231,7 +228,7 @@ } } - inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = CURRENT_TIME; file->f_pos = pos; diff -u --recursive --new-file v2.1.77/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c --- v2.1.77/linux/fs/ncpfs/inode.c Wed Nov 12 13:34:27 1997 +++ linux/fs/ncpfs/inode.c Sun Jan 4 00:53:42 1998 @@ -37,7 +37,7 @@ static void ncp_read_inode(struct inode *); static void ncp_put_inode(struct inode *); static void ncp_delete_inode(struct inode *); -static int ncp_notify_change(struct inode *, struct iattr *); +static int ncp_notify_change(struct dentry *, struct iattr *); static void ncp_put_super(struct super_block *); static int ncp_statfs(struct super_block *, struct statfs *, int); @@ -210,7 +210,7 @@ i->entryName[0] = '\0'; root->finfo.opened= 0; - info->ino = 1; + info->ino = 2; /* tradition */ info->nw_info = root->finfo; } @@ -354,7 +354,7 @@ ncp_unlock_server(server); close_fp(server->ncp_filp); - kill_proc(server->m.wdog_pid, SIGTERM, 0); + kill_proc(server->m.wdog_pid, SIGTERM, 1); ncp_kfree_s(server->packet, server->packet_size); @@ -387,30 +387,34 @@ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; } -static int ncp_notify_change(struct inode *inode, struct iattr *attr) +static int ncp_notify_change(struct dentry *dentry, struct iattr *attr) { + struct inode *inode = dentry->d_inode; int result = 0; int info_mask; struct nw_modify_dos_info info; - if (!ncp_conn_valid(NCP_SERVER(inode))) { - return -EIO; - } - if ((result = inode_change_ok(inode, attr)) < 0) - return result; + result = -EIO; + if (!ncp_conn_valid(NCP_SERVER(inode))) + goto out; + + result = inode_change_ok(inode, attr); + if (result < 0) + goto out; + result = -EPERM; if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != NCP_SERVER(inode)->m.uid))) - return -EPERM; + goto out; if (((attr->ia_valid & ATTR_GID) && (attr->ia_uid != NCP_SERVER(inode)->m.gid))) - return -EPERM; + goto out; if (((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)))) - return -EPERM; + goto out; info_mask = 0; memset(&info, 0, sizeof(info)); @@ -455,7 +459,8 @@ if ((attr->ia_valid & ATTR_SIZE) != 0) { int written; - DPRINTK(KERN_DEBUG "ncpfs: trying to change size to %ld\n", attr->ia_size); + DPRINTK(KERN_DEBUG "ncpfs: trying to change size to %ld\n", + attr->ia_size); if ((result = ncp_make_open(inode, O_RDWR)) < 0) { return -EACCES; @@ -467,11 +472,8 @@ closing the file */ result = ncp_make_closed(inode); } - /* - * We need a dentry here ... - */ - /* ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode); */ - + ncp_invalid_dir_cache(dentry->d_parent->d_inode); +out: return result; } diff -u --recursive --new-file v2.1.77/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.1.77/linux/fs/nfs/dir.c Fri Jan 2 14:37:02 1998 +++ linux/fs/nfs/dir.c Sun Jan 4 01:33:18 1998 @@ -64,7 +64,7 @@ static int nfs_rmdir(struct inode *, struct dentry *); static int nfs_unlink(struct inode *, struct dentry *); static int nfs_symlink(struct inode *, struct dentry *, const char *); -static int nfs_link(struct inode *, struct inode *, struct dentry *); +static int nfs_link(struct dentry *, struct inode *, struct dentry *); static int nfs_mknod(struct inode *, struct dentry *, int, int); static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); @@ -108,8 +108,11 @@ static int nfs_dir_open(struct inode *dir, struct file *file) { - dfprintk(VFS, "NFS: nfs_dir_open(%x/%ld)\n", dir->i_dev, dir->i_ino); - return nfs_revalidate_inode(NFS_SERVER(dir), dir); + struct dentry *dentry = file->f_dentry; + + dfprintk(VFS, "NFS: nfs_dir_open(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); + return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); } static ssize_t @@ -133,7 +136,8 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { - struct inode *inode = filp->f_dentry->d_inode; + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; static struct wait_queue *readdir_wait = NULL; struct wait_queue **waitp = NULL; struct nfs_dirent *cache, *free; @@ -144,14 +148,17 @@ __u32 *entry; char *name, *start; - dfprintk(VFS, "NFS: nfs_readdir(%x/%ld)\n", inode->i_dev, inode->i_ino); + dfprintk(VFS, "NFS: nfs_readdir(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); + result = -EBADF; if (!inode || !S_ISDIR(inode->i_mode)) { printk("nfs_readdir: inode is NULL or not a directory\n"); - return -EBADF; + goto out; } - if ((result = nfs_revalidate_inode(NFS_SERVER(inode), inode)) < 0) - return result; + result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); + if (result < 0) + goto out; /* * Try to find the entry in the cache @@ -250,7 +257,7 @@ goto done; } - result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(inode), + result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(dentry), cookie, PAGE_SIZE, cache->entry); if (result <= 0) goto done; @@ -300,6 +307,7 @@ wake_up(&cache->wait); wake_up(&readdir_wait); +out: return result; } @@ -449,11 +457,21 @@ #endif } -static struct dentry_operations nfs_dentry_operations = { +/* + * Called when the dentry is being freed to release private memory. + */ +static void nfs_dentry_release(struct dentry *dentry) +{ + if (dentry->d_fsdata) + kfree(dentry->d_fsdata); +} + +struct dentry_operations nfs_dentry_operations = { nfs_lookup_revalidate, /* d_validate(struct dentry *) */ - 0, /* d_hash */ - 0, /* d_compare */ - nfs_dentry_delete /* d_delete(struct dentry *) */ + NULL, /* d_hash */ + NULL, /* d_compare */ + nfs_dentry_delete, /* d_delete(struct dentry *) */ + nfs_dentry_release /* d_release(struct dentry *) */ }; /* @@ -470,16 +488,20 @@ } } +static void nfs_set_fh(struct dentry *dentry, struct nfs_fh *fhandle) +{ + *((struct nfs_fh *) dentry->d_fsdata) = *fhandle; +} + static int nfs_lookup(struct inode *dir, struct dentry * dentry) { - int len = dentry->d_name.len; struct inode *inode; int error; struct nfs_fh fhandle; struct nfs_fattr fattr; - dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n", - dir->i_dev, dir->i_ino, len, dentry->d_name.name); + dfprintk(VFS, "NFS: lookup(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); if (!dir || !S_ISDIR(dir->i_mode)) { printk("nfs_lookup: inode is NULL or not a directory\n"); @@ -487,17 +509,26 @@ } error = -ENAMETOOLONG; - if (len > NFS_MAXNAMLEN) + if (dentry->d_name.len > NFS_MAXNAMLEN) goto out; - error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), + error = -ENOMEM; + if (!dentry->d_fsdata) { + dentry->d_fsdata = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL); + if (!dentry->d_fsdata) + goto out; + } + dentry->d_op = &nfs_dentry_operations; + + error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, &fhandle, &fattr); inode = NULL; if (error == -ENOENT) goto no_entry; if (!error) { error = -EACCES; - inode = nfs_fhget(dir->i_sb, &fhandle, &fattr); + nfs_set_fh(dentry, &fhandle); + inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); if (inode) { #ifdef NFS_PARANOIA if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) @@ -506,7 +537,6 @@ inode->i_ino, inode->i_count, inode->i_nlink); #endif no_entry: - dentry->d_op = &nfs_dentry_operations; d_add(dentry, inode); nfs_renew_times(dentry); error = 0; @@ -530,6 +560,7 @@ struct inode *inode; int error = -EACCES; + nfs_set_fh(dentry, fhandle); inode = nfs_fhget(dentry->d_sb, fhandle, fattr); if (inode) { #ifdef NFS_PARANOIA @@ -578,7 +609,7 @@ * Invalidate the dir cache before the operation to avoid a race. */ nfs_invalidate_dircache(dir); - error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir), + error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, &sattr, &fhandle, &fattr); if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); @@ -616,7 +647,7 @@ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; nfs_invalidate_dircache(dir); - error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir), + error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, &sattr, &fhandle, &fattr); if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); @@ -652,7 +683,7 @@ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; nfs_invalidate_dircache(dir); - error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir), + error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, &sattr, &fhandle, &fattr); /* @@ -717,8 +748,8 @@ dentry->d_inode->i_nlink --; d_delete(dentry); nfs_invalidate_dircache(dir); - error = nfs_proc_rmdir(NFS_SERVER(dir), - NFS_FH(dir), dentry->d_name.name); + error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent), + dentry->d_name.name); if (!error) { if (rehash) d_add(dentry, NULL); @@ -839,8 +870,8 @@ nfs_invalidate_dircache(dir); error = nfs_proc_rename(NFS_SERVER(dir), - NFS_FH(dir), dentry->d_name.name, - NFS_FH(dir), silly); + NFS_FH(dentry->d_parent), dentry->d_name.name, + NFS_FH(dentry->d_parent), silly); if (!error) { nfs_renew_times(dentry); d_move(dentry, sdentry); @@ -914,8 +945,8 @@ d_delete(dentry); } nfs_invalidate_dircache(dir); - error = nfs_proc_remove(NFS_SERVER(dir), - NFS_FH(dir), dentry->d_name.name); + error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dentry->d_parent), + dentry->d_name.name); /* * Rehash the negative dentry if the operation succeeded. */ @@ -998,7 +1029,7 @@ */ d_drop(dentry); nfs_invalidate_dircache(dir); - error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir), + error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, symname, &sattr); if (!error) { nfs_renew_times(dentry->d_parent); @@ -1012,13 +1043,14 @@ } static int -nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry) +nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { + struct inode *inode = old_dentry->d_inode; int error; - dfprintk(VFS, "NFS: link(%x/%ld -> %x/%ld, %s)\n", - inode->i_dev, inode->i_ino, - dir->i_dev, dir->i_ino, dentry->d_name.name); + dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n", + old_dentry->d_parent->d_name.name, old_dentry->d_name.name, + dentry->d_parent->d_name.name, dentry->d_name.name); if (!dir || !S_ISDIR(dir->i_mode)) { printk("nfs_link: dir is NULL or not a directory\n"); @@ -1029,13 +1061,21 @@ if (dentry->d_name.len > NFS_MAXNAMLEN) goto out; + /* + * Drop the dentry in advance to force a new lookup. + * Since nfs_proc_link doesn't return a filehandle, + * we can't use the existing dentry. + */ + d_drop(dentry); nfs_invalidate_dircache(dir); - error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode), NFS_FH(dir), - dentry->d_name.name); + error = nfs_proc_link(NFS_DSERVER(old_dentry), NFS_FH(old_dentry), + NFS_FH(dentry->d_parent), dentry->d_name.name); if (!error) { - inode->i_count ++; - inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */ - d_instantiate(dentry, inode); + /* + * Update the link count immediately, as some apps + * (e.g. pine) test this after making a link. + */ + inode->i_nlink++; } out: return error; @@ -1181,9 +1221,9 @@ nfs_invalidate_dircache(new_dir); nfs_invalidate_dircache(old_dir); - error = nfs_proc_rename(NFS_SERVER(old_dir), - NFS_FH(old_dir), old_dentry->d_name.name, - NFS_FH(new_dir), new_dentry->d_name.name); + error = nfs_proc_rename(NFS_DSERVER(old_dentry), + NFS_FH(old_dentry->d_parent), old_dentry->d_name.name, + NFS_FH(new_dentry->d_parent), new_dentry->d_name.name); if (!error) { /* Update the dcache if needed */ if (rehash) diff -u --recursive --new-file v2.1.77/linux/fs/nfs/file.c linux/fs/nfs/file.c --- v2.1.77/linux/fs/nfs/file.c Thu Dec 4 14:53:56 1997 +++ linux/fs/nfs/file.c Sun Jan 4 00:53:41 1998 @@ -109,15 +109,14 @@ static ssize_t nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos) { - struct inode * inode = file->f_dentry->d_inode; + struct dentry * dentry = file->f_dentry; ssize_t result; - dfprintk(VFS, "nfs: read(%x/%ld, %lu@%lu)\n", - inode->i_dev, inode->i_ino, - (unsigned long) count, - (unsigned long) *ppos); + dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + (unsigned long) count, (unsigned long) *ppos); - result = nfs_revalidate_inode(NFS_SERVER(inode), inode); + result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); if (!result) result = generic_file_read(file, buf, count, ppos); return result; @@ -126,12 +125,13 @@ static int nfs_file_mmap(struct file * file, struct vm_area_struct * vma) { - struct inode *inode = file->f_dentry->d_inode; + struct dentry *dentry = file->f_dentry; int status; - dfprintk(VFS, "nfs: mmap(%x/%ld)\n", inode->i_dev, inode->i_ino); + dfprintk(VFS, "nfs: mmap(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); - status = nfs_revalidate_inode(NFS_SERVER(inode), inode); + status = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); if (!status) status = generic_file_mmap(file, vma); return status; @@ -163,31 +163,33 @@ static ssize_t nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct inode * inode = file->f_dentry->d_inode; + struct dentry * dentry = file->f_dentry; + struct inode * inode = dentry->d_inode; ssize_t result; - dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n", - inode->i_dev, inode->i_ino, inode->i_count, - (unsigned long) count, (unsigned long) *ppos); + dfprintk(VFS, "nfs: write(%s/%s (%d), %lu@%lu)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + inode->i_count, (unsigned long) count, (unsigned long) *ppos); if (!inode) { printk("nfs_file_write: inode = NULL\n"); return -EINVAL; } - if (IS_SWAPFILE(inode)) { - printk("NFS: attempt to write to active swap file!\n"); - return -EBUSY; - } - result = nfs_revalidate_inode(NFS_SERVER(inode), inode); + result = -EBUSY; + if (IS_SWAPFILE(inode)) + goto out_swapfile; + result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); if (result) goto out; - /* N.B. This should be impossible now -- inodes can't change mode */ - if (!S_ISREG(inode->i_mode)) { - printk("nfs_file_write: write to non-file, mode %07o\n", - inode->i_mode); - return -EINVAL; - } +#ifdef NFS_PARANOIA +/* N.B. This should be impossible now -- inodes can't change mode */ +if (!S_ISREG(inode->i_mode)) { + printk("nfs_file_write: write to non-file, mode %07o\n", + inode->i_mode); + return -EINVAL; +} +#endif result = count; if (!count) goto out; @@ -198,6 +200,10 @@ result = generic_file_write(file, buf, count, ppos); out: return result; + +out_swapfile: + printk("NFS: attempt to write to active swap file!\n"); + goto out; } /* diff -u --recursive --new-file v2.1.77/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.1.77/linux/fs/nfs/inode.c Sun Dec 21 22:36:16 1997 +++ linux/fs/nfs/inode.c Sun Jan 4 00:53:41 1998 @@ -38,7 +38,7 @@ static void nfs_read_inode(struct inode *); static void nfs_put_inode(struct inode *); static void nfs_delete_inode(struct inode *); -static int nfs_notify_change(struct inode *, struct iattr *); +static int nfs_notify_change(struct dentry *, struct iattr *); static void nfs_put_super(struct super_block *); static int nfs_statfs(struct super_block *, struct statfs *, int); @@ -180,15 +180,15 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) { struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data; - struct sockaddr_in srvaddr; struct nfs_server *server; - struct rpc_timeout timeparms; struct rpc_xprt *xprt; struct rpc_clnt *clnt; + struct nfs_fh *root_fh; + struct inode *root_inode; unsigned int authflavor; int tcp; - kdev_t dev = sb->s_dev; - struct inode *root_inode; + struct sockaddr_in srvaddr; + struct rpc_timeout timeparms; MOD_INC_USE_COUNT; if (!data) @@ -211,7 +211,6 @@ lock_super(sb); sb->s_magic = NFS_SUPER_MAGIC; - sb->s_dev = dev; sb->s_op = &nfs_sops; sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); sb->u.nfs_sb.s_root = data->root; @@ -234,21 +233,19 @@ timeparms.to_maxval = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT; timeparms.to_exponential = 1; - /* Choose authentication flavor */ - if (data->flags & NFS_MOUNT_SECURE) { - authflavor = RPC_AUTH_DES; - } else if (data->flags & NFS_MOUNT_KERBEROS) { - authflavor = RPC_AUTH_KRB; - } else { - authflavor = RPC_AUTH_UNIX; - } - /* Now create transport and client */ xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP, &srvaddr, &timeparms); if (xprt == NULL) goto out_no_xprt; + /* Choose authentication flavor */ + authflavor = RPC_AUTH_UNIX; + if (data->flags & NFS_MOUNT_SECURE) + authflavor = RPC_AUTH_DES; + else if (data->flags & NFS_MOUNT_KERBEROS) + authflavor = RPC_AUTH_KRB; + clnt = rpc_create_client(xprt, server->hostname, &nfs_program, NFS_VERSION, authflavor); if (clnt == NULL) @@ -267,12 +264,20 @@ * Keep the super block locked while we try to get * the root fh attributes. */ + root_fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL); + if (!root_fh) + goto out_no_fh; + *root_fh = data->root; + root_inode = nfs_fhget(sb, &data->root, NULL); if (!root_inode) goto out_no_root; sb->s_root = d_alloc_root(root_inode, NULL); if (!sb->s_root) goto out_no_root; + sb->s_root->d_op = &nfs_dentry_operations; + sb->s_root->d_fsdata = root_fh; + /* We're airborne */ unlock_super(sb); @@ -285,6 +290,8 @@ out_no_root: printk("nfs_read_super: get root inode failed\n"); iput(root_inode); + kfree(root_fh); +out_no_fh: rpciod_down(); goto out_shutdown; @@ -352,36 +359,28 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - struct nfs_fattr newfattr; int error; - struct inode *inode; + struct inode *inode = NULL; + struct nfs_fattr newfattr; - if (!sb) { - printk("nfs_fhget: super block is NULL\n"); - return NULL; - } + if (!sb) + goto out_bad_args; if (!fattr) { - error = nfs_proc_getattr(&sb->u.nfs_sb.s_server, fhandle, - &newfattr); - if (error) { - printk("nfs_fhget: getattr error = %d\n", -error); - return NULL; - } fattr = &newfattr; - } - if (!(inode = iget(sb, fattr->fileid))) { - printk("nfs_fhget: iget failed\n"); - return NULL; - } + error = nfs_proc_getattr(&sb->u.nfs_sb.s_server, fhandle,fattr); + if (error) + goto out_bad_attr; + } + inode = iget(sb, fattr->fileid); + if (!inode) + goto out_no_inode; #ifdef NFS_PARANOIA if (inode->i_dev != sb->s_dev) printk("nfs_fhget: impossible\n"); #endif - if (inode->i_ino != fattr->fileid) { - printk("nfs_fhget: unexpected inode from iget\n"); - return inode; - } + if (inode->i_ino != fattr->fileid) + goto out_bad_id; /* * Check whether the mode has been set, as we only want to @@ -412,29 +411,41 @@ inode->i_size = fattr->size; inode->i_mtime = fattr->mtime.seconds; NFS_OLDMTIME(inode) = fattr->mtime.seconds; - *NFS_FH(inode) = *fhandle; } - if (memcmp(NFS_FH(inode), fhandle, sizeof(struct nfs_fh))) - printk("nfs_fhget: fhandle changed!\n"); nfs_refresh_inode(inode, fattr); dprintk("NFS: fhget(%x/%ld ct=%d)\n", inode->i_dev, inode->i_ino, inode->i_count); +out: return inode; + +out_bad_args: + printk("nfs_fhget: super block is NULL\n"); + goto out; +out_bad_attr: + printk("nfs_fhget: getattr error = %d\n", -error); + goto out; +out_no_inode: + printk("nfs_fhget: iget failed\n"); + goto out; +out_bad_id: + printk("nfs_fhget: unexpected inode from iget\n"); + goto out; } int -nfs_notify_change(struct inode *inode, struct iattr *attr) +nfs_notify_change(struct dentry *dentry, struct iattr *attr) { + struct inode *inode = dentry->d_inode; + int error; struct nfs_sattr sattr; struct nfs_fattr fattr; - int error; /* * Make sure the inode is up-to-date. */ - error = nfs_revalidate(inode); + error = nfs_revalidate(dentry); if (error) { #ifdef NFS_PARANOIA printk("nfs_notify_change: revalidate failed, error=%d\n", error); @@ -470,7 +481,7 @@ sattr.atime.useconds = 0; } - error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode), + error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry), &sattr, &fattr); if (error) goto out; @@ -497,9 +508,9 @@ * Externally visible revalidation function */ int -nfs_revalidate(struct inode *inode) +nfs_revalidate(struct dentry *dentry) { - return nfs_revalidate_inode(NFS_SERVER(inode), inode); + return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); } /* @@ -507,38 +518,43 @@ * the cached attributes have to be refreshed. */ int -_nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) +_nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry) { - struct nfs_fattr fattr; + struct inode *inode = dentry->d_inode; int status = 0; + struct nfs_fattr fattr; if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode)) goto out; - dfprintk(PAGECACHE, "NFS: revalidating %x/%ld inode\n", - inode->i_dev, inode->i_ino); - status = nfs_proc_getattr(server, NFS_FH(inode), &fattr); + dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + inode->i_ino); + status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr); if (status) { #ifdef NFS_PARANOIA -printk("nfs_revalidate_inode: getattr failed, error=%d\n", status); +printk("nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status); #endif - goto done; + goto out; } status = nfs_refresh_inode(inode, &fattr); - if (status) - goto done; + if (status) { +#ifdef NFS_PARANOIA +printk("nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status); +#endif + goto out; + } if (fattr.mtime.seconds == NFS_OLDMTIME(inode)) { /* Update attrtimeo value */ if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode)) NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode); } NFS_OLDMTIME(inode) = fattr.mtime.seconds; - -done: - dfprintk(PAGECACHE, - "NFS: inode %x/%ld revalidation complete (status %d).\n", - inode->i_dev, inode->i_ino, status); + dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n", + dentry->d_parent->d_name.name, dentry->d_name.name); out: return status; } @@ -569,7 +585,8 @@ goto out; } if (inode->i_ino != fattr->fileid) { - printk("nfs_refresh_inode: inode number mismatch\n"); + printk("nfs_refresh_inode: mismatch, ino=%ld, fattr=%d\n", + inode->i_ino, fattr->fileid); goto out; } diff -u --recursive --new-file v2.1.77/linux/fs/nfs/read.c linux/fs/nfs/read.c --- v2.1.77/linux/fs/nfs/read.c Thu Jul 17 10:06:07 1997 +++ linux/fs/nfs/read.c Sun Jan 4 00:53:41 1998 @@ -65,8 +65,8 @@ /* * Read a page synchronously. */ -int -nfs_readpage_sync(struct inode *inode, struct page *page) +static int +nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page) { struct nfs_rreq rqst; unsigned long offset = page->offset; @@ -83,12 +83,13 @@ if (count < rsize) rsize = count; - dprintk("NFS: nfs_proc_read(%s, (%x,%lx), %ld, %d, %p)\n", - NFS_SERVER(inode)->hostname, inode->i_dev, - inode->i_ino, offset, rsize, buffer); + dprintk("NFS: nfs_proc_read(%s, (%s/%s), %ld, %d, %p)\n", + NFS_SERVER(inode)->hostname, + dentry->d_parent->d_name.name, dentry->d_name.name, + offset, rsize, buffer); /* Set up arguments and perform rpc call */ - nfs_readreq_setup(&rqst, NFS_FH(inode), offset, buffer, rsize); + nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize); result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ, &rqst.ra_args, &rqst.ra_res, flags); @@ -160,7 +161,8 @@ } static inline int -nfs_readpage_async(struct inode *inode, struct page *page) +nfs_readpage_async(struct dentry *dentry, struct inode *inode, + struct page *page) { struct nfs_rreq *req; int result, flags; @@ -175,7 +177,7 @@ } /* Initialize request */ - nfs_readreq_setup(req, NFS_FH(inode), page->offset, + nfs_readreq_setup(req, NFS_FH(dentry), page->offset, (void *) page_address(page), PAGE_SIZE); req->ra_inode = inode; req->ra_page = page; @@ -209,8 +211,9 @@ * - The server is congested. */ int -nfs_readpage(struct inode *inode, struct page *page) +nfs_readpage(struct dentry *dentry, struct page *page) { + struct inode *inode = dentry->d_inode; unsigned long address; int error = -1; @@ -218,11 +221,11 @@ set_bit(PG_locked, &page->flags); address = page_address(page); atomic_inc(&page->count); - if (!IS_SWAPFILE(inode) && !PageError(page) - && NFS_SERVER(inode)->rsize >= PAGE_SIZE) - error = nfs_readpage_async(inode, page); + if (!IS_SWAPFILE(inode) && !PageError(page) && + NFS_SERVER(inode)->rsize >= PAGE_SIZE) + error = nfs_readpage_async(dentry, inode, page); if (error < 0) /* couldn't enqueue */ - error = nfs_readpage_sync(inode, page); + error = nfs_readpage_sync(dentry, inode, page); if (error < 0 && IS_SWAPFILE(inode)) printk("Aiee.. nfs swap-in of page failed!\n"); free_page(address); diff -u --recursive --new-file v2.1.77/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c --- v2.1.77/linux/fs/nfs/symlink.c Mon Aug 18 18:19:46 1997 +++ linux/fs/nfs/symlink.c Sun Jan 4 00:53:41 1998 @@ -18,8 +18,8 @@ #include -static int nfs_readlink(struct inode *, char *, int); -static struct dentry *nfs_follow_link(struct inode *, struct dentry *); +static int nfs_readlink(struct dentry *, char *, int); +static struct dentry *nfs_follow_link(struct dentry *, struct dentry *); /* * symlinks can't do much... @@ -44,19 +44,20 @@ NULL /* permission */ }; -static int nfs_readlink(struct inode *inode, char *buffer, int buflen) +static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen) { int error; unsigned int len; char *res; void *mem; - dfprintk(VFS, "nfs: readlink(%x/%ld)\n", inode->i_dev, inode->i_ino); + dfprintk(VFS, "nfs: readlink(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); if (buflen > NFS_MAXPATHLEN) buflen = NFS_MAXPATHLEN; - error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem, - &res, &len, buflen); + error = nfs_proc_readlink(NFS_DSERVER(dentry), NFS_FH(dentry), + &mem, &res, &len, buflen); if (! error) { copy_to_user(buffer, res, len); put_user('\0', buffer + len); @@ -66,34 +67,41 @@ return error; } -static struct dentry * nfs_follow_link(struct inode * inode, struct dentry *base) +static struct dentry * +nfs_follow_link(struct dentry * dentry, struct dentry *base) { int error; unsigned int len; char *res; void *mem; char *path; + struct dentry *result; - dfprintk(VFS, "nfs: follow_link(%x/%ld)\n", inode->i_dev, inode->i_ino); + dfprintk(VFS, "nfs: follow_link(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); - error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem, - &res, &len, NFS_MAXPATHLEN); + error = nfs_proc_readlink(NFS_DSERVER(dentry), NFS_FH(dentry), + &mem, &res, &len, NFS_MAXPATHLEN); + result = ERR_PTR(error); + if (error) + goto out_dput; - if (error) { - dput(base); - return ERR_PTR(error); - } + result = ERR_PTR(-ENOMEM); path = kmalloc(len + 1, GFP_KERNEL); - if (!path) { - dput(base); - kfree(mem); - return ERR_PTR(-ENOMEM); - } + if (!path) + goto out_mem; memcpy(path, res, len); path[len] = 0; kfree(mem); - base = lookup_dentry(path, base, 1); + result = lookup_dentry(path, base, 1); kfree(path); - return base; +out: + return result; + +out_mem: + kfree(mem); +out_dput: + dput(base); + goto out; } diff -u --recursive --new-file v2.1.77/linux/fs/nfs/write.c linux/fs/nfs/write.c --- v2.1.77/linux/fs/nfs/write.c Sun Dec 21 22:36:16 1997 +++ linux/fs/nfs/write.c Sun Jan 4 00:53:41 1998 @@ -79,6 +79,7 @@ struct nfs_wreq { struct rpc_listitem wb_list; /* linked list of req's */ struct rpc_task wb_task; /* RPC task */ + struct dentry * wb_dentry; /* dentry referenced */ struct inode * wb_inode; /* inode referenced */ struct page * wb_page; /* page to be written */ unsigned int wb_offset; /* offset within page */ @@ -169,17 +170,17 @@ * Offset is the data offset within the page. */ static int -nfs_writepage_sync(struct inode *inode, struct page *page, - unsigned long offset, unsigned int count) +nfs_writepage_sync(struct dentry *dentry, struct inode *inode, + struct page *page, unsigned long offset, unsigned int count) { - struct nfs_fattr fattr; unsigned int wsize = NFS_SERVER(inode)->wsize; int result, refresh = 0, written = 0; u8 *buffer; + struct nfs_fattr fattr; - dprintk("NFS: nfs_writepage_sync(%x/%ld %d@%ld)\n", - inode->i_dev, inode->i_ino, - count, page->offset + offset); + dprintk("NFS: nfs_writepage_sync(%s/%s %d@%ld)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + count, page->offset + offset); buffer = (u8 *) page_address(page) + offset; offset += page->offset; @@ -188,7 +189,7 @@ if (count < wsize && !IS_SWAPFILE(inode)) wsize = count; - result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), + result = nfs_proc_write(NFS_DSERVER(dentry), NFS_FH(dentry), IS_SWAPFILE(inode), offset, wsize, buffer, &fattr); @@ -380,16 +381,16 @@ * Create and initialize a writeback request */ static inline struct nfs_wreq * -create_write_request(struct inode *inode, struct page *page, - unsigned int offset, unsigned int bytes) +create_write_request(struct dentry *dentry, struct inode *inode, + struct page *page, unsigned int offset, unsigned int bytes) { struct nfs_wreq *wreq; struct rpc_clnt *clnt = NFS_CLIENT(inode); struct rpc_task *task; - dprintk("NFS: create_write_request(%x/%ld, %ld+%d)\n", - inode->i_dev, inode->i_ino, - page->offset + offset, bytes); + dprintk("NFS: create_write_request(%s/%s, %ld+%d)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + page->offset + offset, bytes); /* FIXME: Enforce hard limit on number of concurrent writes? */ @@ -408,6 +409,7 @@ goto out_req; /* Put the task on inode's writeback request list. */ + wreq->wb_dentry = dentry; wreq->wb_inode = inode; wreq->wb_pid = current->pid; wreq->wb_page = page; @@ -504,9 +506,9 @@ * (for now), and we currently do this synchronously only. */ int -nfs_writepage(struct inode *inode, struct page *page) +nfs_writepage(struct dentry *dentry, struct page *page) { - return nfs_writepage_sync(inode, page, 0, PAGE_SIZE); + return nfs_writepage_sync(dentry, dentry->d_inode, page, 0, PAGE_SIZE); } /* @@ -516,16 +518,17 @@ * things with a page scheduled for an RPC call (e.g. invalidate it). */ int -nfs_updatepage(struct inode *inode, struct page *page, const char *buffer, +nfs_updatepage(struct dentry *dentry, struct page *page, const char *buffer, unsigned long offset, unsigned int count, int sync) { + struct inode *inode = dentry->d_inode; struct nfs_wreq *req; int status = 0, page_locked = 1; u8 *page_addr; - dprintk("NFS: nfs_updatepage(%x/%ld %d@%ld, sync=%d)\n", - inode->i_dev, inode->i_ino, - count, page->offset+offset, sync); + dprintk("NFS: nfs_updatepage(%s/%s %d@%ld, sync=%d)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + count, page->offset+offset, sync); set_bit(PG_locked, &page->flags); page_addr = (u8 *) page_address(page); @@ -535,7 +538,7 @@ */ if (NFS_SERVER(inode)->wsize < PAGE_SIZE) { copy_from_user(page_addr + offset, buffer, count); - return nfs_writepage_sync(inode, page, offset, count); + return nfs_writepage_sync(dentry, inode, page, offset, count); } /* @@ -560,7 +563,7 @@ /* Create the write request. */ status = -ENOBUFS; - req = create_write_request(inode, page, offset, count); + req = create_write_request(dentry, inode, page, offset, count); if (!req) goto done; @@ -823,7 +826,7 @@ { struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata; struct page *page = req->wb_page; - struct inode *inode = req->wb_inode; + struct dentry *dentry = req->wb_dentry; dprintk("NFS: %4d nfs_wback_lock (status %d flags %x)\n", task->tk_pid, task->tk_status, req->wb_flags); @@ -856,7 +859,7 @@ } /* Setup the task struct for a writeback call */ - req->wb_args->fh = NFS_FH(inode); + req->wb_args->fh = NFS_FH(dentry); req->wb_args->offset = page->offset + req->wb_offset; req->wb_args->count = req->wb_bytes; req->wb_args->buffer = (void *) (page_address(page) + req->wb_offset); @@ -873,16 +876,12 @@ nfs_wback_result(struct rpc_task *task) { struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata; - struct inode *inode; - struct page *page; - int status; + struct inode *inode = req->wb_inode; + struct page *page = req->wb_page; + int status = task->tk_status; dprintk("NFS: %4d nfs_wback_result (status %d)\n", - task->tk_pid, task->tk_status); - - inode = req->wb_inode; - page = req->wb_page; - status = task->tk_status; + task->tk_pid, status); if (status < 0) { /* diff -u --recursive --new-file v2.1.77/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.1.77/linux/fs/nfsd/vfs.c Tue Dec 23 16:31:00 1997 +++ linux/fs/nfsd/vfs.c Sun Jan 4 00:53:43 1998 @@ -230,7 +230,7 @@ if (iap->ia_valid) { iap->ia_valid |= ATTR_CTIME; iap->ia_ctime = CURRENT_TIME; - err = notify_change(inode, iap); + err = notify_change(dentry, iap); if (err) return nfserrno(-err); if (EX_ISSYNC(fhp->fh_export)) @@ -475,7 +475,7 @@ ia.ia_valid = ATTR_MODE; ia.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID); - notify_change(inode, &ia); + notify_change(dentry, &ia); } fh_unlock(fhp); /* unlock inode */ @@ -668,7 +668,7 @@ fh_lock(fhp); newattrs.ia_size = size; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - err = notify_change(inode, &newattrs); + err = notify_change(dentry, &newattrs); if (!err) { vmtruncate(inode, size); if (inode->i_op && inode->i_op->truncate) @@ -710,7 +710,7 @@ UPDATE_ATIME(inode); /* N.B. Why does this call need a get_fs()?? */ oldfs = get_fs(); set_fs(KERNEL_DS); - err = inode->i_op->readlink(inode, buf, *lenp); + err = inode->i_op->readlink(dentry, buf, *lenp); set_fs(oldfs); if (err < 0) @@ -789,7 +789,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int len, struct svc_fh *tfhp) { - struct dentry *ddir, *dnew; + struct dentry *ddir, *dnew, *dold; struct inode *dirp, *dest; int err; @@ -811,12 +811,14 @@ err = -EEXIST; if (dnew->d_inode) goto dput_and_out; - dest = tfhp->fh_dentry->d_inode; err = -EPERM; if (!len) goto dput_and_out; + dold = tfhp->fh_dentry; + dest = dold->d_inode; + err = -EACCES; if (nfsd_iscovered(ddir, ffhp->fh_export)) goto dput_and_out; @@ -830,7 +832,7 @@ goto dput_and_out; fh_lock(ffhp); - err = dirp->i_op->link(dest, dirp, dnew); + err = dirp->i_op->link(dold, dirp, dnew); fh_unlock(ffhp); if (!err && EX_ISSYNC(ffhp->fh_export)) { diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp437.c linux/fs/nls/nls_cp437.c --- v2.1.77/linux/fs/nls/nls_cp437.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp437.c Sun Jan 4 10:55:09 1998 @@ -355,6 +355,7 @@ page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -389,6 +390,7 @@ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp737.c linux/fs/nls/nls_cp737.c --- v2.1.77/linux/fs/nls/nls_cp737.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp737.c Sun Jan 4 10:55:09 1998 @@ -283,6 +283,7 @@ page20, NULL, page22, NULL, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -317,6 +318,7 @@ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp775.c linux/fs/nls/nls_cp775.c --- v2.1.77/linux/fs/nls/nls_cp775.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp775.c Sun Jan 4 10:55:09 1998 @@ -283,6 +283,7 @@ page20, NULL, page22, NULL, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -317,6 +318,7 @@ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp850.c linux/fs/nls/nls_cp850.c --- v2.1.77/linux/fs/nls/nls_cp850.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp850.c Sun Jan 4 10:55:09 1998 @@ -247,6 +247,7 @@ page20, NULL, NULL, NULL, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -281,6 +282,7 @@ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp852.c linux/fs/nls/nls_cp852.c --- v2.1.77/linux/fs/nls/nls_cp852.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp852.c Sun Jan 4 10:55:09 1998 @@ -247,6 +247,7 @@ NULL, NULL, NULL, NULL, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -281,6 +282,7 @@ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ 0xf8, 0xf9, 0xfa, 0x00, 0xfc, 0x00, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp855.c linux/fs/nls/nls_cp855.c --- v2.1.77/linux/fs/nls/nls_cp855.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp855.c Sun Jan 4 10:55:09 1998 @@ -247,6 +247,7 @@ NULL, page21, NULL, NULL, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -281,6 +282,7 @@ 0xf0, 0x00, 0xf2, 0x00, 0xf4, 0x00, 0xf6, 0x00, /* 0xf0-0xf7 */ 0xf8, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp857.c linux/fs/nls/nls_cp857.c --- v2.1.77/linux/fs/nls/nls_cp857.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp857.c Sun Jan 4 10:55:09 1998 @@ -211,6 +211,7 @@ NULL, NULL, NULL, NULL, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -245,6 +246,7 @@ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp860.c linux/fs/nls/nls_cp860.c --- v2.1.77/linux/fs/nls/nls_cp860.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp860.c Sun Jan 4 10:55:09 1998 @@ -319,6 +319,7 @@ page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -353,6 +354,7 @@ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/nls/nls_cp861.c linux/fs/nls/nls_cp861.c --- v2.1.77/linux/fs/nls/nls_cp861.c Sat Oct 25 02:44:18 1997 +++ linux/fs/nls/nls_cp861.c Sun Jan 4 10:55:09 1998 @@ -355,6 +355,7 @@ page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; +#if 0 static unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ @@ -389,6 +390,7 @@ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; +#endif static void inc_use_count(void) diff -u --recursive --new-file v2.1.77/linux/fs/open.c linux/fs/open.c --- v2.1.77/linux/fs/open.c Tue Sep 23 16:48:49 1997 +++ linux/fs/open.c Sun Jan 4 00:53:41 1998 @@ -69,15 +69,16 @@ return error; } -int do_truncate(struct inode *inode, unsigned long length) +int do_truncate(struct dentry *dentry, unsigned long length) { + struct inode *inode = dentry->d_inode; int error; struct iattr newattrs; down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - error = notify_change(inode, &newattrs); + error = notify_change(dentry, &newattrs); if (!error) { /* truncate virtual mappings of this file */ vmtruncate(inode, length); @@ -128,7 +129,7 @@ if (!error) { if (inode->i_sb && inode->i_sb->dq_op) inode->i_sb->dq_op->initialize(inode, -1); - error = do_truncate(inode, length); + error = do_truncate(dentry, length); } put_write_access(inode); dput_and_out: @@ -161,7 +162,7 @@ lengthi_size ? length : inode->i_size, abs(inode->i_size - length)); if (!error) - error = do_truncate(inode, length); + error = do_truncate(dentry, length); } unlock_kernel(); return error; @@ -214,7 +215,7 @@ (error = permission(inode,MAY_WRITE)) != 0) goto dput_and_out; } - error = notify_change(inode, &newattrs); + error = notify_change(dentry, &newattrs); dput_and_out: dput(dentry); out: @@ -261,7 +262,7 @@ if ((error = permission(inode,MAY_WRITE)) != 0) goto dput_and_out; } - error = notify_change(inode, &newattrs); + error = notify_change(dentry, &newattrs); dput_and_out: dput(dentry); out: @@ -441,7 +442,7 @@ mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - err = notify_change(inode, &newattrs); + err = notify_change(dentry, &newattrs); out: unlock_kernel(); return err; @@ -474,7 +475,7 @@ mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(inode, &newattrs); + error = notify_change(dentry, &newattrs); dput_and_out: dput(dentry); @@ -530,11 +531,11 @@ error = -EDQUOT; if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0)) goto out; - error = notify_change(inode, &newattrs); + error = notify_change(dentry, &newattrs); if (error) inode->i_sb->dq_op->transfer(inode, &newattrs, 1); } else - error = notify_change(inode, &newattrs); + error = notify_change(dentry, &newattrs); out: return error; } diff -u --recursive --new-file v2.1.77/linux/fs/proc/link.c linux/fs/proc/link.c --- v2.1.77/linux/fs/proc/link.c Mon Aug 4 16:25:39 1997 +++ linux/fs/proc/link.c Sun Jan 4 23:58:28 1998 @@ -15,8 +15,8 @@ #include #include -static int proc_readlink(struct inode *, char *, int); -static struct dentry * proc_follow_link(struct inode *, struct dentry *); +static int proc_readlink(struct dentry *, char *, int); +static struct dentry * proc_follow_link(struct dentry *, struct dentry *); /* * PLAN9_SEMANTICS won't work any more: it used an ugly hack that broke @@ -60,8 +60,10 @@ NULL /* permission */ }; -static struct dentry * proc_follow_link(struct inode *inode, struct dentry *base) +static struct dentry * proc_follow_link(struct dentry *dentry, + struct dentry *base) { + struct inode *inode = dentry->d_inode; struct task_struct *p; struct dentry * result; int ino, pid; @@ -73,7 +75,7 @@ error = permission(inode, MAY_EXEC); result = ERR_PTR(error); if (error) - return result; + goto out; ino = inode->i_ino; pid = ino >> 16; @@ -82,7 +84,7 @@ p = find_task_by_pid(pid); result = ERR_PTR(-ENOENT); if (!p) - return result; + goto out; switch (ino) { case PROC_PID_CWD: @@ -126,30 +128,56 @@ break; } } +out: return result; } -static int proc_readlink(struct inode * inode, char * buffer, int buflen) +/* + * This pretty-prints the pathname of a dentry, + * clarifying sockets etc. + */ +static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen) +{ + struct inode * inode; + char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern; + int len; + + /* Check for special dentries.. */ + pattern = NULL; + inode = dentry->d_inode; + if (inode && dentry->d_parent == dentry) { + if (inode->i_sock) + pattern = "socket:[%lu]"; + if (inode->i_pipe) + pattern = "pipe:[%lu]"; + } + + if (pattern) { + len = sprintf(tmp, pattern, inode->i_ino); + path = tmp; + } else { + path = d_path(dentry, tmp, PAGE_SIZE); + len = tmp + PAGE_SIZE - path; + } + + if (len < buflen) + buflen = len; + dput(dentry); + copy_to_user(buffer, path, buflen); + free_page((unsigned long)tmp); + return buflen; +} + +static int proc_readlink(struct dentry * dentry, char * buffer, int buflen) { int error; - struct dentry * dentry = proc_follow_link(inode, NULL); + dentry = proc_follow_link(dentry, NULL); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { error = -ENOENT; if (dentry) { - char * tmp = (char*)__get_free_page(GFP_KERNEL), *path; - int len; - - path = d_path(dentry, tmp, PAGE_SIZE); - len = tmp + PAGE_SIZE - path; - - if (len < buflen) - buflen = len; - dput(dentry); - copy_to_user(buffer, path, buflen); - free_page((unsigned long)tmp); - error = buflen; + error = do_proc_readlink(dentry, buffer, buflen); } } return error; diff -u --recursive --new-file v2.1.77/linux/fs/proc/proc_devtree.c linux/fs/proc/proc_devtree.c --- v2.1.77/linux/fs/proc/proc_devtree.c Mon Aug 18 18:19:46 1997 +++ linux/fs/proc/proc_devtree.c Sun Jan 4 00:53:41 1998 @@ -65,24 +65,24 @@ NULL /* smap */ }; -static struct dentry *devtree_follow_link(struct inode *inode, +static struct dentry *devtree_follow_link(struct dentry *dentry, struct dentry *base) { struct proc_dir_entry * de; char *link; - de = (struct proc_dir_entry *) inode->u.generic_ip; + de = (struct proc_dir_entry *) dentry->inode->u.generic_ip; link = (char *) de->data; return lookup_dentry(link, base, 1); } -static int devtree_readlink(struct inode *inode, char *buffer, int buflen) +static int devtree_readlink(struct dentry *dentry, char *buffer, int buflen) { struct proc_dir_entry * de; char *link; int linklen; - de = (struct proc_dir_entry *) inode->u.generic_ip; + de = (struct proc_dir_entry *) dentry->inode->u.generic_ip; link = (char *) de->data; linklen = strlen(link); if (linklen > buflen) diff -u --recursive --new-file v2.1.77/linux/fs/proc/root.c linux/fs/proc/root.c --- v2.1.77/linux/fs/proc/root.c Wed Oct 15 16:04:23 1997 +++ linux/fs/proc/root.c Sun Jan 4 00:53:41 1998 @@ -368,7 +368,7 @@ /* * /proc/self: */ -static int proc_self_readlink(struct inode * inode, char * buffer, int buflen) +static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen) { int len; char tmp[30]; @@ -380,12 +380,12 @@ return len; } -static struct dentry * proc_self_follow_link(struct inode *inode, struct dentry *base) +static struct dentry * proc_self_follow_link(struct dentry *dentry, + struct dentry *base) { - int len; char tmp[30]; - len = sprintf(tmp, "%d", current->pid); + sprintf(tmp, "%d", current->pid); return lookup_dentry(tmp, base, 1); } diff -u --recursive --new-file v2.1.77/linux/fs/romfs/inode.c linux/fs/romfs/inode.c --- v2.1.77/linux/fs/romfs/inode.c Thu Sep 11 09:02:24 1997 +++ linux/fs/romfs/inode.c Sun Jan 4 00:53:43 1998 @@ -391,8 +391,9 @@ */ static int -romfs_readpage(struct inode * inode, struct page * page) +romfs_readpage(struct dentry * dentry, struct page * page) { + struct inode *inode = dentry->d_inode; unsigned long buf; unsigned long offset, avail, readlen; int result = -EIO; @@ -428,8 +429,9 @@ } static int -romfs_readlink(struct inode *inode, char *buffer, int len) +romfs_readlink(struct dentry *dentry, char *buffer, int len) { + struct inode *inode = dentry->d_inode; int mylen; char buf[ROMFS_MAXFN]; /* XXX dynamic */ @@ -450,11 +452,12 @@ return mylen; } -static struct dentry *romfs_follow_link(struct inode *inode, struct dentry *base) +static struct dentry *romfs_follow_link(struct dentry *dentry, + struct dentry *base) { + struct inode *inode = dentry->d_inode; char *link; int len, cnt; - struct dentry *dentry; len = inode->i_size; diff -u --recursive --new-file v2.1.77/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c --- v2.1.77/linux/fs/smbfs/dir.c Sun Dec 21 16:17:45 1997 +++ linux/fs/smbfs/dir.c Sun Jan 4 00:53:42 1998 @@ -89,7 +89,7 @@ /* * Make sure our inode is up-to-date. */ - result = smb_revalidate_inode(dir); + result = smb_revalidate_inode(dentry); if (result) goto out; /* @@ -183,7 +183,7 @@ } if (server->conn_pid) - error = smb_revalidate_inode(dir); + error = smb_revalidate_inode(dentry); return error; } @@ -235,7 +235,7 @@ #endif valid = 0; } else if (!valid) - valid = (smb_revalidate_inode(inode) == 0); + valid = (smb_revalidate_inode(dentry) == 0); } else { /* diff -u --recursive --new-file v2.1.77/linux/fs/smbfs/file.c linux/fs/smbfs/file.c --- v2.1.77/linux/fs/smbfs/file.c Fri Dec 19 15:53:01 1997 +++ linux/fs/smbfs/file.c Sun Jan 4 00:53:42 1998 @@ -52,24 +52,17 @@ * Read a page synchronously. */ static int -smb_readpage_sync(struct inode *inode, struct page *page) +smb_readpage_sync(struct dentry *dentry, struct page *page) { + struct inode *inode = dentry->d_inode; char *buffer = (char *) page_address(page); unsigned long offset = page->offset; - struct dentry * dentry = inode->u.smbfs_i.dentry; int rsize = smb_get_rsize(SMB_SERVER(inode)); int count = PAGE_SIZE; int result; clear_bit(PG_error, &page->flags); - result = -EIO; - if (!dentry) { - printk("smb_readpage_sync: no dentry for inode %ld\n", - inode->i_ino); - goto io_error; - } - #ifdef SMBFS_DEBUG_VERBOSE printk("smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, rsize); @@ -110,7 +103,7 @@ } int -smb_readpage(struct inode *inode, struct page *page) +smb_readpage(struct dentry *dentry, struct page *page) { int error; @@ -121,7 +114,7 @@ #endif set_bit(PG_locked, &page->flags); atomic_inc(&page->count); - error = smb_readpage_sync(inode, page); + error = smb_readpage_sync(dentry, page); free_page(page_address(page)); return error; } @@ -131,9 +124,10 @@ * Offset is the data offset within the page. */ static int -smb_writepage_sync(struct inode *inode, struct page *page, +smb_writepage_sync(struct dentry *dentry, struct page *page, unsigned long offset, unsigned int count) { + struct inode *inode = dentry->d_inode; u8 *buffer = (u8 *) page_address(page) + offset; int wsize = smb_get_wsize(SMB_SERVER(inode)); int result, written = 0; @@ -141,8 +135,7 @@ offset += page->offset; #ifdef SMBFS_DEBUG_VERBOSE printk("smb_writepage_sync: file %s/%s, count=%d@%ld, wsize=%d\n", -((struct dentry *) inode->u.smbfs_i.dentry)->d_parent->d_name.name, -((struct dentry *) inode->u.smbfs_i.dentry)->d_name.name, count, offset, wsize); +dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, wsize); #endif do { @@ -185,7 +178,7 @@ * (for now), and we currently do this synchronously only. */ static int -smb_writepage(struct inode *inode, struct page *page) +smb_writepage(struct dentry *dentry, struct page *page) { int result; @@ -195,21 +188,21 @@ #endif set_bit(PG_locked, &page->flags); atomic_inc(&page->count); - result = smb_writepage_sync(inode, page, 0, PAGE_SIZE); + result = smb_writepage_sync(dentry, page, 0, PAGE_SIZE); free_page(page_address(page)); return result; } static int -smb_updatepage(struct inode *inode, struct page *page, const char *buffer, +smb_updatepage(struct dentry *dentry, struct page *page, const char *buffer, unsigned long offset, unsigned int count, int sync) { unsigned long page_addr = page_address(page); int result; - pr_debug("SMB: smb_updatepage(%x/%ld %d@%ld, sync=%d)\n", - inode->i_dev, inode->i_ino, - count, page->offset+offset, sync); + pr_debug("SMBFS: smb_updatepage(%s/%s %d@%ld, sync=%d)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + count, page->offset+offset, sync); #ifdef SMBFS_PARANOIA if (test_bit(PG_locked, &page->flags)) @@ -220,7 +213,7 @@ if (copy_from_user((char *) page_addr + offset, buffer, count)) goto bad_fault; - result = smb_writepage_sync(inode, page, offset, count); + result = smb_writepage_sync(dentry, page, offset, count); out: free_page(page_addr); return result; @@ -240,7 +233,6 @@ smb_file_read(struct file * file, char * buf, size_t count, loff_t *ppos) { struct dentry * dentry = file->f_dentry; - struct inode * inode = dentry->d_inode; ssize_t status; #ifdef SMBFS_DEBUG_VERBOSE @@ -249,7 +241,7 @@ (unsigned long) count, (unsigned long) *ppos); #endif - status = smb_revalidate_inode(inode); + status = smb_revalidate_inode(dentry); if (status) { #ifdef SMBFS_PARANOIA @@ -261,7 +253,8 @@ #ifdef SMBFS_DEBUG_VERBOSE printk("smb_file_read: before read, size=%ld, pages=%ld, flags=%x, atime=%ld\n", -inode->i_size, inode->i_nrpages, inode->i_flags, inode->i_atime); +dentry->d_inode->i_size, dentry->d_inode->i_nrpages, dentry->d_inode->i_flags, +dentry->d_inode->i_atime); #endif status = generic_file_read(file, buf, count, ppos); out: @@ -272,16 +265,14 @@ smb_file_mmap(struct file * file, struct vm_area_struct * vma) { struct dentry * dentry = file->f_dentry; - struct inode * inode = dentry->d_inode; int status; #ifdef SMBFS_DEBUG_VERBOSE printk("smb_file_mmap: file %s/%s, address %lu - %lu\n", -dentry->d_parent->d_name.name, dentry->d_name.name, -vma->vm_start, vma->vm_end); +dentry->d_parent->d_name.name, dentry->d_name.name, vma->vm_start, vma->vm_end); #endif - status = smb_revalidate_inode(inode); + status = smb_revalidate_inode(dentry); if (status) { #ifdef SMBFS_PARANOIA @@ -302,16 +293,15 @@ smb_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { struct dentry * dentry = file->f_dentry; - struct inode * inode = dentry->d_inode; ssize_t result; #ifdef SMBFS_DEBUG_VERBOSE printk("smb_file_write: file %s/%s, count=%lu@%lu, pages=%ld\n", dentry->d_parent->d_name.name, dentry->d_name.name, -(unsigned long) count, (unsigned long) *ppos, inode->i_nrpages); +(unsigned long) count, (unsigned long) *ppos, dentry->d_inode->i_nrpages); #endif - result = smb_revalidate_inode(inode); + result = smb_revalidate_inode(dentry); if (result) { #ifdef SMBFS_PARANOIA @@ -330,7 +320,8 @@ result = generic_file_write(file, buf, count, ppos); #ifdef SMBFS_DEBUG_VERBOSE printk("smb_file_write: pos=%ld, size=%ld, mtime=%ld, atime=%ld\n", -(long) file->f_pos, inode->i_size, inode->i_mtime, inode->i_atime); +(long) file->f_pos, dentry->d_inode->i_size, dentry->d_inode->i_mtime, +dentry->d_inode->i_atime); #endif } out: diff -u --recursive --new-file v2.1.77/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v2.1.77/linux/fs/smbfs/inode.c Sun Dec 21 16:17:45 1997 +++ linux/fs/smbfs/inode.c Sun Jan 4 00:53:42 1998 @@ -186,8 +186,9 @@ * invalidate our local caches. */ int -smb_revalidate_inode(struct inode *inode) +smb_revalidate_inode(struct dentry *dentry) { + struct inode *inode = dentry->d_inode; time_t last_time; int error = 0; @@ -224,8 +225,7 @@ { #ifdef SMBFS_DEBUG_VERBOSE printk("smb_revalidate: %s/%s changed, old=%ld, new=%ld\n", -((struct dentry *)inode->u.smbfs_i.dentry)->d_parent->d_name.name, -((struct dentry *)inode->u.smbfs_i.dentry)->d_name.name, +dentry->d_parent->d_name.name, dentry->d_name.name, (long) last_time, (long) inode->i_mtime); #endif if (!S_ISDIR(inode->i_mode)) @@ -492,22 +492,15 @@ } int -smb_notify_change(struct inode *inode, struct iattr *attr) +smb_notify_change(struct dentry *dentry, struct iattr *attr) { - struct smb_sb_info *server = SMB_SERVER(inode); - struct dentry *dentry = inode->u.smbfs_i.dentry; + struct inode *inode = dentry->d_inode; + struct smb_sb_info *server = server_from_dentry(dentry); unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); int error, changed, refresh = 0; struct smb_fattr fattr; - error = -EIO; - if (!dentry) - { - printk("smb_notify_change: no dentry for inode!\n"); - goto out; - } - - error = smb_revalidate_inode(inode); + error = smb_revalidate_inode(dentry); if (error) goto out; diff -u --recursive --new-file v2.1.77/linux/fs/stat.c linux/fs/stat.c --- v2.1.77/linux/fs/stat.c Thu Jul 17 10:06:07 1997 +++ linux/fs/stat.c Sun Jan 4 00:53:41 1998 @@ -20,10 +20,11 @@ * Revalidate the inode. This is required for proper NFS attribute caching. */ static __inline__ int -do_revalidate(struct inode *inode) +do_revalidate(struct dentry *dentry) { + struct inode * inode = dentry->d_inode; if (inode->i_op && inode->i_op->revalidate) - return inode->i_op->revalidate(inode); + return inode->i_op->revalidate(dentry); return 0; } @@ -128,10 +129,9 @@ error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - struct inode * inode = dentry->d_inode; - error = do_revalidate(inode); + error = do_revalidate(dentry); if (!error) - error = cp_old_stat(inode, statbuf); + error = cp_old_stat(dentry->d_inode, statbuf); dput(dentry); } @@ -150,10 +150,9 @@ error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - struct inode * inode = dentry->d_inode; - error = do_revalidate(inode); + error = do_revalidate(dentry); if (!error) - error = cp_new_stat(inode,statbuf); + error = cp_new_stat(dentry->d_inode, statbuf); dput(dentry); } @@ -177,10 +176,9 @@ error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - struct inode * inode = dentry->d_inode; - error = do_revalidate(inode); + error = do_revalidate(dentry); if (!error) - error = cp_old_stat(inode, statbuf); + error = cp_old_stat(dentry->d_inode, statbuf); dput(dentry); } @@ -200,10 +198,9 @@ error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - struct inode * inode = dentry->d_inode; - error = do_revalidate(inode); + error = do_revalidate(dentry); if (!error) - error = cp_new_stat(inode,statbuf); + error = cp_new_stat(dentry->d_inode, statbuf); dput(dentry); } @@ -225,11 +222,10 @@ lock_kernel(); if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) { struct dentry * dentry = f->f_dentry; - struct inode * inode = dentry->d_inode; - err = do_revalidate(inode); + err = do_revalidate(dentry); if (!err) - err = cp_old_stat(inode,statbuf); + err = cp_old_stat(dentry->d_inode, statbuf); } unlock_kernel(); return err; @@ -245,11 +241,10 @@ lock_kernel(); if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) { struct dentry * dentry = f->f_dentry; - struct inode * inode = dentry->d_inode; - err = do_revalidate(inode); + err = do_revalidate(dentry); if (!err) - err = cp_new_stat(inode,statbuf); + err = cp_new_stat(dentry->d_inode, statbuf); } unlock_kernel(); return err; @@ -271,9 +266,10 @@ struct inode * inode = dentry->d_inode; error = -EINVAL; - if (inode->i_op && inode->i_op->readlink && !(error = do_revalidate(inode))) { + if (inode->i_op && inode->i_op->readlink && + !(error = do_revalidate(dentry))) { UPDATE_ATIME(inode); - error = inode->i_op->readlink(inode,buf,bufsiz); + error = inode->i_op->readlink(dentry, buf, bufsiz); } dput(dentry); } diff -u --recursive --new-file v2.1.77/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.1.77/linux/fs/sysv/inode.c Sat Oct 25 02:44:18 1997 +++ linux/fs/sysv/inode.c Sun Jan 4 00:53:41 1998 @@ -873,8 +873,9 @@ } /* To avoid inconsistencies between inodes in memory and inodes on disk. */ -extern int sysv_notify_change(struct inode *inode, struct iattr *attr) +extern int sysv_notify_change(struct dentry *dentry, struct iattr *attr) { + struct inode *inode = dentry->d_inode; int error; if ((error = inode_change_ok(inode, attr)) != 0) diff -u --recursive --new-file v2.1.77/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c --- v2.1.77/linux/fs/sysv/symlink.c Thu Jul 17 10:06:08 1997 +++ linux/fs/sysv/symlink.c Sun Jan 4 00:53:41 1998 @@ -20,8 +20,8 @@ #include -static int sysv_readlink(struct inode *, char *, int); -static struct dentry *sysv_follow_link(struct inode *, struct dentry *); +static int sysv_readlink(struct dentry *, char *, int); +static struct dentry *sysv_follow_link(struct dentry *, struct dentry *); /* * symlinks can't do much... @@ -46,8 +46,10 @@ NULL /* permission */ }; -static struct dentry *sysv_follow_link(struct inode * inode, struct dentry * base) +static struct dentry *sysv_follow_link(struct dentry * dentry, + struct dentry * base) { + struct inode *inode = dentry->d_inode; struct buffer_head * bh; bh = sysv_file_bread(inode, 0, 0); @@ -61,8 +63,9 @@ return base; } -static int sysv_readlink(struct inode * inode, char * buffer, int buflen) +static int sysv_readlink(struct dentry * dentry, char * buffer, int buflen) { + struct inode *inode = dentry->d_inode; struct buffer_head * bh; char * bh_data; int i; diff -u --recursive --new-file v2.1.77/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c --- v2.1.77/linux/fs/ufs/ufs_symlink.c Wed Dec 10 11:12:45 1997 +++ linux/fs/ufs/ufs_symlink.c Sun Jan 4 00:53:41 1998 @@ -19,8 +19,9 @@ extern int ufs_bmap (struct inode *, int); static int -ufs_readlink(struct inode * inode, char * buffer, int buflen) +ufs_readlink(struct dentry * dentry, char * buffer, int buflen) { + struct inode * inode = dentry->d_inode; unsigned long int block; struct buffer_head * bh = NULL; char * link; @@ -71,8 +72,9 @@ * XXX - blatantly stolen from minix fs */ static struct dentry * -ufs_follow_link(struct inode * inode, struct dentry * base) +ufs_follow_link(struct dentry * dentry, struct dentry * base) { + struct inode * inode = dentry->d_inode; unsigned long int block; struct buffer_head * bh = NULL; char * link; diff -u --recursive --new-file v2.1.77/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v2.1.77/linux/include/linux/cdrom.h Fri Jan 2 14:37:02 1998 +++ linux/include/linux/cdrom.h Mon Jan 5 00:06:26 1998 @@ -4,7 +4,7 @@ * Copyright (C) 1992 David Giller, rafetmad@oxy.edu * 1994, 1995 Eberhard Moenkeberg, emoenke@gwdg.de * 1996 David van Leeuwen, david@tm.tno.nl - * 1997 Erik Andersen, andersee@debian.org + * 1997, 1998 Erik Andersen, andersee@debian.org */ #ifndef _LINUX_CDROM_H @@ -417,4 +417,4 @@ extern int unregister_cdrom(struct cdrom_device_info *cdi); #endif /* End of kernel only stuff */ -#endif _LINUX_CDROM_H +#endif /* _LINUX_CDROM_H */ diff -u --recursive --new-file v2.1.77/linux/include/linux/config.h linux/include/linux/config.h --- v2.1.77/linux/include/linux/config.h Mon Jul 7 16:02:01 1997 +++ linux/include/linux/config.h Mon Jan 5 01:41:01 1998 @@ -3,28 +3,4 @@ #include -/* - * Defines for what uname() should return - */ -#ifndef UTS_SYSNAME -#define UTS_SYSNAME "Linux" -#endif - -#ifndef UTS_MACHINE -#define UTS_MACHINE "unknown" -#endif - -#ifndef UTS_NODENAME -#define UTS_NODENAME "(none)" /* set by sethostname() */ -#endif - -#ifndef UTS_DOMAINNAME -#define UTS_DOMAINNAME "(none)" /* set by setdomainname() */ -#endif - -/* - * The definitions for UTS_RELEASE and UTS_VERSION are now defined - * in linux/version.h, and should only be used by linux/version.c - */ - #endif diff -u --recursive --new-file v2.1.77/linux/include/linux/dcache.h linux/include/linux/dcache.h --- v2.1.77/linux/include/linux/dcache.h Tue Dec 2 09:49:40 1997 +++ linux/include/linux/dcache.h Sun Jan 4 00:53:40 1998 @@ -66,6 +66,7 @@ struct dentry_operations *d_op; struct super_block * d_sb; /* The root of the dentry tree */ unsigned long d_reftime; /* last time referenced */ + void * d_fsdata; /* fs-specific data */ }; struct dentry_operations { @@ -73,6 +74,7 @@ int (*d_hash) (struct dentry *,struct qstr *); int (*d_compare) (struct dentry *,struct qstr *, struct qstr *); void (*d_delete)(struct dentry *); + void (*d_release)(struct dentry *); }; /* the dentry parameter passed to d_hash and d_compare is the parent diff -u --recursive --new-file v2.1.77/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v2.1.77/linux/include/linux/ext2_fs.h Tue Sep 23 16:48:49 1997 +++ linux/include/linux/ext2_fs.h Sun Jan 4 00:53:40 1998 @@ -499,9 +499,10 @@ extern int ext2_rmdir (struct inode *,struct dentry *); extern int ext2_unlink (struct inode *,struct dentry *); extern int ext2_symlink (struct inode *,struct dentry *,const char *); -extern int ext2_link (struct inode *, struct inode *, struct dentry *); +extern int ext2_link (struct dentry *, struct inode *, struct dentry *); extern int ext2_mknod (struct inode *, struct dentry *, int, int); -extern int ext2_rename (struct inode *, struct dentry *,struct inode *, struct dentry *); +extern int ext2_rename (struct inode *, struct dentry *, + struct inode *, struct dentry *); /* super.c */ extern void ext2_error (struct super_block *, const char *, const char *, ...) diff -u --recursive --new-file v2.1.77/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.77/linux/include/linux/fs.h Tue Dec 23 16:31:00 1997 +++ linux/include/linux/fs.h Mon Jan 5 01:43:43 1998 @@ -266,6 +266,7 @@ #include #include #include +#include /* * Attribute flags. These should be or-ed together to figure out what @@ -366,6 +367,7 @@ struct ufs_inode_info ufs_i; struct romfs_inode_info romfs_i; struct smb_inode_info smbfs_i; + struct hfs_inode_info hfs_i; struct socket socket_i; void *generic_ip; } u; @@ -503,6 +505,7 @@ #include #include #include +#include struct super_block { kdev_t s_dev; @@ -538,6 +541,7 @@ struct ufs_sb_info ufs_sb; struct romfs_sb_info romfs_sb; struct smb_sb_info smbfs_sb; + struct hfs_sb_info hfs_sb; void *generic_sbp; } u; }; @@ -571,24 +575,25 @@ struct file_operations * default_file_ops; int (*create) (struct inode *,struct dentry *,int); int (*lookup) (struct inode *,struct dentry *); - int (*link) (struct inode *,struct inode *,struct dentry *); + int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct inode *,struct dentry *,const char *); int (*mkdir) (struct inode *,struct dentry *,int); int (*rmdir) (struct inode *,struct dentry *); int (*mknod) (struct inode *,struct dentry *,int,int); - int (*rename) (struct inode *,struct dentry *,struct inode *,struct dentry *); - int (*readlink) (struct inode *,char *,int); - struct dentry * (*follow_link) (struct inode *, struct dentry *); - int (*readpage) (struct inode *, struct page *); - int (*writepage) (struct inode *, struct page *); + int (*rename) (struct inode *, struct dentry *, + struct inode *, struct dentry *); + int (*readlink) (struct dentry *, char *,int); + struct dentry * (*follow_link) (struct dentry *, struct dentry *); + int (*readpage) (struct dentry *, struct page *); + int (*writepage) (struct dentry *, struct page *); int (*bmap) (struct inode *,int); void (*truncate) (struct inode *); int (*permission) (struct inode *, int); int (*smap) (struct inode *,int); - int (*updatepage) (struct inode *, struct page *, const char *, + int (*updatepage) (struct dentry *, struct page *, const char *, unsigned long, unsigned int, int); - int (*revalidate) (struct inode *); + int (*revalidate) (struct dentry *); }; struct super_operations { @@ -596,7 +601,7 @@ void (*write_inode) (struct inode *); void (*put_inode) (struct inode *); void (*delete_inode) (struct inode *); - int (*notify_change) (struct inode *, struct iattr *); + int (*notify_change) (struct dentry *, struct iattr *); void (*put_super) (struct super_block *); void (*write_super) (struct super_block *); int (*statfs) (struct super_block *, struct statfs *, int); @@ -630,7 +635,7 @@ extern char * getname(const char * filename); extern void putname(char * name); -extern int do_truncate(struct inode *, unsigned long); +extern int do_truncate(struct dentry *, unsigned long); extern int register_blkdev(unsigned int, const char *, struct file_operations *); extern int unregister_blkdev(unsigned int major, const char * name); extern int blkdev_open(struct inode * inode, struct file * filp); @@ -710,7 +715,7 @@ extern int fsync_dev(kdev_t dev); extern void sync_supers(kdev_t dev); extern int bmap(struct inode * inode,int block); -extern int notify_change(struct inode *, struct iattr *); +extern int notify_change(struct dentry *, struct iattr *); extern int permission(struct inode * inode,int mask); extern int get_write_access(struct inode *inode); extern void put_write_access(struct inode *inode); @@ -800,7 +805,7 @@ extern int brw_page(int, struct page *, kdev_t, int [], int, int); -extern int generic_readpage(struct inode *, struct page *); +extern int generic_readpage(struct dentry *, struct page *); extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char*, size_t, loff_t*); @@ -831,7 +836,6 @@ extern int inode_change_ok(struct inode *, struct iattr *); extern void inode_setattr(struct inode *, struct iattr *); -extern int notify_change(struct inode * inode, struct iattr * attr); /* kludge to get SCSI modules working */ #include diff -u --recursive --new-file v2.1.77/linux/include/linux/genhd.h linux/include/linux/genhd.h --- v2.1.77/linux/include/linux/genhd.h Fri Jan 2 14:37:02 1998 +++ linux/include/linux/genhd.h Mon Jan 5 00:22:44 1998 @@ -26,6 +26,11 @@ #define DOS_EXTENDED_PARTITION 5 #define LINUX_EXTENDED_PARTITION 0x85 #define WIN98_EXTENDED_PARTITION 0x0f +#define LINUX_SWAP_PARTITION 0x82 + +#ifdef CONFIG_SOLARIS_X86_PARTITION +#define SOLARIS_X86_PARTITION LINUX_SWAP_PARTITION +#endif #define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */ #define EZD_PARTITION 0x55 /* EZ-DRIVE: same as DM6 (we think) */ @@ -66,6 +71,34 @@ void *real_devices; /* internal use */ struct gendisk *next; }; + +#ifdef CONFIG_SOLARIS_X86_PARTITION + +#define SOLARIS_X86_NUMSLICE 8 +#define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL) + +struct solaris_x86_slice { + ushort s_tag; /* ID tag of partition */ + ushort s_flag; /* permision flags */ + daddr_t s_start; /* start sector no of partition */ + long s_size; /* # of blocks in partition */ +}; + +struct solaris_x86_vtoc { + unsigned long v_bootinfo[3]; /* info needed by mboot (unsupported) */ + unsigned long v_sanity; /* to verify vtoc sanity */ + unsigned long v_version; /* layout version */ + char v_volume[8]; /* volume name */ + ushort v_sectorsz; /* sector size in bytes */ + ushort v_nparts; /* number of partitions */ + unsigned long v_reserved[10]; /* free space */ + struct solaris_x86_slice + v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */ + time_t timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */ + char v_asciilabel[128]; /* for compatibility */ +}; + +#endif /* CONFIG_SOLARIS_X86_PARTITION */ #ifdef CONFIG_BSD_DISKLABEL /* diff -u --recursive --new-file v2.1.77/linux/include/linux/hfs_fs.h linux/include/linux/hfs_fs.h --- v2.1.77/linux/include/linux/hfs_fs.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/hfs_fs.h Mon Jan 5 01:46:23 1998 @@ -0,0 +1,362 @@ +/* + * linux/include/linux/hfs_fs.h + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * The source code distribution of the Columbia AppleTalk Package for + * UNIX, version 6.0, (CAP) was used as a specification of the + * location and format of files used by CAP's Aufs. No code from CAP + * appears in hfs_fs. hfs_fs is not a work ``derived'' from CAP in + * the sense of intellectual property law. + * + * The source code distributions of Netatalk, versions 1.3.3b2 and + * 1.4b2, were used as a specification of the location and format of + * files used by Netatalk's afpd. No code from Netatalk appears in + * hfs_fs. hfs_fs is not a work ``derived'' from Netatalk in the + * sense of intellectual property law. + */ + +#ifndef _LINUX_HFS_FS_H +#define _LINUX_HFS_FS_H + +#include + +/* magic numbers for Apple Double header files */ +#define HFS_DBL_MAGIC 0x00051607 +#define HFS_SNGL_MAGIC 0x00051600 +#define HFS_HDR_VERSION_1 0x00010000 +#define HFS_HDR_VERSION_2 0x00020000 + +/* magic numbers for various internal structures */ +#define HFS_INO_MAGIC 0x4821 +#define HFS_SB_MAGIC 0x4822 + +/* The space used for the AppleDouble or AppleSingle headers */ +#define HFS_DBL_HDR_LEN 1024 + +/* The space used for the Netatalk header */ +#define HFS_NAT_HDR_LEN 1024 /* 589 for an exact match */ + +/* Macros to extract CNID and file "type" from the Linux inode number */ +#define HFS_CNID(X) ((X) & 0x3FFFFFFF) +#define HFS_ITYPE(X) ((X) & 0xC0000000) + +/* Macros to enumerate types */ +#define HFS_ITYPE_TO_INT(X) ((X) >> 30) +#define HFS_INT_TO_ITYPE(X) ((X) << 30) + +/* generic ITYPEs */ +#define HFS_ITYPE_0 0x00000000 +#define HFS_ITYPE_1 0x40000000 +#define HFS_ITYPE_2 0x80000000 +#define HFS_ITYPE_3 0xC0000000 +#define HFS_ITYPE_NORM HFS_ITYPE_0 /* "normal" directory or file */ + +/* ITYPEs for CAP */ +#define HFS_CAP_NORM HFS_ITYPE_0 /* data fork or normal directory */ +#define HFS_CAP_DATA HFS_ITYPE_0 /* data fork of file */ +#define HFS_CAP_NDIR HFS_ITYPE_0 /* normal directory */ +#define HFS_CAP_FNDR HFS_ITYPE_1 /* finder info for file or dir */ +#define HFS_CAP_RSRC HFS_ITYPE_2 /* resource fork of file */ +#define HFS_CAP_RDIR HFS_ITYPE_2 /* .resource directory */ +#define HFS_CAP_FDIR HFS_ITYPE_3 /* .finderinfo directory */ + +/* ITYPEs for Apple Double */ +#define HFS_DBL_NORM HFS_ITYPE_0 /* data fork or directory */ +#define HFS_DBL_DATA HFS_ITYPE_0 /* data fork of file */ +#define HFS_DBL_DIR HFS_ITYPE_0 /* directory */ +#define HFS_DBL_HDR HFS_ITYPE_1 /* AD header of file or dir */ + +/* ITYPEs for netatalk */ +#define HFS_NAT_NORM HFS_ITYPE_0 /* data fork or directory */ +#define HFS_NAT_DATA HFS_ITYPE_0 /* data fork of file */ +#define HFS_NAT_NDIR HFS_ITYPE_0 /* normal directory */ +#define HFS_NAT_HDR HFS_ITYPE_1 /* AD header of file or dir */ +#define HFS_NAT_HDIR HFS_ITYPE_2 /* directory holding AD headers */ + +/* ITYPEs for Apple Single */ +#define HFS_SGL_NORM HFS_ITYPE_0 /* AppleSingle file or directory */ +#define HFS_SGL_SNGL HFS_ITYPE_0 /* AppleSingle file */ +#define HFS_SGL_DIR HFS_ITYPE_0 /* directory */ +#define HFS_SGL_DINF HFS_ITYPE_1 /* %DirInfo for directory */ + +/* IDs for elements of an AppleDouble or AppleSingle header */ +#define HFS_HDR_DATA 1 +#define HFS_HDR_RSRC 2 +#define HFS_HDR_FNAME 3 +#define HFS_HDR_COMNT 4 +#define HFS_HDR_BWICN 5 +#define HFS_HDR_CICON 6 +#define HFS_HDR_OLDI 7 +#define HFS_HDR_DATES 8 +#define HFS_HDR_FINFO 9 +#define HFS_HDR_MACI 10 +#define HFS_HDR_MAX 10 + +/* + * There are three time systems. All three are based on seconds since + * a particular time/date. + * Unix: unsigned lil-endian since 00:00 GMT, Jan. 1, 1970 + * mac: unsigned big-endian since 00:00 GMT, Jan. 1, 1904 + * header: SIGNED big-endian since 00:00 GMT, Jan. 1, 2000 + * + */ +#define hfs_h_to_mtime(ARG) htonl((hfs_s32)ntohl(ARG)+3029529600U) +#define hfs_m_to_htime(ARG) ((hfs_s32)htonl(ntohl(ARG)-3029529600U)) +#define hfs_h_to_utime(ARG) ((hfs_s32)ntohl(ARG)+946684800U) +#define hfs_u_to_htime(ARG) ((hfs_s32)htonl((ARG)-946684800U)) +#define hfs_u_to_mtime(ARG) htonl((ARG)+2082844800U) +#define hfs_m_to_utime(ARG) (ntohl(ARG)-2082844800U) + +/*======== Data structures kept in memory ========*/ + +/* + * A descriptor for a single entry within the header of an + * AppleDouble or AppleSingle header file. + * An array of these make up a table of contents for the file. + */ +struct hfs_hdr_descr { + hfs_u32 id; /* The Apple assigned ID for the entry type */ + hfs_u32 offset; /* The offset to reach the entry */ + hfs_u32 length; /* The length of the entry */ +}; + +/* + * The info needed to reconstruct a given header layout + */ +struct hfs_hdr_layout { + hfs_u32 magic; /* AppleSingle or AppleDouble */ + hfs_u32 version; /* 0x00010000 or 0x00020000 */ + hfs_u16 entries; /* How many entries used */ + struct hfs_hdr_descr + descr[HFS_HDR_MAX]; /* Descriptors */ + struct hfs_hdr_descr + *order[HFS_HDR_MAX]; /* 'descr' ordered by offset */ +}; + +/* + * Default header layout for Netatalk + */ +struct hfs_nat_hdr { + hfs_lword_t magic; + hfs_lword_t version; + hfs_byte_t homefs[16]; + hfs_word_t entries; + hfs_byte_t descrs[60]; + hfs_byte_t real_name[255]; /* id=3 */ + hfs_byte_t comment[200]; /* id=4 XXX: not yet implemented */ + hfs_lword_t create_time; /* \ */ + hfs_lword_t modify_time; /* | */ + hfs_lword_t backup_time; /* | id=7 */ + hfs_word_t filler; /* | */ + hfs_word_t attr; /* / */ + hfs_byte_t finderinfo[32]; /* id=9 */ +}; + +/* + * Default header layout for AppleDouble + */ +struct hfs_dbl_hdr { + hfs_lword_t magic; + hfs_lword_t version; + hfs_byte_t filler[16]; + hfs_word_t entries; + hfs_byte_t descrs[12*HFS_HDR_MAX]; + hfs_u32 create_time; /* \ */ + hfs_u32 modify_time; /* | id=8 */ + hfs_u32 backup_time; /* | */ + hfs_u32 access_time; /* / */ + hfs_u8 finderinfo[32]; /* id=9 */ + hfs_u32 fileinfo; /* id=10 */ + hfs_u8 real_name[32]; /* id=3 */ + hfs_u8 comment[200]; /* id=4 XXX: not yet implemented */ +}; + +/* finder metadata for CAP */ +struct hfs_cap_info { + hfs_byte_t fi_fndr[32]; /* Finder's info */ + hfs_word_t fi_attr; /* AFP attributes */ +#define HFS_AFP_WRI 0x020 /* Write inhibit bit */ +#define HFS_AFP_RNI 0x080 /* Rename inhibit bit (AFP >= 2.0) */ +#define HFS_AFP_DEI 0x100 /* Delete inhibit bit (AFP >= 2.0) */ +#define HFS_AFP_RDONLY ( HFS_AFP_WRI|HFS_AFP_RNI|HFS_AFP_DEI) + hfs_byte_t fi_magic1; /* Magic number: */ +#define HFS_CAP_MAGIC1 0xFF + hfs_byte_t fi_version; /* Version of this structure: */ +#define HFS_CAP_VERSION 0x10 + hfs_byte_t fi_magic; /* Another magic number: */ +#define HFS_CAP_MAGIC 0xDA + hfs_byte_t fi_bitmap; /* Bitmap of which names are valid: */ +#define HFS_CAP_SHORTNAME 0x01 +#define HFS_CAP_LONGNAME 0x02 + hfs_byte_t fi_shortfilename[12+1]; /* "short name" (unused) */ + hfs_byte_t fi_macfilename[32+1]; /* Original (Macintosh) name */ + hfs_byte_t fi_comln; /* Length of comment (always 0) */ + hfs_byte_t fi_comnt[200]; /* Finder comment (unused) */ + /* optional: used by aufs only if compiled with USE_MAC_DATES */ + hfs_byte_t fi_datemagic; /* Magic number for dates extension: */ +#define HFS_CAP_DMAGIC 0xDA + hfs_byte_t fi_datevalid; /* Bitmap of which dates are valid: */ +#define HFS_CAP_MDATE 0x01 +#define HFS_CAP_CDATE 0x02 + hfs_lword_t fi_ctime; /* Creation date (in AFP format) */ + hfs_lword_t fi_mtime; /* Modify date (in AFP format) */ + hfs_lword_t fi_utime; /* Un*x time of last mtime change */ + hfs_byte_t pad; +}; + +#ifdef __KERNEL__ + +#if defined(CONFIG_HFS_FS) || defined(CONFIG_HFS_FS_MODULE) + +typedef ssize_t hfs_rwret_t; +typedef size_t hfs_rwarg_t; + +#include + +/* Some forward declarations */ +struct hfs_fork; +struct hfs_cat_key; +struct hfs_cat_entry; +extern struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *, + const struct hfs_cat_key *); +extern void hfs_tolower(unsigned char *, int); + +/* dir.c */ +extern hfs_rwret_t hfs_dir_read(struct file *, char *, hfs_rwarg_t, + loff_t *); +extern int hfs_create(struct inode *, struct dentry *, int); +extern int hfs_mkdir(struct inode *, struct dentry *, int); +extern int hfs_mknod(struct inode *, struct dentry *, int, int); +extern int hfs_unlink(struct inode *, struct dentry *); +extern int hfs_rmdir(struct inode *, struct dentry *); +extern int hfs_rename(struct inode *, struct dentry *, + struct inode *, struct dentry *); + +/* dir_cap.c */ +extern const struct hfs_name hfs_cap_reserved1[]; +extern const struct hfs_name hfs_cap_reserved2[]; +extern struct inode_operations hfs_cap_ndir_inode_operations; +extern struct inode_operations hfs_cap_fdir_inode_operations; +extern struct inode_operations hfs_cap_rdir_inode_operations; +extern void hfs_cap_drop_dentry(const ino_t, struct dentry *); + +/* dir_dbl.c */ +extern const struct hfs_name hfs_dbl_reserved1[]; +extern const struct hfs_name hfs_dbl_reserved2[]; +extern struct inode_operations hfs_dbl_dir_inode_operations; +extern void hfs_dbl_drop_dentry(const ino_t, struct dentry *); + +/* dir_nat.c */ +extern const struct hfs_name hfs_nat_reserved1[]; +extern const struct hfs_name hfs_nat_reserved2[]; +extern struct inode_operations hfs_nat_ndir_inode_operations; +extern struct inode_operations hfs_nat_hdir_inode_operations; +extern void hfs_nat_drop_dentry(const ino_t, struct dentry *); + +/* dir_sngl.c */ +extern const struct hfs_name hfs_sngl_reserved1[]; +extern const struct hfs_name hfs_sngl_reserved2[]; +extern struct inode_operations hfs_sngl_dir_inode_operations; + +/* file.c */ +extern hfs_s32 hfs_do_read(struct inode *, struct hfs_fork *, hfs_u32, + char *, hfs_u32, int); +extern hfs_s32 hfs_do_write(struct inode *, struct hfs_fork *, hfs_u32, + const char *, hfs_u32); +extern void hfs_file_fix_mode(struct hfs_cat_entry *entry); +extern struct inode_operations hfs_file_inode_operations; + +/* file_cap.c */ +extern struct inode_operations hfs_cap_info_inode_operations; + +/* file_hdr.c */ +extern struct inode_operations hfs_hdr_inode_operations; +extern const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout; +extern const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout; +extern const struct hfs_hdr_layout hfs_nat_hdr_layout; +extern const struct hfs_hdr_layout hfs_sngl_hdr_layout; + +/* inode.c */ +extern void hfs_put_inode(struct inode *); +extern int hfs_notify_change(struct inode *, struct iattr *); +extern struct inode *hfs_iget(struct hfs_cat_entry *, ino_t, struct dentry *); + +extern void hfs_cap_ifill(struct inode *, ino_t); +extern void hfs_dbl_ifill(struct inode *, ino_t); +extern void hfs_nat_ifill(struct inode *, ino_t); +extern void hfs_sngl_ifill(struct inode *, ino_t); + +/* super.c */ +extern struct super_block *hfs_read_super(struct super_block *,void *,int); +extern int init_hfs_fs(void); + +/* trans.c */ +extern void hfs_colon2mac(struct hfs_name *, const char *, int); +extern void hfs_prcnt2mac(struct hfs_name *, const char *, int); +extern void hfs_triv2mac(struct hfs_name *, const char *, int); +extern void hfs_latin2mac(struct hfs_name *, const char *, int); +extern int hfs_mac2cap(char *, const struct hfs_name *); +extern int hfs_mac2nat(char *, const struct hfs_name *); +extern int hfs_mac2latin(char *, const struct hfs_name *); +extern int hfs_mac2seven(char *, const struct hfs_name *); +extern int hfs_mac2eight(char *, const struct hfs_name *); +extern int hfs_mac2alpha(char *, const struct hfs_name *); +extern int hfs_mac2triv(char *, const struct hfs_name *); + +#define HFS_I(X) (&((X)->u.hfs_i)) +#define HFS_SB(X) (&((X)->u.hfs_sb)) + +extern __inline__ void hfs_nameout(struct inode *dir, struct hfs_name *out, + const char *in, int len) { + HFS_SB(dir->i_sb)->s_nameout(out, in, len); +} + +extern __inline__ int hfs_namein(struct inode *dir, char *out, + const struct hfs_name *in) { + int len = HFS_SB(dir->i_sb)->s_namein(out, in); + if (HFS_SB(dir->i_sb)->s_lowercase) { + hfs_tolower(out, len); + } + return len; +} + +static __inline__ struct dentry +*hfs_lookup_dentry(const char *name, const int len, + struct dentry *base) +{ + struct qstr this; + + this.name = name; + this.len = len; + this.hash = full_name_hash(name, len); + + return d_lookup(base, &this); +} + +/* drop a dentry for one of the special subdirectories */ +static __inline__ void hfs_drop_special(const struct hfs_name *name, + struct dentry *base, + struct dentry *dentry) +{ + struct dentry *dparent, *de; + + dparent = hfs_lookup_dentry(name->Name, name->Len, base); + if (dparent) { + de = hfs_lookup_dentry(dentry->d_name.name, dentry->d_name.len, + dparent); + dput(dparent); + + if (de) { + if (!de->d_inode) + d_drop(de); + dput(de); + } + } +} + +#endif +#endif /* __KERNEL__ */ + +#endif diff -u --recursive --new-file v2.1.77/linux/include/linux/hfs_fs_i.h linux/include/linux/hfs_fs_i.h --- v2.1.77/linux/include/linux/hfs_fs_i.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/hfs_fs_i.h Sun Jan 4 10:40:17 1998 @@ -0,0 +1,40 @@ +/* + * linux/include/linux/hfs_fs_i.h + * + * Copyright (C) 1995, 1996 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file defines the type (struct hfs_inode_info) and the two + * subordinate types hfs_extent and hfs_file. + */ + +#ifndef _LINUX_HFS_FS_I_H +#define _LINUX_HFS_FS_I_H + +/* + * struct hfs_inode_info + * + * The HFS-specific part of a Linux (struct inode) + */ +struct hfs_inode_info { + int magic; /* A magic number */ + + struct hfs_cat_entry *entry; + + /* For a regular or header file */ + struct hfs_fork *fork; + int convert; + + /* For a directory */ + ino_t file_type; + char dir_size; + + /* For header files */ + const struct hfs_hdr_layout *default_layout; + struct hfs_hdr_layout *layout; + + /* for dentry cleanup */ + void (*d_drop_op)(const ino_t, struct dentry *); +}; + +#endif diff -u --recursive --new-file v2.1.77/linux/include/linux/hfs_fs_sb.h linux/include/linux/hfs_fs_sb.h --- v2.1.77/linux/include/linux/hfs_fs_sb.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/hfs_fs_sb.h Sun Jan 4 10:40:17 1998 @@ -0,0 +1,52 @@ +/* + * linux/include/linux/hfs_fs_sb.h + * + * Copyright (C) 1995-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file defines the type (struct hfs_sb_info) which contains the + * HFS-specific information in the in-core superblock. + */ + +#ifndef _LINUX_HFS_FS_SB_H +#define _LINUX_HFS_FS_SB_H + +/* forward declaration: */ +struct hfs_name; + +typedef int (*hfs_namein_fn) (char *, const struct hfs_name *); +typedef void (*hfs_nameout_fn) (struct hfs_name *, const char *, int); +typedef void (*hfs_ifill_fn) (struct inode *, ino_t); + +/* + * struct hfs_sb_info + * + * The HFS-specific part of a Linux (struct super_block) + */ +struct hfs_sb_info { + int magic; /* A magic number */ + struct hfs_mdb *s_mdb; /* The HFS MDB */ + int s_quiet; /* Silent failure when + changing owner or mode? */ + int s_lowercase; /* Map names to lowercase? */ + int s_afpd; /* AFPD compatible mode? */ + hfs_namein_fn s_namein; /* The function used to + map Mac filenames to + Linux filenames */ + hfs_nameout_fn s_nameout; /* The function used to + map Linux filenames + to Mac filenames */ + hfs_ifill_fn s_ifill; /* The function used + to fill in inode fields */ + const struct hfs_name *s_reserved1; /* Reserved names */ + const struct hfs_name *s_reserved2; /* Reserved names */ + __u32 s_type; /* Type for new files */ + __u32 s_creator; /* Creator for new files */ + umode_t s_umask; /* The umask applied to the + permissions on all files */ + uid_t s_uid; /* The uid of all files */ + gid_t s_gid; /* The gid of all files */ + char s_conv; /* Type of text conversion */ +}; + +#endif diff -u --recursive --new-file v2.1.77/linux/include/linux/hfs_sysdep.h linux/include/linux/hfs_sysdep.h --- v2.1.77/linux/include/linux/hfs_sysdep.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/hfs_sysdep.h Mon Jan 5 01:46:16 1998 @@ -0,0 +1,224 @@ +/* + * linux/include/linux/hfs_sysdep.h + * + * Copyright (C) 1996-1997 Paul H. Hargrove + * This file may be distributed under the terms of the GNU Public License. + * + * This file contains constants, types and inline + * functions for various system dependent things. + * + * "XXX" in a comment is a note to myself to consider changing something. + * + * In function preconditions the term "valid" applied to a pointer to + * a structure means that the pointer is non-NULL and the structure it + * points to has all fields initialized to consistent values. + */ + +#ifndef _HFS_SYSDEP_H +#define _HFS_SYSDEP_H + +#include +#include +#include +#include + +#include +#include + + +#undef offsetof +#define offsetof(TYPE, MEMB) ((size_t) &((TYPE *)0)->MEMB) + +/* Typedefs for integer types by size and signedness */ +typedef __u8 hfs_u8; +typedef __u16 hfs_u16; +typedef __u32 hfs_u32; +typedef __s8 hfs_s8; +typedef __s16 hfs_s16; +typedef __s32 hfs_s32; + +/* Typedefs for unaligned integer types */ +typedef unsigned char hfs_byte_t; +typedef unsigned char hfs_word_t[2]; +typedef unsigned char hfs_lword_t[4]; + +/* these funny looking things are GCC variable argument macros */ +#define hfs_warn(format, args...) printk(KERN_WARNING format , ## args) +#define hfs_error(format, args...) printk(KERN_ERR format , ## args) + + +#if defined(DEBUG_ALL) || defined(DEBUG_MEM) +extern long int hfs_alloc; +#endif + +extern inline void *hfs_malloc(unsigned int size) { +#if defined(DEBUG_ALL) || defined(DEBUG_MEM) + hfs_warn("%ld bytes allocation at %s:%u\n", + (hfs_alloc += size), __FILE__, __LINE__); +#endif + return kmalloc(size, GFP_KERNEL); +} + +extern inline void hfs_free(void *ptr, unsigned int size) { + kfree_s(ptr, size); +#if defined(DEBUG_ALL) || defined(DEBUG_MEM) + hfs_warn("%ld bytes allocation at %s:%u\n", + (hfs_alloc -= ptr ? size : 0), __FILE__, __LINE__); +#endif +} + + +extern inline hfs_u32 hfs_time(void) { + return htonl(CURRENT_TIME+2082844800U); +} + + +/* + * hfs_wait_queue + */ +typedef struct wait_queue *hfs_wait_queue; + +extern inline void hfs_sleep_on(hfs_wait_queue *queue) { + sleep_on(queue); +} + +extern inline void hfs_wake_up(hfs_wait_queue *queue) { + wake_up(queue); +} + +extern inline void hfs_relinquish(void) { + schedule(); +} + + +/* + * hfs_sysmdb + */ +typedef struct super_block *hfs_sysmdb; + +extern inline void hfs_mdb_dirty(hfs_sysmdb sys_mdb) { + sys_mdb->s_dirt = 1; +} + +extern inline char *hfs_mdb_name(hfs_sysmdb sys_mdb) { + return kdevname(sys_mdb->s_dev); +} + + +/* + * hfs_sysentry + */ +typedef struct dentry *hfs_sysentry[4]; + +/* + * hfs_buffer + */ +typedef struct buffer_head *hfs_buffer; + +#define HFS_BAD_BUFFER NULL + +/* In sysdep.c, since it needs HFS_SECTOR_SIZE */ +extern hfs_buffer hfs_buffer_get(hfs_sysmdb, int, int); + +extern inline int hfs_buffer_ok(hfs_buffer buffer) { + return (buffer != NULL); +} + +extern inline void hfs_buffer_put(hfs_buffer buffer) { + brelse(buffer); +} + +extern inline void hfs_buffer_dirty(hfs_buffer buffer) { + mark_buffer_dirty(buffer, 1); +} + +extern inline void hfs_buffer_sync(hfs_buffer buffer) { + while (buffer_locked(buffer)) { + wait_on_buffer(buffer); + } + if (buffer_dirty(buffer)) { + ll_rw_block(WRITE, 1, &buffer); + wait_on_buffer(buffer); + } +} + +extern inline void *hfs_buffer_data(const hfs_buffer buffer) { + return buffer->b_data; +} + + +/* + * bit operations + */ + +#undef BITNR +#if defined(__BIG_ENDIAN) +# define BITNR(X) ((X)^31) +# if !defined(__constant_htonl) +# define __constant_htonl(x) (x) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) (x) +# endif +#elif defined(__LITTLE_ENDIAN) +# define BITNR(X) ((X)^7) +# if !defined(__constant_htonl) +# define __constant_htonl(x) \ + ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) \ + ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) +# endif +#else +# error "Don't know if bytes are big- or little-endian!" +#endif + +extern inline int hfs_clear_bit(int bitnr, hfs_u32 *lword) { + return test_and_clear_bit(BITNR(bitnr), lword); +} + +extern inline int hfs_set_bit(int bitnr, hfs_u32 *lword) { + return test_and_set_bit(BITNR(bitnr), lword); +} + +extern inline int hfs_test_bit(int bitnr, const hfs_u32 *lword) { + /* the kernel should declare the second arg of test_bit as const */ + return test_bit(BITNR(bitnr), (void *)lword); +} + +#undef BITNR + +/* + * HFS structures have fields aligned to 16-bit boundaries. + * So, 16-bit get/put are easy while 32-bit get/put need + * some care on architectures like the DEC Alpha. + * + * In what follows: + * ns = 16-bit integer in network byte-order w/ 16-bit alignment + * hs = 16-bit integer in host byte-order w/ 16-bit alignment + * nl = 32-bit integer in network byte-order w/ unknown alignment + * hl = 32-bit integer in host byte-order w/ unknown alignment + * anl = 32-bit integer in network byte-order w/ 32-bit alignment + * ahl = 32-bit integer in host byte-order w/ 32-bit alignment + * Example: hfs_get_hl() gets an unaligned 32-bit integer converting + * it to host byte-order. + */ +#define hfs_get_hs(addr) ntohs(*((hfs_u16 *)(addr))) +#define hfs_get_ns(addr) (*((hfs_u16 *)(addr))) +#define hfs_get_hl(addr) ntohl(get_unaligned((hfs_u32 *)(addr))) +#define hfs_get_nl(addr) get_unaligned((hfs_u32 *)(addr)) +#define hfs_get_ahl(addr) ntohl(*((hfs_u32 *)(addr))) +#define hfs_get_anl(addr) (*((hfs_u32 *)(addr))) +#define hfs_put_hs(val, addr) ((void)(*((hfs_u16 *)(addr)) = ntohs(val))) +#define hfs_put_ns(val, addr) ((void)(*((hfs_u16 *)(addr)) = (val))) +#define hfs_put_hl(val, addr) put_unaligned(htonl(val), (hfs_u32 *)(addr)) +#define hfs_put_nl(val, addr) put_unaligned((val), (hfs_u32 *)(addr)) +#define hfs_put_ahl(val, addr) ((void)(*((hfs_u32 *)(addr)) = ntohl(val))) +#define hfs_put_anl(val, addr) ((void)(*((hfs_u32 *)(addr)) = (val))) + +#endif diff -u --recursive --new-file v2.1.77/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h --- v2.1.77/linux/include/linux/msdos_fs.h Sat Oct 25 02:44:18 1997 +++ linux/include/linux/msdos_fs.h Mon Jan 5 01:46:15 1998 @@ -225,7 +225,7 @@ /* inode.c */ extern int fat_bmap(struct inode *inode,int block); -extern int fat_notify_change(struct inode *,struct iattr *); +extern int fat_notify_change(struct dentry *, struct iattr *); extern void fat_put_inode(struct inode *inode); extern void fat_delete_inode(struct inode *inode); extern void fat_put_super(struct super_block *sb); diff -u --recursive --new-file v2.1.77/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- v2.1.77/linux/include/linux/nfs_fs.h Sun Dec 21 22:36:17 1997 +++ linux/include/linux/nfs_fs.h Mon Jan 5 01:43:43 1998 @@ -11,9 +11,10 @@ #include #include -#include #include + #include +#include #include /* @@ -53,11 +54,12 @@ */ #define NFS_SUPER_MAGIC 0x6969 +#define NFS_FH(dentry) ((struct nfs_fh *) ((dentry)->d_fsdata)) +#define NFS_DSERVER(dentry) (&(dentry)->d_sb->u.nfs_sb.s_server) #define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server) #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) #define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode))) #define NFS_CONGESTED(inode) (RPC_CONGESTED(NFS_CLIENT(inode))) -#define NFS_FH(inode) (&(inode)->u.nfs_i.fhandle) #define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies) #define NFS_OLDMTIME(inode) ((inode)->u.nfs_i.read_cache_mtime) @@ -138,8 +140,8 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *); extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); -extern int nfs_revalidate(struct inode *); -extern int _nfs_revalidate_inode(struct nfs_server *, struct inode *); +extern int nfs_revalidate(struct dentry *); +extern int _nfs_revalidate_inode(struct nfs_server *, struct dentry *); /* * linux/fs/nfs/file.c @@ -150,6 +152,7 @@ * linux/fs/nfs/dir.c */ extern struct inode_operations nfs_dir_inode_operations; +extern struct dentry_operations nfs_dentry_operations; extern void nfs_free_dircache(void); extern void nfs_invalidate_dircache(struct inode *); extern void nfs_invalidate_dircache_sb(struct super_block *); @@ -162,25 +165,24 @@ /* * linux/fs/nfs/locks.c */ -extern int nfs_lock(struct file *file, int cmd, struct file_lock *fl); +extern int nfs_lock(struct file *, int, struct file_lock *); /* * linux/fs/nfs/write.c */ -extern int nfs_writepage(struct inode *, struct page *); +extern int nfs_writepage(struct dentry *, struct page *); extern int nfs_check_failed_request(struct inode *); extern int nfs_check_error(struct inode *); extern int nfs_flush_dirty_pages(struct inode *, pid_t, off_t, off_t); extern int nfs_truncate_dirty_pages(struct inode *, unsigned long); extern void nfs_invalidate_pages(struct inode *); -extern int nfs_updatepage(struct inode *, struct page *, const char *, +extern int nfs_updatepage(struct dentry *, struct page *, const char *, unsigned long, unsigned int, int); /* * linux/fs/nfs/read.c */ -extern int nfs_readpage(struct inode *, struct page *); -extern int nfs_readpage_sync(struct inode *, struct page *); +extern int nfs_readpage(struct dentry *, struct page *); /* * linux/fs/mount_clnt.c @@ -192,11 +194,12 @@ * inline functions */ static inline int -nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) +nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry) { + struct inode *inode = dentry->d_inode; if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode)) return 0; - return _nfs_revalidate_inode(server, inode); + return _nfs_revalidate_inode(server, dentry); } extern struct nfs_wreq * nfs_failed_requests; diff -u --recursive --new-file v2.1.77/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h --- v2.1.77/linux/include/linux/nfs_fs_i.h Wed Sep 3 20:52:44 1997 +++ linux/include/linux/nfs_fs_i.h Sun Jan 4 00:53:40 1998 @@ -16,11 +16,6 @@ struct pipe_inode_info pipeinfo; /* - * The file handle - */ - struct nfs_fh fhandle; - - /* * Various flags */ unsigned short flags; diff -u --recursive --new-file v2.1.77/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h --- v2.1.77/linux/include/linux/smb_fs.h Fri Dec 19 15:53:05 1997 +++ linux/include/linux/smb_fs.h Mon Jan 5 01:46:16 1998 @@ -94,9 +94,9 @@ struct super_block *smb_read_super(struct super_block *, void *, int); void smb_get_inode_attr(struct inode *, struct smb_fattr *); void smb_invalidate_inodes(struct smb_sb_info *); -int smb_revalidate_inode(struct inode *); +int smb_revalidate_inode(struct dentry *); int smb_refresh_inode(struct inode *); -int smb_notify_change(struct inode *, struct iattr *); +int smb_notify_change(struct dentry *, struct iattr *); unsigned long smb_invent_inos(unsigned long); struct inode *smb_iget(struct super_block *, struct smb_fattr *); diff -u --recursive --new-file v2.1.77/linux/include/linux/uts.h linux/include/linux/uts.h --- v2.1.77/linux/include/linux/uts.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/uts.h Mon Jan 5 01:41:01 1998 @@ -0,0 +1,23 @@ +#ifndef _LINUX_UTS_H +#define _LINUX_UTS_H + +/* + * Defines for what uname() should return + */ +#ifndef UTS_SYSNAME +#define UTS_SYSNAME "Linux" +#endif + +#ifndef UTS_MACHINE +#define UTS_MACHINE "unknown" +#endif + +#ifndef UTS_NODENAME +#define UTS_NODENAME "(none)" /* set by sethostname() */ +#endif + +#ifndef UTS_DOMAINNAME +#define UTS_DOMAINNAME "(none)" /* set by setdomainname() */ +#endif + +#endif diff -u --recursive --new-file v2.1.77/linux/init/main.c linux/init/main.c --- v2.1.77/linux/init/main.c Fri Jan 2 14:37:03 1998 +++ linux/init/main.c Sun Jan 4 10:40:17 1998 @@ -105,7 +105,10 @@ #ifdef CONFIG_DECNET extern void decnet_setup(char *str, int *ints); #endif +#ifdef CONFIG_BLK_DEV_XD extern void xd_setup(char *str, int *ints); +extern void xd_manual_geo_init(char *str, int *ints); +#endif #ifdef CONFIG_BLK_DEV_IDE extern void ide_setup(char *); #endif @@ -583,6 +586,7 @@ #endif #ifdef CONFIG_BLK_DEV_XD { "xd=", xd_setup }, + { "xd_geo=", xd_manual_geo_init }, #endif #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) { "floppy=", floppy_setup }, diff -u --recursive --new-file v2.1.77/linux/init/version.c linux/init/version.c --- v2.1.77/linux/init/version.c Sun Nov 19 07:45:02 1995 +++ linux/init/version.c Mon Jan 5 01:41:01 1998 @@ -6,14 +6,10 @@ * May be freely distributed as part of Linux. */ -#include +#include #include #include #include - -/* make the "checkconfig" script happy: we really need to include config.h */ -#ifdef CONFIG_BOGUS -#endif #define version(a) Version_ ## a #define version_string(a) version(a) diff -u --recursive --new-file v2.1.77/linux/kernel/Makefile linux/kernel/Makefile --- v2.1.77/linux/kernel/Makefile Mon Dec 1 12:04:15 1997 +++ linux/kernel/Makefile Mon Jan 5 01:41:01 1998 @@ -21,7 +21,6 @@ OX_OBJS += ksyms.o endif -include $(TOPDIR)/Rules.make +CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer -sched.o: sched.c - $(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $< +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.77/linux/kernel/module.c linux/kernel/module.c --- v2.1.77/linux/kernel/module.c Tue Dec 2 09:49:40 1997 +++ linux/kernel/module.c Sun Jan 4 10:40:17 1998 @@ -772,8 +772,10 @@ /* Let the module clean up. */ mod->flags |= MOD_DELETED; - if (mod->flags & MOD_RUNNING) { - mod->cleanup(); + if (mod->flags & MOD_RUNNING) + { + if(mod->cleanup) + mod->cleanup(); mod->flags &= ~MOD_RUNNING; } diff -u --recursive --new-file v2.1.77/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.77/linux/mm/filemap.c Tue Dec 23 16:31:00 1997 +++ linux/mm/filemap.c Sun Jan 4 00:53:41 1998 @@ -260,8 +260,10 @@ * that we could use for the cache (if it is 0 we can try to create one, * this is all overlapped with the IO on the previous page finishing anyway) */ -static unsigned long try_to_read_ahead(struct inode * inode, unsigned long offset, unsigned long page_cache) +static unsigned long try_to_read_ahead(struct dentry * dentry, + unsigned long offset, unsigned long page_cache) { + struct inode *inode = dentry->d_inode; struct page * page; struct page ** hash; @@ -282,7 +284,7 @@ */ page = mem_map + MAP_NR(page_cache); add_to_page_cache(page, inode, offset, hash); - inode->i_op->readpage(inode, page); + inode->i_op->readpage(dentry, page); page_cache = 0; } release_page(page); @@ -445,9 +447,9 @@ return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)]; } -static inline unsigned long generic_file_readahead(int reada_ok, struct file * filp, struct inode * inode, - unsigned long ppos, struct page * page, - unsigned long page_cache) +static inline unsigned long generic_file_readahead(int reada_ok, + struct file * filp, struct inode * inode, + unsigned long ppos, struct page * page, unsigned long page_cache) { unsigned long max_ahead, ahead; unsigned long raend; @@ -511,7 +513,8 @@ ahead = 0; while (ahead < max_ahead) { ahead += PAGE_SIZE; - page_cache = try_to_read_ahead(inode, raend + ahead, page_cache); + page_cache = try_to_read_ahead(filp->f_dentry, raend + ahead, + page_cache); } /* * If we tried to read ahead some pages, @@ -559,7 +562,8 @@ ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; ssize_t error, read; size_t pos, pgpos, page_cache; int reada_ok; @@ -716,7 +720,7 @@ if (reada_ok && filp->f_ramax > MIN_READAHEAD) filp->f_ramax = MIN_READAHEAD; - error = inode->i_op->readpage(inode, page); + error = inode->i_op->readpage(dentry, page); if (!error) goto found_page; release_page(page); @@ -728,7 +732,7 @@ * Try to re-read it _once_. We do this synchronously, * because this happens only if there were errors. */ - error = inode->i_op->readpage(inode, page); + error = inode->i_op->readpage(dentry, page); if (!error) { wait_on_page(page); if (PageUptodate(page) && !PageError(page)) @@ -763,9 +767,10 @@ */ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long address, int no_share) { + struct dentry * dentry = area->vm_dentry; + struct inode * inode = dentry->d_inode; unsigned long offset; struct page * page, **hash; - struct inode * inode = area->vm_dentry->d_inode; unsigned long old_page, new_page; new_page = 0; @@ -846,14 +851,14 @@ new_page = 0; add_to_page_cache(page, inode, offset, hash); - if (inode->i_op->readpage(inode, page) != 0) + if (inode->i_op->readpage(dentry, page) != 0) goto failure; /* * Do a very limited read-ahead if appropriate */ if (PageLocked(page)) - new_page = try_to_read_ahead(inode, offset + PAGE_SIZE, 0); + new_page = try_to_read_ahead(dentry, offset + PAGE_SIZE, 0); goto found_page; page_locked_wait: @@ -868,7 +873,7 @@ * because there really aren't any performance issues here * and we need to check for errors. */ - if (inode->i_op->readpage(inode, page) != 0) + if (inode->i_op->readpage(dentry, page) != 0) goto failure; wait_on_page(page); if (PageError(page)) @@ -1305,7 +1310,8 @@ generic_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; struct page *page, **hash; unsigned long page_cache = 0; unsigned long pgpos, offset; @@ -1367,10 +1373,10 @@ */ if (!PageUptodate(page)) { if (bytes < PAGE_SIZE && pgpos < inode->i_size) { + status = -EIO; /* two tries ... error out */ if (didread < 2) - status = inode->i_op->readpage(inode, page); - else - status = -EIO; /* two tries ... error out */ + status = inode->i_op->readpage(dentry, + page); if (status < 0) goto done_with_page; didread++; @@ -1380,7 +1386,7 @@ } /* Alright, the page is there. Now update it. */ - status = inode->i_op->updatepage(inode, page, buf, + status = inode->i_op->updatepage(dentry, page, buf, offset, bytes, sync); done_with_page: __free_page(page); diff -u --recursive --new-file v2.1.77/linux/net/core/filter.c linux/net/core/filter.c --- v2.1.77/linux/net/core/filter.c Fri Jan 2 14:37:03 1998 +++ linux/net/core/filter.c Sun Jan 4 10:40:17 1998 @@ -322,7 +322,7 @@ * end they _will_ hit this. */ - return (BPF_CLASS(filter[flen - 1].code) == BPF_RET); + return (BPF_CLASS(filter[flen - 1].code) == BPF_RET)?0:-EINVAL; } /* @@ -340,7 +340,7 @@ if(fprog->filter == NULL || fprog->len == 0 || fsize > BPF_MAXINSNS) return (-EINVAL); - if((err = sk_chk_filter(fprog->filter, fprog->len))) + if((err = sk_chk_filter(fprog->filter, fprog->len))==0) { /* If existing filter, remove it first */ if(sk->filter) diff -u --recursive --new-file v2.1.77/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.77/linux/net/ipv4/af_inet.c Mon Dec 1 12:04:16 1997 +++ linux/net/ipv4/af_inet.c Sun Jan 4 10:40:17 1998 @@ -326,7 +326,15 @@ if (sock->type == SOCK_PACKET) { static int warned; if (net_families[AF_PACKET]==NULL) + { +#if defined(CONFIG_KERNELD) && defined(CONFIG_PACKET_MODULE) + char module_name[30]; + sprintf(module_name,"net-pf-%d", AF_PACKET); + request_module(module_name); + if (net_families[AF_PACKET] == NULL) +#endif return -ESOCKTNOSUPPORT; + } if (!warned++) printk(KERN_INFO "%s uses obsolete (AF_INET,SOCK_PACKET)\n", current->comm); return net_families[AF_PACKET]->create(sock, protocol); diff -u --recursive --new-file v2.1.77/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.77/linux/net/netsyms.c Sun Dec 21 22:36:18 1997 +++ linux/net/netsyms.c Sun Jan 4 10:40:17 1998 @@ -191,6 +191,9 @@ EXPORT_SYMBOL(in_ntoa); EXPORT_SYMBOL(net_ratelimit); +/* needed for ip_gre -cw */ +EXPORT_SYMBOL(ip_statistics); + #ifdef CONFIG_IPV6_MODULE /* inet functions common to v4 and v6 */ EXPORT_SYMBOL(inet_stream_ops); diff -u --recursive --new-file v2.1.77/linux/scripts/Makefile linux/scripts/Makefile --- v2.1.77/linux/scripts/Makefile Tue Dec 23 16:31:00 1997 +++ linux/scripts/Makefile Mon Jan 5 01:41:01 1998 @@ -25,15 +25,15 @@ ${HOSTCC} -o tkparse tkparse.o tkcond.o tkgen.o tkparse.o: tkparse.c tkparse.h - $(HOSTCC) $(HOSTCFLAGS) -c -o tkparse.o tkparse.c tkcond.o: tkcond.c tkparse.h - $(HOSTCC) $(HOSTCFLAGS) -c -o tkcond.o tkcond.c tkgen.o: tkgen.c tkparse.h - $(HOSTCC) $(HOSTCFLAGS) -c -o tkgen.o tkgen.c + +tkparse.o tkcond.o tkgen.o: + $(HOSTCC) $(HOSTCFLAGS) -c -o $@ $(@:.o=.c) clean: - rm -f *~ kconfig.tk *.o tkparse + rm -f *~ kconfig.tk *.o tkparse mkdep split-include include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.77/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v2.1.77/linux/scripts/Menuconfig Fri Jan 2 14:37:03 1998 +++ linux/scripts/Menuconfig Mon Jan 5 01:41:01 1998 @@ -31,6 +31,11 @@ # 081297 Pavel Machek (pavel@atrey.karlin.mff.cuni.cz) - better error # handling # +# 131197 Michael Chastain (mec@shout.net) - output all lines for a +# choice list, not just the selected one. This makes the output +# the same as Configure output, which is important for smart config +# dependencies. +# # 101297 Michael Chastain (mec@shout.net) - remove sound driver cruft. # # 221297 Michael Chastain (mec@shout.net) - make define_bool actually @@ -1051,11 +1056,19 @@ : ${current:=$default} # - # Then extract the actual option from the list of choices. + # Output all choices (to be compatible with other configs). # - current=${choices#*$current} ; set $current - - define_bool "$1" "y" + set -- $choices + while [ -n "$2" ] + do + if eval [ "$1" = "$current" ] + then + define_bool "$2" "y" + else + define_bool "$2" "n" + fi + shift ; shift + done } function mainmenu_name () { diff -u --recursive --new-file v2.1.77/linux/scripts/checkconfig.pl linux/scripts/checkconfig.pl --- v2.1.77/linux/scripts/checkconfig.pl Wed Dec 31 16:00:00 1969 +++ linux/scripts/checkconfig.pl Mon Jan 5 01:41:01 1998 @@ -0,0 +1,50 @@ +#! /usr/bin/perl +# +# checkconfig: find uses of CONFIG_* names without matching definitions. + +use integer; + +foreach $file (@ARGV) +{ + # Open this file. + open(FILE, $file) || die "Can't open $file: $!\n"; + + # Initialize variables. + my $fInComment = 0; + my $fUseConfig = 0; + my $iLinuxConfig = 0; + my %configList = (); + + LINE: while ( ) + { + # Strip comments. + $fInComment && (s+^.*?\*/+ +o ? ($fInComment = 0) : next); + m+/\*+o && (s+/\*.*?\*/+ +go, (s+/\*.*$+ +o && ($fInComment = 1))); + + # Pick up definitions. + if ( m/^#/o ) + { + $iLinuxConfig = $. if m/^#\s*include\s+/o; + $configList{uc $1} = 1 if m/^#\s*include\s+/o; + $configList{$1} = 1 if m/^#\s*define\s+CONFIG_(\w*)/o; + $configList{$1} = 1 if m/^#\s*undef\s+CONFIG_(\w*)/o; + } + + # Look for usages. + next unless m/CONFIG_/o; + WORD: while ( m/\bCONFIG_(\w*)/og ) + { + $fUseConfig = 1; + last LINE if $iLinuxConfig; + next WORD if exists $configList{$1}; + print "$file: $.: need CONFIG_$1.\n"; + $configList{$1} = 0; + } + } + + # Report superfluous includes. + if ( $iLinuxConfig && ! $fUseConfig ) + { print "$file: $iLinuxConfig: not needed.\n"; } + + close(FILE); +} diff -u --recursive --new-file v2.1.77/linux/scripts/depend.awk linux/scripts/depend.awk --- v2.1.77/linux/scripts/depend.awk Sun May 19 22:37:40 1996 +++ linux/scripts/depend.awk Mon Jan 5 01:41:01 1998 @@ -1,154 +0,0 @@ -# This is an awk script which does dependencies. We do NOT want it to -# recursively follow #include directives. -# -# The HPATH environment variable should be set to indicate where to look -# for include files. The -I in front of the path is optional. - -# -# Surely there is a more elegant way to see if a file exists. Anyone know -# what it is? -# -function fileExists(f, TMP, dummy, result) { - if(result=FILEHASH[f]) { - if(result=="Yes") { - return "Yes" - } else {return ""} - } - ERRNO = getline dummy < f - if(ERRNO >= 0) { - close(f) - return FILEHASH[f]="Yes" - } else { - FILEHASH[f]="No" - return "" - } -} - -function endfile(f) { - if (hasconfig && !needsconfig) { - printf "%s doesn't need config\n",f > "/dev/stderr" - } - if (hasdep) { - print cmd - } -} - -BEGIN{ - hasdep=0 - hasconfig=0 - needsconfig=0 - incomment=0 - if(!(TOPDIR=ENVIRON["TOPDIR"])) { - print "Environment variable TOPDIR is not set" - exit 1 - } - split(ENVIRON["HPATH"],parray," ") - for(path in parray) { - sub("^-I","",parray[path]) - sub("[/ ]*$","",parray[path]) - } -} - -# eliminate comments -{ - # remove all comments fully contained on a single line - gsub("\\/\\*.*\\*\\/", "") - if (incomment) { - if ($0 ~ /\*\//) { - incomment = 0; - gsub(".*\\*\\/", "") - } else { - next - } - } else { - # start of multi-line comment - if ($0 ~ /\/\*/) - { - incomment = 1; - sub("\\/\\*.*", "") - } else if ($0 ~ /\*\//) { - incomment = 0; - sub(".*\\*\\/", "") - } - } -} - -/^[ ]*#[ ]*if.*[^A-Za-z_]CONFIG_/ { - needsconfig=1 - if (!hasconfig) { - printf "%s needs config but has not included config file\n",FILENAME > "/dev/stderr" - # only say it once per file.. - hasconfig = 1 - } -} - -/^[ ]*#[ ]*include[ ]*[<"][^ ]*[>"]/{ - found=0 - if(LASTFILE!=FILENAME) { - endfile(LASTFILE) - hasdep=0 - hasconfig=0 - needsconfig=0 - incomment=0 - cmd="" - LASTFILE=FILENAME - depname=FILENAME - relpath=FILENAME - sub("\\.c$",".o: ",depname) - sub("\\.S$",".o: ",depname) - if (depname==FILENAME) { - cmd="\n\t@touch "depname - } - sub("\\.h$",".h: ",depname) - if(relpath ~ "^\\." ) { - sub("[^/]*$","", relpath) - relpath=relpath"/" - sub("//","/", relpath) - } else { - relpath="" - } - } - fname=$0 - sub("^#[ ]*include[ ]*[<\"]","",fname) - sub("[>\"].*","",fname) - if (fname=="linux/config.h") { - hasconfig=1 - } - rfname=relpath""fname - if(fileExists(rfname)) { - found=1 - if (!hasdep) { - printf "%s", depname - } - hasdep=1 - printf " \\\n %s", rfname - if(fname ~ "^\\." ) { - fnd=0; - for(i in ARGV) { - if(ARGV[i]==rfname) { - fnd=1 - } - } - if(fnd==0) { - ARGV[ARGC]=rfname - ++ARGC - } - } - } else { - for(path in parray) { - if(fileExists(parray[path]"/"fname)) { - shortp=parray[path] - found=1 - if (!hasdep) { - printf "%s", depname - } - hasdep=1 - printf " \\\n %s", parray[path]"/"fname - } - } - } -} - -END{ - endfile(FILENAME) -} diff -u --recursive --new-file v2.1.77/linux/scripts/header.tk linux/scripts/header.tk --- v2.1.77/linux/scripts/header.tk Tue Dec 23 16:31:00 1997 +++ linux/scripts/header.tk Mon Jan 5 01:41:01 1998 @@ -228,10 +228,10 @@ proc write_tristate { file1 file2 varname variable dep } { if { $variable == 0 } \ then { puts $file1 "# $varname is not set"; \ - puts $file2 "#undef $varname"} \ + puts $file2 "#undef $varname"} \ elseif { $variable == 2 || ($dep == 2 && $variable == 1) } \ then { puts $file1 "$varname=m"; \ - puts $file2 "#undef $varname"; \ + puts $file2 "#undef $varname"; \ puts $file2 "#define ${varname}_MODULE 1" } \ elseif { $variable == 1 && $dep != 2 } \ then { puts $file1 "$varname=y"; \ @@ -244,7 +244,7 @@ proc write_int { file1 file2 varname variable dep } { if { $dep == 0 } \ then { puts $file1 "# $varname is not set"; \ - puts $file2 "#undef $varname"} \ + puts $file2 "#undef $varname"} \ else { puts $file1 "$varname=$variable"; \ puts $file2 "#define $varname $variable"; \ @@ -254,7 +254,7 @@ proc write_hex { file1 file2 varname variable dep } { if { $dep == 0 } \ then { puts $file1 "# $varname is not set"; \ - puts $file2 "#undef $varname"} \ + puts $file2 "#undef $varname"} \ else { puts $file1 "$varname=$variable"; \ puts $file2 "#define $varname 0x$variable"; \ @@ -264,7 +264,7 @@ proc write_string { file1 file2 varname variable dep } { if { $dep == 0 } \ then { puts $file1 "# $varname is not set"; \ - puts $file2 "#undef $varname"} \ + puts $file2 "#undef $varname"} \ else { puts $file1 "$varname=\"$variable\""; \ puts $file2 "#define $varname \"$variable\""; \ diff -u --recursive --new-file v2.1.77/linux/scripts/hfiles.sh linux/scripts/hfiles.sh --- v2.1.77/linux/scripts/hfiles.sh Tue Aug 15 05:07:03 1995 +++ linux/scripts/hfiles.sh Mon Jan 5 01:41:01 1998 @@ -1,11 +0,0 @@ -#!/bin/sh -# -# This script looks to see if a directory contains .h files -# -for dir in $@; do - for hfile in $dir/*.h; do - if [ -f $hfile ]; then echo $dir; fi - break - done -done -exit 0 diff -u --recursive --new-file v2.1.77/linux/scripts/mkdep.c linux/scripts/mkdep.c --- v2.1.77/linux/scripts/mkdep.c Mon Jun 16 16:36:02 1997 +++ linux/scripts/mkdep.c Mon Jan 5 01:41:01 1998 @@ -1,18 +1,31 @@ +/* + * Originally by Linus Torvalds. + * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain. + * + * Usage: mkdep file ... + * + * Read source files and output makefile dependency lines for them. + * I make simple dependency lines for #include <*.h> and #include "*.h". + * I also find instances of CONFIG_FOO and generate dependencies + * like include/config/foo.h. + */ + +#include #include #include - -#include #include -#include -#include #include + #include #include +#include +#include -char *filename, *command, __depname[256] = "\n\t@touch "; -int needsconfig, hasconfig, hasmodules, hasdep; + +char __depname[512] = "\n\t@touch "; #define depname (__depname+9) +int hasdep; struct path_struct { int len; @@ -22,22 +35,113 @@ { 0, "" } }; -static void handle_include(int type, char *name, int len) + + +/* + * This records all the configuration options seen. + * In perl this would be a hash, but here it's a long string + * of values separated by newlines. This is simple and + * extremely fast. + */ +char * str_config = NULL; +int size_config = 0; +int len_config = 0; + + + +/* + * Grow the configuration string to a desired length. + * Usually the first growth is plenty. + */ +void grow_config(int len) +{ + if (str_config == NULL) { + len_config = 0; + size_config = 4096; + str_config = malloc(4096); + if (str_config == NULL) + { perror("malloc"); exit(1); } + } + + while (len_config + len > size_config) { + str_config = realloc(str_config, size_config *= 2); + if (str_config == NULL) + { perror("malloc"); exit(1); } + } +} + + + +/* + * Lookup a value in the configuration string. + */ +int is_defined_config(const char * name, int len) +{ + const char * pconfig; + const char * plast = str_config + len_config - len; + for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) { + if (pconfig[ -1] == '\n' + && pconfig[len] == '\n' + && !memcmp(pconfig, name, len)) + return 1; + } + return 0; +} + + + +/* + * Add a new value to the configuration string. + */ +void define_config(int convert, const char * name, int len) +{ + grow_config(len + 1); + + memcpy(str_config+len_config, name, len); + + if (convert) { + int i; + for (i = 0; i < len; i++) { + char c = str_config[len_config+i]; + if (isupper(c)) c = tolower(c); + if (c == '_') c = '/'; + str_config[len_config+i] = c; + } + } + + len_config += len; + str_config[len_config++] = '\n'; +} + + + +/* + * Clear the set of configuration strings. + */ +void clear_config( ) +{ + len_config = 0; + define_config(0, "", 0); +} + + + +/* + * Handle an #include line. + */ +void handle_include(int type, const char * name, int len) { - int plen; struct path_struct *path = path_array+type; - if (len == 14) - if (!memcmp(name, "linux/config.h", len)) - hasconfig = 1; - else if (!memcmp(name, "linux/module.h", len)) - hasmodules = 1; - - plen = path->len; - memcpy(path->buffer+plen, name, len); - len += plen; - path->buffer[len] = '\0'; - if (access(path->buffer, F_OK)) + if (len == 14 && !memcmp(name, "linux/config.h", len)) + return; + + if (len >= 7 && !memcmp(name, "config/", 7)) + define_config(0, name+7, len-7-2); + + memcpy(path->buffer+path->len, name, len); + path->buffer[path->len+len] = '\0'; + if (access(path->buffer, F_OK) != 0) return; if (!hasdep) { @@ -47,15 +151,48 @@ printf(" \\\n %s", path->buffer); } -static void handle_config(void) + + +/* + * Record the use of a CONFIG_* word. + */ +void use_config(const char * name, int len) { - needsconfig = 1; - if (!hasconfig) - fprintf(stderr, - "%s needs config but has not included config file\n", - filename); + char *pc; + int i; + + pc = path_array[0].buffer + path_array[0].len; + memcpy(pc, "config/", 7); + pc += 7; + + for (i = 0; i < len; i++) { + char c = name[i]; + if (isupper(c)) c = tolower(c); + if (c == '_') c = '/'; + pc[i] = c; + } + pc[len] = '\0'; + + if (is_defined_config(pc, len)) + return; + + define_config(0, pc, len); + + if (!hasdep) { + hasdep = 1; + printf("%s: ", depname); + } + printf(" \\\n $(wildcard %s.h)", path_array[0].buffer); } + + +/* + * Macros for stunningly fast map-based character access. + * __buf is a register which holds the current word of the input. + * Thus, there is one memory access per sizeof(unsigned long) characters. + */ + #if defined(__alpha__) || defined(__i386__) #define LE_MACHINE #endif @@ -69,243 +206,283 @@ #endif #define GETNEXT { \ -next_byte(__buf); \ -if (!__nrbuf) { \ - __buf = *(unsigned long *) next; \ - __nrbuf = sizeof(unsigned long); \ - if (!__buf) \ - break; \ -} next++; __nrbuf--; } + next_byte(__buf); \ + if ((unsigned long) next % sizeof(unsigned long) == 0) { \ + __buf = * (unsigned long *) next; \ + if (!__buf) \ + break; \ + } \ + next++; \ +} + +/* + * State machine macros. + */ #define CASE(c,label) if (current == c) goto label #define NOTCASE(c,label) if (current != c) goto label -static void state_machine(register char *next) -{ - for(;;) { - register unsigned long __buf = 0; - register unsigned long __nrbuf = 0; - -normal: - GETNEXT -__normal: - CASE('/',slash); - CASE('"',string); - CASE('\'',char_const); - CASE('#',preproc); - goto normal; - -slash: - GETNEXT - CASE('*',comment); - goto __normal; +/* + * Yet another state machine speedup. + */ +#define MAX2(a,b) ((a)>(b)?(a):(b)) +#define MIN2(a,b) ((a)<(b)?(a):(b)) +#define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e))))) +#define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e))))) -string: - GETNEXT - CASE('"',normal); - NOTCASE('\\',string); - GETNEXT - goto string; -char_const: - GETNEXT - CASE('\'',normal); - NOTCASE('\\',char_const); - GETNEXT - goto char_const; -comment: - GETNEXT -__comment: - NOTCASE('*',comment); - GETNEXT - CASE('/',normal); - goto __comment; - -preproc: - GETNEXT - CASE('\n',normal); - CASE(' ',preproc); - CASE('\t',preproc); - CASE('i',i_preproc); - CASE('e',e_preproc); - GETNEXT - -skippreproc: - CASE('\n',normal); - CASE('\\',skippreprocslash); - GETNEXT - goto skippreproc; - -skippreprocslash: - GETNEXT; - GETNEXT; - goto skippreproc; - -e_preproc: - GETNEXT - NOTCASE('l',skippreproc); - GETNEXT - NOTCASE('i',skippreproc); - GETNEXT - CASE('f',if_line); - goto skippreproc; +/* + * The state machine looks for (approximately) these Perl regular expressions: + * + * m|\/\*.*?\*\/| + * m|'.*?'| + * m|".*?"| + * m|#\s*include\s*"(.*?)"| + * m|#\s*include\s*<(.*?>"| + * m|#\s*(?define|undef)\s*CONFIG_(\w*)| + * m|(?!\w)CONFIG_| + * + * About 98% of the CPU time is spent here, and most of that is in + * the 'start' paragraph. Because the current characters are + * in a register, the start loop usually eats 4 or 8 characters + * per memory read. The MAX5 and MIN5 tests dispose of most + * input characters with 1 or 2 comparisons. + */ +void state_machine(const char * map) +{ + const char * next = map; + const char * map_dot; + unsigned long __buf = 0; + + for (;;) { +start: + GETNEXT +__start: + if (current > MAX5('/','\'','"','#','C')) goto start; + if (current < MIN5('/','\'','"','#','C')) goto start; + CASE('/', slash); + CASE('\'', squote); + CASE('"', dquote); + CASE('#', pound); + CASE('C', cee); + goto start; -i_preproc: - GETNEXT - CASE('f',if_line); - NOTCASE('n',skippreproc); - GETNEXT - NOTCASE('c',skippreproc); - GETNEXT - NOTCASE('l',skippreproc); - GETNEXT - NOTCASE('u',skippreproc); +/* / */ +slash: GETNEXT - NOTCASE('d',skippreproc); + NOTCASE('*', __start); +slash_star_dot_star: GETNEXT - NOTCASE('e',skippreproc); - -/* "# include" found */ -include_line: +__slash_star_dot_star: + NOTCASE('*', slash_star_dot_star); GETNEXT - CASE('\n',normal); - CASE('<', std_include_file); - NOTCASE('"', include_line); + NOTCASE('/', __slash_star_dot_star); + goto start; -/* "local" include file */ -{ - char *incname = next; -local_include_name: - GETNEXT - CASE('\n',normal); - NOTCASE('"', local_include_name); - handle_include(1, incname, next-incname-1); - goto skippreproc; +/* '.*?' */ +squote: + GETNEXT + CASE('\'', start); + NOTCASE('\\', squote); + GETNEXT + goto squote; + +/* ".*?" */ +dquote: + GETNEXT + CASE('"', start); + NOTCASE('\\', dquote); + GETNEXT + goto dquote; + +/* #\s* */ +pound: + GETNEXT + CASE(' ', pound); + CASE('\t', pound); + CASE('i', pound_i); + CASE('d', pound_d); + CASE('u', pound_u); + goto __start; + +/* #\s*i */ +pound_i: + GETNEXT NOTCASE('n', __start); + GETNEXT NOTCASE('c', __start); + GETNEXT NOTCASE('l', __start); + GETNEXT NOTCASE('u', __start); + GETNEXT NOTCASE('d', __start); + GETNEXT NOTCASE('e', __start); + goto pound_include; + +/* #\s*include\s* */ +pound_include: + GETNEXT + CASE(' ', pound_include); + CASE('\t', pound_include); + map_dot = next; + CASE('"', pound_include_dquote); + CASE('<', pound_include_langle); + goto __start; + +/* #\s*include\s*"(.*)" */ +pound_include_dquote: + GETNEXT + CASE('\n', start); + NOTCASE('"', pound_include_dquote); + handle_include(1, map_dot, next - map_dot - 1); + goto start; + +/* #\s*include\s*<(.*)> */ +pound_include_langle: + GETNEXT + CASE('\n', start); + NOTCASE('>', pound_include_langle); + handle_include(0, map_dot, next - map_dot - 1); + goto start; + +/* #\s*d */ +pound_d: + GETNEXT NOTCASE('e', __start); + GETNEXT NOTCASE('f', __start); + GETNEXT NOTCASE('i', __start); + GETNEXT NOTCASE('n', __start); + GETNEXT NOTCASE('e', __start); + goto pound_define_undef; + +/* #\s*u */ +pound_u: + GETNEXT NOTCASE('n', __start); + GETNEXT NOTCASE('d', __start); + GETNEXT NOTCASE('e', __start); + GETNEXT NOTCASE('f', __start); + goto pound_define_undef; + +/* #\s*(define|undef)\s*CONFIG_(\w*) */ +pound_define_undef: + GETNEXT + CASE(' ', pound_define_undef); + CASE('\t', pound_define_undef); + + NOTCASE('C', __start); + GETNEXT NOTCASE('O', __start); + GETNEXT NOTCASE('N', __start); + GETNEXT NOTCASE('F', __start); + GETNEXT NOTCASE('I', __start); + GETNEXT NOTCASE('G', __start); + GETNEXT NOTCASE('_', __start); + + map_dot = next; +pound_define_undef_CONFIG_word: + GETNEXT + if (isalnum(current) || current == '_') + goto pound_define_undef_CONFIG_word; + define_config(1, map_dot, next - map_dot - 1); + goto __start; + +/* \= map+2 && (isalnum(next[-2]) || next[-2] == '_')) + goto start; + GETNEXT NOTCASE('O', __start); + GETNEXT NOTCASE('N', __start); + GETNEXT NOTCASE('F', __start); + GETNEXT NOTCASE('I', __start); + GETNEXT NOTCASE('G', __start); + GETNEXT NOTCASE('_', __start); + + map_dot = next; +cee_CONFIG_word: + GETNEXT + if (isalnum(current) || current == '_') + goto cee_CONFIG_word; + use_config(map_dot, next - map_dot - 1); + goto __start; + } } -/* include file */ -std_include_file: -{ - char *incname = next; -std_include_name: - GETNEXT - CASE('\n',normal); - NOTCASE('>', std_include_name); - handle_include(0, incname, next-incname-1); - goto skippreproc; -} -if_line: - if (needsconfig) - goto skippreproc; -if_start: - GETNEXT - CASE('C', config); - CASE('\n', normal); - CASE('_', if_middle); - if (current >= 'a' && current <= 'z') - goto if_middle; - if (current < 'A' || current > 'Z') - goto if_start; -config: - GETNEXT - NOTCASE('O', __if_middle); - GETNEXT - NOTCASE('N', __if_middle); - GETNEXT - NOTCASE('F', __if_middle); - GETNEXT - NOTCASE('I', __if_middle); - GETNEXT - NOTCASE('G', __if_middle); - GETNEXT - NOTCASE('_', __if_middle); - handle_config(); - goto skippreproc; - -if_middle: - GETNEXT -__if_middle: - CASE('\n', normal); - CASE('_', if_middle); - if (current >= 'a' && current <= 'z') - goto if_middle; - if (current < 'A' || current > 'Z') - goto if_start; - goto if_middle; - } -} -static void do_depend(void) +/* + * Generate dependencies for one file. + */ +void do_depend(const char * filename, const char * command) { - char *map; int mapsize; int pagesizem1 = getpagesize()-1; - int fd = open(filename, O_RDONLY); + int fd; struct stat st; + char * map; + fd = open(filename, O_RDONLY); if (fd < 0) { - if (errno != ENOENT) - perror(filename); + perror(filename); return; } + fstat(fd, &st); if (st.st_size == 0) { fprintf(stderr,"%s is empty\n",filename); + close(fd); return; } + mapsize = st.st_size + 2*sizeof(unsigned long); mapsize = (mapsize+pagesizem1) & ~pagesizem1; map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0); - if (-1 == (long)map) { + if ((long) map == -1) { perror("mkdep: mmap"); close(fd); return; } - close(fd); + if ((unsigned long) map % sizeof(unsigned long) != 0) + { + fprintf(stderr, "do_depend: map not aligned\n"); + exit(1); + } + + hasdep = 0; + clear_config(); state_machine(map); - munmap(map, mapsize); if (hasdep) puts(command); + + munmap(map, mapsize); + close(fd); } + + +/* + * Generate dependencies for all files. + */ int main(int argc, char **argv) { int len; - char * hpath; + char *hpath; hpath = getenv("HPATH"); if (!hpath) hpath = "/usr/src/linux/include"; len = strlen(hpath); memcpy(path_array[0].buffer, hpath, len); - if (len && hpath[len-1] != '/') { - path_array[0].buffer[len] = '/'; - len++; - } + if (len && hpath[len-1] != '/') + path_array[0].buffer[len++] = '/'; path_array[0].buffer[len] = '\0'; path_array[0].len = len; while (--argc > 0) { - int len; - char *name = *++argv; - - filename = name; - len = strlen(name); - memcpy(depname, name, len+1); - command = __depname; - if (len > 2 && name[len-2] == '.') { - switch (name[len-1]) { - case 'c': - case 'S': - depname[len-1] = 'o'; - command = ""; + const char * filename = *++argv; + const char * command = __depname; + len = strlen(filename); + memcpy(depname, filename, len+1); + if (len > 2 && filename[len-2] == '.') { + if (filename[len-1] == 'c' || filename[len-1] == 'S') { + depname[len-1] = 'o'; + command = ""; } } - needsconfig = hasconfig = hasmodules = hasdep = 0; - do_depend(); - if (hasconfig && !hasmodules && !needsconfig) - fprintf(stderr, "%s doesn't need config\n", filename); + do_depend(filename, command); } return 0; } diff -u --recursive --new-file v2.1.77/linux/scripts/split-include.c linux/scripts/split-include.c --- v2.1.77/linux/scripts/split-include.c Wed Dec 31 16:00:00 1969 +++ linux/scripts/split-include.c Mon Jan 5 01:41:01 1998 @@ -0,0 +1,226 @@ +/* + * split-include.c + * + * Copyright abandoned, Michael Chastain, . + * This is a C version of syncdep.pl by Werner Almesberger. + * + * This program takes autoconf.h as input and outputs a directory full + * of one-line include files, merging onto the old values. + * + * Think of the configuration options as key-value pairs. Then there + * are five cases: + * + * key old value new value action + * + * KEY-1 VALUE-1 VALUE-1 leave file alone + * KEY-2 VALUE-2A VALUE-2B write VALUE-2B into file + * KEY-3 - VALUE-3 write VALUE-3 into file + * KEY-4 VALUE-4 - write an empty file + * KEY-5 (empty) - leave old empty file alone + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ERROR_EXIT(strExit) \ + { \ + const int errnoSave = errno; \ + fprintf(stderr, "%s: ", str_my_name); \ + errno = errnoSave; \ + perror((strExit)); \ + exit(1); \ + } + + + +int main(int argc, const char * argv []) +{ + const char * str_my_name; + const char * str_file_autoconf; + const char * str_dir_config; + + FILE * fp_config; + FILE * fp_target; + FILE * fp_find; + + int buffer_size; + + char * line; + char * old_line; + char * list_target; + char * ptarget; + + struct stat stat_buf; + + /* Check arg count. */ + if (argc != 3) + { + fprintf(stderr, "%s: wrong number of arguments.\n", argv[0]); + exit(1); + } + + str_my_name = argv[0]; + str_file_autoconf = argv[1]; + str_dir_config = argv[2]; + + /* Find a buffer size. */ + if (stat(str_file_autoconf, &stat_buf) != 0) + ERROR_EXIT(str_file_autoconf); + buffer_size = 2 * stat_buf.st_size + 4096; + + /* Allocate buffers. */ + if ( (line = malloc(buffer_size)) == NULL + || (old_line = malloc(buffer_size)) == NULL + || (list_target = malloc(buffer_size)) == NULL ) + ERROR_EXIT(str_file_autoconf); + + /* Open autoconfig file. */ + if ((fp_config = fopen(str_file_autoconf, "r")) == NULL) + ERROR_EXIT(str_file_autoconf); + + /* Make output directory if needed. */ + if (stat(str_dir_config, &stat_buf) != 0) + { + if (mkdir(str_dir_config, 0755) != 0) + ERROR_EXIT(str_dir_config); + } + + /* Change to output directory. */ + if (chdir(str_dir_config) != 0) + ERROR_EXIT(str_dir_config); + + /* Put initial separator into target list. */ + ptarget = list_target; + *ptarget++ = '\n'; + + /* Read config lines. */ + while (fgets(line, buffer_size, fp_config)) + { + const char * str_config; + int is_same; + int itarget; + + if (line[0] != '#') + continue; + if ((str_config = strstr(line, "CONFIG_")) == NULL) + continue; + + /* Make the output file name. */ + str_config += sizeof("CONFIG_") - 1; + for (itarget = 0; !isspace(str_config[itarget]); itarget++) + { + char c = str_config[itarget]; + if (isupper(c)) c = tolower(c); + if (c == '_') c = '/'; + ptarget[itarget] = c; + } + ptarget[itarget++] = '.'; + ptarget[itarget++] = 'h'; + ptarget[itarget++] = '\0'; + + /* Check for existing file. */ + is_same = 0; + if ((fp_target = fopen(ptarget, "r")) != NULL) + { + fgets(old_line, buffer_size, fp_target); + if (fclose(fp_target) != 0) + ERROR_EXIT(ptarget); + if (!strcmp(line, old_line)) + is_same = 1; + } + + if (!is_same) + { + /* Auto-create directories. */ + int islash; + for (islash = 0; islash < itarget; islash++) + { + if (ptarget[islash] == '/') + { + ptarget[islash] = '\0'; + if (stat(ptarget, &stat_buf) != 0 + && mkdir(ptarget, 0755) != 0) + ERROR_EXIT( ptarget ); + ptarget[islash] = '/'; + } + } + + /* Write the file. */ + if ((fp_target = fopen(ptarget, "w" )) == NULL) + ERROR_EXIT(ptarget); + fputs(line, fp_target); + if (ferror(fp_target) || fclose(fp_target) != 0) + ERROR_EXIT(ptarget); + } + + /* Update target list */ + ptarget += itarget; + *(ptarget-1) = '\n'; + } + + /* + * Close autoconfig file. + * Terminate the target list. + */ + if (fclose(fp_config) != 0) + ERROR_EXIT(str_file_autoconf); + *ptarget = '\0'; + + /* + * Fix up existing files which have no new value. + * This is Case 4 and Case 5. + * + * I re-read the tree and filter it against list_target. + * This is crude. But it avoids data copies. Also, list_target + * is compact and contiguous, so it easily fits into cache. + * + * Notice that list_target contains strings separated by \n, + * with a \n before the first string and after the last. + * fgets gives the incoming names a terminating \n. + * So by having an initial \n, strstr will find exact matches. + */ + + fp_find = popen("find * -type f -print", "r"); + if (fp_find == 0) + ERROR_EXIT( "find" ); + + line[0] = '\n'; + while (fgets(line+1, buffer_size, fp_find)) + { + if (strstr(list_target, line) == NULL) + { + /* + * This is an old file with no CONFIG_* flag in autoconf.h. + */ + + /* First strip the \n. */ + line[strlen(line)-1] = '\0'; + + /* Grab size. */ + if (stat(line+1, &stat_buf) != 0) + ERROR_EXIT(line); + + /* If file is not empty, make it empty and give it a fresh date. */ + if (stat_buf.st_size != 0) + { + if ((fp_target = fopen(line+1, "w")) == NULL) + ERROR_EXIT(line); + if (fclose(fp_target) != 0) + ERROR_EXIT(line); + } + } + } + + if (pclose(fp_find) != 0) + ERROR_EXIT("find"); + + return 0; +} diff -u --recursive --new-file v2.1.77/linux/scripts/tkgen.c linux/scripts/tkgen.c --- v2.1.77/linux/scripts/tkgen.c Tue Dec 23 16:31:00 1997 +++ linux/scripts/tkgen.c Mon Jan 5 01:41:02 1998 @@ -53,6 +53,14 @@ * 1997 12 08 * Michael Chastain - Remove sound driver special cases. * + * 1997 11 15 + * Michael Chastain - For choice buttons, write values for all options, + * not just the single chosen one. This is compatible + * with 'make config' and 'make oldconfig', and is + * needed so smart-config dependencies work if the + * user switches from one configuration method to + * another. + * * TO DO: * - clean up - there are useless ifdef's everywhere. * - better comments throughout - C code generating tcl is really cryptic. @@ -1034,9 +1042,10 @@ cfg1 != NULL && cfg1->tok == tok_choice; cfg1 = cfg1->next) { - printf("\tif { $%s == \"%s\" } then { write_tristate $cfg $autocfg %s 1 $notmod }\n", + printf("\tif { $%s == \"%s\" } then { write_tristate $cfg $autocfg %s 1 $notmod } else { write_tristate $cfg $autocfg %s 0 $notmod }\n", cfg->optionname, cfg1->label, + cfg1->optionname, cfg1->optionname); } }