diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/Makefile linux-2.0.29/Makefile --- linux.vanilla/Makefile Sat Feb 8 18:54:36 1997 +++ linux-2.0.29/Makefile Tue Apr 15 19:15:50 1997 @@ -29,7 +29,7 @@ HOSTCC =gcc -I$(HPATH) HOSTCFLAGS =-O2 -fomit-frame-pointer -CROSS_COMPILE = +CROSS_COMPILE = m68k-linux- AS =$(CROSS_COMPILE)as LD =$(CROSS_COMPILE)ld @@ -140,6 +140,10 @@ ifdef CONFIG_PCI DRIVERS := $(DRIVERS) drivers/pci/pci.a +endif + +ifdef CONFIG_MAC +DRIVERS := $(DRIVERS) drivers/nubus/nubus.a endif ifdef CONFIG_SBUS diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/Makefile linux-2.0.29/arch/m68k/Makefile --- linux.vanilla/arch/m68k/Makefile Sat Oct 19 12:33:13 1996 +++ linux-2.0.29/arch/m68k/Makefile Fri Mar 21 12:12:58 1997 @@ -28,7 +28,7 @@ LD += -m m68klinux ifneq ($(COMPILE_ARCH),$(ARCH)) # prefix for cross-compiling binaries - CROSS_COMPILE = m68k-linuxaout- + CROSS_COMPILE = m68k-linux- endif endif @@ -45,7 +45,11 @@ ifdef CONFIG_KERNEL_ELF LINKFLAGS = -Ttext 0x1000 else +ifdef CONFIG_MAC +LINKFLAGS = -omagic -e __start +else LINKFLAGS = -qmagic -Ttext 0xFE0 +endif endif CFLAGS := $(CFLAGS) -pipe diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/config.in linux-2.0.29/arch/m68k/config.in --- linux.vanilla/arch/m68k/config.in Thu Feb 27 16:45:46 1997 +++ linux-2.0.29/arch/m68k/config.in Thu Apr 10 14:01:11 1997 @@ -144,6 +144,9 @@ dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI +fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI endmenu @@ -211,6 +214,9 @@ tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL bool 'GVP IO-Extender support' CONFIG_GVPIOEXT tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY +fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'MAC SCC serial support' CONFIG_MAC_SCC fi bool 'Support for user serial device modules' CONFIG_USERIAL bool 'Watchdog Timer Support' CONFIG_WATCHDOG diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/console/fbcon.c linux-2.0.29/arch/m68k/console/fbcon.c --- linux.vanilla/arch/m68k/console/fbcon.c Sat Oct 5 14:23:56 1996 +++ linux-2.0.29/arch/m68k/console/fbcon.c Mon Mar 24 14:29:50 1997 @@ -24,6 +24,7 @@ * with work by Guenther Kelleter * Martin Schaller * Andreas Schwab + * Alan Cox * * * This file is subject to the terms and conditions of the GNU General Public @@ -68,6 +69,8 @@ #include +#include /*AC DEBUG */ + #include "../../../drivers/char/vt_kern.h" /* vt_cons and vc_resize_con() */ @@ -89,6 +92,7 @@ #undef CONFIG_FBCON_2PLANE #undef CONFIG_FBCON_4PLANE #undef CONFIG_FBCON_8PLANE +#undef CONFIG_FBCON_4PACKED #undef CONFIG_FBCON_8PACKED #undef CONFIG_FBCON_16PACKED #undef CONFIG_FBCON_24PACKED @@ -100,6 +104,20 @@ #define CONFIG_FBCON_MONO +/* Mac support */ + +#ifdef CONFIG_MAC +#ifndef CONFIG_FBCON_4PACKED +#define CONFIG_FBCON_4PACKED +#endif +#ifndef CONFIG_FBCON_8PACKED +#define CONFIG_FBCON_8PACKED +#endif +#ifndef CONFIG_FBCON_16PACKED +#define CONFIG_FBCON_16PACKED +#endif +#endif + /* Amiga support */ #ifdef CONFIG_AMIGA @@ -159,8 +177,8 @@ #endif -struct fb_info *fb_info; -struct display *disp; +static struct fb_info *fb_info; +static struct display *disp; /* ++Geert: Sorry, no hardware cursor support at the moment; @@ -223,7 +241,7 @@ * Interface used by the world */ -static u_long fbcon_startup(u_long kmem_start, char **display_desc); +/*static */u_long fbcon_startup(u_long kmem_start, char **display_desc); static void fbcon_init(struct vc_data *conp); static int fbcon_deinit(struct vc_data *conp); static int fbcon_changevar(int con); @@ -378,6 +396,23 @@ /* + * 4bpp packed pixels (eg the MAC toby board) + */ + +#ifdef CONFIG_FBCON_4PACKED +static void bmove_4_packed(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_4_packed(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_4_packed(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_4_packed(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x); +static void rev_char_4_packed(struct display *p, int x, int y); +#endif /* CONFIG_FBCON_4PACKED */ + + + /* * 8 bpp Packed Pixels */ @@ -454,70 +489,76 @@ #ifdef CONFIG_FBCON_MONO -struct display_switch dispsw_mono = { +static struct display_switch dispsw_mono = { bmove_mono, clear_mono, putc_mono, putcs_mono, rev_char_mono }; #endif /* CONFIG_FBCON_MONO */ #ifdef CONFIG_FBCON_ILBM -struct display_switch dispsw_ilbm = { +static struct display_switch dispsw_ilbm = { bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm, rev_char_ilbm }; #endif /* CONFIG_FBCON_ILBM */ #ifdef CONFIG_FBCON_PLANES -struct display_switch dispsw_plan = { +static struct display_switch dispsw_plan = { bmove_plan, clear_plan, putc_plan, putcs_plan, rev_char_plan }; #endif /* CONFIG_FBCON_PLANES */ #ifdef CONFIG_FBCON_2PLANE -struct display_switch dispsw_2_plane = { +static struct display_switch dispsw_2_plane = { bmove_2_plane, clear_2_plane, putc_2_plane, putcs_2_plane, rev_char_2_plane }; #endif /* CONFIG_FBCON_2PLANE */ #ifdef CONFIG_FBCON_4PLANE -struct display_switch dispsw_4_plane = { +static struct display_switch dispsw_4_plane = { bmove_4_plane, clear_4_plane, putc_4_plane, putcs_4_plane, rev_char_4_plane }; #endif /* CONFIG_FBCON_4PLANE */ #ifdef CONFIG_FBCON_8PLANE -struct display_switch dispsw_8_plane = { +static struct display_switch dispsw_8_plane = { bmove_8_plane, clear_8_plane, putc_8_plane, putcs_8_plane, rev_char_8_plane }; #endif /* CONFIG_FBCON_8PLANE */ +#ifdef CONFIG_FBCON_4PACKED +static struct display_switch dispsw_4_packed = { + bmove_4_packed, clear_4_packed, putc_4_packed, putcs_4_packed, rev_char_4_packed +}; +#endif /* CONFIG_FBCON_4PACKED */ + #ifdef CONFIG_FBCON_8PACKED -struct display_switch dispsw_8_packed = { +static struct display_switch dispsw_8_packed = { bmove_8_packed, clear_8_packed, putc_8_packed, putcs_8_packed, rev_char_8_packed }; #endif /* CONFIG_FBCON_8PACKED */ #ifdef CONFIG_FBCON_16PACKED -struct display_switch dispsw_16_packed = { +static struct display_switch dispsw_16_packed = { bmove_16_packed, clear_16_packed, putc_16_packed, putcs_16_packed, rev_char_16_packed }; #endif /* CONFIG_FBCON_16PACKED */ #ifdef CONFIG_FBCON_CYBER -struct display_switch dispsw_cyber = { +static struct display_switch dispsw_cyber = { bmove_cyber, clear_cyber, putc_cyber, putcs_cyber, rev_char_cyber }; #endif /* CONFIG_FBCON_CYBER */ -static u_long fbcon_startup(u_long kmem_start, char **display_desc) +/* static */u_long fbcon_startup(u_long kmem_start, char **display_desc) { int irqres = 0; - + fb_info = mach_fb_init(&kmem_start); disp = fb_info->disp; *display_desc = fb_info->modename; fb_info->changevar = &fbcon_changevar; - + #ifdef CONFIG_AMIGA if (MACH_IS_AMIGA) { cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE; @@ -664,6 +705,11 @@ p->dispsw = &dispsw_cyber; else #endif /* CONFIG_FBCON_CYBER */ +#ifdef CONFIG_FBCON_4PACKED + if (p->var.bits_per_pixel == 4) + p->dispsw = &dispsw_4_packed; + else +#endif /* CONFIG_FBCON_8PACKED */ #ifdef CONFIG_FBCON_8PACKED if (p->var.bits_per_pixel == 8) p->dispsw = &dispsw_8_packed; @@ -1475,6 +1521,10 @@ int unit = conp->vc_num; struct display *p = &disp[unit]; + /* Avoid flickering if there's no real change. */ + if (p->cursor_x == conp->vc_x && p->cursor_y == conp->vc_y && + (mode == CM_ERASE) == !cursor_on) + return 0; if (CURSOR_UNDRAWN ()) p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y)); p->cursor_x = conp->vc_x; @@ -1861,7 +1911,7 @@ * - Color Interleaved Planes à la Amiga * - Color Normal Planes * - Color Interleaved Planes à la Atari (2, 4 and 8 planes) - * - Color Packed Pixels (8 and 16 bpp) + * - Color Packed Pixels (4, 8 and 16 bpp) * - Cybervision Color Packed Pixels (accelerated) */ @@ -3292,6 +3342,170 @@ /* ====================================================================== */ +#ifdef CONFIG_FBCON_4PACKED + + /* + * 4 bpp Packed Pixels: + * IFF the font is even pixel aligned (that is to say each + * character start is a byte start in the pixel pairs). That + * avoids us having to mask bytes and means we won't be here + * all week. On a MacII that matters _lots_ + */ + +static u_short nibbletab_4_packed[]={ +0x0000,0x000f,0x00f0,0x00ff, +0x0f00,0x0f0f,0x0ff0,0x0fff, +0xf000,0xf00f,0xf0f0,0xf0ff, +0xff00,0xff0f,0xfff0,0xffff}; + +static void bmove_4_packed(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + u_char *src,*dst; + + if (sx == 0 && dx == 0 && width * 4 == bytes) { + mymemmove(p->screen_base + dy * linesize, + p->screen_base + sy * linesize, + height * linesize); + } + else { + if (dy < sy || (dy == sy && dx < sx)) { + src = p->screen_base + sy * linesize + sx * 4; + dst = p->screen_base + dy * linesize + dx * 4; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 4); + src += bytes; + dst += bytes; + } + } + else { + src = p->screen_base + (sy+height) * linesize + sx * 4 + - bytes; + dst = p->screen_base + (dy+height) * linesize + dx * 4 + - bytes; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 4); + src -= bytes; + dst -= bytes; + } + } + } +} + + +static void clear_4_packed(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + u_char *dest0,*dest; + int bytes=p->next_line,lines=height * p->fontheight, rows, i; + u_long bgx; + + if(p->screen_base!=0xFDD00020) + mac_boom(1); + dest = p->screen_base + sy * p->fontheight * bytes + sx * 4; + + bgx=attr_bgcol_ec(p,conp); + bgx |= (bgx << 4); /* expand the colour to 32bits */ + bgx |= (bgx << 8); + bgx |= (bgx << 16); + + if (sx == 0 && width * 4 == bytes) { + for (i = 0 ; i < lines * width ; i++) { + ((u_long *)dest)[0]=bgx; + dest+=4; + } + } else { + dest0=dest; + for (rows = lines; rows-- ; dest0 += bytes) { + dest=dest0; + for (i = 0 ; i < width ; i++) { + /* memset ?? */ + ((u_long *)dest)[0]=bgx; + dest+=4; + } + } + } +} + + +static void putc_4_packed(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest,*cdat; + int bytes=p->next_line,rows; + ulong eorx,fgx,bgx; + + c &= 0xff; + + dest = p->screen_base + y * p->fontheight * bytes + x * 4; + cdat = p->fontdata + c * p->fontheight; + + fgx=15;/*attr_fgcol(p,conp)&0x0F;*/ + bgx=attr_bgcol(p,conp)&0x0F; + fgx |= (fgx << 4); + fgx |= (fgx << 8); + bgx |= (bgx << 4); + bgx |= (bgx << 8); + eorx = fgx ^ bgx; + + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_short *)dest)[0]= + (nibbletab_4_packed[*cdat >> 4] & eorx) ^ bgx; + ((u_short *)dest)[1]= + (nibbletab_4_packed[*cdat++ & 0xf] & eorx) ^ bgx; + } +} + + +static void putcs_4_packed(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x) +{ + u_char *cdat, c, *dest, *dest0; + int rows,bytes=p->next_line; + u_long eorx, fgx, bgx; + + dest0 = p->screen_base + y * p->fontheight * bytes + x * 4; + fgx=15/*attr_fgcol(p,conp)*/; + bgx=attr_bgcol(p,conp); + fgx |= (fgx << 4); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 4); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + while (count--) { + c = *s++; + cdat = p->fontdata + c * p->fontheight; + + for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + ((u_short *)dest)[0]= + (nibbletab_4_packed[*cdat >> 4] & eorx) ^ bgx; + ((u_short *)dest)[1]= + (nibbletab_4_packed[*cdat++ & 0xf] & eorx) ^ bgx; + } + dest0+=4; + } +} + + +static void rev_char_4_packed(struct display *p, int x, int y) +{ + u_char *dest; + int bytes=p->next_line, rows; + + dest = p->screen_base + y * p->fontheight * bytes + x * 4; + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0] ^= 0x0f0f0f0f; + } +} + +#endif /* CONFIG_FBCON_4PACKED */ + +/* ====================================================================== */ + + #ifdef CONFIG_FBCON_8PACKED /* @@ -3766,8 +3980,13 @@ * The console `switch' structure for the frame buffer based console */ +unsigned long precookie=0x0DEC0DED; + struct consw fb_con = { fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc, fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch, fbcon_blank, fbcon_get_font, fbcon_set_font }; + +unsigned long postcookie=0xC0DEBA5E; + diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/kernel/console.c linux-2.0.29/arch/m68k/kernel/console.c --- linux.vanilla/arch/m68k/kernel/console.c Sat Oct 5 14:24:06 1996 +++ linux-2.0.29/arch/m68k/kernel/console.c Mon Mar 24 11:16:58 1997 @@ -123,6 +123,8 @@ #include #include +#include + #include "../../../drivers/char/kbd_kern.h" #include "../../../drivers/char/vt_kern.h" #include "../../../drivers/char/consolemap.h" @@ -2215,11 +2217,12 @@ console_driver.throttle = con_throttle; console_driver.unthrottle = con_unthrottle; + if (tty_register_driver(&console_driver)) panic("Couldn't register console driver\n"); kmem_start = conswitchp->con_startup (kmem_start, &display_desc); - + timer_table[BLANK_TIMER].fn = blank_screen; timer_table[BLANK_TIMER].expires = 0; if (blankinterval) { @@ -2252,6 +2255,8 @@ gotoxy(currcons,0,0); csi_J(currcons, 0); + mac_debugging_penguin(3); + printable = 1; update_screen(fg_console); sw->con_cursor(vc_cons[currcons].d, CM_DRAW); diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/kernel/head.S linux-2.0.29/arch/m68k/kernel/head.S --- linux.vanilla/arch/m68k/kernel/head.S Sat Oct 5 14:24:07 1996 +++ linux-2.0.29/arch/m68k/kernel/head.S Tue Apr 15 16:21:56 1997 @@ -143,13 +143,20 @@ #define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab #define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab +#define is_not_mac(lab) moveq &MACH_MAC,%d7; cmpl %d4,%d7; jne lab #define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab #define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab #define is_060(lab) btst &D6B_060,%d6; jne lab #define is_not_060(lab) btst &D6B_060,%d6; jeq lab +#define CONFIG_MAC + .text +#ifdef CONFIG_MAC +ENTRY(_true_stext) +.equ .,SYMBOL_NAME(_true_stext)+PAGESIZE +#endif ENTRY(_stext) /* * Version numbers of the bootinfo interface @@ -172,6 +179,69 @@ ENTRY(_start) + +#ifdef CONFIG_MAC +# lea _fb_con,%a0 +# movel #_fbcon_startup,a0@ + + /* + * Yes this isnt the clean way to do it. I need to revise + * my 68k asm. + */ + movel %d5,%a0 + movel %a4, %d1 + andl #0xFFFF,%d1 /* rows */ +loopy: + movel %a3, %d0 +loopx: + moveb #0x55, %a0@+ + dbra %d0,loopx + dbra %d1,loopy + /* + * Check we have top of video right + */ + movel %a3,%d0 + movel %d5,%a0 + addl %d0,%d0 + addl %d0,%d0 + addl %d0,%d0 + addl %d0,%d0 +loopw: + moveb #00, %a0@+ + dbra %d0,loopw + + /* + * Save the boot info + */ + lea %pc@(SYMBOL_NAME(boot_info)),%a0 + movel #MACH_MAC,%a0@(BI_machtype) + movel %sp@-, %d0 + movel %d0, %a0@(BI_args) + movel %d4,%d0 + andl #3,%d0 + movel #33,%d0 /* 68020+FPU hardcode */ + movel %d0, %a0@(BI_cputype) + movel %a4, %a0@(BI_dimensions) + movel %d5, %a0@(BI_videoaddr) + movel %a3, %a0@(BI_videorow) + movel %a2, %a0@(BI_videodepth) + lea %pc@(SYMBOL_NAME(_stext):w),%sp + movel #0, %a0@(BI_memory+MI_addr) + movel #5242880, %a0@(BI_memory+MI_size) + jbsr Lserial_init + + + putr() + putc('L') + putc('i') + putc('n') + putc('u') + putc('x') + putc('.') + putr() + + +#else /* * Setup initial stack pointer */ @@ -187,6 +257,8 @@ 1: moveb %a0@+,%a1@+ dbra %d0,1b +#endif + /* * Record the CPU and machine type. */ @@ -206,6 +278,7 @@ jra 2f 1: /* '020 or '030: d6 := no CPU bit, cache mode unused */ moveq #0,%d6 + movel %d6, 0xFD008020 /* ac check */ 2: lea %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0 moveq #0,%d0 @@ -248,8 +321,7 @@ /* * Save physical start address of kernel */ - lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0 - movel %a0,%d5 + movel #0,%d5 #ifdef HACKER_KERNEL lea %pc@(Lkernel_start),%a0 movel %d5,%a0@ @@ -275,6 +347,7 @@ putc('C') + /* * Initialize the pointer tables referred to above. They either point * to page tables in the case of the 680[46]0 or contain early @@ -405,6 +478,7 @@ putc('I') moveq #_PAGE_NOCACHE030+_PAGE_PRESENT,%d0 + orl #0x80000000, %d0 movel %d0,%a5@(0x40<<2) jra Lmapphys @@ -474,6 +548,128 @@ Lnotami: #endif +#ifdef CONFIG_MAC + is_not_mac(Lnotmac) + +/* + * Setup a mapping of the 0xFC range for 32M of physical address space + * at virtual address 0xFC000000, using early termination page descriptors + * for the 68030, and proper page tables for the 680[46]0. Set this area + * as non-cacheable. (040/060 one still wrong XXX) + */ + + putc('H') + + is_040_or_060(Lspmac68040) + + /* + * for the 68030, just setup a translation to map in the + * 32M of physical address space at virtual address 0x80000000 + * using an early termination page descriptor. + */ + + putc('I') + + /* + * Nubus space + */ + + moveq #_PAGE_NOCACHE030+_PAGE_PRESENT,%d0 + orl #0xF8000000,%d0 + movel %d0,%a5@(0x7C<<2) + moveq #_PAGE_NOCACHE030+_PAGE_PRESENT,%d0 + orl #0xFA000000,%d0 + movel %d0,%a5@(0x7D<<2) + moveq #_PAGE_NOCACHE030+_PAGE_PRESENT,%d0 + orl #0xFC000000,%d0 + movel %d0,%a5@(0x7E<<2) + moveq #_PAGE_NOCACHE030+_PAGE_PRESENT,%d0 + orl #0xFE000000,%d0 + movel %d0,%a5@(0x7F<<2) + + /* + * IO space identity at 0x50-> for now + */ + + moveq #_PAGE_NOCACHE030+_PAGE_PRESENT,%d0 + orl #0x50000000,%d0 + movel %d0,%a5@(0x28<<2) + + /* + * MAC onboard video + */ + + moveq #_PAGE_NOCACHE030+_PAGE_PRESENT,%d0 + orl #0x60000000,%d0 + movel %d0,%a5@(0x30<<2) + + jra Lmapphys + +Lspmac68040: + + /* + * for the 680[46]0, use another pointer table, and allocate 4 more + * page tables. Initialize the pointer table to point to the + * page tables. Then initialize the page tables to point to + * the first 16M of memory, with no caching (noncachable/serialized). + */ + + /* clear the mac pointer table */ + lea %a4@(PTR_TABLE_SIZE<<2),%a4 + moveq #PTR_TABLE_SIZE-1,%d1 +1: clrl %a0@+ + dbra %d1,1b + + /* allocate 4 pages for 64 page tables */ + movel %a6,%a3 + addw #4*PAGESIZE,%a6 + + /* initialize the pointer table */ + movel %a4,%a0 + movel %a3,%a1 + addql #_PAGE_TABLE,%a1 /* base descriptor */ + movel #PAGE_TABLE_SIZE<<2,%d2 /* increment */ + moveq #TABLENR_16MB-1,%d1 + +1: movel %a1,%a0@+ + addl %d2,%a1 + dbra %d1,1b + + /* ensure that the root table points to the pointer table */ + movel %a4,%a0 + addql #_PAGE_TABLE,%a0 + movel %a0,%a5@(0x40<<2) + + /* + * initialize the page tables + * descriptor bits include noncachable/serialized and global bits. + */ + movel %a3,%a0 + movew #_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT,%a1 + movel #PAGESIZE,%d2 + movew #(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1 + +1: movel %a1,%a0@+ + addl %d2,%a1 + dbra %d1,1b + + /* + * Finally, since we just allocated 4 page tables, make sure that + * the virtual mapping of the 4 page tables indicates + * noncachable/serialized. + */ + moveq #3,%d0 +1: movel %a2@,%d1 /* a2 already points to root table offset */ + andw #_CACHEMASK040,%d1 + orw %d6,%d1 + movel %d1,%a2@+ + dbra %d0,1b + + jra Lmapphys + +Lnotmac: +#endif + #ifdef CONFIG_ATARI is_not_atari(Lnotatari) @@ -591,6 +787,7 @@ * an Amiga since the first 16M is already identity mapped on the Amiga. */ Lmapphys: + putc('J') #ifdef CONFIG_AMIGA @@ -680,6 +877,7 @@ Lmapphysnotamiga: #endif + #ifdef CONFIG_ATARI is_not_atari(Lmapphysnotatari) @@ -773,14 +971,64 @@ Lmapphysnotatari: #endif +#ifdef CONFIG_MAC + is_not_mac(Lmapphysnotmac) + + putc('L') + + is_040_or_060(Lmacmmu68040) + + lea %pc@(Lmmu),%a3 + movel %d5,%d0 + /* We always follow this path as the kernel is at 0x0000 after + the MacBoot has finished */ + lea LdoneMMUenable:w,%a0 + movel #0x80000002,%a3@ + movel %a5,%a3@(4) + .long 0xf0134800 /* pmove %a3@,%srp */ + .long 0xf0134c00 /* pmove %a3@,%crp */ + .long 0xf0002400 /* pflusha */ + /* + * enable,super root enable,4096 byte pages,7 bit root index, + * 7 bit pointer index, 6 bit page table index. + */ + movel #0x82c07760,%a3@ + .long 0xf0134000 /* pmove %a3@,%tc (enable the MMU) */ + jmp %a0@ + +Lmacmmu68040: + movel %d5,%d0 + lea LdoneMMUenable:w,%a0 + jra 2f +2: nop + .word 0xf518 /* pflusha */ + .long 0x4e7bd807 /* movec %a5,%srp */ + .long 0x4e7bd806 /* movec %a5,%urp */ + movel #TC_ENABLE+TC_PAGE4K,%d0 + /* + * this value is also ok for the 68060, we don`t use the cache + * mode/protection defaults + */ + .long 0x4e7b0003 /* movec %d0,%tc (enable the MMU) */ + jmp %a0@ +3: moveq #0,%d0 + .long 0x4e7b0004 /* movec %d0,%itt0 */ + tstl %a1 + jra LdoneMMUenable + +Lmapphysnotmac: +#endif + LdoneMMUenable: + /* * Fixup the addresses for the kernel pointer table and availmem. * Convert them from physical addresses to virtual addresses. */ - putc('M') + +/* putc('M')*/ /* * d5 contains physaddr of kernel start @@ -794,7 +1042,7 @@ subl %d5,%a6 movel %a6,SYMBOL_NAME(availmem) /* first available memory address */ - putc('N') +/* putc('N')*/ #if 0 putr() @@ -823,10 +1071,24 @@ /* * Enable caches */ + lea %pc@(SYMBOL_NAME(boot_info)),%a0 + movel %a0@(BI_videoaddr),%a0 + movel #2048,%d0 +1: + moveb #0x33,%a0@+ + dbra %d0,1b is_040_or_060(Lcache680460) movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0 movec %d0,%cacr + + lea %pc@(SYMBOL_NAME(boot_info)),%a0 + movel %a0@(BI_videoaddr),%a0 + movel #2048,%d0 +1: + moveb #0xFF,%a0@+ + dbra %d0,1b + jra 1f Lcache680460: @@ -854,7 +1116,7 @@ lea SYMBOL_NAME(init_user_stack)+PAGESIZE,%sp /* jump to the kernel start */ - putr() +/* putr()*/ jbsr SYMBOL_NAME(start_kernel) @@ -903,6 +1165,25 @@ * from the MFP or a serial port of the SCC */ +#ifdef CONFIG_MAC +#define USE_SCC + +scc_initable_mac: + .byte 9,12 /* Reset */ + .byte 4,0x44 /* x16, 1 stopbit, no parity */ + .byte 3,0xc0 /* receiver: 8 bpc */ + .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */ + .byte 9,0 /* no interrupts */ + .byte 10,0 /* NRZ */ + .byte 11,0x50 /* use baud rate generator */ + .byte 12,10,13,0 /* 9600 baud */ + .byte 14,2,14,3 /* use master clock for BRG, enable */ + .byte 3,0xc1 /* enable receiver */ + .byte 5,0xea /* enable transmitter */ + .byte -1 + .even +#endif + #ifdef CONFIG_ATARI /* #define USE_PRINTER */ /* #define USE_SCC */ @@ -1002,7 +1283,16 @@ orb #1,LMFP_TDCDR bset #1,LMFP_TSR #endif +#endif 4: +#ifdef defined(CONFIG_MAC) + lea #50F04000,%a0 + lea %pc@(scc_initable_mac:w),%a1 +2: moveb %a1@+,%d0 + jmi 3f + moveb %d0,%a0@ + moveb %a1@+,%a0@ + jra 2b #endif 9: rts @@ -1025,6 +1315,16 @@ jeq 1b jra 9f 2: +#endif +#ifdef CONFIG_MAC +#if 0 + /* should check if MAC .. - note this base is for a MacII and later ! */ + lea 0x50F04000,%a1 +3: btst #2,%a1@(0) + jeq 3b +#endif + moveb %d7,%a1@(4) + jra 9f #endif #ifdef CONFIG_ATARI cmpil #MACH_ATARI,%d4 diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/kernel/ints.c linux-2.0.29/arch/m68k/kernel/ints.c --- linux.vanilla/arch/m68k/kernel/ints.c Sat Oct 5 14:24:07 1996 +++ linux-2.0.29/arch/m68k/kernel/ints.c Tue Mar 25 14:45:51 1997 @@ -25,6 +25,7 @@ * which must be served /Roman Zippel */ +#include #include #include #include @@ -178,7 +179,7 @@ panic("Can't process interrupt vector %ld\n", vec); return; } - + vec -= VEC_SPUR; kstat.interrupts[vec]++; irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/kernel/setup.c linux-2.0.29/arch/m68k/kernel/setup.c --- linux.vanilla/arch/m68k/kernel/setup.c Sat Oct 5 14:24:07 1996 +++ linux-2.0.29/arch/m68k/kernel/setup.c Tue Mar 25 16:13:26 1997 @@ -127,6 +127,10 @@ memory_start = availmem; memory_end = 0; + + /* AC MAC HACK */ + if(boot_info.num_memory==0) + boot_info.num_memory=1; for (i = 0; i < boot_info.num_memory; i++) memory_end += boot_info.memory[i].size & MASK_256K; diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/kernel/traps.c linux-2.0.29/arch/m68k/kernel/traps.c --- linux.vanilla/arch/m68k/kernel/traps.c Sat Oct 5 14:24:07 1996 +++ linux-2.0.29/arch/m68k/kernel/traps.c Wed Apr 16 16:11:31 1997 @@ -770,6 +770,7 @@ for (i = 0; i < 10; i++) printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); printk ("\n"); + while(1); /* AC trap */ } void bad_super_trap (struct frame *fp) diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/Makefile linux-2.0.29/arch/m68k/mac/Makefile --- linux.vanilla/arch/m68k/mac/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/Makefile Mon Apr 14 15:23:44 1997 @@ -0,0 +1,15 @@ +# +# Makefile for Linux arch/m68k/atari source directory +# +# 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... + +EXTRA_CFLAGS := -Wa,-m68020 + +O_TARGET := mac.o +O_OBJS := config.o ksyms.o bootparse.o macfb.o macints.o via6522.o adb-bus.o + +include $(TOPDIR)/Rules.make diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/adb-bus.c linux-2.0.29/arch/m68k/mac/adb-bus.c --- linux.vanilla/arch/m68k/mac/adb-bus.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/adb-bus.c Tue Apr 15 15:52:04 1997 @@ -0,0 +1,644 @@ +/* + * MACII ADB keyboard handler. + * Copyright (c) 1997 Alan Cox + * + * Derived from code + * Copyright (C) 1996 Paul Mackerras. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "via6522.h" +#include +#include +#include +#include + + +#define MACII /* For now - will be a switch */ + +/* Bits in B data register: all active low */ +#define TREQ 0x08 /* Transfer request (input) */ +#define TACK 0x10 /* Transfer acknowledge (output) */ +#define TIP 0x20 /* Transfer in progress (output) */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#define SR_EXT 0x0c /* Shift on external clock */ +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET 0x80 /* set bits in IER */ +#define IER_CLR 0 /* clear bits in IER */ +#define SR_INT 0x04 /* Shift register full/empty */ + +static struct adb_handler { + void (*handler)(unsigned char *, int, struct pt_regs *); +} adb_handler[16]; + +static enum adb_state { + idle, + sent_first_byte, + sending, + reading, + read_done, + awaiting_reply +} adb_state; + +static struct adb_request *current_req; +static struct adb_request *last_req; +static unsigned char cuda_rbuf[16]; +static unsigned char *reply_ptr; +static int reading_reply; +static int data_index; + +static void adb_start(void); +extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs); +static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs); + + +void adb_bus_init(void) +{ + unsigned long flags; + unsigned char c; + int ct; + + save_flags(flags); + cli(); + + /* + * Setup MacII style ADB - no CUDA + */ +#ifdef MACII + printk("adb: MacII style keyboard/mouse driver.\n"); + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); + /* Shift register on input */ + c=via_read(via1, vACR); + c&=~SR_CTRL; /* Clear shift register bits */ + c|=SR_EXT; /* Shift on external clock */ + via_write(via1, vACR, c); + /* Wipe any pending data and int */ + via_read(via1, vSR); + /* This is interrupts on enable SR for keyboard */ + via_write(via1, vIER, IER_SET|SR_INT); + /* This clears the interrupt bit */ + via_write(via1, vIFR, SR_INT); + /* Lower the bus signals (MacII is active low it seems ???) */ + via_write(via1, vBufB, via_read(via1, vBufB)&~TACK); + + ct=1000; + while( ct-- && (via_read(via1, vBufB)&TREQ)) + udelay(1000); + if(ct<0) + printk("No sync occured\n"); + ct=1000; + while( ct-- && !(via_read(via1, vIFR)&SR_INT)) + udelay(1000); + if(ct<0) + printk("No sync 2 occured\n"); + via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)|TACK); + while( ct-- && !(via_read(via1, vBufB)&TREQ)) + udelay(1000); + if(ct<0) + printk("No sync 3 occured\n"); + ct=1000; + while( ct-- && !(via_read(via1, vIFR)&SR_INT)) + udelay(1000); + if(ct<0) + printk("No sync 4 occured\n"); + via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)|TIP); +#endif + /* + * Ok we probably ;) have a ready to use adb bus. Its also + * hopefully idle (Im assuming the mac didnt leave a half + * complete transaction on booting us). + */ + + adb_state = idle; + via_setup_keyboard(); + restore_flags(flags); +} + +#define WAIT_FOR(cond, what) \ + do { \ + for (x = 1000; !(cond); --x) { \ + if (x == 0) { \ + printk("Timeout waiting for " what); \ + return 0; \ + } \ + __delay(100*160); \ + } \ + } while (0) + +/* Construct and send an adb request */ +int adb_request(struct adb_request *req, void (*done)(struct adb_request *), + int nbytes, ...) +{ + va_list list; + int i; + + req->nbytes = nbytes; + req->done = done; + va_start(list, nbytes); + for (i = 0; i < nbytes; ++i) + req->data[i] = va_arg(list, int); + va_end(list); + req->reply_expected = 1; + return adb_send_request(req); +} + +int adb_send_request(struct adb_request *req) +{ + unsigned long flags; + + req->next = 0; + req->sent = 0; + req->got_reply = 0; + req->reply_len = 0; + save_flags(flags); + cli(); + + if (current_req != NULL) + { + last_req->next = req; + last_req = req; + } + else + { + current_req = req; + last_req = req; + if (adb_state == idle) + adb_start(); + } + + restore_flags(flags); + return 0; +} + +static void adb_start(void) +{ + unsigned long flags; + struct adb_request *req; + + /* assert adb_state == idle */ + /* get the packet to send */ + req = current_req; + if (req == 0) + return; + save_flags(flags); + cli(); + + printk("adb_start: "); + + if ((via_read(via1, vBufB)& TREQ) == 0) + { + /* + * FIXME - we need to restart this on a timer + * or a collision at boot hangs us. + */ + printk("device busy - fail\n"); + restore_flags(flags); + return; /* a byte is coming in from the CUDA */ + } + +#ifdef CUDA + /* set the shift register to shift out and send a byte */ + via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); + via_write(via1, vSR, req->data[0]); + via_write(via1, vBufB, via_read(via1, vBufB)&~TIP); +#endif +#ifdef MACII + /* Output mode */ + via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); + /* Load data */ + via_write(via1, vSR, req->data[0]); + /* Turn off TIP/TACK */ + via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); +#endif + adb_state = sent_first_byte; + printk("sent first byte of %d\n", req->nbytes); + restore_flags(flags); +} + +void adb_poll(void) +{ + unsigned char c; + unsigned long flags; + save_flags(flags); + cli(); + c=via_read(via1, vIFR); + printk("adb_poll: %x \r", c); + if (c & SR_INT) + { + printk("adb interrupt event\n"); + adb_interrupt(0, 0, 0); + } + restore_flags(flags); +} + +void adb_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + int x, status; + struct adb_request *req; + + /* if IRQ==0 its a poll and we've checked and cleared + vIFR already */ + + if (irq && (via_read(via1, vIFR)& SR_INT) == 0) + return; + + status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); + printk("adb_interrupt: state=%d status=%x\n", adb_state, status); + switch (adb_state) + { + case idle: +#ifdef CUDA + /* CUDA has sent us the first byte of data - unsolicited */ + if (status != TREQ) + printk("cuda: state=idle, status=%x\n", status); + x = via_read(via1, vSR); + via[B] &= ~TIP; +#endif +#ifdef MACII + if (status != TREQ) + printk("adb_macII: state=idle status=%x\n", + status); + x = via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); +#endif + adb_state = reading; + reply_ptr = cuda_rbuf; + reading_reply = 0; + break; + + case awaiting_reply: +#ifdef CUDA + /* CUDA has sent us the first byte of data of a reply */ + if (status != TREQ) + printk("cuda: state=awaiting_reply, status=%x\n", status); + x = via[SR]; + via[B] &= ~TIP; +#endif + adb_state = reading; + reply_ptr = current_req->reply; + reading_reply = 1; + break; + + case sent_first_byte: +#ifdef CUDA + if (status == TREQ + TIP + SR_OUT) + { + /* collision */ + via[ACR] &= ~SR_OUT; + x = via[SR]; + via[B] |= TIP | TACK; + adb_state = idle; + } + else + { + /* assert status == TIP + SR_OUT */ + if (status != TIP + SR_OUT) + printk("cuda: state=sent_first_byte status=%x\n", status); + via[SR] = current_req->data[1]; + via[B] ^= TACK; + data_index = 2; + adb_state = sending; + } +#endif +#ifdef MACII + if(status!=TIP+SR_OUT) + printk("adb_macII: state=send_first_byte status=%x\n", status); + via_write(via1, vSR, current_req->data[1]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + data_index=2; + adb_state = sending; +#endif + break; + + case sending: + req = current_req; + if (data_index >= req->nbytes) + { +#ifdef CUDA + via[ACR] &= ~SR_OUT; + x = via[SR]; + via[B] |= TACK | TIP; +#endif +#ifdef MACII + via_write(via1, vACR, + via_read(via1, vACR) & ~SR_OUT); + x=via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#endif + req->sent = 1; + if (req->reply_expected) + { + adb_state = awaiting_reply; + } + else + { + current_req = req->next; + if (req->done) + (*req->done)(req); + /* not sure about this */ + adb_state = idle; + adb_start(); + } + } + else + { +#ifdef CUDA + via[SR] = req->data[data_index++]; + via[B] ^= TACK; +#endif +#ifdef MACII + via_write(via1, vSR, req->data[data_index++]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); +#endif + } + break; + + case reading: + *reply_ptr++ = via_read(via1, vSR); +#ifdef CUDA + if (status == TIP) + { + /* that's all folks */ + via[B] |= TACK | TIP; + adb_state = read_done; + } + else + { + /* assert status == TIP | TREQ */ + if (status != TIP + TREQ) + printk("cuda: state=reading status=%x\n", status); + via[B] ^= TACK; + } +#endif +#ifdef MACII + if( status == TIP) + { + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + adb_state = read_done; + } + else + { + if(status!=TIP+TREQ) + printk("macII_adb: state=reading status=%x\n", status); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } +#endif + break; + + case read_done: + x = via_read(via1, vSR); + if (reading_reply) + { + req = current_req; + req->reply_len = reply_ptr - req->reply; + req->got_reply = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + } + else + { + adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); + } + + if (status == TREQ) + { + via_write(via1, vBufB, + via_read(via1, vBufB)|~TIP); + adb_state = reading; + reply_ptr = cuda_rbuf; + reading_reply = 0; + } + else + { + adb_state = idle; + adb_start(); + } + break; + + default: + printk("adb_interrupt: unknown adb_state %d?\n", adb_state); + } +} + +static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs) +{ + int i, id; + + switch (buf[0]) + { + case ADB_PACKET: + id = buf[2] >> 4; +#if 0 + xmon_printf("adb packet: "); + for (i = 0; i < nb; ++i) + xmon_printf(" %x", buf[i]); + xmon_printf(", id = %d\n", id); +#endif + if (adb_handler[id].handler != 0) + { + (*adb_handler[id].handler)(buf, nb, regs); + } + break; + + default: + printk("data from via (%d bytes):", nb); + for (i = 0; i < nb; ++i) + printk(" %.2x", buf[i]); + printk("\n"); + } +} + +/* Ultimately this should return the number of devices with + the given default id. */ + +int adb_register(int default_id, + void (*handler)(unsigned char *, int, struct pt_regs *)) +{ + if (adb_handler[default_id].handler != 0) + panic("Two handlers for ADB device %d\n", default_id); + adb_handler[default_id].handler = handler; + return 1; +} + +/* + * Here are the file operations we export for /dev/adb. + */ + +#define ADB_MINOR 140 /* /dev/adb is c 10 140 */ + +extern void adbdev_inits(void); + +struct adbdev_state { + struct adb_request req; +}; + +static struct wait_queue *adb_wait; + +static int adb_wait_reply(struct adbdev_state *state, struct file *file) +{ + int ret = 0; + struct wait_queue wait = { current, NULL }; + + add_wait_queue(&adb_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (!state->req.got_reply) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (current->signal & ~current->blocked) { + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&adb_wait, &wait); + + return ret; +} + +static void adb_write_done(struct adb_request *req) +{ + if (!req->got_reply) { + req->reply_len = 0; + req->got_reply = 1; + } + wake_up_interruptible(&adb_wait); +} + +static int adb_open(struct inode *inode, struct file *file) +{ + struct adbdev_state *state; + + state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); + if (state == 0) + return -ENOMEM; + file->private_data = state; + state->req.reply_expected = 0; + return 0; +} + +static void adb_release(struct inode *inode, struct file *file) +{ + struct adbdev_state *state = file->private_data; + + if (state) { + file->private_data = NULL; + if (state->req.reply_expected && !state->req.got_reply) + if (adb_wait_reply(state, file)) + return; + kfree(state); + } + return; +} + +static int adb_lseek(struct inode *inode, struct file *file, + off_t offset, int origin) +{ + return -ESPIPE; +} + +static int adb_read(struct inode *inode, struct file *file, + char *buf, int count) +{ + int ret; + struct adbdev_state *state = file->private_data; + + if (count < 2) + return -EINVAL; + if (count > sizeof(state->req.reply)) + count = sizeof(state->req.reply); + ret = verify_area(VERIFY_WRITE, buf, count); + if (ret) + return ret; + + if (!state->req.reply_expected) + return 0; + + ret = adb_wait_reply(state, file); + if (ret) + return ret; + + ret = state->req.reply_len; + memcpy_tofs(buf, state->req.reply, ret); + state->req.reply_expected = 0; + + return ret; +} + +static int adb_write(struct inode *inode, struct file *file, + const char *buf, int count) +{ + int ret; + struct adbdev_state *state = file->private_data; + + if (count < 2 || count > sizeof(state->req.data)) + return -EINVAL; + ret = verify_area(VERIFY_READ, buf, count); + if (ret) + return ret; + + if (state->req.reply_expected && !state->req.got_reply) { + /* A previous request is still being processed. + Wait for it to finish. */ + ret = adb_wait_reply(state, file); + if (ret) + return ret; + } + + state->req.nbytes = count; + state->req.done = adb_write_done; + memcpy_fromfs(state->req.data, buf, count); + state->req.reply_expected = 1; + state->req.got_reply = 0; + adb_send_request(&state->req); + + return count; +} + +static struct file_operations adb_fops = { + adb_lseek, + adb_read, + adb_write, + NULL, /* no readdir */ + NULL, /* no select */ + NULL, /* no ioctl */ + NULL, /* no mmap */ + adb_open, + adb_release +}; + +static struct miscdevice adb_dev = { + ADB_MINOR, + "adb", + &adb_fops +}; + +void adbdev_init() +{ + misc_register(&adb_dev); +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/bootparse.c linux-2.0.29/arch/m68k/mac/bootparse.c --- linux.vanilla/arch/m68k/mac/bootparse.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/bootparse.c Tue Mar 25 18:16:37 1997 @@ -0,0 +1,89 @@ +#include +#include +#include + +/* + * Booter vars + */ + +int boothowto; + + +/* + * Called early to parse the environment (passed to us from the booter) + * into a bootinfo struct. Will die as soon as we have our own booter + */ + +#define atol(x) simple_strtoul(x,NULL,0) + +void parse_booter(char *env) +{ + char *name; + char *value; + while(*env) + { + name=env; + value=name; + while(*value!='='&&*value) + value++; + if(*value=='=') + *value++=0; + env=value; + while(*value) + value++; +#if 0 + if(strcmp(name,"VIDEO_ADDR")==0) + boot_info.bi_mac.videoaddr=atol(value); + if(strcmp(name,"ROW_BYTES")==0) + boot_info.bi_mac.videorow=atol(value); + if(strcmp(name,"SCREEN_DEPTH")==0) + boot_info.bi_mac.videodepth=atol(value); + if(strcmp(name,"DIMENSIONS")==0) + boot_info.bi_mac.dimensions=atol(value); +#endif + if(strcmp(name,"BOOTTIME")==0) + boot_info.bi_mac.boottime=atol(value); + if(strcmp(name,"GMTBIAS")==0) + boot_info.bi_mac.gmtbias=atol(value); + if(strcmp(name,"BOOTERVER")==0) + boot_info.bi_mac.bootver=atol(value); + if(strcmp(name,"MACOS_VIDEO")==0) + boot_info.bi_mac.videological=atol(value); + if(strcmp(name,"MACOS_SCC")==0) + boot_info.bi_mac.scc=atol(value); + if(strcmp(name,"MACHINEID")==0) + boot_info.bi_mac.id=atol(value); + if(strcmp(name,"MEMSIZE")==0) + boot_info.bi_mac.memsize=atol(value); + if(strcmp(name,"SERIAL_MODEM_FLAGS")==0) + boot_info.bi_mac.serialmf=atol(value); + if(strcmp(name,"SERIAL_MODEM_HSKICLK")==0) + boot_info.bi_mac.serialhsk=atol(value); + if(strcmp(name,"SERIAL_MODEM_GPICLK")==0) + boot_info.bi_mac.serialgpi=atol(value); + if(strcmp(name,"SERIAL_PRINT_FLAGS")==0) + boot_info.bi_mac.printf=atol(value); + if(strcmp(name,"SERIAL_PRINT_HSKICLK")==0) + boot_info.bi_mac.printhsk=atol(value); + if(strcmp(name,"SERIAL_PRINT_GPICLK")==0) + boot_info.bi_mac.printgpi=atol(value); + if(strcmp(name,"PROCESSOR")==0) + boot_info.bi_mac.cpuid=atol(value); + if(strcmp(name,"ROMBASE")==0) + boot_info.bi_mac.rombase=atol(value); + if(strcmp(name,"TIMEDBRA")==0) + boot_info.bi_mac.timedbra=atol(value); + if(strcmp(name,"ADBDELAY")==0) + boot_info.bi_mac.adbdelay=atol(value); + } + /* Fill in the base stuff */ + boot_info.machtype=MACH_MAC; + /* Read this from the macinfo we got ! */ + boot_info.cputype=CPU_68020|FPUB_68881; +/* boot_info.memory[0].addr=0; + boot_info.memory[0].size=boot_info.bi_mac.memsize;*/ + boot_info.num_memory=1; /* On a MacII */ + boot_info.ramdisk_size=0; /* For now */ + *boot_info.command_line=0; + } + diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/config.c linux-2.0.29/arch/m68k/mac/config.c --- linux.vanilla/arch/m68k/mac/config.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/config.c Tue Apr 15 12:01:40 1997 @@ -0,0 +1,190 @@ +/* + * linux/arch/m68k/mac/config.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +/* + * Miscellaneous linux stuff + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "via6522.h" + +void *mac_env; /* Loaded by the boot asm */ + +extern void (*kd_mksound)(unsigned int, unsigned int); + +void mac_get_model(char *str) +{ + strcpy(str,"Macintosh"); +} + +extern void mac_reset(); + +void mac_bang(int irq, void *vector, struct pt_regs *p) +{ + mac_reset(); +} + +void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) +{ + via_init_clock(vector); + request_irq(1, via1_irq, IRQ_FLG_LOCK, "via1", via1_irq); + request_irq(6, mac_bang, IRQ_FLG_LOCK, "offswitch", mac_bang); +} + +int mac_keyb_init(void) +{ + panic("keyb_init:notused"); +} + +int mac_kbdrate(struct kbd_repeat *k) +{ + return 0; +} + +void mac_kbd_leds(unsigned int leds) +{ + ; +} + + +unsigned long mac_gettimeoffset (void) +{ + return 0L; +} + +void mac_mksound( unsigned int count, unsigned int ticks ) +{ + ; +} + + +void mac_waitbut (void) +{ + ; +} + +extern struct consw fb_con; +extern struct fb_info *mac_fb_init(long *); +extern void mac_video_setup(char *, int *); + +void mac_debug_init (void) +{ + ; +} + + +extern void mac_init_IRQ(void); +extern int mac_request_irq (unsigned int, void (*)(int, void *, + struct pt_regs *), + unsigned long, const char *, void *); +extern int mac_free_irq(unsigned int, void *); +extern void mac_enable_irq(unsigned int); +extern void mac_disable_irq(unsigned int); +extern int mac_get_irq_list(char *); +extern void mac_default_handler(int irq); + + +void (*mac_handlers[8])(int, void *, struct pt_regs *)= +{ + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler +}; + +void config_mac(void) +{ + int xd,yd; + int y; + unsigned char c=0xF0; + unsigned char *bp=(unsigned char *)boot_info.bi_mac.videoaddr; + + parse_booter(mac_env); + + xd=boot_info.bi_mac.dimensions; + + yd=xd>>16; + xd&=0xFFFF; + + if(xd<512||yd <256|| boot_info.bi_mac.videoaddr!=0xFDD00020) + { + boot_info.bi_mac.videoaddr=0xFDD00020; + mac_boom(9); + } + + for(y=0;y<16;y++) + { + memset(bp+y*boot_info.bi_mac.videorow, + 0x00,boot_info.bi_mac.videorow); + } + memset(bp+y*boot_info.bi_mac.videorow, + 0xFF,boot_info.bi_mac.videorow); + + *bp=0xFF; + bp[boot_info.bi_mac.videorow-1]=0xFF; + bp[boot_info.bi_mac.videorow]=0xF0; + bp[boot_info.bi_mac.videorow*2-1]=0x0F; + + for(y=17;y +#include +#include + +static struct symbol_table mach_mac_symbol_table = { +#include +#include +}; + +void mach_mac_syms_export(void) +{ + register_symtab(&mach_mac_symbol_table); +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/mac.h linux-2.0.29/arch/m68k/mac/mac.h --- linux.vanilla/arch/m68k/mac/mac.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/mac.h Fri Mar 21 14:43:30 1997 @@ -0,0 +1,74 @@ +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0x0F, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x0F,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xF0,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xF0,0x0F,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0xF0,0x0F,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x0F,0x00,0xF0,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xF0,0x00,0x00,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0xF0,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0xF0,0x00,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0xF0,0x00,0xF0,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0xF0,0x00,0x0F,0x00,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x0F,0x00,0x00,0xF0,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x0F,0x0F,0x00,0x00,0xF0,0x00,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x0F,0x0F,0x00,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0xF0,0xF0,0xF0,0x0F,0x0F,0x00,0xF0,0x0F,0x0F,0x00,0x00,0x0F,0x0F,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xF0,0x00,0xF0,0xF0,0x0F,0x0F,0x00,0xF0,0x0F,0x0F,0x00,0xF0,0x00,0x00,0x0F,0x00,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xF0,0x0F,0x0F,0x0F,0x00,0x0F,0x00,0xF0,0xF0,0xF0,0x00,0xF0,0xF0,0x00,0xF0,0x0F,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xF0,0xFF,0x00,0x0F,0x0F,0x0F,0x00,0x0F,0x00,0xF0,0xF0,0x00,0x0F,0x00,0x00,0xF0,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0xF0,0x0F,0x0F,0x00,0x0F,0x0F,0xF0,0x0F,0x00,0x00,0xF0,0x00,0x0F,0x00,0x00,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0xF0,0xF0,0xF0,0x0F,0xF0,0xF0,0xF0,0x00,0x00,0xF0,0xF0,0x0F,0x0F,0x00,0xF0,0x00,0x0F,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0x0F,0x0F,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x0F,0x00,0x0F,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0xFF,0xF0,0x0F,0x0F,0x00,0x0F,0x00,0xF0,0x00,0x00,0xF0,0xF0,0x0F,0x00,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0x00,0xF0,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x0F,0x00,0xF0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xF0,0xF0,0x0F,0x0F,0x00,0x0F,0x00,0x00,0x00,0x0F,0x00,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0x0F,0x0F,0x0F,0xF0,0xF0,0xF0,0x0F,0x00,0x00,0x00,0xF0,0x0F,0x0F,0x00,0xF0,0xF0,0x0F,0x0F,0x0F,0x00,0x0F,0x00, +0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x0F,0xFF,0x0F,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,0x0F,0x0F,0x00,0xF0,0x0F,0x00,0x00,0xF0,0xF0,0x00,0xF0,0x00,0xF0, +0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0x0F,0x00,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0xF0,0xF0,0x00,0xF0,0x00,0xF0,0x00, +0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0xF0,0xFF,0x00,0x00,0x0F,0xF0,0xF0,0xF0,0xF0,0x0F,0x00,0x0F,0x0F,0x00,0xF0,0x00,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x00,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x0F,0x0F,0xFF,0xFF,0x0F,0x0F,0xF0,0xFF,0x00,0x00,0x0F,0xFF,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x0F,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0x0F,0xFF,0x0F,0x00,0x0F,0xF0,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0x00,0x0F, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0x0F,0xFF,0xFF,0x0F,0x0F,0xF0,0xFF,0x00,0x00,0x00,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0xF0,0x00,0xF0,0xF0,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0xFF,0xFF,0x0F,0xFF,0x0F,0x00,0x00,0xFF,0xF0,0xFF,0x0F,0xF0,0xF0,0xF0,0xF0,0x0F,0x00,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0x0F,0x0F,0x0F,0xF0,0xF0,0xFF,0xFF,0x00,0x00,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0x0F,0x00,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x0F,0x0F,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0xF0,0xF0,0xF0,0xFF,0x00,0x00,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0xF0,0x0F, +0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0x0F,0xFF,0xFF,0xF0,0xFF,0x0F,0xFF,0x0F,0x00,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0xFF,0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x0F,0x00,0x0F,0xF0,0x00,0x00,0xFF,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, +0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0x00,0x00,0x0F,0x00,0x00,0x0F,0xF0,0xFF,0x0F,0x00,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xFF,0x0F,0x0F,0x0F,0x0F, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x0F,0xFF,0x0F,0x0F,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0xF0,0xF0,0x00,0xF0,0xF0,0xF0,0xF0,0xFF,0x0F,0x0F,0x0F, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xFF, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0xF0,0xF0,0x00,0xF0,0xFF,0x00,0x0F,0x00,0xF0,0x0F,0x0F,0x0F,0x0F,0xFF,0xF0,0xF0, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0xF0,0x00,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, +0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x0F,0x00,0x00,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0xFF,0x0F, +0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F, +0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xF0,0x00,0xF0,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0x0F,0x00,0xF0,0xF0,0xF0, +0xFF,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0xF0,0x0F,0x0F,0x00,0x00,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xF0,0xFF,0x0F,0x0F,0x0F, +0xFF,0xFF,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0xF0,0xF0,0xFF,0x00,0xF0,0xF0,0x0F,0x00,0xF0,0xF0,0xF0, +0x0F,0xF0,0xF0,0xF0,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0x00,0x00,0xF0,0x00,0x00,0xF0,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x0F,0x00,0x0F,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F, +0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0x0F,0x00,0xF0,0xF0,0x0F,0x0F,0x0F,0x00,0xFF,0x0F,0x0F,0x00,0xF0,0xF0,0xFF,0x0F,0x00,0xF0,0xF0,0xF0,0x0F,0x0F,0x00, +0x0F,0x0F,0x0F,0x00,0xF0,0x0F,0x00,0x00,0xF0,0xF0,0x00,0x0F,0x00,0x00,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0x0F,0x0F,0x00,0x0F,0x0F,0x0F,0x00,0x00,0x0F,0x00,0x00,0x0F diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/macfb.c linux-2.0.29/arch/m68k/mac/macfb.c --- linux.vanilla/arch/m68k/mac/macfb.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/macfb.c Mon Mar 24 14:22:22 1997 @@ -0,0 +1,338 @@ +/* + * We've been given MAC frame buffer info by the booter. Now go set it up + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +static struct fb_var_screeninfo mac_fb_defined={ + 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/ + 0,0, /* virtual -> visible no offset */ + 8, /* depth -> load bits_per_pixel */ + 0, /* greyscale ? */ + {0,0,0}, /* R */ + {0,0,0}, /* G */ + {0,0,0}, /* B */ + {0,0,0}, /* transparency */ + 0, /* standard pixel format */ + FB_ACTIVATE_NOW, + 274,195, /* 14" monitor *Mikael Nykvist's anyway* */ + FB_ACCEL_NONE, /* The only way to accelerate a mac is .. */ + 0L,0L,0L,0L,0L, + 0L,0L,0, /* No sync info */ + FB_VMODE_NONINTERLACED, + {0,0,0,0,0,0} +}; + +#define NUM_TOTAL_MODES 1 +#define NUM_PREDEF_MODES 1 + +static struct display disp[MAX_NR_CONSOLES]; +static struct fb_info fb_info; +static int node; + +struct mac_fb_par +{ + void *unused; +}; + +static int currcon = 0; +static int current_par_valid = 0; +struct mac_fb_par current_par; + +static int mac_xres,mac_yres,mac_depth, mac_xbytes, mac_vxres; +static unsigned long mac_videobase; +static unsigned long mac_videosize; + + +static void mac_fb_encode_var(struct fb_var_screeninfo *var) +{ + int i=0; + var->xres=mac_xres; + var->yres=mac_yres; + var->xres_virtual=mac_vxres; + var->yres_virtual=var->yres; + var->xoffset=0; + var->yoffset=0; + var->bits_per_pixel = mac_depth; + var->grayscale=0; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + var->nonstd=0; + var->activate=0; + var->height= -1; + var->width= -1; + var->accel=0; + var->vmode=FB_VMODE_NONINTERLACED; + var->pixclock=0; + var->sync=0; + var->left_margin=0; + var->right_margin=0; + var->upper_margin=0; + var->lower_margin=0; + var->hsync_len=0; + var->vsync_len=0; + for(i=0;ireserved);i++) + var->reserved[i]=0; + return; +} + + +static void mac_fb_get_par(struct mac_fb_par *par) +{ + *par=current_par; +} + +static void mac_fb_set_par(struct mac_fb_par *par) +{ + current_par_valid=1; +} + +static int fb_update_var(int con) +{ + return 0; +} + +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + mac_fb_encode_var(var); + return 0; +} + +static void mac_fb_encode_fix(struct fb_fix_screeninfo *fix) +{ + int i; + strcpy(fix->id,"Macintosh"); + fix->smem_start=mac_videobase; + fix->smem_len=mac_videosize; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + fix->xpanstep=0; + fix->ypanstep=0; + fix->ywrapstep=0; + fix->line_length=mac_xbytes; + for(i=0;ireserved);i++) + fix->reserved[i]=0; + return; +} + + + +static int mac_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct mac_fb_par par; + mac_fb_get_par(&par); + mac_fb_encode_fix(fix); + return 0; +} + +static int mac_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + struct mac_fb_par par; + if(con==-1) + { + mac_fb_get_par(&par); + mac_fb_encode_var(var); + } + else + *var=disp[con].var; + return 0; +} + +static void mac_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + + mac_fb_get_fix(&fix,con); + if (con == -1) + con=0; + disp[con].screen_base = (u_char *)fix.smem_start; + disp[con].visual = fix.visual; + disp[con].type = fix.type; + disp[con].type_aux = fix.type_aux; + disp[con].ypanstep = fix.ypanstep; + disp[con].ywrapstep = fix.ywrapstep; + disp[con].line_length = fix.line_length; + disp[con].next_line = fix.line_length; + disp[con].can_soft_blank = 0; + disp[con].inverse = 0; +} + +static int mac_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err; + + if ((err=do_fb_set_var(var, 1))) + return err; + return 0; +} + +static int mac_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + return -EINVAL; +} + +static int mac_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + return -EINVAL; +} + +static int mac_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + /* no panning */ + return -EINVAL; +} + +static int mac_fb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con) +{ + return -EINVAL; +} + +static struct fb_ops mac_fb_ops = { + mac_fb_get_fix, + mac_fb_get_var, + mac_fb_set_var, + mac_fb_get_cmap, + mac_fb_set_cmap, + mac_fb_pan_display, + mac_fb_ioctl +}; + +void mac_video_setup(char *options, int *ints) +{ +} + +static int macfb_switch(int con) +{ + do_fb_set_var(&disp[con].var,1); + currcon=con; + return 0; +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static void macfb_blank(int blank) +{ + /* Not supported */ +} + +struct fb_info *mac_fb_init(long *mem_start) +{ + /* nubus_remap the video .. */ + int err; + + mac_xres=boot_info.bi_mac.dimensions&0xFFFF; + mac_yres=(boot_info.bi_mac.dimensions&0xFFFF0000)>>16; + mac_depth=boot_info.bi_mac.videodepth; + mac_xbytes=boot_info.bi_mac.videorow; + mac_vxres = (mac_xbytes/mac_depth)*8; + mac_videosize=mac_xbytes*mac_yres; + mac_videobase=boot_info.bi_mac.videoaddr; + mac_debugging_penguin(4); + + /* + * Fill in the available video resolution + */ + + mac_fb_defined.xres=mac_xres; + mac_fb_defined.yres=mac_yres; + mac_fb_defined.xres_virtual=mac_vxres; + mac_fb_defined.yres_virtual=mac_yres; + mac_fb_defined.bits_per_pixel=mac_depth; + + + /* + * Let there be consoles.. + */ + err=register_framebuffer("Macintosh", &node, &mac_fb_ops, NUM_TOTAL_MODES, &mac_fb_defined); + if(err<0) + { + mac_boom(5); + return NULL; + } + fb_info.disp=disp; + fb_info.switch_con=&macfb_switch; + fb_info.updatevar=&fb_update_var; + fb_info.blank=&macfb_blank; + do_fb_set_var(&mac_fb_defined,1); + mac_fb_get_var(&disp[0].var, -1); + mac_fb_set_disp(-1); + + return &fb_info; +} + +static char that_penguin[]={ +#include "that_penguin.h" +}; + +void mac_debugging_penguin(int peng) +{ + unsigned char *pengoffset; + unsigned char *pptr; + unsigned char *pdptr=that_penguin; + int i; + + pengoffset=(unsigned char *)(boot_info.bi_mac.videoaddr+ + 64*boot_info.bi_mac.videorow)+40*peng; + + pptr=pengoffset; + + for(i=0;i<74;i++) + { + memcpy(pptr,pdptr,32); + pdptr+=32; + pptr+=boot_info.bi_mac.videorow; + } +} + +static char kaboom_map[]={ +#include "mac.h" +}; + +static void mac_boom_boom(void) +{ + static unsigned char *boomoffset=NULL; + unsigned char *pptr; + unsigned char *pdptr=kaboom_map; + int i; + + if(!boomoffset) + boomoffset=(unsigned char *)(boot_info.bi_mac.videoaddr+ + 256*boot_info.bi_mac.videorow); + else + boomoffset+=32; + + pptr=boomoffset; + + for(i=0;i<74;i++) + { + memcpy(pptr,pdptr,32); + pdptr+=32; + pptr+=boot_info.bi_mac.videorow; + } +} + +void mac_boom(int booms) +{ + int i; + for(i=0;i +#include +#include +#include + +#include +#include +#include + +asmlinkage void bad_interrupt(void); + +void mac_init_IRQ(void) +{ +} + +/* + * We have no machine specific interrupts on a macintoy + */ + +int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + return -EINVAL; +} + +int mac_free_irq (unsigned int irq, void *dev_id) +{ + return -EINVAL; +} + +void mac_enable_irq (unsigned int irq) +{ + ; +} + +void mac_disable_irq (unsigned int irq) +{ + ; +} + +int mac_get_irq_list (char *buf) +{ + return 0; +} + +void mac_default_handler(int irq) +{ +/* printk("Unexpected IRQ %d\n",irq);*/ +} + diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/that_penguin.h linux-2.0.29/arch/m68k/mac/that_penguin.h --- linux.vanilla/arch/m68k/mac/that_penguin.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/that_penguin.h Fri Mar 21 13:44:53 1997 @@ -0,0 +1,74 @@ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0xFF,0xFF,0x0F,0xF0,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0x00,0xFF,0xFF,0x0F,0xFF,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0x0F,0xFF,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x0F,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x0F,0xF0,0x00,0x00,0xFF,0xF0,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0xF0,0xFF,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0x00,0x00, +0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0xF0,0x00,0x00, +0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00, +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00, +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00, +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00, +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0, +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F, +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00, +0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00, +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00, +0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, +0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00 diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/via6522.c linux-2.0.29/arch/m68k/mac/via6522.c --- linux.vanilla/arch/m68k/mac/via6522.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/via6522.c Tue Apr 15 14:45:38 1997 @@ -0,0 +1,198 @@ +/* + * 6522 Versatile Interface Adapter (VIA) + * + * There are two of these on the Mac II. Some IRQ's are vectored + * via them as are assorted bits and bobs - eg rtc, adb. + */ + +#include +#include +#include +#include + +#include "via6522.h" + +volatile unsigned char *via1=(unsigned char *)VIABASE; +volatile unsigned char *via2=(unsigned char *)VIABASE2; + +/* + * VIA1 - hardwired vectors + */ + +extern void via_wtf(int slot, void *via, struct pt_regs *regs); +extern void adb_interrupt(int slot, void *via, struct pt_regs *regs); + +static struct via_irq_tab via1_func_tab= +{ + { + via_wtf, + via_wtf, + via_wtf, /* The frontdesk bus events on a MacII anyway */ + via_wtf, + via_wtf, + via_wtf, + via_wtf, /* Slot 6 is replaced by the timer */ + via_wtf + } +}; + +#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */ +#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) +#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) + + +void via_init_clock(void (*func)(int, void *, struct pt_regs *)) +{ + unsigned char c; + + mac_debugging_penguin(6); + + /* + * Shut it down + */ + + via_write(via1,vIER, 0x7F); + via_write(via2,vIER, 0x7F); + + /* + * Kill the timers + */ + + via_write(via1,vT1LL,0); + via_write(via1,vT1LH,0); + via_write(via1,vT1CL,0); + via_write(via1,vT1CH,0); + via_write(via1,vT2CL,0); + via_write(via1,vT2CH,0); + + /* + * Now do via2 + */ + + via_write(via2,vT1LL,0); + via_write(via2,vT1LH,0); + via_write(via2,vT1CL,0); + via_write(via2,vT1CH,0); + via_write(via2,vT2CL,0); + via_write(via2,vT2CH,0); + + /* + * Disable the timer latches + */ + + c=via_read(via1,vACR); + via_write(via1,vACR,c&0x3F); + + c=via_read(via2,vACR); + via_write(via2,vACR,c&0x3F); + + /* + * Now start the clock - we want 100Hz + */ + + via_write(via1,vACR,via_read(via1,vACR)|0x40); + + via_write(via1,vT1LL, MAC_CLOCK_LOW); + via_write(via1,vT1LH, MAC_CLOCK_HIGH); + via_write(via1,vT1CL, MAC_CLOCK_LOW); + via_write(via1,vT1CH, MAC_CLOCK_HIGH); + + /* + * And enable its interrupt + */ + + via_write(via1, vIER, 0x80|(1<<6)); + + via1_func_tab.vector[6]=func; + mac_debugging_penguin(7); +} + + +static void via_irq(unsigned char *via, struct via_irq_tab *irqtab, + struct pt_regs *regs) +{ + unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F; + int i; + + /* + * Shouldnt happen + */ + + if(events==0) + { + printk("via_irq: nothing pending!\n"); + return; + } + + /* + * Clear the pending flag + */ + + via_write(via, vIFR, events); + + /* + * Now see what bits are raised + */ + + for(i=0;i<7;i++) + { + if(events&(1<vector[i])(i, via, regs); + } + + /* + * And done.. + */ +} + +/* + * System interrupts + */ + +void via1_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + via_irq(via1, &via1_func_tab, regs); +} + +/* + * Nubus interrupts + */ + +void via2_irq(int irq, void *dev_id, struct pt_regs *regs) +{ +#if 0 + via_irq(via1, &nubus_func_tab, regs); +#endif +} + +/* + * Unexpected via interrupt + */ + +void via_wtf(int slot, void *via, struct pt_regs *regs) +{ + printk("Unexpected event %d on via %p\n",slot,via); +} + +/* + * The power switch - yes its software! + */ + +void mac_reset(void) +{ + /* Direction of vDirB is output */ + via_write(via2,vDirB,via_read(via2,vDirB)|0x04); + /* Send a value of 0 on that line */ + via_write(via2,vBufB,via_read(via2,vBufB)&~0x04); + /* We never make it this far... */ + /* XXX - delay do we need to spin here ? */ +} + +/* + * Set up the keyboard + */ + +void via_setup_keyboard(void) +{ + via1_func_tab.vector[2]=adb_interrupt; +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mac/via6522.h linux-2.0.29/arch/m68k/mac/via6522.h --- linux.vanilla/arch/m68k/mac/via6522.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/arch/m68k/mac/via6522.h Tue Apr 15 15:44:11 1997 @@ -0,0 +1,96 @@ +/* + * 6522 Versatile Interface Adapter (VIA) + * + * There are two of these on the Mac II. Some IRQ's are vectored + * via them as are assorted bits and bobs - eg rtc, adb. The picture + * is a bit incomplete as the Mac documentation doesnt cover this well + */ + +#define VIABASE 0x50F00000 +#define VIABASE2 0x50F02000 + +/* + * Not all of these are true post MacII I think + */ + +#define VIA1A_vSccWrReq 0x80 /* SCC write */ +#define VIA1A_vRev8 0x40 /* Revision 8 board ??? */ +#define VIA1A_vHeadSel 0x20 /* Head select for IWM */ +#define VIA1A_vOverlay 0x10 +#define VIA1A_vSync 0x08 +#define VIA1A_vVolume 0x07 /* Audio volume mask */ + +#define VIA1B_vSound 0x80 /* Audio on/off */ +#define VIA1B_vMystery 0x40 +#define VIA1B_vADBS2 0x20 /* ADB state 2 */ +#define VIA1B_vADBS1 0x10 /* ADB state 1 */ +#define VIA1B_vADBInt 0x08 /* ADB interrupt */ +#define VIA1B_vRTCEnb 0x04 /* Real time clock */ +#define VIA1B_vRTCClk 0x02 +#define VIA1B_vRTCData 0x01 + +/* + * VIA2 A register is the interrupt lines raised off the nubus + * slots. + */ + +#define VIA2A_vIRQE 0x20 +#define VIA2A_vIRQD 0x10 +#define VIA2A_vIRQC 0x08 +#define VIA2A_vIRQB 0x04 +#define VIA2A_vIRQA 0x02 +#define VIA2A_vIRQ9 0x01 + +/* + * Register B has the fun stuff in it + */ + +#define VIA2B_vPower 0x04 /* Off switch */ +#define VIA2B_vBusLk 0x02 +#define VIA2B_vCDis 0x01 + +extern __inline__ void via_write(volatile unsigned char *via,int reg, int v) +{ + via[reg]=v; +} + +extern __inline__ int via_read(volatile unsigned char *via,int reg) +{ + return (int)via[reg]; +} + +extern volatile unsigned char *via1,*via2; + +/* + * 6522 registers - see databook + */ + +#define vBufB 0x0000 +#define vBufA 0x0200 +#define vDirB 0x0400 +#define vDirA 0x0600 +#define vT1CL 0x0800 +#define vT1CH 0x0a00 +#define vT1LL 0x0c00 +#define vT1LH 0x0e00 +#define vT2CL 0x1000 +#define vT2CH 0x1200 +#define vSR 0x1400 +#define vACR 0x1600 +#define vPCR 0x1800 +#define vIFR 0x1a00 +#define vIER 0x1c00 +#define vANH 0x1e00 /* register A (no shake) */ + +/* + * VIA interrupt + */ + +struct via_irq_tab +{ + void (*vector[8])(int, void *, struct pt_regs *); +}; + +extern void via1_irq(int, void *, struct pt_regs *); +extern void via2_irq(int, void *, struct pt_regs *); + diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/arch/m68k/mm/memory.c linux-2.0.29/arch/m68k/mm/memory.c --- linux.vanilla/arch/m68k/mm/memory.c Wed Feb 19 14:44:42 1997 +++ linux-2.0.29/arch/m68k/mm/memory.c Tue Mar 25 17:55:20 1997 @@ -288,8 +288,18 @@ unsigned long voff = vaddr; unsigned long offset = 0; + if(boot_info.memory[0].size==0) + { + mac_boom(2); + } + for (i = 0; i < boot_info.num_memory; i++) { +#if 0 + printk("Want %lx virtual, Try slot %d (%lx,%lx)\n", + vaddr, i, boot_info.memory[i].addr, + boot_info.memory[i].size); +#endif if (voff < offset + boot_info.memory[i].size) { #ifdef DEBUGPV printk ("VTOP(%lx)=%lx\n", vaddr, diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/Makefile linux-2.0.29/drivers/Makefile --- linux.vanilla/drivers/Makefile Sat Oct 5 14:24:24 1996 +++ linux-2.0.29/drivers/Makefile Tue Apr 15 16:49:47 1997 @@ -9,7 +9,7 @@ SUB_DIRS := block char net #streams MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) pci sbus scsi sound cdrom isdn +ALL_SUB_DIRS := $(SUB_DIRS) pci sbus scsi sound cdrom isdn nubus ifdef CONFIG_PCI SUB_DIRS += pci @@ -17,6 +17,10 @@ ifdef CONFIG_SBUS SUB_DIRS += sbus +endif + +ifdef CONFIG_MAC +SUB_DIRS += nubus endif # If CONFIG_SCSI is set, the core of scsi support will be added to the kernel, diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/block/genhd.c linux-2.0.29/drivers/block/genhd.c --- linux.vanilla/drivers/block/genhd.c Sat Oct 5 14:24:26 1996 +++ linux-2.0.29/drivers/block/genhd.c Thu Apr 10 12:42:10 1997 @@ -780,6 +780,170 @@ } #endif /* CONFIG_ATARI_PARTITION */ +#ifdef CONFIG_MAC_PARTITION +#include + +/* + * Code to understand MacOS partition tables. + */ + +#define MAC_PARTITION_MAGIC 0x504d + +/* type field value for A/UX or other Unix partitions */ +#define APPLE_AUX_TYPE "Apple_UNIX_SVR2" + +struct mac_partition { + __u8 signature[2]; /* expected to be MAC_PARTITION_MAGIC */ + __u8 res1[2]; + __u8 map_count[4]; /* # blocks in partition map */ + __u8 start_block[4]; /* absolute starting block # of partition */ + __u8 block_count[4]; /* number of blocks in partition */ + char name[32]; /* partition name */ + char type[32]; /* string type description */ + __u8 data_start[4]; /* rel block # of first data block */ + __u8 data_count[4]; /* number of data blocks */ + __u8 status[4]; /* partition status bits */ + __u8 boot_start[4]; + __u8 boot_size[4]; + __u8 boot_load[4]; + __u8 boot_load2[4]; + __u8 boot_entry[4]; + __u8 boot_entry2[4]; + __u8 boot_cksum[4]; + char processor[16]; /* identifies ISA of boot */ + /* there is more stuff after this that we don't need */ +}; + +#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */ + +#define MAC_DRIVER_MAGIC 0x4552 + +/* Driver descriptor structure, in block 0 */ +struct mac_driver_desc { + __u8 signature[2]; /* expected to be MAC_DRIVER_MAGIC */ + __u8 block_size[2]; + __u8 block_count[4]; + /* ... more stuff */ +}; + +/* Retrieve a 16-bit bigendian number */ +static inline __u16 get16_be(void *x) +{ + __u8 *p = x; + return (p[0] << 8) + p[1]; +} + +/* Retrieve a 32-bit bigendian number */ +static inline __u32 get32_be(void *x) +{ + __u8 *p = x; + return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; +} + +static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec) +{ + struct buffer_head *bh; + int blk, blocks_in_map, cblk, b, i; + extern kdev_t boot_dev; + unsigned secsize; + struct mac_partition *part; + struct mac_driver_desc *md; + char *cpu = "powerpc"; /* XXX */ + + /* XXX At this stage the block-device stuff thinks that + the disk has 1024-byte blocks, each of which is 2 + 512-byte disk sectors (for a disk with 512-byte sectors). + So then we have to look at two entries in each "block". */ + /* Get 0th block and look at the first partition map entry. */ + if ((bh = bread(dev, 0, 1024)) == 0) { + printk("%s: error reading partition table\n", + kdevname(dev)); + return -1; + } + cblk = 0; + md = (struct mac_driver_desc *) bh->b_data; + if (get16_be(md->signature) != MAC_DRIVER_MAGIC) { + brelse(bh); + return 0; + } + secsize = get16_be(md->block_size); + if (secsize < 1024) + part = (struct mac_partition *) (bh->b_data + secsize); + else { + brelse(bh); + cblk = secsize / 1024; + if ((bh = bread(dev, cblk, 1024)) == 0) { + printk("%s: error reading partition table\n", + kdevname(dev)); + return -1; + } + part = (struct mac_partition *) bh->b_data; + } + if (get16_be(part->signature) != MAC_PARTITION_MAGIC) { + brelse(bh); + return 0; /* not a MacOS disk */ + } + blocks_in_map = get32_be(part->map_count); + for (blk = 1; blk <= blocks_in_map; ++blk) { + b = (blk * secsize) / 1024; + if (b != cblk) { + brelse(bh); + cblk = b; + if ((bh = bread(dev, cblk, 1024)) == 0) { + printk("%s: error reading partition table\n", + kdevname(dev)); + return -1; + } + } + part = (struct mac_partition *) + (bh->b_data + (blk * secsize) % 1024); + if (get16_be(part->signature) != MAC_PARTITION_MAGIC) + break; + blocks_in_map = get32_be(part->map_count); +#if 0 + printk("mac partition %d(%d) name '%s' type '%s' bim %d\n", + get32_be(part->start_block), + get32_be(part->block_count), + part->name, part->type, blocks_in_map); +#endif +#if 0 + /* for now, ignore non-unix partitions */ + if (strcmp(part->type, APPLE_AUX_TYPE) != 0) + continue; +#endif + add_partition(hd, current_minor, + fsec + get32_be(part->start_block) * (secsize / 512), + get32_be(part->block_count) * (secsize / 512)); +#if 0 + /* + * XXX check if this is the first bootable partition + * on the boot disk, and make it the root if so. + * We rely on arch/ppc/kernel/setup.c leaving boot_dev + * as 0 if an explicit root was given on the command line. + */ + if (get32_be(part->status) & MAC_STATUS_BOOTABLE + && kdev_t_to_nr(dev) == kdev_t_to_nr(boot_dev)) { + /* i wanna strcasecmp */ + for (i = 0; cpu[i] != 0 && part->processor[i] != 0; ++i) + if (tolower(part->processor[i]) != cpu[i]) + break; + if (cpu[i] == 0 && part->processor[i] == 0) { + ROOT_DEV = MKDEV(MAJOR(dev), current_minor); + boot_dev = MKDEV(0, 0); + printk(" (root)"); + } + } +#endif + ++current_minor; + } + brelse(bh); + printk("\n"); + return 1; +} + +#endif /* CONFIG_MAC_PARTITION */ + + static void check_partition(struct gendisk *hd, kdev_t dev) { static int first_time = 1; @@ -819,6 +983,10 @@ #endif #ifdef CONFIG_ATARI_PARTITION if(atari_partition(hd, dev, first_sector)) + return; +#endif +#ifdef CONFIG_MAC_PARTITION + if (mac_partition(hd, dev, first_sector)) return; #endif printk(" unknown partition table\n"); diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/Makefile linux-2.0.29/drivers/char/Makefile --- linux.vanilla/drivers/char/Makefile Sat Oct 5 14:24:30 1996 +++ linux-2.0.29/drivers/char/Makefile Tue Apr 15 11:53:01 1997 @@ -32,7 +32,15 @@ endif ifeq "$(ARCH)" "m68k" -L_OBJS += fbmem.o keyboard.o defkeymap.o +L_OBJS += fbmem.o defkeymap.o + +ifeq ($(CONFIG_MAC),y) +L_OBJS += macserial.o mackeymap.o keyb-mac.o +M = y +else +L_OBJS += keyboard.o +endif + endif ifeq ($(CONFIG_AMIGA_GSP),y) Binary files linux.vanilla/drivers/char/conmakehash and linux-2.0.29/drivers/char/conmakehash differ diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/keyb-mac.c linux-2.0.29/drivers/char/keyb-mac.c --- linux.vanilla/drivers/char/keyb-mac.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/drivers/char/keyb-mac.c Tue Apr 15 18:54:40 1997 @@ -0,0 +1,990 @@ +/* + * drivers/char/keyb-mac.c + * + * Keyboard driver for Power Macintosh computers. + * Extended for M68K Mac's by Alan Cox. + * + * Adapted from drivers/char/keyboard.c by Paul Mackerras + * (see that file for its authors and contributors). + * + * Copyright (C) 1996 Paul Mackerras. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "kbd_kern.h" +#include "diacr.h" +#include "vt_kern.h" + +#define KEYB_KEYREG 0 /* register # for key up/down data */ +#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ +#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN + +#ifndef KBD_DEFMODE +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#endif + +#ifndef KBD_DEFLEDS +#define KBD_DEFLEDS 0 +#endif + +#ifndef KBD_DEFLOCK +#define KBD_DEFLOCK 0 +#endif + +extern void poke_blanked_console(void); +extern void ctrl_alt_del(void); +extern void reset_vc(unsigned int new_console); +extern void scrollback(int); +extern void scrollfront(int); + +static void kbd_repeat(unsigned long); +static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; +static int last_keycode; + +/* + * global state includes the following, and various static variables + * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. + * (last_console is now a global variable) + */ + +/* shift state counters.. */ +static unsigned char k_down[NR_SHIFT] = {0, }; +/* keyboard key bitmap */ +#define BITS_PER_LONG (8*sizeof(unsigned long)) +static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; + +static int dead_key_next = 0; + +/* + * shift_state is global so the mouse driver can get at it. + */ +int shift_state = 0; +static int npadch = -1; /* -1 or number assembled on pad */ +static unsigned char diacr = 0; +static char rep = 0; /* flag telling character repeat */ +struct kbd_struct kbd_table[MAX_NR_CONSOLES]; +static struct tty_struct **ttytab; +static struct kbd_struct * kbd = kbd_table; +static struct tty_struct * tty = NULL; + +extern void compute_shiftstate(void); + +typedef void (*k_hand)(unsigned char value, char up_flag); +typedef void (k_handfn)(unsigned char value, char up_flag); + +static k_handfn + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore; + +static k_hand key_handler[16] = { + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, + do_ignore, do_ignore, do_ignore +}; + +typedef void (*void_fnp)(void); +typedef void (void_fn)(void); + +static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, + SAK, decr_console, incr_console, spawn_console, bare_num; + +static void_fnp spec_fn_table[] = { + do_null, enter, show_ptregs, show_mem, + show_state, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, + boot_it, caps_on, compose, SAK, + decr_console, incr_console, spawn_console, bare_num +}; + +/* maximum values each key_handler can handle */ +const int max_vals[] = { + 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, + 255, NR_ASCII - 1, NR_LOCK - 1, 255, + NR_LOCK - 1 +}; + +const int NR_TYPES = SIZE(max_vals); + +static void put_queue(int); +static unsigned char handle_diacr(unsigned char); +static void keyboard_input(unsigned char *, int, struct pt_regs *); +static void input_keycode(int, int); +static void leds_done(struct adb_request *); + +/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +static struct pt_regs * pt_regs; + +/* this map indicates which keys shouldn't autorepeat. */ +static unsigned char dont_repeat[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* + * Many other routines do put_queue, but I think either + * they produce ASCII, or they produce some user-assigned + * string, and in both cases we might assume that it is + * in utf-8 already. + */ +void to_utf8(ushort c) { + if (c < 0x80) + put_queue(c); /* 0******* */ + else if (c < 0x800) { + put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */ + put_queue(0x80 | (c & 0x3f)); + } else { + put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */ + put_queue(0x80 | ((c >> 6) & 0x3f)); + put_queue(0x80 | (c & 0x3f)); + } + /* UTF-8 is defined for words of up to 31 bits, + but we need only 16 bits here */ +} + +int setkeycode(unsigned int scancode, unsigned int keycode) +{ + return -EINVAL; +} + +int getkeycode(unsigned int scancode) +{ + return -EINVAL; +} + +static void keyboard_input(unsigned char *data, int nb, struct pt_regs *regs) +{ + /* first check this is from register 0 */ + if (nb != 5 || (data[2] & 3) != KEYB_KEYREG) + return; /* ignore it */ + + pt_regs = regs; + do_poke_blanked_console = 1; + mark_bh(CONSOLE_BH); + mark_bh(KEYBOARD_BH); + add_keyboard_randomness(data[3]); + + input_keycode(data[3], 0); + if (data[4] != 0xff && data[3] != 0x7f) + input_keycode(data[4], 0); +} + +static void +mouse_input(unsigned char *data, int nb, struct pt_regs *regs) +{ + int i; + + if (nb != 5 || (data[2] & 3) != MOUSE_DATAREG) { + printk("data from mouse:"); + for (i = 0; i < nb; ++i) + printk(" %x", data[i]); + printk("\n"); + return; + } + + tty = ttytab[fg_console]; + kbd = kbd_table + fg_console; + if (kbd->kbdmode == VC_RAW) { + put_queue(0x7e); + put_queue(data[3]); + put_queue(data[4]); + } +} + +static void +input_keycode(int keycode, int repeat) +{ + int up_flag, raw_mode; + + tty = ttytab[fg_console]; + kbd = kbd_table + fg_console; + if ((raw_mode = (kbd->kbdmode == VC_RAW))) { + put_queue(keycode); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + + up_flag = (keycode & 0200); + keycode &= 0x7f; + del_timer(&repeat_timer); + + /* + * Convert R-shift/control/option to L version. + */ + switch (keycode) { + case 0x7b: keycode = 0x38; break; /* R-shift */ + case 0x7c: keycode = 0x3a; break; /* R-option */ + case 0x7d: keycode = 0x36; break; /* R-control */ + } + + /* + * At this point the variable `keycode' contains the keycode. + * We keep track of the up/down status of the key, and + * return the keycode if in MEDIUMRAW mode. + */ + if (up_flag) { + rep = 0; + clear_bit(keycode, key_down); + } else { + if (!dont_repeat[keycode]) { + last_keycode = keycode; + repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2); + add_timer(&repeat_timer); + } + rep = set_bit(keycode, key_down); + } + + if (raw_mode) + return; + + if (kbd->kbdmode == VC_MEDIUMRAW) { + /* soon keycodes will require more than one byte */ + put_queue(keycode + up_flag); + return; + } + + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ + + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. + */ + if (!rep || + (vc_kbd_mode(kbd,VC_REPEAT) && tty && + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + + if (type >= 0xf0) { + type -= 0xf0; + if (type == KT_LETTER) { + type = KT_LATIN; + if (vc_kbd_led(kbd, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<slockstate = 0; + } else { + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag) + to_utf8(keysym); + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ +#if 1 /* how? two almost equivalent choices follow */ + compute_shiftstate(); +#else + keysym = U(plain_map[keycode]); + type = KTYP(keysym); + if (type == KT_SHIFT) + (*key_handler[type])(keysym & 0xff, up_flag); +#endif + } + } +} + +static void +kbd_repeat(unsigned long xxx) +{ + unsigned long flags; + + save_flags(flags); + cli(); + input_keycode(last_keycode, 1); + restore_flags(flags); +} + +static void put_queue(int ch) +{ + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + tty_schedule_flip(tty); + } +} + +static void puts_queue(char *cp) +{ + wake_up(&keypress_wait); + if (!tty) + return; + + while (*cp) { + tty_insert_flip_char(tty, *cp, 0); + cp++; + } + tty_schedule_flip(tty); +} + +static void applkey(int key, char mode) +{ + static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; + + buf[1] = (mode ? 'O' : '['); + buf[2] = key; + puts_queue(buf); +} + +static void enter(void) +{ + put_queue(13); + if (vc_kbd_mode(kbd,VC_CRLF)) + put_queue(10); +} + +static void caps_toggle(void) +{ + if (rep) + return; + chg_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void caps_on(void) +{ + if (rep) + return; + set_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void show_ptregs(void) +{ + if (pt_regs) + show_regs(pt_regs); +} + +static void hold(void) +{ + if (rep || !tty) + return; + + /* + * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); + * these routines are also activated by ^S/^Q. + * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) + */ + if (tty->stopped) + start_tty(tty); + else + stop_tty(tty); +} + +static void num(void) +{ + if (vc_kbd_mode(kbd,VC_APPLIC)) + applkey('P', 1); + else + bare_num(); +} + +/* + * Bind this to Shift-NumLock if you work in application keypad mode + * but want to be able to change the NumLock flag. + * Bind this to NumLock if you prefer that the NumLock key always + * changes the NumLock flag. + */ +static void bare_num(void) +{ + if (!rep) + chg_vc_kbd_led(kbd,VC_NUMLOCK); +} + +static void lastcons(void) +{ + /* switch to the last used console, ChN */ + set_console(last_console); +} + +static void decr_console(void) +{ + int i; + + for (i = fg_console-1; i != fg_console; i--) { + if (i == -1) + i = MAX_NR_CONSOLES-1; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void incr_console(void) +{ + int i; + + for (i = fg_console+1; i != fg_console; i++) { + if (i == MAX_NR_CONSOLES) + i = 0; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void send_intr(void) +{ + if (!tty) + return; + tty_insert_flip_char(tty, 0, TTY_BREAK); + tty_schedule_flip(tty); +} + +static void scroll_forw(void) +{ + scrollfront(0); +} + +static void scroll_back(void) +{ + scrollback(0); +} + +static void boot_it(void) +{ + ctrl_alt_del(); +} + +static void compose(void) +{ + dead_key_next = 1; +} + +int spawnpid, spawnsig; + +static void spawn_console(void) +{ + if (spawnpid) + if(kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; +} + +static void SAK(void) +{ + do_SAK(tty); +#if 0 + /* + * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and + * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK + * handling. + * + * We should do this some day --- the whole point of a secure + * attention key is that it should be guaranteed to always + * work. + */ + reset_vc(fg_console); + do_unblank_screen(); /* not in interrupt routine? */ +#endif +} + +static void do_ignore(unsigned char value, char up_flag) +{ +} + +static void do_null() +{ + compute_shiftstate(); +} + +static void do_spec(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value >= SIZE(spec_fn_table)) + return; + spec_fn_table[value](); +} + +static void do_lowercase(unsigned char value, char up_flag) +{ + printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n"); +} + +static void do_self(unsigned char value, char up_flag) +{ + if (up_flag) + return; /* no action, if this is a key release */ + + if (diacr) + value = handle_diacr(value); + + if (dead_key_next) { + dead_key_next = 0; + diacr = value; + return; + } + + put_queue(value); +} + +#define A_GRAVE '`' +#define A_ACUTE '\'' +#define A_CFLEX '^' +#define A_TILDE '~' +#define A_DIAER '"' +static unsigned char ret_diacr[] = + {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER }; + +/* If a dead key pressed twice, output a character corresponding to it, */ +/* otherwise just remember the dead key. */ + +static void do_dead(unsigned char value, char up_flag) +{ + if (up_flag) + return; + + value = ret_diacr[value]; + if (diacr == value) { /* pressed twice */ + diacr = 0; + put_queue(value); + return; + } + diacr = value; +} + + +/* If space is pressed, return the character corresponding the pending */ +/* dead key, otherwise try to combine the two. */ + +unsigned char handle_diacr(unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + if (ch == ' ') + return d; + + for (i = 0; i < accent_table_size; i++) { + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; + } + + put_queue(d); + return ch; +} + +static void do_cons(unsigned char value, char up_flag) +{ + if (up_flag) + return; + set_console(value); +} + +static void do_fn(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value < SIZE(func_table)) { + if (func_table[value]) + puts_queue(func_table[value]); + } else + printk(KERN_ERR "do_fn called with value=%d\n", value); +} + +static void do_pad(unsigned char value, char up_flag) +{ + static const char *pad_chars = "0123456789+-*/\015,.?"; + static const char *app_map = "pqrstuvwxylSRQMnn?"; + + if (up_flag) + return; /* no action, if this is a key release */ + + /* kludge... shift forces cursor/number keys */ + if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { + applkey(app_map[value], 1); + return; + } + + if (!vc_kbd_led(kbd,VC_NUMLOCK)) + switch (value) { + case KVAL(K_PCOMMA): + case KVAL(K_PDOT): + do_fn(KVAL(K_REMOVE), 0); + return; + case KVAL(K_P0): + do_fn(KVAL(K_INSERT), 0); + return; + case KVAL(K_P1): + do_fn(KVAL(K_SELECT), 0); + return; + case KVAL(K_P2): + do_cur(KVAL(K_DOWN), 0); + return; + case KVAL(K_P3): + do_fn(KVAL(K_PGDN), 0); + return; + case KVAL(K_P4): + do_cur(KVAL(K_LEFT), 0); + return; + case KVAL(K_P6): + do_cur(KVAL(K_RIGHT), 0); + return; + case KVAL(K_P7): + do_fn(KVAL(K_FIND), 0); + return; + case KVAL(K_P8): + do_cur(KVAL(K_UP), 0); + return; + case KVAL(K_P9): + do_fn(KVAL(K_PGUP), 0); + return; + case KVAL(K_P5): + applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + return; + } + + put_queue(pad_chars[value]); + if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) + put_queue(10); +} + +static void do_cur(unsigned char value, char up_flag) +{ + static const char *cur_chars = "BDCA"; + if (up_flag) + return; + + applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); +} + +static void do_shift(unsigned char value, char up_flag) +{ + int old_state = shift_state; + + if (rep) + return; + + /* Mimic typewriter: + a CapsShift key acts like Shift but undoes CapsLock */ + if (value == KVAL(K_CAPSSHIFT)) { + value = KVAL(K_SHIFT); + if (!up_flag) + clr_vc_kbd_led(kbd, VC_CAPSLOCK); + } + + if (up_flag) { + /* handle the case that two shift or control + keys are depressed simultaneously */ + if (k_down[value]) + k_down[value]--; + } else + k_down[value]++; + + if (k_down[value]) + shift_state |= (1 << value); + else + shift_state &= ~ (1 << value); + + /* kludge */ + if (up_flag && shift_state != old_state && npadch != -1) { + if (kbd->kbdmode == VC_UNICODE) + to_utf8(npadch & 0xffff); + else + put_queue(npadch & 0xff); + npadch = -1; + } +} + +/* called after returning from RAW mode or when changing consoles - + recompute k_down[] and shift_state from key_down[] */ +/* maybe called when keymap is undefined, so that shiftkey release is seen */ +void compute_shiftstate(void) +{ + int i, j, k, sym, val; + + shift_state = 0; + for (i = 0; i < SIZE(k_down); i++) + k_down[i] = 0; + + for (i = 0; i < SIZE(key_down); i++) + if (key_down[i]) { /* skip this word if not a single bit on */ + k = i*BITS_PER_LONG; + for (j = 0; jledmode = LED_SHOW_IOCTL; + } else + kbd->ledmode = LED_SHOW_FLAGS; + set_leds(); +} + +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; + +void register_leds(int console, unsigned int led, + unsigned int *addr, unsigned int mask) { + struct kbd_struct *kbd = kbd_table + console; + if (led < 3) { + ledptrs[led].addr = addr; + ledptrs[led].mask = mask; + ledptrs[led].valid = 1; + kbd->ledmode = LED_SHOW_MEM; + } else + kbd->ledmode = LED_SHOW_FLAGS; +} + +/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ +static unsigned char mac_ledmap[8] = { + 0, /* none */ + 4, /* scroll lock */ + 1, /* num lock */ + 5, /* scroll + num lock */ + 2, /* caps lock */ + 6, /* caps + scroll lock */ + 3, /* caps + num lock */ + 7, /* caps + num + scroll lock */ +}; + +static inline unsigned char getleds(void){ + struct kbd_struct *kbd = kbd_table + fg_console; + unsigned char leds; + + if (kbd->ledmode == LED_SHOW_IOCTL) + return ledioctl; + leds = mac_ledmap[kbd->ledflagstate]; + if (kbd->ledmode == LED_SHOW_MEM) { + if (ledptrs[0].valid) { + if (*ledptrs[0].addr & ledptrs[0].mask) + leds |= 1; + else + leds &= ~1; + } + if (ledptrs[1].valid) { + if (*ledptrs[1].addr & ledptrs[1].mask) + leds |= 2; + else + leds &= ~2; + } + if (ledptrs[2].valid) { + if (*ledptrs[2].addr & ledptrs[2].mask) + leds |= 4; + else + leds &= ~4; + } + } + return leds; +} + +/* + * This routine is the bottom half of the keyboard interrupt + * routine, and runs with all interrupts enabled. It does + * console changing, led setting and copy_to_cooked, which can + * take a reasonably long time. + * + * Aside from timing (which isn't really that important for + * keyboard interrupts as they happen often), using the software + * interrupt routines for this thing allows us to easily mask + * this when we don't want any of the above to happen. Not yet + * used, but this allows for easy and efficient race-condition + * prevention later on. + */ +static struct adb_request led_request; + +static void kbd_bh(void) +{ + unsigned char leds = getleds(); + + if (leds != ledstate && led_request.got_reply) { + ledstate = leds; + adb_request(&led_request, leds_done, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), + ~leds >> 8, ~leds); + } +} + +static void leds_done(struct adb_request *req) +{ + mark_bh(KEYBOARD_BH); +} + +int kbd_init(void) +{ + int i; + struct kbd_struct kbd0; + extern struct tty_driver console_driver; + struct adb_request req; + + adb_bus_init(); + + kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; + kbd0.ledmode = LED_SHOW_FLAGS; + kbd0.lockstate = KBD_DEFLOCK; + kbd0.slockstate = 0; + kbd0.modeflags = KBD_DEFMODE; + kbd0.kbdmode = VC_XLATE; + + for (i = 0 ; i < MAX_NR_CONSOLES ; i++) + kbd_table[i] = kbd0; + + ttytab = console_driver.table; + + init_bh(KEYBOARD_BH, kbd_bh); + mark_bh(KEYBOARD_BH); + + adb_register(ADB_KEYBOARD, keyboard_input); + adb_register(ADB_MOUSE, mouse_input); + + /* turn on ADB auto-polling in the CUDA */ + + /* + * Older boxes don't support CUDA_* targets and CUDA commands + * instead we emulate them in the adb_request hook to make + * the code interfaces saner. + * + * Note XXX: the Linux PMac and this code both assume the + * devices are at their primary ids and do not do device + * assignment. This isn't ideal. We should fix it to follow + * the reassignment specs. + */ + +#if 0 + adb_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); + while (!req.got_reply) + adb_poll(); +#endif + printk("Configuring keyboard\n"); + /* turn off all leds */ + adb_request(&req, NULL, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff); + printk("SKIP\n"); + return 0; + printk("Wait keyboard reply\n"); + while (!req.got_reply) + adb_poll(); + + printk("Configuring coding mode\n"); + /* get the keyboard to send separate codes for + left and right shift, control, option keys. */ + adb_request(&req, NULL, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); + while (!req.got_reply) + adb_poll(); + + led_request.got_reply = 1; + + printk("Keyboard init done\n"); + + return 0; +} + diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/mackeymap.c linux-2.0.29/drivers/char/mackeymap.c --- linux.vanilla/drivers/char/mackeymap.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/drivers/char/mackeymap.c Thu Apr 10 12:43:54 1997 @@ -0,0 +1,262 @@ +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable defkeymap.map > defkeymap.c */ + +#include +#include +#include + +u_short plain_map[NR_KEYS] = { + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, + 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, + 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, + 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, + 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, + 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short shift_map[NR_KEYS] = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, + 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, + 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, + 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, + 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, + 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, + 0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short altgr_map[NR_KEYS] = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, + 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, + 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, + 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, + 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, + 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, + 0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, + 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, + 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, + 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, + 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short shift_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, + 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, + 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, + 0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, +}; + +u_short alt_map[NR_KEYS] = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, + 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, + 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, + 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, + 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, + 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, + 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short ctrl_alt_map[NR_KEYS] = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, + 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, + 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, + 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, 0, 0, + alt_map, 0, 0, 0, + ctrl_alt_map, 0 +}; + +unsigned int keymap_count = 7; + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + '\033', '[', 'M', 0, + '\033', '[', 'P', 0, +}; + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + func_buf + 145, + 0, + 0, + func_buf + 149, + 0, +}; + +struct kbdiacr accent_table[MAX_DIACR] = { + {'`', 'A', '\300'}, {'`', 'a', '\340'}, + {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, + {'^', 'A', '\302'}, {'^', 'a', '\342'}, + {'~', 'A', '\303'}, {'~', 'a', '\343'}, + {'"', 'A', '\304'}, {'"', 'a', '\344'}, + {'O', 'A', '\305'}, {'o', 'a', '\345'}, + {'0', 'A', '\305'}, {'0', 'a', '\345'}, + {'A', 'A', '\305'}, {'a', 'a', '\345'}, + {'A', 'E', '\306'}, {'a', 'e', '\346'}, + {',', 'C', '\307'}, {',', 'c', '\347'}, + {'`', 'E', '\310'}, {'`', 'e', '\350'}, + {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, + {'^', 'E', '\312'}, {'^', 'e', '\352'}, + {'"', 'E', '\313'}, {'"', 'e', '\353'}, + {'`', 'I', '\314'}, {'`', 'i', '\354'}, + {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, + {'^', 'I', '\316'}, {'^', 'i', '\356'}, + {'"', 'I', '\317'}, {'"', 'i', '\357'}, + {'-', 'D', '\320'}, {'-', 'd', '\360'}, + {'~', 'N', '\321'}, {'~', 'n', '\361'}, + {'`', 'O', '\322'}, {'`', 'o', '\362'}, + {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, + {'^', 'O', '\324'}, {'^', 'o', '\364'}, + {'~', 'O', '\325'}, {'~', 'o', '\365'}, + {'"', 'O', '\326'}, {'"', 'o', '\366'}, + {'/', 'O', '\330'}, {'/', 'o', '\370'}, + {'`', 'U', '\331'}, {'`', 'u', '\371'}, + {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, + {'^', 'U', '\333'}, {'^', 'u', '\373'}, + {'"', 'U', '\334'}, {'"', 'u', '\374'}, + {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, + {'T', 'H', '\336'}, {'t', 'h', '\376'}, + {'s', 's', '\337'}, {'"', 'y', '\377'}, + {'s', 'z', '\337'}, {'i', 'j', '\377'}, +}; + +unsigned int accent_table_size = 68; diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/mackeymap.map linux-2.0.29/drivers/char/mackeymap.map --- linux.vanilla/drivers/char/mackeymap.map Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/drivers/char/mackeymap.map Thu Apr 10 12:43:55 1997 @@ -0,0 +1,345 @@ +# Kernel keymap for Macintoshes. This uses 7 modifier combinations. +keymaps 0-2,4-5,8,12 +# We use the Command (pretzel) key as Alt, and the Option key as AltGr. +# +keycode 0x00 = a + altgr keycode 0x00 = Hex_A +keycode 0x01 = s +keycode 0x02 = d + altgr keycode 0x02 = Hex_D +keycode 0x03 = f + altgr keycode 0x03 = Hex_F +keycode 0x04 = h +keycode 0x05 = g +keycode 0x06 = z +keycode 0x07 = x +keycode 0x08 = c + altgr keycode 0x08 = Hex_C +keycode 0x09 = v +keycode 0x0a = +keycode 0x0b = b + altgr keycode 0x0b = Hex_B +keycode 0x0c = q +keycode 0x0d = w +keycode 0x0e = e + altgr keycode 0x0e = Hex_E +keycode 0x0f = r +keycode 0x10 = y +keycode 0x11 = t +keycode 0x12 = one exclam + alt keycode 0x12 = Meta_one +keycode 0x13 = two at at + control keycode 0x13 = nul + shift control keycode 0x13 = nul + alt keycode 0x13 = Meta_two +keycode 0x14 = three numbersign + control keycode 0x14 = Escape + alt keycode 0x14 = Meta_three +keycode 0x15 = four dollar dollar + control keycode 0x15 = Control_backslash + alt keycode 0x15 = Meta_four +keycode 0x16 = six asciicircum + control keycode 0x16 = Control_asciicircum + alt keycode 0x16 = Meta_six +keycode 0x17 = five percent + control keycode 0x17 = Control_bracketright + alt keycode 0x17 = Meta_five +keycode 0x18 = equal plus + alt keycode 0x18 = Meta_equal +keycode 0x19 = nine parenleft bracketright + alt keycode 0x19 = Meta_nine +keycode 0x1a = seven ampersand braceleft + control keycode 0x1a = Control_underscore + alt keycode 0x1a = Meta_seven +keycode 0x1b = minus underscore backslash + control keycode 0x1b = Control_underscore + shift control keycode 0x1b = Control_underscore + alt keycode 0x1b = Meta_minus +keycode 0x1c = eight asterisk bracketleft + control keycode 0x1c = Delete + alt keycode 0x1c = Meta_eight +keycode 0x1d = zero parenright braceright + alt keycode 0x1d = Meta_zero +keycode 0x1e = bracketright braceright asciitilde + control keycode 0x1e = Control_bracketright + alt keycode 0x1e = Meta_bracketright +keycode 0x1f = o +keycode 0x20 = u +keycode 0x21 = bracketleft braceleft + control keycode 0x21 = Escape + alt keycode 0x21 = Meta_bracketleft +keycode 0x22 = i +keycode 0x23 = p +keycode 0x24 = Return + alt keycode 0x24 = Meta_Control_m +keycode 0x25 = l +keycode 0x26 = j +keycode 0x27 = apostrophe quotedbl + control keycode 0x27 = Control_g + alt keycode 0x27 = Meta_apostrophe +keycode 0x28 = k +keycode 0x29 = semicolon colon + alt keycode 0x29 = Meta_semicolon +keycode 0x2a = backslash bar + control keycode 0x2a = Control_backslash + alt keycode 0x2a = Meta_backslash +keycode 0x2b = comma less + alt keycode 0x2b = Meta_comma +keycode 0x2c = slash question + control keycode 0x2c = Delete + alt keycode 0x2c = Meta_slash +keycode 0x2d = n +keycode 0x2e = m +keycode 0x2f = period greater + control keycode 0x2f = Compose + alt keycode 0x2f = Meta_period +keycode 0x30 = Tab Tab + alt keycode 0x30 = Meta_Tab +keycode 0x31 = space space + control keycode 0x31 = nul + alt keycode 0x31 = Meta_space +keycode 0x32 = grave asciitilde + control keycode 0x32 = nul + alt keycode 0x32 = Meta_grave +keycode 0x33 = Delete Delete + control keycode 0x33 = BackSpace + alt keycode 0x33 = Meta_Delete +keycode 0x34 = +keycode 0x35 = Escape Escape + alt keycode 0x35 = Meta_Escape +keycode 0x36 = Control +keycode 0x37 = Alt +keycode 0x38 = Shift +keycode 0x39 = Caps_Lock +keycode 0x3a = AltGr +keycode 0x3b = Left + alt keycode 0x3b = Decr_Console +keycode 0x3c = Right + alt keycode 0x3c = Incr_Console +keycode 0x3d = Down +keycode 0x3e = Up +keycode 0x3f = +keycode 0x40 = +keycode 0x41 = KP_Period +keycode 0x42 = +keycode 0x43 = KP_Multiply +keycode 0x44 = +keycode 0x45 = KP_Add +keycode 0x46 = +keycode 0x47 = Num_Lock +# shift keycode 0x47 = Bare_Num_Lock +keycode 0x48 = +keycode 0x49 = +keycode 0x4a = +keycode 0x4b = KP_Divide +keycode 0x4c = KP_Enter +keycode 0x4d = +keycode 0x4e = KP_Subtract +keycode 0x4f = +keycode 0x50 = +keycode 0x51 = +#keycode 0x51 = KP_Equals +keycode 0x52 = KP_0 + alt keycode 0x52 = Ascii_0 + altgr keycode 0x52 = Hex_0 +keycode 0x53 = KP_1 + alt keycode 0x53 = Ascii_1 + altgr keycode 0x53 = Hex_1 +keycode 0x54 = KP_2 + alt keycode 0x54 = Ascii_2 + altgr keycode 0x54 = Hex_2 +keycode 0x55 = KP_3 + alt keycode 0x55 = Ascii_3 + altgr keycode 0x55 = Hex_3 +keycode 0x56 = KP_4 + alt keycode 0x56 = Ascii_4 + altgr keycode 0x56 = Hex_4 +keycode 0x57 = KP_5 + alt keycode 0x57 = Ascii_5 + altgr keycode 0x57 = Hex_5 +keycode 0x58 = KP_6 + alt keycode 0x58 = Ascii_6 + altgr keycode 0x58 = Hex_6 +keycode 0x59 = KP_7 + alt keycode 0x59 = Ascii_7 + altgr keycode 0x59 = Hex_7 +keycode 0x5a = +keycode 0x5b = KP_8 + alt keycode 0x5b = Ascii_8 + altgr keycode 0x5b = Hex_8 +keycode 0x5c = KP_9 + alt keycode 0x5c = Ascii_9 + altgr keycode 0x5c = Hex_9 +keycode 0x5d = +keycode 0x5e = +keycode 0x5f = +keycode 0x60 = F5 F15 Console_17 + control keycode 0x60 = F5 + alt keycode 0x60 = Console_5 + control alt keycode 0x60 = Console_5 +keycode 0x61 = F6 F16 Console_18 + control keycode 0x61 = F6 + alt keycode 0x61 = Console_6 + control alt keycode 0x61 = Console_6 +keycode 0x62 = F7 F17 Console_19 + control keycode 0x62 = F7 + alt keycode 0x62 = Console_7 + control alt keycode 0x62 = Console_7 +keycode 0x63 = F3 F13 Console_15 + control keycode 0x63 = F3 + alt keycode 0x63 = Console_3 + control alt keycode 0x63 = Console_3 +keycode 0x64 = F8 F18 Console_20 + control keycode 0x64 = F8 + alt keycode 0x64 = Console_8 + control alt keycode 0x64 = Console_8 +keycode 0x65 = F9 F19 Console_21 + control keycode 0x65 = F9 + alt keycode 0x65 = Console_9 + control alt keycode 0x65 = Console_9 +keycode 0x66 = +keycode 0x67 = F11 F11 Console_23 + control keycode 0x67 = F11 + alt keycode 0x67 = Console_11 + control alt keycode 0x67 = Console_11 +keycode 0x68 = +keycode 0x69 = F13 +keycode 0x6a = +keycode 0x6b = Scroll_Lock Show_Memory Show_Registers + control keycode 0x6b = Show_State + alt keycode 0x6b = Scroll_Lock +keycode 0x6c = +keycode 0x6d = F10 F20 Console_22 + control keycode 0x6d = F10 + alt keycode 0x6d = Console_10 + control alt keycode 0x6d = Console_10 +keycode 0x6e = +keycode 0x6f = F12 F12 Console_24 + control keycode 0x6f = F12 + alt keycode 0x6f = Console_12 + control alt keycode 0x6f = Console_12 +keycode 0x70 = +keycode 0x71 = Pause +keycode 0x72 = Insert +keycode 0x73 = Home +keycode 0x74 = Prior + shift keycode 0x74 = Scroll_Backward +keycode 0x75 = Remove +keycode 0x76 = F4 F14 Console_16 + control keycode 0x76 = F4 + alt keycode 0x76 = Console_4 + control alt keycode 0x76 = Console_4 +keycode 0x77 = End +keycode 0x78 = F2 F12 Console_14 + control keycode 0x78 = F2 + alt keycode 0x78 = Console_2 + control alt keycode 0x78 = Console_2 +keycode 0x79 = Next + shift keycode 0x79 = Scroll_Forward +keycode 0x7a = F1 F11 Console_13 + control keycode 0x7a = F1 + alt keycode 0x7a = Console_1 + control alt keycode 0x7a = Console_1 +keycode 0x7b = Shift +keycode 0x7c = AltGr +keycode 0x7d = Control +keycode 0x7e = +keycode 0x7f = +#keycode 0x7f = Power + control shift keycode 0x7f = Boot +string F1 = "\033[[A" +string F2 = "\033[[B" +string F3 = "\033[[C" +string F4 = "\033[[D" +string F5 = "\033[[E" +string F6 = "\033[17~" +string F7 = "\033[18~" +string F8 = "\033[19~" +string F9 = "\033[20~" +string F10 = "\033[21~" +string F11 = "\033[23~" +string F12 = "\033[24~" +string F13 = "\033[25~" +string F14 = "\033[26~" +string F15 = "\033[28~" +string F16 = "\033[29~" +string F17 = "\033[31~" +string F18 = "\033[32~" +string F19 = "\033[33~" +string F20 = "\033[34~" +string Find = "\033[1~" +string Insert = "\033[2~" +string Remove = "\033[3~" +string Select = "\033[4~" +string Prior = "\033[5~" +string Next = "\033[6~" +string Macro = "\033[M" +string Pause = "\033[P" +compose '`' 'A' to 'À' +compose '`' 'a' to 'à' +compose '\'' 'A' to 'Á' +compose '\'' 'a' to 'á' +compose '^' 'A' to 'Â' +compose '^' 'a' to 'â' +compose '~' 'A' to 'Ã' +compose '~' 'a' to 'ã' +compose '"' 'A' to 'Ä' +compose '"' 'a' to 'ä' +compose 'O' 'A' to 'Å' +compose 'o' 'a' to 'å' +compose '0' 'A' to 'Å' +compose '0' 'a' to 'å' +compose 'A' 'A' to 'Å' +compose 'a' 'a' to 'å' +compose 'A' 'E' to 'Æ' +compose 'a' 'e' to 'æ' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '`' 'E' to 'È' +compose '`' 'e' to 'è' +compose '\'' 'E' to 'É' +compose '\'' 'e' to 'é' +compose '^' 'E' to 'Ê' +compose '^' 'e' to 'ê' +compose '"' 'E' to 'Ë' +compose '"' 'e' to 'ë' +compose '`' 'I' to 'Ì' +compose '`' 'i' to 'ì' +compose '\'' 'I' to 'Í' +compose '\'' 'i' to 'í' +compose '^' 'I' to 'Î' +compose '^' 'i' to 'î' +compose '"' 'I' to 'Ï' +compose '"' 'i' to 'ï' +compose '-' 'D' to 'Ð' +compose '-' 'd' to 'ð' +compose '~' 'N' to 'Ñ' +compose '~' 'n' to 'ñ' +compose '`' 'O' to 'Ò' +compose '`' 'o' to 'ò' +compose '\'' 'O' to 'Ó' +compose '\'' 'o' to 'ó' +compose '^' 'O' to 'Ô' +compose '^' 'o' to 'ô' +compose '~' 'O' to 'Õ' +compose '~' 'o' to 'õ' +compose '"' 'O' to 'Ö' +compose '"' 'o' to 'ö' +compose '/' 'O' to 'Ø' +compose '/' 'o' to 'ø' +compose '`' 'U' to 'Ù' +compose '`' 'u' to 'ù' +compose '\'' 'U' to 'Ú' +compose '\'' 'u' to 'ú' +compose '^' 'U' to 'Û' +compose '^' 'u' to 'û' +compose '"' 'U' to 'Ü' +compose '"' 'u' to 'ü' +compose '\'' 'Y' to 'Ý' +compose '\'' 'y' to 'ý' +compose 'T' 'H' to 'Þ' +compose 't' 'h' to 'þ' +compose 's' 's' to 'ß' +compose '"' 'y' to 'ÿ' +compose 's' 'z' to 'ß' +compose 'i' 'j' to 'ÿ' diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/macserial.c linux-2.0.29/drivers/char/macserial.c --- linux.vanilla/drivers/char/macserial.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/drivers/char/macserial.c Tue Apr 15 10:55:02 1997 @@ -0,0 +1,1988 @@ +/* + * macserial.c: Serial port driver for Power Macintoshes. + * Extended for the 68K mac by Alan Cox. + * + * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras. + * + * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifndef CONFIG_MAC +#include +#endif +#include +#include +#include + +#include "macserial.h" + +/* + * It would be nice to dynamically allocate everything that + * depends on NUM_SERIAL, so we could support any number of + * Z8530s, but for now... + */ +#define NUM_SERIAL 2 /* Max number of ZS chips supported */ +#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */ + +#ifdef CONFIG_MAC +/* + * All the Macintosh 68K boxes that have an MMU also have hardware + * recovery delays. + */ +#define RECOVERY_DELAY +#else +/* On PowerMacs, the hardware takes care of the SCC recovery time, + but we need the eieio to make sure that the accesses occur + in the order we want. */ +#define RECOVERY_DELAY eieio() +#endif + +struct mac_zschannel *zs_kgdbchan; +struct mac_zschannel zs_channels[NUM_CHANNELS]; + +struct mac_serial zs_soft[NUM_CHANNELS]; +int zs_channels_found; +struct mac_serial *zs_chain; /* list of all channels */ + +struct tty_struct zs_ttys[NUM_CHANNELS]; +/** struct tty_struct *zs_constty; **/ + +/* Console hooks... */ +static int zs_cons_chanout = 0; +static int zs_cons_chanin = 0; +struct mac_serial *zs_consinfo = 0; +struct mac_zschannel *zs_conschan; + +static unsigned char kgdb_regs[16] = { + 0, 0, 0, /* write 0, 1, 2 */ + (Rx8 | RxENABLE), /* write 3 */ + (X16CLK | SB1 | PAR_EVEN), /* write 4 */ + (Tx8 | TxENAB), /* write 5 */ + 0, 0, 0, /* write 6, 7, 8 */ + (NV), /* write 9 */ + (NRZ), /* write 10 */ + (TCBR | RCBR), /* write 11 */ + 1, 0, /* 38400 baud divisor, write 12 + 13 */ + (BRENABL), /* write 14 */ + (DCDIE) /* write 15 */ +}; + +#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */ + +DECLARE_TASK_QUEUE(tq_serial); + +struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* Debugging... DEBUG_INTR is bad to use when one of the zs + * lines is your console ;( + */ +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW + +#define RS_STROBE_TIME 10 +#define RS_ISR_PASS_LIMIT 256 + +#define _INLINE_ inline + +static void probe_sccs(void); +static void change_speed(struct mac_serial *info); + +static struct tty_struct *serial_table[NUM_CHANNELS]; +static struct termios *serial_termios[NUM_CHANNELS]; +static struct termios *serial_termios_locked[NUM_CHANNELS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the memcpy_fromfs blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char tmp_buf[4096]; /* This is cheating */ +static struct semaphore tmp_buf_sem = MUTEX; + +static inline int serial_paranoia_check(struct mac_serial *info, + dev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%d, %d) in %s\n"; + static const char *badinfo = + "Warning: null mac_serial for (%d, %d) in %s\n"; + + if (!info) { + printk(badinfo, MAJOR(device), MINOR(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, MAJOR(device), MINOR(device), routine); + return 1; + } +#endif + return 0; +} + +/* + * This is used to figure out the divisor speeds and the timeouts + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 0 }; + +/* + * Reading and writing Z8530 registers. + */ +static inline unsigned char read_zsreg(struct mac_zschannel *channel, + unsigned char reg) +{ + unsigned char retval; + + if (reg != 0) { + *channel->control = reg; + RECOVERY_DELAY; + } + retval = *channel->control; + RECOVERY_DELAY; + return retval; +} + +static inline void write_zsreg(struct mac_zschannel *channel, + unsigned char reg, unsigned char value) +{ + if (reg != 0) { + *channel->control = reg; + RECOVERY_DELAY; + } + *channel->control = value; + RECOVERY_DELAY; + return; +} + +static inline unsigned char read_zsdata(struct mac_zschannel *channel) +{ + unsigned char retval; + + retval = *channel->data; + RECOVERY_DELAY; + return retval; +} + +static inline void write_zsdata(struct mac_zschannel *channel, + unsigned char value) +{ + *channel->data = value; + RECOVERY_DELAY; + return; +} + +static inline void load_zsregs(struct mac_zschannel *channel, + unsigned char *regs) +{ + ZS_CLEARERR(channel); + ZS_CLEARFIFO(channel); + /* Load 'em up */ + write_zsreg(channel, R4, regs[R4]); + write_zsreg(channel, R10, regs[R10]); + write_zsreg(channel, R3, regs[R3] & ~RxENABLE); + write_zsreg(channel, R5, regs[R5] & ~TxENAB); + write_zsreg(channel, R1, regs[R1]); + write_zsreg(channel, R9, regs[R9]); + write_zsreg(channel, R11, regs[R11]); + write_zsreg(channel, R12, regs[R12]); + write_zsreg(channel, R13, regs[R13]); + write_zsreg(channel, R14, regs[R14]); + write_zsreg(channel, R15, regs[R15]); + write_zsreg(channel, R3, regs[R3]); + write_zsreg(channel, R5, regs[R5]); + return; +} + +/* Sets or clears DTR/RTS on the requested line */ +static inline void zs_rtsdtr(struct mac_serial *ss, int set) +{ + if (set) + ss->curregs[5] |= (RTS | DTR); + else + ss->curregs[5] &= ~(RTS | DTR); + write_zsreg(ss->zs_channel, 5, ss->curregs[5]); + return; +} + +static inline void kgdb_chaninit(struct mac_serial *ss, int intson, int bps) +{ + int brg; + + if (intson) { + kgdb_regs[R1] = INT_ALL_Rx; + kgdb_regs[R9] |= MIE; + } else { + kgdb_regs[R1] = 0; + kgdb_regs[R9] &= ~MIE; + } + brg = BPS_TO_BRG(bps, ZS_CLOCK/16); + kgdb_regs[R12] = brg; + kgdb_regs[R13] = brg >> 8; + load_zsregs(ss->zs_channel, kgdb_regs); +} + +/* Utility routines for the Zilog */ +static inline int get_zsbaud(struct mac_serial *ss) +{ + struct mac_zschannel *channel = ss->zs_channel; + int brg; + + /* The baud rate is split up between two 8-bit registers in + * what is termed 'BRG time constant' format in my docs for + * the chip, it is a function of the clk rate the chip is + * receiving which happens to be constant. + */ + brg = (read_zsreg(channel, 13) << 8); + brg |= read_zsreg(channel, 12); + return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor))); +} + +/* On receive, this clears errors and the receiver interrupts */ +static inline void rs_recv_clear(struct mac_zschannel *zsc) +{ + write_zsreg(zsc, 0, ERR_RES); + write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */ +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(struct mac_serial *info, + int event) +{ + info->event |= 1 << event; + queue_task_irq_off(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +extern void breakpoint(void); /* For the KGDB frame character */ + +static _INLINE_ void receive_chars(struct mac_serial *info, + struct pt_regs *regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch, stat, flag; + + while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) { + + stat = read_zsreg(info->zs_channel, R1); + ch = read_zsdata(info->zs_channel); + +#if 0 /* KGDB not yet supported */ + /* Look for kgdb 'stop' character, consult the gdb documentation + * for remote target debugging and arch/sparc/kernel/sparc-stub.c + * to see how all this works. + */ + if ((info->kgdb_channel) && (ch =='\003')) { + breakpoint(); + continue; + } +#endif + + if (!tty) + continue; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + tty->flip.count++; + if (stat & Rx_OVR) { + flag = TTY_OVERRUN; + /* reset the error indication */ + write_zsreg(info->zs_channel, 0, ERR_RES); + } else if (stat & FRM_ERR) { + /* this error is not sticky */ + flag = TTY_FRAME; + } else if (stat & PAR_ERR) { + flag = TTY_PARITY; + /* reset the error indication */ + write_zsreg(info->zs_channel, 0, ERR_RES); + } else + flag = 0; + *tty->flip.flag_buf_ptr++ = flag; + *tty->flip.char_buf_ptr++ = ch; + + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + } +#if 0 +clear_and_exit: + rs_recv_clear(info->zs_channel); +#endif +} + +static void transmit_chars(struct mac_serial *info) +{ + if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) + return; + info->tx_active = 0; + + if (info->x_char) { + /* Send next char */ + write_zsdata(info->zs_channel, info->x_char); + info->x_char = 0; + info->tx_active = 1; + return; + } + + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) { + write_zsreg(info->zs_channel, 0, RES_Tx_P); + return; + } + + /* Send char */ + write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + info->tx_active = 1; + + if (info->xmit_cnt < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); +} + +static _INLINE_ void status_handle(struct mac_serial *info) +{ + unsigned char status; + + /* Get status from Read Register 0 */ + status = read_zsreg(info->zs_channel, 0); + + /* Check for DCD transitions */ + if (((status ^ info->read_reg_zero) & DCD) != 0 + && info->tty && C_CLOCAL(info->tty)) { + if (status & DCD) { + wake_up_interruptible(&info->open_wait); + } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) { + queue_task_irq_off(&info->tqueue_hangup, + &tq_scheduler); + } + } + + /* Check for CTS transitions */ + if (info->tty && C_CRTSCTS(info->tty)) { + /* + * For some reason, on the Power Macintosh, + * it seems that the CTS bit is 1 when CTS is + * *negated* and 0 when it is asserted. + * The DCD bit doesn't seem to be inverted + * like this. + */ + if ((status & CTS) == 0) { + if (info->tx_stopped) { + info->tx_stopped = 0; + if (!info->tx_active) + transmit_chars(info); + } + } else { + info->tx_stopped = 1; + } + } + + /* Clear status condition... */ + write_zsreg(info->zs_channel, 0, RES_EXT_INT); + info->read_reg_zero = status; +} + +/* + * This is the serial driver's generic interrupt routine + */ +void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct mac_serial *info = (struct mac_serial *) dev_id; + unsigned char zs_intreg; + int shift; + + /* NOTE: The read register 3, which holds the irq status, + * does so for both channels on each chip. Although + * the status value itself must be read from the A + * channel and is only valid when read from channel A. + * Yes... broken hardware... + */ +#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT) + + if (info->zs_chan_a == info->zs_channel) + shift = 3; /* Channel A */ + else + shift = 0; /* Channel B */ + + for (;;) { + zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; + if ((zs_intreg & CHAN_IRQMASK) == 0) + break; + + if (zs_intreg & CHBRxIP) + receive_chars(info, regs); + if (zs_intreg & CHBTxIP) + transmit_chars(info); + if (zs_intreg & CHBEXT) + status_handle(info); + } +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + +#if 0 + save_flags(flags); cli(); + if (info->curregs[5] & TxENAB) { + info->curregs[5] &= ~TxENAB; + info->pendregs[5] &= ~TxENAB; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + } + restore_flags(flags); +#endif +} + +static void rs_start(struct tty_struct *tty) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); +#if 0 + if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) { + info->curregs[5] |= TxENAB; + info->pendregs[5] = info->curregs[5]; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + } +#else + if (info->xmit_cnt && info->xmit_buf && !info->tx_active) { + transmit_chars(info); + } +#endif + restore_flags(flags); +} + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct mac_serial *info = (struct mac_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void do_serial_hangup(void *private_) +{ + struct mac_serial *info = (struct mac_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + tty_hangup(tty); +} + +static void rs_timer(void) +{ +} + +static int startup(struct mac_serial * info) +{ + unsigned long flags; + + if (info->flags & ZILOG_INITIALIZED) + return 0; + + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL); + if (!info->xmit_buf) + return -ENOMEM; + } + + save_flags(flags); cli(); + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (irq %d)...", info->line, info->irq); +#endif + + /* + * Clear the receive FIFO. + */ + ZS_CLEARFIFO(info->zs_channel); + info->xmit_fifo_size = 1; + + /* + * Clear the interrupt registers. + */ + write_zsreg(info->zs_channel, 0, ERR_RES); + write_zsreg(info->zs_channel, 0, RES_H_IUS); + + /* + * Turn on RTS and DTR. + */ + zs_rtsdtr(info, 1); + + /* + * Finally, enable sequencing and interrupts + */ + info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); + info->pendregs[1] = info->curregs[1]; + info->curregs[3] |= (RxENABLE | Rx8); + info->pendregs[3] = info->curregs[3]; + info->curregs[5] |= (TxENAB | Tx8); + info->pendregs[5] = info->curregs[5]; + info->curregs[9] |= (NV | MIE); + info->pendregs[9] = info->curregs[9]; + write_zsreg(info->zs_channel, 3, info->curregs[3]); + write_zsreg(info->zs_channel, 5, info->curregs[5]); + write_zsreg(info->zs_channel, 9, info->curregs[9]); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set the speed of the serial port + */ + change_speed(info); + + /* Save the current value of RR0 */ + info->read_reg_zero = read_zsreg(info->zs_channel, 0); + + info->flags |= ZILOG_INITIALIZED; + restore_flags(flags); + return 0; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct mac_serial * info) +{ + unsigned long flags; + + if (!(info->flags & ZILOG_INITIALIZED)) + return; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + info->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + info->pendregs[1] = info->curregs[1] = 0; + write_zsreg(info->zs_channel, 1, 0); /* no interrupts */ + + info->curregs[3] &= ~RxENABLE; + info->pendregs[3] = info->curregs[3]; + write_zsreg(info->zs_channel, 3, info->curregs[3]); + + info->curregs[5] &= ~TxENAB; + if (!info->tty || C_HUPCL(info->tty)) + info->curregs[5] &= ~(DTR | RTS); + info->pendregs[5] = info->curregs[5]; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ZILOG_INITIALIZED; + restore_flags(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct mac_serial *info) +{ + unsigned short port; + unsigned cflag; + int i; + int brg; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!(port = info->port)) + return; + i = cflag & CBAUD; + if (i & CBAUDEX) { + /* XXX CBAUDEX is not obeyed. + * It is impossible at a 32bits PPC. XXX?? + * But we have to report this to user ... someday. + */ + i = B9600; + } + + save_flags(flags); cli(); + info->zs_baud = baud_table[i]; + info->clk_divisor = 16; + + info->curregs[4] = X16CLK; + info->curregs[11] = TCBR | RCBR; + brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor); + info->curregs[12] = (brg & 255); + info->curregs[13] = ((brg >> 8) & 255); + info->curregs[14] = BRENABL; + + /* byte size and parity */ + info->curregs[3] &= ~RxNBITS_MASK; + info->curregs[5] &= ~TxNBITS_MASK; + switch (cflag & CSIZE) { + case CS5: + info->curregs[3] |= Rx5; + info->curregs[5] |= Tx5; + break; + case CS6: + info->curregs[3] |= Rx6; + info->curregs[5] |= Tx6; + break; + case CS7: + info->curregs[3] |= Rx7; + info->curregs[5] |= Tx7; + break; + case CS8: + default: /* defaults to 8 bits */ + info->curregs[3] |= Rx8; + info->curregs[5] |= Tx8; + break; + } + info->pendregs[3] = info->curregs[3]; + info->pendregs[5] = info->curregs[5]; + + info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN); + if (cflag & CSTOPB) { + info->curregs[4] |= SB2; + } else { + info->curregs[4] |= SB1; + } + if (cflag & PARENB) { + info->curregs[4] |= PAR_ENA; + } + if (!(cflag & PARODD)) { + info->curregs[4] |= PAR_EVEN; + } + info->pendregs[4] = info->curregs[4]; + + info->curregs[15] &= ~(DCDIE | CTSIE); + if (!(cflag & CLOCAL)) { + info->curregs[15] |= DCDIE; + } + if (cflag & CRTSCTS) { + info->curregs[15] |= CTSIE; + if ((read_zsreg(info->zs_channel, 0) & CTS) != 0) + info->tx_stopped = 1; + } else + info->tx_stopped = 0; + info->pendregs[15] = info->curregs[15]; + + /* Load up the new values */ + load_zsregs(info->zs_channel, info->curregs); + + restore_flags(flags); +} + +/* This is for console output over ttya/ttyb */ +static void rs_put_char(char ch) +{ + struct mac_zschannel *chan = zs_conschan; + int loops = 0; + unsigned long flags; + + if(!chan) + return; + + save_flags(flags); cli(); + while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) { + loops++; + udelay(5); + } + write_zsdata(chan, ch); + restore_flags(flags); +} + +/* These are for receiving and sending characters under the kgdb + * source level kernel debugger. + */ +void putDebugChar(char kgdb_char) +{ + struct mac_zschannel *chan = zs_kgdbchan; + + while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) + udelay(5); + write_zsdata(chan, kgdb_char); +} + +char getDebugChar(void) +{ + struct mac_zschannel *chan = zs_kgdbchan; + + while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0) + udelay(5); + return read_zsdata(chan); +} + +/* + * Fair output driver allows a process to speak. + */ +static void rs_fair_output(void) +{ + int left; /* Output no more than that */ + unsigned long flags; + struct mac_serial *info = zs_consinfo; + char c; + + if (info == 0) return; + if (info->xmit_buf == 0) return; + + save_flags(flags); cli(); + left = info->xmit_cnt; + while (left != 0) { + c = info->xmit_buf[info->xmit_tail]; + info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + restore_flags(flags); + + rs_put_char(c); + + save_flags(flags); cli(); + left = MIN(info->xmit_cnt, left-1); + } + + restore_flags(flags); + return; +} + +/* + * zs_console_print is registered for printk. + */ +static void zs_console_print(const char *p) +{ + char c; + + while ((c = *(p++)) != 0) { + if (c == '\n') + rs_put_char('\r'); + rs_put_char(c); + } + + /* Comment this if you want to have a strict interrupt-driven output */ + rs_fair_output(); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped || + !info->xmit_buf) + return; + + /* Enable transmitter */ + save_flags(flags); cli(); + transmit_chars(info); + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, total = 0; + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf) + return 0; + + save_flags(flags); + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + if (from_user) { + down(&tmp_buf_sem); + memcpy_fromfs(tmp_buf, buf, c); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + up(&tmp_buf_sem); + } else + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + if (info->xmit_cnt && !tty->stopped && !info->tx_stopped + && !info->tx_active) + transmit_chars(info); + restore_flags(flags); + return total; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + sti(); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) { + save_flags(flags); cli(); + info->x_char = STOP_CHAR(tty); + if (!info->tx_active) + transmit_chars(info); + restore_flags(flags); + } + + if (C_CRTSCTS(tty)) { + /* + * Here we want to turn off the RTS line. On Macintoshes, + * we only get the DTR line, which goes to both DTR and + * RTS on the modem. RTS doesn't go out to the serial + * port socket. So you should make sure your modem is + * set to ignore DTR if you're using CRTSCTS. + */ + save_flags(flags); cli(); + info->curregs[5] &= ~(DTR | RTS); + info->pendregs[5] &= ~(DTR | RTS); + write_zsreg(info->zs_channel, 5, info->curregs[5]); + restore_flags(flags); + } +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + save_flags(flags); cli(); + if (info->x_char) + info->x_char = 0; + else { + info->x_char = START_CHAR(tty); + if (!info->tx_active) + transmit_chars(info); + } + restore_flags(flags); + } + + if (C_CRTSCTS(tty)) { + /* Assert RTS and DTR lines */ + save_flags(flags); cli(); + info->curregs[5] |= DTR | RTS; + info->pendregs[5] |= DTR | RTS; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + restore_flags(flags); + } +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct mac_serial * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->port; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + memcpy_tofs(retinfo,&tmp,sizeof(*retinfo)); + return 0; +} + +static int set_serial_info(struct mac_serial * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct mac_serial old_info; + int retval = 0; + + if (!new_info) + return -EFAULT; + memcpy_fromfs(&new_serial,new_info,sizeof(new_serial)); + old_info = *info; + + if (!suser()) { + if ((new_serial.baud_base != info->baud_base) || + (new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ZILOG_USR_MASK) != + (info->flags & ~ZILOG_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ZILOG_USR_MASK) | + (new_serial.flags & ZILOG_USR_MASK)); + info->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if (info->count > 1) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->flags = ((info->flags & ~ZILOG_FLAGS) | + (new_serial.flags & ZILOG_FLAGS)); + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + +check_and_exit: + retval = startup(info); + return retval; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct mac_serial * info, unsigned int *value) +{ + unsigned char status; + + cli(); + status = read_zsreg(info->zs_channel, 0); + sti(); + put_user(status,value); + return 0; +} + +static int get_modem_info(struct mac_serial *info, unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + + cli(); + control = info->curregs[5]; + status = read_zsreg(info->zs_channel, 0); + sti(); + result = ((control & RTS) ? TIOCM_RTS: 0) + | ((control & DTR) ? TIOCM_DTR: 0) + | ((status & DCD) ? TIOCM_CAR: 0) + | ((status & CTS) ? 0: TIOCM_CTS); + put_user(result,value); + return 0; +} + +static int set_modem_info(struct mac_serial *info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg, bits; + + error = verify_area(VERIFY_READ, value, sizeof(int)); + if (error) + return error; + arg = get_user(value); + bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0); + cli(); + switch (cmd) { + case TIOCMBIS: + info->curregs[5] |= bits; + break; + case TIOCMBIC: + info->curregs[5] &= ~bits; + break; + case TIOCMSET: + info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits; + break; + default: + sti(); + return -EINVAL; + } + info->pendregs[5] = info->curregs[5]; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + sti(); + return 0; +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break( struct mac_serial * info, int duration) +{ + if (!info->port) + return; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + duration; + cli(); + info->curregs[5] |= SND_BRK; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + schedule(); + info->curregs[5] &= ~SND_BRK; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + sti(); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct mac_serial * info = (struct mac_serial *)tty->driver_data; + int retval; + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + send_break(info, HZ/4); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + send_break(info, arg ? arg*(HZ/10) : HZ/4); + return 0; + case TIOCGSOFTCAR: + error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); + if (error) + return error; + put_fs_long(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + return 0; + case TIOCSSOFTCAR: + arg = get_fs_long((unsigned long *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct)); + if (error) + return error; + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERGETLSR: /* Get line status register */ + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + else + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct mac_serial)); + if (error) + return error; + memcpy_tofs((struct mac_serial *) arg, + info, sizeof(struct mac_serial)); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct mac_serial *info = (struct mac_serial *)tty->driver_data; + int was_stopped; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + was_stopped = info->tx_stopped; + + change_speed(info); + + if (was_stopped && !info->tx_stopped) + rs_start(tty); +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. + * Wait for the last remaining data to be sent. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct mac_serial * info = (struct mac_serial *)tty->driver_data; + unsigned long flags; + unsigned long timeout; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, info->count); +#endif + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + restore_flags(flags); + return; + } + info->flags |= ZILOG_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ZILOG_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ZILOG_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receiver and receive interrupts. + */ + /** if (!info->iscons) ... **/ + info->curregs[3] &= ~RxENABLE; + info->pendregs[3] = info->curregs[3]; + write_zsreg(info->zs_channel, 3, info->curregs[3]); + info->curregs[1] &= ~(0x18); /* disable any rx ints */ + info->pendregs[1] = info->curregs[1]; + write_zsreg(info->zs_channel, 1, info->curregs[1]); + ZS_CLEARFIFO(info->zs_channel); + if (info->flags & ZILOG_INITIALIZED) { + /* + * Before we drop DTR, make sure the SCC transmitter + * has completely drained. + */ + timeout = jiffies+HZ; + while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + info->timeout; + schedule(); + if (jiffies > timeout) + break; + } + } + + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + info->close_delay; + schedule(); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| + ZILOG_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void rs_hangup(struct tty_struct *tty) +{ + struct mac_serial * info = (struct mac_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct mac_serial *info) +{ + struct wait_queue wait = { current, NULL }; + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & ZILOG_CLOSING) { + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ZILOG_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ZILOG_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ZILOG_CALLOUT_ACTIVE) && + (info->flags & ZILOG_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ZILOG_CALLOUT_ACTIVE) && + (info->flags & ZILOG_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ZILOG_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ZILOG_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ZILOG_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ZILOG_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + info->line, info->count); +#endif + info->count--; + info->blocked_open++; + while (1) { + cli(); + if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) + zs_rtsdtr(info, 1); + sti(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ZILOG_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ZILOG_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && + !(info->flags & ZILOG_CLOSING) && do_clocal) + break; + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= ZILOG_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its ZILOG structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct mac_serial *info; + int retval, line; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= zs_channels_found)) + return -ENODEV; + info = zs_soft + line; + + /* Is the kgdb running over this line? */ + if (info->kgdb_channel) + return -ENODEV; + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->count); +#endif + + info->count++; + tty->driver_data = info; + info->tty = tty; + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + change_speed(info); + } + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* Finally, routines used to initialize the serial driver. */ + +#ifdef CONFIG_MAC + +/* + * MacII hardcoded - will be in the hwtab + */ + +static void show_serial_version(void) +{ + printk("Mac68K Z8530 serial driver version 1.00\n"); +} + +static void probe_sccs(void) +{ + int n; +#define ZS_CONTROL 0x50F04000 +#define ZS_DATA (ZS_CONTROL+4) +#define ZS_IRQ 5 +#define ZS_MOVE 3 + for(n=0;n<2;n++) + { + zs_channels[n].control = (volatile unsigned char *) + ZS_CONTROL+ZS_MOVE*n; + zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n; + zs_soft[n].zs_channel = &zs_channels[n]; + zs_soft[n].irq = ZS_IRQ; +#if 0 + if (request_irq(ch->intrs[0], rs_interrupt, 0, + "SCC", &zs_soft[n])) + panic("macserial: can't get irq %d", + ch->intrs[0]); +#endif + if (n & 1) + zs_soft[n].zs_chan_a = &zs_channels[n-1]; + else + zs_soft[n].zs_chan_a = &zs_channels[n]; + } + if(request_irq(ZS_IRQ, rs_interrupt, 0, "SCC", &zs_soft[n])) + panic("macserial: can't get irq %d", ZS_IRQ); +} + +#else + +/* + * PowerMAC - query the PROM + */ + +static void show_serial_version(void) +{ + printk("PowerMac Z8530 serial driver version 1.00\n"); +} + +/* Ask the PROM how many Z8530s we have and initialize their zs_channels */ +static void +probe_sccs() +{ + struct device_node *dev, *ch; + struct mac_serial **pp; + int n; + + n = 0; + pp = &zs_chain; + for (dev = find_devices("escc"); dev != 0; dev = dev->next) { + if (n >= NUM_CHANNELS) { + printk("Sorry, can't use %s: no more channels\n", + dev->full_name); + continue; + } + for (ch = dev->child; ch != 0; ch = ch->sibling) { + if (ch->n_addrs < 1 || ch ->n_intrs < 1) { + printk("Can't use %s: %d addrs %d intrs\n", + ch->full_name, ch->n_addrs, ch->n_intrs); + continue; + } + zs_channels[n].control = (volatile unsigned char *) + ch->addrs[0].address; + zs_channels[n].data = zs_channels[n].control + + ch->addrs[0].size / 2; + zs_soft[n].zs_channel = &zs_channels[n]; + zs_soft[n].irq = ch->intrs[0]; + if (request_irq(ch->intrs[0], rs_interrupt, 0, + "SCC", &zs_soft[n])) + panic("macserial: can't get irq %d", + ch->intrs[0]); + /* XXX this assumes the prom puts chan A before B */ + if (n & 1) + zs_soft[n].zs_chan_a = &zs_channels[n-1]; + else + zs_soft[n].zs_chan_a = &zs_channels[n]; + + *pp = &zs_soft[n]; + pp = &zs_soft[n].zs_next; + ++n; + } + } + *pp = 0; + zs_channels_found = n; +} + +#endif + +extern void register_console(void (*proc)(const char *)); + +static inline void +rs_cons_check(struct mac_serial *ss, int channel) +{ + int i, o, io; + static consout_registered = 0; + static msg_printed = 0; + + i = o = io = 0; + + /* Is this one of the serial console lines? */ + if ((zs_cons_chanout != channel) && + (zs_cons_chanin != channel)) + return; + zs_conschan = ss->zs_channel; + zs_consinfo = ss; + + /* Register the console output putchar, if necessary */ + if (zs_cons_chanout == channel) { + o = 1; + /* double whee.. */ + if (!consout_registered) { + register_console(zs_console_print); + consout_registered = 1; + } + } + + if (zs_cons_chanin == channel) { + i = 1; + } + if (o && i) + io = 1; + if (ss->zs_baud != 9600) + panic("Console baud rate weirdness"); + + /* Set flag variable for this port so that it cannot be + * opened for other uses by accident. + */ + ss->is_cons = 1; + + if (io) { + if(!msg_printed) { + printk("zs%d: console I/O\n", ((channel>>1)&1)); + msg_printed = 1; + } + } else { + printk("zs%d: console %s\n", ((channel>>1)&1), + (i==1 ? "input" : (o==1 ? "output" : "WEIRD"))); + } +} + +volatile int test_done; + +/* rs_init inits the driver */ +int rs_init(void) +{ + int channel, i; + unsigned long flags; + struct mac_serial *info; + + /* Setup base handler, and timer table. */ + init_bh(SERIAL_BH, do_serial_bh); + timer_table[RS_TIMER].fn = rs_timer; + timer_table[RS_TIMER].expires = 0; + + /* Find out how many Z8530 SCCs we have */ + if (zs_chain == 0) + probe_sccs(); + + show_serial_version(); + + /* Initialize the tty_driver structure */ + /* Not all of this is exactly right for us. */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = zs_channels_found; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + save_flags(flags); cli(); + + for (channel = 0; channel < zs_channels_found; ++channel) { + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); + + /* If console serial line, then enable interrupts. */ + if (zs_soft[channel].is_cons) { + write_zsreg(zs_soft[channel].zs_channel, R1, + (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB)); + write_zsreg(zs_soft[channel].zs_channel, R9, + (NV | MIE)); + write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ)); + write_zsreg(zs_soft[channel].zs_channel, R3, + (Rx8 | RxENABLE)); + write_zsreg(zs_soft[channel].zs_channel, R5, + (Tx8 | TxENAB)); + } + /* If this is the kgdb line, enable interrupts because we + * now want to receive the 'control-c' character from the + * client attached to us asynchronously. + */ + if (zs_soft[channel].kgdb_channel) + kgdb_chaninit(&zs_soft[channel], 1, + zs_soft[channel].zs_baud); + } + + for (info = zs_chain, i = 0; info; info = info->zs_next, i++) + { + info->magic = SERIAL_MAGIC; + info->port = (int) info->zs_channel->control; + info->line = i; + info->tty = 0; + info->custom_divisor = 16; + info->close_delay = 50; + info->closing_wait = 3000; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->tqueue_hangup.routine = do_serial_hangup; + info->tqueue_hangup.data = info; + info->callout_termios =callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + info->open_wait = 0; + info->close_wait = 0; + printk("tty%02d at 0x%08x (irq = %d)", info->line, + info->port, info->irq); +#ifdef CONFIG_MAC + printk(" is a Z8530 ESCC\n"); +#else + printk(" is a Z8530 SCC\n"); +#endif + + } + + restore_flags(flags); + + return 0; +} + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +/* PowerMac: Unused at this time, just here to make things link. */ +int register_serial(struct serial_struct *req) +{ + return -1; +} + +void unregister_serial(int line) +{ + return; +} + +/* Hooks for running a serial console. con_init() calls this if the + * console is being run over one of the serial ports. + * 'channel' is decoded as 0=modem 1=printer, 'chip' is ignored. + */ +void +rs_cons_hook(int chip, int out, int channel) +{ + if (zs_chain == 0) + probe_sccs(); + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); + rs_cons_check(&zs_soft[channel], channel); + if (out) + zs_cons_chanout = channel; + else + zs_cons_chanin = channel; + +} + +/* This is called at boot time to prime the kgdb serial debugging + * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1 + * for /dev/ttyS1 which is determined in setup_arch() from the + * boot command line flags. + */ +void +rs_kgdb_hook(int tty_num) +{ + if (zs_chain == 0) + probe_sccs(); + zs_kgdbchan = zs_soft[tty_num].zs_channel; + zs_soft[tty_num].clk_divisor = 16; + zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]); + zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */ + zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */ + /* Turn on transmitter/receiver at 8-bits/char */ + kgdb_chaninit(&zs_soft[tty_num], 0, 9600); + ZS_CLEARERR(zs_kgdbchan); + ZS_CLEARFIFO(zs_kgdbchan); +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/macserial.h linux-2.0.29/drivers/char/macserial.h --- linux.vanilla/drivers/char/macserial.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/drivers/char/macserial.h Thu Apr 10 12:43:55 1997 @@ -0,0 +1,407 @@ +/* + * macserial.h: Definitions for the Macintosh Z8530 serial driver. + * + * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras. + * + * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ +#ifndef _MACSERIAL_H +#define _MACSERIAL_H + +#define NUM_ZSREGS 16 + +struct serial_struct { + int type; + int line; + int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char reserved_char[2]; + int hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + int reserved[4]; +}; + +/* + * For the close wait times, 0 means wait forever for serial port to + * flush its output. 65535 means don't wait at all. + */ +#define ZILOG_CLOSING_WAIT_INF 0 +#define ZILOG_CLOSING_WAIT_NONE 65535 + +/* + * Definitions for ZILOG_struct (and serial_struct) flags field + */ +#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ +#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ +#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */ +#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ + +#define ZILOG_SPD_MASK 0x0030 +#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ + +#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */ + +#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ +#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ +#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ +#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ + +#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */ +#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged + * users can set or reset */ + +/* Internal flags used only by kernel/chr_drv/serial.c */ +#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ +#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ + +/* Software state per channel */ + +#ifdef __KERNEL__ +/* + * This is our internal structure for each serial port's state. + * + * Many fields are paralleled by the structure used by the serial_struct + * structure. + * + * For definitions of the flags field, see tty.h + */ + +struct mac_zschannel { + volatile unsigned char *control; + volatile unsigned char *data; +}; + +struct mac_serial { + struct mac_serial *zs_next; /* For IRQ servicing chain */ + struct mac_zschannel *zs_channel; /* Channel registers */ + struct mac_zschannel *zs_chan_a; /* A side registers */ + unsigned char read_reg_zero; + + char soft_carrier; /* Use soft carrier on this channel */ + char break_abort; /* Is serial console in, so process brk/abrt */ + char kgdb_channel; /* Kgdb is running on this channel */ + char is_cons; /* Is this our console. */ + unsigned char tx_active; /* character is being xmitted */ + unsigned char tx_stopped; /* output is suspended */ + + /* We need to know the current clock divisor + * to read the bps rate the chip has currently + * loaded. + */ + unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ + int zs_baud; + + /* Current write register values */ + unsigned char curregs[NUM_ZSREGS]; + + /* Values we need to set next opportunity */ + unsigned char pendregs[NUM_ZSREGS]; + + char change_needed; + + int magic; + int baud_base; + int port; + int irq; + int flags; /* defined in tty.h */ + int type; /* UART type */ + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int timeout; + int xmit_fifo_size; + int custom_divisor; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + unsigned long last_active; + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + struct termios normal_termios; + struct termios callout_termios; + struct wait_queue *open_wait; + struct wait_queue *close_wait; +}; + + +#define SERIAL_MAGIC 0x5301 + +/* + * The size of the serial xmit buffer is 1 page, or 4096 bytes + */ +#define SERIAL_XMIT_SIZE 4096 + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_WRITE_WAKEUP 0 + +#endif /* __KERNEL__ */ + +/* Conversion routines to/from brg time constants from/to bits + * per second. + */ +#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +/* The Zilog register set */ + +#define FLAG 0x7e + +/* Write Register 0 */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 */ + +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ +#define INT_ERR_Rx 0x18 /* Int on error only */ + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register #2 (Interrupt Vector) */ + +/* Write Register 3 */ + +#define RxENABLE 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ +#define RxNBITS_MASK 0xc0 + +/* Write Register 4 */ + +#define PAR_ENA 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ +#define SB_MASK 0xc + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xC0 /* x64 clock mode */ +#define XCLK_MASK 0xC0 + +/* Write Register 5 */ + +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define TxNBITS_MASK 0x60 +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 8 (transmit buffer) */ + +/* Write Register 9 (Master interrupt control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (misc control bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (lower byte of baud rate generator time constant) */ + +/* Write Register 13 (upper byte of baud rate generator time constant) */ + +/* Write Register 14 (Misc control bits) */ +#define BRENABL 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (external/status interrupt control) */ +#define ZCIE 2 /* Zero count IE */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define FRM_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (channel b only) - Interrupt vector */ + +/* Read Register 3 (interrupt pending register) ch a only */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 8 (receive data register) */ + +/* Read Register 10 (misc status bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (lower byte of baud rate generator constant) */ + +/* Read Register 13 (upper byte of baud rate generator constant) */ + +/* Read Register 15 (value of WR 15) */ + +/* Misc macros */ +#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES)) +#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \ + garbage = read_zsdata(channel); \ + garbage = read_zsdata(channel); \ + garbage = read_zsdata(channel); \ + } while(0) + +#endif /* !(_MACSERIAL_H) */ diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/mem.c linux-2.0.29/drivers/char/mem.c --- linux.vanilla/drivers/char/mem.c Thu Nov 14 21:23:58 1996 +++ linux-2.0.29/drivers/char/mem.c Tue Apr 15 18:54:15 1997 @@ -413,6 +413,9 @@ gsp_init(); #endif tty_init(); +#ifdef CONFIG_MAC + nubus_probe_bus(); +#endif #ifdef CONFIG_PRINTER lp_init(); #endif diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/misc.c linux-2.0.29/drivers/char/misc.c --- linux.vanilla/drivers/char/misc.c Sat Nov 9 14:07:30 1996 +++ linux-2.0.29/drivers/char/misc.c Mon Apr 14 15:14:11 1997 @@ -198,6 +198,9 @@ &proc_misc_read /* get_info */, }); #endif /* PROC_FS */ +#ifdef CONFIG_MAC + adbdev_init(); +#endif #ifdef CONFIG_BUSMOUSE bus_mouse_init(); #endif diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/char/tty_io.c linux-2.0.29/drivers/char/tty_io.c --- linux.vanilla/drivers/char/tty_io.c Sun Nov 3 20:15:41 1996 +++ linux-2.0.29/drivers/char/tty_io.c Thu Apr 10 14:17:35 1997 @@ -1910,7 +1910,8 @@ #if defined(CONFIG_SERIAL) || defined(CONFIG_ATARI_MFPSER) || \ defined(CONFIG_ATARI_SCC) || defined(CONFIG_ATARI_MIDI) || \ defined(CONFIG_AMIGA_BUILTIN_SERIAL) || defined(CONFIG_GVIOEXT) || \ - defined(CONFIG_MULTIFACE_III_TTY) || defined(CONFIG_USERIAL) + defined(CONFIG_MULTIFACE_III_TTY) || defined(CONFIG_USERIAL) || \ + defined(CONFIG_MAC_SCC) rs_init(); #endif #ifdef CONFIG_SCC diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/nubus/Makefile linux-2.0.29/drivers/nubus/Makefile --- linux.vanilla/drivers/nubus/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/drivers/nubus/Makefile Tue Apr 15 16:50:47 1997 @@ -0,0 +1,15 @@ +# +# Makefile for the nubus specific drivers. +# +# 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 definition is now inherited from the +# parent makefile. +# + +L_OBJS := nubus.o +L_TARGET := nubus.a + +include $(TOPDIR)/Rules.make diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/drivers/nubus/nubus.c linux-2.0.29/drivers/nubus/nubus.c --- linux.vanilla/drivers/nubus/nubus.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/drivers/nubus/nubus.c Wed Apr 16 16:57:52 1997 @@ -0,0 +1,230 @@ +/* + * Macintosh Nubus Interface Code + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +static struct nubus_slot nubus_slots[16]; + +/* + * Please skip to the bottom of this file if you ate lunch recently + * -- Alan + */ + + + +/* This function tests for the presence of an address, specially a + * hardware register address. It is called very early in the kernel + * initialization process, when the VBR register isn't set up yet. On + * an Atari, it still points to address 0, which is unmapped. So a bus + * error would cause another bus error while fetching the exception + * vector, and the CPU would do nothing at all. So we needed to set up + * a temporary VBR and a vector table for the duration of the test. + * + * See the atari/config.c code we nicked it from for more clues. + */ + +static int hwreg_present( volatile void *regp ) +{ + int ret = 0; + long save_sp, save_vbr; + long tmp_vectors[3]; + unsigned long flags; + + save_flags(flags); + cli(); + + __asm__ __volatile__ + ( "movec %/vbr,%2\n\t" + "movel #Lberr1,%4@(8)\n\t" + "movec %4,%/vbr\n\t" + "movel %/sp,%1\n\t" + "moveq #0,%0\n\t" + "tstb %3@\n\t" + "nop\n\t" + "moveq #1,%0\n" + "Lberr1:\n\t" + "movel %1,%/sp\n\t" + "movec %2,%/vbr" + : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) + : "a" (regp), "a" (tmp_vectors) + ); + restore_flags(flags); + return( ret ); +} + + + +/* + * Yes this sucks. The ROM can appear on arbitary bytes of the long + * word. We are unamused. + */ + +extern __inline__ int not_useful(void *p, int map) +{ + unsigned long pv=(unsigned long)p; + pv&=3; + if(map&(1<>4)^dp)&0x0F)!=0x0F) + continue; + + if((dp&0x0F) >= 1< #include #include +#include #include extern void device_setup(void); @@ -108,6 +109,9 @@ #ifdef CONFIG_UFS_FS init_ufs_fs(); +#endif +#ifdef CONFIG_HFS_FS + init_hfs_fs(); #endif mount_root(); diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/BUG_INFO linux-2.0.29/fs/hfs/BUG_INFO --- linux.vanilla/fs/hfs/BUG_INFO Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/BUG_INFO Wed Apr 9 04:41:47 1997 @@ -0,0 +1,23 @@ +#!/bin/sh +# +# This script attempt to collect some of the +# information I need for a complete bug report. +# + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +export PATH + +echo -n "kernel version: " +uname -r + +echo -n "hfs_fs version: " +grep hfs_version version.c | cut '-d"' -f2 + +echo -n "gcc version: " +gcc --version + +echo -n "gcc output: " +file hfs.o | cut -d: -f2- + +echo -n "insmod version: " +insmod -V 2>/dev/null diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/COPYING linux-2.0.29/fs/hfs/COPYING --- linux.vanilla/fs/hfs/COPYING Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/COPYING Wed Apr 9 04:41:47 1997 @@ -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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/ChangeLog linux-2.0.29/fs/hfs/ChangeLog --- linux.vanilla/fs/hfs/ChangeLog Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/ChangeLog Wed Apr 9 04:41:47 1997 @@ -0,0 +1,2160 @@ +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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/Makefile linux-2.0.29/fs/hfs/Makefile --- linux.vanilla/fs/hfs/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/Makefile Thu Apr 10 12:39:44 1997 @@ -0,0 +1,14 @@ +# +# Makefile for the linux ufs-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 Binary files linux.vanilla/fs/hfs/README.dvi and linux-2.0.29/fs/hfs/README.dvi differ diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/README.sgml linux-2.0.29/fs/hfs/README.sgml --- linux.vanilla/fs/hfs/README.sgml Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/README.sgml Wed Apr 9 04:41:47 1997 @@ -0,0 +1,1255 @@ + +
+ +Macintosh HFS Filesystem for Linux +<author>Paul H. Hargrove, <tt><htmlurl url="mailto:hargrove@sccm.Stanford.EDU" +name="hargrove@sccm.Stanford.EDU"></tt> +<date>version 0.8.3, 08 Apr 1997 +<abstract> +This document describes version 0.8.3 of <tt>hfs_fs</tt>, +a Linux kernel loadable module implementing the Macintosh HFS filesystem. +The most current versions of this document and the software are kept at +<url url="http://www-sccm.Stanford.EDU/˜hargrove/HFS/" +name="The HFS for Linux Page">. +</abstract> +<!-- Table of contents --> +<toc> +<!-- Begin the document --> +<sect>Introduction +<p> +This package is a Macintosh HFS filesystem module for Linux. It allows +you to read and write Macintosh HFS filesystems +on floppy disks, CDROMs, hard drives, ZIP drives, etc. +It is <em>not</em> an AppleShare client. +<p> +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. +<p> +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. +<p> +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 <em>strongly</em> recommend +that you reboot before writing any files. +<!-- --> +<sect>System Requirements +<p> +You will need the following to compile and use this release of <tt>hfs_fs</tt>: +<itemize> + <item> + Kernel version 2.0.1 or newer + compiled with modules enabled (<tt>CONFIG_MODULES</tt>). + <!-- --> + <item> + The kernel sources (or at least the header files) available online. + <!-- --> + <item> + The module utilities package current for your kernel version and + an understanding of how to use it. (The file + <tt>Documentation/modules.txt</tt> in the kernel source directory + provides a brief introduction.) + <!-- XXX: add a URL for the module utilities --> +</itemize> +<p> +In theory the code is endian-independent, but is tested most extensively +on Intel platforms. It is also known to compile on m68k, PPC and Alpha +machines, but is not as extensively tested on any of these platforms. +<!-- --> +<sect>Installation +<p> +The <tt>hfs_fs</tt> code is not yet 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 <tt>CONFIG_MODULES</tt> enabled. +<!-- --> +<sect1>Compiling the loadable module +<p> +To compile <tt>hfs.o</tt> you should only need to execute <tt>make</tt> +in the <tt>hfs_fs</tt> source directory. +<p> +If <tt>gcc</tt> 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 +<tt>/usr/include/linux</tt>, <tt>/usr/include/asm</tt> and +<tt>/usr/include/scsi</tt> should be symbolic links to <tt>include/linux</tt>, +<tt>include/asm</tt> and <tt>include/scsi</tt> in the +kernel source tree for the kernel you wish to use <tt>hfs_fs</tt> with, +or else they should be directories containing the header files for the +kernel you wish to use <tt>hfs_fs</tt> with. +<p> +If <tt>gcc</tt> complains about not finding <tt>linux/version.h</tt>, +then you will need to run <tt>make dep</tt> in the kernel source +directory to build it. +<p> +If <tt>gcc</tt> complains about not finding the files +<tt>linux/config.h</tt> or <tt>linux/autoconf.h</tt>, then you will +need to run <tt>make config</tt> and <tt>make dep</tt> in the kernel +source directory to build these two files and <tt>linux/version.h</tt>. +<p> +If you are compiling on a DEC Alpha and receive messages saying +<tt>assignment from incompatible pointer type</tt> when compiling +files <tt>dir_*.c</tt> and <tt>file_*.c</tt>, then you need to change +a single line in the file <tt>hfs_fs.h</tt>. Remove the text +``<tt>&& !defined(__alpha__)</tt>'' from the end of line 217. +<!-- --> +<sect1>Installing the module in the modules directory (optional) +<p> +If you plan to use <tt>kerneld</tt> to automatically load the module +or if you wish to use <tt>modprobe</tt> or <tt>insmod</tt> without +supplying a complete path to <tt>hfs.o</tt>, then you will need to +copy <tt>hfs.o</tt> into a directory where the module utilities +expect to find it. +<p> +The proper directory may depend slightly on your configuration. +However, <tt>/lib/modules/default/fs/</tt> is a common one for filesystem +modules. Once <tt>hfs.o</tt> is in the proper directory you should run +<tt>depmod -a</tt> to update the dependency list used by +<tt>kerneld</tt> and <tt>modprobe</tt>. +<!-- --> +<sect1>Loading the module into the running kernel +<p> +There are three ways to accomplish this: +<enum> + <item> + If you are running <tt>kerneld</tt> and have installed <tt>hfs.o</tt> + 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. + <!-- --> + <item> + If you are <em>not</em> running <tt>kerneld</tt> then you + can load <tt>hfs.o</tt> manually by running + <tt>modprobe hfs.o</tt>. If you have not installed + <tt>hfs.o</tt> in one of the standard module directories, + then you will need provide a full path to the file + <tt>hfs.o</tt>. + <!-- --> + <item> + If you have been experiencing kernel crashes with + <tt>hfs_fs</tt>, 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 + <tt>insmod -m hfs.o >loadmap</tt>. Again, you may need a + full path to the file <tt>hfs.o</tt> if you have not placed + it in one of the standard module directories. +</enum> +<!-- --> +<sect1>Using the module with versioned symbols +<p> +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 (<tt>CONFIG_MODVERSIONS</tt>) 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. +<p> +In any case, it is unlikely that this module will need changes with +each new kernel patch; simple recompilation should usually suffice. +<!-- --> +<sect>Mounting HFS Filesystems +<p> +Once you have installed the module, you will be able to use +<tt>hfs</tt> as a filesystem type option to <tt>mount</tt>. For +instance, to mount a Macintosh floppy disk on the directory +<tt>/mnt</tt> using the default mount options you would execute +<tt>mount -t hfs /dev/fd0 /mnt</tt>. +<p> +The remainder of this section describes the several mount options available +to control how the HFS filesystem is mapped onto a Linux structure. The +values for the multiple-choice options (<tt>case</tt>, <tt>conv</tt>, +<tt>fork</tt> and <tt>names</tt>) can be abbreviated by their first character. +<!-- --> +<sect1>afpd +<p> +If included in the options, then the behavior of <tt>hfs_fs</tt> 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 +<tt>rm -r</tt> will loop forever. +<p> +This option implies <tt>fork=netatalk</tt>, which in turn implies +<tt>names=netatalk</tt>. If either of these options are explicitly +set to something else they will take precedence and will confuse afpd. +The <tt>quiet</tt> option has no effect. The <tt>case=</tt> option +functions normally, but afpd usually does the same thing for you. The +<tt>conv=</tt> and <tt>part=</tt> options also function normally. +<p> +You will probably want to use the <tt>uid=</tt>, <tt>gid=</tt> and +<tt>umask=</tt> 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. +<p> +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. +<p> +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 likely that <tt>hfs_fs</tt>'s afpd mode +will be compatible with afpd from Netatalk version 1.4 when it is +released. +<!-- --> +<sect1>case={asis, lower} +<p> +default value: <tt>asis</tt> +<p> +This option determines if Mac filenames are presented in their original +case or in all lowercase. Filename matching is not affected, so +either way <tt>foo</tt> and <tt>Foo</tt> refer to the same file but +<tt>ls</tt> will list <tt>Foo</tt> with <tt>case=asis</tt>, and +<tt>foo</tt> with <tt>case=lower</tt>. +(Same as for the HPFS filesystem.) + <descrip> + <tag><tt>asis</tt></tag> + Filenames are reported in the case they were created with. + <tag><tt>lower</tt></tag> + Filenames are reported in lowercase. + </descrip> +<!-- --> +<sect1>conv={auto, binary, text} +<p> +default value: <tt>binary</tt> +<p> +This option controls <tt>CR</tt><-><tt>NL</tt> conversion of Macintosh +<em>data forks</em>. +Any translation takes place only for files accessed with the <tt>read()</tt> +and <tt>write()</tt> system calls (either directly or through +the stdio functions). Access through <tt>mmap()</tt> is unaffected. +(Similar to the <tt>conv=</tt> option for the MS-DOS filesystem.) + <descrip> + <tag><tt>auto</tt></tag> + If the Finder's type for a file is <tt>TEXT</tt> or <tt>ttro</tt>, + then <tt>CR</tt> characters are converted to <tt>NL</tt> characters + when read, and <tt>NL</tt> characters are converted to <tt>CR</tt> + characters when written. + <p> + Please e-mail me if you know of any other types that + indicate pure text files. + <!-- --> + <tag><tt>binary</tt></tag> + No <tt>CR</tt><-><tt>NL</tt> conversion is done. + <!-- --> + <tag><tt>text</tt></tag> + In all data forks, regardless of the Finder's type for the file, + <tt>CR</tt> characters are converted to <tt>NL</tt> characters + when read, and <tt>NL</tt> characters are converted to <tt>CR</tt> + characters when written. + </descrip> +<!-- --> +<sect1>creator=cccc +<p> +default value: ``????'' +<p> +Specifies the 4-character string specifying the Finder's Creator for new files. +<!-- --> +<sect1>fork={cap, double, netatalk} +<p> +default value: <tt>cap</tt> +<p> +This option determines how resource forks and the Finder's metadata are +represented within the structure of the Linux filesystem. + <descrip> + <tag><tt>cap</tt></tag> + The scheme used by the Columbia AppleTalk Package's AUFS. + <p> + Associated with each directory are two special directories and a + metadata file. The directory <tt>./bar</tt> is represented by: + <descrip> + <tag><tt>./bar</tt></tag> + The directory itself, containing subdirectories, the data + forks of files, and the following two special directories. + <!-- --> + <tag><tt>./bar/.resource</tt></tag> + A special directory holding resource forks of the + files in <tt>./bar</tt>. + <!-- --> + <tag><tt>./bar/.finderinfo</tt></tag> + A special directory holding metadata files for the files and + subdirectories in <tt>./bar</tt>. + <!-- --> + <tag><tt>./.finderinfo/bar</tt></tag> + The metadata file for the directory <tt>./bar</tt>. + </descrip> + <p> + The files in a directory are represented as three files: + <descrip> + <tag><tt>./foo</tt></tag> + The data fork of the file <tt>./foo</tt>. + <!-- --> + <tag><tt>./.resource/foo</tt></tag> + The resource fork of the file <tt>./foo</tt>. + <!-- --> + <tag><tt>./.finderinfo/foo</tt></tag> + The metadata file for the file <tt>./foo</tt>. + </descrip> + <p> + Additionally, the file <tt>.rootinfo</tt> in the root directory + of the HFS filesystem is a metadata file for the root directory. + <p> + Documentation on the format of file containing the Finder's metadata + is included in the Columbia AppleTalk Package. + <!-- XXX: Add URL for CAP homepage --> + <!-- --> + <tag><tt>double</tt></tag> + The ``AppleDouble'' format recommended by Apple. (Apple's other + recommended format, ``AppleSingle'', is not yet implemented.) + <p> + Associated with each directory is an AppleDouble ``header file''. + The directory <tt>./bar</tt> is represented by: + <descrip> + <tag><tt>./bar</tt></tag> + The directory itself, containing subdirectories, the data + forks for files, and the header files for files and + subdirectories. + <!-- --> + <tag><tt>./%bar</tt></tag> + The header file for the directory <tt>./bar</tt>, containing + the Finder's metadata for the directory. + </descrip> + <p> + The files in a directory are represented as two files: + <descrip> + <tag><tt>./foo</tt></tag> + The data fork of the file <tt>./foo</tt>. + <!-- --> + <tag><tt>./%foo</tt></tag> + The header file for the file <tt>./foo</tt>, containing the + resource fork and the Finder's metadata for the file. + </descrip> + <p> + Additionally, the file <tt>%RootInfo</tt> in the root + directory of the HFS filesystem is a header file for the root + directory. This is not quite the <tt>%RootInfo</tt> + file referred to in the AppleDouble specification. + <p> + The header files used in this scheme are version 2 AppleDouble + header files. Their format is documented in + ``AppleSingle/AppleDouble Formats: Developer's Note (9/94)'', + available from from <url url="http://devworld.apple.com" + name="Apple's Developer Services Page">. + <!-- XXX: give full URL for the document --> + <p> + Note that the naming convention for the header file can cause + name conflicts. For instance, using Apple's 7-bit ASCII name + conversion the name <tt>%Desktop</tt> could be interpreted + either as the header file for the file <tt>Desktop</tt> or as the + file with 0xDE as the hexadecimal representation of its first + character, and &dquot;sktop&dquot; as the remaining 5 characters. + The problem arises when both files exist, since only one will be + accessible. The behavior of the + HFS module 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.) + <!-- --> + <tag><tt>netatalk</tt></tag> + The scheme used by the Netatalk afpd. + <p> + Associated with each directory is a special directory and a + metadata file. The directory <tt>./bar</tt> is represented by: + <descrip> + <tag><tt>./bar</tt></tag> + The directory itself, containing subdirectories, the data + forks of files, and the following special directory. + <!-- --> + <tag><tt>./bar/.AppleDouble</tt></tag> + A special directory holding AppleDouble header files + for <tt>./bar</tt> and the files it contains, but not for + the subdirectories it contains. + <!-- --> + <tag><tt>./bar/.AppleDouble/.Parent</tt></tag> + The header file for the directory <tt>./bar</tt>, + containing the Finder's metadata for the directory. + </descrip> + <p> + The files in a directory are represented as two files: + <descrip> + <tag><tt>./foo</tt></tag> + The data fork of the file <tt>./foo</tt>. + <!-- --> + <tag><tt>./.AppleDouble/foo</tt></tag> + The header file for file <tt>./foo</tt>, containing the + resource fork and the Finder's metadata. + </descrip> + <p> + The header files used in this scheme are version 1 AppleDouble + header files. Their format is documented 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. + <!-- XXX: give URL for the file type notes --> + <!-- XXX: Add URL for Netatalk homepage --> + </descrip> +<!-- --> +<sect1>gid=n +<p> +default value: gid of the mounting process +<p> +Specifies the group that owns all files and directories on the filesystem. +(Same as for the MS-DOS and HPFS filesystems.) +<!-- --> +<sect1>names={7bit, 8bit, alpha, cap, latin, netatalk, trivial} +<p> +default value: varies as follows + <itemize> + <item> If the <tt>fork</tt> option is set to <tt>double</tt>, + then <tt>names</tt> defaults to <tt>alpha</tt>. + <!-- --> + <item> If the <tt>fork</tt> option is set to <tt>netatalk</tt>, + then <tt>names</tt> defaults to <tt>netatalk</tt>. + <!-- --> + <item>If the <tt>fork</tt> option is set to <tt>cap</tt> + (or has taken that value by default), + then <tt>names</tt> defaults to <tt>cap</tt>. + </itemize> +<p> +This option determines how to convert between valid Macintosh filenames +and valid Linux filenames. +The <tt>7bit</tt>, <tt>8bit</tt> and <tt>alpha</tt> +options correspond to Apple's recommended conventions named +``7-bit ASCII'', ``8-bit'' and ``7-bit alphanumeric''. +<p> + <descrip> + <tag><tt>7bit</tt></tag> + 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. + <p> + When converting from Linux filenames to Macintosh filenames + the string &dquot;%YZ&dquot; 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 &dquot;%YZ&dquot; is unchanged. A colon + (:) is replaced by a pipe character (|). + <!-- --> + <tag><tt>8bit</tt></tag> + 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. + <p> + When converting from Linux filenames to Macintosh filenames + the string &dquot;%YZ&dquot; 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 &dquot;%YZ&dquot; is unchanged. A colon + (:) is replaced by a pipe character (|). + <!-- --> + <tag><tt>alpha</tt></tag> + 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. + <p> + When converting from Linux filenames to Macintosh filenames + the string &dquot;%YZ&dquot; 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 &dquot;%YZ&dquot; is unchanged. A colon + (:) is replaced by a pipe character (|). + <!-- --> + <tag><tt>cap</tt></tag> + The convention used by the Columbia AppleTalk Package's AUFS. + <p> + 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. + <p> + When converting from Linux filenames to Macintosh filenames + the string &dquot;:YZ&dquot; 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 (|). + <!-- --> + <tag><tt>latin</tt></tag> + 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. + <p> + When converting from Linux filenames to Macintosh filenames + the string &dquot;%YZ&dquot; 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 &dquot;%YZ&dquot; 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 (|). + <p> + Thanks to Holger Schemel + (<tt><htmlurl url="mailto:aeglos@valinor.owl.de" + name="aeglos@valinor.owl.de"></tt>) for contributing this + conversion mode. + <!-- --> + <tag><tt>netatalk</tt></tag> + The convention used by the Netatalk afpd. + <p> + 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. + <p> + When converting from Linux filenames to Macintosh filenames + the string &dquot;:YZ&dquot; 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 (|). + <!-- --> + <tag><tt>trivial</tt></tag> + When converting from Macintosh filenames to Linux filenames + a slash character (/) is replaced by a colon (:). + <p> + When converting from Linux filenames to Macintosh filenames + a colon (:) is replaced by a slash character (/). + </descrip> +<!-- --> +<sect1>part=n +<p> +default value: 0 +<p> +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. +<p> +Note that in versions before 0.8.3 partitions were numbered from 1. +<!-- --> +<sect1>quiet +<p> +If included in the options, then <tt>chown</tt> and <tt>chmod</tt> +operations will not return errors, but will instead fail silently. +(Same as for the MS-DOS and HPFS filesystems.) +<!-- --> +<sect1>type=cccc +<p> +default value: ``????'' +<p> +Specifies the 4-character string specifying the Finder's Type for new files. +<!-- --> +<sect1>uid=n +<p> +default value: uid of the mounting process +<p> +Specifies the user that owns all files and directories on the filesystem. +(Same as for the MS-DOS and HPFS filesystems.) +<!-- --> +<sect1>umask=n +<p> +default value: umask of the mounting process +<p> +Specifies (in octal) the umask used for all files and directories. +(Same as for the MS-DOS and HPFS filesystems.) +<!-- --> +<sect>Writing to HFS Filesystems +<p> +Each of the values of the <tt>fork</tt> 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. +<p> +Regardless of the value of the <tt>fork</tt> 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: + <itemize> + <item>You can't change the uid or gid of files. + <item>You can't set the set-uid, set-gid or sticky permission bits. + <item>You can't clear the execute permission bits. + </itemize> +<p> +Likewise you can do virtually everything to a directory that you can to +a directory on another file system with the following exceptions: + <itemize> + <item>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. + <item>You can't change permissions on directories. + <item>You can't change the uid or gid of directories. + <item>You can't create multiple links to files. + <item>You can't create symlinks, device files, sockets or FIFOs. + </itemize> +<!-- --> +<sect1>Writing with fork=cap +<p> +Unlike the other schemes for representing forked files, the CAP scheme +presents the resource fork as an independent file; the resource fork +of <tt>./foo</tt> is <tt>./.resource/foo</tt>. 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. +<p> +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 <em>Inside Macintosh: More Macintosh +Toolbox</em>. <tt>hfs_fs</tt> knows nothing about this format and so +can do nothing to enforce it. +<p> +The current support for reading and writing is sufficient to allow +copying of entire directories with <tt>tar</tt>, as long as both the +source and destination are mounted with <tt>fork=cap</tt>. +<tt>tar</tt> may complain about being unable to change the +<tt>uid</tt>, <tt>gid</tt> or <tt>mode</tt> of files. This is normal +and is an unavoidable side effect of the having a single <tt>uid</tt>, +<tt>gid</tt> and <tt>umask</tt> for the entire filesystem. +<p> +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 <tt>foo</tt> to <tt>dir/bar</tt> you should +do the following: + <enum> + <item><tt>cp foo dir/bar</tt> + <item><tt>cp .resource/foo dir/.resource/bar</tt> + <item><tt>cp .finderinfo/foo dir/.finderinfo/bar</tt> + </enum> +You may get ``Operation not permitted'' errors from <tt>cp</tt> when +it tries to change the permissions on files. These errors can safely +be ignored. This method will work even if the file <tt>dir/bar</tt> +exists. +<p> +If you wish to move <tt>foo</tt> to <tt>dir/bar</tt> and <tt>foo</tt> +and <tt>dir</tt> are on the same filesystem then you only need to +execute <tt>mv foo dir/bar</tt> and the resource fork and the Finder's +metadata will move too. However, if <tt>foo</tt> and <tt>dir</tt> are +on different filesystem then this will lose the resource fork and +metadata. Therefore, it is safest to always move files as follows: + <enum> + <item><tt>cp foo dir/bar</tt> + <item><tt>cp .resource/foo dir/.resource/bar</tt> + <item><tt>cp .finderinfo/foo dir/.finderinfo/bar</tt> + <item><tt>rm foo</tt> + </enum> +You may get ``Operation not permitted'' errors from <tt>cp</tt> when +it tries to change the permissions on files. These errors can safely +be ignored. This method will work even if the file <tt>dir/bar</tt> +exists. +<p> +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 <tt>bar</tt> the same location, layout, +creation date and modify date as <tt>foo</tt> you simply execute +<tt>cp .finderinfo/foo .finderinfo/bar</tt>. +<p> +When copying an entire directory with <tt>cp -R</tt> you may also wish +to copy the metadata for the directory: + <enum> + <item><tt>cp -R foo bar</tt> + <item><tt>cp .finderinfo/foo .finderinfo/bar</tt> + </enum> +You may get ``Operation not permitted'' errors from <tt>cp</tt> when +it tries to change the permissions on files. These errors can safely +be ignored. +<!-- --> +<sect1>Writing with fork=double +<p> +The current support for reading and writing header files is sufficient +to allow copying of entire directories with <tt>tar</tt>, as long as +both the source and destination are mounted with <tt>fork=double</tt>. +<tt>tar</tt> may complain about being unable to change the +<tt>uid</tt>, <tt>gid</tt> or <tt>mode</tt> of files. This is normal +and is an unavoidable side effect of the having a single <tt>uid</tt>, +<tt>gid</tt> and <tt>umask</tt> for the entire filesystem. +<p> +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 <tt>foo</tt> to +<tt>dir/bar</tt> you should do the following: + <enum> + <item><tt>cp foo dir/bar</tt> + <item><tt>cp %foo dir/%bar</tt> + </enum> You may get ``Operation not permitted'' errors from +<tt>cp</tt> when it tries to change the permissions on files. These +errors can safely be ignored. This method will work even if the file +<tt>dir/bar</tt> exists. +<p> +If you wish to move <tt>foo</tt> to <tt>dir/bar</tt> and <tt>foo</tt> +and <tt>dir</tt> are on the same filesystem then you only need to +execute <tt>mv foo dir/bar</tt> and the header file will move too. +However, if <tt>foo</tt> and <tt>dir</tt> are on different filesystem +then this will lose the header file. Therefore, it is safest to +always move files as follows: + <enum> + <item><tt>cp foo dir/bar</tt> + <item><tt>cp %foo dir/%bar</tt> + <item><tt>rm foo</tt> + </enum> +You may get ``Operation not permitted'' errors from <tt>cp</tt> when +it tries to change the permissions on files. These errors can safely +be ignored. This method will work even if the file <tt>dir/bar</tt> +exists. +<p> +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 <tt>bar</tt> the same location, +layout, creation date and modify date as <tt>foo</tt> simply execute +<tt>cp %foo %bar</tt>. +<p> +When copying an entire directory with <tt>cp -R</tt> you may also wish +to copy the header file for the directory as well: + <enum> + <item><tt>cp -R foo bar</tt> + <item><tt>cp %foo %bar</tt> + </enum> +You may get ``Operation not permitted'' errors from <tt>cp</tt> when +it tries to change the permissions on files. These errors can safely +be ignored. +<!-- --> +<sect1>Writing with fork=netatalk +<p> +The current support for reading and writing header files is sufficient +to allow copying of entire directories with <tt>tar</tt>, as long as +both the source and destination are mounted <tt>fork=netatalk</tt>. +<tt>tar</tt> may complain about being unable to change the +<tt>uid</tt>, <tt>gid</tt> or <tt>mode</tt> of files. This is normal +and is an unavoidable side effect of the having a single <tt>uid</tt>, +<tt>gid</tt> and <tt>umask</tt> for the entire filesystem. +<p> +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 <tt>foo</tt> to +<tt>dir/bar</tt> you should do the following: + <enum> + <item><tt>cp foo dir/bar</tt> + <item><tt>cp .AppleDouble/foo dir/.AppleDouble/bar</tt> + </enum> +You may get ``Operation not permitted'' errors from <tt>cp</tt> when +it tries to change the permissions on files. These errors can safely +be ignored. This method will work even if the file <tt>dir/bar</tt> +exists. +<p> +If you wish to move <tt>foo</tt> to <tt>dir/bar</tt> and <tt>foo</tt> +and <tt>dir</tt> are on the same filesystem then you only need to +execute <tt>mv foo dir/bar</tt> and the header file will move too. +However, if <tt>foo</tt> and <tt>dir</tt> are on different filesystem +then this will lose the header file. Therefore, it is safest to +always move files as follows: + <enum> + <item><tt>cp foo dir/bar</tt> + <item><tt>cp .AppleDouble/foo dir/.AppleDouble/bar</tt> + <item><tt>rm foo</tt> + </enum> +You may get ``Operation not permitted'' errors from <tt>cp</tt> when +it tries to change the permissions on files. These errors can safely +be ignored. This method will work even if the file <tt>dir/bar</tt> +exists. +<p> +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 <tt>bar</tt> the same location, +layout, creation date and modify date as <tt>foo</tt> you simply +execute <tt>cp foo/.AppleDouble/.Parent bar/.AppleDouble/.Parent</tt>. +<p> +Because the <tt>fork=netatalk</tt> scheme holds the header file for a +directory within that directory, directories can safely be copied with +<tt>cp -R foo bar</tt> with no loss of information. However, +you may get ``Operation not permitted'' errors from <tt>cp</tt> when +it tries to change the permissions on files. These errors can safely +be ignored. +<!-- --> +<sect>A Guide to Special File Formats +<p> +Each of the values of the <tt>fork</tt> 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). +<!-- --> +<sect1>CAP .finderinfo Files +<p> +The Finder's metadata for the file <tt>./foo</tt> in held in the +file <tt>./.finderinfo/foo</tt>. The file has a fixed format defined +in <tt>hfs_fs.h</tt> as follows: +<tscreen><code> +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 */ +}; +</code></tscreen> +The type <tt>__u8</tt> is an unsigned character, and <tt>__u16</tt> is +an unsigned 16-bit integer. +<p> +Currently only the fields <tt>fi_fndr</tt>, <tt>fi_attr</tt>, +<tt>fi_ctime</tt> and <tt>fi_mtime</tt> 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. +<p> +The <tt>fi_fndr</tt> 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. +<p> +The <tt>fi_attr</tt> 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 <tt>0x01 +0xA0</tt>, which corresponds to setting the ``write-inhibit'', +``rename-inhibit'' and ``delete-inhibit'' bits. +<p> +The <tt>fi_ctime</tt> and <tt>fi_mtime</tt> 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. <!-- Is this correct? --> +<!-- --> +<sect1>AppleDouble Header Files +<p> +Both the <tt>fork=double</tt> and <tt>fork=netatalk</tt> schemes for +representing forked files use AppleDouble header files to contain the +resource fork and the Finder's metadata together in a single file. +<p> +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 <tt>fork=netatalk</tt> is available +from ??????. The version 2 format used when <tt>fork=double</tt> 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 :-). +<p> +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. +<p> +When a header file is opened it is initially presented with a default +header layout. You may write to the header and 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. +<p> +<tt>hfs_fs</tt> currently uses a fixed-size table to hold the +descriptors. Therefore you are limited to <tt>HFS_HDR_MAX</tt> +(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 in <tt>hfs_fs</tt> and will hopefully change sooner +rather than later. +<p> +The results of specifying overlapping entries is undefined and should +not be relied upon to remain unchanged from one version of +<tt>hfs_fs</tt> to the next. There is no valid reason to define +overlapping entries, so just don't do it! +<p> +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. +<p> +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 +<tt>hfs_fs</tt> may enforce the format more strictly. +<p> +Entry ids 1, 2, 7, 8, 9 and 10 (``Data Fork'', ``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 data and resource forks are, of course, +supported only for files, not directories. +<p> +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 of <tt>hfs_fs</tt> may +prevent it. +<p> +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. +<p> +All other entry ids are ignored. You may create descriptors for them; +in fact the default header layout when <tt>fork=netatalk</tt> 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. +<p> +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. +<p> +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. +<p> +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. +<p> +Writes beyond the end of the data or resource fork that extend into +empty space between entries or beyond the end of the file will extend +the corresponding 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. +<p> +Calling truncate() on a header file can change the length of either +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 either 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 corresponding entry is now entirely +beyond the end of the file. If the last entry in a header file is the +data or 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. +<!-- --> +<sect>Frequently Asked Questions (and their answers) +<p> +This is a quick and dirty attempt at answering some of the more common +questions I receive about <tt>hfs_fs</tt>. Additions are welcome. +<!-- --> +<sect1>What is HFS? +<p> +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 +by <tt>hfs_fs</tt>. +<!-- --> +<sect1>Does hfs_fs allow me to mount AppleShare volumes? +<p> +No, <tt>hfs_fs</tt> is for mounting local volumes only. I am not +aware of any software that allows Linux to act as an AppleShare client. +<!-- --> +<sect1>Why can I mount some HFS CDROMs but not others? +<p> +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. +<!-- --> +<sect1>What does ``only 1024-char blocks implemented (512)'' mean? +<p> +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. +<tt>hfs_fs</tt> only works with 512-byte blocks, and therefore doesn't +function with these devices. Eventually <tt>hfs_fs</tt> will be able to +use 1024-byte blocks when necessary. +<!-- --> +<sect1>Why do I get a message about a bad or unknown partition table? +<p> +The Linux kernel doesn't yet know anything about Macintosh partition +tables, so it gives this warning when it can't find a partition table it +recognizes. The decoding of Mac partition tables is done by +<tt>hfs_fs</tt>, so you should still be able to mount the disk. +<!-- --> +<sect1>Can I mount multiple HFS partitions from the same Macintosh disk? +<p> +Not simultaneously. Because the Linux kernel doesn't understand the +Macintosh partition table, <tt>hfs_fs</tt> must access the raw device. +Therefore, the kernel thinks the entire drive is in use and prevents +additional mounts on it. However, you can use the <tt>part=n</tt> +mount option to select which HFS partition to mount. +<!-- --> +<sect1>In what ways can I write to HFS volumes? +<p> +<tt>hfs_fs</tt> is as capable as the MS-DOS or VFAT filesystems, +except that certain things can only be done with a file's data fork. +<p> +You <bf>can</bf>: +<itemize> + <item> + Create, delete and rename directories and data forks of + files with the caveat that names are case insensitive + (so <tt>foo</tt> and <tt>Foo</tt> are the same file or + directory). + <!-- --> + <item> + Run Linux executables or shared libraries on an HFS disk if + they are stored in the data fork of a file. + <!-- --> + <item> + Read, write and truncate both forks of files and the + Finder's metadata of files and directories. + <!-- --> + <item> + Mmap data forks of files (and the resource + fork if the filesystem is mounted with the <tt>fork=cap</tt> + option). + <!-- --> + <item> + Toggle the 'w' permission bits (as a group) of data forks. + <!-- --> + <item> + Change the <tt>i_mtime</tt> of files and directories. +</itemize> +<p> +You <bf>cannot</bf>: +<itemize> + <item> + 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. + <!-- --> + <item> + Run Linux executables or shared libraries on an HFS disk + if they are stored in the resource fork of a file. + <!-- --> + <item> + Mmap the Finder's metadata (when <tt>fork=cap</tt>) or AppleDouble + header files (when <tt>fork=double</tt> or <tt>fork=netatalk</tt>). + <!-- --> + <item> + Change permissions on directories. + <!-- --> + <item> + Change the uid or gid of files or directories. + <!-- --> + <item> + Set the set-uid, set-gid or sticky permission bits. + <!-- --> + <item> + Create multiple links to files. + <!-- --> + <item> + Create symlinks, device files, sockets or FIFOs. +</itemize> +<!-- --> +<sect1>Does hfs_fs work with 400k or 800k Macintosh diskettes? +<p> +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. +<!-- --> +<sect1>How can I format an HFS volume? +<p> +Robert Leslie (<tt><htmlurl url="mailto:rob@mars.org" +name="rob@mars.org"></tt>) has written a package for working +with HFS volumes (like <tt>mtools</tt> plus a graphical interface). +One program in the package is <tt>hformat</tt> which can format +HFS volumes. The latest version can be found on +<url url="http://www.mars.org/home/rob/proj/hfs/" +name="the HFS Utilities home page">. +<!-- --> +<sect>Reporting Bugs +<p> +If you'd like any problems you encounter fixed, you'll need to provide +a detailed bug report. However, you should check the FAQ first to be +certain that your problem is not a known limitation of <tt>hfs_fs</tt>. +If your bug doesn't appear in the FAQ then you should e-mail me at +<tt><htmlurl url="mailto:hargrove@sccm.Stanford.EDU" +name="hargrove@sccm.Stanford.EDU"></tt>. +<!-- --> +<sect1>What Goes in a Bug Report +<p> +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: +<itemize> + <item> + The version of <tt>hfs_fs</tt> you are using. + <item> + The kernel version you are using. + <item> + The version of <tt>gcc</tt> you used to compile the module, including + whether it is producing ELF or a.out output. + <item> + The version of the module utilities used to load <tt>hfs.o</tt>. + <item> + Any unofficial kernel patches or loadable modules you are using. + <item> + The type of media you are working with + (floppy, CDROM, ZIP Drive, etc.). + <item> + 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.) +</itemize> +<p> +There is a script, <tt>BUG_INFO</tt>, in the <tt>hfs_fs</tt> source directory +that will attempt to determine the first four items for you. +<!-- --> +<sect1>How to Report a Kernel Oops or GPF +<p> +If you encounter a bug that causes a kernel Oops or a General Protection +Fault then you'll need to collect some information for the bug report +before you reboot. +It is important that you do this before +rebooting, since the module is unlikely to be loaded at the same address +after the reboot. +<p> +You should include all the information that the kernel prints to the console +or to the system logs. However, the <tt>EIP</tt> and <tt>Stack Trace</tt> +are addresses in <em>your</em> kernel and mean nothing to me without +more information. Using your <tt>System.map</tt> file (or either +<tt>ksymoops</tt> or <tt>klogd</tt>) determine which functions the +<tt>EIP</tt> and <tt>Stack Trace</tt> are in. If you do this by hand using +your <tt>System.map</tt> file then the correct symbol is the one +of type <tt>t</tt> or <tt>T</tt> with the largest address less than or +equal to the one you are resolving. +<p> +If the Oops or GPF was in the <tt>hfs_fs</tt> code then the <tt>EIP</tt> and +the top levels of the <tt>Stack Trace</tt> will be in a loadable module, rather +than in the kernel proper. So, their symbols will not be in the file +<tt>System.map</tt>. +Therefore, you will need to use <tt>/proc/ksyms</tt>, or a +loadmap produced by passing the <tt>-m</tt> option to <tt>insmod</tt>, to +locate those symbols. Keep in mind that neither of these files is sorted. +<!-- --> +<sect>Legal Notices +<sect1>This Document +<p> +This document is Copyright © 1996, 1997 by Paul H. Hargrove. +<p> +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. +<p> +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. +<p> +Permission is granted to copy and distribute translations of this +document into another language, under the conditions specified above +for modified versions. +<p> +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. +<!-- --> +<sect1>The Software +<p> +The <tt>hfs_fs</tt> software is Copyright © 1994-1997 by Paul H. Hargrove. +<p> +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. +<p> +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. +<p> +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. +<!-- XXX: add a URL for the GPL? --> +<!-- --> +<sect2>The Columbia AppleTalk Package for UNIX +<p> +The source code distribution of the Columbia AppleTalk Package for +UNIX, version 6.0, (CAP) was used as a <em>specification</em> of the +location and format of files used by CAP's Aufs. No code from CAP +appears in <tt>hfs_fs</tt>. <tt>hfs_fs</tt> is not a work ``derived'' +from CAP in the sense of intellectual property law. +<!-- --> +<sect2>Netatalk +<p> +The source code distributions of Netatalk, versions 1.3.3b2 and 1.4b2, +were used as a <em>specification</em> of the location and format of +files used by Netatalk's afpd. No code from Netatalk appears in +<tt>hfs_fs</tt>. <tt>hfs_fs</tt> is not a work ``derived'' from +Netatalk in the sense of intellectual property law. +<!-- --> +<sect1>Trademarks +<p> +<itemize> + <item> + ``Finder'' is a trademarks of Apple Computer, Inc. + <!-- --> + <item> + ``Apple'', ``AppleShare'', ``AppleTalk'' and ``Macintosh'' are + registered trademarks of Apple Computer, Inc. + <!-- --> + <item> + ``Microsoft'' and ``MS-DOS'' are registered trademarks + of Microsoft Corporation. + <!-- --> + <item> + All other trademarks are the property of their respective owners. +</itemize> +</article> diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/README.txt linux-2.0.29/fs/hfs/README.txt --- linux.vanilla/fs/hfs/README.txt Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/README.txt Wed Apr 9 04:41:47 1997 @@ -0,0 +1,1259 @@ + Macintosh HFS Filesystem for Linux + Paul H. Hargrove, hargrove@sccm.Stanford.EDU + version 0.8.3, 08 Apr 1997 + + This document describes version 0.8.3 of hfs_fs, a Linux kernel load- + able module implementing the Macintosh HFS filesystem. The most cur- + rent versions of this document and the software are kept at The HFS + for Linux Page <http://www-sccm.Stanford.EDU/~hargrove/HFS/>. + ______________________________________________________________________ + + Table of Contents: + + 1. Introduction + + 2. System Requirements + + 3. Installation + + 3.1. Compiling the loadable module + + 3.2. Installing the module in the modules directory (optional) + + 3.3. Loading the module into the running kernel + + 3.4. Using the module with versioned symbols + + 4. Mounting HFS Filesystems + + 4.1. afpd + + 4.2. case={asis, lower} + + 4.3. conv={auto, binary, text} + + 4.4. creator=cccc + + 4.5. fork={cap, double, netatalk} + + 4.6. gid=n + + 4.7. names={7bit, 8bit, alpha, cap, latin, netatalk, trivial} + + 4.8. part=n + + 4.9. quiet + + 4.10. type=cccc + + 4.11. uid=n + + 4.12. umask=n + + 5. Writing to HFS Filesystems + + 5.1. Writing with fork=cap + + 5.2. Writing with fork=double + + 5.3. Writing with fork=netatalk + + 6. A Guide to Special File Formats + + 6.1. CAP .finderinfo Files + + 6.2. AppleDouble Header Files + + 7. Frequently Asked Questions (and their answers) + + 7.1. What is HFS? + + 7.2. Does hfs_fs allow me to mount AppleShare volumes? + + 7.3. Why can I mount some HFS CDROMs but not others? + + 7.4. What does ``only 1024-char blocks implemented (512)'' mean? + + 7.5. Why do I get a message about a bad or unknown partition table? + + 7.6. Can I mount multiple HFS partitions from the same Macintosh + disk? + + 7.7. In what ways can I write to HFS volumes? + + 7.8. Does hfs_fs work with 400k or 800k Macintosh diskettes? + + 7.9. How can I format an HFS volume? + + 8. Reporting Bugs + + 8.1. What Goes in a Bug Report + + 8.2. How to Report a Kernel Oops or GPF + + 9. Legal Notices + + 9.1. This Document + + 9.2. The Software + + 9.2.1. The Columbia AppleTalk Package for UNIX + + 9.2.2. Netatalk + + 9.3. Trademarks + ______________________________________________________________________ + + 11.. IInnttrroodduuccttiioonn + + This package is a Macintosh HFS filesystem module for Linux. It + allows you to read and write Macintosh 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.. 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.) + + In theory the code is endian-independent, but is tested most + extensively on Intel platforms. It is also known to compile on m68k, + PPC and Alpha machines, but is not as extensively tested on any of + these platforms. + + 33.. IInnssttaallllaattiioonn + + The hfs_fs code is not yet 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. + + 33..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. + + 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 and + linux/version.h. + + 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 + hfs_fs.h. Remove the text ``&& !defined(__alpha__)'' from the end of + line 217. + + 33..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. + + 33..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. + + 33..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. + + 44.. MMoouunnttiinngg HHFFSS FFiilleessyysstteemmss + + Once you have installed the 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 + structure. The values for the multiple-choice options (case, conv, + fork and names) can be abbreviated by their first character. + + 44..11.. aaffppdd + + If included in the options, then the behavior of hfs_fs 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. + + 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. + 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 likely that hfs_fs's afpd mode will be + compatible with afpd from Netatalk version 1.4 when it is released. + + 44..22.. ccaassee=={{aassiiss,, lloowweerr}} + + default value: asis + + This option determines if Mac filenames are presented in their + original case or in all lowercase. Filename matching is not affected, + 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. + + 44..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. + + Please e-mail me if you know of any other types that indicate + pure text files. + + 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. + + 44..44.. ccrreeaattoorr==cccccccc + + default value: ``????'' + + Specifies the 4-character string specifying the Finder's Creator for + new files. + + 44..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. + + Documentation on the format of file containing the Finder's + metadata is included 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 documented in + ``AppleSingle/AppleDouble Formats: Developer's Note (9/94)'', + available from from Apple's Developer Services Page + <http://devworld.apple.com>. + + Note that the naming convention for the header file can cause + name conflicts. For instance, using Apple's 7-bit ASCII name + conversion 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 module 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. Their format is documented 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. + + 44..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.) + + 44..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 (/). + + 44..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. + + Note that in versions before 0.8.3 partitions were numbered from 1. + + 44..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.) + + 44..1100.. ttyyppee==cccccccc + + default value: ``????'' + + Specifies the 4-character string specifying the Finder's Type for new + files. + 44..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.) + + 44..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.) + + 55.. 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. + + 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. + + 55..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. hfs_fs + knows nothing about this format and so can do 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. + + 55..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. + + 55..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. + + 66.. 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). + + 66..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. + + 66..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 and 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. + + hfs_fs 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 in + hfs_fs 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 hfs_fs 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 + hfs_fs may enforce the format more strictly. + + Entry ids 1, 2, 7, 8, 9 and 10 (``Data Fork'', ``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 data and resource forks are, of course, + supported only for files, not 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 of hfs_fs 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 data or resource fork that extend into + empty space between entries or beyond the end of the file will extend + the corresponding 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 either + 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 either 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 corresponding entry is now entirely + beyond the end of the file. If the last entry in a header file is the + data or 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. + + 77.. FFrreeqquueennttllyy AAsskkeedd QQuueessttiioonnss ((aanndd tthheeiirr aannsswweerrss)) + + This is a quick and dirty attempt at answering some of the more common + questions I receive about hfs_fs. Additions are welcome. + + 77..11.. 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 by + hfs_fs. + + 77..22.. DDooeess hhffss__ffss aallllooww mmee ttoo mmoouunntt AApppplleeSShhaarree vvoolluummeess?? + + No, hfs_fs is for mounting local volumes only. I am not aware of any + software that allows Linux to act as an AppleShare client. + 77..33.. 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. + + 77..44.. 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. hfs_fs only works with 512-byte blocks, and + therefore doesn't function with these devices. Eventually hfs_fs will + be able to use 1024-byte blocks when necessary. + + 77..55.. WWhhyy ddoo II ggeett aa mmeessssaaggee aabboouutt aa bbaadd oorr uunnkknnoowwnn ppaarrttiittiioonn ttaabbllee?? + + The Linux kernel doesn't yet know anything about Macintosh partition + tables, so it gives this warning when it can't find a partition table + it recognizes. The decoding of Mac partition tables is done by + hfs_fs, so you should still be able to mount the disk. + + 77..66.. CCaann II mmoouunntt mmuullttiippllee HHFFSS ppaarrttiittiioonnss ffrroomm tthhee ssaammee MMaacciinnttoosshh + ddiisskk?? + + Not simultaneously. Because the Linux kernel doesn't understand the + Macintosh partition table, hfs_fs must access the raw device. + Therefore, the kernel thinks the entire drive is in use and prevents + additional mounts on it. However, you can use the part=n mount option + to select which HFS partition to mount. + + 77..77.. IInn wwhhaatt wwaayyss ccaann II wwrriittee ttoo HHFFSS vvoolluummeess?? + + hfs_fs 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. + + 77..88.. DDooeess hhffss__ffss 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. + + 77..99.. HHooww ccaann II ffoorrmmaatt aann HHFFSS vvoolluummee?? + + Robert Leslie (rob@mars.org) has written a package for working with + HFS volumes (like mtools plus a graphical interface). One program in + the package is hformat which can format HFS volumes. The latest + version can be found on the HFS Utilities home page + <http://www.mars.org/home/rob/proj/hfs/>. + + 88.. 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 first to be + certain that your problem is not a known limitation of hfs_fs. If + your bug doesn't appear in the FAQ then you should e-mail me at + hargrove@sccm.Stanford.EDU. + + 88..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 hfs_fs you are using. + + +o The kernel version you are using. + + +o The version of gcc you used to compile the module, including + whether it is producing ELF or a.out output. + + +o The version of the module utilities used to load hfs.o. + + +o Any unofficial kernel patches or loadable modules you are using. + + +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.) + + There is a script, BUG_INFO, in the hfs_fs source directory that will + attempt to determine the first four items for you. + 88..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 information for the + bug report before you reboot. It 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 the Oops or GPF was in the hfs_fs 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. + Keep in mind that neither of these files is sorted. + + 99.. LLeeggaall NNoottiicceess + + 99..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. + + 99..22.. TThhee SSooffttwwaarree + + The hfs_fs software 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. + + 99..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 + hfs_fs. hfs_fs is not a work ``derived'' from CAP in the sense of + intellectual property law. + + 99..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 hfs_fs. hfs_fs + is not a work ``derived'' from Netatalk in the sense of intellectual + property law. + + 99..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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/TODO linux-2.0.29/fs/hfs/TODO --- linux.vanilla/fs/hfs/TODO Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/TODO Wed Apr 9 04:41:47 1997 @@ -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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/balloc.c linux-2.0.29/fs/hfs/balloc.c --- linux.vanilla/fs/hfs/balloc.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/balloc.c Thu Apr 10 12:22:02 1997 @@ -0,0 +1,433 @@ +/* + * 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 <linux/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_set_bit(0, bnode_key(retval, 1)); + 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_u32 bmap_size; /* number of bits in the current bitmap */ + hfs_u32 *bmap; /* address of the hfs_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 (;;) { + bmap_size = 8*bnode_rsize(bn, bn->ndNRecs); + + if (bitnr < bmap_size) { + 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 -= bmap_size; + } + + /* bitmap is always on a 32-bit boundary: */ + bmap = (hfs_u32 *)bnode_key(bn, bn->ndNRecs)+(bitnr>>5); + bitnr %= 32; + if ((set && hfs_set_bit(bitnr, bmap)) || + (!set && !hfs_clear_bit(bitnr, bmap))) { + 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_u32 bmap_size; /* number of bits in current bitmap */ + hfs_u16 first; /* the first clear bit in this bnode */ + hfs_u32 *bitmap; /* address of the bitmap in this bnode */ + + bn = &tree->head; + for (;;) { + bmap_size = 8*bnode_rsize(bn, bn->ndNRecs); + /* bitmap is always on a 32-bit boundary: */ + bitmap = (hfs_u32 *)bnode_key(bn, bn->ndNRecs); + + /* search the current node */ + first = hfs_find_first_zero_bit(bitmap, bmap_size); + if (first < bmap_size) { + 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 += bmap_size; + } + + if ((bitnr += first) >= tree->bthNNodes) { + hfs_warn("hfs_bnode_alloc: no free nodes found, " + "count wrong?\n"); + goto bail; + } + + if (hfs_set_bit(first % 32, bitmap + (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 += 8 * bnode_rsize(bn, bn->ndNRecs); + + 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/bdelete.c linux-2.0.29/fs/hfs/bdelete.c --- linux.vanilla/fs/hfs/bdelete.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/bdelete.c Thu Apr 10 12:21:52 1997 @@ -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 <linux/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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/bfind.c linux-2.0.29/fs/hfs/bfind.c --- linux.vanilla/fs/hfs/bfind.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/bfind.c Thu Apr 10 12:35:26 1997 @@ -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 <linux/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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/bins_del.c linux-2.0.29/fs/hfs/bins_del.c --- linux.vanilla/fs/hfs/bins_del.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/bins_del.c Thu Apr 10 12:23:26 1997 @@ -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 <linux/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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/binsert.c linux-2.0.29/fs/hfs/binsert.c --- linux.vanilla/fs/hfs/binsert.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/binsert.c Thu Apr 10 12:23:41 1997 @@ -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 <linux/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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/bitmap.c linux-2.0.29/fs/hfs/bitmap.c --- linux.vanilla/fs/hfs/bitmap.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/bitmap.c Thu Apr 10 12:23:52 1997 @@ -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 <linux/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, max_bits); + 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, *num_bits); + 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_next_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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/bitops.c linux-2.0.29/fs/hfs/bitops.c --- linux.vanilla/fs/hfs/bitops.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/bitops.c Thu Apr 10 12:24:04 1997 @@ -0,0 +1,160 @@ +/* + * 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 <linux/hfs.h> + +/*================ Global functions ================*/ + +/* + * hfs_find_first_zero_bit() + * + * Description: + * Given the address of a block of memory find the first (by + * left-to-right ordering) zero bit in the first 'size' bits. + */ +hfs_u32 hfs_find_first_zero_bit(const void * addr, hfs_u32 size) +{ + const hfs_u32 *start = (const hfs_u32 *)addr; + const hfs_u32 *end = start + ((size+31) >> 5); + const hfs_u32 *curr = start; + int bit = 0; + + while (curr < end) { + if (*curr == ~((hfs_u32)0)) { + ++curr; + } else { + while (hfs_test_bit(bit, curr)) { + ++bit; + } + break; + } + } + return ((curr-start)<<5) | bit; +} + +/* + * hfs_find_next_zero_bit() + * + * Description: + * Given the address of a block of memory find the next (by + * left-to-right bit-ordering) zero bit in the first 'size' bits. + */ +hfs_u32 hfs_find_next_zero_bit(const void * addr, hfs_u32 size, hfs_u32 offset) +{ + const hfs_u32 *start = (const hfs_u32 *)addr; + const hfs_u32 *end = start + ((size+31) >> 5); + const hfs_u32 *curr = start + (offset>>5); + int bit = offset % 32; + + if (size < offset) { + return size; + } + + /* finish up first partial hfs_u32 */ + if (bit != 0) { + do { + if (!hfs_test_bit(bit, curr)) { + goto done; + } + ++bit; + } while (bit < 32); + bit = 0; + ++curr; + } + + /* skip fully set hfs_u32 */ + while (*curr == ~((hfs_u32)0)) { + if (curr == end) { + goto done; + } else { + ++curr; + } + } + + /* check final partial hfs_u32 */ + do { + if (!hfs_test_bit(bit, curr)) { + goto done; + } + ++bit; + } while (bit<32); + +done: + return ((curr-start)<<5) | bit; +} + +/* + * 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) + * starting at that location, up to 'max'. + */ +hfs_u32 hfs_count_zero_bits(const void *addr, hfs_u32 size, + hfs_u32 offset, hfs_u32 max) +{ + const hfs_u32 *curr = (const hfs_u32 *)addr + (offset>>5); + const hfs_u32 *end = (const hfs_u32 *)addr + ((size+31)>>5); + int bit = offset % 32; + hfs_u32 count = 0; + + /* fix up max to avoid running off end */ + if (max > (size - offset)) { + max = size - offset; + } + + /* finish up first partial hfs_u32 */ + if (bit != 0) { + do { + if (hfs_test_bit(bit, curr)) { + goto done; + } + ++count; + ++bit; + } while (bit<32); + ++curr; + } + + /* eat up any full hfs_u32s of zeros */ + if (size > (offset + max)) { + size = offset + max; + } + while (*curr == ((hfs_u32)0)) { + if (curr == end) { + goto done; + } else { + ++curr; + count += 32; + } + } + + /* count bits in the last hfs_u32 */ + bit = 0; + do { + if (hfs_test_bit(bit, curr)) { + goto done; + } + ++count; + ++bit; + } while (bit<32); + +done: + if (count > max) { + count = max; + } + return count; +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/bnode.c linux-2.0.29/fs/hfs/bnode.c --- linux.vanilla/fs/hfs/bnode.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/bnode.c Thu Apr 10 12:24:22 1997 @@ -0,0 +1,524 @@ +/* + * 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 <linux/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; + + /* 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); + } + + /* 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/brec.c linux-2.0.29/fs/hfs/brec.c --- linux.vanilla/fs/hfs/brec.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/brec.c Thu Apr 10 12:24:37 1997 @@ -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 <linux/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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/btree.c linux-2.0.29/fs/hfs/btree.c --- linux.vanilla/fs/hfs/btree.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/btree.c Thu Apr 10 12:25:31 1997 @@ -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 <linux/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; lcv<HFS_CACHELEN; ++lcv) { +#if defined(DEBUG_BNODES) || defined(DEBUG_ALL) + hfs_warn("deleting nodes from bucket %d:\n", lcv); +#endif + hfs_bnode_ditch(bt->cache[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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/catalog.c linux-2.0.29/fs/hfs/catalog.c --- linux.vanilla/fs/hfs/catalog.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/catalog.c Thu Apr 10 12:25:45 1997 @@ -0,0 +1,1587 @@ +/* + * 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 <linux/hfs.h> + +/*================ Variable-like macros ================*/ + +/* 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; +} + +/* + * 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; + + 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) { + 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 key1<key2, positive if key1>key2, 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; + 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/dir.c linux-2.0.29/fs/hfs/dir.c --- linux.vanilla/fs/hfs/dir.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/dir.c Thu Apr 10 12:25:59 1997 @@ -0,0 +1,379 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ 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 inode *tmp = dir->sys_entry[i]; + if (tmp) { + 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; + } + } +} + +/* + * 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 inode *tmp = dir->sys_entry[i]; + if (tmp) { + 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_inodes_deleted() + * + * Update inodes associated with a deleted entry to reflect its deletion. + */ +static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, int is_dir) +{ + int i; + + for (i = 0; i < 4; ++i) { + struct inode *tmp = entry->sys_entry[i]; + if (tmp) { + if (is_dir && S_ISDIR(tmp->i_mode)) { + tmp->i_size = 0; + } + tmp->i_nlink = 0; + tmp->i_ctime = CURRENT_TIME; + } + } +} + +/*================ 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 inode * inode, struct file * filp, + char *buf, hfs_rwarg_t count) +{ + 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, const char * name, int len, int mode, + struct inode ** result) +{ + struct hfs_cat_entry *entry = HFS_I(dir)->entry; + struct hfs_cat_entry *new; + struct hfs_cat_key key; + int error; + + *result = NULL; + + /* build the key, checking against reserved names */ + if (build_key(&key, dir, 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 */ + *result = __hfs_iget(new, HFS_I(dir)->file_type, 0); + if (!(*result)) { + /* XXX correct error? */ + error = -EIO; + } + } + + iput(dir); + 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, const char * name, int len, int mode) +{ + struct hfs_cat_entry *entry = HFS_I(parent)->entry; + struct hfs_cat_key key; + int error; + + /* build the key, checking against reserved names */ + if (build_key(&key, parent, name, len)) { + error = -EEXIST; + } else { + /* try to create the directory */ + error = hfs_cat_mkdir(entry, &key, NULL); + } + + if (!error) { + update_dirs_plus(entry, 1); + } + + iput(parent); + 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, const char *name, int len, int mode, int rdev) +{ + int error; + struct inode *inode; + + if (!dir) { + error = -ENOENT; + } else if (S_ISREG(mode)) { + error = hfs_create(dir, name, len, mode, &inode); + if (!error) { + iput(inode); + } + } 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, const char * name, int len) +{ + 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, 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, 0); + update_dirs_minus(entry, 0); + } + + hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ + iput(dir); + 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, const char * name, int len) +{ + 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, name, len)) { + error = -EPERM; + } else if (!(victim = hfs_cat_get(entry->mdb, &key))) { + error = -ENOENT; + } else if ((entry == victim) || + (entry->sys_entry[0] && entry->sys_entry[0]->i_mount) || + (entry->sys_entry[1] && entry->sys_entry[1]->i_mount) || + (entry->sys_entry[2] && entry->sys_entry[2]->i_mount) || + (entry->sys_entry[3] && entry->sys_entry[3]->i_mount)) { + error = -EPERM; + } else if (victim->type != HFS_CDR_DIR) { + error = -ENOTDIR; + } else if (!(error = hfs_cat_delete(entry, victim, 1))) { + mark_inodes_deleted(victim, 1); + update_dirs_minus(entry, 1); + } + + hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ + iput(parent); + 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. + */ +int hfs_rename(struct inode *old_dir, const char * old_name, int old_len, + struct inode *new_dir, const char * new_name, int new_len, + int must_be_dir) +{ + 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_name, old_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 (must_be_dir && (victim->type != HFS_CDR_DIR)) { + error = -ENOENT; + } else if (build_key(&key, new_dir, new_name, new_len)) { + error = -EPERM; + } else if (!(error = hfs_cat_move(old_parent, new_parent, + victim, &key, &deleted))) { + int is_dir = (victim->type == HFS_CDR_DIR); + + update_dirs_minus(old_parent, is_dir); + if (deleted) { + mark_inodes_deleted(deleted, is_dir); + hfs_cat_put(deleted); + } else { + update_dirs_plus(new_parent, is_dir); + } + } + + hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ + iput(old_dir); + iput(new_dir); + return error; +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/dir_cap.c linux-2.0.29/fs/hfs/dir_cap.c --- linux.vanilla/fs/hfs/dir_cap.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/dir_cap.c Thu Apr 10 12:26:14 1997 @@ -0,0 +1,368 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ Forward declarations ================*/ + +static int cap_lookup(struct inode *, const char *, int, struct inode **); +static int cap_readdir(struct inode *, 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, const char * name, + int len, struct inode ** result) +{ + 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); + + if (len && !name) { + *result = NULL; + iput(dir); + return -EINVAL; + } + + /* Perform name-mangling */ + hfs_nameout(dir, &cname, name, len); + + /* Check for "." */ + if (hfs_streq(&cname, DOT)) { + /* this little trick skips the iget and iput */ + *result = 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, 0); + 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, 1); + goto done; + } else if (hfs_streq(&cname, DOT_FINDERINFO)) { + ++entry->count; /* __hfs_iget() eats one */ + inode = __hfs_iget(entry, HFS_CAP_FDIR, 1); + 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, 0); + goto done; + } + } + + /* Do an hfs_iget() on the mangled name. */ + hfs_cat_build_key(entry->cnid, &cname, &key); + inode = hfs_iget(entry->mdb, &key, HFS_I(dir)->file_type); + + /* Don't return a resource fork for a directory */ + if (inode && (dtype == HFS_CAP_RDIR) && + (HFS_I(inode)->entry->type == HFS_CDR_DIR)) { + iput(inode); + inode = NULL; + } + +done: + iput(dir); + *result = inode; + return inode ? 0 : -ENOENT; +} + +/* + * 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 inode * dir, struct file * filp, + void * dirent, filldir_t filldir) +{ + ino_t type; + int skip_dirs; + struct hfs_brec brec; + struct hfs_cat_entry *entry; + + 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; +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/dir_dbl.c linux-2.0.29/fs/hfs/dir_dbl.c --- linux.vanilla/fs/hfs/dir_dbl.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/dir_dbl.c Thu Apr 10 12:26:25 1997 @@ -0,0 +1,440 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ Forward declarations ================*/ + +static int dbl_lookup(struct inode *, const char *, int, struct inode **); +static int dbl_readdir(struct inode *, struct file *, void *, filldir_t); +static int dbl_create(struct inode *, const char *, int, int, struct inode **); +static int dbl_mkdir(struct inode *, const char *, int, int); +static int dbl_mknod(struct inode *, const char *, int, int, int); +static int dbl_unlink(struct inode *, const char *, int); +static int dbl_rmdir(struct inode *, const char *, int); +static int dbl_rename(struct inode *, const char *, int, + struct inode *, const char *, int, int); + +/*================ 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, const char * name, + int len, struct inode ** result) +{ + 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; + + if (len && !name) { + *result = NULL; + iput(dir); + return -EINVAL; + } + + /* Perform name-mangling */ + hfs_nameout(dir, &cname, name, len); + + /* Check for "." */ + if (hfs_streq(&cname, DOT)) { + /* this little trick skips the iget and iput */ + *result = dir; + return 0; + } + + /* Check for "..". */ + if (hfs_streq(&cname, DOT_DOT)) { + inode = __hfs_iget(hfs_cat_parent(entry), HFS_DBL_DIR, 0); + 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, 0); + goto done; + } + + /* Do an hfs_iget() on the mangled name. */ + hfs_cat_build_key(entry->cnid, &cname, &key); + inode = hfs_iget(entry->mdb, &key, HFS_DBL_NORM); + + /* Try as a header if not found and first character is '%' */ + if (!inode && (name[0] == '%')) { + hfs_nameout(dir, &cname, name+1, len-1); + hfs_cat_build_key(entry->cnid, &cname, &key); + inode = hfs_iget(entry->mdb, &key, HFS_DBL_HDR); + } + +done: + iput(dir); + *result = inode; + return inode ? 0 : -ENOENT; +} + +/* + * 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 inode * dir, struct file * filp, + void * dirent, filldir_t filldir) +{ + struct hfs_brec brec; + struct hfs_cat_entry *entry; + + 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)) { + ino_t ino; + int is_hdr = (filp->f_pos & 1); + unsigned int len; + unsigned char tmp_name[HFS_NAMEMAX + 1]; + + 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, const char * name, int len, + int mode, struct inode **result) +{ + int error; + + *result = NULL; + if (is_hdr(dir, name, len)) { + iput(dir); + error = -EEXIST; + } else { + error = hfs_create(dir, name, len, mode, result); + } + 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, const char * name, + int len, int mode) +{ + int error; + + if (is_hdr(parent, name, len)) { + iput(parent); + error = -EEXIST; + } else { + error = hfs_mkdir(parent, name, len, 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, const char *name, + int len, int mode, int rdev) +{ + int error; + + if (is_hdr(dir, name, len)) { + iput(dir); + error = -EEXIST; + } else { + error = hfs_mknod(dir, name, len, 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, const char * name, int len) +{ + int error; + + ++dir->i_count; + error = hfs_unlink(dir, name, len); + if ((error == -ENOENT) && is_hdr(dir, name, len)) { + error = -EPERM; + } + iput(dir); + 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, const char * name, int len) +{ + int error; + + ++parent->i_count; + error = hfs_rmdir(parent, name, len); + if ((error == -ENOENT) && is_hdr(parent, name, len)) { + error = -ENOTDIR; + } + iput(parent); + 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. + */ +static int dbl_rename(struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) +{ + int error; + + if (is_hdr(new_dir, new_name, new_len)) { + error = -EPERM; + } else { + ++old_dir->i_count; + ++new_dir->i_count; + error = hfs_rename(old_dir, old_name, old_len, + new_dir, new_name, new_len, must_be_dir); + if ((error == -ENOENT) && !must_be_dir && + is_hdr(old_dir, old_name, old_len)) { + error = -EPERM; + } + } + iput(old_dir); + iput(new_dir); + return error; +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/dir_nat.c linux-2.0.29/fs/hfs/dir_nat.c --- linux.vanilla/fs/hfs/dir_nat.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/dir_nat.c Thu Apr 10 12:26:34 1997 @@ -0,0 +1,459 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ Forward declarations ================*/ + +static int nat_lookup(struct inode *, const char *, int, struct inode **); +static int nat_readdir(struct inode *, struct file *, void *, filldir_t); +static int nat_rmdir(struct inode *, const char *, int); +static int nat_hdr_unlink(struct inode *, const char *, int); +static int nat_hdr_rename(struct inode *, const char *, int, + struct inode *, const char *, int, int); + +/*================ 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 */ +}; + +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 */ +}; + +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 */ +}; + +/*================ 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, const char * name, + int len, struct inode ** result) +{ + 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); + + if (len && !name) { + *result = NULL; + iput(dir); + return -EINVAL; + } + + /* Perform name-mangling */ + hfs_nameout(dir, &cname, name, len); + + /* Check for "." */ + if (hfs_streq(&cname, DOT)) { + /* this little trick skips the iget and iput */ + *result = 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, 0); + 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, 1); + 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, 0); + goto done; + } + } + + /* Do an hfs_iget() on the mangled name. */ + hfs_cat_build_key(entry->cnid, &cname, &key); + inode = hfs_iget(entry->mdb, &key, HFS_I(dir)->file_type); + + /* 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: + iput(dir); + *result = inode; + return inode ? 0 : -ENOENT; +} + +/* + * 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 inode * dir, struct file * filp, + void * dirent, filldir_t filldir) +{ + ino_t type; + int skip_dirs; + struct hfs_brec brec; + struct hfs_cat_entry *entry; + + 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; +} + +/* + * 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, const char *name, int len) +{ + struct hfs_cat_entry *entry = HFS_I(parent)->entry; + struct hfs_name cname; + int error; + + hfs_nameout(parent, &cname, 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; + } + iput(parent); + } else { + error = hfs_rmdir(parent, name, len); + } + 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, const char *name, int len) +{ + 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, 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) { + hfs_cat_put(victim); + } else { + error = -ENOENT; + } + } + } + iput(dir); + 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, const char *old_name, + int old_len, struct inode *new_dir, + const char *new_name, int new_len, int must_be_dir) +{ + struct hfs_cat_entry *entry = HFS_I(old_dir)->entry; + int error = 0; + + if (!HFS_SB(old_dir->i_sb)->s_afpd) { + error = -EPERM; + } else { + struct hfs_name cname; + + hfs_nameout(old_dir, &cname, old_name, old_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) { + hfs_cat_put(victim); + } else { + error = -ENOENT; + } + } + + if (!error && (HFS_ITYPE(new_dir->i_ino) != HFS_NAT_HDIR)) { + error = -EPERM; + } + } + iput(old_dir); + iput(new_dir); + return error; +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/extent.c linux-2.0.29/fs/hfs/extent.c --- linux.vanilla/fs/hfs/extent.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/extent.c Thu Apr 10 12:29:02 1997 @@ -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 <linux/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; j<end; ++j) { + if (hfs_buffer_ok(buf = hfs_buffer_get(mdb->sys_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 key1<key2, positive if key1>key2, 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/file.c linux-2.0.29/fs/hfs/file.c --- linux.vanilla/fs/hfs/file.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/file.c Thu Apr 10 12:29:13 1997 @@ -0,0 +1,519 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ Forward declarations ================*/ + +static hfs_rwret_t hfs_file_read(struct inode *, struct file *, char *, + hfs_rwarg_t); +static hfs_rwret_t hfs_file_write(struct inode *, struct file *, const char *, + hfs_rwarg_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 */ +}; + +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 */ +}; + +/*================ 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 inode * inode, struct file * filp, + char * buf, hfs_rwarg_t count) +{ + 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; + } + if (filp->f_pos >= HFS_FORK_MAX) { + return 0; + } + pos = filp->f_pos; + size = inode->i_size; + if (pos > size) { + left = 0; + } else { + left = size - pos; + } + if (left > count) { + left = count; + } + if (left <= 0) { + return 0; + } + read = hfs_do_read(inode, HFS_I(inode)->fork, pos, + buf, left, filp->f_reada != 0); + if (read > 0) { + filp->f_pos += 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 inode * inode, struct file * filp, + const char * buf, hfs_rwarg_t count) +{ + struct hfs_fork *fork = HFS_I(inode)->fork; + hfs_s32 written; + + if (!S_ISREG(inode->i_mode)) { + hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode); + return -EINVAL; + } + if (filp->f_flags & O_APPEND) { + filp->f_pos = inode->i_size; + } + if (filp->f_pos >= HFS_FORK_MAX) { + return 0; + } + if (count > HFS_FORK_MAX) { + count = HFS_FORK_MAX; + } + written = hfs_do_write(inode, fork, filp->f_pos, buf, count); + if (written > 0) { + filp->f_pos += written; + if (filp->f_pos > inode->i_size) { + inode->i_size = filp->f_pos; + } + } + 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 inode **inodes = entry->sys_entry; + int i; + + if (entry->u.file.flags & HFS_FIL_LOCK) { + for (i = 0; i < 4; ++i) { + if (inodes[i]) { + inodes[i]->i_mode &= ~S_IWUGO; + } + } + } else { + for (i = 0; i < 4; ++i) { + if (inodes[i]) { + inodes[i]->i_mode |= S_IWUGO; + inodes[i]->i_mode &= + ~HFS_SB(inodes[i]->i_sb)->s_umask; + } + } + } +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/file_cap.c linux-2.0.29/fs/hfs/file_cap.c --- linux.vanilla/fs/hfs/file_cap.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/file_cap.c Thu Apr 10 12:29:24 1997 @@ -0,0 +1,293 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ Forward declarations ================*/ + +static hfs_rwret_t cap_info_read(struct inode *, struct file *, char *, + hfs_rwarg_t); +static hfs_rwret_t cap_info_write(struct inode *, struct file *, const char *, + hfs_rwarg_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 */ +}; + +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 */ +}; + +/*================ 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 inode *inode, struct file *filp, + char *buf, hfs_rwarg_t count) +{ + 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; + } + + if (filp->f_pos > HFS_FORK_MAX) { + return 0; + } + pos = filp->f_pos; + 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); + copy_to_user(buf, ((char *)&meta) + pos, memcount); + left -= memcount; + read += memcount; + pos += memcount; + buf += memcount; + } + + if (left > 0) { + read += left; + while (left--) { + put_user(0, buf++); + } + } + + if (read) { + inode->i_atime = CURRENT_TIME; + filp->f_pos += read; + } + 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 + * 'file->f_pos' 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 inode *inode, struct file *filp, + const char *buf, hfs_rwarg_t count) +{ + 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; + } + if (filp->f_flags & O_APPEND) { + filp->f_pos = inode->i_size; + } + if (filp->f_pos > HFS_FORK_MAX) { + return 0; + } + pos = filp->f_pos; + + filp->f_pos += count; + if (filp->f_pos > HFS_FORK_MAX) { + filp->f_pos = HFS_FORK_MAX; + count = HFS_FORK_MAX - pos; + } + if (filp->f_pos > inode->i_size) { + inode->i_size = filp->f_pos; + } + + /* 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/file_hdr.c linux-2.0.29/fs/hfs/file_hdr.c --- linux.vanilla/fs/hfs/file_hdr.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/file_hdr.c Thu Apr 10 12:29:37 1997 @@ -0,0 +1,925 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ Forward declarations ================*/ + +static hfs_rwret_t hdr_read(struct inode *, struct file *, char *, hfs_rwarg_t); +static hfs_rwret_t hdr_write(struct inode *, struct file *, const char *, + hfs_rwarg_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 */ +}; + +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 */ +}; + +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) { + 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) { + 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 inode * inode, struct file * filp, + char * buf, hfs_rwarg_t count) +{ + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + const struct hfs_hdr_layout *layout; + off_t start, length, offset; + off_t pos = filp->f_pos; + 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; + } + +done: + if (read) { + inode->i_atime = CURRENT_TIME; + filp->f_pos += read; + } + 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 + * 'file->f_pos' from user-space at the address 'buf'. + * The return value is the number of bytes actually transferred. + */ +static hfs_rwret_t hdr_write(struct inode *inode, struct file *filp, + const char *buf, hfs_rwarg_t count) +{ + 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; + } + if (filp->f_flags & O_APPEND) { + filp->f_pos = inode->i_size; + } + pos = filp->f_pos; + + 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; + } + +done: + if (written > 0) { + inode->i_mtime = inode->i_atime = CURRENT_TIME; + filp->f_pos += written; + if (filp->f_pos > inode->i_size) { + inode->i_size = filp->f_pos; + } + } + 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_DATA) { + fork = &HFS_I(inode)->entry->u.file.data_fork; + } else if (descr->id == HFS_HDR_RSRC) { + fork = &HFS_I(inode)->entry->u.file.rsrc_fork; + } 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/inode.c linux-2.0.29/fs/hfs/inode.c --- linux.vanilla/fs/hfs/inode.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/inode.c Thu Apr 10 12:32:07 1997 @@ -0,0 +1,425 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ 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); + } + } + + if (inode->i_count == 1) { + clear_inode(inode); + } +} + +/* + * 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 inode **inodes = 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); + inode->i_dirt = 0; + + /* 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 (inodes[i] && (inodes[i] != inode)) { + inode_setattr(inodes[i], attr); + inodes[i]->i_dirt = 0; + } + } + + /* 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, int crsmnt) +{ + struct inode **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 ((inode = *sys_entry)) { + /* 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, crsmnt)) || + (inode->i_dev != sb->s_dev)) { + /* Something went wrong or the inode is on another fs. */ + 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 = inode; + } + } 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 = inode; + } + 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; + + 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; + + 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; + + 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/mdb.c linux-2.0.29/fs/hfs/mdb.c --- linux.vanilla/fs/hfs/mdb.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/mdb.c Thu Apr 10 12:32:17 1997 @@ -0,0 +1,300 @@ +/* + * 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 <linux/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, + hfs_s32 dev_size, hfs_s32 part_start) +{ + struct hfs_mdb *mdb; + hfs_buffer buf; + struct raw_mdb *raw; + unsigned int bs, block; + int lcv; + 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; + mdb->dev_size = dev_size; + + /* 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; + + /* TRY to get the alternate (backup) MDB */ + buf = hfs_buffer_get(sys_mdb, part_start + dev_size - 2, 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; + } else { + hfs_buffer_put(buf); + } + } +#if !defined(HFS_DEVSIZE_CORRECT) + /* The Linux kernel records the sizes of block devices in + units of 1024 bytes, so dev_size might not include the + final block. Therefore, we also look for the alternate + MDB one block later than normal if dev_size is even. + XXX: Should get dev_size correct instead + */ + if ((mdb->alt_buf == NULL) && !(dev_size & 1)) { + buf = hfs_buffer_get(sys_mdb, part_start + dev_size - 1, 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; + mdb->dev_size += 1; + } else { + hfs_buffer_put(buf); + } + } + } +#endif + 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"); + } + + 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); + + /* 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; + } + + return mdb; + +bail1: + hfs_mdb_put(mdb); +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_ns(mdb->attrib, raw->drAtrb); + 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 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]); + } + + /* 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/part_tbl.c linux-2.0.29/fs/hfs/part_tbl.c --- linux.vanilla/fs/hfs/part_tbl.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/part_tbl.c Thu Apr 10 12:32:30 1997 @@ -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 <linux/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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/string.c linux-2.0.29/fs/hfs/string.c --- linux.vanilla/fs/hfs/string.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/string.c Thu Apr 10 12:32:44 1997 @@ -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 <linux/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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/super.c linux-2.0.29/fs/hfs/super.c --- linux.vanilla/fs/hfs/super.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/super.c Thu Apr 10 12:32:55 1997 @@ -0,0 +1,493 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +#include <linux/blkdev.h> +#include <linux/module.h> + +/*================ Forward declarations ================*/ + +static void hfs_put_super(struct super_block *); +static void 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 = { + NULL, /* read_inode */ + hfs_notify_change, /* notify_change - in inode.c */ + NULL, /* write_inode */ + hfs_put_inode, /* put_inode - 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_read_super, "hfs", 1, NULL}; + +/*================ File-local functions ================*/ + +/* + * 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)) { + if (mdb->attrib & htons(HFS_SB_ATTRIB_CLEAN)) { + mdb->attrib &= htons(~HFS_SB_ATTRIB_CLEAN); + } + + /* 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 the filesystem is mounted r/w, set the + * 'successfully unmounted' flag of the drAtrb + * field of the MDB and write the MDB to disk + */ + if (!(sb->s_flags & MS_RDONLY)) { + mdb->attrib |= htons(HFS_SB_ATTRIB_CLEAN); + hfs_mdb_commit(mdb, 0); + sb->s_dirt = 0; + } + + /* release the MDB's resources */ + hfs_mdb_put(mdb); + + /* 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 void 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; + + copy_to_user(buf, &tmp, len); +} + +/* + * 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; + hfs_s32 part_size, part_start; + 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 */ + if (hfs_part_find(s, part, silent, &part_size, &part_start)) { + goto bail2; + } + + if (!part_size && blk_size[MAJOR(dev)]) { + part_size = + (blk_size[MAJOR(dev)][MINOR(dev)] << 1) - part_start; + } + + mdb = hfs_mdb_get(s, part_size, part_start); + 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); + s->s_mounted = hfs_iget(mdb, &key, HFS_ITYPE_NORM); + if (!s->s_mounted) { + hfs_warn("hfs_fs: get root inode failed.\n"); + goto bail1; + } + unlock_super(s); + return s; + +bail1: + hfs_mdb_put(mdb); +bail2: + set_blocksize(dev, BLOCK_SIZE); + MOD_DEC_USE_COUNT; + unlock_super(s); +bail3: + s->s_dev = 0; + return NULL; +} + +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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/sysdep.c linux-2.0.29/fs/hfs/sysdep.c --- linux.vanilla/fs/hfs/sysdep.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/sysdep.c Thu Apr 10 12:33:08 1997 @@ -0,0 +1,44 @@ +/* + * 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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/* + * 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; +} diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/trans.c linux-2.0.29/fs/hfs/trans.c --- linux.vanilla/fs/hfs/trans.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/trans.c Thu Apr 10 12:33:18 1997 @@ -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 <linux/hfs.h> +#include <linux/hfs_fs_sb.h> +#include <linux/hfs_fs_i.h> +#include <linux/hfs_fs.h> + +/*================ 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/fs/hfs/version.c linux-2.0.29/fs/hfs/version.c --- linux.vanilla/fs/hfs/version.c Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/fs/hfs/version.c Wed Apr 9 04:41:46 1997 @@ -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.8.3"; diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/asm-m68k/adb.h linux-2.0.29/include/asm-m68k/adb.h --- linux.vanilla/include/asm-m68k/adb.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/asm-m68k/adb.h Mon Apr 14 16:45:58 1997 @@ -0,0 +1,75 @@ +/* + * Definitions for talking to ADB and CUDA. The CUDA is a microcontroller + * which controls the ADB, system power, RTC, and various other things on + * later Macintoshes + * + * Copyright (C) 1996 Paul Mackerras. + */ + +/* First byte sent to or received from CUDA */ +#define ADB_PACKET 0 +#define CUDA_PACKET 1 +#define ERROR_PACKET 2 +#define TIMER_PACKET 3 +#define POWER_PACKET 4 +#define MACIIC_PACKET 5 + +/* ADB commands (2nd byte) */ +#define ADB_BUSRESET 0 +#define ADB_FLUSH(id) (1 + ((id) << 4)) +#define ADB_WRITEREG(id, reg) (8 + (reg) + ((id) << 4)) +#define ADB_READREG(id, reg) (0xc + (reg) + ((id) << 4)) + +/* ADB default device IDs (upper 4 bits of 2nd byte) */ +#define ADB_DONGLE 1 /* "software execution control" devices */ +#define ADB_KEYBOARD 2 +#define ADB_MOUSE 3 +#define ADB_TABLET 4 +#define ADB_MODEM 5 +#define ADB_MISC 7 /* maybe a monitor */ + +/* CUDA commands (2nd byte) */ +#define CUDA_WARM_START 0 +#define CUDA_AUTOPOLL 1 +#define CUDA_GET_6805_ADDR 2 +#define CUDA_GET_TIME 3 +#define CUDA_GET_PRAM 7 +#define CUDA_SET_6805_ADDR 8 +#define CUDA_SET_TIME 9 +#define CUDA_POWERDOWN 0xa +#define CUDA_POWERUP_TIME 0xb +#define CUDA_SET_PRAM 0xc +#define CUDA_MS_RESET 0xd +#define CUDA_SEND_DFAC 0xe +#define CUDA_RESET_SYSTEM 0x11 +#define CUDA_SET_IPL 0x12 +#define CUDA_SET_AUTO_RATE 0x14 +#define CUDA_GET_AUTO_RATE 0x16 +#define CUDA_SET_DEVICE_LIST 0x19 +#define CUDA_GET_DEVICE_LIST 0x1a +#define CUDA_GET_SET_IIC 0x22 + +#ifdef __KERNEL__ + +struct adb_request { + unsigned char data[16]; + int nbytes; + unsigned char reply[16]; + int reply_len; + unsigned char reply_expected; + unsigned char sent; + unsigned char got_reply; + void (*done)(struct adb_request *); + void *arg; + struct adb_request *next; +}; + +void via_adb_init(void); +int adb_request(struct adb_request *req, + void (*done)(struct adb_request *), int nbytes, ...); +int adb_send_request(struct adb_request *req); +void adb_poll(void); +int adb_register(int default_id, + void (*handler)(unsigned char *, int, struct pt_regs *)); + +#endif /* __KERNEL */ diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/asm-m68k/cuda.h linux-2.0.29/include/asm-m68k/cuda.h --- linux.vanilla/include/asm-m68k/cuda.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/asm-m68k/cuda.h Thu Apr 10 16:36:37 1997 @@ -0,0 +1,74 @@ +/* + * Definitions for talking to the CUDA. The CUDA is a microcontroller + * which controls the ADB, system power, RTC, and various other things. + * + * Copyright (C) 1996 Paul Mackerras. + */ + +/* First byte sent to or received from CUDA */ +#define ADB_PACKET 0 +#define CUDA_PACKET 1 +#define ERROR_PACKET 2 +#define TIMER_PACKET 3 +#define POWER_PACKET 4 +#define MACIIC_PACKET 5 + +/* ADB commands (2nd byte) */ +#define ADB_BUSRESET 0 +#define ADB_FLUSH(id) (1 + ((id) << 4)) +#define ADB_WRITEREG(id, reg) (8 + (reg) + ((id) << 4)) +#define ADB_READREG(id, reg) (0xc + (reg) + ((id) << 4)) + +/* ADB default device IDs (upper 4 bits of 2nd byte) */ +#define ADB_DONGLE 1 /* "software execution control" devices */ +#define ADB_KEYBOARD 2 +#define ADB_MOUSE 3 +#define ADB_TABLET 4 +#define ADB_MODEM 5 +#define ADB_MISC 7 /* maybe a monitor */ + +/* CUDA commands (2nd byte) */ +#define CUDA_WARM_START 0 +#define CUDA_AUTOPOLL 1 +#define CUDA_GET_6805_ADDR 2 +#define CUDA_GET_TIME 3 +#define CUDA_GET_PRAM 7 +#define CUDA_SET_6805_ADDR 8 +#define CUDA_SET_TIME 9 +#define CUDA_POWERDOWN 0xa +#define CUDA_POWERUP_TIME 0xb +#define CUDA_SET_PRAM 0xc +#define CUDA_MS_RESET 0xd +#define CUDA_SEND_DFAC 0xe +#define CUDA_RESET_SYSTEM 0x11 +#define CUDA_SET_IPL 0x12 +#define CUDA_SET_AUTO_RATE 0x14 +#define CUDA_GET_AUTO_RATE 0x16 +#define CUDA_SET_DEVICE_LIST 0x19 +#define CUDA_GET_DEVICE_LIST 0x1a +#define CUDA_GET_SET_IIC 0x22 + +#ifdef __KERNEL__ + +struct adb_request { + unsigned char data[16]; + int nbytes; + unsigned char reply[16]; + int reply_len; + unsigned char reply_expected; + unsigned char sent; + unsigned char got_reply; + void (*done)(struct adb_request *); + void *arg; + struct adb_request *next; +}; + +void via_adb_init(void); +int adb_request(struct adb_request *req, + void (*done)(struct adb_request *), int nbytes, ...); +int adb_send_request(struct adb_request *req); +void adb_poll(void); +int adb_register(int default_id, + void (*handler)(unsigned char *, int, struct pt_regs *)); + +#endif /* __KERNEL */ diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/asm-m68k/setup.h linux-2.0.29/include/asm-m68k/setup.h --- linux.vanilla/include/asm-m68k/setup.h Thu Feb 27 17:42:23 1997 +++ linux-2.0.29/include/asm-m68k/setup.h Thu Apr 10 14:09:59 1997 @@ -185,6 +185,43 @@ #endif /* __ASSEMBLY__ */ +#ifndef __ASSEMBLY__ + +struct bi_Macintosh +{ + unsigned long videoaddr; + unsigned long videorow; + unsigned long videodepth; + unsigned long dimensions; + unsigned long args; + unsigned long boottime; + unsigned long gmtbias; + unsigned long bootver; + unsigned long videological; + unsigned long scc; + unsigned long id; + unsigned long memsize; + unsigned long serialmf; + unsigned long serialhsk; + unsigned long serialgpi; + unsigned long printf; + unsigned long printhsk; + unsigned long printgpi; + unsigned long cpuid; + unsigned long rombase; + unsigned long adbdelay; + unsigned long timedbra; +}; + +#else + +#define BI_videoaddr BI_un +#define BI_videorow BI_videoaddr+4 +#define BI_videodepth BI_videorow+4 +#define BI_dimensions BI_videodepth+4 +#define BI_args BI_dimensions+4 +#endif + #define NUM_MEMINFO 4 #define MACH_AMIGA 1 @@ -241,8 +278,13 @@ # define MACH_TYPE (MACH_ATARI) #endif +/* + * FIXME: When we have the booter we can multiarch this + */ + #if defined(CONFIG_MAC) -# error Currently no Mac support! +# define MAC_TYPE (MACH_MAC) +# define MACH_IS_MAC (1) #endif #ifndef MACH_TYPE @@ -336,6 +378,7 @@ union { struct bi_Amiga bi_ami; /* Amiga specific information */ struct bi_Atari bi_ata; /* Atari specific information */ + struct bi_Macintosh bi_mac; /* Mac specific information */ } bi_un; }; #define bi_amiga bi_un.bi_ami diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/linux/compile.h linux-2.0.29/include/linux/compile.h --- linux.vanilla/include/linux/compile.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/linux/compile.h Wed Apr 16 16:58:02 1997 @@ -0,0 +1,6 @@ +#define UTS_VERSION "#315 Wed Apr 16 16:57:59 BST 1997" +#define LINUX_COMPILE_TIME "16:58:00" +#define LINUX_COMPILE_BY "alan" +#define LINUX_COMPILE_HOST "blacksun" +#define LINUX_COMPILE_DOMAIN "cymru.net" +#define LINUX_COMPILER "gcc version 2.7.2.2" diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/linux/hfs.h linux-2.0.29/include/linux/hfs.h --- linux.vanilla/include/linux/hfs.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/linux/hfs.h Thu Apr 10 14:34:06 1997 @@ -0,0 +1,491 @@ +/* + * 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 <linux/hfs_sysdep.h> + +#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 dev_size; /* The number of + 512-byte blocks + on the device */ + 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_first_zero_bit(const void *, hfs_u32); +extern hfs_u32 hfs_find_next_zero_bit(const void *, hfs_u32, hfs_u32); +extern hfs_u32 hfs_count_zero_bits(const void *, 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, hfs_s32, hfs_s32); +extern void hfs_mdb_commit(struct hfs_mdb *, int); +extern void hfs_mdb_put(struct hfs_mdb *); + +/* 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); + +#endif diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/linux/hfs_btree.h linux-2.0.29/include/linux/hfs_btree.h --- linux.vanilla/include/linux/hfs_btree.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/linux/hfs_btree.h Thu Apr 10 12:34:30 1997 @@ -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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/linux/hfs_fs.h linux-2.0.29/include/linux/hfs_fs.h --- linux.vanilla/include/linux/hfs_fs.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/linux/hfs_fs.h Tue Apr 15 19:19:24 1997 @@ -0,0 +1,355 @@ +/* + * 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 <linux/hfs_sysdep.h> + +/* 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__ + +#include <linux/version.h> + +#if (LINUX_VERSION_CODE < 0x020001) +#error "Linux kernel version 2.0.1 or newer is required." +#endif + +#if (LINUX_VERSION_CODE < 0x020100) && !defined(__alpha__) +typedef int hfs_rwret_t; +typedef int hfs_rwarg_t; +#else +typedef long hfs_rwret_t; +typedef unsigned long hfs_rwarg_t; +#endif + +#if (LINUX_VERSION_CODE < 0x020104) +# define copy_to_user memcpy_tofs +# define copy_from_user memcpy_fromfs +#endif + +#if (LINUX_VERSION_CODE < 0x020106) +# include <asm/segment.h> +#else +# include <asm/uaccess.h> +#endif + +#if (LINUX_VERSION_CODE < 0x020105) +extern inline void clear_user(char *addr, off_t count) +{ while (count--) { put_user(0, addr++); } } +#endif + +/* Some forward declarations */ +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 inode *, struct file *, char *, + hfs_rwarg_t); +extern int hfs_create(struct inode *, const char *, int, int, struct inode **); +extern int hfs_mkdir(struct inode *, const char *, int, int); +extern int hfs_mknod(struct inode *, const char *, int, int, int); +extern int hfs_unlink(struct inode *, const char *, int); +extern int hfs_rmdir(struct inode *, const char *, int); +extern int hfs_rename(struct inode *, const char *, int, + struct inode *, const char *, int, int); + +/* 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; + +/* 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; + +/* 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; + +/* 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, int); +extern inline struct inode *hfs_iget(struct hfs_mdb *mdb, + const struct hfs_cat_key *key, + ino_t type) +{ return __hfs_iget(hfs_cat_get(mdb, key), type, 1); } + +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 *); + +extern __inline__ struct hfs_inode_info *HFS_I(struct inode *inode) { + return (struct hfs_inode_info *)(&inode->u); +} + +extern __inline__ struct hfs_sb_info *HFS_SB(struct super_block *super) { + return (struct hfs_sb_info *)(&super->u); +} + +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; +} + +#endif /* __KERNEL__ */ + +#endif diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/linux/hfs_fs_i.h linux-2.0.29/include/linux/hfs_fs_i.h --- linux.vanilla/include/linux/hfs_fs_i.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/linux/hfs_fs_i.h Wed Apr 9 04:41:47 1997 @@ -0,0 +1,37 @@ +/* + * 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; +}; + +#endif diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/linux/hfs_fs_sb.h linux-2.0.29/include/linux/hfs_fs_sb.h --- linux.vanilla/include/linux/hfs_fs_sb.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/linux/hfs_fs_sb.h Wed Apr 9 04:41:47 1997 @@ -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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/linux/hfs_sysdep.h linux-2.0.29/include/linux/hfs_sysdep.h --- linux.vanilla/include/linux/hfs_sysdep.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/linux/hfs_sysdep.h Thu Apr 10 14:34:06 1997 @@ -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 <linux/malloc.h> +#include <linux/types.h> +#include <linux/locks.h> +#include <linux/fs.h> + +#include <asm/byteorder.h> +#include <asm/unaligned.h> + + +#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 inode *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 clear_bit(BITNR(bitnr), lword); +} + +extern inline int hfs_set_bit(int bitnr, hfs_u32 *lword) { + return set_bit(BITNR(bitnr), lword); +} + +extern inline int hfs_test_bit(int bitnr, const hfs_u32 *lword) { + return test_bit(BITNR(bitnr), 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 --recursive --unified --new-file --exclude-from exclude linux.vanilla/include/linux/nubus.h linux-2.0.29/include/linux/nubus.h --- linux.vanilla/include/linux/nubus.h Thu Jan 1 01:00:00 1970 +++ linux-2.0.29/include/linux/nubus.h Wed Apr 16 16:51:18 1997 @@ -0,0 +1,22 @@ + +struct nubus_slot +{ + int slot_flags; +#define NUBUS_DEVICE_PRESENT 1 +#define NUBUS_DEVICE_ACTIVE 2 +#define NUBUS_DEVICE_IRQ 4 + __u32 slot_directory; + __u32 slot_dlength; + __u32 slot_crc; + __u8 slot_rev; + __u8 slot_format; + /* + * Stuff we pulled from the directory + */ + __u32 slot_dirbase; + __u32 slot_thisdir; + char slot_vendor[64]; + char slot_cardname[64]; +}; + + \ No newline at end of file diff --recursive --unified --new-file --exclude-from exclude linux.vanilla/init/main.c linux-2.0.29/init/main.c --- linux.vanilla/init/main.c Wed Dec 4 22:38:06 1996 +++ linux-2.0.29/init/main.c Tue Mar 25 18:38:17 1997 @@ -39,6 +39,9 @@ #include <asm/bugs.h> +#include <asm/setup.h> /*AC*/ +#include <linux/console.h> /*AC*/ + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -789,8 +792,15 @@ asmlinkage void start_kernel(void) { + extern unsigned long precookie,postcookie; /* AC*/ char * command_line; + extern struct consw fb_con; + extern u_long fbcon_startup(u_long, char **); + + if(fb_con.con_startup!=fbcon_startup) + mac_boom(1); + /* * This little check will move. */ @@ -833,12 +843,16 @@ memory_start += prof_len * sizeof(unsigned int); memset(prof_buffer, 0, prof_len * sizeof(unsigned int)); } + mac_debugging_penguin(1); memory_start = console_init(memory_start,memory_end); +/* mac_debugging_penguin(2);*/ #ifdef CONFIG_PCI memory_start = pci_init(memory_start,memory_end); #endif memory_start = kmalloc_init(memory_start,memory_end); sti(); + printk("Memory start=%p, Memory end=%p\n", + memory_start,memory_end); calibrate_delay(); memory_start = inode_init(memory_start,memory_end); memory_start = file_table_init(memory_start,memory_end); .