diff -urN xnu-344.49/EXTERNAL_HEADERS/bsd/i386/ansi.h xnu-517/EXTERNAL_HEADERS/bsd/i386/ansi.h --- xnu-344.49/EXTERNAL_HEADERS/bsd/i386/ansi.h Thu Sep 18 21:02:01 2003 +++ xnu-517/EXTERNAL_HEADERS/bsd/i386/ansi.h Sat Oct 25 00:24:25 2003 @@ -80,6 +80,7 @@ #define _BSD_SSIZE_T_ int /* byte count or error */ #define _BSD_TIME_T_ long /* time() */ #define _BSD_VA_LIST_ void * /* va_list */ +#define _BSD_SOCKLEN_T_ int32_t /* socklen_t (duh) */ /* * Runes (wchar_t) is declared to be an ``int'' instead of the more natural diff -urN xnu-344.49/EXTERNAL_HEADERS/bsd/ppc/ansi.h xnu-517/EXTERNAL_HEADERS/bsd/ppc/ansi.h --- xnu-344.49/EXTERNAL_HEADERS/bsd/ppc/ansi.h Thu Sep 18 21:02:01 2003 +++ xnu-517/EXTERNAL_HEADERS/bsd/ppc/ansi.h Sat Oct 25 00:24:25 2003 @@ -80,6 +80,7 @@ #define _BSD_SSIZE_T_ int /* byte count or error */ #define _BSD_TIME_T_ long /* time() */ #define _BSD_VA_LIST_ char * /* va_list */ +#define _BSD_SOCKLEN_T_ int32_t /* socklen_t (duh) */ /* * Runes (wchar_t) is declared to be an ``int'' instead of the more natural diff -urN xnu-344.49/EXTERNAL_HEADERS/mach-o/kld.h xnu-517/EXTERNAL_HEADERS/mach-o/kld.h --- xnu-344.49/EXTERNAL_HEADERS/mach-o/kld.h Thu Sep 18 21:02:01 2003 +++ xnu-517/EXTERNAL_HEADERS/mach-o/kld.h Sat Oct 25 00:24:25 2003 @@ -33,6 +33,9 @@ * These API's are in libkld. Both kmodload(8) and /mach_kernel should * link with -lkld and then ld(1) will expand -lkld to libkld.dylib or * libkld.a depending on if -dynamic or -static is in effect. + * + * Note: we are using the __DYNAMIC__ flag to indicate user space kernel + * linking and __STATIC__ as a synonym of KERNEL. */ /* @@ -42,7 +45,7 @@ extern void kld_error_vprintf(const char *format, va_list ap); /* - * This two are only in libkld.dylib for use by kmodload(8) (user code compiled + * These two are only in libkld.dylib for use by kmodload(8) (user code compiled * with the default -dynamic). */ #ifdef __DYNAMIC__ @@ -54,6 +57,13 @@ struct mach_header **header_addr, const char *object_filename, const char *output_filename); + +__private_extern__ long kld_load_from_memory( + struct mach_header **header_addr, + const char *object_name, + char *object_addr, + long object_size, + const char *output_filename); #endif /* __DYNAMIC__ */ /* @@ -69,6 +79,11 @@ long object_size); #endif /* __STATIC__ */ +__private_extern__ long kld_load_basefile_from_memory( + const char *base_filename, + char *base_addr, + long base_size); + __private_extern__ long kld_unload_all( long deallocate_sets); @@ -81,5 +96,11 @@ __private_extern__ void kld_address_func( unsigned long (*func)(unsigned long size, unsigned long headers_size)); + +#define KLD_STRIP_ALL 0x00000000 +#define KLD_STRIP_NONE 0x00000001 + +__private_extern__ void kld_set_link_options( + unsigned long link_options); #endif /* _MACHO_KLD_H_ */ diff -urN xnu-344.49/EXTERNAL_HEADERS/mach-o/loader.h xnu-517/EXTERNAL_HEADERS/mach-o/loader.h --- xnu-344.49/EXTERNAL_HEADERS/mach-o/loader.h Thu Sep 18 21:02:01 2003 +++ xnu-517/EXTERNAL_HEADERS/mach-o/loader.h Sat Oct 25 00:24:25 2003 @@ -723,4 +723,4 @@ unsigned long header_addr; /* files virtual address */ }; -#endif _MACHO_LOADER_H_ +#endif /* _MACHO_LOADER_H_ */ diff -urN xnu-344.49/Makefile xnu-517/Makefile --- xnu-344.49/Makefile Thu Sep 18 03:15:26 2003 +++ xnu-517/Makefile Tue Oct 21 21:24:55 2003 @@ -31,6 +31,8 @@ libkern \ libsa +CONFIG_SUBDIRS = config + INSTINC_SUBDIRS = $(ALL_SUBDIRS) INSTINC_SUBDIRS_PPC = $(INSTINC_SUBDIRS) @@ -44,6 +46,7 @@ EXPINC_SUBDIRS_I386 = $(EXPINC_SUBDIRS) COMP_SUBDIRS = $(ALL_SUBDIRS) + INST_SUBDIRS = \ libkern \ diff -urN xnu-344.49/bsd/conf/MASTER xnu-517/bsd/conf/MASTER --- xnu-344.49/bsd/conf/MASTER Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/MASTER Tue Oct 21 21:24:55 2003 @@ -144,6 +144,7 @@ options RANDOM_IP_ID # random (not sequential) ip ids # options TCP_DROP_SYNFIN # Drop TCP packets with SYN+FIN set # options ICMP_BANDLIM # ICMP bandwidth limiting sysctl +options AUDIT # Security event auditing # # @@ -152,6 +153,7 @@ options COMPAT_43 # 4.3 BSD compatibility # options DIAGNOSTIC # diagnostics # options KTRACE # ktrace support # +options GPROF # build profiling # # # 4.4 filesystems @@ -245,6 +247,10 @@ # # vnode device pseudo-device vndevice 4 init vndevice_init + +# +# memory device +pseudo-device mdevdevice 1 init mdevinit # # diff -urN xnu-344.49/bsd/conf/MASTER.ppc xnu-517/bsd/conf/MASTER.ppc --- xnu-344.49/bsd/conf/MASTER.ppc Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/MASTER.ppc Tue Oct 21 21:24:55 2003 @@ -47,7 +47,7 @@ # # RELEASE = [ppc mach medium vol pst gdb simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs noprofiling hfs volfs devfs synthfs netat mrouting ipdivert ipfirewall ktrace inet6 ipsec tcpdrop_synfin gif stf] # RELEASE_TRACE = [RELEASE kdebug] -# PROFILE = [ppc mach medium vol pst gdb debug simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs profile hfs volfs devfs synthfs netat mrouting ipdivert ipfirewall ktrace inet6 ipsec tcpdrop_synfin gif stf] +# PROFILE = [ppc mach medium vol pst gdb simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs profile hfs volfs devfs synthfs netat mrouting ipdivert ipfirewall ktrace inet6 ipsec tcpdrop_synfin gif stf] # DEBUG = [ppc mach medium vol pst gdb debug simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs profiling hfs volfs devfs synthfs netat mrouting mach_assert ipdivert ipfirewall ktrace inet6 ipsec tcpdrop_synfin gif stf] # DEBUG_TRACE = [DEBUG kdebug] # diff -urN xnu-344.49/bsd/conf/Makefile xnu-517/bsd/conf/Makefile --- xnu-344.49/bsd/conf/Makefile Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/Makefile Tue Oct 21 21:24:55 2003 @@ -18,7 +18,7 @@ export BSD_KERNEL_CONFIG = $(KERNEL_CONFIG) endif -COMPOBJROOT=$(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT) +export COMPOBJROOT=$(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT) $(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT)/doconf: make build_setup @@ -53,6 +53,7 @@ SOURCE=$${next_source} \ TARGET=$(TARGET) \ INCL_MAKEDEP=FALSE \ + KERNEL_CONFIG=$(BSD_KERNEL_CONFIG) \ build_all; \ echo "[ $(SOURCE) ] Returning do_all $(COMPONENT) $(BSD_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; diff -urN xnu-344.49/bsd/conf/Makefile.template xnu-517/bsd/conf/Makefile.template --- xnu-344.49/bsd/conf/Makefile.template Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/Makefile.template Tue Oct 21 21:24:55 2003 @@ -70,6 +70,13 @@ %MACHDEP # +# This rule insures that the subr_prof.c does NOT get compiled with +# profiling. It implements mcount() and profiling it leads to recursion. +# + +subr_prof.o_CFLAGS_RM = -pg + +# # OBJSDEPS is the set of files (defined in the machine dependent # template if necessary) which all objects depend on (such as an # in-line assembler expansion filter) @@ -84,7 +91,7 @@ $(COMPONENT).o: $(LDOBJS) @echo "[ creating $(COMPONENT).o ]" $(RM) $(RMFLAGS) vers.c - $(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT)/newvers \ + $(COMPOBJROOT)/newvers \ `$(CAT) ${VERSION_FILES}` ${COPYRIGHT_FILES} ${KCC} $(CFLAGS) $(INCLUDES) -c vers.c @echo [ updating $(COMPONENT).o ${BSD_KERNEL_CONFIG} ] diff -urN xnu-344.49/bsd/conf/files xnu-517/bsd/conf/files --- xnu-344.49/bsd/conf/files Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/files Tue Oct 21 21:24:55 2003 @@ -60,6 +60,7 @@ OPTIONS/ktrace optional ktrace OPTIONS/profiling optional profiling OPTIONS/vndevice optional vndevice +OPTIONS/audit optional audit # # Network options @@ -115,6 +116,9 @@ bsd/dev/random/YarrowCoreLib/src/prng.c standard bsd/dev/random/YarrowCoreLib/src/sha1mod.c standard bsd/dev/random/YarrowCoreLib/src/yarrowUtils.c standard + +bsd/dev/memdev.c standard + bsd/dev/vn/vn.c optional vndevice bsd/dev/vn/shadow.c optional vndevice @@ -289,6 +293,7 @@ bsd/crypto/sha1.c optional crypto bsd/crypto/sha2/sha2.c optional crypto bsd/crypto/des/des_ecb.c optional crypto +bsd/crypto/des/des_enc.c optional crypto bsd/crypto/des/des_setkey.c optional crypto bsd/crypto/blowfish/bf_enc.c optional crypto bsd/crypto/blowfish/bf_skey.c optional crypto @@ -380,6 +385,7 @@ bsd/nfs/nfs_syscalls.c optional nfsclient nfsserver bsd/nfs/nfs_vfsops.c optional nfsclient bsd/nfs/nfs_vnops.c optional nfsclient +bsd/nfs/nfs_lock.c optional nfsclient bsd/kern/netboot.c optional nfsclient @@ -392,6 +398,7 @@ bsd/ufs/ffs/ffs_vnops.c standard bsd/ufs/mfs/mfs_vfsops.c optional mfs bsd/ufs/mfs/mfs_vnops.c optional mfs +bsd/ufs/ufs/ufs_attrlist.c standard bsd/ufs/ufs/ufs_bmap.c standard bsd/ufs/ufs/ufs_byte_order.c optional rev_endian_fs bsd/ufs/ufs/ufs_ihash.c standard @@ -410,9 +417,11 @@ bsd/hfs/hfs_encodinghint.c optional hfs bsd/hfs/hfs_encodings.c optional hfs bsd/hfs/hfs_endian.c optional hfs +bsd/hfs/hfs_hotfiles.c optional hfs bsd/hfs/hfs_link.c optional hfs bsd/hfs/hfs_lockf.c optional hfs bsd/hfs/hfs_lookup.c optional hfs +bsd/hfs/hfs_notification.c optional hfs bsd/hfs/hfs_quota.c optional quota bsd/hfs/hfs_readwrite.c optional hfs bsd/hfs/hfs_search.c optional hfs @@ -425,6 +434,7 @@ bsd/hfs/hfscommon/BTree/BTreeAllocate.c optional hfs bsd/hfs/hfscommon/BTree/BTreeMiscOps.c optional hfs bsd/hfs/hfscommon/BTree/BTreeNodeOps.c optional hfs +bsd/hfs/hfscommon/BTree/BTreeNodeReserve.c optional hfs bsd/hfs/hfscommon/BTree/BTreeScanner.c optional hfs bsd/hfs/hfscommon/BTree/BTreeTreeOps.c optional hfs bsd/hfs/hfscommon/Catalog/Catalog.c optional hfs @@ -440,6 +450,11 @@ bsd/kern/init_sysent.c standard bsd/kern/kdebug.c standard bsd/kern/kern_acct.c standard +bsd/kern/kern_aio.c standard +bsd/kern/kern_audit.c standard +bsd/kern/kern_bsm_token.c standard +bsd/kern/kern_bsm_audit.c standard +bsd/kern/kern_bsm_klib.c standard bsd/kern/kern_clock.c standard bsd/kern/kern_core.c standard bsd/kern/kern_symfile.c standard diff -urN xnu-344.49/bsd/conf/files.i386 xnu-517/bsd/conf/files.i386 --- xnu-344.49/bsd/conf/files.i386 Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/files.i386 Tue Oct 21 21:24:55 2003 @@ -11,6 +11,7 @@ bsd/dev/i386/memmove.c standard bsd/dev/i386/stubs.c standard bsd/dev/i386/lock_stubs.c standard +bsd/dev/i386/sysctl.c standard bsd/dev/i386/unix_signal.c standard bsd/dev/i386/unix_startup.c standard diff -urN xnu-344.49/bsd/conf/files.ppc xnu-517/bsd/conf/files.ppc --- xnu-344.49/bsd/conf/files.ppc Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/files.ppc Tue Oct 21 21:24:55 2003 @@ -17,6 +17,10 @@ bsd/dev/ppc/systemcalls.c standard bsd/dev/ppc/km.c standard bsd/dev/ppc/xsumas.s standard +bsd/dev/ppc/sysctl.c standard + +bsd/dev/ppc/chud/chud_bsd_callback.c standard +bsd/dev/ppc/chud/chud_process.c standard bsd/kern/bsd_stubs.c standard diff -urN xnu-344.49/bsd/conf/param.c xnu-517/bsd/conf/param.c --- xnu-344.49/bsd/conf/param.c Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/conf/param.c Sat Oct 25 00:25:25 2003 @@ -77,16 +77,19 @@ #include #include #include +#include struct timezone tz = { TIMEZONE, PST }; #define NPROC (20 + 16 * MAXUSERS) +#define HNPROC (20 + 64 * MAXUSERS) int maxproc = NPROC; +__private_extern__ int hard_maxproc = HNPROC; /* hardcoded limit */ int nprocs = 0; /* XXX */ #define NTEXT (80 + NPROC / 8) /* actually the object cache */ #define NVNODE (NPROC + NTEXT + 300) -int desiredvnodes = NVNODE + 350; +int desiredvnodes = NVNODE + 700; #define MAXFILES (OPEN_MAX + 2048) int maxfiles = MAXFILES; @@ -97,6 +100,16 @@ #define MAXSOCKETS NMBCLUSTERS int maxsockets = MAXSOCKETS; + +/* + * async IO (aio) configurable limits + */ +#define AIO_MAX 90 /* system wide limit of async IO requests */ +#define AIO_PROCESS_MAX AIO_LISTIO_MAX /* process limit of async IO requests */ +#define AIO_THREAD_COUNT 4 /* number of async IO worker threads created */ +int aio_max_requests = AIO_MAX; +int aio_max_requests_per_process = AIO_PROCESS_MAX; +int aio_worker_threads = AIO_THREAD_COUNT; /* * These have to be allocated somewhere; allocating diff -urN xnu-344.49/bsd/conf/version.major xnu-517/bsd/conf/version.major --- xnu-344.49/bsd/conf/version.major Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/version.major Tue Oct 21 21:24:55 2003 @@ -1 +1 @@ -6 +7 diff -urN xnu-344.49/bsd/conf/version.minor xnu-517/bsd/conf/version.minor --- xnu-344.49/bsd/conf/version.minor Thu Sep 18 03:15:26 2003 +++ xnu-517/bsd/conf/version.minor Tue Oct 21 21:24:55 2003 @@ -1 +1 @@ -8 +0 diff -urN xnu-344.49/bsd/conf/version.variant xnu-517/bsd/conf/version.variant --- xnu-344.49/bsd/conf/version.variant Thu Sep 18 03:15:10 2003 +++ xnu-517/bsd/conf/version.variant Tue Oct 21 21:24:55 2003 @@ -0,0 +1 @@ +0 diff -urN xnu-344.49/bsd/crypto/blowfish/bf_enc.c xnu-517/bsd/crypto/blowfish/bf_enc.c --- xnu-344.49/bsd/crypto/blowfish/bf_enc.c Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/blowfish/bf_enc.c Sat Oct 25 00:25:25 2003 @@ -1,12 +1,12 @@ -/* $FreeBSD: src/sys/crypto/blowfish/bf_enc.c,v 1.1.2.2 2001/07/03 11:01:28 ume Exp $ */ -/* $KAME: bf_enc.c,v 1.5 2000/09/18 21:21:19 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/blowfish/bf_enc.c,v 1.1.2.3 2002/03/26 10:12:23 ume Exp $ */ +/* $KAME: bf_enc.c,v 1.7 2002/02/27 01:33:59 itojun Exp $ */ /* crypto/bf/bf_enc.c */ -/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written - * by Eric Young (eay@mincom.oz.au). + * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as @@ -14,7 +14,7 @@ * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. @@ -34,12 +34,12 @@ * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by - * Eric Young (eay@mincom.oz.au)" + * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -75,10 +75,9 @@ /* XXX "data" is host endian */ void -BF_encrypt(data, key, encrypt) +BF_encrypt(data, key) BF_LONG *data; BF_KEY *key; - int encrypt; { register BF_LONG l, r, *p, *s; @@ -87,57 +86,73 @@ l = data[0]; r = data[1]; - if (encrypt) { - l^=p[0]; - BF_ENC(r, l, s, p[ 1]); - BF_ENC(l, r, s, p[ 2]); - BF_ENC(r, l, s, p[ 3]); - BF_ENC(l, r, s, p[ 4]); - BF_ENC(r, l, s, p[ 5]); - BF_ENC(l, r, s, p[ 6]); - BF_ENC(r, l, s, p[ 7]); - BF_ENC(l, r, s, p[ 8]); - BF_ENC(r, l, s, p[ 9]); - BF_ENC(l, r, s, p[10]); - BF_ENC(r, l, s, p[11]); - BF_ENC(l, r, s, p[12]); - BF_ENC(r, l, s, p[13]); - BF_ENC(l, r, s, p[14]); - BF_ENC(r, l, s, p[15]); - BF_ENC(l, r, s, p[16]); + l^=p[0]; + BF_ENC(r, l, s, p[ 1]); + BF_ENC(l, r, s, p[ 2]); + BF_ENC(r, l, s, p[ 3]); + BF_ENC(l, r, s, p[ 4]); + BF_ENC(r, l, s, p[ 5]); + BF_ENC(l, r, s, p[ 6]); + BF_ENC(r, l, s, p[ 7]); + BF_ENC(l, r, s, p[ 8]); + BF_ENC(r, l, s, p[ 9]); + BF_ENC(l, r, s, p[10]); + BF_ENC(r, l, s, p[11]); + BF_ENC(l, r, s, p[12]); + BF_ENC(r, l, s, p[13]); + BF_ENC(l, r, s, p[14]); + BF_ENC(r, l, s, p[15]); + BF_ENC(l, r, s, p[16]); #if BF_ROUNDS == 20 - BF_ENC(r, l, s, p[17]); - BF_ENC(l, r, s, p[18]); - BF_ENC(r, l, s, p[19]); - BF_ENC(l, r, s, p[20]); + BF_ENC(r, l, s, p[17]); + BF_ENC(l, r, s, p[18]); + BF_ENC(r, l, s, p[19]); + BF_ENC(l, r, s, p[20]); #endif - r ^= p[BF_ROUNDS + 1]; - } else { - l ^= p[BF_ROUNDS + 1]; + r ^= p[BF_ROUNDS + 1]; + + data[1] = l & 0xffffffff; + data[0] = r & 0xffffffff; +} + +/* XXX "data" is host endian */ +void +BF_decrypt(data, key) + BF_LONG *data; + BF_KEY *key; +{ + register BF_LONG l, r, *p, *s; + + p = key->P; + s= &key->S[0]; + l = data[0]; + r = data[1]; + + l ^= p[BF_ROUNDS + 1]; #if BF_ROUNDS == 20 - BF_ENC(r, l, s, p[20]); - BF_ENC(l, r, s, p[19]); - BF_ENC(r, l, s, p[18]); - BF_ENC(l, r, s, p[17]); + BF_ENC(r, l, s, p[20]); + BF_ENC(l, r, s, p[19]); + BF_ENC(r, l, s, p[18]); + BF_ENC(l, r, s, p[17]); #endif - BF_ENC(r, l, s, p[16]); - BF_ENC(l, r, s, p[15]); - BF_ENC(r, l, s, p[14]); - BF_ENC(l, r, s, p[13]); - BF_ENC(r, l, s, p[12]); - BF_ENC(l, r, s, p[11]); - BF_ENC(r, l, s, p[10]); - BF_ENC(l, r, s, p[ 9]); - BF_ENC(r, l, s, p[ 8]); - BF_ENC(l, r, s, p[ 7]); - BF_ENC(r, l, s, p[ 6]); - BF_ENC(l, r, s, p[ 5]); - BF_ENC(r, l, s, p[ 4]); - BF_ENC(l, r, s, p[ 3]); - BF_ENC(r, l, s, p[ 2]); - BF_ENC(l, r, s, p[ 1]); - r ^= p[0]; - } + BF_ENC(r, l, s, p[16]); + BF_ENC(l, r, s, p[15]); + BF_ENC(r, l, s, p[14]); + BF_ENC(l, r, s, p[13]); + BF_ENC(r, l, s, p[12]); + BF_ENC(l, r, s, p[11]); + BF_ENC(r, l, s, p[10]); + BF_ENC(l, r, s, p[ 9]); + BF_ENC(r, l, s, p[ 8]); + BF_ENC(l, r, s, p[ 7]); + BF_ENC(r, l, s, p[ 6]); + BF_ENC(l, r, s, p[ 5]); + BF_ENC(r, l, s, p[ 4]); + BF_ENC(l, r, s, p[ 3]); + BF_ENC(r, l, s, p[ 2]); + BF_ENC(l, r, s, p[ 1]); + r ^= p[0]; + data[1] = l & 0xffffffff; data[0] = r & 0xffffffff; } diff -urN xnu-344.49/bsd/crypto/blowfish/bf_pi.h xnu-517/bsd/crypto/blowfish/bf_pi.h --- xnu-344.49/bsd/crypto/blowfish/bf_pi.h Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/blowfish/bf_pi.h Sat Oct 25 00:25:25 2003 @@ -59,7 +59,7 @@ * [including the GNU Public Licence.] */ -static BF_KEY bf_init= { +static const BF_KEY bf_init= { { 0x243f6a88L, 0x85a308d3L, 0x13198a2eL, 0x03707344L, 0xa4093822L, 0x299f31d0L, 0x082efa98L, 0xec4e6c89L, diff -urN xnu-344.49/bsd/crypto/blowfish/bf_skey.c xnu-517/bsd/crypto/blowfish/bf_skey.c --- xnu-344.49/bsd/crypto/blowfish/bf_skey.c Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/blowfish/bf_skey.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ -/* $FreeBSD: src/sys/crypto/blowfish/bf_skey.c,v 1.1.2.2 2001/07/03 11:01:28 ume Exp $ */ -/* $KAME: bf_skey.c,v 1.5 2000/11/06 13:58:08 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/blowfish/bf_skey.c,v 1.1.2.3 2002/03/26 10:12:23 ume Exp $ */ +/* $KAME: bf_skey.c,v 1.7 2002/02/27 01:33:59 itojun Exp $ */ /* crypto/bf/bf_skey.c */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) @@ -76,7 +76,7 @@ BF_LONG *p, ri, in[2]; unsigned char *d, *end; - memcpy((char *)key, (char *)&bf_init, sizeof(BF_KEY)); + memcpy((char *)key, (const char *)&bf_init, sizeof(BF_KEY)); p = key->P; if (len > ((BF_ROUNDS + 2) * 4)) @@ -106,14 +106,14 @@ in[0] = 0L; in[1] = 0L; for (i = 0; i < BF_ROUNDS + 2; i += 2) { - BF_encrypt(in, key, BF_ENCRYPT); + BF_encrypt(in, key); p[i ] = in[0]; p[i+1] = in[1]; } p = key->S; for (i = 0; i < 4 * 256; i += 2) { - BF_encrypt(in, key, BF_ENCRYPT); + BF_encrypt(in, key); p[i ] = in[0]; p[i+1] = in[1]; } diff -urN xnu-344.49/bsd/crypto/blowfish/blowfish.h xnu-517/bsd/crypto/blowfish/blowfish.h --- xnu-344.49/bsd/crypto/blowfish/blowfish.h Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/blowfish/blowfish.h Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ -/* $FreeBSD: src/sys/crypto/blowfish/blowfish.h,v 1.1.2.2 2001/07/03 11:01:28 ume Exp $ */ -/* $KAME: blowfish.h,v 1.10 2000/09/18 21:21:20 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/blowfish/blowfish.h,v 1.1.2.3 2002/03/26 10:12:23 ume Exp $ */ +/* $KAME: blowfish.h,v 1.12 2002/02/27 01:33:59 itojun Exp $ */ /* crypto/bf/blowfish.h */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) @@ -81,7 +81,11 @@ } BF_KEY; void BF_set_key __P((BF_KEY *, int, unsigned char *)); -void BF_encrypt __P((BF_LONG *, BF_KEY *, int)); +void BF_encrypt __P((BF_LONG *, BF_KEY *)); +void BF_decrypt __P((BF_LONG *, BF_KEY *)); +void BF_cbc_encrypt(const unsigned char *, unsigned char *, long, + const BF_KEY *, unsigned char *, int); + #ifdef __cplusplus } #endif diff -urN xnu-344.49/bsd/crypto/des/des.h xnu-517/bsd/crypto/des/des.h --- xnu-344.49/bsd/crypto/des/des.h Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/des/des.h Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ -/* $FreeBSD: src/sys/crypto/des/des.h,v 1.1.2.2 2001/07/03 11:01:31 ume Exp $ */ -/* $KAME: des.h,v 1.7 2000/09/18 20:59:21 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/des/des.h,v 1.1.2.3 2002/03/26 10:12:24 ume Exp $ */ +/* $KAME: des.h,v 1.8 2001/09/10 04:03:57 itojun Exp $ */ /* lib/des/des.h */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) @@ -61,15 +61,14 @@ typedef unsigned char des_cblock[8]; typedef struct des_ks_struct { - union { - des_cblock _; - /* make sure things are correct size on machines with - * 8 byte longs */ - DES_LONG pad[2]; - } ks; -#undef _ -#define _ ks._ - } des_key_schedule[16]; + union { + des_cblock cblock; + /* make sure things are correct size on machines with + * 8 byte longs */ + DES_LONG deslong[2]; + } ks; + int weak_key; +} des_key_schedule[16]; #define DES_KEY_SZ (sizeof(des_cblock)) #define DES_SCHEDULE_SZ (sizeof(des_key_schedule)) @@ -85,13 +84,32 @@ char *des_options __P((void)); void des_ecb_encrypt __P((des_cblock *, des_cblock *, des_key_schedule, int)); -void des_encrypt __P((DES_LONG *, des_key_schedule, int)); + +void des_encrypt1 __P((DES_LONG *, des_key_schedule, int)); void des_encrypt2 __P((DES_LONG *, des_key_schedule, int)); +void des_encrypt3 __P((DES_LONG *, des_key_schedule, des_key_schedule, + des_key_schedule)); +void des_decrypt3 __P((DES_LONG *, des_key_schedule, des_key_schedule, + des_key_schedule)); + +void des_ecb3_encrypt __P((des_cblock *, des_cblock *, des_key_schedule, + des_key_schedule, des_key_schedule, int)); + +void des_ncbc_encrypt __P((const unsigned char *, unsigned char *, long, + des_key_schedule, des_cblock *, int)); + +void des_ede3_cbc_encrypt(const unsigned char *, unsigned char *, long, + des_key_schedule, des_key_schedule, + des_key_schedule, des_cblock *, int); void des_set_odd_parity __P((des_cblock *)); +void des_fixup_key_parity __P((des_cblock *)); int des_is_weak_key __P((des_cblock *)); int des_set_key __P((des_cblock *, des_key_schedule)); int des_key_sched __P((des_cblock *, des_key_schedule)); +int des_set_key_checked __P((des_cblock *, des_key_schedule)); +void des_set_key_unchecked __P((des_cblock *, des_key_schedule)); +int des_check_key_parity __P((des_cblock *)); #ifdef __cplusplus } diff -urN xnu-344.49/bsd/crypto/des/des_ecb.c xnu-517/bsd/crypto/des/des_ecb.c --- xnu-344.49/bsd/crypto/des/des_ecb.c Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/des/des_ecb.c Sat Oct 25 00:25:25 2003 @@ -1,8 +1,8 @@ -/* $FreeBSD: src/sys/crypto/des/des_ecb.c,v 1.1.2.2 2001/07/03 11:01:31 ume Exp $ */ -/* $KAME: des_ecb.c,v 1.5 2000/11/06 13:58:08 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/des/des_ecb.c,v 1.1.2.3 2002/03/26 10:12:24 ume Exp $ */ +/* $KAME: des_ecb.c,v 1.6 2001/09/10 04:03:58 itojun Exp $ */ /* crypto/des/ecb_enc.c */ -/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) +/* Copyright (C) 1995-1998 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written @@ -53,182 +53,84 @@ #include #include -char *libdes_version="libdes v 3.24 - 20-Apr-1996 - eay"; -char *DES_version="DES part of SSLeay 0.6.4 30-Aug-1996"; +/* char *libdes_version="libdes v 3.24 - 20-Apr-1996 - eay"; */ /* wrong */ +/* char *DES_version="DES part of SSLeay 0.6.4 30-Aug-1996"; */ + +char *des_options(void) + { + static int init=1; + static char buf[32]; + + if (init) + { + const char *ptr,*unroll,*risc,*size; -char *des_options() - { #ifdef DES_PTR - if (sizeof(DES_LONG) != sizeof(long)) - return("des(ptr,int)"); - else - return("des(ptr,long)"); + ptr="ptr"; #else - if (sizeof(DES_LONG) != sizeof(long)) - return("des(idx,int)"); - else - return("des(idx,long)"); + ptr="idx"; #endif - } - - -void des_ecb_encrypt(input, output, ks, encrypt) -des_cblock (*input); -des_cblock (*output); -des_key_schedule ks; -int encrypt; - { +#if defined(DES_RISC1) || defined(DES_RISC2) +#ifdef DES_RISC1 + risc="risc1"; +#endif +#ifdef DES_RISC2 + risc="risc2"; +#endif +#else + risc="cisc"; +#endif +#ifdef DES_UNROLL + unroll="16"; +#else + unroll="4"; +#endif + if (sizeof(DES_LONG) != sizeof(long)) + size="int"; + else + size="long"; + sprintf(buf,"des(%s,%s,%s,%s)",ptr,risc,unroll,size); + init=0; + } + return(buf); +} +void des_ecb_encrypt(des_cblock *input, des_cblock *output, + des_key_schedule ks, int enc) +{ register DES_LONG l; - register unsigned char *in,*out; DES_LONG ll[2]; + const unsigned char *in=&(*input)[0]; + unsigned char *out = &(*output)[0]; - in=(unsigned char *)input; - out=(unsigned char *)output; c2l(in,l); ll[0]=l; c2l(in,l); ll[1]=l; - des_encrypt(ll,ks,encrypt); + des_encrypt1(ll,ks,enc); l=ll[0]; l2c(l,out); l=ll[1]; l2c(l,out); l=ll[0]=ll[1]=0; - } +} -void des_encrypt(data, ks, encrypt) -DES_LONG *data; -des_key_schedule ks; -int encrypt; - { - register DES_LONG l,r,t,u; -#ifdef DES_PTR - register unsigned char *des_SP=(unsigned char *)des_SPtrans; -#endif -#ifdef undef - union fudge { - DES_LONG l; - unsigned short s[2]; - unsigned char c[4]; - } U,T; -#endif - register int i; - register DES_LONG *s; - - u=data[0]; - r=data[1]; +void des_ecb3_encrypt(des_cblock *input, des_cblock *output, + des_key_schedule ks1, des_key_schedule ks2, des_key_schedule ks3, + int enc) +{ + register DES_LONG l0,l1; + DES_LONG ll[2]; + const unsigned char *in = &(*input)[0]; + unsigned char *out = &(*output)[0]; + + c2l(in,l0); + c2l(in,l1); + ll[0]=l0; + ll[1]=l1; - IP(u,r); - /* Things have been modified so that the initial rotate is - * done outside the loop. This required the - * des_SPtrans values in sp.h to be rotated 1 bit to the right. - * One perl script later and things have a 5% speed up on a sparc2. - * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> - * for pointing this out. */ - l=(r<<1)|(r>>31); - r=(u<<1)|(u>>31); - - /* clear the top bits on machines with 8byte longs */ - l&=0xffffffffL; - r&=0xffffffffL; - - s=(DES_LONG *)ks; - /* I don't know if it is worth the effort of loop unrolling the - * inner loop - */ - if (encrypt) - { - for (i=0; i<32; i+=8) - { - D_ENCRYPT(l,r,i+0); /* 1 */ - D_ENCRYPT(r,l,i+2); /* 2 */ - D_ENCRYPT(l,r,i+4); /* 3 */ - D_ENCRYPT(r,l,i+6); /* 4 */ - } - } + if (enc) + des_encrypt3(ll,ks1,ks2,ks3); else - { - for (i=30; i>0; i-=8) - { - D_ENCRYPT(l,r,i-0); /* 16 */ - D_ENCRYPT(r,l,i-2); /* 15 */ - D_ENCRYPT(l,r,i-4); /* 14 */ - D_ENCRYPT(r,l,i-6); /* 13 */ - } - } - l=(l>>1)|(l<<31); - r=(r>>1)|(r<<31); - /* clear the top bits on machines with 8byte longs */ - l&=0xffffffffL; - r&=0xffffffffL; - - FP(r,l); - data[0]=l; - data[1]=r; - l=r=t=u=0; - } - -void des_encrypt2(data, ks, encrypt) -DES_LONG *data; -des_key_schedule ks; -int encrypt; - { - register DES_LONG l,r,t,u; -#ifdef DES_PTR - register unsigned char *des_SP=(unsigned char *)des_SPtrans; -#endif -#ifdef undef - union fudge { - DES_LONG l; - unsigned short s[2]; - unsigned char c[4]; - } U,T; -#endif - register int i; - register DES_LONG *s; + des_decrypt3(ll,ks1,ks2,ks3); - u=data[0]; - r=data[1]; - - /* Things have been modified so that the initial rotate is - * done outside the loop. This required the - * des_SPtrans values in sp.h to be rotated 1 bit to the right. - * One perl script later and things have a 5% speed up on a sparc2. - * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> - * for pointing this out. */ - l=(r<<1)|(r>>31); - r=(u<<1)|(u>>31); - - /* clear the top bits on machines with 8byte longs */ - l&=0xffffffffL; - r&=0xffffffffL; - - s=(DES_LONG *)ks; - /* I don't know if it is worth the effort of loop unrolling the - * inner loop */ - if (encrypt) - { - for (i=0; i<32; i+=8) - { - D_ENCRYPT(l,r,i+0); /* 1 */ - D_ENCRYPT(r,l,i+2); /* 2 */ - D_ENCRYPT(l,r,i+4); /* 3 */ - D_ENCRYPT(r,l,i+6); /* 4 */ - } - } - else - { - for (i=30; i>0; i-=8) - { - D_ENCRYPT(l,r,i-0); /* 16 */ - D_ENCRYPT(r,l,i-2); /* 15 */ - D_ENCRYPT(l,r,i-4); /* 14 */ - D_ENCRYPT(r,l,i-6); /* 13 */ - } - } - l=(l>>1)|(l<<31); - r=(r>>1)|(r<<31); - /* clear the top bits on machines with 8byte longs */ - l&=0xffffffffL; - r&=0xffffffffL; - - data[0]=l; - data[1]=r; - l=r=t=u=0; - } + l0=ll[0]; + l1=ll[1]; + l2c(l0,out); + l2c(l1,out); +} diff -urN xnu-344.49/bsd/crypto/des/des_enc.c xnu-517/bsd/crypto/des/des_enc.c --- xnu-344.49/bsd/crypto/des/des_enc.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/crypto/des/des_enc.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,294 @@ +/* $KAME: kame/kame/sys/crypto/des/des_enc.c,v 1.1 2001/09/10 04:03:58 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/des/des_enc.c,v 1.1.2.1 2002/03/26 10:12:24 ume Exp $ */ + +/* crypto/des/des_enc.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include + +extern const DES_LONG des_SPtrans[8][64]; + +void des_encrypt1(DES_LONG *data, des_key_schedule ks, int enc) +{ + register DES_LONG l,r,t,u; +#ifdef DES_PTR + register const unsigned char *des_SP=(const unsigned char *)des_SPtrans; +#endif +#ifndef DES_UNROLL + register int i; +#endif + register DES_LONG *s; + + r=data[0]; + l=data[1]; + + IP(r,l); + /* Things have been modified so that the initial rotate is + * done outside the loop. This required the + * des_SPtrans values in sp.h to be rotated 1 bit to the right. + * One perl script later and things have a 5% speed up on a sparc2. + * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> + * for pointing this out. */ + /* clear the top bits on machines with 8byte longs */ + /* shift left by 2 */ + r=ROTATE(r,29)&0xffffffffL; + l=ROTATE(l,29)&0xffffffffL; + + s=ks->ks.deslong; + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) + { +#ifdef DES_UNROLL + D_ENCRYPT(l,r, 0); /* 1 */ + D_ENCRYPT(r,l, 2); /* 2 */ + D_ENCRYPT(l,r, 4); /* 3 */ + D_ENCRYPT(r,l, 6); /* 4 */ + D_ENCRYPT(l,r, 8); /* 5 */ + D_ENCRYPT(r,l,10); /* 6 */ + D_ENCRYPT(l,r,12); /* 7 */ + D_ENCRYPT(r,l,14); /* 8 */ + D_ENCRYPT(l,r,16); /* 9 */ + D_ENCRYPT(r,l,18); /* 10 */ + D_ENCRYPT(l,r,20); /* 11 */ + D_ENCRYPT(r,l,22); /* 12 */ + D_ENCRYPT(l,r,24); /* 13 */ + D_ENCRYPT(r,l,26); /* 14 */ + D_ENCRYPT(l,r,28); /* 15 */ + D_ENCRYPT(r,l,30); /* 16 */ +#else + for (i=0; i<32; i+=8) + { + D_ENCRYPT(l,r,i+0); /* 1 */ + D_ENCRYPT(r,l,i+2); /* 2 */ + D_ENCRYPT(l,r,i+4); /* 3 */ + D_ENCRYPT(r,l,i+6); /* 4 */ + } +#endif + } + else + { +#ifdef DES_UNROLL + D_ENCRYPT(l,r,30); /* 16 */ + D_ENCRYPT(r,l,28); /* 15 */ + D_ENCRYPT(l,r,26); /* 14 */ + D_ENCRYPT(r,l,24); /* 13 */ + D_ENCRYPT(l,r,22); /* 12 */ + D_ENCRYPT(r,l,20); /* 11 */ + D_ENCRYPT(l,r,18); /* 10 */ + D_ENCRYPT(r,l,16); /* 9 */ + D_ENCRYPT(l,r,14); /* 8 */ + D_ENCRYPT(r,l,12); /* 7 */ + D_ENCRYPT(l,r,10); /* 6 */ + D_ENCRYPT(r,l, 8); /* 5 */ + D_ENCRYPT(l,r, 6); /* 4 */ + D_ENCRYPT(r,l, 4); /* 3 */ + D_ENCRYPT(l,r, 2); /* 2 */ + D_ENCRYPT(r,l, 0); /* 1 */ +#else + for (i=30; i>0; i-=8) + { + D_ENCRYPT(l,r,i-0); /* 16 */ + D_ENCRYPT(r,l,i-2); /* 15 */ + D_ENCRYPT(l,r,i-4); /* 14 */ + D_ENCRYPT(r,l,i-6); /* 13 */ + } +#endif + } + + /* rotate and clear the top bits on machines with 8byte longs */ + l=ROTATE(l,3)&0xffffffffL; + r=ROTATE(r,3)&0xffffffffL; + + FP(r,l); + data[0]=l; + data[1]=r; + l=r=t=u=0; +} + +void des_encrypt2(DES_LONG *data, des_key_schedule ks, int enc) +{ + register DES_LONG l,r,t,u; +#ifdef DES_PTR + register const unsigned char *des_SP=(const unsigned char *)des_SPtrans; +#endif +#ifndef DES_UNROLL + register int i; +#endif + register DES_LONG *s; + + r=data[0]; + l=data[1]; + + /* Things have been modified so that the initial rotate is + * done outside the loop. This required the + * des_SPtrans values in sp.h to be rotated 1 bit to the right. + * One perl script later and things have a 5% speed up on a sparc2. + * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> + * for pointing this out. */ + /* clear the top bits on machines with 8byte longs */ + r=ROTATE(r,29)&0xffffffffL; + l=ROTATE(l,29)&0xffffffffL; + + s=ks->ks.deslong; + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) + { +#ifdef DES_UNROLL + D_ENCRYPT(l,r, 0); /* 1 */ + D_ENCRYPT(r,l, 2); /* 2 */ + D_ENCRYPT(l,r, 4); /* 3 */ + D_ENCRYPT(r,l, 6); /* 4 */ + D_ENCRYPT(l,r, 8); /* 5 */ + D_ENCRYPT(r,l,10); /* 6 */ + D_ENCRYPT(l,r,12); /* 7 */ + D_ENCRYPT(r,l,14); /* 8 */ + D_ENCRYPT(l,r,16); /* 9 */ + D_ENCRYPT(r,l,18); /* 10 */ + D_ENCRYPT(l,r,20); /* 11 */ + D_ENCRYPT(r,l,22); /* 12 */ + D_ENCRYPT(l,r,24); /* 13 */ + D_ENCRYPT(r,l,26); /* 14 */ + D_ENCRYPT(l,r,28); /* 15 */ + D_ENCRYPT(r,l,30); /* 16 */ +#else + for (i=0; i<32; i+=8) + { + D_ENCRYPT(l,r,i+0); /* 1 */ + D_ENCRYPT(r,l,i+2); /* 2 */ + D_ENCRYPT(l,r,i+4); /* 3 */ + D_ENCRYPT(r,l,i+6); /* 4 */ + } +#endif + } + else + { +#ifdef DES_UNROLL + D_ENCRYPT(l,r,30); /* 16 */ + D_ENCRYPT(r,l,28); /* 15 */ + D_ENCRYPT(l,r,26); /* 14 */ + D_ENCRYPT(r,l,24); /* 13 */ + D_ENCRYPT(l,r,22); /* 12 */ + D_ENCRYPT(r,l,20); /* 11 */ + D_ENCRYPT(l,r,18); /* 10 */ + D_ENCRYPT(r,l,16); /* 9 */ + D_ENCRYPT(l,r,14); /* 8 */ + D_ENCRYPT(r,l,12); /* 7 */ + D_ENCRYPT(l,r,10); /* 6 */ + D_ENCRYPT(r,l, 8); /* 5 */ + D_ENCRYPT(l,r, 6); /* 4 */ + D_ENCRYPT(r,l, 4); /* 3 */ + D_ENCRYPT(l,r, 2); /* 2 */ + D_ENCRYPT(r,l, 0); /* 1 */ +#else + for (i=30; i>0; i-=8) + { + D_ENCRYPT(l,r,i-0); /* 16 */ + D_ENCRYPT(r,l,i-2); /* 15 */ + D_ENCRYPT(l,r,i-4); /* 14 */ + D_ENCRYPT(r,l,i-6); /* 13 */ + } +#endif + } + /* rotate and clear the top bits on machines with 8byte longs */ + data[0]=ROTATE(l,3)&0xffffffffL; + data[1]=ROTATE(r,3)&0xffffffffL; + l=r=t=u=0; +} + +void des_encrypt3(DES_LONG *data, des_key_schedule ks1, des_key_schedule ks2, + des_key_schedule ks3) +{ + register DES_LONG l,r; + + l=data[0]; + r=data[1]; + IP(l,r); + data[0]=l; + data[1]=r; + des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT); + des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT); + des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT); + l=data[0]; + r=data[1]; + FP(r,l); + data[0]=l; + data[1]=r; +} + +void des_decrypt3(DES_LONG *data, des_key_schedule ks1, des_key_schedule ks2, + des_key_schedule ks3) +{ + register DES_LONG l,r; + + l=data[0]; + r=data[1]; + IP(l,r); + data[0]=l; + data[1]=r; + des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT); + des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT); + des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT); + l=data[0]; + r=data[1]; + FP(r,l); + data[0]=l; + data[1]=r; +} diff -urN xnu-344.49/bsd/crypto/des/des_locl.h xnu-517/bsd/crypto/des/des_locl.h --- xnu-344.49/bsd/crypto/des/des_locl.h Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/des/des_locl.h Sat Oct 25 00:25:25 2003 @@ -1,8 +1,8 @@ -/* $FreeBSD: src/sys/crypto/des/des_locl.h,v 1.2.2.2 2001/07/03 11:01:31 ume Exp $ */ -/* $KAME: des_locl.h,v 1.6 2000/11/06 13:58:09 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/des/des_locl.h,v 1.2.2.3 2002/03/26 10:12:25 ume Exp $ */ +/* $KAME: des_locl.h,v 1.7 2001/09/10 04:03:58 itojun Exp $ */ -/* lib/des/des_locl.h */ -/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) +/* crypto/des/des_locl.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written @@ -47,13 +47,6 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - * - * Always modify des_locl.org since des_locl.h is automatically generated from - * it during SSLeay configuration. - * - * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - */ #ifndef HEADER_DES_LOCL_H #define HEADER_DES_LOCL_H @@ -130,6 +123,11 @@ #define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n)))) +#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g) +#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ + u=R^s[S ]; \ + t=R^s[S+1] + /* The changes to this macro may help or hinder, depending on the * compiler and the achitecture. gcc2 always seems to do well :-). * Inspired by Dana How @@ -138,49 +136,170 @@ * bytes, probably an issue of accessing non-word aligned objects :-( */ #ifdef DES_PTR -#define D_ENCRYPT(L,R,S) { \ - u=((R^s[S ])<<2); \ - t= R^s[S+1]; \ - t=ROTATE(t,2); \ - L^= (\ - *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))+ \ - *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8)&0xfc))+ \ - *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16)&0xfc))+ \ - *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24)&0xfc))+ \ - *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))+ \ - *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8)&0xfc))+ \ - *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16)&0xfc))+ \ - *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24)&0xfc))); } +/* It recently occurred to me that 0^0^0^0^0^0^0 == 0, so there + * is no reason to not xor all the sub items together. This potentially + * saves a register since things can be xored directly into L */ + +#if defined(DES_RISC1) || defined(DES_RISC2) +#ifdef DES_RISC1 +#define D_ENCRYPT(LL,R,S) { \ + unsigned int u1,u2,u3; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u2=(int)u>>8L; \ + u1=(int)u&0xfc; \ + u2&=0xfc; \ + t=ROTATE(t,4); \ + u>>=16L; \ + LL^= *(const DES_LONG *)(des_SP +u1); \ + LL^= *(const DES_LONG *)(des_SP+0x200+u2); \ + u3=(int)(u>>8L); \ + u1=(int)u&0xfc; \ + u3&=0xfc; \ + LL^= *(const DES_LONG *)(des_SP+0x400+u1); \ + LL^= *(const DES_LONG *)(des_SP+0x600+u3); \ + u2=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u2&=0xfc; \ + t>>=16L; \ + LL^= *(const DES_LONG *)(des_SP+0x100+u1); \ + LL^= *(const DES_LONG *)(des_SP+0x300+u2); \ + u3=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u3&=0xfc; \ + LL^= *(const DES_LONG *)(des_SP+0x500+u1); \ + LL^= *(const DES_LONG *)(des_SP+0x700+u3); } +#endif /* DES_RISC1 */ +#ifdef DES_RISC2 +#define D_ENCRYPT(LL,R,S) { \ + unsigned int u1,u2,s1,s2; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u2=(int)u>>8L; \ + u1=(int)u&0xfc; \ + u2&=0xfc; \ + t=ROTATE(t,4); \ + LL^= *(const DES_LONG *)(des_SP +u1); \ + LL^= *(const DES_LONG *)(des_SP+0x200+u2); \ + s1=(int)(u>>16L); \ + s2=(int)(u>>24L); \ + s1&=0xfc; \ + s2&=0xfc; \ + LL^= *(const DES_LONG *)(des_SP+0x400+s1); \ + LL^= *(const DES_LONG *)(des_SP+0x600+s2); \ + u2=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u2&=0xfc; \ + LL^= *(const DES_LONG *)(des_SP+0x100+u1); \ + LL^= *(const DES_LONG *)(des_SP+0x300+u2); \ + s1=(int)(t>>16L); \ + s2=(int)(t>>24L); \ + s1&=0xfc; \ + s2&=0xfc; \ + LL^= *(const DES_LONG *)(des_SP+0x400+s1); \ + LL^= *(const DES_LONG *)(des_SP+0x600+s2); \ + u2=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u2&=0xfc; \ + LL^= *(const DES_LONG *)(des_SP+0x100+u1); \ + LL^= *(const DES_LONG *)(des_SP+0x300+u2); \ + s1=(int)(t>>16L); \ + s2=(int)(t>>24L); \ + s1&=0xfc; \ + s2&=0xfc; \ + LL^= *(const DES_LONG *)(des_SP+0x500+s1); \ + LL^= *(const DES_LONG *)(des_SP+0x700+s2); } +#endif /* DES_RISC2 */ +#else /* DES_RISC1 || DES_RISC2 */ +#define D_ENCRYPT(LL,R,S) { \ + LOAD_DATA_tmp(R,S,u,t,E0,E1); \ + t=ROTATE(t,4); \ + LL^= \ + *(const DES_LONG *)(des_SP +((u )&0xfc))^ \ + *(const DES_LONG *)(des_SP+0x200+((u>> 8L)&0xfc))^ \ + *(const DES_LONG *)(des_SP+0x400+((u>>16L)&0xfc))^ \ + *(const DES_LONG *)(des_SP+0x600+((u>>24L)&0xfc))^ \ + *(const DES_LONG *)(des_SP+0x100+((t )&0xfc))^ \ + *(const DES_LONG *)(des_SP+0x300+((t>> 8L)&0xfc))^ \ + *(const DES_LONG *)(des_SP+0x500+((t>>16L)&0xfc))^ \ + *(const DES_LONG *)(des_SP+0x700+((t>>24L)&0xfc)); } +#endif /* DES_RISC1 || DES_RISC2 */ #else /* original version */ -#ifdef undef -#define D_ENCRYPT(L,R,S) \ - U.l=R^s[S+1]; \ - T.s[0]=((U.s[0]>>4)|(U.s[1]<<12))&0x3f3f; \ - T.s[1]=((U.s[1]>>4)|(U.s[0]<<12))&0x3f3f; \ - U.l=(R^s[S ])&0x3f3f3f3fL; \ - L^= des_SPtrans[1][(T.c[0])]| \ - des_SPtrans[3][(T.c[1])]| \ - des_SPtrans[5][(T.c[2])]| \ - des_SPtrans[7][(T.c[3])]| \ - des_SPtrans[0][(U.c[0])]| \ - des_SPtrans[2][(U.c[1])]| \ - des_SPtrans[4][(U.c[2])]| \ - des_SPtrans[6][(U.c[3])]; -#else -#define D_ENCRYPT(Q,R,S) {\ - u=(R^s[S ]); \ - t=R^s[S+1]; \ + +#if defined(DES_RISC1) || defined(DES_RISC2) +#ifdef DES_RISC1 +#define D_ENCRYPT(LL,R,S) {\ + unsigned int u1,u2,u3; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u>>=2L; \ + t=ROTATE(t,6); \ + u2=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u2&=0x3f; \ + u>>=16L; \ + LL^=des_SPtrans[0][u1]; \ + LL^=des_SPtrans[2][u2]; \ + u3=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u3&=0x3f; \ + LL^=des_SPtrans[4][u1]; \ + LL^=des_SPtrans[6][u3]; \ + u2=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u2&=0x3f; \ + t>>=16L; \ + LL^=des_SPtrans[1][u1]; \ + LL^=des_SPtrans[3][u2]; \ + u3=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u3&=0x3f; \ + LL^=des_SPtrans[5][u1]; \ + LL^=des_SPtrans[7][u3]; } +#endif /* DES_RISC1 */ +#ifdef DES_RISC2 +#define D_ENCRYPT(LL,R,S) {\ + unsigned int u1,u2,s1,s2; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u>>=2L; \ + t=ROTATE(t,6); \ + u2=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u2&=0x3f; \ + LL^=des_SPtrans[0][u1]; \ + LL^=des_SPtrans[2][u2]; \ + s1=(int)u>>16L; \ + s2=(int)u>>24L; \ + s1&=0x3f; \ + s2&=0x3f; \ + LL^=des_SPtrans[4][s1]; \ + LL^=des_SPtrans[6][s2]; \ + u2=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u2&=0x3f; \ + LL^=des_SPtrans[1][u1]; \ + LL^=des_SPtrans[3][u2]; \ + s1=(int)t>>16; \ + s2=(int)t>>24L; \ + s1&=0x3f; \ + s2&=0x3f; \ + LL^=des_SPtrans[5][s1]; \ + LL^=des_SPtrans[7][s2]; } +#endif /* DES_RISC2 */ + +#else /* DES_RISC1 || DES_RISC2 */ + +#define D_ENCRYPT(LL,R,S) {\ + LOAD_DATA_tmp(R,S,u,t,E0,E1); \ t=ROTATE(t,4); \ - Q^= des_SPtrans[1][(t )&0x3f]| \ - des_SPtrans[3][(t>> 8L)&0x3f]| \ - des_SPtrans[5][(t>>16L)&0x3f]| \ - des_SPtrans[7][(t>>24L)&0x3f]| \ - des_SPtrans[0][(u )&0x3f]| \ - des_SPtrans[2][(u>> 8L)&0x3f]| \ - des_SPtrans[4][(u>>16L)&0x3f]| \ - des_SPtrans[6][(u>>24L)&0x3f]; } -#endif -#endif + LL^=\ + des_SPtrans[0][(u>> 2L)&0x3f]^ \ + des_SPtrans[2][(u>>10L)&0x3f]^ \ + des_SPtrans[4][(u>>18L)&0x3f]^ \ + des_SPtrans[6][(u>>26L)&0x3f]^ \ + des_SPtrans[1][(t>> 2L)&0x3f]^ \ + des_SPtrans[3][(t>>10L)&0x3f]^ \ + des_SPtrans[5][(t>>18L)&0x3f]^ \ + des_SPtrans[7][(t>>26L)&0x3f]; } +#endif /* DES_RISC1 || DES_RISC2 */ +#endif /* DES_PTR */ /* IP and FP * The problem is more of a geometric problem that random bit fiddling. diff -urN xnu-344.49/bsd/crypto/des/des_setkey.c xnu-517/bsd/crypto/des/des_setkey.c --- xnu-344.49/bsd/crypto/des/des_setkey.c Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/des/des_setkey.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ -/* $FreeBSD: src/sys/crypto/des/des_setkey.c,v 1.1.2.3 2001/07/10 09:46:35 ume Exp $ */ -/* $KAME: des_setkey.c,v 1.6 2001/07/03 14:27:53 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/des/des_setkey.c,v 1.1.2.4 2002/03/26 10:12:25 ume Exp $ */ +/* $KAME: des_setkey.c,v 1.7 2001/09/10 04:03:58 itojun Exp $ */ /* crypto/des/set_key.c */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) @@ -61,22 +61,18 @@ #include #include -static int check_parity __P((des_cblock (*))); - int des_check_key=0; -void des_set_odd_parity(key) -des_cblock (*key); - { +void des_set_odd_parity(des_cblock *key) +{ int i; for (i=0; i>(n))^(b))&(m)),\ * (b)^=(t),\ * (a)=((a)^((t)<<(n)))) @@ -141,49 +138,48 @@ #define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\ (a)=(a)^(t)^(t>>(16-(n)))) +int des_set_key(des_cblock *key, des_key_schedule schedule) +{ + if (des_check_key) + { + return des_set_key_checked(key, schedule); + } + else + { + des_set_key_unchecked(key, schedule); + return 0; + } +} + /* return 0 if key parity is odd (correct), * return -1 if key parity error, * return -2 if illegal weak key. */ -int des_set_key(key, schedule) -des_cblock (*key); -des_key_schedule schedule; - { +int des_set_key_checked(des_cblock *key, des_key_schedule schedule) +{ + if (!des_check_key_parity(key)) + return(-1); + if (des_is_weak_key(key)) + return(-2); + des_set_key_unchecked(key, schedule); + return 0; +} + +void des_set_key_unchecked(des_cblock *key, des_key_schedule schedule) +{ static int shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0}; - register DES_LONG c,d,t,s; - register unsigned char *in; + register DES_LONG c,d,t,s,t2; + register const unsigned char *in; register DES_LONG *k; register int i; - if (des_check_key) - { - if (!check_parity(key)) - return(-1); - - if (des_is_weak_key(key)) - return(-2); - } - - k=(DES_LONG *)schedule; - in=(unsigned char *)key; + k = &schedule->ks.deslong[0]; + in = &(*key)[0]; c2l(in,c); c2l(in,d); - /* do PC1 in 60 simple operations */ -/* PERM_OP(d,c,t,4,0x0f0f0f0fL); - HPERM_OP(c,t,-2, 0xcccc0000L); - HPERM_OP(c,t,-1, 0xaaaa0000L); - HPERM_OP(c,t, 8, 0x00ff0000L); - HPERM_OP(c,t,-1, 0xaaaa0000L); - HPERM_OP(d,t,-8, 0xff000000L); - HPERM_OP(d,t, 8, 0x00ff0000L); - HPERM_OP(d,t, 2, 0x33330000L); - d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L); - d=(d>>8)|((c&0xf0000000L)>>4); - c&=0x0fffffffL; */ - - /* I now do it in 47 simple operations :-) + /* do PC1 in 47 simple operations :-) * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov) * for the inspiration. :-) */ PERM_OP (d,c,t,4,0x0f0f0f0fL); @@ -197,7 +193,7 @@ c&=0x0fffffffL; for (i=0; i>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); } else @@ -205,30 +201,32 @@ c&=0x0fffffffL; d&=0x0fffffffL; /* could be a few less shifts but I am to lazy at this - * point in time to investigate */ + * point in time to investigate */ s= des_skb[0][ (c )&0x3f ]| - des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]| - des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]| - des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) | - ((c>>22L)&0x38)]; + des_skb[1][((c>> 6L)&0x03)|((c>> 7L)&0x3c)]| + des_skb[2][((c>>13L)&0x0f)|((c>>14L)&0x30)]| + des_skb[3][((c>>20L)&0x01)|((c>>21L)&0x06) | + ((c>>22L)&0x38)]; t= des_skb[4][ (d )&0x3f ]| des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]| des_skb[6][ (d>>15L)&0x3f ]| des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)]; /* table contained 0213 4657 */ - *(k++)=((t<<16L)|(s&0x0000ffffL))&0xffffffffL; - s= ((s>>16L)|(t&0xffff0000L)); - - s=(s<<4L)|(s>>28L); - *(k++)=s&0xffffffffL; - } - return(0); + t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL; + *(k++)=ROTATE(t2,30)&0xffffffffL; + + t2=((s>>16L)|(t&0xffff0000L)); + *(k++)=ROTATE(t2,26)&0xffffffffL; } +} -int des_key_sched(key, schedule) -des_cblock (*key); -des_key_schedule schedule; - { +int des_key_sched(des_cblock *key, des_key_schedule schedule) +{ return(des_set_key(key,schedule)); - } +} + +void des_fixup_key_parity(des_cblock *key) +{ + des_set_odd_parity(key); +} diff -urN xnu-344.49/bsd/crypto/des/spr.h xnu-517/bsd/crypto/des/spr.h --- xnu-344.49/bsd/crypto/des/spr.h Thu Sep 18 21:00:31 2003 +++ xnu-517/bsd/crypto/des/spr.h Sat Oct 25 00:25:25 2003 @@ -1,23 +1,28 @@ -/* $FreeBSD: src/sys/crypto/des/spr.h,v 1.1.2.1 2000/07/15 07:14:22 kris Exp $ */ -/* $KAME: spr.h,v 1.3 2000/03/27 04:36:35 sumikawa Exp $ */ +/* $FreeBSD: src/sys/crypto/des/spr.h,v 1.1.2.2 2002/03/26 10:12:25 ume Exp $ */ +/* $KAME: spr.h,v 1.4 2001/09/10 04:03:58 itojun Exp $ */ /* crypto/des/spr.h */ -/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * - * This file is part of an SSL implementation written - * by Eric Young (eay@mincom.oz.au). - * The implementation was written so as to conform with Netscapes SSL - * specification. This library and applications are - * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE - * as long as the following conditions are aheared to. - * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. If this code is used in a product, - * Eric Young should be given attribution as the author of the parts used. + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -28,8 +33,14 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by Eric Young (eay@mincom.oz.au) - * + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -41,156 +52,156 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ -static const DES_LONG des_SPtrans[8][64]={ +const DES_LONG des_SPtrans[8][64]={ { /* nibble 0 */ -0x00820200L, 0x00020000L, 0x80800000L, 0x80820200L, -0x00800000L, 0x80020200L, 0x80020000L, 0x80800000L, -0x80020200L, 0x00820200L, 0x00820000L, 0x80000200L, -0x80800200L, 0x00800000L, 0x00000000L, 0x80020000L, -0x00020000L, 0x80000000L, 0x00800200L, 0x00020200L, -0x80820200L, 0x00820000L, 0x80000200L, 0x00800200L, -0x80000000L, 0x00000200L, 0x00020200L, 0x80820000L, -0x00000200L, 0x80800200L, 0x80820000L, 0x00000000L, -0x00000000L, 0x80820200L, 0x00800200L, 0x80020000L, -0x00820200L, 0x00020000L, 0x80000200L, 0x00800200L, -0x80820000L, 0x00000200L, 0x00020200L, 0x80800000L, -0x80020200L, 0x80000000L, 0x80800000L, 0x00820000L, -0x80820200L, 0x00020200L, 0x00820000L, 0x80800200L, -0x00800000L, 0x80000200L, 0x80020000L, 0x00000000L, -0x00020000L, 0x00800000L, 0x80800200L, 0x00820200L, -0x80000000L, 0x80820000L, 0x00000200L, 0x80020200L, +0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L, +0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L, +0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L, +0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L, +0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L, +0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L, +0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L, +0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L, +0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L, +0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L, +0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L, +0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L, +0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L, +0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L, +0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L, +0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L, },{ /* nibble 1 */ -0x10042004L, 0x00000000L, 0x00042000L, 0x10040000L, -0x10000004L, 0x00002004L, 0x10002000L, 0x00042000L, -0x00002000L, 0x10040004L, 0x00000004L, 0x10002000L, -0x00040004L, 0x10042000L, 0x10040000L, 0x00000004L, -0x00040000L, 0x10002004L, 0x10040004L, 0x00002000L, -0x00042004L, 0x10000000L, 0x00000000L, 0x00040004L, -0x10002004L, 0x00042004L, 0x10042000L, 0x10000004L, -0x10000000L, 0x00040000L, 0x00002004L, 0x10042004L, -0x00040004L, 0x10042000L, 0x10002000L, 0x00042004L, -0x10042004L, 0x00040004L, 0x10000004L, 0x00000000L, -0x10000000L, 0x00002004L, 0x00040000L, 0x10040004L, -0x00002000L, 0x10000000L, 0x00042004L, 0x10002004L, -0x10042000L, 0x00002000L, 0x00000000L, 0x10000004L, -0x00000004L, 0x10042004L, 0x00042000L, 0x10040000L, -0x10040004L, 0x00040000L, 0x00002004L, 0x10002000L, -0x10002004L, 0x00000004L, 0x10040000L, 0x00042000L, +0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L, +0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L, +0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L, +0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L, +0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L, +0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L, +0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L, +0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L, +0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L, +0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L, +0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L, +0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L, +0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L, +0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L, +0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L, +0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L, },{ /* nibble 2 */ -0x41000000L, 0x01010040L, 0x00000040L, 0x41000040L, -0x40010000L, 0x01000000L, 0x41000040L, 0x00010040L, -0x01000040L, 0x00010000L, 0x01010000L, 0x40000000L, -0x41010040L, 0x40000040L, 0x40000000L, 0x41010000L, -0x00000000L, 0x40010000L, 0x01010040L, 0x00000040L, -0x40000040L, 0x41010040L, 0x00010000L, 0x41000000L, -0x41010000L, 0x01000040L, 0x40010040L, 0x01010000L, -0x00010040L, 0x00000000L, 0x01000000L, 0x40010040L, -0x01010040L, 0x00000040L, 0x40000000L, 0x00010000L, -0x40000040L, 0x40010000L, 0x01010000L, 0x41000040L, -0x00000000L, 0x01010040L, 0x00010040L, 0x41010000L, -0x40010000L, 0x01000000L, 0x41010040L, 0x40000000L, -0x40010040L, 0x41000000L, 0x01000000L, 0x41010040L, -0x00010000L, 0x01000040L, 0x41000040L, 0x00010040L, -0x01000040L, 0x00000000L, 0x41010000L, 0x40000040L, -0x41000000L, 0x40010040L, 0x00000040L, 0x01010000L, +0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L, +0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L, +0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L, +0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L, +0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L, +0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L, +0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L, +0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L, +0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L, +0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L, +0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L, +0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L, +0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L, +0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L, +0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L, +0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L, },{ /* nibble 3 */ -0x00100402L, 0x04000400L, 0x00000002L, 0x04100402L, -0x00000000L, 0x04100000L, 0x04000402L, 0x00100002L, -0x04100400L, 0x04000002L, 0x04000000L, 0x00000402L, -0x04000002L, 0x00100402L, 0x00100000L, 0x04000000L, -0x04100002L, 0x00100400L, 0x00000400L, 0x00000002L, -0x00100400L, 0x04000402L, 0x04100000L, 0x00000400L, -0x00000402L, 0x00000000L, 0x00100002L, 0x04100400L, -0x04000400L, 0x04100002L, 0x04100402L, 0x00100000L, -0x04100002L, 0x00000402L, 0x00100000L, 0x04000002L, -0x00100400L, 0x04000400L, 0x00000002L, 0x04100000L, -0x04000402L, 0x00000000L, 0x00000400L, 0x00100002L, -0x00000000L, 0x04100002L, 0x04100400L, 0x00000400L, -0x04000000L, 0x04100402L, 0x00100402L, 0x00100000L, -0x04100402L, 0x00000002L, 0x04000400L, 0x00100402L, -0x00100002L, 0x00100400L, 0x04100000L, 0x04000402L, -0x00000402L, 0x04000000L, 0x04000002L, 0x04100400L, +0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L, +0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L, +0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L, +0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L, +0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L, +0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L, +0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L, +0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L, +0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L, +0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L, +0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L, +0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L, +0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L, +0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L, +0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L, +0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L, },{ /* nibble 4 */ -0x02000000L, 0x00004000L, 0x00000100L, 0x02004108L, -0x02004008L, 0x02000100L, 0x00004108L, 0x02004000L, -0x00004000L, 0x00000008L, 0x02000008L, 0x00004100L, -0x02000108L, 0x02004008L, 0x02004100L, 0x00000000L, -0x00004100L, 0x02000000L, 0x00004008L, 0x00000108L, -0x02000100L, 0x00004108L, 0x00000000L, 0x02000008L, -0x00000008L, 0x02000108L, 0x02004108L, 0x00004008L, -0x02004000L, 0x00000100L, 0x00000108L, 0x02004100L, -0x02004100L, 0x02000108L, 0x00004008L, 0x02004000L, -0x00004000L, 0x00000008L, 0x02000008L, 0x02000100L, -0x02000000L, 0x00004100L, 0x02004108L, 0x00000000L, -0x00004108L, 0x02000000L, 0x00000100L, 0x00004008L, -0x02000108L, 0x00000100L, 0x00000000L, 0x02004108L, -0x02004008L, 0x02004100L, 0x00000108L, 0x00004000L, -0x00004100L, 0x02004008L, 0x02000100L, 0x00000108L, -0x00000008L, 0x00004108L, 0x02004000L, 0x02000008L, +0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L, +0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L, +0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L, +0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L, +0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L, +0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L, +0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L, +0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L, +0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L, +0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L, +0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L, +0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L, +0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L, +0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L, +0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L, +0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L, },{ /* nibble 5 */ -0x20000010L, 0x00080010L, 0x00000000L, 0x20080800L, -0x00080010L, 0x00000800L, 0x20000810L, 0x00080000L, -0x00000810L, 0x20080810L, 0x00080800L, 0x20000000L, -0x20000800L, 0x20000010L, 0x20080000L, 0x00080810L, -0x00080000L, 0x20000810L, 0x20080010L, 0x00000000L, -0x00000800L, 0x00000010L, 0x20080800L, 0x20080010L, -0x20080810L, 0x20080000L, 0x20000000L, 0x00000810L, -0x00000010L, 0x00080800L, 0x00080810L, 0x20000800L, -0x00000810L, 0x20000000L, 0x20000800L, 0x00080810L, -0x20080800L, 0x00080010L, 0x00000000L, 0x20000800L, -0x20000000L, 0x00000800L, 0x20080010L, 0x00080000L, -0x00080010L, 0x20080810L, 0x00080800L, 0x00000010L, -0x20080810L, 0x00080800L, 0x00080000L, 0x20000810L, -0x20000010L, 0x20080000L, 0x00080810L, 0x00000000L, -0x00000800L, 0x20000010L, 0x20000810L, 0x20080800L, -0x20080000L, 0x00000810L, 0x00000010L, 0x20080010L, +0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L, +0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L, +0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L, +0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L, +0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L, +0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L, +0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L, +0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L, +0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L, +0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L, +0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L, +0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L, +0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L, +0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L, +0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L, +0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L, },{ /* nibble 6 */ -0x00001000L, 0x00000080L, 0x00400080L, 0x00400001L, -0x00401081L, 0x00001001L, 0x00001080L, 0x00000000L, -0x00400000L, 0x00400081L, 0x00000081L, 0x00401000L, -0x00000001L, 0x00401080L, 0x00401000L, 0x00000081L, -0x00400081L, 0x00001000L, 0x00001001L, 0x00401081L, -0x00000000L, 0x00400080L, 0x00400001L, 0x00001080L, -0x00401001L, 0x00001081L, 0x00401080L, 0x00000001L, -0x00001081L, 0x00401001L, 0x00000080L, 0x00400000L, -0x00001081L, 0x00401000L, 0x00401001L, 0x00000081L, -0x00001000L, 0x00000080L, 0x00400000L, 0x00401001L, -0x00400081L, 0x00001081L, 0x00001080L, 0x00000000L, -0x00000080L, 0x00400001L, 0x00000001L, 0x00400080L, -0x00000000L, 0x00400081L, 0x00400080L, 0x00001080L, -0x00000081L, 0x00001000L, 0x00401081L, 0x00400000L, -0x00401080L, 0x00000001L, 0x00001001L, 0x00401081L, -0x00400001L, 0x00401080L, 0x00401000L, 0x00001001L, +0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L, +0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L, +0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L, +0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L, +0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L, +0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L, +0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L, +0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L, +0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L, +0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L, +0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L, +0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L, +0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L, +0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L, +0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L, +0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L, },{ /* nibble 7 */ -0x08200020L, 0x08208000L, 0x00008020L, 0x00000000L, -0x08008000L, 0x00200020L, 0x08200000L, 0x08208020L, -0x00000020L, 0x08000000L, 0x00208000L, 0x00008020L, -0x00208020L, 0x08008020L, 0x08000020L, 0x08200000L, -0x00008000L, 0x00208020L, 0x00200020L, 0x08008000L, -0x08208020L, 0x08000020L, 0x00000000L, 0x00208000L, -0x08000000L, 0x00200000L, 0x08008020L, 0x08200020L, -0x00200000L, 0x00008000L, 0x08208000L, 0x00000020L, -0x00200000L, 0x00008000L, 0x08000020L, 0x08208020L, -0x00008020L, 0x08000000L, 0x00000000L, 0x00208000L, -0x08200020L, 0x08008020L, 0x08008000L, 0x00200020L, -0x08208000L, 0x00000020L, 0x00200020L, 0x08008000L, -0x08208020L, 0x00200000L, 0x08200000L, 0x08000020L, -0x00208000L, 0x00008020L, 0x08008020L, 0x08200000L, -0x00000020L, 0x08208000L, 0x00208020L, 0x00000000L, -0x08000000L, 0x08200020L, 0x00008000L, 0x00208020L, +0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L, +0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L, +0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L, +0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L, +0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L, +0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L, +0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L, +0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L, +0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L, +0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L, +0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L, +0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L, +0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L, +0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L, +0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L, +0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L, }}; diff -urN xnu-344.49/bsd/crypto/sha2/sha2.c xnu-517/bsd/crypto/sha2/sha2.c --- xnu-344.49/bsd/crypto/sha2/sha2.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/crypto/sha2/sha2.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ -/* $FreeBSD: src/sys/crypto/sha2/sha2.c,v 1.2.2.1 2001/07/03 11:01:36 ume Exp $ */ -/* $KAME: sha2.c,v 1.6 2001/03/12 11:31:04 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/sha2/sha2.c,v 1.2.2.2 2002/03/05 08:36:47 ume Exp $ */ +/* $KAME: sha2.c,v 1.8 2001/11/08 01:07:52 itojun Exp $ */ /* * sha2.c @@ -565,7 +565,7 @@ /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; - if (usedspace < SHA256_SHORT_BLOCK_LENGTH) { + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ bzero(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); } else { @@ -882,7 +882,7 @@ /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; - if (usedspace < SHA512_SHORT_BLOCK_LENGTH) { + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); } else { diff -urN xnu-344.49/bsd/dev/disk.h xnu-517/bsd/dev/disk.h --- xnu-344.49/bsd/dev/disk.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/disk.h Sat Oct 25 00:25:25 2003 @@ -22,129 +22,5 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* @(#)disk.h 1.0 08/29/87 (c) 1987 NeXT */ -#ifndef _BSD_DEV_DISK_ -#define _BSD_DEV_DISK_ -#ifndef _SYS_DISK_H_ -#define _SYS_DISK_H_ - -#include -#include -#include -#include -#include -#include -#include - -/* - * USE INSTEAD (NOTE: DKIOCGETBLOCKCOUNT -> DKIOCGETBLOCKCOUNT32) - */ - -#ifdef __APPLE_API_OBSOLETE - -#define DR_CMDSIZE 32 -#define DR_ERRSIZE 32 - -struct disk_req { - int dr_bcount; /* byte count for data transfers */ - caddr_t dr_addr; /* memory addr for data transfers */ - struct timeval dr_exec_time; /* execution time of operation */ - - /* - * interpretation of cmdblk and errblk is driver specific. - */ - char dr_cmdblk[DR_CMDSIZE]; - char dr_errblk[DR_ERRSIZE]; -}; - -struct sdc_wire { - vm_offset_t start, end; - boolean_t new_pageable; -}; - - -#define BAD_BLK_OFF 4 /* offset of bad blk tbl from label */ -#define NBAD_BLK (12 * 1024 / sizeof (int)) - -struct bad_block { /* bad block table, sized to be 12KB */ - int bad_blk[NBAD_BLK]; -}; - -/* - * sector bitmap states (2 bits per sector) - */ -#define SB_UNTESTED 0 /* must be zero */ -#define SB_BAD 1 -#define SB_WRITTEN 2 -#define SB_ERASED 3 - -struct drive_info { /* info about drive hardware */ - char di_name[MAXDNMLEN]; /* drive type name */ - int di_label_blkno[NLABELS];/* label loc'ns in DEVICE SECTORS */ - int di_devblklen; /* device sector size */ - int di_maxbcount; /* max bytes per transfer request */ -}; - -#define DS_STATSIZE 32 - -struct disk_stats { - int s_ecccnt; /* avg ECC corrections per sector */ - int s_maxecc; /* max ECC corrections observed */ - - /* - * interpretation of s_stats is driver specific - */ - char s_stats[DS_STATSIZE]; -}; - -struct drive_location { - char location[ 128 ]; -}; - -#define DKIOCGLABEL _IOR('d', 0,struct disk_label) /* read label */ -#define DKIOCSLABEL _IOW('d', 1,struct disk_label) /* write label */ -#define DKIOCGBITMAP _IO('d', 2) /* read bitmap */ -#define DKIOCSBITMAP _IO('d', 3) /* write bitmap */ -#define DKIOCREQ _IOWR('d', 4, struct disk_req) /* cmd request */ -#define DKIOCINFO _IOR('d', 5, struct drive_info) /* get drive info */ -#define DKIOCZSTATS _IO('d',7) /* zero statistics */ -#define DKIOCGSTATS _IO('d', 8) /* get statistics */ -#define DKIOCRESET _IO('d', 9) /* reset disk */ -#define DKIOCGFLAGS _IOR('d', 11, int) /* get driver flags */ -#define DKIOCSFLAGS _IOW('d', 12, int) /* set driver flags */ -#define DKIOCSDCWIRE _IOW('d', 14, struct sdc_wire) /* sdc wire memory */ -#define DKIOCSDCLOCK _IO('d', 15) /* sdc lock */ -#define DKIOCSDCUNLOCK _IO('d', 16) /* sdc unlock */ -#define DKIOCGFREEVOL _IOR('d', 17, int) /* get free volume # */ -#define DKIOCGBBT _IO('d', 18) /* read bad blk tbl */ -#define DKIOCSBBT _IO('d', 19) /* write bad blk tbl */ -#define DKIOCMNOTIFY _IOW('d', 20, int) /* message on insert */ -#define DKIOCEJECT _IO('d', 21) /* eject disk */ -#define DKIOCPANELPRT _IOW('d', 22, int) /* register Panel */ - /* Request port */ -#define DKIOCSFORMAT _IOW('d', 23, int) /* set 'Formatted' flag */ -#define DKIOCGFORMAT _IOR('d', 23, int) /* get 'Formatted' flag */ -#define DKIOCBLKSIZE _IOR('d', 24, int) /* device sector size */ -#define DKIOCNUMBLKS _IOR('d', 25, int) /* number of sectors */ -#define DKIOCCHECKINSERT _IO('d',26) /* manually poll removable */ - /* media drive */ -#define DKIOCCANCELAUTOMOUNT _IOW('d',27, dev_t) /* cancel automount request */ -#define DKIOCGLOCATION _IOR('d',28, struct drive_location) /* arch dependent location descrip */ -#define DKIOCSETBLOCKSIZE _IOW('d', 24, int) /* set media's preferred sector size */ -#define DKIOCGETBLOCKSIZE DKIOCBLKSIZE /* get media's preferred sector size */ -#define DKIOCGETBLOCKCOUNT32 DKIOCNUMBLKS /* get media's sector count */ -#define DKIOCGETBLOCKCOUNT64 _IOR('d', 25, u_int64_t) /* get media's sector count */ -#define DKIOCGETLOCATION DKIOCGLOCATION /* get media's location description */ -#define DKIOCISFORMATTED DKIOCGFORMAT /* is media formatted? */ -#define DKIOCISWRITABLE _IOR('d', 29, int) /* is media writable? */ - -#define DKIOCGETMAXBLOCKCOUNTREAD _IOR('d', 64, u_int64_t) /* get device's maximum block count for read requests */ -#define DKIOCGETMAXBLOCKCOUNTWRITE _IOR('d', 65, u_int64_t) /* get device's maximum block count for write requests */ -#define DKIOCGETMAXSEGMENTCOUNTREAD _IOR('d', 66, u_int64_t) /* get device's maximum physical segment count for read buffers */ -#define DKIOCGETMAXSEGMENTCOUNTWRITE _IOR('d', 67, u_int64_t) /* get device's maximum physical segment count for write buffers */ - -#endif /* __APPLE_API_OBSOLETE */ - -#endif /* _SYS_DISK_H_ */ -#endif /* _BSD_DEV_DISK_ */ +#warning is obsolete, please use instead diff -urN xnu-344.49/bsd/dev/disk_label.h xnu-517/bsd/dev/disk_label.h --- xnu-344.49/bsd/dev/disk_label.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/disk_label.h Sat Oct 25 00:25:25 2003 @@ -22,91 +22,5 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* Copyright (c) 1991 by NeXT Computer, Inc. - * - * File: bsd/dev/disk_label.h - NeXT disk label definition. - * - */ - -#ifndef _BSD_DEV_DISK_LABEL_ -#define _BSD_DEV_DISK_LABEL_ - -#include -#include - -#ifdef __APPLE_API_OBSOLETE - -#define NLABELS 4 /* # of labels on a disk */ -#define MAXLBLLEN 24 /* dl_label[] size */ -#define NBAD 1670 /* sized to make label ~= 8KB */ - -/* - * if dl_version >= DL_V3 then the bad block table is relocated - * to a structure separate from the disk label. - */ -typedef union { - unsigned short DL_v3_checksum; - int DL_bad[NBAD]; /* block number that is bad */ -} dl_un_t; - -typedef struct disk_label { - int dl_version; // label version number - int dl_label_blkno; // block # where this label is - int dl_size; // size of media area (sectors) - char dl_label[MAXLBLLEN]; // media label - unsigned dl_flags; // flags (see DL_xxx, below) - unsigned dl_tag; // volume tag - struct disktab dl_dt; // common info in disktab - dl_un_t dl_un; - unsigned short dl_checksum; // ones complement checksum - - /* add things here so dl_checksum stays in a fixed place */ -} disk_label_t; - -/* - * Known label versions. - */ -#define DL_V1 0x4e655854 /* version #1: "NeXT" */ -#define DL_V2 0x646c5632 /* version #2: "dlV2" */ -#define DL_V3 0x646c5633 /* version #3: "dlV3" */ -#define DL_VERSION DL_V3 /* default version */ - - -/* - * dl_flags values - */ -#define DL_UNINIT 0x80000000 /* label is uninitialized */ - -/* - * Aliases for disktab fields - */ -#define dl_name dl_dt.d_name -#define dl_type dl_dt.d_type -#define dl_part dl_dt.d_partitions -#define dl_front dl_dt.d_front -#define dl_back dl_dt.d_back -#define dl_ngroups dl_dt.d_ngroups -#define dl_ag_size dl_dt.d_ag_size -#define dl_ag_alts dl_dt.d_ag_alts -#define dl_ag_off dl_dt.d_ag_off -#define dl_secsize dl_dt.d_secsize -#define dl_ncyl dl_dt.d_ncylinders -#define dl_nsect dl_dt.d_nsectors -#define dl_ntrack dl_dt.d_ntracks -#define dl_rpm dl_dt.d_rpm -#define dl_bootfile dl_dt.d_bootfile -#define dl_boot0_blkno dl_dt.d_boot0_blkno -#define dl_hostname dl_dt.d_hostname -#define dl_rootpartition dl_dt.d_rootpartition -#define dl_rwpartition dl_dt.d_rwpartition - -/* - * Other aliases - */ -#define dl_v3_checksum dl_un.DL_v3_checksum -#define dl_bad dl_un.DL_bad - -#endif /* __APPLE_API_OBSOLETE */ - -#endif /* _BSD_DEV_DISK_LABEL_ */ +#warning is obsolete diff -urN xnu-344.49/bsd/dev/i386/conf.c xnu-517/bsd/dev/i386/conf.c --- xnu-344.49/bsd/dev/i386/conf.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/i386/conf.c Sat Oct 25 00:25:25 2003 @@ -109,7 +109,7 @@ extern int cttyopen(), cttyread(), cttywrite(), cttyioctl(), cttyselect(); extern int mmread(),mmwrite(); -#define mmselect seltrue +#define mmselect (select_fcn_t *)seltrue #define mmmmap eno_mmap #include @@ -138,8 +138,6 @@ extern int fdesc_open(), fdesc_read(), fdesc_write(), fdesc_ioctl(), fdesc_select(); -extern int seltrue(); - struct cdevsw cdevsw[] = { /* @@ -241,7 +239,7 @@ NO_CDEVICE, /*41*/ { volopen, volclose, eno_rdwrt, eno_rdwrt, /*42*/ - volioctl, eno_stop, eno_reset, 0, seltrue, + volioctl, eno_stop, eno_reset, 0, (select_fcn_t *)seltrue, eno_mmap, eno_strat, eno_getc, eno_putc, 0 }, }; diff -urN xnu-344.49/bsd/dev/i386/km.c xnu-517/bsd/dev/i386/km.c --- xnu-344.49/bsd/dev/i386/km.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/i386/km.c Sat Oct 25 00:25:25 2003 @@ -62,7 +62,6 @@ int initialized = 0; static int kmoutput(struct tty *tp); -static void kmtimeout(struct tty *tp); static void kmstart(struct tty *tp); extern void KeyboardOpen(void); @@ -311,9 +310,10 @@ } static void -kmtimeout( struct tty *tp) +kmtimeout(void *arg) { boolean_t funnel_state; + struct tty *tp = (struct tty *) arg; funnel_state = thread_funnel_set(kernel_flock, TRUE); kmoutput(tp); diff -urN xnu-344.49/bsd/dev/i386/stubs.c xnu-517/bsd/dev/i386/stubs.c --- xnu-344.49/bsd/dev/i386/stubs.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/i386/stubs.c Sat Oct 25 00:25:25 2003 @@ -60,10 +60,12 @@ int slen,len,error=0; slen = strlen(from) + 1; + if (slen > maxlen) + error = ENAMETOOLONG; len = min(maxlen,slen); if (copyout(from, to, len)) - error = EIO; + error = EFAULT; *lencopied = len; return error; @@ -110,8 +112,6 @@ bcopy(src,dst,count); return 0; } - -cpu_number() {return(0);} set_bsduthreadargs(thread_t th, void * pcb, void *ignored_arg) { diff -urN xnu-344.49/bsd/dev/i386/sysctl.c xnu-517/bsd/dev/i386/sysctl.c --- xnu-344.49/bsd/dev/i386/sysctl.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/dev/i386/sysctl.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include + +static int +hw_cpu_sysctl SYSCTL_HANDLER_ARGS +{ + i386_cpu_info_t cpu_info; + void *ptr = (uint8_t *)&cpu_info + (uint32_t)arg1; + int value; + + cpuid_get_info(&cpu_info); + + if (arg2 == sizeof(uint8_t)) { + value = (uint32_t) *(uint8_t *)ptr; + ptr = &value; + arg2 = sizeof(uint32_t); + } + return SYSCTL_OUT(req, ptr, arg2 ? arg2 : strlen((char *)ptr)+1); + return 0; +} + +static int +hw_cpu_features SYSCTL_HANDLER_ARGS +{ + i386_cpu_info_t cpu_info; + char buf[256]; + vm_size_t size; + + cpuid_get_info(&cpu_info); + buf[0] = '\0'; + cpuid_get_feature_names(cpu_info.cpuid_features, buf, sizeof(buf)); + + return SYSCTL_OUT(req, buf, strlen(buf) + 1); +} + +SYSCTL_NODE(_machdep, OID_AUTO, cpu, CTLFLAG_RW, 0, + "CPU info"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, vendor, CTLTYPE_STRING | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_vendor), 0, + hw_cpu_sysctl, "A", "CPU vendor"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, brand_string, CTLTYPE_STRING | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_brand_string), 0, + hw_cpu_sysctl, "A", "CPU brand string"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, value, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_value), sizeof(uint32_t), + hw_cpu_sysctl, "I", "CPU value"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, family, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_family), sizeof(uint8_t), + hw_cpu_sysctl, "I", "CPU family"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, model, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_model), sizeof(uint8_t), + hw_cpu_sysctl, "I", "CPU model"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, extmodel, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_extmodel), sizeof(uint8_t), + hw_cpu_sysctl, "I", "CPU extended model"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, extfamily, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_extfamily), sizeof(uint8_t), + hw_cpu_sysctl, "I", "CPU extended family"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, stepping, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_stepping), sizeof(uint8_t), + hw_cpu_sysctl, "I", "CPU stepping"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, feature_bits, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_features), sizeof(uint32_t), + hw_cpu_sysctl, "I", "CPU features"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, signature, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_signature), sizeof(uint32_t), + hw_cpu_sysctl, "I", "CPU signature"); + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, brand, CTLTYPE_INT | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, cpuid_brand), sizeof(uint8_t), + hw_cpu_sysctl, "I", "CPU brand"); + +#if 0 +SYSCTL_PROC(_machdep_cpu, OID_AUTO, model_string, CTLTYPE_STRING | CTLFLAG_RD, + (void *)offsetof(i386_cpu_info_t, model_string), 0, + hw_cpu_sysctl, "A", "CPU model string"); +#endif + +SYSCTL_PROC(_machdep_cpu, OID_AUTO, features, CTLTYPE_STRING | CTLFLAG_RD, + 0, 0, + hw_cpu_features, "A", "CPU feature names"); + + +struct sysctl_oid *machdep_sysctl_list[] = +{ + &sysctl__machdep_cpu, + &sysctl__machdep_cpu_vendor, + &sysctl__machdep_cpu_brand_string, + &sysctl__machdep_cpu_value, + &sysctl__machdep_cpu_family, + &sysctl__machdep_cpu_model, + &sysctl__machdep_cpu_extmodel, + &sysctl__machdep_cpu_extfamily, + &sysctl__machdep_cpu_feature_bits, + &sysctl__machdep_cpu_stepping, + &sysctl__machdep_cpu_signature, + &sysctl__machdep_cpu_brand, + &sysctl__machdep_cpu_features, + (struct sysctl_oid *) 0 +}; + diff -urN xnu-344.49/bsd/dev/i386/unix_signal.c xnu-517/bsd/dev/i386/unix_signal.c --- xnu-344.49/bsd/dev/i386/unix_signal.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/i386/unix_signal.c Sat Oct 25 00:25:25 2003 @@ -52,9 +52,11 @@ #define USER_CS 0x17 #define USER_DS 0x1f +#define USER_CTHREAD 0x27 #define UDATA_SEL USER_DS #define UCODE_SEL USER_CS +#define UCTHREAD_SEL USER_CTHREAD #define valid_user_code_selector(x) (TRUE) #define valid_user_data_selector(x) (TRUE) @@ -63,6 +65,10 @@ #define NULL_SEG 0 +/* Signal handler flavors supported */ +/* These defns should match the Libc implmn */ +#define UC_TRAD 1 + /* * Send an interrupt to process. * @@ -95,7 +101,8 @@ thread_t thread = current_thread(); thread_act_t th_act = current_act(); struct uthread * ut; - struct i386_saved_state * saved_state = get_user_regs(th_act); + struct i386_saved_state * saved_state = (struct i386_saved_state *) + get_user_regs(th_act); sig_t trampact; ut = get_bsdthread_info(th_act); @@ -116,7 +123,7 @@ /* Handler should call sigreturn to get out of it */ frame.retaddr = 0xffffffff; frame.catcher = catcher; - frame.sigstyle = 1; + frame.sigstyle = UC_TRAD; frame.sig = sig; if (sig == SIGILL || sig == SIGFPE) { @@ -179,7 +186,7 @@ saved_state->ds = UDATA_SEL; saved_state->es = UDATA_SEL; saved_state->fs = NULL_SEG; - saved_state->gs = NULL_SEG; + saved_state->gs = USER_CTHREAD; return; bad: @@ -217,7 +224,8 @@ thread_t thread = current_thread(); thread_act_t th_act = current_act(); int error; - struct i386_saved_state* saved_state = get_user_regs(th_act); + struct i386_saved_state* saved_state = (struct i386_saved_state*) + get_user_regs(th_act); struct uthread * ut; diff -urN xnu-344.49/bsd/dev/ldd.h xnu-517/bsd/dev/ldd.h --- xnu-344.49/bsd/dev/ldd.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ldd.h Sat Oct 25 00:25:25 2003 @@ -44,7 +44,7 @@ #define _BSD_DEV_LDD_PRIV_ #include -#include +#include typedef int (*PFI)(); diff -urN xnu-344.49/bsd/dev/memdev.c xnu-517/bsd/dev/memdev.c --- xnu-344.49/bsd/dev/memdev.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/dev/memdev.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,578 @@ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah Hdr: vn.c 1.13 94/04/02 + * + * from: @(#)vn.c 8.6 (Berkeley) 4/1/94 + * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $ + */ + +/* + * RAM disk driver. + * + * Block interface to a ramdisk. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +static open_close_fcn_t mdevopen; +static open_close_fcn_t mdevclose; +static psize_fcn_t mdevsize; +static strategy_fcn_t mdevstrategy; +static int mdevbioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p); +static int mdevcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p); +static int mdevrw(dev_t dev, struct uio *uio, int ioflag); +static char *nonspace(char *pos, char *end); +static char *getspace(char *pos, char *end); +static char *cvtnum(char *pos, char *end, unsigned int *num); + +/* + * cdevsw + * D_DISK we want to look like a disk + * D_CANFREE We support B_FREEBUF + */ + +static struct bdevsw mdevbdevsw = { + /* open */ mdevopen, + /* close */ mdevclose, + /* strategy */ mdevstrategy, + /* ioctl */ mdevbioctl, + /* dump */ eno_dump, + /* psize */ mdevsize, + /* flags */ D_DISK, +}; + +static struct cdevsw mdevcdevsw = { + /* open */ mdevopen, + /* close */ mdevclose, + /* read */ mdevrw, + /* write */ mdevrw, + /* ioctl */ mdevcioctl, + /* stop */ eno_stop, + /* reset */ eno_reset, + /* ttys */ 0, + /* select */ eno_select, + /* mmap */ eno_mmap, + /* strategy */ eno_strat, + /* getc */ eno_getc, + /* putc */ eno_putc, + /* flags */ D_DISK, +}; + +struct mdev { + vm_offset_t mdBase; /* file size in bytes */ + uint32_t mdSize; /* file size in bytes */ + int mdFlags; /* flags */ + int mdSecsize; /* sector size */ + int mdBDev; /* Block device number */ + int mdCDev; /* Character device number */ + void * mdbdevb; + void * mdcdevb; +} mdev[16]; + +/* mdFlags */ +#define mdInited 0x01 /* This device defined */ +#define mdRO 0x02 /* This device is read-only */ +#define mdPhys 0x04 /* This device is in physical memory */ + +int mdevBMajor = -1; +int mdevCMajor = -1; + +static int mdevioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p, int is_char); +dev_t mdevadd(int devid, ppnum_t base, unsigned int size, int phys); +dev_t mdevlookup(int devid); + +static int mdevclose(dev_t dev, int flags, int devtype, struct proc *p) { + return (0); +} + +static int mdevopen(dev_t dev, int flags, int devtype, struct proc *p) { + + int devid; + + devid = minor(dev); /* Get minor device number */ + + if (devid > 16) return (ENXIO); /* Not valid */ + + if ((flags & FWRITE) && (mdev[devid].mdFlags & mdRO)) return (EACCES); /* Currently mounted RO */ + + return(0); +} + +static int mdevrw(dev_t dev, struct uio *uio, int ioflag) { + int status; + int unit; + addr64_t mdata; + int devid; + enum uio_seg saveflag; + + devid = minor(dev); /* Get minor device number */ + + if (devid > 16) return (ENXIO); /* Not valid */ + if (!(mdev[devid].mdFlags & mdInited)) return (ENXIO); /* Have we actually been defined yet? */ + + mdata = ((addr64_t)mdev[devid].mdBase << 12) + uio->uio_offset; /* Point to the area in "file" */ + + saveflag = uio->uio_segflg; /* Remember what the request is */ + if (mdev[devid].mdFlags & mdPhys) uio->uio_segflg = UIO_PHYS_USERSPACE; /* Make sure we are moving from physical ram if physical device */ + status = uiomove64(mdata, uio->uio_resid, uio); /* Move the data */ + uio->uio_segflg = saveflag; /* Restore the flag */ + + return (status); +} + +static void mdevstrategy(struct buf *bp) { + int unmap; + unsigned int sz, left, lop, csize; + kern_return_t ret; + vm_offset_t vaddr, blkoff; + struct buf *tbuf; + int devid; + addr64_t paddr, fvaddr; + ppnum_t pp; + + devid = minor(bp->b_dev); /* Get minor device number */ + + if ((mdev[devid].mdFlags & mdInited) == 0) { /* Have we actually been defined yet? */ + bp->b_error = ENXIO; + bp->b_flags |= B_ERROR; + biodone(bp); + return; + } + + bp->b_resid = bp->b_bcount; /* Set byte count */ + + blkoff = bp->b_blkno * mdev[devid].mdSecsize; /* Get offset into file */ + +/* + * Note that reading past end is an error, but reading at end is an EOF. For these + * we just return with b_resid == b_bcount. + */ + + if (blkoff >= (mdev[devid].mdSize << 12)) { /* Are they trying to read/write at/after end? */ + if(blkoff != (mdev[devid].mdSize << 12)) { /* Are we trying to read after EOF? */ + bp->b_error = EINVAL; /* Yeah, this is an error */ + bp->b_flags |= B_ERROR | B_INVAL; + } + biodone(bp); /* Return */ + return; + } + + if ((blkoff + bp->b_bcount) > (mdev[devid].mdSize << 12)) { /* Will this read go past end? */ + bp->b_bcount = ((mdev[devid].mdSize << 12) - blkoff); /* Yes, trim to max */ + } + + vaddr = 0; /* Assume not mapped yet */ + unmap = 0; + + if (bp->b_flags & B_VECTORLIST) { /* Do we have a list of UPLs? */ + tbuf = (struct buf *)bp->b_real_bp; /* Get this for C's inadequacies */ + if((bp->b_flags & B_NEED_IODONE) && /* If we have a UPL, is it already mapped? */ + tbuf && + tbuf->b_data) { + vaddr = (vm_offset_t)tbuf->b_data; /* We already have this mapped in, get base address */ + } + else { /* Not mapped yet */ + ret = ubc_upl_map(bp->b_pagelist, &vaddr); /* Map it in */ + if(ret != KERN_SUCCESS) panic("ramstrategy: ubc_upl_map failed, rc = %08X\n", ret); + unmap = 1; /* Remember to unmap later */ + } + vaddr = vaddr += bp->b_uploffset; /* Calculate actual vaddr */ + } + else vaddr = (vm_offset_t)bp->b_data; /* No UPL, we already have address */ + + fvaddr = (mdev[devid].mdBase << 12) + blkoff; /* Point to offset into ram disk */ + + if(bp->b_flags & B_READ) { /* Is this a read? */ + if(!(mdev[devid].mdFlags & mdPhys)) { /* Physical mapped disk? */ + bcopy((void *)((uintptr_t)fvaddr), + (void *)vaddr, (size_t)bp->b_bcount); /* This is virtual, just get the data */ + } + else { + left = bp->b_bcount; /* Init the amount left to copy */ + while(left) { /* Go until it is all copied */ + + lop = min((4096 - (vaddr & 4095)), (4096 - (fvaddr & 4095))); /* Get smallest amount left on sink and source */ + csize = min(lop, left); /* Don't move more than we need to */ + + pp = pmap_find_phys(kernel_pmap, (addr64_t)((unsigned int)vaddr)); /* Get the sink physical address */ + if(!pp) { /* Not found, what gives? */ + panic("mdevstrategy: sink address %016llX not mapped\n", (addr64_t)((unsigned int)vaddr)); + } + paddr = (addr64_t)(((addr64_t)pp << 12) | (addr64_t)(vaddr & 4095)); /* Get actual address */ + bcopy_phys(fvaddr, paddr, csize); /* Copy this on in */ + mapping_set_mod(paddr >> 12); /* Make sure we know that it is modified */ + + left = left - csize; /* Calculate what is left */ + vaddr = vaddr + csize; /* Move to next sink address */ + fvaddr = fvaddr + csize; /* Bump to next physical address */ + } + } + } + else { /* This is a write */ + if(!(mdev[devid].mdFlags & mdPhys)) { /* Physical mapped disk? */ + bcopy((void *)vaddr, (void *)((uintptr_t)fvaddr), + (size_t)bp->b_bcount); /* This is virtual, just put the data */ + } + else { + left = bp->b_bcount; /* Init the amount left to copy */ + while(left) { /* Go until it is all copied */ + + lop = min((4096 - (vaddr & 4095)), (4096 - (fvaddr & 4095))); /* Get smallest amount left on sink and source */ + csize = min(lop, left); /* Don't move more than we need to */ + + pp = pmap_find_phys(kernel_pmap, (addr64_t)((unsigned int)vaddr)); /* Get the source physical address */ + if(!pp) { /* Not found, what gives? */ + panic("mdevstrategy: source address %016llX not mapped\n", (addr64_t)((unsigned int)vaddr)); + } + paddr = (addr64_t)(((addr64_t)pp << 12) | (addr64_t)(vaddr & 4095)); /* Get actual address */ + + bcopy_phys(paddr, fvaddr, csize); /* Move this on out */ + + left = left - csize; /* Calculate what is left */ + vaddr = vaddr + csize; /* Move to next sink address */ + fvaddr = fvaddr + csize; /* Bump to next physical address */ + } + } + } + + if (unmap) { /* Do we need to unmap this? */ + ubc_upl_unmap(bp->b_pagelist); /* Yes, unmap it */ + } + + bp->b_resid = 0; /* Nothing more to do */ + biodone(bp); /* Say we've finished */ +} + +static int mdevbioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { + return (mdevioctl(dev, cmd, data, flag, p, 0)); +} + +static int mdevcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { + return (mdevioctl(dev, cmd, data, flag, p, 1)); +} + +static int mdevioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p, int is_char) { + + int error; + u_long *f; + u_int64_t *o; + int devid; + + devid = minor(dev); /* Get minor device number */ + + if (devid > 16) return (ENXIO); /* Not valid */ + + error = suser(p->p_ucred, &p->p_acflag); /* Are we superman? */ + if (error) return (error); /* Nope... */ + + f = (u_long*)data; + o = (u_int64_t *)data; + + switch (cmd) { + + case DKIOCGETMAXBLOCKCOUNTREAD: + *o = 32; + break; + + case DKIOCGETMAXBLOCKCOUNTWRITE: + *o = 32; + break; + + case DKIOCGETMAXSEGMENTCOUNTREAD: + *o = 32; + break; + + case DKIOCGETMAXSEGMENTCOUNTWRITE: + *o = 32; + break; + + case DKIOCGETBLOCKSIZE: + *f = mdev[devid].mdSecsize; + break; + + case DKIOCSETBLOCKSIZE: + if (is_char) return (ENODEV); /* We can only do this for a block */ + + if (*f < DEV_BSIZE) return (EINVAL); /* Too short? */ + + mdev[devid].mdSecsize = *f; /* set the new block size */ + break; + + case DKIOCISWRITABLE: + *f = 1; + break; + + case DKIOCGETBLOCKCOUNT32: + if(!(mdev[devid].mdFlags & mdInited)) return (ENXIO); + *f = ((mdev[devid].mdSize << 12) + mdev[devid].mdSecsize - 1) / mdev[devid].mdSecsize; + break; + + case DKIOCGETBLOCKCOUNT: + if(!(mdev[devid].mdFlags & mdInited)) return (ENXIO); + *o = ((mdev[devid].mdSize << 12) + mdev[devid].mdSecsize - 1) / mdev[devid].mdSecsize; + break; + + default: + error = ENOTTY; + break; + } + return(error); +} + + +static int mdevsize(dev_t dev) { + + int devid; + + devid = minor(dev); /* Get minor device number */ + if (devid > 16) return (ENXIO); /* Not valid */ + + if ((mdev[devid].mdFlags & mdInited) == 0) return(-1); /* Not inited yet */ + + return(mdev[devid].mdSecsize); +} + +#include + +void mdevinit(int cnt) { + + int devid, phys; + ppnum_t base; + unsigned int size; + char *ba, *lp; + dev_t dev; + + + ba = PE_boot_args(); /* Get the boot arguments */ + lp = ba + 256; /* Point to the end */ + + while(1) { /* Step through, looking for our keywords */ + phys = 0; /* Assume virtual memory device */ + ba = nonspace(ba, lp); /* Find non-space */ + if(ba >= lp) return; /* We are done if no more... */ + if(((ba[0] != 'v') && (ba[0] != 'p')) + || (ba[1] != 'm') || (ba[2] != 'd') || (ba[4] != '=') + || (ba[3] < '0') || (ba[3] > 'f') + || ((ba[3] > '9') && (ba[3] < 'a'))) { /* Is this of form "vmdx=" or "pmdx=" where x is hex digit? */ + + ba = getspace(ba, lp); /* Find next white space or end */ + continue; /* Start looking for the next one */ + } + + if(ba[0] == 'p') phys = 1; /* Set physical memory disk */ + + devid = ba[3] & 0xF; /* Assume digit */ + if(ba[3] > '9') devid += 9; /* Adjust for hex digits */ + + ba = &ba[5]; /* Step past keyword */ + ba = cvtnum(ba, lp, &base); /* Convert base of memory disk */ + if(ba >= lp) return; /* Malformed one at the end, leave */ + if(ba[0] != '.') continue; /* If not length separater, try next... */ + if(base & 0xFFF) continue; /* Only allow page aligned stuff */ + + ba++; /* Step past '.' */ + ba = cvtnum(ba, lp, &size); /* Try to convert it */ + if(!size || (size & 0xFFF)) continue; /* Allow only non-zer page size multiples */ + if(ba < lp) { /* If we are not at end, check end character */ + if((ba[0] != ' ') && (ba[0] != 0)) continue; /* End must be null or space */ + } + + dev = mdevadd(devid, base >> 12, size >> 12, phys); /* Go add the device */ + } + + return; + +} + +char *nonspace(char *pos, char *end) { /* Find next non-space in string */ + + if(pos >= end) return end; /* Don't go past end */ + if(pos[0] == 0) return end; /* If at null, make end */ + + while(1) { /* Keep going */ + if(pos[0] != ' ') return pos; /* Leave if we found one */ + pos++; /* Stop */ + if(pos >= end) return end; /* Quit if we run off end */ + } +} + +char *getspace(char *pos, char *end) { /* Find next non-space in string */ + + while(1) { /* Keep going */ + if(pos >= end) return end; /* Don't go past end */ + if(pos[0] == 0) return end; /* Leave if we hit null */ + if(pos[0] == ' ') return pos; /* Leave if we found one */ + pos++; /* Stop */ + } +} + +char *cvtnum(char *pos, char *end, unsigned int *num) { /* Convert to a number */ + + int rad, dig; + + *num = 0; /* Set answer to 0 to start */ + rad = 10; + + if(pos >= end) return end; /* Don't go past end */ + if(pos[0] == 0) return end; /* If at null, make end */ + + if(pos[0] == '0' && ((pos[1] == 'x') || (pos[1] == 'x'))) { /* A hex constant? */ + rad = 16; + pos += 2; /* Point to the number */ + } + + while(1) { /* Convert it */ + + if(pos >= end) return end; /* Don't go past end */ + if(pos[0] == 0) return end; /* If at null, make end */ + if(pos[0] < '0') return pos; /* Leave if non-digit */ + dig = pos[0] & 0xF; /* Extract digit */ + if(pos[0] > '9') { /* Is it bigger than 9? */ + if(rad == 10) return pos; /* Leave if not base 10 */ + if(!(((pos[0] >= 'A') && (pos[0] <= 'F')) + || ((pos[0] >= 'a') && (pos[0] <= 'f')))) return pos; /* Leave if bogus char */ + dig = dig + 9; /* Adjust for character */ + } + *num = (*num * rad) + dig; /* Accumulate the number */ + pos++; /* Step on */ + } +} + +dev_t mdevadd(int devid, ppnum_t base, unsigned int size, int phys) { + + int i; + + if(devid < 0) { + + devid = -1; + for(i = 0; i < 16; i++) { /* Search all known memory devices */ + if(!(mdev[i].mdFlags & mdInited)) { /* Is this a free one? */ + if(devid < 0)devid = i; /* Remember first free one */ + continue; /* Skip check */ + } + if(!(((base + size -1 ) < mdev[i].mdBase) || ((mdev[i].mdBase + mdev[i].mdSize - 1) < base))) { /* Is there any overlap? */ + panic("mdevadd: attempt to add overlapping memory device at %08X-%08X\n", mdev[i].mdBase, mdev[i].mdBase + mdev[i].mdSize - 1); + } + } + if(devid < 0) { /* Do we have free slots? */ + panic("mdevadd: attempt to add more than 16 memory devices\n"); + } + } + else { + if(devid >= 16) { /* Giving us something bogus? */ + panic("mdevadd: attempt to explicitly add a bogus memory device: &08X\n", devid); + } + if(mdev[devid].mdFlags &mdInited) { /* Already there? */ + panic("mdevadd: attempt to explicitly add a previously defined memory device: &08X\n", devid); + } + } + + if(mdevBMajor < 0) { /* Have we gotten a major number yet? */ + mdevBMajor = bdevsw_add(-1, &mdevbdevsw); /* Add to the table and figure out a major number */ + if (mdevBMajor < 0) { + printf("mdevadd: error - bdevsw_add() returned %d\n", mdevBMajor); + return -1; + } + } + + if(mdevCMajor < 0) { /* Have we gotten a major number yet? */ + mdevCMajor = cdevsw_add_with_bdev(-1, &mdevcdevsw, mdevBMajor); /* Add to the table and figure out a major number */ + if (mdevCMajor < 0) { + printf("ramdevice_init: error - cdevsw_add() returned %d\n", mdevCMajor); + return -1; + } + } + + mdev[devid].mdBDev = makedev(mdevBMajor, devid); /* Get the device number */ + mdev[devid].mdbdevb = devfs_make_node(mdev[devid].mdBDev, DEVFS_BLOCK, /* Make the node */ + UID_ROOT, GID_OPERATOR, + 0600, "md%d", devid); + if (mdev[devid].mdbdevb == NULL) { /* Did we make one? */ + printf("mdevadd: devfs_make_node for block failed!\n"); + return -1; /* Nope... */ + } + + mdev[devid].mdCDev = makedev(mdevCMajor, devid); /* Get the device number */ + mdev[devid].mdcdevb = devfs_make_node(mdev[devid].mdCDev, DEVFS_CHAR, /* Make the node */ + UID_ROOT, GID_OPERATOR, + 0600, "rmd%d", devid); + if (mdev[devid].mdcdevb == NULL) { /* Did we make one? */ + printf("mdevadd: devfs_make_node for character failed!\n"); + return -1; /* Nope... */ + } + + mdev[devid].mdBase = base; /* Set the base address of ram disk */ + mdev[devid].mdSize = size; /* Set the length of the ram disk */ + mdev[devid].mdSecsize = DEV_BSIZE; /* Set starting block size */ + if(phys) mdev[devid].mdFlags |= mdPhys; /* Show that we are in physical memory */ + mdev[devid].mdFlags |= mdInited; /* Show we are all set up */ + printf("Added memory device md%x/rmd%x (%08X/%08X) at %08X for %08X\n", + devid, devid, mdev[devid].mdBDev, mdev[devid].mdCDev, base << 12, size << 12); + return mdev[devid].mdBDev; +} + + +dev_t mdevlookup(int devid) { + + if((devid < 0) || (devid > 15)) return -1; /* Filter any bogus requests */ + if(!(mdev[devid].mdFlags & mdInited)) return -1; /* This one hasn't been defined */ + return mdev[devid].mdBDev; /* Return the device number */ +} diff -urN xnu-344.49/bsd/dev/memdev.h xnu-517/bsd/dev/memdev.h --- xnu-344.49/bsd/dev/memdev.h Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/dev/memdev.h Sat Oct 25 00:25:25 2003 @@ -0,0 +1,17 @@ + +#ifndef _SYS_MEMDEV_H_ +#define _SYS_MEMDEV_H_ + +#include + +#ifdef KERNEL_PRIVATE + +#ifdef __APPLE_API_PRIVATE + +void mdevinit(vm_offset_t base, unsigned int size); + +#endif /* __APPLE_API_PRIVATE */ + +#endif KERNEL_PRIVATE + +#endif /* _SYS_MEMDEV_H_*/ diff -urN xnu-344.49/bsd/dev/ppc/chud/chud_bsd_callback.c xnu-517/bsd/dev/ppc/chud/chud_bsd_callback.c --- xnu-344.49/bsd/dev/ppc/chud/chud_bsd_callback.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/dev/ppc/chud/chud_bsd_callback.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include + +#include +#include /* u_int */ +#include /* struct proc */ +#include /* struct sysent */ + +struct exit_args { + int rval; +}; +extern void exit(struct proc *p, struct exit_args *uap, int *retval); +extern struct sysent sysent[]; + +#pragma mark **** kern debug **** +typedef void (*chudxnu_kdebug_callback_func_t)(uint32_t debugid, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4); +static chudxnu_kdebug_callback_func_t kdebug_callback_fn = NULL; + +extern void kdbg_control_chudxnu(int val, void *fn); +extern unsigned int kdebug_enable; + +static void chudxnu_private_kdebug_callback(unsigned int debugid, unsigned int arg0, unsigned int arg1, unsigned int arg2, unsigned int arg3, unsigned int arg4) +{ + if(kdebug_callback_fn) { + (kdebug_callback_fn)(debugid, arg0, arg1, arg2, arg3, arg4); + } +} + +__private_extern__ +kern_return_t chudxnu_kdebug_callback_enter(chudxnu_kdebug_callback_func_t func) +{ + kdebug_callback_fn = func; + + kdbg_control_chud(TRUE, (void *)chudxnu_private_kdebug_callback); + kdebug_enable |= 0x10; + + return KERN_SUCCESS; +} + +__private_extern__ +kern_return_t chudxnu_kdebug_callback_cancel(void) +{ + kdebug_callback_fn = NULL; + kdbg_control_chud(FALSE, NULL); + kdebug_enable &= ~(0x10); + + return KERN_SUCCESS; +} + +#pragma mark **** task will exit **** + +typedef kern_return_t (*chudxnu_exit_callback_func_t)(int pid); + +__private_extern__ +kern_return_t chudxnu_exit_callback_enter(chudxnu_exit_callback_func_t func) +{ + + return KERN_FAILURE; + +} + +__private_extern__ +kern_return_t chudxnu_exit_callback_cancel(void) +{ + + return KERN_FAILURE; + +} diff -urN xnu-344.49/bsd/dev/ppc/chud/chud_process.c xnu-517/bsd/dev/ppc/chud/chud_process.c --- xnu-344.49/bsd/dev/ppc/chud/chud_process.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/dev/ppc/chud/chud_process.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include + +__private_extern__ +int chudxnu_pid_for_task(task_t task) +{ + struct proc *p; + + if(task!=TASK_NULL) { + p = (struct proc *)(get_bsdtask_info(task)); + if(p) { + return (p->p_pid); + } + } + return -1; +} + +__private_extern__ +task_t chudxnu_task_for_pid(int pid) +{ + struct proc *p = pfind(pid); + if(p) { + return p->task; + } + return TASK_NULL; +} + +__private_extern__ +int chudxnu_current_pid(void) +{ + return current_proc()->p_pid; +} diff -urN xnu-344.49/bsd/dev/ppc/conf.c xnu-517/bsd/dev/ppc/conf.c --- xnu-344.49/bsd/dev/ppc/conf.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ppc/conf.c Sat Oct 25 00:25:25 2003 @@ -103,6 +103,9 @@ #define mmselect seltrue #if 1 +#ifdef NPTY +#undef NPTY +#endif /* NPTY */ #define NPTY 32 #else /* 1 */ #include @@ -147,7 +150,7 @@ { consopen, consclose, consread, conswrite, /* 0*/ consioctl, nulldev, nulldev, 0, consselect, - eno_mmap, eno_strat, cons_getc, cons_putc, D_TTY + eno_mmap, eno_strat, (getc_fcn_t *)cons_getc, (putc_fcn_t *)cons_putc, D_TTY }, NO_CDEVICE, /* 1*/ { @@ -157,7 +160,7 @@ }, { nulldev, nulldev, mmread, mmwrite, /* 3*/ - eno_ioctl, nulldev, nulldev, 0, mmselect, + eno_ioctl, nulldev, nulldev, 0, (select_fcn_t *)mmselect, eno_mmap, eno_strat, eno_getc, eno_putc, 0 }, { diff -urN xnu-344.49/bsd/dev/ppc/kern_machdep.c xnu-517/bsd/dev/ppc/kern_machdep.c --- xnu-344.49/bsd/dev/ppc/kern_machdep.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ppc/kern_machdep.c Sat Oct 25 00:25:25 2003 @@ -55,18 +55,14 @@ if (cpu_subtype == ms->cpu_subtype) return (TRUE); - if (cpu_subtype == CPU_SUBTYPE_POWERPC_601) - return (FALSE); - switch (cpu_subtype) { + case CPU_SUBTYPE_POWERPC_970: + /* Do not allow a 970 binary to run on non-970 systems */ + if (ms->cpu_subtype != CPU_SUBTYPE_POWERPC_970) + break; case CPU_SUBTYPE_POWERPC_7450: case CPU_SUBTYPE_POWERPC_7400: case CPU_SUBTYPE_POWERPC_750: - case CPU_SUBTYPE_POWERPC_604e: - case CPU_SUBTYPE_POWERPC_604: - case CPU_SUBTYPE_POWERPC_603ev: - case CPU_SUBTYPE_POWERPC_603e: - case CPU_SUBTYPE_POWERPC_603: case CPU_SUBTYPE_POWERPC_ALL: return (TRUE); } @@ -93,43 +89,35 @@ * cctools project. As of 2/16/98 this is what has been agreed upon for * the PowerPC subtypes. If an exact match is not found the subtype will * be picked from the following order: - * 7400, 750, 604e, 604, 603ev, 603e, 603, ALL + * 970(but only on 970), 7450, 7400, 750, ALL * Note the 601 is NOT in the list above. It is only picked via an exact * match. For details see Radar 2213821. * * To implement this function to follow what was agreed upon above, we use - * the fact there are currently 10 different subtypes. Exact matches return - * the value 10, the value 0 is returned for 601 that is not an exact match, - * and the values 9 thru 1 are returned for the subtypes listed in the order - * above. + * the fact there are currently 4 different subtypes. Exact matches return + * the value 6, and the values 5 thru 1 are returned for the + * subtypes listed in the order above. */ if (ms->cpu_subtype == cpu_subtype) - return 10; - if (cpu_subtype == CPU_SUBTYPE_POWERPC_601) - return 0; + return 6; switch (cpu_subtype) { - case CPU_SUBTYPE_POWERPC_7450: - return 9; - case CPU_SUBTYPE_POWERPC_7400: - return 8; - case CPU_SUBTYPE_POWERPC_750: - return 7; - case CPU_SUBTYPE_POWERPC_604e: - return 6; - case CPU_SUBTYPE_POWERPC_604: + case CPU_SUBTYPE_POWERPC_970: + /* Do not allow a 970 binary to run on non-970 systems */ + if (ms->cpu_subtype != CPU_SUBTYPE_POWERPC_970) + break; return 5; - case CPU_SUBTYPE_POWERPC_603ev: + case CPU_SUBTYPE_POWERPC_7450: return 4; - case CPU_SUBTYPE_POWERPC_603e: + case CPU_SUBTYPE_POWERPC_7400: return 3; - case CPU_SUBTYPE_POWERPC_603: + case CPU_SUBTYPE_POWERPC_750: return 2; case CPU_SUBTYPE_POWERPC_ALL: return 1; } /* - * If we get here it is because it is a cpusubtype we don't support (602 and - * 620) or new cpusubtype that was added since this code was written. Both + * If we get here it is because it is a cpusubtype we don't support + * or a new cpusubtype that was added since this code was written. Both * will be considered unacceptable. */ return 0; @@ -144,7 +132,7 @@ off_t base; off_t end; - base = trunc_page(start); + base = trunc_page_64(start); end = start + len; while (base < end) { diff -urN xnu-344.49/bsd/dev/ppc/km.c xnu-517/bsd/dev/ppc/km.c --- xnu-344.49/bsd/dev/ppc/km.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ppc/km.c Sat Oct 25 00:25:25 2003 @@ -345,7 +345,7 @@ } } if (tp->t_outq.c_cc > 0) { - timeout(kmtimeout, tp, hz); + timeout((timeout_fcn_t)kmtimeout, tp, hz); } tp->t_state &= ~TS_BUSY; ttwwakeup(tp); diff -urN xnu-344.49/bsd/dev/ppc/mem.c xnu-517/bsd/dev/ppc/mem.c --- xnu-344.49/bsd/dev/ppc/mem.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ppc/mem.c Sat Oct 25 00:25:25 2003 @@ -89,7 +89,6 @@ static caddr_t devzerobuf; -extern vm_offset_t mem_actual; extern pmap_t kernel_pmap; mmread(dev, uio) @@ -115,6 +114,7 @@ { register int o; register u_int c, v; + addr64_t vll; register struct iovec *iov; int error = 0; vm_offset_t where; @@ -135,45 +135,48 @@ /* minor device 0 is physical memory */ case 0: - v = trunc_page(uio->uio_offset); - if (uio->uio_offset >= ((dgWork.dgFlags & enaDiagDM) ? mem_actual : mem_size)) + vll = trunc_page_64(uio->uio_offset); + if(((vll >> 31) == 1) || vll >= ((dgWork.dgFlags & enaDiagDM) ? mem_actual : max_mem)) goto fault; - size= PAGE_SIZE; - if(dgWork.dgFlags & enaDiagDM) { /* Can we really get all memory? */ - if (kmem_alloc_pageable(kernel_map, &where, size) != KERN_SUCCESS) { + if (kmem_alloc_pageable(kernel_map, &where, PAGE_SIZE) != KERN_SUCCESS) { goto fault; } else { - (void)mapping_make(kernel_pmap, 0, where, v, - VM_PROT_READ, 2, 0); /* Map it in for the moment */ + addr64_t collad; + + collad = mapping_make(kernel_pmap, (addr64_t)where, (ppnum_t)(vll >> 12), 0, 1, VM_PROT_READ); /* Map it in for the moment */ + if(collad) { /* See if it failed (shouldn't happen) */ + kmem_free(kernel_map, where, PAGE_SIZE); /* Toss the page */ + goto fault; /* Kill the transfer */ + } } } else { - if (kmem_alloc(kernel_map, &where, size) + if (kmem_alloc(kernel_map, &where, 4096) != KERN_SUCCESS) { goto fault; } } - o = uio->uio_offset - v; + o = uio->uio_offset - vll; c = min(PAGE_SIZE - o, (u_int)iov->iov_len); - error = uiomove((caddr_t) (where + o), c, uio); + error = uiomove((caddr_t)(where + o), c, uio); - if(dgWork.dgFlags & enaDiagDM) (void)mapping_remove(kernel_pmap, where); /* Unmap it */ + if(dgWork.dgFlags & enaDiagDM) (void)mapping_remove(kernel_pmap, (addr64_t)where); /* Unmap it */ kmem_free(kernel_map, where, PAGE_SIZE); continue; /* minor device 1 is kernel memory */ case 1: /* Do some sanity checking */ - if (((caddr_t)uio->uio_offset >= VM_MAX_KERNEL_ADDRESS) || - ((caddr_t)uio->uio_offset <= VM_MIN_KERNEL_ADDRESS)) + if (((addr64_t)uio->uio_offset > vm_last_addr) || + ((addr64_t)uio->uio_offset < VM_MIN_KERNEL_ADDRESS)) goto fault; c = iov->iov_len; - if (!kernacc((caddr_t)uio->uio_offset, c)) + if (!kernacc(uio->uio_offset, c)) goto fault; - error = uiomove((caddr_t)uio->uio_offset, (int)c, uio); + error = uiomove64(uio->uio_offset, (int)c, uio); continue; /* minor device 2 is EOF/RATHOLE */ diff -urN xnu-344.49/bsd/dev/ppc/stubs.c xnu-517/bsd/dev/ppc/stubs.c --- xnu-344.49/bsd/dev/ppc/stubs.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ppc/stubs.c Sat Oct 25 00:25:25 2003 @@ -43,38 +43,6 @@ /* - * copy a null terminated string from the kernel address space into - * the user address space. - * - if the user is denied write access, return EFAULT. - * - if the end of string isn't found before - * maxlen bytes are copied, return ENAMETOOLONG, - * indicating an incomplete copy. - * - otherwise, return 0, indicating success. - * the number of bytes copied is always returned in lencopied. - */ -int -copyoutstr(from, to, maxlen, lencopied) - void * from, * to; - size_t maxlen, *lencopied; -{ - int slen,len,error=0; - - /* XXX Must optimize this */ - - slen = strlen(from) + 1; - if (slen > maxlen) - error = ENAMETOOLONG; - - len = min(maxlen,slen); - if (copyout(from, to, len)) - error = EFAULT; - *lencopied = len; - - return error; -} - - -/* * copy a null terminated string from one point to another in * the kernel address space. * - no access checks are performed. diff -urN xnu-344.49/bsd/dev/ppc/sysctl.c xnu-517/bsd/dev/ppc/sysctl.c --- xnu-344.49/bsd/dev/ppc/sysctl.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/dev/ppc/sysctl.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include + +struct sysctl_oid *machdep_sysctl_list[] = +{ + (struct sysctl_oid *) 0 +}; + diff -urN xnu-344.49/bsd/dev/ppc/systemcalls.c xnu-517/bsd/dev/ppc/systemcalls.c --- xnu-344.49/bsd/dev/ppc/systemcalls.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ppc/systemcalls.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include extern void unix_syscall( @@ -49,8 +51,8 @@ find_user_regs( thread_act_t act); -extern enter_funnel_section(funnel_t *funnel_lock); -extern exit_funnel_section(funnel_t *funnel_lock); +extern void enter_funnel_section(funnel_t *funnel_lock); +extern void exit_funnel_section(void); /* * Function: unix_syscall @@ -73,6 +75,21 @@ boolean_t flavor; int funnel_type; + flavor = (((unsigned int)regs->save_r0) == NULL)? 1: 0; + + if (flavor) + code = regs->save_r3; + else + code = regs->save_r0; + + if (kdebug_enable && (code != 180)) { + if (flavor) + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, + regs->save_r4, regs->save_r5, regs->save_r6, regs->save_r7, 0); + else + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, + regs->save_r3, regs->save_r4, regs->save_r5, regs->save_r6, 0); + } thread_act = current_act(); uthread = get_bsdthread_info(thread_act); @@ -81,15 +98,8 @@ else proc = current_proc(); - flavor = (regs->save_r0 == NULL)? 1: 0; - uthread->uu_ar0 = (int *)regs; - if (flavor) - code = regs->save_r3; - else - code = regs->save_r0; - callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; #ifdef DEBUG @@ -118,24 +128,12 @@ } } - callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; - - if (kdebug_enable && (code != 180)) { - if (flavor) - KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, - regs->save_r4, regs->save_r5, regs->save_r6, regs->save_r7, 0); - else - KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, - regs->save_r3, regs->save_r4, regs->save_r5, regs->save_r6, 0); - } - funnel_type = (int)callp->sy_funnel; - if(funnel_type == KERNEL_FUNNEL) + if (funnel_type == KERNEL_FUNNEL) enter_funnel_section(kernel_flock); else if (funnel_type == NETWORK_FUNNEL) enter_funnel_section(network_flock); - uthread->uu_rval[0] = 0; /* @@ -156,7 +154,9 @@ if (KTRPOINT(proc, KTR_SYSCALL)) ktrsyscall(proc, code, callp->sy_narg, uthread->uu_arg, funnel_type); + AUDIT_CMD(audit_syscall_enter(code, proc, uthread)); error = (*(callp->sy_call))(proc, (void *)uthread->uu_arg, &(uthread->uu_rval[0])); + AUDIT_CMD(audit_syscall_exit(error, proc, uthread)); regs = find_user_regs(thread_act); @@ -164,7 +164,7 @@ regs->save_srr0 -= 8; } else if (error != EJUSTRETURN) { if (error) { - regs->save_r3 = error; + regs->save_r3 = (long long)error; /* set the "pc" to execute cerror routine */ regs->save_srr0 -= 4; } else { /* (not error) */ @@ -177,10 +177,7 @@ if (KTRPOINT(proc, KTR_SYSRET)) ktrsysret(proc, code, error, uthread->uu_rval[0], funnel_type); - if(funnel_type == KERNEL_FUNNEL) - exit_funnel_section(kernel_flock); - else if (funnel_type == NETWORK_FUNNEL) - exit_funnel_section(network_flock); + exit_funnel_section(); if (kdebug_enable && (code != 180)) { KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, @@ -214,7 +211,7 @@ regs->save_srr0 -= 8; } else if (error != EJUSTRETURN) { if (error) { - regs->save_r3 = error; + regs->save_r3 = (long long)error; /* set the "pc" to execute cerror routine */ regs->save_srr0 -= 4; } else { /* (not error) */ @@ -236,10 +233,7 @@ if (KTRPOINT(proc, KTR_SYSRET)) ktrsysret(proc, code, error, uthread->uu_rval[0], funnel_type); - if(funnel_type == KERNEL_FUNNEL) - exit_funnel_section(kernel_flock); - else if (funnel_type == NETWORK_FUNNEL) - exit_funnel_section(network_flock); + exit_funnel_section(); if (kdebug_enable && (code != 180)) { KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, @@ -263,33 +257,31 @@ struct timeval *tp; struct timezone *tzp; }; -/* NOTE THIS implementation is for ppc architectures only */ +/* NOTE THIS implementation is for ppc architectures only. + * It is infrequently called, since the commpage intercepts + * most calls in user mode. + */ int ppc_gettimeofday(p, uap, retval) struct proc *p; register struct gettimeofday_args *uap; register_t *retval; { - struct timeval atv; int error = 0; - struct timezone ltz; - //struct savearea *child_state; - extern simple_lock_data_t tz_slock; - - if (uap->tp) { - microtime(&atv); - retval[0] = atv.tv_sec; - retval[1] = atv.tv_usec; - } + + if (uap->tp) + clock_gettimeofday(&retval[0], &retval[1]); if (uap->tzp) { + struct timezone ltz; + extern simple_lock_data_t tz_slock; + usimple_lock(&tz_slock); ltz = tz; usimple_unlock(&tz_slock); - error = copyout((caddr_t)<z, (caddr_t)uap->tzp, - sizeof (tz)); + error = copyout((caddr_t)<z, (caddr_t)uap->tzp, sizeof (tz)); } - return(error); + return (error); } diff -urN xnu-344.49/bsd/dev/ppc/unix_signal.c xnu-517/bsd/dev/ppc/unix_signal.c --- xnu-344.49/bsd/dev/ppc/unix_signal.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ppc/unix_signal.c Sat Oct 25 00:25:25 2003 @@ -41,7 +41,6 @@ #include #include #include -#define __ELF__ 0 #include #define C_REDZONE_LEN 224 @@ -51,6 +50,42 @@ #define TRUNC_DOWN(a,b,c) (((((unsigned)a)-(b))/(c)) * (c)) /* + * The stack layout possibilities (info style); This needs to mach with signal trampoline code + * + * Traditional: 1 + * Traditional64: 20 + * Traditional64with vec: 25 + * 32bit context 30 + * 32bit context with vector 35 + * 64bit context 40 + * 64bit context with vector 45 + * Dual context 50 + * Dual context with vector 55 + * + */ + +#define UC_TRAD 1 +#define UC_TRAD_VEC 6 +#define UC_TRAD64 20 +#define UC_TRAD64_VEC 25 +#define UC_FLAVOR 30 +#define UC_FLAVOR_VEC 35 +#define UC_FLAVOR64 40 +#define UC_FLAVOR64_VEC 45 +#define UC_DUAL 50 +#define UC_DUAL_VEC 55 + + /* The following are valid mcontext sizes */ +#define UC_FLAVOR_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)) + +#define UC_FLAVOR_VEC_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int)) + +#define UC_FLAVOR64_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)) + +#define UC_FLAVOR64_VEC_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int)) + + +/* * Arrange for this process to run a signal handler */ @@ -61,7 +96,9 @@ int sig, mask; u_long code; { + kern_return_t kretn; struct mcontext mctx, *p_mctx; + struct mcontext64 mctx64, *p_mctx64; struct ucontext uctx, *p_uctx; siginfo_t sinfo, *p_sinfo; struct sigacts *ps = p->p_sigacts; @@ -72,42 +109,114 @@ thread_act_t th_act; struct uthread *ut; unsigned long paramp,linkp; - int infostyle = 1; + int infostyle = UC_TRAD; + int dualcontext =0; sig_t trampact; int vec_used = 0; int stack_size = 0; int stack_flags = 0; + void * tstate; + int flavor; + int ctx32 = 1; + int is_64signalregset(void); th_act = current_act(); ut = get_bsdthread_info(th_act); - state_count = PPC_EXCEPTION_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_EXCEPTION_STATE, &mctx.es, &state_count) != KERN_SUCCESS) { - goto bad; - } + + if (p->p_sigacts->ps_siginfo & sigmask(sig)) { + infostyle = UC_FLAVOR; + } + if(is_64signalregset() && (infostyle == UC_FLAVOR)) { + dualcontext = 1; + infostyle = UC_DUAL; + } + if (p->p_sigacts->ps_64regset & sigmask(sig)) { + dualcontext = 0; + ctx32 = 0; + infostyle = UC_FLAVOR64; + } + if (is_64signalregset() && (infostyle == UC_TRAD)) { + ctx32=0; + infostyle = UC_TRAD64; + } + + /* I need this for SIGINFO anyway */ + flavor = PPC_THREAD_STATE; + tstate = (void *)&mctx.ss; state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) goto bad; - } - state_count = PPC_FLOAT_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) { - goto bad; - } - vec_save(th_act); - if (find_user_vec(th_act)) { - vec_used = 1; - state_count = PPC_VECTOR_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) { - goto bad; - } - + if ((ctx32 == 0) || dualcontext) { + flavor = PPC_THREAD_STATE64; + tstate = (void *)&mctx64.ss; + state_count = PPC_THREAD_STATE64_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; } + if ((ctx32 == 1) || dualcontext) { + flavor = PPC_EXCEPTION_STATE; + tstate = (void *)&mctx.es; + state_count = PPC_EXCEPTION_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + } + + if ((ctx32 == 0) || dualcontext) { + flavor = PPC_EXCEPTION_STATE64; + tstate = (void *)&mctx64.es; + state_count = PPC_EXCEPTION_STATE64_COUNT; + + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + + } + + + if ((ctx32 == 1) || dualcontext) { + flavor = PPC_FLOAT_STATE; + tstate = (void *)&mctx.fs; + state_count = PPC_FLOAT_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + } + + if ((ctx32 == 0) || dualcontext) { + flavor = PPC_FLOAT_STATE; + tstate = (void *)&mctx64.fs; + state_count = PPC_FLOAT_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + + } + + + if (find_user_vec_curr()) { + vec_used = 1; + + if ((ctx32 == 1) || dualcontext) { + flavor = PPC_VECTOR_STATE; + tstate = (void *)&mctx.vs; + state_count = PPC_VECTOR_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + infostyle += 5; + } + + if ((ctx32 == 0) || dualcontext) { + flavor = PPC_VECTOR_STATE; + tstate = (void *)&mctx64.vs; + state_count = PPC_VECTOR_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + infostyle += 5; + } + } + trampact = ps->ps_trampact[sig]; oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK; - if (p->p_sigacts->ps_siginfo & sigmask(sig)) - infostyle = 2; /* figure out where our new stack lives */ if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && @@ -117,13 +226,30 @@ stack_size = ps->ps_sigstk.ss_size; ps->ps_sigstk.ss_flags |= SA_ONSTACK; } - else - sp = mctx.ss.r1; + else { + if (ctx32 == 0) + sp = (unsigned int)mctx64.ss.r1; + else + sp = mctx.ss.r1; + } + + /* put siginfo on top */ + /* preserve RED ZONE area */ sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN); - /* context goes first on stack */ + /* next are the saved registers */ + if ((ctx32 == 0) || dualcontext) { + sp -= sizeof(*p_mctx64); + p_mctx64 = (struct mcontext64 *)sp; + } + if ((ctx32 == 1) || dualcontext) { + sp -= sizeof(*p_mctx); + p_mctx = (struct mcontext *)sp; + } + + /* context goes first on stack */ sp -= sizeof(*p_uctx); p_uctx = (struct ucontext *) sp; @@ -131,13 +257,9 @@ sp -= sizeof(*p_sinfo); p_sinfo = (siginfo_t *) sp; - /* next are the saved registers */ - sp -= sizeof(*p_mctx); - p_mctx = (struct mcontext *)sp; - /* C calling conventions, create param save and linkage - * areas - */ + * areas + */ sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN); paramp = sp; @@ -152,14 +274,25 @@ uctx.uc_stack.ss_flags |= SS_ONSTACK; uctx.uc_link = 0; - uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + if (ctx32 == 0) + uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE64_COUNT + PPC_THREAD_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + else + uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + if (vec_used) uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int)); - uctx.uc_mcontext = p_mctx; + + if (ctx32 == 0) + uctx.uc_mcontext = (void *)p_mctx64; + else + uctx.uc_mcontext = (void *)p_mctx; /* setup siginfo */ bzero((caddr_t)&sinfo, sizeof(siginfo_t)); sinfo.si_signo = sig; + sinfo.si_addr = (void *)mctx.ss.srr0; + sinfo.pad[0] = (unsigned int)mctx.ss.r1; + switch (sig) { case SIGCHLD: sinfo.si_pid = p->si_pid; @@ -233,13 +366,23 @@ break; } + /* copy info out to user space */ if (copyout((caddr_t)&uctx, (caddr_t)p_uctx, sizeof(struct ucontext))) goto bad; if (copyout((caddr_t)&sinfo, (caddr_t)p_sinfo, sizeof(siginfo_t))) goto bad; - if (copyout((caddr_t)&mctx, (caddr_t)p_mctx, uctx.uc_mcsize)) + if ((ctx32 == 0) || dualcontext) { + tstate = &mctx64; + if (copyout((caddr_t)tstate, (caddr_t)p_mctx64, uctx.uc_mcsize)) goto bad; + } + if ((ctx32 == 1) || dualcontext) { + tstate = &mctx; + if (copyout((caddr_t)tstate, (caddr_t)p_mctx, uctx.uc_mcsize)) + goto bad; + } + /* Place our arguments in arg registers: rtm dependent */ @@ -253,10 +396,9 @@ mctx.ss.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */ mctx.ss.r1 = sp; state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { - goto bad; + if ((kretn = thread_setstatus(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count)) != KERN_SUCCESS) { + panic("sendsig: thread_setstatus failed, ret = %08X\n", kretn); } - return; bad: @@ -280,8 +422,122 @@ * psl to gain improper priviledges or to cause * a machine fault. */ + +#define FOR64_TRANSITION 1 + + +#ifdef FOR64_TRANSITION + +struct osigreturn_args { + struct ucontext *uctx; +}; + +/* ARGSUSED */ +int +osigreturn(p, uap, retval) + struct proc *p; + struct osigreturn_args *uap; + int *retval; +{ + struct ucontext uctx; + struct ucontext *p_uctx; + struct mcontext64 mctx64; + struct mcontext64 *p_64mctx; + struct mcontext *p_mctx; + int error; + thread_act_t th_act; + struct sigacts *ps = p->p_sigacts; + sigset_t mask; + register sig_t action; + unsigned long state_count; + unsigned int state_flavor; + struct uthread * ut; + int vec_used = 0; + void *tsptr, *fptr, *vptr, *mactx; + void ppc_checkthreadstate(void *, int); + + th_act = current_act(); + /* lets use the larger one */ + mactx = (void *)&mctx64; + + ut = (struct uthread *)get_bsdthread_info(th_act); + if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) { + return(error); + } + if (error = copyin(uctx.uc_mcontext, mactx, uctx.uc_mcsize)) { + return(error); + } + + if (uctx.uc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; + + ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask; + if (ut->uu_siglist & ~ut->uu_sigmask) + signal_setast(current_act()); + + vec_used = 0; + switch (uctx.uc_mcsize) { + case UC_FLAVOR64_VEC_SIZE : + vec_used = 1; + case UC_FLAVOR64_SIZE : { + p_64mctx = (struct mcontext64 *)mactx; + tsptr = (void *)&p_64mctx->ss; + fptr = (void *)&p_64mctx->fs; + vptr = (void *)&p_64mctx->vs; + state_flavor = PPC_THREAD_STATE64; + state_count = PPC_THREAD_STATE64_COUNT; + } + break; + case UC_FLAVOR_VEC_SIZE : + vec_used = 1; + case UC_FLAVOR_SIZE: + default: { + p_mctx = (struct mcontext *)mactx; + tsptr = (void *)&p_mctx->ss; + fptr = (void *)&p_mctx->fs; + vptr = (void *)&p_mctx->vs; + state_flavor = PPC_THREAD_STATE; + state_count = PPC_THREAD_STATE_COUNT; + } + break; + } /* switch () */ + + /* validate the thread state, set/reset appropriate mode bits in srr1 */ + (void)ppc_checkthreadstate(tsptr, state_flavor); + + if (thread_setstatus(th_act, state_flavor, tsptr, &state_count) != KERN_SUCCESS) { + return(EINVAL); + } + + state_count = PPC_FLOAT_STATE_COUNT; + if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, &state_count) != KERN_SUCCESS) { + return(EINVAL); + } + + mask = sigmask(SIGFPE); + if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) { + action = ps->ps_sigact[SIGFPE]; + if((action != SIG_DFL) && (action != SIG_IGN)) { + thread_enable_fpe(th_act, 1); + } + } + + if (vec_used) { + state_count = PPC_VECTOR_STATE_COUNT; + if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, &state_count) != KERN_SUCCESS) { + return(EINVAL); + } + } + return (EJUSTRETURN); +} + +#endif /* FOR64_TRANSITION */ + struct sigreturn_args { struct ucontext *uctx; + int infostyle; }; /* ARGSUSED */ @@ -291,19 +547,23 @@ struct sigreturn_args *uap; int *retval; { - struct ucontext uctx, *p_uctx; - struct mcontext mctx, *p_mctx; + struct ucontext uctx; + struct ucontext *p_uctx; + char mactx[sizeof(struct mcontext64)]; + struct mcontext *p_mctx; + struct mcontext64 *p_64mctx; int error; thread_act_t th_act; - struct ppc_float_state fs; - struct ppc_exception_state es; struct sigacts *ps = p->p_sigacts; sigset_t mask; register sig_t action; unsigned long state_count; - unsigned int nbits, rbits; + unsigned int state_flavor; struct uthread * ut; int vec_used = 0; + void *tsptr, *fptr, *vptr; + int infostyle = uap->infostyle; + void ppc_checkthreadstate(void *, int); th_act = current_act(); @@ -311,7 +571,9 @@ if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) { return(error); } - if (error = copyin(uctx.uc_mcontext, &mctx, sizeof(struct mcontext))) { + + + if (error = copyin(uctx.uc_mcontext, mactx, uctx.uc_mcsize)) { return(error); } @@ -319,32 +581,51 @@ p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; - ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask; - + ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask; if (ut->uu_siglist & ~ut->uu_sigmask) signal_setast(current_act()); - nbits = get_msr_nbits(); - rbits = get_msr_rbits(); - /* adjust the critical fields */ - /* make sure naughty bits are off */ - mctx.ss.srr1 &= ~(nbits); - /* make sure necessary bits are on */ - mctx.ss.srr1 |= (rbits); + vec_used = 0; + switch (infostyle) { + case UC_FLAVOR64_VEC: + case UC_TRAD64_VEC: + vec_used = 1; + case UC_TRAD64: + case UC_FLAVOR64: { + p_64mctx = (struct mcontext64 *)mactx; + tsptr = (void *)&p_64mctx->ss; + fptr = (void *)&p_64mctx->fs; + vptr = (void *)&p_64mctx->vs; + state_flavor = PPC_THREAD_STATE64; + state_count = PPC_THREAD_STATE64_COUNT; + } + break; + case UC_FLAVOR_VEC : + case UC_TRAD_VEC : + vec_used = 1; + case UC_FLAVOR : + case UC_TRAD : + default: { + p_mctx = (struct mcontext *)mactx; + tsptr = (void *)&p_mctx->ss; + fptr = (void *)&p_mctx->fs; + vptr = (void *)&p_mctx->vs; + state_flavor = PPC_THREAD_STATE; + state_count = PPC_THREAD_STATE_COUNT; + } + break; + } /* switch () */ - state_count = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + /* validate the thread state, set/reset appropriate mode bits in srr1 */ + (void)ppc_checkthreadstate(tsptr, state_flavor); - if (uctx.uc_mcsize > state_count) - vec_used = 1; - - state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { + if (thread_setstatus(th_act, state_flavor, tsptr, &state_count) != KERN_SUCCESS) { return(EINVAL); } state_count = PPC_FLOAT_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) { + if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, &state_count) != KERN_SUCCESS) { return(EINVAL); } @@ -358,11 +639,10 @@ if (vec_used) { state_count = PPC_VECTOR_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) { + if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, &state_count) != KERN_SUCCESS) { return(EINVAL); } } - return (EJUSTRETURN); } diff -urN xnu-344.49/bsd/dev/ppc/unix_startup.c xnu-517/bsd/dev/ppc/unix_startup.c --- xnu-344.49/bsd/dev/ppc/unix_startup.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/ppc/unix_startup.c Sat Oct 25 00:25:25 2003 @@ -68,7 +68,7 @@ kern_return_t ret; if (nbuf == 0) - nbuf = atop(mem_size / 100); /* 1% */ + nbuf = atop_64(sane_size / 100); /* Get 1% of ram, but no more than we can map */ if (nbuf > 8192) nbuf = 8192; if (nbuf < 256) @@ -82,7 +82,7 @@ niobuf = 128; size = (nbuf + niobuf) * sizeof (struct buf); - size = round_page(size); + size = round_page_32(size); ret = kmem_suballoc(kernel_map, &firstaddr, @@ -106,13 +106,13 @@ buf = (struct buf * )firstaddr; bzero(buf,size); - if ((mem_size > (64 * 1024 * 1024)) || ncl) { + if ((sane_size > (64 * 1024 * 1024)) || ncl) { int scale; extern u_long tcp_sendspace; extern u_long tcp_recvspace; if ((nmbclusters = ncl) == 0) { - if ((nmbclusters = ((mem_size / 16) / MCLBYTES)) > 16384) + if ((nmbclusters = ((sane_size / 16) / MCLBYTES)) > 16384) nmbclusters = 16384; } if ((scale = nmbclusters / NMBCLUSTERS) > 1) { @@ -137,7 +137,7 @@ bsd_startupearly(); ret = kmem_suballoc(kernel_map, - &mbutl, + (vm_offset_t *) &mbutl, (vm_size_t) (nmbclusters * MCLBYTES), FALSE, TRUE, diff -urN xnu-344.49/bsd/dev/random/YarrowCoreLib/src/prng.c xnu-517/bsd/dev/random/YarrowCoreLib/src/prng.c --- xnu-344.49/bsd/dev/random/YarrowCoreLib/src/prng.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/random/YarrowCoreLib/src/prng.c Sat Oct 25 00:25:25 2003 @@ -343,8 +343,8 @@ #if defined(macintosh) || defined(__APPLE__) #if (defined(TARGET_API_MAC_OSX) || defined(KERNEL_BUILD)) struct timeval tv; - int32_t endTime; - #else TARGET_API_MAC_CARBON + int64_t endTime, curTime; + #else /* TARGET_API_MAC_CARBON */ UnsignedWide uwide; /* struct needed for Microseconds() */ LONGLONG start; LONGLONG now; @@ -360,15 +360,11 @@ #if (defined(TARGET_API_MAC_OSX) || defined(KERNEL_BUILD)) /* note we can't loop for more than a million microseconds */ #ifdef KERNEL_BUILD - microtime (&tv); + microuptime (&tv); #else gettimeofday(&tv, NULL); #endif - endTime = tv.tv_usec + ticks; - if(endTime > 1000000) { - /* handle rollover now */ - endTime -= 1000000; - } + endTime = (int64_t)tv.tv_sec*1000000LL + (int64_t)tv.tv_usec + ticks; #else /* TARGET_API_MAC_OSX */ Microseconds(&uwide); start = UnsignedWideToUInt64(uwide); @@ -393,9 +389,10 @@ #ifdef TARGET_API_MAC_OSX gettimeofday(&tv, NULL); #else - microtime (&tv); + microuptime (&tv); + curTime = (int64_t)tv.tv_sec*1000000LL + (int64_t)tv.tv_usec; #endif - } while(tv.tv_usec < endTime); + } while(curTime < endTime); #else Microseconds(&uwide); now = UnsignedWideToUInt64(uwide); diff -urN xnu-344.49/bsd/dev/random/randomdev.c xnu-517/bsd/dev/random/randomdev.c --- xnu-344.49/bsd/dev/random/randomdev.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/random/randomdev.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999, 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -40,6 +40,8 @@ #define RANDOM_MAJOR -1 /* let the kernel pick the device number */ +d_ioctl_t random_ioctl; + /* * A struct describing which functions will get invoked for certain * actions. @@ -50,7 +52,7 @@ random_close, /* close */ random_read, /* read */ random_write, /* write */ - eno_ioctl, /* ioctl */ + random_ioctl, /* ioctl */ nulldev, /* stop */ nulldev, /* reset */ NULL, /* tty's */ @@ -142,14 +144,33 @@ } devfs_make_node(makedev (ret, 0), DEVFS_CHAR, - UID_ROOT, GID_WHEEL, 0644, "random", 0); + UID_ROOT, GID_WHEEL, 0666, "random", 0); /* * also make urandom * (which is exactly the same thing in our context) */ devfs_make_node(makedev (ret, 1), DEVFS_CHAR, - UID_ROOT, GID_WHEEL, 0644, "urandom", 0); + UID_ROOT, GID_WHEEL, 0666, "urandom", 0); +} + +int +random_ioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + switch (cmd) { + case FIONBIO: + case FIOASYNC: + break; + default: + return ENODEV; + } + + return (0); } /* @@ -172,8 +193,10 @@ if (flags & FWRITE) { if (securelevel >= 2) return (EPERM); +#ifndef __APPLE__ if ((securelevel >= 1) && suser(p->p_ucred, &p->p_acflag)) return (EPERM); +#endif /* !__APPLE__ */ } return (0); diff -urN xnu-344.49/bsd/dev/vn/shadow.c xnu-517/bsd/dev/vn/shadow.c --- xnu-344.49/bsd/dev/vn/shadow.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/vn/shadow.c Sat Oct 25 00:25:25 2003 @@ -61,11 +61,11 @@ #include #define my_malloc(a) malloc(a) #define my_free(a) free(a) -#else TEST_SHADOW +#else /* !TEST_SHADOW */ #include #define my_malloc(a) _MALLOC(a, M_TEMP, M_WAITOK) #define my_free(a) FREE(a, M_TEMP) -#endif TEST_SHADOW +#endif /* TEST_SHADOW */ #include "shadow.h" diff -urN xnu-344.49/bsd/dev/vn/vn.c xnu-517/bsd/dev/vn/vn.c --- xnu-344.49/bsd/dev/vn/vn.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/dev/vn/vn.c Sat Oct 25 00:25:25 2003 @@ -73,11 +73,10 @@ #include #include #include -#include #include #include #include -#include +#include #include #include @@ -91,6 +90,17 @@ #include +extern void +vfs_io_maxsegsize(struct vnode *vp, + int flags, /* B_READ or B_WRITE */ + int *maxsegsize); + +extern void +vfs_io_attributes(struct vnode *vp, + int flags, /* B_READ or B_WRITE */ + int *iosize, + int *vectors); + #include "shadow.h" static ioctl_fcn_t vnioctl_chr; @@ -388,7 +398,7 @@ VOP_TRUNCATE(vn->sc_shadow_vp, size, IO_SYNC, vn->sc_cred, p); VOP_UNLOCK(vn->sc_shadow_vp, 0, p); -#endif 0 +#endif } error = file_io(vn->sc_shadow_vp, vn->sc_cred, UIO_WRITE, base + start, @@ -494,8 +504,10 @@ * simply read or write less. */ if (bp->b_blkno >= vn->sc_size) { - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR | B_INVAL; + if (bp->b_blkno > vn->sc_size) { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR | B_INVAL; + } biodone(bp); return; } @@ -531,8 +543,10 @@ struct vn_ioctl *vio; int error; u_long *f; + int num = 0; u_int64_t * o; int unit; + int size = 0; unit = vnunit(dev); if (vnunit(dev) >= NVNDEVICE) { @@ -548,10 +562,15 @@ o = (u_int64_t *)data; switch (cmd) { case VNIOCDETACH: + case DKIOCGETBLOCKSIZE: + case DKIOCSETBLOCKSIZE: case DKIOCGETMAXBLOCKCOUNTREAD: case DKIOCGETMAXBLOCKCOUNTWRITE: case DKIOCGETMAXSEGMENTCOUNTREAD: case DKIOCGETMAXSEGMENTCOUNTWRITE: + case DKIOCGETMAXSEGMENTBYTECOUNTREAD: + case DKIOCGETMAXSEGMENTBYTECOUNTWRITE: + case DKIOCGETBLOCKCOUNT: case DKIOCGETBLOCKCOUNT32: if ((vn->sc_flags & VNF_INITED) == 0) { return (ENXIO); @@ -562,16 +581,36 @@ } switch (cmd) { case DKIOCGETMAXBLOCKCOUNTREAD: - *o = vn->sc_vp->v_mount->mnt_maxreadcnt / vn->sc_secsize; + vfs_io_attributes(vn->sc_vp, B_READ, &size, &num); + *o = size / vn->sc_secsize; break; case DKIOCGETMAXBLOCKCOUNTWRITE: - *o = vn->sc_vp->v_mount->mnt_maxwritecnt / vn->sc_secsize; + vfs_io_attributes(vn->sc_vp, B_WRITE, &size, &num); + *o = size / vn->sc_secsize; + break; + case DKIOCGETMAXBYTECOUNTREAD: + vfs_io_attributes(vn->sc_vp, B_READ, &size, &num); + *o = size; + break; + case DKIOCGETMAXBYTECOUNTWRITE: + vfs_io_attributes(vn->sc_vp, B_WRITE, &size, &num); + *o = size; break; case DKIOCGETMAXSEGMENTCOUNTREAD: - *o = vn->sc_vp->v_mount->mnt_segreadcnt; + vfs_io_attributes(vn->sc_vp, B_READ, &size, &num); + *o = num; break; case DKIOCGETMAXSEGMENTCOUNTWRITE: - *o = vn->sc_vp->v_mount->mnt_segwritecnt; + vfs_io_attributes(vn->sc_vp, B_WRITE, &size, &num); + *o = num; + break; + case DKIOCGETMAXSEGMENTBYTECOUNTREAD: + vfs_io_maxsegsize(vn->sc_vp, B_READ, &size); + *o = size; + break; + case DKIOCGETMAXSEGMENTBYTECOUNTWRITE: + vfs_io_maxsegsize(vn->sc_vp, B_WRITE, &size); + *o = size; break; case DKIOCGETBLOCKSIZE: *f = vn->sc_secsize; @@ -598,7 +637,7 @@ case DKIOCGETBLOCKCOUNT32: *f = vn->sc_size; break; - case DKIOCGETBLOCKCOUNT64: + case DKIOCGETBLOCKCOUNT: *o = vn->sc_size; break; case VNIOCSHADOW: @@ -757,7 +796,7 @@ vn->sc_size = (quad_t)vio->vn_size * PAGE_SIZE / vn->sc_secsize; else vn->sc_size = vattr.va_size / vn->sc_secsize; -#endif 0 +#endif vn->sc_secsize = DEV_BSIZE; vn->sc_fsize = vattr.va_size; vn->sc_size = vattr.va_size / vn->sc_secsize; @@ -980,4 +1019,4 @@ printf("vninit: devfs_make_node failed!\n"); } } -#endif NVNDEVICE +#endif /* NVNDEVICE */ diff -urN xnu-344.49/bsd/hfs/hfs.h xnu-517/bsd/hfs/hfs.h --- xnu-344.49/bsd/hfs/hfs.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs.h Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,6 +26,8 @@ #ifndef __HFS__ #define __HFS__ +#define HFS_SPARSE_DEV 1 + #include #ifdef KERNEL @@ -38,6 +40,7 @@ #include #include #include +#include #include @@ -46,6 +49,7 @@ #include #include #include +#include struct uio; // This is more effective than #include in case KERNEL is undefined... @@ -60,6 +64,11 @@ #define HFS_MAX_DEFERED_ALLOC (1024*1024) +// 32 gigs is a "big" file (i.e. one that when deleted +// would touch enough data that we should break it into +// multiple separate transactions +#define HFS_BIGFILE_SIZE (32LL * 1024LL * 1024LL * 1024LL) + enum { kMDBSize = 512 }; /* Size of I/O transfer to read entire MDB */ @@ -104,7 +113,24 @@ * superuser may continue to allocate blocks. */ #define HFS_MINFREE 1 -#define HFS_MAXRESERVE (u_int64_t)(250*1024*1024) +#define HFS_MAXRESERVE ((u_int64_t)(250*1024*1024)) + +/* + * The system distinguishes between the desirable low-disk + * notifiaction levels for root volumes and non-root volumes. + * The various thresholds are computed as a fraction of the + * volume size, all capped at a certain fixed level + */ + +#define HFS_ROOTLOWDISKTRIGGERFRACTION 5 +#define HFS_ROOTLOWDISKTRIGGERLEVEL ((u_int64_t)(250*1024*1024)) +#define HFS_ROOTLOWDISKSHUTOFFFRACTION 6 +#define HFS_ROOTLOWDISKSHUTOFFLEVEL ((u_int64_t)(375*1024*1024)) + +#define HFS_LOWDISKTRIGGERFRACTION 1 +#define HFS_LOWDISKTRIGGERLEVEL ((u_int64_t)(50*1024*1024)) +#define HFS_LOWDISKSHUTOFFFRACTION 2 +#define HFS_LOWDISKSHUTOFFLEVEL ((u_int64_t)(75*1024*1024)) /* Internal Data structures*/ @@ -183,10 +209,7 @@ /* This structure describes the HFS specific mount structure data. */ typedef struct hfsmount { - u_int8_t hfs_fs_ronly; /* Whether this was mounted as read-initially */ - u_int8_t hfs_unknownpermissions; /* Whether this was mounted with MNT_UNKNOWNPERMISSIONS */ - u_int8_t hfs_media_writeable; - u_int8_t hfs_orphans_cleaned; + u_int32_t hfs_flags; /* see below */ /* Physical Description */ u_long hfs_phys_block_count; /* Num of PHYSICAL blocks of volume */ @@ -206,9 +229,6 @@ mode_t hfs_file_mask; /* mask to and with file protection bits */ u_long hfs_encoding; /* Defualt encoding for non hfs+ volumes */ - /* simple lock for shared meta renaming */ - simple_lock_data_t hfs_renamelock; - /* HFS Specific */ struct vfsVCB hfs_vcb; struct cat_desc hfs_privdir_desc; @@ -217,19 +237,66 @@ hfs_to_unicode_func_t hfs_get_unicode; unicode_to_hfs_func_t hfs_get_hfsname; + /* Quota variables: */ struct quotafile hfs_qfiles[MAXQUOTAS]; /* quota files */ - // XXXdbg + /* Journaling variables: */ void *jnl; // the journal for this volume (if one exists) struct vnode *jvp; // device where the journal lives (may be equal to devvp) u_int32_t jnl_start; // start block of the journal file (so we don't delete it) + u_int32_t jnl_size; u_int32_t hfs_jnlfileid; u_int32_t hfs_jnlinfoblkid; - volatile int readers; + volatile int readers; volatile int blocker; + + /* Notification variables: */ + unsigned long hfs_notification_conditions; + u_int32_t hfs_freespace_notify_warninglimit; + u_int32_t hfs_freespace_notify_desiredlevel; + + /* Metadata allocation zone variables: */ + u_int32_t hfs_metazone_start; + u_int32_t hfs_metazone_end; + u_int32_t hfs_hotfile_start; + u_int32_t hfs_hotfile_end; + int hfs_hotfile_freeblks; + int hfs_hotfile_maxblks; + int hfs_overflow_maxblks; + int hfs_catalog_maxblks; + + /* Hot File Clustering variables: */ + enum hfc_stage hfc_stage; /* what are we up to... */ + time_t hfc_timebase; /* recording period start time */ + time_t hfc_timeout; /* recording period stop time */ + void * hfc_recdata; /* recording data (opaque) */ + int hfc_maxfiles; /* maximum files to track */ + struct vnode * hfc_filevp; + +#ifdef HFS_SPARSE_DEV + /* Sparse device variables: */ + struct vnode * hfs_backingfs_rootvp; + int hfs_sparsebandblks; +#endif } hfsmount_t; -#define hfs_private_metadata_dir hfs_privdir_desc.cd_cnid + +/* HFS mount point flags */ +#define HFS_READ_ONLY 0x001 +#define HFS_UNKNOWN_PERMS 0x002 +#define HFS_WRITEABLE_MEDIA 0x004 +#define HFS_CLEANED_ORPHANS 0x008 +#define HFS_X 0x010 +#define HFS_CASE_SENSITIVE 0x020 +#define HFS_STANDARD 0x040 +#define HFS_METADATA_ZONE 0x080 +#define HFS_FRAGMENTED_FREESPACE 0x100 +#define HFS_NEED_JNL_RESET 0x200 + +#ifdef HFS_SPARSE_DEV +#define HFS_HAS_SPARSE_DEVICE 0x400 +#endif + #define hfs_global_shared_lock_acquire(hfsmp) \ do { \ @@ -276,16 +343,6 @@ #define MAKE_INODE_NAME(name,linkno) \ (void) sprintf((name), "%s%d", HFS_INODE_PREFIX, (linkno)) -/* - * Write check macro - */ -#define WRITE_CK(VNODE, FUNC_NAME) { \ - if ((VNODE)->v_mount->mnt_flag & MNT_RDONLY) { \ - DBG_ERR(("%s: ATTEMPT TO WRITE A READONLY VOLUME\n", \ - FUNC_NAME)); \ - return(EROFS); \ - } \ -} /* structure to hold a "." or ".." directory entry (12 bytes) */ typedef struct hfsdotentry { @@ -304,55 +361,6 @@ ((sizeof(struct dirent) - (NAME_MAX+1)) + (((namlen)+1 + 3) &~ 3)) -enum { - kCatalogFolderNode = 1, - kCatalogFileNode = 2 -}; - -/* - * CatalogNodeData has same layout as the on-disk HFS Plus file/dir records. - * Classic hfs file/dir records are converted to match this layout. - * - * The cnd_extra padding allows big hfs plus thread records (520 bytes max) - * to be read onto this stucture during a cnid lookup. - * - */ -struct CatalogNodeData { - int16_t cnd_type; - u_int16_t cnd_flags; - u_int32_t cnd_valence; /* dirs only */ - u_int32_t cnd_nodeID; - u_int32_t cnd_createDate; - u_int32_t cnd_contentModDate; - u_int32_t cnd_attributeModDate; - u_int32_t cnd_accessDate; - u_int32_t cnd_backupDate; - u_int32_t cnd_ownerID; - u_int32_t cnd_groupID; - u_int8_t cnd_adminFlags; /* super-user changeable flags */ - u_int8_t cnd_ownerFlags; /* owner changeable flags */ - u_int16_t cnd_mode; /* file type + permission bits */ - union { - u_int32_t cndu_iNodeNum; /* indirect links only */ - u_int32_t cndu_linkCount; /* indirect nodes only */ - u_int32_t cndu_rawDevice; /* special files (FBLK and FCHR) only */ - } cnd_un; - u_int8_t cnd_finderInfo[32]; - u_int32_t cnd_textEncoding; - u_int32_t cnd_reserved; - HFSPlusForkData cnd_datafork; - HFSPlusForkData cnd_rsrcfork; - u_int32_t cnd_iNodeNumCopy; - u_int32_t cnd_linkCNID; /* for hard links only */ - u_int8_t cnd_extra[264]; /* make struct at least 520 bytes long */ -}; -typedef struct CatalogNodeData CatalogNodeData; - -#define cnd_iNodeNum cnd_un.cndu_iNodeNum -#define cnd_linkCount cnd_un.cndu_linkCount -#define cnd_rawDevice cnd_un.cndu_rawDevice - - enum { kHFSPlusMaxFileNameBytes = kHFSPlusMaxFileNameChars * 3 }; @@ -388,6 +396,9 @@ #define FCBTOVCB(FCB) (&(((struct hfsmount *)((FCB)->ff_cp->c_vp->v_mount->mnt_data))->hfs_vcb.vcb_vcb)) +#define HFS_KNOTE(vp, hint) KNOTE(&VTOC(vp)->c_knotes, (hint)) + + #define E_NONE 0 #define kHFSBlockSize 512 @@ -411,11 +422,10 @@ u_int32_t to_bsd_time(u_int32_t hfs_time); u_int32_t to_hfs_time(u_int32_t bsd_time); -int hfs_flushfiles(struct mount *mp, int flags, struct proc *p); int hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush); #define HFS_ALTFLUSH 1 -short hfsUnmount(struct hfsmount *hfsmp, struct proc *p); +extern int hfsUnmount(struct hfsmount *hfsmp, struct proc *p); extern int hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, @@ -493,6 +503,10 @@ extern void replace_desc(struct cnode *cp, struct cat_desc *cdp); extern int hfs_namecmp(const char *, size_t, const char *, size_t); + +extern int hfs_virtualmetafile(struct cnode *); + +void hfs_generate_volume_notifications(struct hfsmount *hfsmp); #endif /* __APPLE_API_PRIVATE */ diff -urN xnu-344.49/bsd/hfs/hfs_attrlist.c xnu-517/bsd/hfs/hfs_attrlist.c --- xnu-344.49/bsd/hfs/hfs_attrlist.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_attrlist.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -45,9 +45,6 @@ -extern uid_t console_user; - - /* Routines that are shared by hfs_setattr: */ extern int hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags); @@ -71,22 +68,22 @@ static void packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, - struct vnode *vp); + struct vnode *vp, struct proc *p); static void packvolattr(struct attrblock *abp, struct hfsmount *hfsmp, - struct vnode *vp); + struct vnode *vp, struct proc *p); static void packcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp, struct cat_desc * cdp, - struct cat_attr * cap); + struct cat_attr * cap, struct proc *p); static void packfileattr(struct attrblock *abp, struct hfsmount *hfsmp, struct cat_attr *cattrp, struct cat_fork *datafork, - struct cat_fork *rsrcfork); + struct cat_fork *rsrcfork, struct proc *p); static void packdirattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp, struct cat_desc * descp, - struct cat_attr * cattrp); + struct cat_attr * cattrp, struct proc *p); static void unpackattrblk(struct attrblock *abp, struct vnode *vp); @@ -192,39 +189,34 @@ (alist->commonattr & ATTR_CMN_OBJPERMANENTID) && (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + cat_cookie_t cookie = {0}; + + if (hfsmp->hfs_flags & HFS_READ_ONLY) return (EROFS); if ((error = hfs_write_access(vp, ap->a_cred, ap->a_p, false)) != 0) return (error); - // XXXdbg - hfs_global_shared_lock_acquire(hfsmp); - if (hfsmp->jnl) { - if ((error = journal_start_transaction(hfsmp->jnl)) != 0) { - hfs_global_shared_lock_release(hfsmp); - return error; - } - } + /* + * Reserve some space in the Catalog file. + */ + error = cat_preflight(hfsmp, CAT_CREATE, &cookie, ap->a_p); + if (error) + return (error); /* Lock catalog b-tree */ - error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, ap->a_p); + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, + LK_EXCLUSIVE, ap->a_p); if (error) { - if (hfsmp->jnl) { - journal_end_transaction(hfsmp->jnl); - } - hfs_global_shared_lock_release(hfsmp); - return (error); + cat_postflight(hfsmp, &cookie, ap->a_p); + return (error); } error = cat_insertfilethread(hfsmp, &cp->c_desc); - /* Unlock catalog b-tree */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p); + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, + ap->a_p); - if (hfsmp->jnl) { - journal_end_transaction(hfsmp->jnl); - } - hfs_global_shared_lock_release(hfsmp); + cat_postflight(hfsmp, &cookie, ap->a_p); if (error) return (error); @@ -291,7 +283,7 @@ attrblk.ab_blocksize = attrblocksize; hfs_packattrblk(&attrblk, hfsmp, vp, &cp->c_desc, &cp->c_attr, - datafp, rsrcfp); + datafp, rsrcfp, ap->a_p); /* Don't copy out more data than was generated */ attrbufsize = MIN(attrbufsize, (u_int)varptr - (u_int)attrbufptr); @@ -346,7 +338,7 @@ u_long saved_flags; int error = 0; - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + if (hfsmp->hfs_flags & HFS_READ_ONLY) return (EROFS); if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) || @@ -378,7 +370,7 @@ if (hfsmp->jnl && cp->c_datafork) { struct HFSPlusExtentDescriptor *extd; - extd = &cp->c_datafork->ff_data.cf_extents[0]; + extd = &cp->c_datafork->ff_extents[0]; if (extd->startBlock == HFSTOVCB(hfsmp)->vcbJinfoBlock || extd->startBlock == hfsmp->jnl_start) { return EPERM; } @@ -503,6 +495,10 @@ struct cat_desc to_desc = {0}; struct cat_desc todir_desc = {0}; struct cat_desc new_desc = {0}; + cat_cookie_t cookie = {0}; + int catreserve = 0; + int catlocked = 0; + int started_tr = 0; todir_desc.cd_parentcnid = kRootParID; todir_desc.cd_cnid = kRootParID; @@ -517,38 +513,38 @@ // XXXdbg hfs_global_shared_lock_acquire(hfsmp); if (hfsmp->jnl) { - if (journal_start_transaction(hfsmp->jnl) != 0) { - hfs_global_shared_lock_release(hfsmp); - error = EINVAL; - /* Restore the old name in the VCB */ - copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL); - vcb->vcbFlags |= 0xFF00; - goto ErrorExit; - } + if ((error = journal_start_transaction(hfsmp->jnl) != 0)) { + goto rename_out; + } + started_tr = 1; } + /* + * Reserve some space in the Catalog file. + */ + error = cat_preflight(hfsmp, CAT_RENAME, &cookie, p); + if (error) { + goto rename_out; + } + catreserve = 1; /* Lock catalog b-tree */ error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); if (error) { - if (hfsmp->jnl) { - journal_end_transaction(hfsmp->jnl); - } - hfs_global_shared_lock_release(hfsmp); - - /* Restore the old name in the VCB */ - copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL); - vcb->vcbFlags |= 0xFF00; - goto ErrorExit; + goto rename_out; } + catlocked = 1; error = cat_rename(hfsmp, &cp->c_desc, &todir_desc, &to_desc, &new_desc); - - /* Unlock the Catalog */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - - if (hfsmp->jnl) { - journal_end_transaction(hfsmp->jnl); +rename_out: + if (catlocked) { + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + } + if (catreserve) { + cat_postflight(hfsmp, &cookie, p); + } + if (started_tr) { + journal_end_transaction(hfsmp->jnl); } hfs_global_shared_lock_release(hfsmp); @@ -565,7 +561,7 @@ cp->c_desc.cd_nameptr = 0; cp->c_desc.cd_namelen = 0; cp->c_desc.cd_flags &= ~CD_HASBUF; - FREE(name, M_TEMP); + remove_name(name); } /* Update cnode's catalog descriptor */ replace_desc(cp, &new_desc); @@ -788,14 +784,12 @@ cdescp = &cp->c_desc; cattrp = &cp->c_attr; if (cp->c_datafork) { - c_datafork.cf_size = cp->c_datafork->ff_data.cf_size; - c_datafork.cf_clump = cp->c_datafork->ff_data.cf_clump; - c_datafork.cf_blocks = cp->c_datafork->ff_data.cf_blocks; + c_datafork.cf_size = cp->c_datafork->ff_size; + c_datafork.cf_blocks = cp->c_datafork->ff_blocks; } if (cp->c_rsrcfork) { - c_rsrcfork.cf_size = cp->c_rsrcfork->ff_data.cf_size; - c_rsrcfork.cf_clump = cp->c_rsrcfork->ff_data.cf_clump; - c_rsrcfork.cf_blocks = cp->c_rsrcfork->ff_data.cf_blocks; + c_rsrcfork.cf_size = cp->c_rsrcfork->ff_size; + c_rsrcfork.cf_blocks = cp->c_rsrcfork->ff_blocks; } } } @@ -808,7 +802,7 @@ /* Pack catalog entries into attribute buffer. */ hfs_packattrblk(&attrblk, hfsmp, vp, cdescp, cattrp, - &c_datafork, &c_rsrcfork); + &c_datafork, &c_rsrcfork, p); currattrbufsize = ((char *)varptr - (char *)attrbufptr); /* All done with cnode. */ @@ -910,25 +904,26 @@ struct cat_desc *descp, struct cat_attr *attrp, struct cat_fork *datafork, - struct cat_fork *rsrcfork) + struct cat_fork *rsrcfork, + struct proc *p) { struct attrlist *attrlistp = abp->ab_attrlist; if (attrlistp->volattr) { if (attrlistp->commonattr) - packvolcommonattr(abp, hfsmp, vp); + packvolcommonattr(abp, hfsmp, vp, p); if (attrlistp->volattr & ~ATTR_VOL_INFO) - packvolattr(abp, hfsmp, vp); + packvolattr(abp, hfsmp, vp, p); } else { if (attrlistp->commonattr) - packcommonattr(abp, hfsmp, vp, descp, attrp); + packcommonattr(abp, hfsmp, vp, descp, attrp, p); if (attrlistp->dirattr && S_ISDIR(attrp->ca_mode)) - packdirattr(abp, hfsmp, vp, descp,attrp); + packdirattr(abp, hfsmp, vp, descp,attrp, p); if (attrlistp->fileattr && !S_ISDIR(attrp->ca_mode)) - packfileattr(abp, hfsmp, attrp, datafork, rsrcfork); + packfileattr(abp, hfsmp, attrp, datafork, rsrcfork, p); } } @@ -966,7 +961,8 @@ struct attrblock *abp, struct vnode *vp, char *name, - int namelen) + int namelen, + struct proc *p) { void *varbufptr; struct attrreference * attr_refptr; @@ -1022,7 +1018,7 @@ * Pack common volume attributes. */ static void -packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp) +packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp, struct proc *p) { attrgroup_t attr; void *attrbufptr = *abp->ab_attrbufpp; @@ -1035,7 +1031,7 @@ attr = abp->ab_attrlist->commonattr; if (ATTR_CMN_NAME & attr) { - packnameattr(abp, vp, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen); + packnameattr(abp, vp, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen, p); attrbufptr = *abp->ab_attrbufpp; varbufptr = *abp->ab_varbufpp; } @@ -1107,7 +1103,7 @@ } if (ATTR_CMN_OWNERID & attr) { if (cp->c_uid == UNKNOWNUID) - *((uid_t *)attrbufptr)++ = console_user; + *((uid_t *)attrbufptr)++ = p->p_ucred->cr_uid; else *((uid_t *)attrbufptr)++ = cp->c_uid; } @@ -1154,7 +1150,7 @@ static void -packvolattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp) +packvolattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp, struct proc *p) { attrgroup_t attr; void *attrbufptr = *abp->ab_attrbufpp; @@ -1179,7 +1175,6 @@ if (ATTR_VOL_SPACEFREE & attr) { *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 0) * (off_t)vcb->blockSize; - } if (ATTR_VOL_SPACEAVAIL & attr) { *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 1) * @@ -1263,31 +1258,70 @@ vcapattrptr = (vol_capabilities_attr_t *)attrbufptr; if (vcb->vcbSigWord == kHFSPlusSigWord) { + u_int32_t journal_active; + u_int32_t case_sensitive; + + if (hfsmp->jnl) + journal_active = VOL_CAP_FMT_JOURNAL_ACTIVE; + else + journal_active = 0; + + if (hfsmp->hfs_flags & HFS_CASE_SENSITIVE) + case_sensitive = VOL_CAP_FMT_CASE_SENSITIVE; + else + case_sensitive = 0; + vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | - VOL_CAP_FMT_HARDLINKS; + VOL_CAP_FMT_HARDLINKS | + VOL_CAP_FMT_JOURNAL | + journal_active | + case_sensitive | + VOL_CAP_FMT_CASE_PRESERVING | + VOL_CAP_FMT_FAST_STATFS ; } else { /* Plain HFS */ vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] = - VOL_CAP_FMT_PERSISTENTOBJECTIDS; + VOL_CAP_FMT_PERSISTENTOBJECTIDS | + VOL_CAP_FMT_CASE_PRESERVING | + VOL_CAP_FMT_FAST_STATFS ; } vcapattrptr->capabilities[VOL_CAPABILITIES_INTERFACES] = VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | - VOL_CAP_INT_READDIRATTR ; + VOL_CAP_INT_READDIRATTR | + VOL_CAP_INT_EXCHANGEDATA | + VOL_CAP_INT_ALLOCATE | + VOL_CAP_INT_VOL_RENAME | + VOL_CAP_INT_ADVLOCK | + VOL_CAP_INT_FLOCK ; vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED1] = 0; vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED2] = 0; vcapattrptr->valid[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | - VOL_CAP_FMT_HARDLINKS; + VOL_CAP_FMT_HARDLINKS | + VOL_CAP_FMT_JOURNAL | + VOL_CAP_FMT_JOURNAL_ACTIVE | + VOL_CAP_FMT_NO_ROOT_TIMES | + VOL_CAP_FMT_SPARSE_FILES | + VOL_CAP_FMT_ZERO_RUNS | + VOL_CAP_FMT_CASE_SENSITIVE | + VOL_CAP_FMT_CASE_PRESERVING | + VOL_CAP_FMT_FAST_STATFS ; vcapattrptr->valid[VOL_CAPABILITIES_INTERFACES] = VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | - VOL_CAP_INT_READDIRATTR ; + VOL_CAP_INT_READDIRATTR | + VOL_CAP_INT_EXCHANGEDATA | + VOL_CAP_INT_COPYFILE | + VOL_CAP_INT_ALLOCATE | + VOL_CAP_INT_VOL_RENAME | + VOL_CAP_INT_ADVLOCK | + VOL_CAP_INT_FLOCK ; vcapattrptr->valid[VOL_CAPABILITIES_RESERVED1] = 0; vcapattrptr->valid[VOL_CAPABILITIES_RESERVED2] = 0; @@ -1322,7 +1356,8 @@ struct hfsmount *hfsmp, struct vnode *vp, struct cat_desc * cdp, - struct cat_attr * cap) + struct cat_attr * cap, + struct proc *p) { attrgroup_t attr = abp->ab_attrlist->commonattr; struct mount *mp = HFSTOVFS(hfsmp); @@ -1331,7 +1366,7 @@ u_long attrlength = 0; if (ATTR_CMN_NAME & attr) { - packnameattr(abp, vp, cdp->cd_nameptr, cdp->cd_namelen); + packnameattr(abp, vp, cdp->cd_nameptr, cdp->cd_namelen, p); attrbufptr = *abp->ab_attrbufpp; varbufptr = *abp->ab_varbufpp; } @@ -1409,7 +1444,7 @@ } if (ATTR_CMN_OWNERID & attr) { *((uid_t *)attrbufptr)++ = - (cap->ca_uid == UNKNOWNUID) ? console_user : cap->ca_uid; + (cap->ca_uid == UNKNOWNUID) ? p->p_ucred->cr_uid : cap->ca_uid; } if (ATTR_CMN_GRPID & attr) { *((gid_t *)attrbufptr)++ = cap->ca_gid; @@ -1459,7 +1494,8 @@ struct hfsmount *hfsmp, struct vnode *vp, struct cat_desc * descp, - struct cat_attr * cattrp) + struct cat_attr * cattrp, + struct proc *p) { attrgroup_t attr = abp->ab_attrlist->dirattr; void *attrbufptr = *abp->ab_attrbufpp; @@ -1470,7 +1506,7 @@ u_long entries = cattrp->ca_entries; if (descp->cd_parentcnid == kRootParID) { - if (hfsmp->hfs_private_metadata_dir != 0) + if (hfsmp->hfs_privdir_desc.cd_cnid != 0) --entries; /* hide private dir */ if (hfsmp->jnl) entries -= 2; /* hide the journal files */ @@ -1493,7 +1529,8 @@ struct hfsmount *hfsmp, struct cat_attr *cattrp, struct cat_fork *datafork, - struct cat_fork *rsrcfork) + struct cat_fork *rsrcfork, + struct proc *p) { attrgroup_t attr = abp->ab_attrlist->fileattr; void *attrbufptr = *abp->ab_attrbufpp; @@ -1517,7 +1554,7 @@ *((u_long *)attrbufptr)++ = hfsmp->hfs_logBlockSize; } if (ATTR_FILE_CLUMPSIZE & attr) { - *((u_long *)attrbufptr)++ = datafork->cf_clump; /* XXX ambiguity */ + *((u_long *)attrbufptr)++ = HFSTOVCB(hfsmp)->vcbClpSiz; } if (ATTR_FILE_DEVTYPE & attr) { if (S_ISBLK(cattrp->ca_mode) || S_ISCHR(cattrp->ca_mode)) @@ -1870,7 +1907,7 @@ int i; if (obj_uid == UNKNOWNUID) - obj_uid = console_user; + obj_uid = p->p_ucred->cr_uid; /* User id 0 (root) always gets access. */ if (cred->cr_uid == 0) { diff -urN xnu-344.49/bsd/hfs/hfs_attrlist.h xnu-517/bsd/hfs/hfs_attrlist.h --- xnu-344.49/bsd/hfs/hfs_attrlist.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_attrlist.h Sat Oct 25 00:25:25 2003 @@ -64,7 +64,7 @@ extern void hfs_packattrblk(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp, struct cat_desc *descp, struct cat_attr *attrp, - struct cat_fork *datafork, struct cat_fork *rsrcfork); + struct cat_fork *datafork, struct cat_fork *rsrcfork, struct proc *p); #endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ diff -urN xnu-344.49/bsd/hfs/hfs_btreeio.c xnu-517/bsd/hfs/hfs_btreeio.c --- xnu-344.49/bsd/hfs/hfs_btreeio.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_btreeio.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -142,6 +142,27 @@ blockPtr->isModified = 1; } +static int +btree_journal_modify_block_end(struct hfsmount *hfsmp, struct buf *bp) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + struct vnode *vp = bp->b_vp; + BlockDescriptor block; + + /* Prepare the block pointer */ + block.blockHeader = bp; + block.buffer = bp->b_data; + /* not found in cache ==> came from disk */ + block.blockReadFromDisk = (bp->b_flags & B_CACHE) == 0; + block.blockSize = bp->b_bcount; + + // XXXdbg have to swap the data before it goes in the journal + SWAP_BT_NODE (&block, ISHFSPLUS (VTOVCB(vp)), VTOC(vp)->c_fileid, 1); +#endif + + return journal_modify_block_end(hfsmp->jnl, bp); +} + __private_extern__ OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options) @@ -171,7 +192,8 @@ if (blockPtr->isModified == 0) { panic("hfs: releaseblock: modified is 0 but forcewrite set! bp 0x%x\n", bp); } - retval = journal_modify_block_end(hfsmp->jnl, bp); + + retval = btree_journal_modify_block_end(hfsmp, bp); blockPtr->isModified = 0; } else { retval = VOP_BWRITE(bp); @@ -206,7 +228,7 @@ if (blockPtr->isModified == 0) { panic("hfs: releaseblock: modified is 0 but markdirty set! bp 0x%x\n", bp); } - retval = journal_modify_block_end(hfsmp->jnl, bp); + retval = btree_journal_modify_block_end(hfsmp, bp); blockPtr->isModified = 0; } else if (bdwrite_internal(bp, 1) != 0) { hfs_btsync(vp, 0); @@ -226,7 +248,7 @@ // // journal_modify_block_abort(hfsmp->jnl, bp); //panic("hfs: releaseblock called for 0x%x but mod_block_start previously called.\n", bp); - journal_modify_block_end(hfsmp->jnl, bp); + btree_journal_modify_block_end(hfsmp, bp); blockPtr->isModified = 0; } else { brelse(bp); /* note: B-tree code will clear blockPtr->blockHeader and blockPtr->buffer */ @@ -311,7 +333,9 @@ // is at least the node size then we break out of the loop and let // the error propagate back up. do { - retval = ExtendFileC(vcb, filePtr, bytesToAdd, 0, kEFContigMask, &actualBytesAdded); + retval = ExtendFileC(vcb, filePtr, bytesToAdd, 0, + kEFContigMask | kEFMetadataMask, + &actualBytesAdded); if (retval == dskFulErr && actualBytesAdded == 0) { if (bytesToAdd == btInfo.nodeSize || bytesToAdd < (minEOF - origSize)) { @@ -336,6 +360,7 @@ * there's plenty of room to grow. */ if ((retval == 0) && + ((VCBTOHFS(vcb)->hfs_flags & HFS_METADATA_ZONE) == 0) && (vcb->nextAllocation > startAllocation) && ((vcb->nextAllocation + fileblocks) < vcb->totalBlocks)) { vcb->nextAllocation += fileblocks; @@ -418,6 +443,11 @@ ) { MarkVCBDirty( vcb ); ret = hfs_flushvolumeheader(VCBTOHFS(vcb), MNT_WAIT, HFS_ALTFLUSH); + } else { + struct timeval tv = time; + + VTOC(vp)->c_flag |= C_CHANGE | C_UPDATE; + (void) VOP_UPDATE(vp, &tv, &tv, MNT_WAIT); } ret = ClearBTNodes(vp, btInfo.nodeSize, filePtr->fcbEOF - actualBytesAdded, actualBytesAdded); diff -urN xnu-344.49/bsd/hfs/hfs_catalog.c xnu-517/bsd/hfs/hfs_catalog.c --- xnu-344.49/bsd/hfs/hfs_catalog.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_catalog.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -89,6 +89,8 @@ int resolvelink(struct hfsmount *hfsmp, u_long linkref, struct HFSPlusCatalogFile *recp); +static int resolvelinkid(struct hfsmount *hfsmp, u_long linkref, ino_t *ino); + static int getkey(struct hfsmount *hfsmp, cnid_t cnid, CatalogKey * key); static int buildkey(struct hfsmount *hfsmp, struct cat_desc *descp, @@ -118,8 +120,46 @@ static int buildthread(void *keyp, void *recp, int std_hfs, int directory); +__private_extern__ +int +cat_preflight(struct hfsmount *hfsmp, catops_t ops, cat_cookie_t *cookie, struct proc *p) +{ + FCB *fcb; + int result; + + fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum); + + /* Lock catalog b-tree */ + result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (result) + return (result); + + result = BTReserveSpace(fcb, ops, (void*)cookie); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + + MacToVFSError(result); +} + +__private_extern__ +void +cat_postflight(struct hfsmount *hfsmp, cat_cookie_t *cookie, struct proc *p) +{ + FCB *fcb; + int error; + + fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum); + + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + (void) BTReleaseReserve(fcb, (void*)cookie); + if (error == 0) { + hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + } +} + - +__private_extern__ void cat_convertattr( struct hfsmount *hfsmp, @@ -145,11 +185,39 @@ promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, 0, datafp); promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, 1, rsrcfp); } else { - bcopy(&recp->hfsPlusFile.dataFork, datafp, sizeof(*datafp)); - bcopy(&recp->hfsPlusFile.resourceFork, rsrcfp, sizeof(*rsrcfp)); + /* Convert the data fork. */ + datafp->cf_size = recp->hfsPlusFile.dataFork.logicalSize; + datafp->cf_blocks = recp->hfsPlusFile.dataFork.totalBlocks; + if ((hfsmp->hfc_stage == HFC_RECORDING) && + (attrp->ca_atime >= hfsmp->hfc_timebase)) { + datafp->cf_bytesread = + recp->hfsPlusFile.dataFork.clumpSize * + HFSTOVCB(hfsmp)->blockSize; + } else { + datafp->cf_bytesread = 0; + } + datafp->cf_vblocks = 0; + bcopy(&recp->hfsPlusFile.dataFork.extents[0], + &datafp->cf_extents[0], sizeof(HFSPlusExtentRecord)); + + /* Convert the resource fork. */ + rsrcfp->cf_size = recp->hfsPlusFile.resourceFork.logicalSize; + rsrcfp->cf_blocks = recp->hfsPlusFile.resourceFork.totalBlocks; + if ((hfsmp->hfc_stage == HFC_RECORDING) && + (attrp->ca_atime >= hfsmp->hfc_timebase)) { + datafp->cf_bytesread = + recp->hfsPlusFile.resourceFork.clumpSize * + HFSTOVCB(hfsmp)->blockSize; + } else { + datafp->cf_bytesread = 0; + } + rsrcfp->cf_vblocks = 0; + bcopy(&recp->hfsPlusFile.resourceFork.extents[0], + &rsrcfp->cf_extents[0], sizeof(HFSPlusExtentRecord)); } } +__private_extern__ int cat_convertkey( struct hfsmount *hfsmp, @@ -181,6 +249,7 @@ /* * cat_releasedesc */ +__private_extern__ void cat_releasedesc(struct cat_desc *descp) { @@ -195,7 +264,7 @@ descp->cd_nameptr = NULL; descp->cd_namelen = 0; descp->cd_flags &= ~CD_HASBUF; - FREE(name, M_TEMP); + remove_name(name); } descp->cd_nameptr = NULL; descp->cd_namelen = 0; @@ -209,6 +278,7 @@ /* * cat_lookup - lookup a catalog node using a cnode decriptor */ +__private_extern__ int cat_lookup(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc, struct cat_desc *outdescp, struct cat_attr *attrp, @@ -243,6 +313,7 @@ return (result); } +__private_extern__ int cat_insertfilethread(struct hfsmount *hfsmp, struct cat_desc *descp) { @@ -264,11 +335,6 @@ if (result) goto exit; - // XXXdbg - preflight all btree operations to make sure there's enough space - result = BTCheckFreeSpace(fcb); - if (result) - goto exit; - BDINIT(file_data, &file_rec); result = BTSearchRecord(fcb, &iterator[0], &file_data, &datasize, &iterator[0]); if (result) @@ -306,6 +372,7 @@ /* * cat_idlookup - lookup a catalog node using a cnode id */ +__private_extern__ int cat_idlookup(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *outdescp, struct cat_attr *attrp, struct cat_fork *forkp) @@ -473,14 +540,41 @@ } } if (forkp != NULL) { - if (isadir(recp)) + if (isadir(recp)) { bzero(forkp, sizeof(*forkp)); - else if (std_hfs) + } else if (std_hfs) { promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, wantrsrc, forkp); - else if (wantrsrc) - bcopy(&recp->hfsPlusFile.resourceFork, forkp, sizeof(*forkp)); - else - bcopy(&recp->hfsPlusFile.dataFork, forkp, sizeof(*forkp)); + } else if (wantrsrc) { + /* Convert the resource fork. */ + forkp->cf_size = recp->hfsPlusFile.resourceFork.logicalSize; + forkp->cf_blocks = recp->hfsPlusFile.resourceFork.totalBlocks; + if ((hfsmp->hfc_stage == HFC_RECORDING) && + (to_bsd_time(recp->hfsPlusFile.accessDate) >= hfsmp->hfc_timebase)) { + forkp->cf_bytesread = + recp->hfsPlusFile.resourceFork.clumpSize * + HFSTOVCB(hfsmp)->blockSize; + } else { + forkp->cf_bytesread = 0; + } + forkp->cf_vblocks = 0; + bcopy(&recp->hfsPlusFile.resourceFork.extents[0], + &forkp->cf_extents[0], sizeof(HFSPlusExtentRecord)); + } else { + /* Convert the data fork. */ + forkp->cf_size = recp->hfsPlusFile.dataFork.logicalSize; + forkp->cf_blocks = recp->hfsPlusFile.dataFork.totalBlocks; + if ((hfsmp->hfc_stage == HFC_RECORDING) && + (to_bsd_time(recp->hfsPlusFile.accessDate) >= hfsmp->hfc_timebase)) { + forkp->cf_bytesread = + recp->hfsPlusFile.dataFork.clumpSize * + HFSTOVCB(hfsmp)->blockSize; + } else { + forkp->cf_bytesread = 0; + } + forkp->cf_vblocks = 0; + bcopy(&recp->hfsPlusFile.dataFork.extents[0], + &forkp->cf_extents[0], sizeof(HFSPlusExtentRecord)); + } } if (descp != NULL) { HFSPlusCatalogKey * pluskey = NULL; @@ -508,6 +602,7 @@ /* * cat_create - create a node in the catalog */ +__private_extern__ int cat_create(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp, struct cat_desc *out_descp) @@ -547,11 +642,6 @@ hfs_setencodingbits(hfsmp, encoding); } - // XXXdbg - preflight all btree operations to make sure there's enough space - result = BTCheckFreeSpace(fcb); - if (result) - goto exit; - /* * Insert the thread record first */ @@ -660,6 +750,7 @@ * 4. BTDeleteRecord(from_thread); * 5. BTInsertRecord(to_thread); */ +__private_extern__ int cat_rename ( struct hfsmount * hfsmp, @@ -700,11 +791,6 @@ if ((result = buildkey(hfsmp, to_cdp, (HFSPlusCatalogKey *)&to_iterator->key, 0))) goto exit; - // XXXdbg - preflight all btree operations to make sure there's enough space - result = BTCheckFreeSpace(fcb); - if (result) - goto exit; - to_key = (HFSPlusCatalogKey *)&to_iterator->key; MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK); BDINIT(btdata, recp); @@ -753,7 +839,7 @@ if (result) goto exit; - /* Update the text encoding (on disk and in descriptor */ + /* Update the text encoding (on disk and in descriptor) */ if (!std_hfs) { encoding = hfs_pickencoding(to_key->nodeName.unicode, to_key->nodeName.length); @@ -871,6 +957,14 @@ if (std_hfs) { MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK); promotekey(hfsmp, (HFSCatalogKey *)&to_iterator->key, pluskey, &encoding); + + /* Save the real encoding hint in the Finder Info (field 4). */ + if (directory && from_cdp->cd_cnid == kHFSRootFolderID) { + u_long realhint; + + realhint = hfs_pickencoding(pluskey->nodeName.unicode, pluskey->nodeName.length); + vcb->vcbFndrInfo[4] = SET_HFS_TEXT_ENCODING(realhint); + } } else pluskey = (HFSPlusCatalogKey *)&to_iterator->key; @@ -901,6 +995,7 @@ * 2. BTDeleteRecord(thread); * 3. BTUpdateRecord(parent); */ +__private_extern__ int cat_delete(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp) { @@ -945,11 +1040,6 @@ if (result) goto exit; - // XXXdbg - preflight all btree operations to make sure there's enough space - result = BTCheckFreeSpace(fcb); - if (result) - goto exit; - /* Delete record */ result = BTDeleteRecord(fcb, iterator); if (result) @@ -973,6 +1063,7 @@ * cnode_update - update the catalog node described by descp * using the data from attrp and forkp. */ +__private_extern__ int cat_update(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp, struct cat_fork *dataforkp, struct cat_fork *rsrcforkp) @@ -1217,6 +1308,9 @@ file->resourceFork.totalBlocks = forkp->cf_blocks; bcopy(&forkp->cf_extents[0], &file->resourceFork.extents, sizeof(HFSPlusExtentRecord)); + /* Push blocks read to disk */ + file->resourceFork.clumpSize = + howmany(forkp->cf_bytesread, blksize); } if (state->s_datafork) { forkp = state->s_datafork; @@ -1224,6 +1318,9 @@ file->dataFork.totalBlocks = forkp->cf_blocks; bcopy(&forkp->cf_extents[0], &file->dataFork.extents, sizeof(HFSPlusExtentRecord)); + /* Push blocks read to disk */ + file->resourceFork.clumpSize = + howmany(forkp->cf_bytesread, blksize); } if ((file->resourceFork.extents[0].startBlock != 0) && @@ -1295,7 +1392,7 @@ /* Hide the private meta data directory and journal files */ if (parentcnid == kRootDirID) { if ((rec->recordType == kHFSPlusFolderRecord) && - (rec->hfsPlusFolder.folderID == hfsmp->hfs_private_metadata_dir)) { + (rec->hfsPlusFolder.folderID == hfsmp->hfs_privdir_desc.cd_cnid)) { return (1); /* continue */ } if (hfsmp->jnl && @@ -1355,6 +1452,7 @@ /* * Note: index is zero relative */ +__private_extern__ int cat_getentriesattr(struct hfsmount *hfsmp, struct cat_desc *prevdesc, int index, struct cat_entrylist *ce_list) @@ -1463,6 +1561,10 @@ return MacToVFSError(result); } +struct linkinfo { + u_long link_ref; + void * dirent_addr; +}; struct read_state { u_int32_t cbs_parentID; @@ -1472,20 +1574,40 @@ off_t cbs_lastoffset; struct uio * cbs_uio; ExtendedVCB * cbs_vcb; - int16_t cbs_hfsPlus; + int8_t cbs_hfsPlus; + int8_t cbs_case_sensitive; int16_t cbs_result; + int32_t cbs_numresults; + u_long *cbs_cookies; + int32_t cbs_ncookies; + int32_t cbs_nlinks; + int32_t cbs_maxlinks; + struct linkinfo *cbs_linkinfo; +}; + +/* Map file mode type to directory entry types */ +u_char modetodirtype[16] = { + DT_REG, DT_FIFO, DT_CHR, DT_UNKNOWN, + DT_DIR, DT_UNKNOWN, DT_BLK, DT_UNKNOWN, + DT_REG, DT_UNKNOWN, DT_LNK, DT_UNKNOWN, + DT_SOCK, DT_UNKNOWN, DT_WHT, DT_UNKNOWN }; +#define MODE_TO_DT(mode) (modetodirtype[((mode) & S_IFMT) >> 12]) static int catrec_read(const CatalogKey *ckp, const CatalogRecord *crp, u_int16_t recordLen, struct read_state *state) { + struct hfsmount *hfsmp; CatalogName *cnp; size_t utf8chars; u_int32_t curID; OSErr result; struct dirent catent; + time_t itime; + u_long ilinkref = 0; + void * uiobase; if (state->cbs_hfsPlus) curID = ckp->hfsPlus.parentID; @@ -1529,7 +1651,18 @@ catent.d_fileno = crp->hfsPlusFolder.folderID; break; case kHFSPlusFileRecord: - catent.d_type = DT_REG; + itime = to_bsd_time(crp->hfsPlusFile.createDate); + hfsmp = VCBTOHFS(state->cbs_vcb); + /* + * When a hardlink link is encountered save its link ref. + */ + if ((SWAP_BE32(crp->hfsPlusFile.userInfo.fdType) == kHardLinkFileType) && + (SWAP_BE32(crp->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator) && + ((itime == state->cbs_vcb->vcbCrDate) || + (itime == hfsmp->hfs_metadata_createdate))) { + ilinkref = crp->hfsPlusFile.bsdInfo.special.iNodeNum; + } + catent.d_type = MODE_TO_DT(crp->hfsPlusFile.bsdInfo.fileMode); catent.d_fileno = crp->hfsPlusFile.fileID; break; default: @@ -1575,37 +1708,76 @@ /* hide our private meta data directory */ if (curID == kRootDirID && catent.d_fileno == state->cbs_hiddenDirID && - catent.d_type == DT_DIR) - goto lastitem; + catent.d_type == DT_DIR) { + if (state->cbs_case_sensitive) { + // This is how we skip over these entries. The next + // time we fill in a real item the uio_offset will + // point to the correct place in the "virtual" directory + // so that PositionIterator() will do the right thing + // when scanning to get to a particular position in the + // directory. + state->cbs_uio->uio_offset += catent.d_reclen; + state->cbs_lastoffset = state->cbs_uio->uio_offset; + return (1); /* skip and continue */ + } else + goto lastitem; + } + /* Hide the journal files */ if ((curID == kRootDirID) && (catent.d_type == DT_REG) && ((catent.d_fileno == state->cbs_hiddenJournalID) || (catent.d_fileno == state->cbs_hiddenInfoBlkID))) { + // see comment up above for why this is here + state->cbs_uio->uio_offset += catent.d_reclen; + state->cbs_lastoffset = state->cbs_uio->uio_offset; + return (1); /* skip and continue */ } state->cbs_lastoffset = state->cbs_uio->uio_offset; + uiobase = state->cbs_uio->uio_iov->iov_base; /* if this entry won't fit then we're done */ - if (catent.d_reclen > state->cbs_uio->uio_resid) + if (catent.d_reclen > state->cbs_uio->uio_resid || + (ilinkref != 0 && state->cbs_nlinks == state->cbs_maxlinks) || + (state->cbs_ncookies != 0 && state->cbs_numresults >= state->cbs_ncookies)) return (0); /* stop */ state->cbs_result = uiomove((caddr_t) &catent, catent.d_reclen, state->cbs_uio); + /* + * Record any hard links for post processing. + */ + if ((ilinkref != 0) && + (state->cbs_result == 0) && + (state->cbs_nlinks < state->cbs_maxlinks)) { + state->cbs_linkinfo[state->cbs_nlinks].dirent_addr = uiobase; + state->cbs_linkinfo[state->cbs_nlinks].link_ref = ilinkref; + state->cbs_nlinks++; + } + + if (state->cbs_cookies) { + state->cbs_cookies[state->cbs_numresults++] = state->cbs_uio->uio_offset; + } else { + state->cbs_numresults++; + } + /* continue iteration if there's room */ return (state->cbs_result == 0 && state->cbs_uio->uio_resid >= AVERAGE_HFSDIRENTRY_SIZE); } +#define SMALL_DIRENTRY_SIZE (sizeof(struct dirent) - (MAXNAMLEN + 1) + 8) /* * */ +__private_extern__ int -cat_getdirentries(struct hfsmount *hfsmp, struct cat_desc *descp, - struct uio *uio, int *eofflag) +cat_getdirentries(struct hfsmount *hfsmp, struct cat_desc *descp, int entrycnt, + struct uio *uio, int *eofflag, u_long *cookies, int ncookies) { ExtendedVCB *vcb = HFSTOVCB(hfsmp); BTreeIterator * iterator; @@ -1614,13 +1786,24 @@ u_int16_t op; struct read_state state; u_int32_t dirID = descp->cd_cnid; + void * buffer; + int bufsize; + int maxdirentries; int result; diroffset = uio->uio_offset; *eofflag = 0; + maxdirentries = MIN(entrycnt, uio->uio_resid / SMALL_DIRENTRY_SIZE); - MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); - bzero(iterator, sizeof(*iterator)); + /* Get a buffer for collecting link info and for a btree iterator */ + bufsize = (maxdirentries * sizeof(struct linkinfo)) + sizeof(*iterator); + MALLOC(buffer, void *, bufsize, M_TEMP, M_WAITOK); + bzero(buffer, bufsize); + + state.cbs_nlinks = 0; + state.cbs_maxlinks = maxdirentries; + state.cbs_linkinfo = (struct linkinfo *) buffer; + iterator = (BTreeIterator *) ((char *)buffer + (maxdirentries * sizeof(struct linkinfo))); /* get an iterator and position it */ cip = GetCatalogIterator(vcb, dirID, diroffset); @@ -1634,7 +1817,7 @@ } else if ((result = MacToVFSError(result))) goto cleanup; - state.cbs_hiddenDirID = hfsmp->hfs_private_metadata_dir; + state.cbs_hiddenDirID = hfsmp->hfs_privdir_desc.cd_cnid; if (hfsmp->jnl) { state.cbs_hiddenJournalID = hfsmp->hfs_jnlfileid; state.cbs_hiddenInfoBlkID = hfsmp->hfs_jnlinfoblkid; @@ -1645,16 +1828,58 @@ state.cbs_uio = uio; state.cbs_result = 0; state.cbs_parentID = dirID; + if (diroffset <= 2*sizeof(struct hfsdotentry)) { + state.cbs_numresults = diroffset/sizeof(struct hfsdotentry); + } else { + state.cbs_numresults = 0; + } + state.cbs_cookies = cookies; + state.cbs_ncookies = ncookies; if (vcb->vcbSigWord == kHFSPlusSigWord) state.cbs_hfsPlus = 1; else state.cbs_hfsPlus = 0; + if (hfsmp->hfs_flags & HFS_CASE_SENSITIVE) + state.cbs_case_sensitive = 1; + else + state.cbs_case_sensitive = 0; + /* process as many entries as possible... */ result = BTIterateRecords(GetFileControlBlock(vcb->catalogRefNum), op, iterator, (IterateCallBackProcPtr)catrec_read, &state); + /* + * Post process any hard links to get the real file id. + */ + if (state.cbs_nlinks > 0) { + struct iovec aiov; + struct uio auio; + u_int32_t fileid; + int i; + u_int32_t tempid; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_segflg = uio->uio_segflg; + auio.uio_rw = UIO_READ; /* read kernel memory into user memory */ + auio.uio_procp = uio->uio_procp; + + for (i = 0; i < state.cbs_nlinks; ++i) { + fileid = 0; + + if (resolvelinkid(hfsmp, state.cbs_linkinfo[i].link_ref, &fileid) != 0) + continue; + + /* Update the file id in the user's buffer */ + aiov.iov_base = (char *) state.cbs_linkinfo[i].dirent_addr; + aiov.iov_len = sizeof(fileid); + auio.uio_offset = 0; + auio.uio_resid = aiov.iov_len; + (void) uiomove((caddr_t)&fileid, sizeof(fileid), &auio); + } + } if (state.cbs_result) result = state.cbs_result; else @@ -1679,13 +1904,71 @@ } (void) ReleaseCatalogIterator(cip); - FREE(iterator, M_TEMP); + FREE(buffer, M_TEMP); return (result); } /* + * cat_binarykeycompare - compare two HFS Plus catalog keys. + + * The name portion of the key is comapred using a 16-bit binary comparison. + * This is called from the b-tree code. + */ +__private_extern__ +int +cat_binarykeycompare(HFSPlusCatalogKey *searchKey, HFSPlusCatalogKey *trialKey) +{ + u_int32_t searchParentID, trialParentID; + int result; + + searchParentID = searchKey->parentID; + trialParentID = trialKey->parentID; + result = 0; + + if (searchParentID > trialParentID) { + ++result; + } else if (searchParentID < trialParentID) { + --result; + } else { + u_int16_t * str1 = &searchKey->nodeName.unicode[0]; + u_int16_t * str2 = &trialKey->nodeName.unicode[0]; + int length1 = searchKey->nodeName.length; + int length2 = trialKey->nodeName.length; + u_int16_t c1, c2; + int length; + + if (length1 < length2) { + length = length1; + --result; + } else if (length1 > length2) { + length = length2; + ++result; + } else { + length = length1; + } + + while (length--) { + c1 = *(str1++); + c2 = *(str2++); + + if (c1 > c2) { + result = 1; + break; + } + if (c1 < c2) { + result = -1; + break; + } + } + } + + return result; +} + + +/* * buildkey - build a Catalog b-tree key from a cnode descriptor */ static int @@ -1766,7 +2049,7 @@ bzero(iterator, sizeof(*iterator)); /* Build a descriptor for private dir. */ - idesc.cd_parentcnid = hfsmp->hfs_private_metadata_dir; + idesc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid; idesc.cd_nameptr = inodename; idesc.cd_namelen = strlen(inodename); idesc.cd_flags = 0; @@ -1791,6 +2074,25 @@ } /* + * Resolve hard link reference to obtain the inode number. + */ +static int +resolvelinkid(struct hfsmount *hfsmp, u_long linkref, ino_t *ino) +{ + struct HFSPlusCatalogFile record; + int error; + + error = resolvelink(hfsmp, linkref, &record); + if (error == 0) { + if (record.fileID == 0) + error = ENOENT; + else + *ino = record.fileID; + } + return (error); +} + +/* * getkey - get a key from id by doing a thread lookup */ static int @@ -1947,10 +2249,15 @@ char * nameptr; long bufsize; size_t utf8len; + char tmpbuff[128]; /* guess a size... */ bufsize = (3 * key->nodeName.length) + 1; - MALLOC(nameptr, char *, bufsize, M_TEMP, M_WAITOK); + if (bufsize >= sizeof(tmpbuff)-1) { + MALLOC(nameptr, char *, bufsize, M_TEMP, M_WAITOK); + } else { + nameptr = &tmpbuff[0]; + } result = utf8_encodestr(key->nodeName.unicode, key->nodeName.length * sizeof(UniChar), @@ -1970,14 +2277,17 @@ bufsize, ':', 0); } descp->cd_parentcnid = key->parentID; - descp->cd_nameptr = nameptr; + descp->cd_nameptr = add_name(nameptr, utf8len, 0, 0); descp->cd_namelen = utf8len; descp->cd_cnid = cnid; descp->cd_hint = hint; descp->cd_flags = CD_DECOMPOSED | CD_HASBUF; if (isdir) - descp->cd_flags |= CD_ISDIR; + descp->cd_flags |= CD_ISDIR; descp->cd_encoding = encoding; + if (nameptr != &tmpbuff[0]) { + FREE(nameptr, M_TEMP); + } return result; } @@ -2115,6 +2425,8 @@ if (resource) { forkp->cf_size = filep->rsrcLogicalSize; forkp->cf_blocks = filep->rsrcPhysicalSize / blocksize; + forkp->cf_bytesread = 0; + forkp->cf_vblocks = 0; xp[0].startBlock = (u_int32_t)filep->rsrcExtents[0].startBlock; xp[0].blockCount = (u_int32_t)filep->rsrcExtents[0].blockCount; xp[1].startBlock = (u_int32_t)filep->rsrcExtents[1].startBlock; @@ -2124,6 +2436,8 @@ } else { forkp->cf_size = filep->dataLogicalSize; forkp->cf_blocks = filep->dataPhysicalSize / blocksize; + forkp->cf_bytesread = 0; + forkp->cf_vblocks = 0; xp[0].startBlock = (u_int32_t)filep->dataExtents[0].startBlock; xp[0].blockCount = (u_int32_t)filep->dataExtents[0].blockCount; xp[1].startBlock = (u_int32_t)filep->dataExtents[1].startBlock; diff -urN xnu-344.49/bsd/hfs/hfs_catalog.h xnu-517/bsd/hfs/hfs_catalog.h --- xnu-344.49/bsd/hfs/hfs_catalog.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_catalog.h Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -65,6 +65,7 @@ /* cd_flags */ #define CD_HASBUF 0x01 /* allocated filename buffer */ #define CD_DECOMPOSED 0x02 /* name is fully decomposed */ +#define CD_ISMETA 0x40 /* describes a metadata file */ #define CD_ISDIR 0x80 /* describes a directory */ /* @@ -95,15 +96,24 @@ #define ca_entries ca_union.cau_entries /* - * Catalog Node Fork (runtime + on disk) + * Catalog Node Fork (runtime) + * + * NOTE: this is not the same as a struct HFSPlusForkData */ struct cat_fork { - u_int64_t cf_size; /* fork's logical size in bytes */ - u_int32_t cf_clump; /* fork's clump size in bytes */ - u_int32_t cf_blocks; /* total blocks used by this fork */ - struct HFSPlusExtentDescriptor cf_extents[8]; /* initial set of extents */ + u_int64_t cf_size; /* fork's logical size in bytes */ + union { + u_int32_t cfu_clump; /* fork's clump size in bytes (sys files only) */ + u_int64_t cfu_bytesread; /* bytes read from this fork */ + } cf_union; + u_int32_t cf_vblocks; /* virtual (unalloated) blocks */ + u_int32_t cf_blocks; /* total blocks used by this fork */ + struct HFSPlusExtentDescriptor cf_extents[8]; /* initial set of extents */ }; +#define cf_clump cf_union.cfu_clump +#define cf_bytesread cf_union.cfu_bytesread + /* * Catalog Node Entry @@ -132,6 +142,28 @@ }; /* + * Catalog Operations Hint + * + * lower 16 bits: count of B-tree insert operations + * upper 16 bits: count of B-tree delete operations + * + */ +#define CAT_DELETE 0x00020000 +#define CAT_CREATE 0x00000002 +#define CAT_RENAME 0x00020002 +#define CAT_EXCHANGE 0x00020002 + +typedef u_int32_t catops_t; + +/* + * The size of cat_cookie_t much match the size of + * the nreserve struct (in BTreeNodeReserve.c). + */ +typedef struct cat_cookie_t { + char opaque[24]; +} cat_cookie_t; + +/* * Catalog Interface * * These functions perform a catalog transactions. The @@ -186,12 +218,30 @@ extern int cat_getdirentries( struct hfsmount *hfsmp, struct cat_desc *descp, + int entrycnt, struct uio *uio, - int *eofflag); + int *eofflag, + u_long *cookies, + int ncookies); extern int cat_insertfilethread ( struct hfsmount *hfsmp, struct cat_desc *descp); + +extern int cat_preflight( + struct hfsmount *hfsmp, + catops_t ops, + cat_cookie_t *cookie, + struct proc *p); + +extern void cat_postflight( + struct hfsmount *hfsmp, + cat_cookie_t *cookie, + struct proc *p); + +extern int cat_binarykeycompare( + HFSPlusCatalogKey *searchKey, + HFSPlusCatalogKey *trialKey); #endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ diff -urN xnu-344.49/bsd/hfs/hfs_chash.c xnu-517/bsd/hfs/hfs_chash.c --- xnu-344.49/bsd/hfs/hfs_chash.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_chash.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -140,7 +140,7 @@ (void)tsleep((caddr_t)cp, PINOD, "hfs_chashget-2", 0); goto loop; } - if (cp->c_flag & C_NOEXISTS) + if (cp->c_flag & (C_NOEXISTS | C_DELETED)) continue; /* @@ -177,7 +177,7 @@ */ if (wantrsrc && *rvpp == NULL && cp->c_rsrc_vp) { error = vget(cp->c_rsrc_vp, 0, p); - vput(*vpp); /* ref no longer needed */ + vrele(*vpp); /* ref no longer needed */ *vpp = NULL; if (error) goto loop; @@ -185,7 +185,7 @@ } else if (!wantrsrc && *vpp == NULL && cp->c_vp) { error = vget(cp->c_vp, 0, p); - vput(*rvpp); /* ref no longer needed */ + vrele(*rvpp); /* ref no longer needed */ *rvpp = NULL; if (error) goto loop; @@ -205,11 +205,11 @@ void hfs_chashinsert(struct cnode *cp) { - if (cp->c_fileid == 0) - panic("hfs_chashinsert: trying to insert file id 0"); - simple_lock(&hfs_chash_slock); - LIST_INSERT_HEAD(CNODEHASH(cp->c_dev, cp->c_fileid), cp, c_hash); - simple_unlock(&hfs_chash_slock); + if (cp->c_fileid != 0) { + simple_lock(&hfs_chash_slock); + LIST_INSERT_HEAD(CNODEHASH(cp->c_dev, cp->c_fileid), cp, c_hash); + simple_unlock(&hfs_chash_slock); + } } diff -urN xnu-344.49/bsd/hfs/hfs_cnode.c xnu-517/bsd/hfs/hfs_cnode.c --- xnu-344.49/bsd/hfs/hfs_cnode.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_cnode.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -66,6 +66,8 @@ int forkcount = 0; int truncated = 0; int started_tr = 0, grabbed_lock = 0; + cat_cookie_t cookie; + int cat_reserve = 0; if (prtactive && vp->v_usecount != 0) vprint("hfs_inactive: pushing active", vp); @@ -76,7 +78,7 @@ if (cp->c_mode == 0) goto out; - if (vp->v_mount->mnt_flag & MNT_RDONLY) + if (hfsmp->hfs_flags & HFS_READ_ONLY) goto out; if (cp->c_datafork) @@ -85,15 +87,14 @@ ++forkcount; /* If needed, get rid of any fork's data for a deleted file */ - if ((cp->c_flag & C_DELETED) && - vp->v_type == VREG && - (VTOF(vp)->ff_blocks != 0)) { - error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p); - truncated = 1; - // have to do this to prevent the lost ubc_info panic - SET(cp->c_flag, C_TRANSIT); + if ((vp->v_type == VREG) && (cp->c_flag & C_DELETED)) { + if (VTOF(vp)->ff_blocks != 0) { + error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p); + if (error) + goto out; + truncated = 1; + } recycle = 1; - if (error) goto out; } /* @@ -102,13 +103,13 @@ */ if ((cp->c_flag & C_DELETED) && (forkcount <= 1)) { /* - * Mark cnode in transit so that one can get this + * Mark cnode in transit so that no one can get this * cnode from cnode hash. */ SET(cp->c_flag, C_TRANSIT); cp->c_flag &= ~C_DELETED; cp->c_rdev = 0; - + // XXXdbg hfs_global_shared_lock_acquire(hfsmp); grabbed_lock = 1; @@ -120,6 +121,15 @@ started_tr = 1; } + /* + * Reserve some space in the Catalog file. + */ + if ((error = cat_preflight(hfsmp, CAT_DELETE, &cookie, p))) { + goto out; + } + cat_reserve = 1; + + /* Lock catalog b-tree */ error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); if (error) goto out; @@ -158,18 +168,20 @@ hfs_volupdate(hfsmp, VOL_RMFILE, 0); } - /* Push any defered access times to disk */ - if (cp->c_flag & C_ATIMEMOD) { - cp->c_flag &= ~C_ATIMEMOD; - if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) - cp->c_flag |= C_MODIFIED; - } - if (cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) { tv = time; + // if the only thing being updated is the access time + // then set the modified bit too so that update will + // flush it to disk. otherwise it'll get dropped. + if ((cp->c_flag & C_CHANGEMASK) == C_ACCESS) { + cp->c_flag |= C_MODIFIED; + } VOP_UPDATE(vp, &tv, &tv, 0); } out: + if (cat_reserve) + cat_postflight(hfsmp, &cookie, p); + // XXXdbg - have to do this because a goto could have come here if (started_tr) { journal_end_transaction(hfsmp->jnl); @@ -211,7 +223,12 @@ if (prtactive && vp->v_usecount != 0) vprint("hfs_reclaim(): pushing active", vp); - devvp = cp->c_devvp; /* For later releasing */ + /* + * Keep track of an inactive hot file. + */ + (void) hfs_addhotfile(vp); + + devvp = cp->c_devvp; /* For later releasing */ /* * Find file fork for this vnode (if any) @@ -224,6 +241,9 @@ } else if ((fp = cp->c_rsrcfork) && (cp->c_rsrc_vp == vp)) { cp->c_rsrcfork = NULL; cp->c_rsrc_vp = NULL; + if (VPARENT(vp) == cp->c_vp) { + cp->c_flag &= ~C_VPREFHELD; + } altfp = cp->c_datafork; } else { cp->c_vp = NULL; @@ -288,7 +308,7 @@ cp->c_desc.cd_nameptr = 0; cp->c_desc.cd_flags &= ~CD_HASBUF; cp->c_desc.cd_namelen = 0; - FREE(nameptr, M_TEMP); + remove_name(nameptr); } CLR(cp->c_flag, (C_ALLOC | C_TRANSIT)); if (ISSET(cp->c_flag, C_WALLOC) || ISSET(cp->c_flag, C_WTRANSIT)) @@ -333,8 +353,8 @@ cp = hfs_chashget(dev, cnid, wantrsrc, &vp, &rvp); if (cp != NULL) { /* hide open files that have been deleted */ - if ((hfsmp->hfs_private_metadata_dir != 0) - && (cp->c_parentcnid == hfsmp->hfs_private_metadata_dir) + if ((hfsmp->hfs_privdir_desc.cd_cnid != 0) + && (cp->c_parentcnid == hfsmp->hfs_privdir_desc.cd_cnid) && (cp->c_nlink == 0)) { retval = ENOENT; goto exit; @@ -393,6 +413,7 @@ cnattr.ca_fileid = kRootParID; cnattr.ca_nlink = 2; + cnattr.ca_entries = 1; cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); } else { /* Lock catalog b-tree */ @@ -408,8 +429,9 @@ goto exit; /* Hide open files that have been deleted */ - if ((hfsmp->hfs_private_metadata_dir != 0) && - (cndesc.cd_parentcnid == hfsmp->hfs_private_metadata_dir)) { + if ((hfsmp->hfs_privdir_desc.cd_cnid != 0) && + (cndesc.cd_parentcnid == hfsmp->hfs_privdir_desc.cd_cnid) && + (cnattr.ca_nlink == 0)) { cat_releasedesc(&cndesc); retval = ENOENT; goto exit; @@ -426,14 +448,16 @@ && cndesc.cd_namelen > 0) { replace_desc(VTOC(new_vp), &cndesc); } + cat_releasedesc(&cndesc); } + exit: /* Release reference taken on opposite vnode (if any). */ if (vp) - vput(vp); + vrele(vp); else if (rvp) - vput(rvp); + vrele(rvp); if (retval) { *vpp = NULL; @@ -445,7 +469,8 @@ if (vp == NULL) panic("hfs_getcnode: missing vp!"); - UBCINFOCHECK("hfs_getcnode", vp); + if (UBCISVALID(vp)) + UBCINFOCHECK("hfs_getcnode", vp); *vpp = vp; return (0); } @@ -478,12 +503,13 @@ int retval; dev_t dev; struct proc *p = current_proc(); - +#if 0 /* Bail when unmount is in progress */ if (mp->mnt_kern_flag & MNTK_UNMOUNT) { *vpp = NULL; return (EPERM); } +#endif #if !FIFO if (IFTOVT(attrp->ca_mode) == VFIFO) { @@ -502,6 +528,11 @@ SET(cp2->c_flag, C_ALLOC); cp2->c_cnid = descp->cd_cnid; cp2->c_fileid = attrp->ca_fileid; + if (cp2->c_fileid == 0) { + FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE); + *vpp = NULL; + return (ENOENT); + } cp2->c_dev = dev; lockinit(&cp2->c_lock, PINOD, "cnode", 0, 0); (void) lockmgr(&cp2->c_lock, LK_EXCLUSIVE, (struct slock *)0, p); @@ -560,9 +591,9 @@ /* Release reference taken on opposite vnode (if any). */ if (rvp) - vput(rvp); + vrele(rvp); if (vp) - vput(vp); + vrele(vp); vp = new_vp; vp->v_ubcinfo = UBC_NOINFO; @@ -604,9 +635,7 @@ bzero(fp, sizeof(struct filefork)); fp->ff_cp = cp; if (forkp) - bcopy(forkp, &fp->ff_data, sizeof(HFSPlusForkData)); - if (fp->ff_clumpsize == 0) - fp->ff_clumpsize = HFSTOVCB(hfsmp)->vcbClpSiz; + bcopy(forkp, &fp->ff_data, sizeof(struct cat_fork)); rl_init(&fp->ff_invalidranges); if (wantrsrc) { if (cp->c_rsrcfork != NULL) @@ -632,7 +661,7 @@ vp->v_type = IFTOVT(cp->c_mode); /* Tag system files */ - if ((descp->cd_cnid < kHFSFirstUserCatalogNodeID) && (vp->v_type == VREG)) + if ((descp->cd_flags & CD_ISMETA) && (vp->v_type == VREG)) vp->v_flag |= VSYSTEM; /* Tag root directory */ if (cp->c_cnid == kRootDirID) @@ -672,6 +701,11 @@ vp->v_op = hfs_fifoop_p; #endif } + + /* + * Stop tracking an active hot file. + */ + (void) hfs_removehotfile(vp); /* Vnode is now initialized - see if anyone was waiting for it. */ CLR(cp->c_flag, C_ALLOC); diff -urN xnu-344.49/bsd/hfs/hfs_cnode.h xnu-517/bsd/hfs/hfs_cnode.h --- xnu-344.49/bsd/hfs/hfs_cnode.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_cnode.h Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -47,27 +47,30 @@ struct filefork { struct cnode *ff_cp; /* cnode associated with this fork */ struct rl_head ff_invalidranges; /* Areas of disk that should read back as zeroes */ + long ff_evtonly_refs; /* number of vnode references used solely for events (O_EVTONLY) */ union { struct hfslockf *ffu_lockf; /* Head of byte-level lock list. */ void *ffu_sysdata; /* private data for system files */ char *ffu_symlinkptr; /* symbolic link pathname */ } ff_un; struct cat_fork ff_data; - u_int32_t ff_unallocblocks; /* unallocated blocks (until cmap) */ }; +typedef struct filefork filefork_t; /* Aliases for common fields */ #define ff_size ff_data.cf_size #define ff_clumpsize ff_data.cf_clump +#define ff_bytesread ff_data.cf_bytesread #define ff_blocks ff_data.cf_blocks #define ff_extents ff_data.cf_extents +#define ff_unallocblocks ff_data.cf_vblocks + #define ff_symlinkptr ff_un.ffu_symlinkptr #define ff_lockf ff_un.ffu_lockf /* The btree code still needs these... */ #define fcbEOF ff_size -#define fcbClmpSize ff_clumpsize #define fcbExtents ff_extents #define fcbBTCBPtr ff_un.ffu_sysdata @@ -97,13 +100,16 @@ struct vnode *c_devvp; /* vnode for block I/O */ dev_t c_dev; /* cnode's device */ struct dquot *c_dquot[MAXQUOTAS]; /* cnode's quota info */ + struct klist c_knotes; /* knotes attached to this vnode */ cnid_t c_childhint; /* catalog hint for children */ struct cat_desc c_desc; /* cnode's descriptor */ struct cat_attr c_attr; /* cnode's attributes */ SLIST_HEAD(hfs_indexhead, hfs_index) c_indexlist; /* directory index list */ + long c_evtonly_refs; /* number of vnode references used solely for events (O_EVTONLY) */ struct filefork *c_datafork; /* cnode's data fork */ struct filefork *c_rsrcfork; /* cnode's rsrc fork */ }; +typedef struct cnode cnode_t; /* Aliases for common cnode fields */ #define c_cnid c_desc.cd_cnid @@ -131,23 +137,28 @@ /* Runtime cnode flags (kept in c_flag) */ -#define C_ACCESS 0x0001 /* Access time update request */ -#define C_CHANGE 0x0002 /* Change time update request */ -#define C_UPDATE 0x0004 /* Modification time update request */ -#define C_MODIFIED 0x0008 /* CNode has been modified */ -#define C_ATIMEMOD 0x0010 /* Access time has been modified */ - -#define C_NOEXISTS 0x0020 /* CNode has been deleted, catalog entry is gone */ -#define C_DELETED 0x0040 /* CNode has been marked to be deleted */ -#define C_HARDLINK 0x0080 /* CNode is a hard link */ - -#define C_ALLOC 0x0100 /* CNode is being allocated */ -#define C_WALLOC 0x0200 /* Waiting for allocation to finish */ -#define C_TRANSIT 0x0400 /* CNode is getting recycled */ -#define C_WTRANSIT 0x0800 /* Waiting for cnode getting recycled */ +#define C_ACCESS 0x00001 /* Access time update request */ +#define C_CHANGE 0x00002 /* Change time update request */ +#define C_UPDATE 0x00004 /* Modification time update request */ +#define C_MODIFIED 0x00008 /* CNode has been modified */ + +#define C_RELOCATING 0x00010 /* CNode's fork is being relocated */ +#define C_NOEXISTS 0x00020 /* CNode has been deleted, catalog entry is gone */ +#define C_DELETED 0x00040 /* CNode has been marked to be deleted */ +#define C_HARDLINK 0x00080 /* CNode is a hard link */ + +#define C_ALLOC 0x00100 /* CNode is being allocated */ +#define C_WALLOC 0x00200 /* Waiting for allocation to finish */ +#define C_TRANSIT 0x00400 /* CNode is getting recycled */ +#define C_WTRANSIT 0x00800 /* Waiting for cnode getting recycled */ +#define C_NOBLKMAP 0x01000 /* CNode blocks cannot be mapped */ +#define C_WBLKMAP 0x02000 /* Waiting for block map */ + +#define C_ZFWANTSYNC 0x04000 /* fsync requested and file has holes */ +#define C_VPREFHELD 0x08000 /* resource fork has done a vget() on c_vp (for its parent ptr) */ -#define C_RENAME 0x1000 /* CNode is being renamed */ -#define C_ZFWANTSYNC 0x2000 /* fsync requested and file has holes */ +#define C_FROMSYNC 0x10000 /* fsync was called from sync */ +#define C_FORCEUPDATE 0x20000 /* force the catalog entry update */ #define ZFTIMELIMIT (5 * 60) @@ -176,6 +187,8 @@ FTOC(fp)->c_rsrc_vp : \ FTOC(fp)->c_vp) +#define EVTONLYREFS(vp) ((vp->v_type == VREG) ? VTOF(vp)->ff_evtonly_refs : VTOC(vp)->c_evtonly_refs) + /* * Test for a resource fork */ @@ -189,23 +202,18 @@ */ #define C_TIMEMASK (C_ACCESS | C_CHANGE | C_UPDATE) -#define ATIME_ACCURACY 60 +#define C_CHANGEMASK (C_ACCESS | C_CHANGE | C_UPDATE | C_MODIFIED) + +#define ATIME_ACCURACY 1 +#define ATIME_ONDISK_ACCURACY 300 #define CTIMES(cp, t1, t2) { \ if ((cp)->c_flag & C_TIMEMASK) { \ /* \ - * If only the access time is changing then defer \ - * updating it on-disk util later (in hfs_inactive). \ - * If it was recently updated then skip the update. \ + * Only do the update if it is more than just \ + * the C_ACCESS field being updated. \ */ \ - if (((cp)->c_flag & (C_TIMEMASK | C_MODIFIED)) == C_ACCESS) { \ - if (((cp)->c_flag & C_ATIMEMOD) || \ - (t1)->tv_sec > ((cp)->c_atime + ATIME_ACCURACY)) { \ - (cp)->c_atime = (t1)->tv_sec; \ - (cp)->c_flag |= C_ATIMEMOD; \ - } \ - (cp)->c_flag &= ~C_ACCESS; \ - } else { \ + if (((cp)->c_flag & C_CHANGEMASK) != C_ACCESS) { \ if ((cp)->c_flag & C_ACCESS) { \ (cp)->c_atime = (t1)->tv_sec; \ } \ diff -urN xnu-344.49/bsd/hfs/hfs_encodinghint.c xnu-517/bsd/hfs/hfs_encodinghint.c --- xnu-344.49/bsd/hfs/hfs_encodinghint.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_encodinghint.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2001-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,16 +34,16 @@ #define CJK_CHINESE_SIMP 0x8 #define CJK_ALL 0xF -#define CJK_CHINESE (CJK_CHINESE_TRAD | CJK_CHINESE_SIMP) -#define CJK_KATAKANA (CJK_JAPAN | CJK_CHINESE_SIMP | CJK_KOREAN) +#define CJK_CHINESE (CJK_CHINESE_TRAD | CJK_CHINESE_SIMP) +#define CJK_KATAKANA (CJK_JAPAN) /* Remember the last unique CJK bit */ u_int8_t cjk_lastunique = 0; -/* CJK encoding bias */ +/* Encoding bias */ u_int32_t hfs_encodingbias = 0; - +int hfs_islatinbias = 0; /* Map CJK bits to Mac encoding */ u_int8_t cjk_encoding[] = { @@ -793,6 +793,14 @@ cjkstate = CJK_ALL; continue; } + if (hfs_islatinbias && ch >= 0x0300 && ch <= 0x0329) { + guess = hfs_encodingbias; + continue; + } + if (ch <= 0x03CE && ch >= 0x0384) { + guess = kTextEncodingMacGreek; + continue; + } if (ch <= 0x0491 && ch >= 0x0401) { guess = kTextEncodingMacCyrillic; continue; @@ -806,6 +814,35 @@ if (ch >= 0x0E00 && ch <= 0x0E5B) { return kTextEncodingMacThai; } + /* Catch a few Shift-JIS strays */ + if (guess == 0 || guess == kTextEncodingMacUnicode) { + if (ch == 0x2010 || ch == 0x2014 || ch == 0x2015 || ch == 0x2016) { + guess = kTextEncodingMacJapanese; + if ((cjkstate == 0) || (cjkstate & CJK_JAPAN)) + cjkstate = CJK_JAPAN; + else + cjkstate |= CJK_JAPAN; + continue; + } + if ((hfs_encodingbias == kTextEncodingMacJapanese) && + (ch == 0x00A2 || ch == 0x00A3 || ch == 0x00AC)) { + guess = kTextEncodingMacJapanese; + continue; + } + /* TM char depends on the Mac encoding used. */ + if (ch == 0x2122) { + switch(hfs_encodingbias) { + case kTextEncodingMacJapanese: + case kTextEncodingMacChineseTrad: + case kTextEncodingMacKorean: + case kTextEncodingMacGreek: + case kTextEncodingMacThai: + case kTextEncodingMacChineseSimp: + guess = hfs_encodingbias; + break; + } + } + } if (guess == 0 && ch > 0x2122) { guess = kTextEncodingMacUnicode; } @@ -852,4 +889,33 @@ return guess; } + +__private_extern__ +u_int32_t +hfs_getencodingbias() +{ + return (hfs_encodingbias); +} + + +__private_extern__ +void +hfs_setencodingbias(u_int32_t bias) +{ + hfs_encodingbias = bias; + + switch (bias) { + case kTextEncodingMacRoman: + case kTextEncodingMacCentralEurRoman: + case kTextEncodingMacTurkish: + case kTextEncodingMacCroatian: + case kTextEncodingMacIcelandic: + case kTextEncodingMacRomanian: + hfs_islatinbias = 1; + break; + default: + hfs_islatinbias = 0; + break; + } +} diff -urN xnu-344.49/bsd/hfs/hfs_encodings.c xnu-517/bsd/hfs/hfs_encodings.c --- xnu-344.49/bsd/hfs/hfs_encodings.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_encodings.c Sat Oct 25 00:25:25 2003 @@ -55,7 +55,7 @@ #define MAX_HFS_UNICODE_CHARS (15*5) -int mac_roman_to_unicode(Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *usedCharLen); +int mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *usedCharLen); static int unicode_to_mac_roman(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs_str); @@ -202,7 +202,7 @@ encp = NULL; simple_unlock(&hfs_encoding_list_slock); - kmod_destroy(host_priv_self(), id); + kmod_destroy((host_priv_t) host_priv_self(), id); simple_lock(&hfs_encoding_list_slock); } break; @@ -614,7 +614,7 @@ * Unicode output is fully decomposed */ int -mac_roman_to_unicode(Str31 hfs_str, UniChar *uni_str, +mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *unicodeChars) { const UInt8 *p; diff -urN xnu-344.49/bsd/hfs/hfs_encodings.h xnu-517/bsd/hfs/hfs_encodings.h --- xnu-344.49/bsd/hfs/hfs_encodings.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_encodings.h Sat Oct 25 00:25:25 2003 @@ -32,10 +32,6 @@ #include #ifdef __APPLE_API_UNSTABLE -/* - * Sysctl value for HFS Unicode encoding matching. - */ -#define HFS_ENCODINGBIAS 1 /* encoding matching CJK bias */ #define CTL_HFS_NAMES { \ { 0, 0 }, \ @@ -55,7 +51,7 @@ * encoding conversion routines. */ -typedef int (* hfs_to_unicode_func_t)(Str31 hfs_str, UniChar *uni_str, +typedef int (* hfs_to_unicode_func_t)(const Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *usedCharLen); typedef int (* unicode_to_hfs_func_t)(UniChar *uni_str, UInt32 unicodeChars, diff -urN xnu-344.49/bsd/hfs/hfs_endian.c xnu-517/bsd/hfs/hfs_endian.c --- xnu-344.49/bsd/hfs/hfs_endian.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_endian.c Sat Oct 25 00:25:25 2003 @@ -358,9 +358,31 @@ if (unswap) srcPtr[0] = SWAP_BE16 (srcPtr[0]); } + } else if (fileID > kHFSFirstUserCatalogNodeID) { + HotFileKey *srcKey; + UInt32 *srcRec; + + for (i = 0; i < srcDesc->numRecords; i++) { + srcKey = (HotFileKey *)((char *)src->buffer + srcOffs[i]); + + if (!unswap) + srcKey->keyLength = SWAP_BE16 (srcKey->keyLength); + srcRec = (u_int32_t *)((char *)srcKey + srcKey->keyLength + 2); + if (unswap) + srcKey->keyLength = SWAP_BE16 (srcKey->keyLength); + + /* Don't swap srcKey->forkType */ + /* Don't swap srcKey->pad */ + + srcKey->temperature = SWAP_BE32 (srcKey->temperature); + srcKey->fileID = SWAP_BE32 (srcKey->fileID); + + *((UInt32 *)srcRec) = SWAP_BE32 (*((UInt32 *)srcRec)); + } } else { panic ("%s unrecognized B-Tree type", "hfs_swap_BTNode:"); } + return (0); } diff -urN xnu-344.49/bsd/hfs/hfs_endian.h xnu-517/bsd/hfs/hfs_endian.h --- xnu-344.49/bsd/hfs/hfs_endian.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_endian.h Sat Oct 25 00:25:25 2003 @@ -51,7 +51,7 @@ /* HFS is always big endian, no swapping needed */ #define SWAP_HFS_PLUS_FORK_DATA(__a) - #define SWAP_BT_NODE(__a, __b, __c) + #define SWAP_BT_NODE(__a, __b, __c, __d) /************************/ /* LITTLE ENDIAN Macros */ diff -urN xnu-344.49/bsd/hfs/hfs_format.h xnu-517/bsd/hfs/hfs_format.h --- xnu-344.49/bsd/hfs/hfs_format.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_format.h Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,6 +25,9 @@ #ifndef __HFS_FORMAT__ #define __HFS_FORMAT__ +#ifndef __HFSVOLUMES__ + +#include #include /* @@ -48,9 +51,11 @@ enum { kHFSSigWord = 0x4244, /* 'BD' in ASCII */ kHFSPlusSigWord = 0x482B, /* 'H+' in ASCII */ - kHFSJSigWord = 0x484a, /* 'HJ' in ASCII */ - kHFSPlusVersion = 0x0004, /* will change as format changes */ - /* version 4 shipped with Mac OS 8.1 */ + kHFSXSigWord = 0x4858, /* 'HX' in ASCII */ + + kHFSPlusVersion = 0x0004, /* 'H+' volumes are version 4 only */ + kHFSXVersion = 0x0005, /* 'HX' volumes start with version 5 */ + kHFSPlusMountVersion = 0x31302E30, /* '10.0' for Mac OS X */ kHFSJMountVersion = 0x4846534a /* 'HFSJ' for journaled HFS+ on OS X */ }; @@ -89,6 +94,7 @@ }; +#ifndef __FILES__ /* Unicode strings are used for HFS Plus file and folder names */ struct HFSUniStr255 { u_int16_t length; /* number of unicode characters */ @@ -96,6 +102,7 @@ }; typedef struct HFSUniStr255 HFSUniStr255; typedef const HFSUniStr255 *ConstHFSUniStr255Param; +#endif /* __FILES__ */ enum { kHFSMaxVolumeNameChars = 27, @@ -228,6 +235,7 @@ kHFSAllocationFileID = 6, /* File ID of the allocation file (HFS Plus only) */ kHFSStartupFileID = 7, /* File ID of the startup file (HFS Plus only) */ kHFSAttributesFileID = 8, /* File ID of the attribute file (HFS Plus only) */ + kHFSRepairCatalogFileID = 14, /* Used when rebuilding Catalog B-tree */ kHFSBogusExtentFileID = 15, /* Used for exchanging extents in extents file */ kHFSFirstUserCatalogNodeID = 16 }; @@ -458,7 +466,7 @@ kHFSBootVolumeInconsistentBit = 11, /* boot volume is inconsistent (System 7.6 and later) */ kHFSCatalogNodeIDsReusedBit = 12, kHFSVolumeJournaledBit = 13, /* this volume has a journal on it */ - /* Bit 14 is reserved for future use */ + kHFSVolumeInconsistentBit = 14, /* serious inconsistencies detected at runtime */ kHFSVolumeSoftwareLockBit = 15, /* volume is locked by software */ kHFSVolumeHardwareLockMask = 1 << kHFSVolumeHardwareLockBit, @@ -468,6 +476,7 @@ kHFSBootVolumeInconsistentMask = 1 << kHFSBootVolumeInconsistentBit, kHFSCatalogNodeIDsReusedMask = 1 << kHFSCatalogNodeIDsReusedBit, kHFSVolumeJournaledMask = 1 << kHFSVolumeJournaledBit, + kHFSVolumeInconsistentMask = 1 << kHFSVolumeInconsistentBit, kHFSVolumeSoftwareLockMask = 1 << kHFSVolumeSoftwareLockBit, kHFSMDBAttributesMask = 0x8380 }; @@ -509,6 +518,14 @@ typedef struct HFSMasterDirectoryBlock HFSMasterDirectoryBlock; +#ifdef __APPLE_API_UNSTABLE +#define SET_HFS_TEXT_ENCODING(hint) \ + (0x656e6300 | ((hint) & 0xff)) +#define GET_HFS_TEXT_ENCODING(hint) \ + (((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU) +#endif /* __APPLE_API_UNSTABLE */ + + /* HFS Plus Volume Header - 512 bytes */ /* Stored at sector #2 (3rd sector) and second-to-last sector. */ struct HFSPlusVolumeHeader { @@ -516,7 +533,6 @@ u_int16_t version; /* == kHFSPlusVersion */ u_int32_t attributes; /* volume attributes */ u_int32_t lastMountedVersion; /* implementation version which last mounted volume */ -//XXXdbg u_int32_t reserved; /* reserved - initialized as zero */ u_int32_t journalInfoBlock; /* block addr of journal info (if volume is journaled, zero otherwise) */ u_int32_t createDate; /* date and time of volume creation */ @@ -596,7 +612,7 @@ u_int16_t reserved1; /* unused */ u_int32_t clumpSize; /* reserved */ u_int8_t btreeType; /* reserved */ - u_int8_t reserved2; /* reserved */ + u_int8_t keyCompareType; /* Key string Comparison Type */ u_int32_t attributes; /* persistent attributes about the tree */ u_int32_t reserved3[16]; /* reserved */ }; @@ -609,6 +625,13 @@ kBTVariableIndexKeysMask = 0x00000004 /* keys in index nodes are variable length */ }; + +/* Catalog Key Name Comparison Type */ +enum { + kHFSCaseFolding = 0xCF, /* case folding (case-insensitive) */ + kHFSBinaryCompare = 0xBC, /* binary compare (case-sensitive) */ +}; + /* JournalInfoBlock - Structure that describes where our journal lives */ struct JournalInfoBlock { u_int32_t flags; @@ -631,5 +654,9 @@ #ifdef __cplusplus } #endif + +#else +#warning hfs_format.h is not compatible with HFSVolumes.h (include only one) +#endif /* __HFSVOLUMES__ */ #endif /* __HFS_FORMAT__ */ diff -urN xnu-344.49/bsd/hfs/hfs_hotfiles.c xnu-517/bsd/hfs/hfs_hotfiles.c --- xnu-344.49/bsd/hfs/hfs_hotfiles.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/hfs/hfs_hotfiles.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,2156 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "hfscommon/headers/BTreeScanner.h" + + +#define HFC_DEBUG 0 +#define HFC_VERBOSE 0 + + + +/* + * Hot File List (runtime). + */ +typedef struct hotfileinfo { + u_int32_t hf_fileid; + u_int32_t hf_temperature; + u_int32_t hf_blocks; +} hotfileinfo_t; + +typedef struct hotfilelist { + u_int32_t hfl_magic; + u_int32_t hfl_version; + time_t hfl_duration; /* duration of sample period */ + int hfl_count; /* count of hot files recorded */ + int hfl_next; /* next file to move */ + int hfl_totalblocks; /* total hot file blocks */ + int hfl_reclaimblks; /* blocks to reclaim in HFV */ + u_int32_t hfl_spare[2]; + hotfileinfo_t hfl_hotfile[1]; /* array of hot files */ +} hotfilelist_t; + + +/* + * Hot File Entry (runtime). + */ +typedef struct hotfile_entry { + struct hotfile_entry *left; + struct hotfile_entry *right; + u_int32_t fileid; + u_int32_t temperature; + u_int32_t blocks; +} hotfile_entry_t; + +/* + * Hot File Recording Data (runtime). + */ +typedef struct hotfile_data { + struct hfsmount *hfsmp; + long refcount; + int activefiles; /* active number of hot files */ + u_int32_t threshold; + u_int32_t maxblocks; + hotfile_entry_t *rootentry; + hotfile_entry_t *freelist; + hotfile_entry_t *coldest; + hotfile_entry_t entries[1]; +} hotfile_data_t; + + + +/* + * Hot File Data recording functions (in-memory binary tree). + */ +static void hf_insert (hotfile_data_t *, hotfile_entry_t *); +static void hf_delete (hotfile_data_t *, u_int32_t, u_int32_t); +static hotfile_entry_t * hf_lookup (hotfile_data_t *, u_int32_t, u_int32_t); +static hotfile_entry_t * hf_coldest (hotfile_data_t *); +static hotfile_entry_t * hf_getnewentry (hotfile_data_t *); +static int hf_getsortedlist (hotfile_data_t *, hotfilelist_t *); +static void hf_printtree (hotfile_entry_t *); + +/* + * Hot File misc support functions. + */ +static int hotfiles_collect (struct hfsmount *, struct proc *); +static int hotfiles_age (struct hfsmount *, struct proc *); +static int hotfiles_adopt (struct hfsmount *, struct proc *); +static int hotfiles_evict (struct hfsmount *, struct proc *); +static int hotfiles_refine (struct hfsmount *, struct proc *); +static int hotextents(struct hfsmount *, HFSPlusExtentDescriptor *); + +/* + * Hot File Cluster B-tree (on disk) functions. + */ +static int hfc_btree_create (struct hfsmount *, int, int); +static int hfc_btree_open (struct hfsmount *, struct vnode **); +static int hfc_btree_close (struct hfsmount *, struct vnode *); +static int hfc_comparekeys (HotFileKey *, HotFileKey *); + + +char hfc_tag[] = "CLUSTERED HOT FILES B-TREE "; + + +/* + *======================================================================== + * HOT FILE INTERFACE ROUTINES + *======================================================================== + */ + +/* + * Start recording the hotest files on a file system. + * + */ +__private_extern__ +int +hfs_recording_start(struct hfsmount *hfsmp, struct proc *p) +{ + hotfile_data_t *hotdata; + int maxentries; + size_t size; + int i; + int error; + + if ((hfsmp->hfs_flags & HFS_READ_ONLY) || + (hfsmp->jnl == NULL) || + (hfsmp->hfs_flags & HFS_METADATA_ZONE) == 0) { + return (EPERM); + } + if (HFSTOVCB(hfsmp)->freeBlocks < (2 * hfsmp->hfs_hotfile_maxblks)) { + return (ENOSPC); + } + if (hfsmp->hfc_stage != HFC_IDLE) { + return (EBUSY); + } + hfsmp->hfc_stage = HFC_BUSY; + + /* + * Dump previous recording data. + */ + if (hfsmp->hfc_recdata) { + void * tmp; + + tmp = hfsmp->hfc_recdata; + hfsmp->hfc_recdata = NULL; + FREE(tmp, M_TEMP); + } + + /* + * On first startup check for suspended recording. + */ + if (hfsmp->hfc_timebase == 0 && + hfc_btree_open(hfsmp, &hfsmp->hfc_filevp) == 0) { + HotFilesInfo hotfileinfo; + + if ((BTGetUserData(VTOF(hfsmp->hfc_filevp), &hotfileinfo, + sizeof(hotfileinfo)) == 0) && + (SWAP_BE32 (hotfileinfo.magic) == HFC_MAGIC) && + (SWAP_BE32 (hotfileinfo.timeleft) > 0) && + (SWAP_BE32 (hotfileinfo.timebase) > 0)) { + hfsmp->hfc_maxfiles = SWAP_BE32 (hotfileinfo.maxfilecnt); + hfsmp->hfc_timeout = SWAP_BE32 (hotfileinfo.timeleft) + time.tv_sec ; + hfsmp->hfc_timebase = SWAP_BE32 (hotfileinfo.timebase); +#if HFC_VERBOSE + printf("HFS: resume recording hot files (%d left)\n", SWAP_BE32 (hotfileinfo.timeleft)); +#endif + } else { + hfsmp->hfc_maxfiles = HFC_DEFAULT_FILE_COUNT; + hfsmp->hfc_timebase = time.tv_sec + 1; + hfsmp->hfc_timeout = hfsmp->hfc_timebase + HFC_DEFAULT_DURATION; + } + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + } else { + struct cat_attr cattr; + u_int32_t cnid; + + /* + * Make sure a btree file exists. + */ + cnid = GetFileInfo(HFSTOVCB(hfsmp), kRootDirID, HFC_FILENAME, &cattr, NULL); + if ((cnid == 0) && + !S_ISREG(cattr.ca_mode) && + (error = hfc_btree_create(hfsmp, HFSTOVCB(hfsmp)->blockSize, HFC_DEFAULT_FILE_COUNT))) { + hfsmp->hfc_stage = HFC_IDLE; + wakeup((caddr_t)&hfsmp->hfc_stage); + return (error); + } +#if HFC_VERBOSE + printf("HFS: begin recording hot files\n"); +#endif + hfsmp->hfc_maxfiles = HFC_DEFAULT_FILE_COUNT; + hfsmp->hfc_timeout = time.tv_sec + HFC_DEFAULT_DURATION; + + /* Reset time base. */ + if (hfsmp->hfc_timebase == 0) { + hfsmp->hfc_timebase = time.tv_sec + 1; + } else { + u_int32_t cumulativebase; + u_int32_t oldbase = hfsmp->hfc_timebase; + + cumulativebase = hfsmp->hfc_timeout - (HFC_CUMULATIVE_CYCLES * HFC_DEFAULT_DURATION); + hfsmp->hfc_timebase = MAX(hfsmp->hfc_timebase, cumulativebase); + } + } + + if ((hfsmp->hfc_maxfiles == 0) || + (hfsmp->hfc_maxfiles > HFC_MAXIMUM_FILE_COUNT)) { + hfsmp->hfc_maxfiles = HFC_DEFAULT_FILE_COUNT; + } + maxentries = hfsmp->hfc_maxfiles; + + size = sizeof(hotfile_data_t) + (maxentries * sizeof(hotfile_entry_t)); + MALLOC(hotdata, hotfile_data_t *, size, M_TEMP, M_WAITOK); + bzero(hotdata, size); + + for (i = 1; i < maxentries ; i++) + hotdata->entries[i-1].right = &hotdata->entries[i]; + + hotdata->freelist = &hotdata->entries[0]; + /* + * Establish minimum temperature and maximum file size. + */ + hotdata->threshold = HFC_MINIMUM_TEMPERATURE; + hotdata->maxblocks = HFC_MAXIMUM_FILESIZE / HFSTOVCB(hfsmp)->blockSize; + hotdata->hfsmp = hfsmp; + + hfsmp->hfc_recdata = hotdata; +out: + hfsmp->hfc_stage = HFC_RECORDING; + wakeup((caddr_t)&hfsmp->hfc_stage); + return (0); +} + +/* + * Stop recording the hotest files on a file system. + */ +__private_extern__ +int +hfs_recording_stop(struct hfsmount *hfsmp, struct proc *p) +{ + hotfile_data_t *hotdata; + hotfilelist_t *listp; + size_t size; + enum hfc_stage newstage = HFC_IDLE; + void * tmp; + int error; + + + if (hfsmp->hfc_stage != HFC_RECORDING) + return (EPERM); + + hotfiles_collect(hfsmp, p); + + if (hfsmp->hfc_stage != HFC_RECORDING) + return (0); + + hfsmp->hfc_stage = HFC_BUSY; + + /* + * Convert hot file data into a simple file id list.... + * + * then dump the sample data + */ +#if HFC_VERBOSE + printf("HFS: end of hot file recording\n"); +#endif + hotdata = (hotfile_data_t *)hfsmp->hfc_recdata; + if (hotdata == NULL) + return (0); + hfsmp->hfc_recdata = NULL; + hfsmp->hfc_stage = HFC_EVALUATION; + wakeup((caddr_t)&hfsmp->hfc_stage); + +#if HFC_VERBOSE + printf(" curentries: %d\n", hotdata->activefiles); +#endif + /* + * If no hot files recorded then we're done. + */ + if (hotdata->rootentry == NULL) { + error = 0; + goto out; + } + + /* Open the B-tree file for writing... */ + if (hfsmp->hfc_filevp) + panic("hfs_recording_stop: hfc_filevp exists (vp = 0x%08x)", hfsmp->hfc_filevp); + + error = hfc_btree_open(hfsmp, &hfsmp->hfc_filevp); + if (error) { + goto out; + } + + /* + * Age the previous set of clustered hot files. + */ + error = hotfiles_age(hfsmp, p); + if (error) { + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + goto out; + } + + /* + * Create a sorted list of hotest files. + */ + size = sizeof(hotfilelist_t); + size += sizeof(hotfileinfo_t) * (hotdata->activefiles - 1); + MALLOC(listp, hotfilelist_t *, size, M_TEMP, M_WAITOK); + bzero(listp, size); + + hf_getsortedlist(hotdata, listp); + listp->hfl_duration = time.tv_sec - hfsmp->hfc_timebase; + hfsmp->hfc_recdata = listp; + + /* + * Account for duplicates. + */ + error = hotfiles_refine(hfsmp, p); + if (error) { + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + goto out; + } + + /* + * Compute the amount of space to reclaim... + */ + if (listp->hfl_totalblocks > hfsmp->hfs_hotfile_freeblks) { + listp->hfl_reclaimblks = + MIN(listp->hfl_totalblocks, hfsmp->hfs_hotfile_maxblks) - + hfsmp->hfs_hotfile_freeblks; +#if HFC_VERBOSE + printf("hfs_recording_stop: need to reclaim %d blocks\n", listp->hfl_reclaimblks); +#endif + if (listp->hfl_reclaimblks) + newstage = HFC_EVICTION; + else + newstage = HFC_ADOPTION; + } else { + newstage = HFC_ADOPTION; + } + + if (newstage == HFC_ADOPTION && listp->hfl_totalblocks == 0) { + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + newstage = HFC_IDLE; + } +out: +#if HFC_VERBOSE + if (newstage == HFC_EVICTION) + printf("HFS: evicting coldest files\n"); + else if (newstage == HFC_ADOPTION) + printf("HFS: adopting hotest files\n"); +#endif + FREE(hotdata, M_TEMP); + + hfsmp->hfc_stage = newstage; + wakeup((caddr_t)&hfsmp->hfc_stage); + return (error); +} + +/* + * Suspend recording the hotest files on a file system. + */ +__private_extern__ +int +hfs_recording_suspend(struct hfsmount *hfsmp, struct proc *p) +{ + HotFilesInfo hotfileinfo; + hotfile_data_t *hotdata; + int error; + + if (hfsmp->hfc_stage != HFC_RECORDING) + return (0); + + hotdata = (hotfile_data_t *)hfsmp->hfc_recdata; + if (hotdata == NULL) { + hfsmp->hfc_stage = HFC_DISABLED; + return (0); + } + hfsmp->hfc_stage = HFC_BUSY; + +#if HFC_VERBOSE + printf("HFS: suspend hot file recording\n"); +#endif + error = hfc_btree_open(hfsmp, &hfsmp->hfc_filevp); + if (error) { + printf("hfs_recording_suspend: err %d opening btree\n", error); + goto out; + } + + hfs_global_shared_lock_acquire(hfsmp); + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + hfs_global_shared_lock_release(hfsmp); + error = EINVAL; + goto out; + } + } + vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + + hotfileinfo.magic = SWAP_BE32 (HFC_MAGIC); + hotfileinfo.version = SWAP_BE32 (HFC_VERSION); + hotfileinfo.duration = SWAP_BE32 (HFC_DEFAULT_DURATION); + hotfileinfo.timebase = SWAP_BE32 (hfsmp->hfc_timebase); + hotfileinfo.timeleft = SWAP_BE32 (hfsmp->hfc_timeout - time.tv_sec); + hotfileinfo.threshold = SWAP_BE32 (hotdata->threshold); + hotfileinfo.maxfileblks = SWAP_BE32 (hotdata->maxblocks); + hotfileinfo.maxfilecnt = SWAP_BE32 (HFC_DEFAULT_FILE_COUNT); + strcpy(hotfileinfo.tag, hfc_tag); + (void) BTSetUserData(VTOF(hfsmp->hfc_filevp), &hotfileinfo, sizeof(hotfileinfo)); + + (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + if (hfsmp->jnl) { + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); + + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; +out: + FREE(hotdata, M_TEMP); + + hfsmp->hfc_stage = HFC_DISABLED; + wakeup((caddr_t)&hfsmp->hfc_stage); + return (error); +} + +/* + * Abort a hot file recording session. + */ +__private_extern__ +int +hfs_recording_abort(struct hfsmount *hfsmp, struct proc *p) +{ + void * tmp; + + if (hfsmp->hfc_stage == HFC_DISABLED) + return (0); + + if (hfsmp->hfc_stage == HFC_BUSY) { + (void) tsleep((caddr_t)&hfsmp->hfc_stage, PINOD, "hfs_recording_abort", 0); + } + hfsmp->hfc_stage = HFC_BUSY; + + printf("HFS: terminate hot file recording\n"); + + if (hfsmp->hfc_recdata) { + tmp = hfsmp->hfc_recdata; + hfsmp->hfc_recdata = NULL; + FREE(tmp, M_TEMP); + } + hfsmp->hfc_stage = HFC_DISABLED; + wakeup((caddr_t)&hfsmp->hfc_stage); + return (0); +} + +/* + * + */ +__private_extern__ +int +hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) +{ + CatalogKey * keyp; + CatalogRecord * datap; + u_int32_t dataSize; + HFSPlusCatalogFile *filep; + BTScanState scanstate; + BTreeIterator * iterator; + FSBufferDescriptor record; + HotFileKey * key; + filefork_t * filefork; + u_int32_t data; + struct cat_attr cattr; + u_int32_t cnid; + int error = 0; + + int inserted = 0; /* debug variables */ + int filecount = 0; + + /* + * If the Hot File btree exists then metadata zone is ready. + */ + cnid = GetFileInfo(HFSTOVCB(hfsmp), kRootDirID, HFC_FILENAME, &cattr, NULL); + if (cnid != 0 && S_ISREG(cattr.ca_mode)) { + if (hfsmp->hfc_stage == HFC_DISABLED) + hfsmp->hfc_stage = HFC_IDLE; + return (0); + } + /* + * For now, only the boot volume is supported. + */ + if ((HFSTOVFS(hfsmp)->mnt_flag & MNT_ROOTFS) == 0) { + hfsmp->hfs_flags &= ~HFS_METADATA_ZONE; + return (EPERM); + } + error = hfc_btree_create(hfsmp, HFSTOVCB(hfsmp)->blockSize, HFC_DEFAULT_FILE_COUNT); + if (error) { + return (error); + } + /* + * Open the Hot File B-tree file for writing. + */ + if (hfsmp->hfc_filevp) + panic("hfs_recording_init: hfc_filevp exists (vp = 0x%08x)", hfsmp->hfc_filevp); + error = hfc_btree_open(hfsmp, &hfsmp->hfc_filevp); + if (error) { + return (error); + } + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + key = (HotFileKey*) &iterator->key; + key->keyLength = HFC_KEYLENGTH; + + record.bufferAddress = &data; + record.itemSize = sizeof(u_int32_t); + record.itemCount = 1; +#if HFC_VERBOSE + printf("Evaluating space for \"%s\" metadata zone...\n", HFSTOVCB(hfsmp)->vcbVN); +#endif + /* + * Get ready to scan the Catalog file. + */ + error = BTScanInitialize(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), 0, 0, 0, + kCatSearchBufferSize, &scanstate); + if (error) { + printf("hfs_recording_init: err %d BTScanInit\n", error); + goto out2; + } + + /* + * The writes to Hot File B-tree file are journaled. + */ + hfs_global_shared_lock_acquire(hfsmp); + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + hfs_global_shared_lock_release(hfsmp); + error = EINVAL; + goto out1; + } + } + vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + filefork = VTOF(hfsmp->hfc_filevp); + + /* + * Visit all the catalog btree leaf records. + */ + for (;;) { + error = BTScanNextRecord(&scanstate, 0, (void **)&keyp, (void **)&datap, &dataSize); + if (error) { + if (error == btNotFound) + error = 0; + else + printf("hfs_recording_init: err %d BTScanNext\n", error); + break; + } + if ((datap->recordType != kHFSPlusFileRecord) || + (dataSize != sizeof(HFSPlusCatalogFile))) { + continue; + } + filep = (HFSPlusCatalogFile *)datap; + filecount++; + if (filep->dataFork.totalBlocks == 0) { + continue; + } + /* + * Any file that has blocks inside the hot file + * space is recorded for later eviction. + * + * For now, resource forks are ignored. + */ + if (!hotextents(hfsmp, &filep->dataFork.extents[0])) { + continue; + } + cnid = filep->fileID; + + /* Skip over journal files. */ + if (cnid == hfsmp->hfs_jnlfileid || cnid == hfsmp->hfs_jnlinfoblkid) { + continue; + } + /* + * XXX - need to skip quota files as well. + */ + + /* Insert a hot file entry. */ + key->keyLength = HFC_KEYLENGTH; + key->temperature = HFC_MINIMUM_TEMPERATURE; + key->fileID = cnid; + key->forkType = 0; + data = 0x3f3f3f3f; + error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + if (error) { + printf("hfs_recording_init: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); + error = MacToVFSError(error); + break; + } + + /* Insert the corresponding thread record. */ + key->keyLength = HFC_KEYLENGTH; + key->temperature = HFC_LOOKUPTAG; + key->fileID = cnid; + key->forkType = 0; + data = HFC_MINIMUM_TEMPERATURE; + error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + if (error) { + printf("hfs_recording_init: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); + error = MacToVFSError(error); + break; + } + inserted++; + } + (void) BTFlushPath(filefork); + (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + + if (hfsmp->jnl) { + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); +#if HFC_VERBOSE + printf("%d files identified out of %d\n", inserted, filecount); +#endif + +out1: + (void) BTScanTerminate(&scanstate, &data, &data, &data); +out2: + FREE(iterator, M_TEMP); + if (hfsmp->hfc_filevp) { + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + } + if (error == 0) + hfsmp->hfc_stage = HFC_IDLE; + + return (error); +} + +/* + * Use sync to perform ocassional background work. + */ +__private_extern__ +int +hfs_hotfilesync(struct hfsmount *hfsmp, struct proc *p) +{ + if ((HFSTOVFS(hfsmp)->mnt_kern_flag & MNTK_UNMOUNT) == 0 && hfsmp->hfc_stage) { + switch (hfsmp->hfc_stage) { + case HFC_IDLE: + (void) hfs_recording_start(hfsmp, p); + break; + + case HFC_RECORDING: + if (time.tv_sec > hfsmp->hfc_timeout) + (void) hfs_recording_stop(hfsmp, p); + break; + + case HFC_EVICTION: + (void) hotfiles_evict(hfsmp, p); + break; + + case HFC_ADOPTION: + (void) hotfiles_adopt(hfsmp, p); + break; + } + } + return (0); +} + +/* + * Add a hot file to the recording list. + * + * This can happen when a hot file gets reclaimed or at the + * end of the recording period for any active hot file. + * + * NOTE: Since both the data and resource fork can be hot, + * there can be two entries for the same file id. + * + */ +__private_extern__ +int +hfs_addhotfile(struct vnode *vp) +{ + hotfile_data_t *hotdata; + hotfile_entry_t *entry; + hfsmount_t *hfsmp; + cnode_t *cp; + filefork_t *ffp; + u_int32_t temperature; + + hfsmp = VTOHFS(vp); + if (hfsmp->hfc_stage != HFC_RECORDING) + return (0); + + if (!(vp->v_type == VREG || vp->v_type == VLNK) || + (vp->v_flag & (VSYSTEM | VSWAP))) { + return (0); + } + /* Skip resource forks for now. */ + if (VNODE_IS_RSRC(vp)) { + return (0); + } + if ((hotdata = (hotfile_data_t *)hfsmp->hfc_recdata) == NULL) { + return (0); + } + ffp = VTOF(vp); + cp = VTOC(vp); + + if ((ffp->ff_bytesread == 0) || + (ffp->ff_blocks == 0) || + (ffp->ff_blocks > hotdata->maxblocks) || + (cp->c_flag & (C_DELETED | C_NOEXISTS)) || + (cp->c_flags & UF_NODUMP) || + (cp->c_atime < hfsmp->hfc_timebase)) { + return (0); + } + + temperature = ffp->ff_bytesread / ffp->ff_size; + if (temperature < hotdata->threshold) { + return (0); + } + /* + * If there is room or this file is hotter than + * the coldest one then add it to the list. + * + */ + if ((hotdata->activefiles < hfsmp->hfc_maxfiles) || + (hotdata->coldest == NULL) || + (temperature > hotdata->coldest->temperature)) { + ++hotdata->refcount; + entry = hf_getnewentry(hotdata); + entry->temperature = temperature; + entry->fileid = cp->c_fileid; + entry->blocks = ffp->ff_blocks; + hf_insert(hotdata, entry); + --hotdata->refcount; + } + + return (0); +} + +/* + * Remove a hot file to the recording list. + * + * This can happen when a hot file becomes + * an active vnode (active hot files are + * not kept in the recording list until the + * end of the recording period). + * + */ +__private_extern__ +int +hfs_removehotfile(struct vnode *vp) +{ + hotfile_data_t *hotdata; + hfsmount_t *hfsmp; + cnode_t *cp; + filefork_t *ffp; + u_int32_t temperature; + + hfsmp = VTOHFS(vp); + if (hfsmp->hfc_stage != HFC_RECORDING) + return (0); + + if (!(vp->v_type == VREG || vp->v_type == VLNK) || + (vp->v_flag & (VSYSTEM | VSWAP))) { + return (0); + } + if ((hotdata = (hotfile_data_t *)hfsmp->hfc_recdata) == NULL) + return (0); + + ffp = VTOF(vp); + cp = VTOC(vp); + + if ((ffp->ff_bytesread == 0) || (ffp->ff_blocks == 0) || + (cp->c_atime < hfsmp->hfc_timebase)) { + return (0); + } + + temperature = ffp->ff_bytesread / ffp->ff_size; + if (temperature < hotdata->threshold) + return (0); + + if (hotdata->coldest && (temperature >= hotdata->coldest->temperature)) { + ++hotdata->refcount; + hf_delete(hotdata, VTOC(vp)->c_fileid, temperature); + --hotdata->refcount; + } + + return (0); +} + + +/* + *======================================================================== + * HOT FILE MAINTENANCE ROUTINES + *======================================================================== + */ + +/* + * Add all active hot files to the recording list. + */ +static int +hotfiles_collect(struct hfsmount *hfsmp, struct proc *p) +{ + struct mount *mp = HFSTOVFS(hfsmp); + struct vnode *nvp, *vp; + struct cnode *cp; + int error; + + if (vfs_busy(mp, LK_NOWAIT, 0, p)) + return (0); +loop: + simple_lock(&mntvnode_slock); + for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { + if (vp->v_mount != mp) { + simple_unlock(&mntvnode_slock); + goto loop; + } + simple_lock(&vp->v_interlock); + nvp = vp->v_mntvnodes.le_next; + + if ((vp->v_flag & VSYSTEM) || + !(vp->v_type == VREG || vp->v_type == VLNK)) { + simple_unlock(&vp->v_interlock); + continue; + } + + cp = VTOC(vp); + if (cp == NULL || vp->v_flag & (VXLOCK|VORECLAIM)) { + simple_unlock(&vp->v_interlock); + continue; + } + + simple_unlock(&mntvnode_slock); + error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); + if (error) { + if (error == ENOENT) + goto loop; + simple_lock(&mntvnode_slock); + continue; + } + (void) hfs_addhotfile(vp); + vput(vp); + + simple_lock(&mntvnode_slock); + } + + simple_unlock(&mntvnode_slock); + + vfs_unbusy(mp, p); + + return (0); +} + + +/* + * Update the data of a btree record + * This is called from within BTUpdateRecord. + */ +static int +update_callback(const HotFileKey *key, u_int32_t *data, u_int16_t datalen, u_int32_t *state) +{ + if (key->temperature == HFC_LOOKUPTAG) + *data = *state; + return (0); +} + +/* + * Identify files already in hot area. + */ +static int +hotfiles_refine(struct hfsmount *hfsmp, struct proc *p) +{ + BTreeIterator * iterator; + struct mount *mp; + struct vnode *vp; + filefork_t * filefork; + hotfilelist_t *listp; + FSBufferDescriptor record; + HotFileKey * key; + u_int32_t data; + int i; + int error = 0; + + + if ((listp = (hotfilelist_t *)hfsmp->hfc_recdata) == NULL) + return (0); + + mp = HFSTOVFS(hfsmp); + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + key = (HotFileKey*) &iterator->key; + + record.bufferAddress = &data; + record.itemSize = sizeof(u_int32_t); + record.itemCount = 1; + + hfs_global_shared_lock_acquire(hfsmp); + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + hfs_global_shared_lock_release(hfsmp); + error = EINVAL; + goto out; + } + } + vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + filefork = VTOF(hfsmp->hfc_filevp); + + for (i = 0; i < listp->hfl_count; ++i) { + /* + * Check if entry (thread) is already in hot area. + */ + key->keyLength = HFC_KEYLENGTH; + key->temperature = HFC_LOOKUPTAG; + key->fileID = listp->hfl_hotfile[i].hf_fileid; + key->forkType = 0; + (void) BTInvalidateHint(iterator); + if (BTSearchRecord(filefork, iterator, &record, NULL, iterator) != 0) { + continue; /* not in hot area, so skip */ + } + + /* + * Update thread entry with latest temperature. + */ + error = BTUpdateRecord(filefork, iterator, + (IterateCallBackProcPtr)update_callback, + &listp->hfl_hotfile[i].hf_temperature); + if (error) { + printf("hotfiles_refine: BTUpdateRecord failed %d (file %d)\n", error, key->fileID); + error = MacToVFSError(error); + // break; + } + /* + * Re-key entry with latest temperature. + */ + key->keyLength = HFC_KEYLENGTH; + key->temperature = data; + key->fileID = listp->hfl_hotfile[i].hf_fileid; + key->forkType = 0; + /* Pick up record data. */ + (void) BTInvalidateHint(iterator); + (void) BTSearchRecord(filefork, iterator, &record, NULL, iterator); + error = BTDeleteRecord(filefork, iterator); + if (error) { + printf("hotfiles_refine: BTDeleteRecord failed %d (file %d)\n", error, key->fileID); + error = MacToVFSError(error); + break; + } + key->keyLength = HFC_KEYLENGTH; + key->temperature = listp->hfl_hotfile[i].hf_temperature; + key->fileID = listp->hfl_hotfile[i].hf_fileid; + key->forkType = 0; + error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + if (error) { + printf("hotfiles_refine: BTInsertRecord failed %d (file %d)\n", error, key->fileID); + error = MacToVFSError(error); + break; + } + + /* + * Invalidate this entry in the list. + */ + listp->hfl_hotfile[i].hf_temperature = 0; + listp->hfl_totalblocks -= listp->hfl_hotfile[i].hf_blocks; + + } /* end for */ + + (void) BTFlushPath(filefork); + (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + + if (hfsmp->jnl) { + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); +out: + FREE(iterator, M_TEMP); + return (error); +} + +/* + * Move new hot files into hot area. + */ +static int +hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) +{ + BTreeIterator * iterator; + struct mount *mp; + struct vnode *vp; + filefork_t * filefork; + hotfilelist_t *listp; + FSBufferDescriptor record; + HotFileKey * key; + u_int32_t data; + enum hfc_stage stage; + int fileblocks; + int blksmoved; + int i; + int last; + int error = 0; + int startedtrans = 0; + int aquiredlock = 0; + + if ((listp = (hotfilelist_t *)hfsmp->hfc_recdata) == NULL) + return (0); + + if (hfsmp->hfc_stage != HFC_ADOPTION) { + return (EBUSY); + } + stage = hfsmp->hfc_stage; + hfsmp->hfc_stage = HFC_BUSY; + + mp = HFSTOVFS(hfsmp); + blksmoved = 0; + last = listp->hfl_next + HFC_FILESPERSYNC; + if (last > listp->hfl_count) + last = listp->hfl_count; + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + key = (HotFileKey*) &iterator->key; + key->keyLength = HFC_KEYLENGTH; + + record.bufferAddress = &data; + record.itemSize = sizeof(u_int32_t); + record.itemCount = 1; + + vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + filefork = VTOF(hfsmp->hfc_filevp); + + for (i = listp->hfl_next; (i < last) && (blksmoved < HFC_BLKSPERSYNC); ++i) { + /* + * Skip invalid entries (already in hot area). + */ + if (listp->hfl_hotfile[i].hf_temperature == 0) { + listp->hfl_next++; + continue; + } + /* + * Acquire a vnode for this file. + */ + error = VFS_VGET(mp, &listp->hfl_hotfile[i].hf_fileid, &vp); + if (error) { + if (error == ENOENT) { + error = 0; + listp->hfl_next++; + continue; /* stale entry, go to next */ + } + break; + } + if (vp->v_type != VREG && vp->v_type != VLNK) { + printf("hotfiles_adopt: huh, not a file %d (%d)\n", listp->hfl_hotfile[i].hf_fileid, VTOC(vp)->c_cnid); + vput(vp); + listp->hfl_hotfile[i].hf_temperature == 0; + listp->hfl_next++; + continue; /* stale entry, go to next */ + } + if (hotextents(hfsmp, &VTOF(vp)->ff_extents[0])) { + vput(vp); + listp->hfl_hotfile[i].hf_temperature == 0; + listp->hfl_next++; + listp->hfl_totalblocks -= listp->hfl_hotfile[i].hf_blocks; + continue; /* stale entry, go to next */ + } + fileblocks = VTOF(vp)->ff_blocks; + if (fileblocks > hfsmp->hfs_hotfile_freeblks) { + vput(vp); + listp->hfl_next++; + listp->hfl_totalblocks -= fileblocks; + continue; /* entry too big, go to next */ + } + + if ((blksmoved > 0) && + (blksmoved + fileblocks) > HFC_BLKSPERSYNC) { + vput(vp); + break; + } + /* Start a new transaction. */ + hfs_global_shared_lock_acquire(hfsmp); + aquiredlock = 1; + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + error = EINVAL; + vput(vp); + break; + } + startedtrans = 1; + } + + error = hfs_relocate(vp, hfsmp->hfs_hotfile_start, p->p_ucred, p); + vput(vp); + if (error) + break; + + /* Keep hot file free space current. */ + hfsmp->hfs_hotfile_freeblks -= fileblocks; + listp->hfl_totalblocks -= fileblocks; + + /* Insert hot file entry */ + key->keyLength = HFC_KEYLENGTH; + key->temperature = listp->hfl_hotfile[i].hf_temperature; + key->fileID = listp->hfl_hotfile[i].hf_fileid; + key->forkType = 0; + if (VTOC(vp)->c_desc.cd_nameptr) + data = *(u_int32_t *)(VTOC(vp)->c_desc.cd_nameptr); + else + data = 0x3f3f3f3f; + + error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + if (error) { + printf("hotfiles_adopt: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); + error = MacToVFSError(error); + stage = HFC_IDLE; + break; + } + + /* Insert thread record */ + key->keyLength = HFC_KEYLENGTH; + key->temperature = HFC_LOOKUPTAG; + key->fileID = listp->hfl_hotfile[i].hf_fileid; + key->forkType = 0; + data = listp->hfl_hotfile[i].hf_temperature; + error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + if (error) { + printf("hotfiles_adopt: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); + error = MacToVFSError(error); + stage = HFC_IDLE; + break; + } + (void) BTFlushPath(filefork); + + /* Transaction complete. */ + if (startedtrans) { + journal_end_transaction(hfsmp->jnl); + startedtrans = 0; + } + hfs_global_shared_lock_release(hfsmp); + aquiredlock = 0; + + blksmoved += fileblocks; + listp->hfl_next++; + if (listp->hfl_next >= listp->hfl_count) { + break; + } + if (hfsmp->hfs_hotfile_freeblks <= 0) { +#if HFC_VERBOSE + printf("hotfiles_adopt: free space exhausted (%d)\n", hfsmp->hfs_hotfile_freeblks); +#endif + break; + } + } /* end for */ + +#if HFC_VERBOSE + printf("hotfiles_adopt: [%d] adopted %d blocks (%d left)\n", listp->hfl_next, blksmoved, listp->hfl_totalblocks); +#endif + /* Finish any outstanding transactions. */ + if (startedtrans) { + (void) BTFlushPath(filefork); + journal_end_transaction(hfsmp->jnl); + startedtrans = 0; + } + if (aquiredlock) { + hfs_global_shared_lock_release(hfsmp); + aquiredlock = 0; + } + (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + + if ((listp->hfl_next >= listp->hfl_count) || (hfsmp->hfs_hotfile_freeblks <= 0)) { +#if HFC_VERBOSE + printf("hotfiles_adopt: all done relocating %d files\n", listp->hfl_count); + printf("hotfiles_adopt: %d blocks free in hot file band\n", hfsmp->hfs_hotfile_freeblks); +#endif + stage = HFC_IDLE; + } + FREE(iterator, M_TEMP); + + if (stage != HFC_ADOPTION && hfsmp->hfc_filevp) { + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + } + hfsmp->hfc_stage = stage; + wakeup((caddr_t)&hfsmp->hfc_stage); + return (error); +} + +/* + * Reclaim space by evicting the coldest files. + */ +static int +hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) +{ + BTreeIterator * iterator; + struct mount *mp; + struct vnode *vp; + HotFileKey * key; + filefork_t * filefork; + hotfilelist_t *listp; + enum hfc_stage stage; + int blksmoved; + int filesmoved; + int fileblocks; + int error = 0; + int startedtrans = 0; + int aquiredlock = 0; + + if (hfsmp->hfc_stage != HFC_EVICTION) { + return (EBUSY); + } + + if ((listp = (hotfilelist_t *)hfsmp->hfc_recdata) == NULL) + return (0); + + stage = hfsmp->hfc_stage; + hfsmp->hfc_stage = HFC_BUSY; + + mp = HFSTOVFS(hfsmp); + filesmoved = blksmoved = 0; + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + key = (HotFileKey*) &iterator->key; + + vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + filefork = VTOF(hfsmp->hfc_filevp); + + while (listp->hfl_reclaimblks > 0 && + blksmoved < HFC_BLKSPERSYNC && + filesmoved < HFC_FILESPERSYNC) { + + /* + * Obtain the first record (ie the coldest one). + */ + if (BTIterateRecord(filefork, kBTreeFirstRecord, iterator, NULL, NULL) != 0) { +#if HFC_VERBOSE + printf("hotfiles_evict: no more records\n"); +#endif + error = 0; + stage = HFC_ADOPTION; + break; + } + if (key->keyLength != HFC_KEYLENGTH) { + printf("hotfiles_evict: invalid key length %d\n", key->keyLength); + error = EFTYPE; + break; + } + if (key->temperature == HFC_LOOKUPTAG) { +#if HFC_VERBOSE + printf("hotfiles_evict: ran into thread records\n"); +#endif + error = 0; + stage = HFC_ADOPTION; + break; + } + /* + * Aquire the vnode for this file. + */ + error = VFS_VGET(mp, &key->fileID, &vp); + + /* Start a new transaction. */ + hfs_global_shared_lock_acquire(hfsmp); + aquiredlock = 1; + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + if (error == 0) + vput(vp); + error = EINVAL; + break; + } + startedtrans = 1; + } + if (error) { + if (error == ENOENT) { + (void) BTDeleteRecord(filefork, iterator); + key->temperature = HFC_LOOKUPTAG; + (void) BTDeleteRecord(filefork, iterator); + goto next; /* stale entry, go to next */ + } else { + printf("hotfiles_evict: err %d getting file %d (%d)\n", + error, key->fileID); + } + break; + } + if (vp->v_type != VREG && vp->v_type != VLNK) { + printf("hotfiles_evict: huh, not a file %d\n", key->fileID); + vput(vp); + (void) BTDeleteRecord(filefork, iterator); + key->temperature = HFC_LOOKUPTAG; + (void) BTDeleteRecord(filefork, iterator); + goto next; /* invalid entry, go to next */ + } + fileblocks = VTOF(vp)->ff_blocks; + if ((blksmoved > 0) && + (blksmoved + fileblocks) > HFC_BLKSPERSYNC) { + vput(vp); + break; + } + /* + * Make sure file is in the hot area. + */ + if (!hotextents(hfsmp, &VTOF(vp)->ff_extents[0])) { +#if HFC_VERBOSE + printf("hotfiles_evict: file %d isn't hot!\n", key->fileID); +#endif + vput(vp); + (void) BTDeleteRecord(filefork, iterator); + key->temperature = HFC_LOOKUPTAG; + (void) BTDeleteRecord(filefork, iterator); + goto next; /* go to next */ + } + + /* + * Relocate file out of hot area. + */ + error = hfs_relocate(vp, HFSTOVCB(hfsmp)->nextAllocation, p->p_ucred, p); + if (error) { + /* XXX skip to next record here! */ + printf("hotfiles_evict: err % relocating file\n", error, key->fileID); + vput(vp); + break; + } + (void) VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p); + + vput(vp); + + hfsmp->hfs_hotfile_freeblks += fileblocks; + listp->hfl_reclaimblks -= fileblocks; + if (listp->hfl_reclaimblks < 0) + listp->hfl_reclaimblks = 0; + blksmoved += fileblocks; + filesmoved++; + + error = BTDeleteRecord(filefork, iterator); + if (error) { + printf("hotfiles_evict: BTDeleteRecord failed %d (fileid %d)\n", error, key->fileID); + error = MacToVFSError(error); + break; + } + key->temperature = HFC_LOOKUPTAG; + error = BTDeleteRecord(filefork, iterator); + if (error) { + printf("hotfiles_evict: BTDeleteRecord thread failed %d (fileid %d)\n", error, key->fileID); + error = MacToVFSError(error); + break; + } +next: + (void) BTFlushPath(filefork); + + /* Transaction complete. */ + if (startedtrans) { + journal_end_transaction(hfsmp->jnl); + startedtrans = 0; + } + hfs_global_shared_lock_release(hfsmp); + aquiredlock = 0; + + } /* end while */ + +#if HFC_VERBOSE + printf("hotfiles_evict: moved %d files (%d blks, %d to go)\n", filesmoved, blksmoved, listp->hfl_reclaimblks); +#endif + /* Finish any outstanding transactions. */ + if (startedtrans) { + (void) BTFlushPath(filefork); + journal_end_transaction(hfsmp->jnl); + startedtrans = 0; + } + if (aquiredlock) { + hfs_global_shared_lock_release(hfsmp); + aquiredlock = 0; + } + (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + + /* + * Move to next stage when finished. + */ + if (listp->hfl_reclaimblks <= 0) { + stage = HFC_ADOPTION; +#if HFC_VERBOSE + printf("hotfiles_evict: %d blocks free in hot file band\n", hfsmp->hfs_hotfile_freeblks); +#endif + } + FREE(iterator, M_TEMP); + hfsmp->hfc_stage = stage; + wakeup((caddr_t)&hfsmp->hfc_stage); + return (error); +} + +/* + * Age the existing records in the hot files b-tree. + */ +static int +hotfiles_age(struct hfsmount *hfsmp, struct proc *p) +{ + BTreeInfoRec btinfo; + BTreeIterator * iterator; + BTreeIterator * prev_iterator; + FSBufferDescriptor record; + FSBufferDescriptor prev_record; + HotFileKey * key; + HotFileKey * prev_key; + filefork_t * filefork; + u_int32_t data; + u_int32_t prev_data; + u_int32_t newtemp; + int error; + int i; + int numrecs; + int aged = 0; + u_int16_t reclen; + + + MALLOC(iterator, BTreeIterator *, 2 * sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, 2 * sizeof(*iterator)); + key = (HotFileKey*) &iterator->key; + + prev_iterator = &iterator[1]; + prev_key = (HotFileKey*) &prev_iterator->key; + + record.bufferAddress = &data; + record.itemSize = sizeof(data); + record.itemCount = 1; + prev_record.bufferAddress = &prev_data; + prev_record.itemSize = sizeof(prev_data); + prev_record.itemCount = 1; + + /* + * Capture b-tree changes inside a transaction + */ + hfs_global_shared_lock_acquire(hfsmp); + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + hfs_global_shared_lock_release(hfsmp); + error = EINVAL; + goto out2; + } + } + vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + filefork = VTOF(hfsmp->hfc_filevp); + + error = BTGetInformation(filefork, 0, &btinfo); + if (error) { + error = MacToVFSError(error); + goto out; + } + if (btinfo.numRecords < 2) { + error = 0; + goto out; + } + + /* Only want 1st half of leaf records */ + numrecs = (btinfo.numRecords /= 2) - 1; + + error = BTIterateRecord(filefork, kBTreeFirstRecord, iterator, &record, &reclen); + if (error) { + printf("hfs_agehotfiles: BTIterateRecord: %d\n", error); + error = MacToVFSError(error); + goto out; + } + bcopy(iterator, prev_iterator, sizeof(BTreeIterator)); + prev_data = data; + + for (i = 0; i < numrecs; ++i) { + error = BTIterateRecord(filefork, kBTreeNextRecord, iterator, &record, &reclen); + if (error == 0) { + if (key->temperature < prev_key->temperature) { + printf("hfs_agehotfiles: out of order keys!\n"); + error = EFTYPE; + break; + } + if (reclen != sizeof(data)) { + printf("hfs_agehotfiles: invalid record length %d\n", reclen); + error = EFTYPE; + break; + } + if (key->keyLength != HFC_KEYLENGTH) { + printf("hfs_agehotfiles: invalid key length %d\n", key->keyLength); + error = EFTYPE; + break; + } + } else if ((error == fsBTEndOfIterationErr || error == fsBTRecordNotFoundErr) && + (i == (numrecs - 1))) { + error = 0; + } else if (error) { + printf("hfs_agehotfiles: %d of %d BTIterateRecord: %d\n", i, numrecs, error); + error = MacToVFSError(error); + break; + } + if (prev_key->temperature == HFC_LOOKUPTAG) { +#if HFC_VERBOSE + printf("hfs_agehotfiles: ran into thread record\n"); +#endif + error = 0; + break; + } + error = BTDeleteRecord(filefork, prev_iterator); + if (error) { + printf("hfs_agehotfiles: BTDeleteRecord failed %d (file %d)\n", error, prev_key->fileID); + error = MacToVFSError(error); + break; + } + + /* Age by halving the temperature (floor = 4) */ + newtemp = MAX(prev_key->temperature >> 1, 4); + prev_key->temperature = newtemp; + + error = BTInsertRecord(filefork, prev_iterator, &prev_record, sizeof(data)); + if (error) { + printf("hfs_agehotfiles: BTInsertRecord failed %d (file %d)\n", error, prev_key->fileID); + error = MacToVFSError(error); + break; + } + ++aged; + /* + * Update thread entry with latest temperature. + */ + prev_key->temperature = HFC_LOOKUPTAG; + error = BTUpdateRecord(filefork, prev_iterator, + (IterateCallBackProcPtr)update_callback, + &newtemp); + if (error) { + printf("hfs_agehotfiles: %d of %d BTUpdateRecord failed %d (file %d, %d)\n", + i, numrecs, error, prev_key->fileID, newtemp); + error = MacToVFSError(error); + // break; + } + + bcopy(iterator, prev_iterator, sizeof(BTreeIterator)); + prev_data = data; + + } /* end for */ + +#if HFC_VERBOSE + if (error == 0) + printf("hfs_agehotfiles: aged %d records out of %d\n", aged, btinfo.numRecords); +#endif + (void) BTFlushPath(filefork); +out: + (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + + if (hfsmp->jnl) { + // hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); +out2: + FREE(iterator, M_TEMP); + return (error); +} + +/* + * Return true if any blocks (or all blocks if all is true) + * are contained in the hot file region. + */ +static int +hotextents(struct hfsmount *hfsmp, HFSPlusExtentDescriptor * extents) +{ + u_int32_t b1, b2; + int i; + int inside = 0; + + for (i = 0; i < kHFSPlusExtentDensity; ++i) { + b1 = extents[i].startBlock; + if (b1 == 0) + break; + b2 = b1 + extents[i].blockCount - 1; + if ((b1 >= hfsmp->hfs_hotfile_start && + b2 <= hfsmp->hfs_hotfile_end) || + (b1 < hfsmp->hfs_hotfile_end && + b2 > hfsmp->hfs_hotfile_end)) { + inside = 1; + break; + } + } + return (inside); +} + + +/* + *======================================================================== + * HOT FILE B-TREE ROUTINES + *======================================================================== + */ + +/* + * Open the hot files b-tree for writing. + * + * On successful exit the vnode has a reference but is unlocked. + */ +static int +hfc_btree_open(struct hfsmount *hfsmp, struct vnode **vpp) +{ + struct proc *p; + struct vnode *vp; + struct cat_desc cdesc = {0}; + struct cat_attr cattr; + struct cat_fork cfork; + static char filename[] = HFC_FILENAME; + int error; + int retry = 0; + + *vpp = NULL; + p = current_proc(); + + cdesc.cd_parentcnid = kRootDirID; + cdesc.cd_nameptr = filename; + cdesc.cd_namelen = strlen(filename); + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); + if (error) + return (error); + + error = cat_lookup(hfsmp, &cdesc, 0, &cdesc, &cattr, &cfork); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + + if (error) { + printf("hfc_btree_open: cat_lookup error %d\n", error); + return (error); + } +again: + cdesc.cd_flags |= CD_ISMETA; + error = hfs_getnewvnode(hfsmp, NULL, &cdesc, 0, &cattr, &cfork, &vp); + if (error) { + printf("hfc_btree_open: hfs_getnewvnode error %d\n", error); + cat_releasedesc(&cdesc); + return (error); + } + if ((vp->v_flag & VSYSTEM) == 0) { +#if HFC_VERBOSE + printf("hfc_btree_open: file has UBC, try again\n"); +#endif + vput(vp); + vgone(vp); + if (retry++ == 0) + goto again; + else + return (EBUSY); + } + + /* Open the B-tree file for writing... */ + error = BTOpenPath(VTOF(vp), (KeyCompareProcPtr) hfc_comparekeys); + if (error) { + printf("hfc_btree_open: BTOpenPath error %d\n", error); + error = MacToVFSError(error); + } else { +#if HFC_VERBOSE + struct BTreeInfoRec btinfo; + + if (BTGetInformation(VTOF(vp), 0, &btinfo) == 0) { + printf("btinfo: nodeSize %d\n", btinfo.nodeSize); + printf("btinfo: maxKeyLength %d\n", btinfo.maxKeyLength); + printf("btinfo: treeDepth %d\n", btinfo.treeDepth); + printf("btinfo: numRecords %d\n", btinfo.numRecords); + printf("btinfo: numNodes %d\n", btinfo.numNodes); + printf("btinfo: numFreeNodes %d\n", btinfo.numFreeNodes); + } +#endif + } + + VOP_UNLOCK(vp, 0, p); /* unlocked with a single reference */ + if (error) + vrele(vp); + else + *vpp = vp; + + if ((vp->v_flag & VSYSTEM) == 0) + panic("hfc_btree_open: not a system file (vp = 0x%08x)", vp); + + if (UBCINFOEXISTS(vp)) + panic("hfc_btree_open: has UBCInfo (vp = 0x%08x)", vp); + + return (error); +} + +/* + * Close the hot files b-tree. + * + * On entry the vnode is not locked but has a reference. + */ +static int +hfc_btree_close(struct hfsmount *hfsmp, struct vnode *vp) +{ + struct proc *p = current_proc(); + int error; + + + if (hfsmp->jnl) { + journal_flush(hfsmp->jnl); + } + + if (vget(vp, LK_EXCLUSIVE, p) == 0) { + (void) VOP_FSYNC(vp, NOCRED, MNT_WAIT, p); + error = BTClosePath(VTOF(vp)); + if (error) + printf("hfc_btree_close: BTClosePath error %d\n", error); + vput(vp); + } + vrele(vp); + vgone(vp); + vp = NULL; + + return (0); +} + +/* + * Create a hot files btree file. + * + */ +static int +hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) +{ + struct proc *p; + struct nameidata nd; + struct vnode *vp; + char path[128]; + int error; + + + if (hfsmp->hfc_filevp) + panic("hfc_btree_create: hfc_filevp exists (vp = 0x%08x)", hfsmp->hfc_filevp); + + p = current_proc(); + snprintf(path, sizeof(path), "%s/%s", + hfsmp->hfs_mp->mnt_stat.f_mntonname, HFC_FILENAME); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, p); + if ((error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR)) != 0) { + return (error); + } + vp = nd.ni_vp; + + /* Don't use non-regular files or files with links. */ + if (vp->v_type != VREG || VTOC(vp)->c_nlink != 1) { + error = EFTYPE; + goto out; + } + + printf("HFS: created HFBT on %s\n", HFSTOVCB(hfsmp)->vcbVN); + + if (VTOF(vp)->ff_size < nodesize) { + caddr_t buffer; + u_int16_t *index; + u_int16_t offset; + BTNodeDescriptor *ndp; + BTHeaderRec *bthp; + HotFilesInfo *hotfileinfo; + int nodecnt; + int filesize; + int entirespernode; + + /* + * Mark it invisible (truncate will pull these changes). + */ + ((FndrFileInfo *)&VTOC(vp)->c_finderinfo[0])->fdFlags |= + SWAP_BE16 (kIsInvisible + kNameLocked); + + if (kmem_alloc(kernel_map, (vm_offset_t *)&buffer, nodesize)) { + error = ENOMEM; + goto out; + } + bzero(buffer, nodesize); + index = (int16_t *)buffer; + + entirespernode = (nodesize - sizeof(BTNodeDescriptor) - 2) / + (sizeof(HotFileKey) + 6); + nodecnt = 2 + howmany(entries * 2, entirespernode); + nodecnt = roundup(nodecnt, 8); + filesize = nodecnt * nodesize; + + /* FILL IN THE NODE DESCRIPTOR: */ + ndp = (BTNodeDescriptor *)buffer; + ndp->kind = kBTHeaderNode; + ndp->numRecords = SWAP_BE16 (3); + offset = sizeof(BTNodeDescriptor); + index[(nodesize / 2) - 1] = SWAP_BE16 (offset); + + /* FILL IN THE HEADER RECORD: */ + bthp = (BTHeaderRec *)((UInt8 *)buffer + offset); + bthp->nodeSize = SWAP_BE16 (nodesize); + bthp->totalNodes = SWAP_BE32 (filesize / nodesize); + bthp->freeNodes = SWAP_BE32 (nodecnt - 1); + bthp->clumpSize = SWAP_BE32 (filesize); + bthp->btreeType = kUserBTreeType; /* non-metadata */ + bthp->attributes |= SWAP_BE32 (kBTBigKeysMask); + bthp->maxKeyLength = SWAP_BE16 (HFC_KEYLENGTH); + offset += sizeof(BTHeaderRec); + index[(nodesize / 2) - 2] = SWAP_BE16 (offset); + + /* FILL IN THE USER RECORD: */ + hotfileinfo = (HotFilesInfo *)((UInt8 *)buffer + offset); + hotfileinfo->magic = SWAP_BE32 (HFC_MAGIC); + hotfileinfo->version = SWAP_BE32 (HFC_VERSION); + hotfileinfo->duration = SWAP_BE32 (HFC_DEFAULT_DURATION); + hotfileinfo->timebase = 0; + hotfileinfo->timeleft = 0; + hotfileinfo->threshold = SWAP_BE32 (HFC_MINIMUM_TEMPERATURE); + hotfileinfo->maxfileblks = SWAP_BE32 (HFC_MAXIMUM_FILESIZE / HFSTOVCB(hfsmp)->blockSize); + hotfileinfo->maxfilecnt = SWAP_BE32 (HFC_DEFAULT_FILE_COUNT); + strcpy(hotfileinfo->tag, hfc_tag); + offset += kBTreeHeaderUserBytes; + index[(nodesize / 2) - 3] = SWAP_BE16 (offset); + + /* FILL IN THE MAP RECORD (only one node in use). */ + *((u_int8_t *)buffer + offset) = 0x80; + offset += nodesize - sizeof(BTNodeDescriptor) - sizeof(BTHeaderRec) + - kBTreeHeaderUserBytes - (4 * sizeof(int16_t)); + index[(nodesize / 2) - 4] = SWAP_BE16 (offset); + + vp->v_flag |= VNOFLUSH; + error = VOP_TRUNCATE(vp, (off_t)filesize, IO_NDELAY, NOCRED, p); + if (error == 0) { + struct iovec aiov; + struct uio auio; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = buffer; + aiov.iov_len = filesize; + auio.uio_resid = nodesize; + auio.uio_offset = (off_t)(0); + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_procp = (struct proc *)0; + error = VOP_WRITE(vp, &auio, 0, kernproc->p_ucred); + } + kmem_free(kernel_map, (vm_offset_t)buffer, nodesize); + } +out: + (void) VOP_UNLOCK(vp, 0, p); + (void) vn_close(vp, FWRITE, kernproc->p_ucred, p); + vgone(vp); + return (error); +} + +/* + * Compare two hot file b-tree keys. + * + * Result: +n search key > trial key + * 0 search key = trial key + * -n search key < trial key + */ +static int +hfc_comparekeys(HotFileKey *searchKey, HotFileKey *trialKey) +{ + /* + * Compared temperatures first. + */ + if (searchKey->temperature == trialKey->temperature) { + /* + * Temperatures are equal so compare file ids. + */ + if (searchKey->fileID == trialKey->fileID) { + /* + * File ids are equal so compare fork types. + */ + if (searchKey->forkType == trialKey->forkType) { + return (0); + } else if (searchKey->forkType > trialKey->forkType) { + return (1); + } + } else if (searchKey->fileID > trialKey->fileID) { + return (1); + } + } else if (searchKey->temperature > trialKey->temperature) { + return (1); + } + + return (-1); +} + + +/* + *======================================================================== + * HOT FILE DATA COLLECTING ROUTINES + *======================================================================== + */ + +/* + * Lookup a hot file entry in the tree. + */ +static hotfile_entry_t * +hf_lookup(hotfile_data_t *hotdata, u_int32_t fileid, u_int32_t temperature) +{ + hotfile_entry_t *entry = hotdata->rootentry; + + while (entry && + entry->temperature != temperature && + entry->fileid != fileid) { + + if (temperature > entry->temperature) + entry = entry->right; + else if (temperature < entry->temperature) + entry = entry->left; + else if (fileid > entry->fileid) + entry = entry->right; + else + entry = entry->left; + } + return (entry); +} + +/* + * Insert a hot file entry into the tree. + */ +static void +hf_insert(hotfile_data_t *hotdata, hotfile_entry_t *newentry) +{ + hotfile_entry_t *entry = hotdata->rootentry; + u_int32_t fileid = newentry->fileid; + u_int32_t temperature = newentry->temperature; + + if (entry == NULL) { + hotdata->rootentry = newentry; + hotdata->coldest = newentry; + hotdata->activefiles++; + return; + } + + while (entry) { + if (temperature > entry->temperature) { + if (entry->right) + entry = entry->right; + else { + entry->right = newentry; + break; + } + } else if (temperature < entry->temperature) { + if (entry->left) + entry = entry->left; + else { + entry->left = newentry; + break; + } + } else if (fileid > entry->fileid) { + if (entry->right) + entry = entry->right; + else { + if (entry->fileid != fileid) + entry->right = newentry; + break; + } + } else { + if (entry->left) + entry = entry->left; + else { + if (entry->fileid != fileid) + entry->left = newentry; + break; + } + } + } + + hotdata->activefiles++; +} + +/* + * Find the coldest entry in the tree. + */ +static hotfile_entry_t * +hf_coldest(hotfile_data_t *hotdata) +{ + hotfile_entry_t *entry = hotdata->rootentry; + + if (entry) { + while (entry->left) + entry = entry->left; + } + return (entry); +} + +/* + * Delete a hot file entry from the tree. + */ +static void +hf_delete(hotfile_data_t *hotdata, u_int32_t fileid, u_int32_t temperature) +{ + hotfile_entry_t *entry, *parent, *next; + + parent = NULL; + entry = hotdata->rootentry; + + while (entry && + entry->temperature != temperature && + entry->fileid != fileid) { + + parent = entry; + if (temperature > entry->temperature) + entry = entry->right; + else if (temperature < entry->temperature) + entry = entry->left; + else if (fileid > entry->fileid) + entry = entry->right; + else + entry = entry->left; + } + + if (entry) { + /* + * Reorginize the sub-trees spanning from our entry. + */ + if ((next = entry->right)) { + hotfile_entry_t *pnextl, *psub; + /* + * Tree pruning: take the left branch of the + * current entry and place it at the lowest + * left branch of the current right branch + */ + psub = next; + + /* Walk the Right/Left sub tree from current entry */ + while ((pnextl = psub->left)) + psub = pnextl; + + /* Plug the old left tree to the new ->Right leftmost entry */ + psub->left = entry->left; + + } else /* only left sub-tree, simple case */ { + next = entry->left; + } + /* + * Now, plug the current entry sub tree to + * the good pointer of our parent entry. + */ + if (parent == NULL) + hotdata->rootentry = next; + else if (parent->left == entry) + parent->left = next; + else + parent->right = next; + + /* Place entry back on the free-list */ + entry->left = 0; + entry->fileid = 0; + entry->temperature = 0; + + entry->right = hotdata->freelist; + hotdata->freelist = entry; + hotdata->activefiles--; + + if (hotdata->coldest == entry || hotdata->coldest == NULL) { + hotdata->coldest = hf_coldest(hotdata); + } + + } +} + +/* + * Get a free hot file entry. + */ +static hotfile_entry_t * +hf_getnewentry(hotfile_data_t *hotdata) +{ + hotfile_entry_t * entry; + + /* + * When the free list is empty then steal the coldest one + */ + if (hotdata->freelist == NULL) { + entry = hf_coldest(hotdata); + hf_delete(hotdata, entry->fileid, entry->temperature); + } + entry = hotdata->freelist; + hotdata->freelist = entry->right; + entry->right = 0; + + return (entry); +} + + +/* + * Visit the tree in desending order. + */ +static void +hf_sortlist(hotfile_entry_t * root, int *index, hotfilelist_t *sortedlist) +{ + if (root) { + int i; + + hf_sortlist(root->right, index, sortedlist); + i = *index; + ++(*index); + sortedlist->hfl_hotfile[i].hf_fileid = root->fileid; + sortedlist->hfl_hotfile[i].hf_temperature = root->temperature; + sortedlist->hfl_hotfile[i].hf_blocks = root->blocks; + sortedlist->hfl_totalblocks += root->blocks; + hf_sortlist(root->left, index, sortedlist); + } +} + +/* + * Generate a sorted list of hot files. + */ +static int +hf_getsortedlist(hotfile_data_t * hotdata, hotfilelist_t *sortedlist) +{ + int index = 0; + + hf_sortlist(hotdata->rootentry, &index, sortedlist); + + sortedlist->hfl_count = hotdata->activefiles; + + return (index); +} + + +#if HFC_DEBUG +static void +hf_maxdepth(hotfile_entry_t * root, int depth, int *maxdepth) +{ + if (root) { + depth++; + if (depth > *maxdepth) + *maxdepth = depth; + hf_maxdepth(root->left, depth, maxdepth); + hf_maxdepth(root->right, depth, maxdepth); + } +} + +static void +hf_printtree(hotfile_entry_t * root) +{ + if (root) { + hf_printtree(root->left); + printf("temperature: % 8d, fileid %d\n", root->temperature, root->fileid); + hf_printtree(root->right); + } +} +#endif diff -urN xnu-344.49/bsd/hfs/hfs_hotfiles.h xnu-517/bsd/hfs/hfs_hotfiles.h --- xnu-344.49/bsd/hfs/hfs_hotfiles.h Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/hfs/hfs_hotfiles.h Sat Oct 25 00:25:25 2003 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef __HFS_HOTFILES__ +#define __HFS_HOTFILES__ + +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + + +#define HFC_FILENAME ".hotfiles.btree" + + +/* + * Temperature measurement constraints. + */ +#define HFC_DEFAULT_FILE_COUNT 1000 +#define HFC_DEFAULT_DURATION (3600 * 60) +#define HFC_CUMULATIVE_CYCLES 4 +#define HFC_MAXIMUM_FILE_COUNT 5000 +#define HFC_MAXIMUM_FILESIZE (10 * 1024 * 1024) +#define HFC_MINIMUM_TEMPERATURE 16 + + +/* + * Sync constraints. + */ +#define HFC_BLKSPERSYNC 300 +#define HFC_FILESPERSYNC 50 + + +/* + * Hot file clustering stages. + */ +enum hfc_stage { + HFC_DISABLED, + HFC_IDLE, + HFC_BUSY, + HFC_RECORDING, + HFC_EVALUATION, + HFC_EVICTION, + HFC_ADOPTION, +}; + + +/* + * B-tree file key format (on-disk). + */ +struct HotFileKey { + u_int16_t keyLength; /* length of key, excluding this field */ + u_int8_t forkType; /* 0 = data fork, FF = resource fork */ + u_int8_t pad; /* make the other fields align on 32-bit boundary */ + u_int32_t temperature; /* temperature recorded */ + u_int32_t fileID; /* file ID */ +}; +typedef struct HotFileKey HotFileKey; + +#define HFC_LOOKUPTAG 0xFFFFFFFF +#define HFC_KEYLENGTH (sizeof(HotFileKey) - sizeof(u_int16_t)) + +/* + * B-tree header node user info (on-disk). + */ +struct HotFilesInfo { + u_int32_t magic; + u_int32_t version; + u_int32_t duration; /* duration of sample period */ + u_int32_t timebase; /* recording period start time */ + u_int32_t timeleft; /* recording period stop time */ + u_int32_t threshold; + u_int32_t maxfileblks; + u_int32_t maxfilecnt; + u_int8_t tag[32]; +}; +typedef struct HotFilesInfo HotFilesInfo; + +#define HFC_MAGIC 0xFF28FF26 +#define HFC_VERSION 1 + + +struct hfsmount; +struct proc; +struct vnode; + +/* + * Hot File interface functions. + */ +int hfs_hotfilesync (struct hfsmount *, struct proc *); + +int hfs_recording_init(struct hfsmount *, struct proc *); +int hfs_recording_start (struct hfsmount *, struct proc *); +int hfs_recording_stop (struct hfsmount *, struct proc *); +int hfs_recording_suspend (struct hfsmount *, struct proc *); +int hfs_recording_abort (struct hfsmount *, struct proc *); + +int hfs_addhotfile (struct vnode *); +int hfs_removehotfile (struct vnode *); + +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#endif /* __HFS_HOTFILES__ */ diff -urN xnu-344.49/bsd/hfs/hfs_link.c xnu-517/bsd/hfs/hfs_link.c --- xnu-344.49/bsd/hfs/hfs_link.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_link.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -116,6 +116,7 @@ struct cat_desc to_desc; int newlink = 0; int retval; + cat_cookie_t cookie = {0}; /* We don't allow link nodes in our Private Meta Data folder! */ @@ -125,10 +126,15 @@ if (hfs_freeblks(hfsmp, 0) == 0) return (ENOSPC); + /* Reserve some space in the Catalog file. */ + if ((retval = cat_preflight(hfsmp, (2 * CAT_CREATE)+ CAT_RENAME, &cookie, p))) { + return (retval); + } + /* Lock catalog b-tree */ retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); if (retval) { - return retval; + goto out2; } /* @@ -219,7 +225,8 @@ out: /* Unlock catalog b-tree */ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - +out2: + cat_postflight(hfsmp, &cookie, p); return (retval); } @@ -235,6 +242,7 @@ IN struct componentname *cnp; */ +__private_extern__ int hfs_link(ap) struct vop_link_args /* { @@ -267,7 +275,7 @@ if (VTOVCB(tdvp)->vcbSigWord != kHFSPlusSigWord) return err_link(ap); /* hfs disks don't support hard links */ - if (hfsmp->hfs_private_metadata_dir == 0) + if (hfsmp->hfs_privdir_desc.cd_cnid == 0) return err_link(ap); /* no private metadata dir, no links possible */ if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) { @@ -329,12 +337,22 @@ // XXXdbg - need to do this here as well because cp could have changed error = VOP_UPDATE(vp, &tv, &tv, 1); - FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); if (hfsmp->jnl) { journal_end_transaction(hfsmp->jnl); } hfs_global_shared_lock_release(hfsmp); + + /* free the pathname buffer */ + { + char *tmp = cnp->cn_pnbuf; + cnp->cn_pnbuf = NULL; + cnp->cn_flags &= ~HASBUF; + FREE_ZONE(tmp, cnp->cn_pnlen, M_NAMEI); + } + + HFS_KNOTE(vp, NOTE_LINK); + HFS_KNOTE(tdvp, NOTE_WRITE); out1: if (tdvp != vp) diff -urN xnu-344.49/bsd/hfs/hfs_lookup.c xnu-517/bsd/hfs/hfs_lookup.c --- xnu-344.49/bsd/hfs/hfs_lookup.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_lookup.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -274,16 +274,15 @@ retval = EJUSTRETURN; goto exit; } - + /* * Insert name into cache (as non-existent) if appropriate. * - * Disable negative caching since HFS is case-insensitive. + * Only done for case-sensitive HFS+ volumes. */ -#if 0 - if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) + if ((hfsmp->hfs_flags & HFS_CASE_SENSITIVE) && + (cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) cache_enter(dvp, *vpp, cnp); -#endif retval = ENOENT; goto exit; } @@ -456,6 +455,34 @@ cache_enter(dvp, *vpp, cnp); } + + // + // have to patch up the resource fork name because + // it won't happen properly in the layers above us. + // + if (wantrsrc) { + if (VTOC(*vpp)->c_vp == NULL) { + if (VNAME(*vpp) == NULL) { + VNAME(*vpp) = add_name(cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_hash, 0); + } + if (VPARENT(*vpp) == NULL) { + vget(dvp, 0, p); + VPARENT(*vpp) = dvp; + } + } else { + if (VNAME(*vpp) == NULL) { + // the +1/-2 thing is to skip the leading "/" on the rsrc fork spec + // and to not count the trailing null byte at the end of the string. + VNAME(*vpp) = add_name(_PATH_RSRCFORKSPEC+1, sizeof(_PATH_RSRCFORKSPEC)-2, 0, 0); + } + if (VPARENT(*vpp) == NULL && *vpp != VTOC(*vpp)->c_vp) { + VPARENT(*vpp) = VTOC(*vpp)->c_vp; + VTOC(*vpp)->c_flag |= C_VPREFHELD; + vget(VTOC(*vpp)->c_vp, 0, p); + } + } + } + exit: cat_releasedesc(&desc); return (retval); @@ -483,6 +510,8 @@ * */ +#define S_IXALL 0000111 + __private_extern__ int hfs_cache_lookup(ap) @@ -495,16 +524,15 @@ struct vnode *dvp; struct vnode *vp; struct cnode *cp; + struct cnode *dcp; int lockparent; int error; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; - struct ucred *cred = cnp->cn_cred; int flags = cnp->cn_flags; struct proc *p = cnp->cn_proc; u_long vpid; /* capability number of vnode */ - *vpp = NULL; dvp = ap->a_dvp; lockparent = flags & LOCKPARENT; @@ -514,11 +542,17 @@ if (dvp->v_type != VDIR) return (ENOTDIR); if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) - return (EROFS); - if ((error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc))) - return (error); + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { + error = EROFS; + goto err_exit; + } + dcp = VTOC(dvp); + if (((dcp->c_mode & S_IXALL) != S_IXALL) && (cnp->cn_cred->cr_uid != 0)) { + if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))) { + goto err_exit; + } + } /* * Lookup an entry in the cache * If the lookup succeeds, the vnode is returned in *vpp, and a status of -1 is @@ -527,14 +561,15 @@ * fails, a status of zero is returned. */ error = cache_lookup(dvp, vpp, cnp); - if (error == 0) { /* Unsuccessfull */ - error = hfs_lookup(ap); - return (error); + if (error != -1) { + if (error == 0) { /* Unsuccessfull */ + goto lookup; + } + + if (error == ENOENT) { + goto err_exit; + } } - - if (error == ENOENT) - return (error); - /* We have a name that matched */ vp = *vpp; vpid = vp->v_id; @@ -583,20 +618,51 @@ int wantrsrc = 0; cnp->cn_consume = forkcomponent(cnp, &wantrsrc); - - /* Fork names are only for lookups */ - if (cnp->cn_consume && - (cnp->cn_nameiop != LOOKUP && cnp->cn_nameiop != CREATE)) - return (EPERM); - /* - * We only store data forks in the name cache. - */ - if (wantrsrc) - return (hfs_lookup(ap)); + if (cnp->cn_consume) { + flags |= ISLASTCN; + /* Fork names are only for lookups */ + if (cnp->cn_nameiop != LOOKUP && + cnp->cn_nameiop != CREATE) { + error = EPERM; + + goto err_exit; + } + } + + if (wantrsrc) { + /* Use cnode's rsrcfork vnode (if available) */ + if (cp->c_rsrc_vp != NULL) { + *vpp = vp = cp->c_rsrc_vp; + if (VNAME(vp) == NULL) { + // the +1/-2 thing is to skip the leading "/" on the rsrc fork spec + // and to not count the trailing null byte at the end of the string. + VNAME(vp) = add_name(_PATH_RSRCFORKSPEC+1, sizeof(_PATH_RSRCFORKSPEC)-2, 0, 0); + } + if (VPARENT(vp) == NULL) { + vget(cp->c_vp, 0, p); + VPARENT(vp) = cp->c_vp; + } + vpid = vp->v_id; + } else { + goto lookup; + } + } + } + error = vget(vp, 0, p); + if (error == 0) { + if (VTOC(vp) == NULL || vp->v_data != (void *)cp) { + panic("hfs: cache lookup: my cnode disappeared/went bad! vp 0x%x 0x%x 0x%x\n", + vp, vp->v_data, cp); + } + if (cnp->cn_nameiop == LOOKUP && + (!(flags & ISLASTCN) || (flags & SHAREDLEAF))) + error = lockmgr(&VTOC(vp)->c_lock, LK_SHARED, NULL, p); + else + error = lockmgr(&VTOC(vp)->c_lock, LK_EXCLUSIVE, NULL, p); + } + if (!lockparent || error || !(flags & ISLASTCN)) { + (void) lockmgr(&dcp->c_lock, LK_RELEASE, NULL, p); } - error = vget(vp, LK_EXCLUSIVE, p); - if (!lockparent || error || !(flags & ISLASTCN)) - VOP_UNLOCK(dvp, 0, p); } /* * Check that the capability number did not change @@ -616,8 +682,12 @@ if ((error = vn_lock(dvp, LK_EXCLUSIVE, p))) return (error); - +lookup: return (hfs_lookup(ap)); + +err_exit: + *vpp = NULL; + return (error); } diff -urN xnu-344.49/bsd/hfs/hfs_mount.h xnu-517/bsd/hfs/hfs_mount.h --- xnu-344.49/bsd/hfs/hfs_mount.h Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_mount.h Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,17 @@ #define HFSFSMNT_NOXONFILES 0x1 /* disable execute permissions for files */ #define HFSFSMNT_WRAPPER 0x2 /* mount HFS wrapper (if it exists) */ #define HFSFSMNT_EXTENDED_ARGS 0x4 /* indicates new fields after "flags" are valid */ + +/* + * Sysctl values for HFS + */ +#define HFS_ENCODINGBIAS 1 /* encoding matching CJK bias */ +#define HFS_EXTEND_FS 2 +#define HFS_ENCODINGHINT 3 /* guess encoding for string */ +#define HFS_ENABLE_JOURNALING 0x082969 +#define HFS_DISABLE_JOURNALING 0x031272 +#define HFS_GET_JOURNAL_INFO 0x6a6e6c69 +#define HFS_SET_PKG_EXTENSIONS 0x121031 #endif /* __APPLE_API_UNSTABLE */ diff -urN xnu-344.49/bsd/hfs/hfs_notification.c xnu-517/bsd/hfs/hfs_notification.c --- xnu-344.49/bsd/hfs/hfs_notification.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/hfs/hfs_notification.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hfs.h" +#include "hfs_catalog.h" +#include "hfs_cnode.h" +#include "hfs_lockf.h" +#include "hfs_dbg.h" +#include "hfs_mount.h" +#include "hfs_quota.h" +#include "hfs_endian.h" + +#include "hfscommon/headers/BTreesInternal.h" +#include "hfscommon/headers/FileMgrInternal.h" + + + +void hfs_generate_volume_notifications(struct hfsmount *hfsmp) { + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + + if (hfsmp->hfs_notification_conditions & VQ_LOWDISK) { + /* Check to see whether the free space is back above the minimal level: */ + if (hfs_freeblks(hfsmp, 1) > hfsmp->hfs_freespace_notify_desiredlevel) { + hfsmp->hfs_notification_conditions &= ~VQ_LOWDISK; + vfs_event_signal(&HFSTOVFS(hfsmp)->mnt_stat.f_fsid, hfsmp->hfs_notification_conditions, NULL); + } + } else { + /* Check to see whether the free space fell below the requested limit: */ + if (hfs_freeblks(hfsmp, 1) < hfsmp->hfs_freespace_notify_warninglimit) { + hfsmp->hfs_notification_conditions |= VQ_LOWDISK; + vfs_event_signal(&HFSTOVFS(hfsmp)->mnt_stat.f_fsid, hfsmp->hfs_notification_conditions, NULL); + } + }; +} diff -urN xnu-344.49/bsd/hfs/hfs_quota.c xnu-517/bsd/hfs/hfs_quota.c --- xnu-344.49/bsd/hfs/hfs_quota.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_quota.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -707,11 +707,9 @@ for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) { if (vp->v_mount != mp) goto again; - nextvp = vp->v_mntvnodes.le_next; simple_lock(&vp->v_interlock); simple_unlock(&mntvnode_slock); - error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); if (error) { simple_lock(&mntvnode_slock); @@ -720,13 +718,11 @@ continue; } - // Make sure that this is really an hfs vnode. - // - if ( vp->v_mount != mp - || vp->v_type == VNON - || vp->v_tag != VT_HFS - || VTOC(vp) == NULL) { - + /* Make sure that this is really an hfs vnode. */ + if (vp->v_mount != mp || + vp->v_type == VNON || + vp->v_tag != VT_HFS || + VTOC(vp) == NULL) { vput(vp); simple_lock(&mntvnode_slock); goto again; diff -urN xnu-344.49/bsd/hfs/hfs_readwrite.c xnu-517/bsd/hfs/hfs_readwrite.c --- xnu-344.49/bsd/hfs/hfs_readwrite.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_readwrite.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,10 @@ extern u_int32_t GetLogicalBlockSize(struct vnode *vp); +static int hfs_clonelink(struct vnode *, int, struct ucred *, struct proc *); +static int hfs_clonefile(struct vnode *, int, int, int, struct ucred *, struct proc *); +static int hfs_clonesysfile(struct vnode *, int, int, int, struct ucred *, struct proc *); + /***************************************************************************** * @@ -97,18 +102,16 @@ register struct vnode *vp = ap->a_vp; struct cnode *cp; struct filefork *fp; - struct buf *bp; - daddr_t logBlockNo; - u_long fragSize, moveSize, startOffset, ioxfersize; int devBlockSize = 0; - off_t bytesRemaining; int retval = 0; off_t filesize; off_t filebytes; + off_t start_resid = uio->uio_resid; + /* Preflight checks */ - if (vp->v_type != VREG && vp->v_type != VLNK) - return (EISDIR); /* HFS can only read files */ + if ((vp->v_type != VREG) || !UBCINFOEXISTS(vp)) + return (EPERM); /* can only read regular files */ if (uio->uio_resid == 0) return (0); /* Nothing left to do */ if (uio->uio_offset < 0) @@ -130,105 +133,29 @@ KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START, (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0); - if (UBCISVALID(vp)) { - retval = cluster_read(vp, uio, filesize, devBlockSize, 0); - } else { - - for (retval = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { - - if ((bytesRemaining = (filesize - uio->uio_offset)) <= 0) - break; - - logBlockNo = (daddr_t)(uio->uio_offset / PAGE_SIZE_64); - startOffset = (u_long) (uio->uio_offset & PAGE_MASK_64); - fragSize = PAGE_SIZE; - - if (((logBlockNo * PAGE_SIZE) + fragSize) < filesize) - ioxfersize = fragSize; - else { - ioxfersize = filesize - (logBlockNo * PAGE_SIZE); - ioxfersize = (ioxfersize + (devBlockSize - 1)) & ~(devBlockSize - 1); - } - moveSize = ioxfersize; - moveSize -= startOffset; - - if (bytesRemaining < moveSize) - moveSize = bytesRemaining; - - if (uio->uio_resid < moveSize) { - moveSize = uio->uio_resid; - }; - if (moveSize == 0) { - break; - }; - - if (( uio->uio_offset + fragSize) >= filesize) { - retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp); - - } else if (logBlockNo - 1 == vp->v_lastr && !(vp->v_flag & VRAOFF)) { - daddr_t nextLogBlockNo = logBlockNo + 1; - int nextsize; - - if (((nextLogBlockNo * PAGE_SIZE) + - (daddr_t)fragSize) < filesize) - nextsize = fragSize; - else { - nextsize = filesize - (nextLogBlockNo * PAGE_SIZE); - nextsize = (nextsize + (devBlockSize - 1)) & ~(devBlockSize - 1); - } - retval = breadn(vp, logBlockNo, ioxfersize, &nextLogBlockNo, &nextsize, 1, NOCRED, &bp); - } else { - retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp); - }; - - if (retval != E_NONE) { - if (bp) { - brelse(bp); - bp = NULL; - } - break; - }; - vp->v_lastr = logBlockNo; - - /* - * We should only get non-zero b_resid when an I/O retval - * has occurred, which should cause us to break above. - * However, if the short read did not cause an retval, - * then we want to ensure that we do not uiomove bad - * or uninitialized data. - */ - ioxfersize -= bp->b_resid; - - if (ioxfersize < moveSize) { /* XXX PPD This should take the offset into account, too! */ - if (ioxfersize == 0) - break; - moveSize = ioxfersize; - } - if ((startOffset + moveSize) > bp->b_bcount) - panic("hfs_read: bad startOffset or moveSize\n"); - - if ((retval = uiomove((caddr_t)bp->b_data + startOffset, (int)moveSize, uio))) - break; - - if (S_ISREG(cp->c_mode) && - (((startOffset + moveSize) == fragSize) || (uio->uio_offset == filesize))) { - bp->b_flags |= B_AGE; - }; - - brelse(bp); - /* Start of loop resets bp to NULL before reaching outside this block... */ - } - - if (bp != NULL) { - brelse(bp); - } - } + retval = cluster_read(vp, uio, filesize, devBlockSize, 0); cp->c_flag |= C_ACCESS; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END, (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0); + /* + * Keep track blocks read + */ + if (VTOHFS(vp)->hfc_stage == HFC_RECORDING && retval == 0) { + /* + * If this file hasn't been seen since the start of + * the current sampling period then start over. + */ + if (cp->c_atime < VTOHFS(vp)->hfc_timebase) { + fp->ff_bytesread = start_resid - uio->uio_resid; + cp->c_atime = time.tv_sec; + } else { + fp->ff_bytesread += start_resid - uio->uio_resid; + } + } + return (retval); } @@ -256,37 +183,32 @@ struct uio *uio = ap->a_uio; struct cnode *cp; struct filefork *fp; - struct buf *bp; struct proc *p; struct timeval tv; ExtendedVCB *vcb; - int devBlockSize = 0; - daddr_t logBlockNo; - long fragSize; - off_t origFileSize, currOffset, writelimit, bytesToAdd; - off_t actualBytesAdded; - u_long blkoffset, resid, xfersize, clearSize; - int eflags, ioflag; - int retval; + int devBlockSize = 0; + off_t origFileSize, writelimit, bytesToAdd; + off_t actualBytesAdded; + u_long resid; + int eflags, ioflag; + int retval; off_t filebytes; - u_long fileblocks; struct hfsmount *hfsmp; int started_tr = 0, grabbed_lock = 0; - ioflag = ap->a_ioflag; if (uio->uio_offset < 0) return (EINVAL); if (uio->uio_resid == 0) return (E_NONE); - if (vp->v_type != VREG && vp->v_type != VLNK) - return (EISDIR); /* Can only write files */ + if ((vp->v_type != VREG) || !UBCINFOEXISTS(vp)) + return (EPERM); /* Can only write regular files */ + ioflag = ap->a_ioflag; cp = VTOC(vp); fp = VTOF(vp); vcb = VTOVCB(vp); - fileblocks = fp->ff_blocks; - filebytes = (off_t)fileblocks * (off_t)vcb->blockSize; + filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize; if (ioflag & IO_APPEND) uio->uio_offset = fp->ff_size; @@ -297,7 +219,7 @@ if (VTOHFS(vp)->jnl && cp->c_datafork) { struct HFSPlusExtentDescriptor *extd; - extd = &cp->c_datafork->ff_data.cf_extents[0]; + extd = &cp->c_datafork->ff_extents[0]; if (extd->startBlock == VTOVCB(vp)->vcbJinfoBlock || extd->startBlock == VTOHFS(vp)->jnl_start) { return EPERM; } @@ -324,19 +246,6 @@ eflags = kEFDeferMask; /* defer file block allocations */ filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize; - /* - * NOTE: In the following loop there are two positions tracked: - * currOffset is the current I/O starting offset. currOffset - * is never >LEOF; the LEOF is nudged along with currOffset as - * data is zeroed or written. uio->uio_offset is the start of - * the current I/O operation. It may be arbitrarily beyond - * currOffset. - * - * The following is true at all times: - * currOffset <= LEOF <= uio->uio_offset <= writelimit - */ - currOffset = MIN(uio->uio_offset, fp->ff_size); - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_START, (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0); retval = 0; @@ -356,6 +265,20 @@ #endif /* QUOTA */ hfsmp = VTOHFS(vp); + +#ifdef HFS_SPARSE_DEV + /* + * When the underlying device is sparse and space + * is low (< 8MB), stop doing delayed allocations + * and begin doing synchronous I/O. + */ + if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) && + (hfs_freeblks(hfsmp, 0) < 2048)) { + eflags &= ~kEFDeferMask; + ioflag |= IO_SYNC; + } +#endif /* HFS_SPARSE_DEV */ + if (writelimit > filebytes) { hfs_global_shared_lock_acquire(hfsmp); grabbed_lock = 1; @@ -369,16 +292,19 @@ } while (writelimit > filebytes) { - bytesToAdd = writelimit - filebytes; - if (suser(ap->a_cred, NULL) != 0) + if (ap->a_cred && suser(ap->a_cred, NULL) != 0) eflags |= kEFReserveMask; /* lock extents b-tree (also protects volume bitmap) */ retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, current_proc()); if (retval != E_NONE) break; - + + /* Files that are changing size are not hot file candidates. */ + if (hfsmp->hfc_stage == HFC_RECORDING) { + fp->ff_bytesread = 0; + } retval = MacToVFSError(ExtendFileC (vcb, (FCB*)fp, bytesToAdd, 0, eflags, &actualBytesAdded)); @@ -394,6 +320,9 @@ // XXXdbg if (started_tr) { + tv = time; + VOP_UPDATE(vp, &tv, &tv, 1); + hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); journal_end_transaction(hfsmp->jnl); started_tr = 0; @@ -403,7 +332,7 @@ grabbed_lock = 0; } - if (UBCISVALID(vp) && retval == E_NONE) { + if (retval == E_NONE) { off_t filesize; off_t zero_off; off_t tail_off; @@ -427,8 +356,10 @@ of the transfer to see whether is invalid and should be zero-filled as part of the transfer: */ - if (rl_scan(&fp->ff_invalidranges, zero_off, uio->uio_offset - 1, &invalid_range) != RL_NOOVERLAP) - lflag |= IO_HEADZEROFILL; + if (uio->uio_offset > zero_off) { + if (rl_scan(&fp->ff_invalidranges, zero_off, uio->uio_offset - 1, &invalid_range) != RL_NOOVERLAP) + lflag |= IO_HEADZEROFILL; + } } else { off_t eof_page_base = fp->ff_size & ~PAGE_MASK_64; @@ -528,105 +459,10 @@ } if (resid > uio->uio_resid) cp->c_flag |= C_CHANGE | C_UPDATE; - } else { - while (retval == E_NONE && uio->uio_resid > 0) { - logBlockNo = currOffset / PAGE_SIZE; - blkoffset = currOffset & PAGE_MASK; - - if ((filebytes - currOffset) < PAGE_SIZE_64) - fragSize = filebytes - ((off_t)logBlockNo * PAGE_SIZE_64); - else - fragSize = PAGE_SIZE; - xfersize = fragSize - blkoffset; - - /* Make any adjustments for boundary conditions */ - if (currOffset + (off_t)xfersize > writelimit) - xfersize = writelimit - currOffset; - - /* - * There is no need to read into bp if: - * We start on a block boundary and will overwrite the whole block - * - * OR - */ - if ((blkoffset == 0) && (xfersize >= fragSize)) { - bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ); - retval = 0; - - if (bp->b_blkno == -1) { - brelse(bp); - retval = EIO; /* XXX */ - break; - } - } else { - - if (currOffset == fp->ff_size && blkoffset == 0) { - bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ); - retval = 0; - if (bp->b_blkno == -1) { - brelse(bp); - retval = EIO; /* XXX */ - break; - } - } else { - /* - * This I/O transfer is not sufficiently aligned, - * so read the affected block into a buffer: - */ - retval = bread(vp, logBlockNo, fragSize, ap->a_cred, &bp); - if (retval != E_NONE) { - if (bp) - brelse(bp); - break; - } - } - } - - /* See if we are starting to write within file boundaries: - * If not, then we need to present a "hole" for the area - * between the current EOF and the start of the current - * I/O operation: - * - * Note that currOffset is only less than uio_offset if - * uio_offset > LEOF... - */ - if (uio->uio_offset > currOffset) { - clearSize = MIN(uio->uio_offset - currOffset, xfersize); - bzero(bp->b_data + blkoffset, clearSize); - currOffset += clearSize; - blkoffset += clearSize; - xfersize -= clearSize; - } - - if (xfersize > 0) { - retval = uiomove((caddr_t)bp->b_data + blkoffset, (int)xfersize, uio); - currOffset += xfersize; - } - - if (ioflag & IO_SYNC) { - (void)VOP_BWRITE(bp); - } else if ((xfersize + blkoffset) == fragSize) { - bp->b_flags |= B_AGE; - bawrite(bp); - } else { - bdwrite(bp); - } - - /* Update the EOF if we just extended the file - * (the PEOF has already been moved out and the - * block mapping table has been updated): - */ - if (currOffset > fp->ff_size) { - fp->ff_size = currOffset; - if (UBCISVALID(vp)) - ubc_setsize(vp, fp->ff_size); /* XXX check errors */ - } - if (retval || (resid == 0)) - break; - cp->c_flag |= C_CHANGE | C_UPDATE; - } /* endwhile */ } + HFS_KNOTE(vp, NOTE_WRITE); + ioerr_exit: /* * If we successfully wrote any data, and we are not the superuser @@ -648,6 +484,7 @@ tv = time; retval = VOP_UPDATE(vp, &tv, &tv, 1); } + vcb->vcbWrCnt++; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_END, (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0); @@ -656,6 +493,22 @@ } +#ifdef HFS_SPARSE_DEV +struct hfs_backingstoreinfo { + int signature; /* == 3419115 */ + int version; /* version of this struct (1) */ + int backingfd; /* disk image file (on backing fs) */ + int bandsize; /* sparse disk image band size */ +}; + +#define HFSIOC_SETBACKINGSTOREINFO _IOW('h', 7, struct hfs_backingstoreinfo) +#define HFSIOC_CLRBACKINGSTOREINFO _IO('h', 8) + +#define HFS_SETBACKINGSTOREINFO IOCBASECMD(HFSIOC_SETBACKINGSTOREINFO) +#define HFS_CLRBACKINGSTOREINFO IOCBASECMD(HFSIOC_CLRBACKINGSTOREINFO) + +#endif /* HFS_SPARSE_DEV */ + /* #% ioctl vp U U U @@ -684,10 +537,127 @@ } */ *ap; { switch (ap->a_command) { - case 1: { + +#ifdef HFS_SPARSE_DEV + case HFS_SETBACKINGSTOREINFO: { + struct hfsmount * hfsmp; + struct vnode * bsfs_rootvp; + struct vnode * di_vp; + struct file * di_fp; + struct hfs_backingstoreinfo *bsdata; + int error = 0; + + hfsmp = VTOHFS(ap->a_vp); + if (hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) { + return (EALREADY); + } + if (ap->a_p->p_ucred->cr_uid != 0 && + ap->a_p->p_ucred->cr_uid != (HFSTOVFS(hfsmp))->mnt_stat.f_owner) { + return (EACCES); /* must be owner of file system */ + } + bsdata = (struct hfs_backingstoreinfo *)ap->a_data; + if (bsdata == NULL) { + return (EINVAL); + } + if (error = fdgetf(ap->a_p, bsdata->backingfd, &di_fp)) { + return (error); + } + if (fref(di_fp) == -1) { + return (EBADF); + } + if (di_fp->f_type != DTYPE_VNODE) { + frele(di_fp); + return (EINVAL); + } + di_vp = (struct vnode *)di_fp->f_data; + if (ap->a_vp->v_mount == di_vp->v_mount) { + frele(di_fp); + return (EINVAL); + } + + /* + * Obtain the backing fs root vnode and keep a reference + * on it. This reference will be dropped in hfs_unmount. + */ + error = VFS_ROOT(di_vp->v_mount, &bsfs_rootvp); + if (error) { + frele(di_fp); + return (error); + } + VOP_UNLOCK(bsfs_rootvp, 0, ap->a_p); /* Hold on to the reference */ + + hfsmp->hfs_backingfs_rootvp = bsfs_rootvp; + hfsmp->hfs_flags |= HFS_HAS_SPARSE_DEVICE; + hfsmp->hfs_sparsebandblks = bsdata->bandsize / HFSTOVCB(hfsmp)->blockSize; + hfsmp->hfs_sparsebandblks *= 4; + + frele(di_fp); + return (0); + } + case HFS_CLRBACKINGSTOREINFO: { + struct hfsmount * hfsmp; + struct vnode * tmpvp; + + hfsmp = VTOHFS(ap->a_vp); + if (ap->a_p->p_ucred->cr_uid != 0 && + ap->a_p->p_ucred->cr_uid != (HFSTOVFS(hfsmp))->mnt_stat.f_owner) { + return (EACCES); /* must be owner of file system */ + } + if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) && + hfsmp->hfs_backingfs_rootvp) { + + hfsmp->hfs_flags &= ~HFS_HAS_SPARSE_DEVICE; + tmpvp = hfsmp->hfs_backingfs_rootvp; + hfsmp->hfs_backingfs_rootvp = NULLVP; + hfsmp->hfs_sparsebandblks = 0; + vrele(tmpvp); + } + return (0); + } +#endif /* HFS_SPARSE_DEV */ + + case 6: { + int error; + + ap->a_vp->v_flag |= VFULLFSYNC; + error = VOP_FSYNC(ap->a_vp, ap->a_cred, MNT_NOWAIT, ap->a_p); + ap->a_vp->v_flag &= ~VFULLFSYNC; + + return error; + } + case 5: { + register struct vnode *vp; register struct cnode *cp; + struct filefork *fp; + int error; + + vp = ap->a_vp; + cp = VTOC(vp); + fp = VTOF(vp); + + if (vp->v_type != VREG) + return EINVAL; + + VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ); + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p); + if (error) + return (error); + + /* + * used by regression test to determine if + * all the dirty pages (via write) have been cleaned + * after a call to 'fsysnc'. + */ + error = is_file_clean(vp, fp->ff_size); + VOP_UNLOCK(vp, 0, ap->a_p); + + return (error); + } + + case 1: { register struct vnode *vp; register struct radvisory *ra; + register struct cnode *cp; struct filefork *fp; int devBlockSize = 0; int error; @@ -992,6 +962,7 @@ struct rl_entry *invalid_range; enum rl_overlaptype overlaptype; int started_tr = 0, grabbed_lock = 0; + struct timeval tv; /* * Check for underlying vnode requests and ensure that logical @@ -1001,6 +972,17 @@ return (0); p = current_proc(); + + if (ISSET(VTOC(ap->a_vp)->c_flag, C_NOBLKMAP)) { + /* + * File blocks are getting remapped. Wait until its finished. + */ + SET(VTOC(ap->a_vp)->c_flag, C_WBLKMAP); + (void) tsleep((caddr_t)VTOC(ap->a_vp), PINOD, "hfs_cmap", 0); + if (ISSET(VTOC(ap->a_vp)->c_flag, C_NOBLKMAP)) + panic("hfs_cmap: no mappable blocks"); + } + retry: if (fp->ff_unallocblocks) { lockExtBtree = 1; @@ -1040,7 +1022,7 @@ if (fp->ff_unallocblocks) { SInt64 reqbytes, actbytes; - // + // // Make sure we have a transaction. It's possible // that we came in and fp->ff_unallocblocks was zero // but during the time we blocked acquiring the extents @@ -1052,7 +1034,7 @@ (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p); lockExtBtree = 0; } - + goto retry; } @@ -1071,6 +1053,10 @@ fp->ff_blocks -= fp->ff_unallocblocks; fp->ff_unallocblocks = 0; + /* Files that are changing size are not hot file candidates. */ + if (hfsmp->hfc_stage == HFC_RECORDING) { + fp->ff_bytesread = 0; + } while (retval == 0 && reqbytes > 0) { retval = MacToVFSError(ExtendFileC(HFSTOVCB(hfsmp), (FCB*)fp, reqbytes, 0, @@ -1090,7 +1076,11 @@ if (retval) { (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p); + VTOC(ap->a_vp)->c_flag |= C_MODIFIED; if (started_tr) { + tv = time; + VOP_UPDATE(ap->a_vp, &tv, &tv, 1); + hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); journal_end_transaction(hfsmp->jnl); } @@ -1099,7 +1089,6 @@ } return (retval); } - VTOC(ap->a_vp)->c_flag |= C_MODIFIED; } retval = MacToVFSError( @@ -1115,6 +1104,9 @@ // XXXdbg if (started_tr) { + tv = time; + retval = VOP_UPDATE(ap->a_vp, &tv, &tv, 1); + hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); journal_end_transaction(hfsmp->jnl); started_tr = 0; @@ -1361,21 +1353,7 @@ } -/* -# -#% truncate vp L L L -# -vop_truncate { - IN struct vnode *vp; - IN off_t length; - IN int flags; (IO_SYNC) - IN struct ucred *cred; - IN struct proc *p; -}; - * Truncate a cnode to at most length size, freeing (or adding) the - * disk blocks. - */ -int hfs_truncate(ap) +static int do_hfs_truncate(ap) struct vop_truncate_args /* { struct vnode *a_vp; off_t a_length; @@ -1420,6 +1398,11 @@ tv = time; retval = E_NONE; + /* Files that are changing size are not hot file candidates. */ + if (hfsmp->hfc_stage == HFC_RECORDING) { + fp->ff_bytesread = 0; + } + /* * We cannot just check if fp->ff_size == length (as an optimization) * since there may be extra physical blocks that also need truncation. @@ -1447,13 +1430,23 @@ */ if (length > filebytes) { int eflags; + u_long blockHint = 0; /* All or nothing and don't round up to clumpsize. */ eflags = kEFAllMask | kEFNoClumpMask; - if (suser(ap->a_cred, NULL) != 0) + if (ap->a_cred && suser(ap->a_cred, NULL) != 0) eflags |= kEFReserveMask; /* keep a reserve */ + /* + * Allocate Journal and Quota files in metadata zone. + */ + if (filebytes == 0 && + hfsmp->hfs_flags & HFS_METADATA_ZONE && + hfs_virtualmetafile(cp)) { + eflags |= kEFMetadataMask; + blockHint = hfsmp->hfs_metazone_start; + } // XXXdbg hfs_global_shared_lock_acquire(hfsmp); if (hfsmp->jnl) { @@ -1479,7 +1472,7 @@ retval = MacToVFSError(ExtendFileC(VTOVCB(vp), (FCB*)fp, bytesToAdd, - 0, + blockHint, eflags, &actualBytesAdded)); @@ -1495,6 +1488,9 @@ // XXXdbg if (hfsmp->jnl) { + tv = time; + VOP_UPDATE(vp, &tv, &tv, 1); + hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); journal_end_transaction(hfsmp->jnl); } @@ -1642,6 +1638,9 @@ // XXXdbg if (hfsmp->jnl) { + tv = time; + VOP_UPDATE(vp, &tv, &tv, 1); + hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); journal_end_transaction(hfsmp->jnl); } @@ -1676,6 +1675,83 @@ } +/* +# +#% truncate vp L L L +# +vop_truncate { + IN struct vnode *vp; + IN off_t length; + IN int flags; (IO_SYNC) + IN struct ucred *cred; + IN struct proc *p; +}; + * Truncate a cnode to at most length size, freeing (or adding) the + * disk blocks. + */ +int hfs_truncate(ap) + struct vop_truncate_args /* { + struct vnode *a_vp; + off_t a_length; + int a_flags; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + register struct vnode *vp = ap->a_vp; + register struct cnode *cp = VTOC(vp); + struct filefork *fp = VTOF(vp); + off_t length; + off_t filebytes; + u_long fileblocks; + int blksize, error; + u_int64_t nsize; + + if (vp->v_type != VREG && vp->v_type != VLNK) + return (EISDIR); /* cannot truncate an HFS directory! */ + + length = ap->a_length; + blksize = VTOVCB(vp)->blockSize; + fileblocks = fp->ff_blocks; + filebytes = (off_t)fileblocks * (off_t)blksize; + + // have to loop truncating or growing files that are + // really big because otherwise transactions can get + // enormous and consume too many kernel resources. + if (length < filebytes && (filebytes - length) > HFS_BIGFILE_SIZE) { + while (filebytes > length) { + if ((filebytes - length) > HFS_BIGFILE_SIZE) { + filebytes -= HFS_BIGFILE_SIZE; + } else { + filebytes = length; + } + + ap->a_length = filebytes; + error = do_hfs_truncate(ap); + if (error) + break; + } + } else if (length > filebytes && (length - filebytes) > HFS_BIGFILE_SIZE) { + while (filebytes < length) { + if ((length - filebytes) > HFS_BIGFILE_SIZE) { + filebytes += HFS_BIGFILE_SIZE; + } else { + filebytes = (length - filebytes); + } + + ap->a_length = filebytes; + error = do_hfs_truncate(ap); + if (error) + break; + } + } else { + error = do_hfs_truncate(ap); + } + + return error; +} + + /* # @@ -1706,6 +1782,7 @@ struct vnode *vp = ap->a_vp; struct cnode *cp = VTOC(vp); struct filefork *fp = VTOF(vp); + ExtendedVCB *vcb = VTOVCB(vp); off_t length = ap->a_length; off_t startingPEOF; off_t moreBytesRequested; @@ -1716,31 +1793,30 @@ struct timeval tv; int retval, retval2; UInt32 blockHint; - UInt32 extendFlags =0; /* For call to ExtendFileC */ + UInt32 extendFlags; /* For call to ExtendFileC */ struct hfsmount *hfsmp; hfsmp = VTOHFS(vp); *(ap->a_bytesallocated) = 0; fileblocks = fp->ff_blocks; - filebytes = (off_t)fileblocks * (off_t)VTOVCB(vp)->blockSize; + filebytes = (off_t)fileblocks * (off_t)vcb->blockSize; if (length < (off_t)0) return (EINVAL); - if (vp->v_type != VREG && vp->v_type != VLNK) + if (vp->v_type != VREG) return (EISDIR); - if ((ap->a_flags & ALLOCATEFROMVOL) && (length <= filebytes)) + if ((ap->a_flags & ALLOCATEFROMVOL) && (length < filebytes)) return (EINVAL); /* Fill in the flags word for the call to Extend the file */ + extendFlags = kEFNoClumpMask; if (ap->a_flags & ALLOCATECONTIG) extendFlags |= kEFContigMask; - if (ap->a_flags & ALLOCATEALL) extendFlags |= kEFAllMask; - - if (suser(ap->a_cred, NULL) != 0) + if (ap->a_cred && suser(ap->a_cred, NULL) != 0) extendFlags |= kEFReserveMask; tv = time; @@ -1767,12 +1843,31 @@ #if QUOTA retval = hfs_chkdq(cp, - (int64_t)(roundup(moreBytesRequested, VTOVCB(vp)->blockSize)), + (int64_t)(roundup(moreBytesRequested, vcb->blockSize)), ap->a_cred, 0); if (retval) return (retval); #endif /* QUOTA */ + /* + * Metadata zone checks. + */ + if (hfsmp->hfs_flags & HFS_METADATA_ZONE) { + /* + * Allocate Journal and Quota files in metadata zone. + */ + if (hfs_virtualmetafile(cp)) { + extendFlags |= kEFMetadataMask; + blockHint = hfsmp->hfs_metazone_start; + } else if ((blockHint >= hfsmp->hfs_metazone_start) && + (blockHint <= hfsmp->hfs_metazone_end)) { + /* + * Move blockHint outside metadata zone. + */ + blockHint = hfsmp->hfs_metazone_end + 1; + } + } + // XXXdbg hfs_global_shared_lock_acquire(hfsmp); if (hfsmp->jnl) { @@ -1792,7 +1887,7 @@ goto Err_Exit; } - retval = MacToVFSError(ExtendFileC(VTOVCB(vp), + retval = MacToVFSError(ExtendFileC(vcb, (FCB*)fp, moreBytesRequested, blockHint, @@ -1800,12 +1895,15 @@ &actualBytesAdded)); *(ap->a_bytesallocated) = actualBytesAdded; - filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize; + filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize; (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); // XXXdbg if (hfsmp->jnl) { + tv = time; + VOP_UPDATE(vp, &tv, &tv, 1); + hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); journal_end_transaction(hfsmp->jnl); } @@ -1827,7 +1925,7 @@ */ if ((actualBytesAdded != 0) && (moreBytesRequested < actualBytesAdded)) *(ap->a_bytesallocated) = - roundup(moreBytesRequested, (off_t)VTOVCB(vp)->blockSize); + roundup(moreBytesRequested, (off_t)vcb->blockSize); } else { /* Shorten the size of the file */ @@ -1863,14 +1961,17 @@ retval = MacToVFSError( TruncateFileC( - VTOVCB(vp), + vcb, (FCB*)fp, length, false)); (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); - filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize; + filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize; if (hfsmp->jnl) { + tv = time; + VOP_UPDATE(vp, &tv, &tv, 1); + hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); journal_end_transaction(hfsmp->jnl); } @@ -1925,7 +2026,7 @@ int devBlockSize = 0; int error; - if (vp->v_type != VREG && vp->v_type != VLNK) + if (vp->v_type != VREG) panic("hfs_pagein: vp not UBC type\n"); VOP_DEVBLOCKSIZE(VTOC(vp)->c_devvp, &devBlockSize); @@ -1933,6 +2034,25 @@ error = cluster_pagein(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, ap->a_size, (off_t)VTOF(vp)->ff_size, devBlockSize, ap->a_flags); + /* + * Keep track blocks read + */ + if (VTOHFS(vp)->hfc_stage == HFC_RECORDING && error == 0) { + struct cnode *cp; + + cp = VTOC(vp); + /* + * If this file hasn't been seen since the start of + * the current sampling period then start over. + */ + if (cp->c_atime < VTOHFS(vp)->hfc_timebase) + VTOF(vp)->ff_bytesread = ap->a_size; + else + VTOF(vp)->ff_bytesread += ap->a_size; + + cp->c_flag |= C_ACCESS; + } + return (error); } @@ -1966,10 +2086,18 @@ filesize = fp->ff_size; end_of_range = ap->a_f_offset + ap->a_size - 1; + if (cp->c_flag & C_RELOCATING) { + if (end_of_range < (filesize / 2)) { + return (EBUSY); + } + } + if (end_of_range >= filesize) end_of_range = (off_t)(filesize - 1); - if (ap->a_f_offset < filesize) + if (ap->a_f_offset < filesize) { rl_remove(ap->a_f_offset, end_of_range, &fp->ff_invalidranges); + cp->c_flag |= C_MODIFIED; /* leof is dirty */ + } retval = cluster_pageout(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, ap->a_size, filesize, devBlockSize, ap->a_flags); @@ -2036,3 +2164,459 @@ return (retval); } + +/* + * Relocate a file to a new location on disk + * cnode must be locked on entry + * + * Relocation occurs by cloning the file's data from its + * current set of blocks to a new set of blocks. During + * the relocation all of the blocks (old and new) are + * owned by the file. + * + * ----------------- + * |///////////////| + * ----------------- + * 0 N (file offset) + * + * ----------------- ----------------- + * |///////////////| | | STEP 1 (aquire new blocks) + * ----------------- ----------------- + * 0 N N+1 2N + * + * ----------------- ----------------- + * |///////////////| |///////////////| STEP 2 (clone data) + * ----------------- ----------------- + * 0 N N+1 2N + * + * ----------------- + * |///////////////| STEP 3 (head truncate blocks) + * ----------------- + * 0 N + * + * During steps 2 and 3 page-outs to file offsets less + * than or equal to N are suspended. + * + * During step 3 page-ins to the file get supended. + */ +__private_extern__ +int +hfs_relocate(vp, blockHint, cred, p) + struct vnode *vp; + u_int32_t blockHint; + struct ucred *cred; + struct proc *p; +{ + struct filefork *fp; + struct hfsmount *hfsmp; + ExtendedVCB *vcb; + + u_int32_t headblks; + u_int32_t datablks; + u_int32_t blksize; + u_int32_t realsize; + u_int32_t growsize; + u_int32_t nextallocsave; + u_int32_t sector_a; + u_int32_t sector_b; + int eflags; + u_int32_t oldstart; /* debug only */ + off_t newbytes; + int retval; + + if (vp->v_type != VREG && vp->v_type != VLNK) { + return (EPERM); + } + + hfsmp = VTOHFS(vp); + if (hfsmp->hfs_flags & HFS_FRAGMENTED_FREESPACE) { + return (ENOSPC); + } + + fp = VTOF(vp); + if (fp->ff_unallocblocks) + return (EINVAL); + vcb = VTOVCB(vp); + blksize = vcb->blockSize; + if (blockHint == 0) + blockHint = vcb->nextAllocation; + + if ((fp->ff_size > (u_int64_t)0x7fffffff) || + (vp->v_type == VLNK && fp->ff_size > blksize)) { + return (EFBIG); + } + + headblks = fp->ff_blocks; + datablks = howmany(fp->ff_size, blksize); + growsize = datablks * blksize; + realsize = fp->ff_size; + eflags = kEFContigMask | kEFAllMask | kEFNoClumpMask; + if (blockHint >= hfsmp->hfs_metazone_start && + blockHint <= hfsmp->hfs_metazone_end) + eflags |= kEFMetadataMask; + + hfs_global_shared_lock_acquire(hfsmp); + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + return (EINVAL); + } + } + + /* Lock extents b-tree (also protects volume bitmap) */ + retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p); + if (retval) + goto out2; + + retval = MapFileBlockC(vcb, (FCB *)fp, 1, growsize - 1, §or_a, NULL); + if (retval) { + retval = MacToVFSError(retval); + goto out; + } + + /* + * STEP 1 - aquire new allocation blocks. + */ + nextallocsave = vcb->nextAllocation; + retval = ExtendFileC(vcb, (FCB*)fp, growsize, blockHint, eflags, &newbytes); + if (eflags & kEFMetadataMask) + vcb->nextAllocation = nextallocsave; + + retval = MacToVFSError(retval); + if (retval == 0) { + VTOC(vp)->c_flag |= C_MODIFIED; + if (newbytes < growsize) { + retval = ENOSPC; + goto restore; + } else if (fp->ff_blocks < (headblks + datablks)) { + printf("hfs_relocate: allocation failed"); + retval = ENOSPC; + goto restore; + } + + retval = MapFileBlockC(vcb, (FCB *)fp, 1, growsize, §or_b, NULL); + if (retval) { + retval = MacToVFSError(retval); + } else if ((sector_a + 1) == sector_b) { + retval = ENOSPC; + goto restore; + } else if ((eflags & kEFMetadataMask) && + ((((u_int64_t)sector_b * hfsmp->hfs_phys_block_size) / blksize) > + hfsmp->hfs_metazone_end)) { + printf("hfs_relocate: didn't move into metadata zone\n"); + retval = ENOSPC; + goto restore; + } + } + if (retval) { + /* + * Check to see if failure is due to excessive fragmentation. + */ + if (retval == ENOSPC && + hfs_freeblks(hfsmp, 0) > (datablks * 2)) { + hfsmp->hfs_flags |= HFS_FRAGMENTED_FREESPACE; + } + goto out; + } + + fp->ff_size = fp->ff_blocks * blksize; + if (UBCISVALID(vp)) + (void) ubc_setsize(vp, fp->ff_size); + + /* + * STEP 2 - clone data into the new allocation blocks. + */ + + if (vp->v_type == VLNK) + retval = hfs_clonelink(vp, blksize, cred, p); + else if (vp->v_flag & VSYSTEM) + retval = hfs_clonesysfile(vp, headblks, datablks, blksize, cred, p); + else + retval = hfs_clonefile(vp, headblks, datablks, blksize, cred, p); + + if (retval) + goto restore; + + oldstart = fp->ff_extents[0].startBlock; + + /* + * STEP 3 - switch to clone and remove old blocks. + */ + SET(VTOC(vp)->c_flag, C_NOBLKMAP); /* suspend page-ins */ + + retval = HeadTruncateFile(vcb, (FCB*)fp, headblks); + + CLR(VTOC(vp)->c_flag, C_NOBLKMAP); /* resume page-ins */ + if (ISSET(VTOC(vp)->c_flag, C_WBLKMAP)) + wakeup(VTOC(vp)); + if (retval) + goto restore; + + fp->ff_size = realsize; + if (UBCISVALID(vp)) { + (void) ubc_setsize(vp, realsize); + (void) vinvalbuf(vp, V_SAVE, cred, p, 0, 0); + } + + CLR(VTOC(vp)->c_flag, C_RELOCATING); /* Resume page-outs for this file. */ +out: + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p); + + retval = VOP_FSYNC(vp, cred, MNT_WAIT, p); +out2: + if (hfsmp->jnl) { + if (VTOC(vp)->c_cnid < kHFSFirstUserCatalogNodeID) + (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, HFS_ALTFLUSH); + else + (void) hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); + + return (retval); + +restore: + /* + * Give back any newly allocated space. + */ + if (fp->ff_size != realsize) + fp->ff_size = realsize; + (void) TruncateFileC(vcb, (FCB*)fp, fp->ff_size, false); + if (UBCISVALID(vp)) + (void) ubc_setsize(vp, fp->ff_size); + CLR(VTOC(vp)->c_flag, C_RELOCATING); + goto out; +} + + +/* + * Clone a symlink. + * + */ +static int +hfs_clonelink(struct vnode *vp, int blksize, struct ucred *cred, struct proc *p) +{ + struct buf *head_bp = NULL; + struct buf *tail_bp = NULL; + int error; + + + error = meta_bread(vp, 0, blksize, cred, &head_bp); + if (error) + goto out; + + tail_bp = getblk(vp, 1, blksize, 0, 0, BLK_META); + if (tail_bp == NULL) { + error = EIO; + goto out; + } + bcopy(head_bp->b_data, tail_bp->b_data, blksize); + error = bwrite(tail_bp); +out: + if (head_bp) { + head_bp->b_flags |= B_INVAL; + brelse(head_bp); + } + (void) vinvalbuf(vp, V_SAVE, cred, p, 0, 0); + + return (error); +} + +/* + * Clone a file's data within the file. + * + */ +static int +hfs_clonefile(struct vnode *vp, int blkstart, int blkcnt, int blksize, + struct ucred *cred, struct proc *p) +{ + caddr_t bufp; + size_t writebase; + size_t bufsize; + size_t copysize; + size_t iosize; + size_t filesize; + size_t offset; + struct uio auio; + struct iovec aiov; + int devblocksize; + int didhold; + int error; + + + if ((error = vinvalbuf(vp, V_SAVE, cred, p, 0, 0))) { + printf("hfs_clonefile: vinvalbuf failed - %d\n", error); + return (error); + } + + if (!ubc_clean(vp, 1)) { + printf("hfs_clonefile: not ubc_clean\n"); + return (EIO); /* XXX error code */ + } + + /* + * Suspend page-outs for this file. + */ + SET(VTOC(vp)->c_flag, C_RELOCATING); + + filesize = VTOF(vp)->ff_size; + writebase = blkstart * blksize; + copysize = blkcnt * blksize; + iosize = bufsize = MIN(copysize, 4096 * 16); + offset = 0; + + if (kmem_alloc(kernel_map, (vm_offset_t *)&bufp, bufsize)) { + return (ENOMEM); + } + + VOP_DEVBLOCKSIZE(VTOC(vp)->c_devvp, &devblocksize); + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = p; + + while (offset < copysize) { + iosize = MIN(copysize - offset, iosize); + + aiov.iov_base = bufp; + aiov.iov_len = iosize; + auio.uio_resid = iosize; + auio.uio_offset = offset; + auio.uio_rw = UIO_READ; + + error = cluster_read(vp, &auio, copysize, devblocksize, 0); + if (error) { + printf("hfs_clonefile: cluster_read failed - %d\n", error); + break; + } + if (auio.uio_resid != 0) { + printf("clonedata: cluster_read: uio_resid = %d\n", (int)auio.uio_resid); + error = EIO; + break; + } + + + aiov.iov_base = bufp; + aiov.iov_len = iosize; + auio.uio_resid = iosize; + auio.uio_offset = writebase + offset; + auio.uio_rw = UIO_WRITE; + + error = cluster_write(vp, &auio, filesize + offset, + filesize + offset + iosize, + auio.uio_offset, 0, devblocksize, 0); + if (error) { + printf("hfs_clonefile: cluster_write failed - %d\n", error); + break; + } + if (auio.uio_resid != 0) { + printf("hfs_clonefile: cluster_write failed - uio_resid not zero\n"); + error = EIO; + break; + } + offset += iosize; + } + if (error == 0) { + /* Clean the pages in VM. */ + didhold = ubc_hold(vp); + if (didhold) + (void) ubc_clean(vp, 1); + + /* + * Clean out all associated buffers. + */ + (void) vinvalbuf(vp, V_SAVE, cred, p, 0, 0); + + if (didhold) + ubc_rele(vp); + } + kmem_free(kernel_map, (vm_offset_t)bufp, bufsize); + + return (error); +} + +/* + * Clone a system (metadata) file. + * + */ +static int +hfs_clonesysfile(struct vnode *vp, int blkstart, int blkcnt, int blksize, + struct ucred *cred, struct proc *p) +{ + caddr_t bufp; + char * offset; + size_t bufsize; + size_t iosize; + struct buf *bp = NULL; + daddr_t blkno; + daddr_t blk; + int breadcnt; + int i; + int error = 0; + + + iosize = GetLogicalBlockSize(vp); + bufsize = MIN(blkcnt * blksize, 1024 * 1024) & ~(iosize - 1); + breadcnt = bufsize / iosize; + + if (kmem_alloc(kernel_map, (vm_offset_t *)&bufp, bufsize)) { + return (ENOMEM); + } + blkstart = (blkstart * blksize) / iosize; + blkcnt = (blkcnt * blksize) / iosize; + blkno = 0; + + while (blkno < blkcnt) { + /* + * Read up to a megabyte + */ + offset = bufp; + for (i = 0, blk = blkno; (i < breadcnt) && (blk < blkcnt); ++i, ++blk) { + error = meta_bread(vp, blk, iosize, cred, &bp); + if (error) { + printf("hfs_clonesysfile: meta_bread error %d\n", error); + goto out; + } + if (bp->b_bcount != iosize) { + printf("hfs_clonesysfile: b_bcount is only %d\n", bp->b_bcount); + goto out; + } + + bcopy(bp->b_data, offset, iosize); + bp->b_flags |= B_INVAL; + brelse(bp); + bp = NULL; + offset += iosize; + } + + /* + * Write up to a megabyte + */ + offset = bufp; + for (i = 0; (i < breadcnt) && (blkno < blkcnt); ++i, ++blkno) { + bp = getblk(vp, blkstart + blkno, iosize, 0, 0, BLK_META); + if (bp == NULL) { + printf("hfs_clonesysfile: getblk failed on blk %d\n", blkstart + blkno); + error = EIO; + goto out; + } + bcopy(offset, bp->b_data, iosize); + error = bwrite(bp); + bp = NULL; + if (error) + goto out; + offset += iosize; + } + } +out: + if (bp) { + brelse(bp); + } + + kmem_free(kernel_map, (vm_offset_t)bufp, bufsize); + + error = VOP_FSYNC(vp, cred, MNT_WAIT, p); + + return (error); +} + diff -urN xnu-344.49/bsd/hfs/hfs_search.c xnu-517/bsd/hfs/hfs_search.c --- xnu-344.49/bsd/hfs/hfs_search.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_search.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1997-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -102,7 +102,7 @@ searchinfospec_t *searchInfo2, Boolean lookForDup ); -static int CheckAccess(ExtendedVCB *vcb, CatalogKey *key, struct proc *p); +static int CheckAccess(ExtendedVCB *vcb, u_long searchBits, CatalogKey *key, struct proc *p); static int InsertMatch(struct vnode *vp, struct uio *a_uio, CatalogRecord *rec, CatalogKey *key, struct attrlist *returnAttrList, @@ -161,6 +161,7 @@ }; */ +__private_extern__ int hfs_search( ap ) struct vop_searchfs_args *ap; /* @@ -198,6 +199,7 @@ BTScanState myBTScanState; void *user_start = NULL; int user_len; + int32_t searchTime; /* XXX Parameter check a_searchattrs? */ @@ -206,10 +208,32 @@ if (ap->a_options & ~SRCHFS_VALIDOPTIONSMASK) return (EINVAL); + /* SRCHFS_SKIPLINKS requires root access. + * This option cannot be used with either + * the ATTR_CMN_NAME or ATTR_CMN_PAROBJID + * attributes. + */ + if (ap->a_options & SRCHFS_SKIPLINKS) { + attrgroup_t attrs; + + attrs = ap->a_searchattrs->commonattr | ap->a_returnattrs->commonattr; + if (attrs & (ATTR_CMN_NAME | ATTR_CMN_PAROBJID)) + return (EINVAL); + if ((err = suser(p->p_ucred, &p->p_acflag))) + return (err); + } + if (ap->a_uio->uio_resid <= 0) return (EINVAL); isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); + + searchTime = kMaxMicroSecsInKernel; + if (ap->a_timelimit->tv_sec == 0 && + ap->a_timelimit->tv_usec > 0 && + ap->a_timelimit->tv_usec < kMaxMicroSecsInKernel) { + searchTime = ap->a_timelimit->tv_usec; + } /* UnPack the search boundries, searchInfo1, searchInfo2 */ err = UnpackSearchAttributeBlock(ap->a_vp, ap->a_searchattrs, @@ -256,6 +280,10 @@ /* Starting a new search. */ /* Make sure the on-disk Catalog file is current */ (void) VOP_FSYNC(vcb->catalogRefNum, NOCRED, MNT_WAIT, p); + if (VTOHFS(ap->a_vp)->jnl) { + journal_flush(VTOHFS(ap->a_vp)->jnl); + } + ap->a_options &= ~SRCHFS_START; bzero( (caddr_t)myCatPositionPtr, sizeof( *myCatPositionPtr ) ); err = BTScanInitialize(catalogFCB, 0, 0, 0, kCatSearchBufferSize, &myBTScanState); @@ -289,7 +317,7 @@ if ( result == E_NONE ) { if (CheckCriteria(vcb, ap->a_options, ap->a_searchattrs, &rec, keyp, &searchInfo1, &searchInfo2, false) && - CheckAccess(vcb, keyp, ap->a_uio->uio_procp)) { + CheckAccess(vcb, ap->a_options, keyp, ap->a_uio->uio_procp)) { result = InsertMatch(ap->a_vp, ap->a_uio, &rec, keyp, ap->a_returnattrs, @@ -340,12 +368,12 @@ break; /* Resolve any hardlinks */ - if (isHFSPlus) + if (isHFSPlus && (ap->a_options & SRCHFS_SKIPLINKS) == 0) ResolveHardlink(vcb, (HFSPlusCatalogFile *) myCurrentDataPtr); if (CheckCriteria( vcb, ap->a_options, ap->a_searchattrs, myCurrentDataPtr, myCurrentKeyPtr, &searchInfo1, &searchInfo2, true ) - && CheckAccess(vcb, myCurrentKeyPtr, ap->a_uio->uio_procp)) { + && CheckAccess(vcb, ap->a_options, myCurrentKeyPtr, ap->a_uio->uio_procp)) { err = InsertMatch(ap->a_vp, ap->a_uio, myCurrentDataPtr, myCurrentKeyPtr, ap->a_returnattrs, attributesBuffer, variableBuffer, @@ -373,7 +401,7 @@ timersub(&myCurrentTime, &myBTScanState.startTime, &myElapsedTime); /* Note: assumes kMaxMicroSecsInKernel is less than 1,000,000 */ if (myElapsedTime.tv_sec > 0 - || myElapsedTime.tv_usec >= kMaxMicroSecsInKernel) { + || myElapsedTime.tv_usec >= searchTime) { timerExpired = true; } } @@ -418,7 +446,12 @@ && (SWAP_BE32(recp->userInfo.fdCreator) == kHFSPlusCreator) && ((to_bsd_time(recp->createDate) == vcb->vcbCrDate) || (to_bsd_time(recp->createDate) == VCBTOHFS(vcb)->hfs_metadata_createdate))) { + cnid_t saved_cnid; + + /* Export link's cnid (a unique value) instead of inode's cnid */ + saved_cnid = recp->fileID; (void) resolvelink(VCBTOHFS(vcb), recp->bsdInfo.special.iNodeNum, recp); + recp->fileID = saved_cnid; } } @@ -484,12 +517,130 @@ } + +static char *extension_table=NULL; +static int nexts; +static int max_ext_width; + +static int +extension_cmp(void *a, void *b) +{ + return (strlen((char *)a) - strlen((char *)b)); +} + + +// +// This is the api LaunchServices uses to inform the kernel +// the list of package extensions to ignore. +// +// Internally we keep the list sorted by the length of the +// the extension (from longest to shortest). We sort the +// list of extensions so that we can speed up our searches +// when comparing file names -- we only compare extensions +// that could possibly fit into the file name, not all of +// them (i.e. a short 8 character name can't have an 8 +// character extension). +// +__private_extern__ int +set_package_extensions_table(void *data, int nentries, int maxwidth) +{ + char *new_exts, *ptr; + int error, i, len; + + if (nentries <= 0 || nentries > 1024 || maxwidth <= 0 || maxwidth > 255) { + return EINVAL; + } + + MALLOC(new_exts, char *, nentries * maxwidth, M_TEMP, M_WAITOK); + + error = copyin(data, new_exts, nentries * maxwidth); + if (error) { + FREE(new_exts, M_TEMP); + return error; + } + + if (extension_table) { + FREE(extension_table, M_TEMP); + } + extension_table = new_exts; + nexts = nentries; + max_ext_width = maxwidth; + + qsort(extension_table, nexts, maxwidth, extension_cmp); + + return 0; +} + + +static int +is_package_name(char *name, int len) +{ + int i, extlen; + char *ptr, *name_ext; + + if (len <= 3) { + return 0; + } + + name_ext = NULL; + for(ptr=name; *ptr != '\0'; ptr++) { + if (*ptr == '.') { + name_ext = ptr; + } + } + + // if there is no "." extension, it can't match + if (name_ext == NULL) { + return 0; + } + + // advance over the "." + name_ext++; + + // now iterate over all the extensions to see if any match + ptr = &extension_table[0]; + for(i=0; i < nexts; i++, ptr+=max_ext_width) { + extlen = strlen(ptr); + if (strncmp(name_ext, ptr, extlen) == 0 && name_ext[extlen] == '\0') { + // aha, a match! + return 1; + } + } + + // if we get here, no extension matched + return 0; +} + +// +// Determine if a name is "inappropriate" where the definition +// of "inappropriate" is up to higher level execs. Currently +// that's limited to /System. +// +static int +is_inappropriate_name(char *name, int len) +{ + char *bad_names[] = { "System" }; + int bad_len[] = { 6 }; + int i; + + for(i=0; i < sizeof(bad_names) / sizeof(bad_names[0]); i++) { + if (len == bad_len[i] && strcmp(name, bad_names[i]) == 0) { + return 1; + } + } + + // if we get here, no name matched + return 0; +} + + + /* * Check to see if caller has access rights to this item */ static int -CheckAccess(ExtendedVCB *theVCBPtr, CatalogKey *theKeyPtr, struct proc *theProcPtr) +CheckAccess(ExtendedVCB *theVCBPtr, u_long searchBits, CatalogKey *theKeyPtr, struct proc *theProcPtr) { Boolean isHFSPlus; int myErr; @@ -499,6 +650,8 @@ hfsmount_t * my_hfsmountPtr; struct cat_desc my_cat_desc; struct cat_attr my_cat_attr; + struct FndrDirInfo *finder_info; + myResult = 0; /* default to "no access" */ my_cat_desc.cd_nameptr = NULL; @@ -527,10 +680,34 @@ if ( myErr ) goto ExitThisRoutine; /* no access */ + if (searchBits & SRCHFS_SKIPPACKAGES) { + if (is_package_name(my_cat_desc.cd_nameptr, my_cat_desc.cd_namelen)) { + myResult = 0; + goto ExitThisRoutine; + } + } + + if (searchBits & SRCHFS_SKIPINAPPROPRIATE) { + if ( my_cat_desc.cd_parentcnid == kRootDirID + && is_inappropriate_name(my_cat_desc.cd_nameptr, my_cat_desc.cd_namelen)) { + myResult = 0; + goto ExitThisRoutine; + } + } + + finder_info = (struct FndrDirInfo *)&my_cat_attr.ca_finderinfo[0]; + if ( (searchBits & SRCHFS_SKIPINVISIBLE) + && (SWAP_BE16(finder_info->frFlags) & kIsInvisible)) { + + myResult = 0; + goto ExitThisRoutine; + } + myNodeID = my_cat_desc.cd_parentcnid; /* move up the hierarchy */ myPerms = DerivePermissionSummary(my_cat_attr.ca_uid, my_cat_attr.ca_gid, my_cat_attr.ca_mode, my_hfsmountPtr->hfs_mp, theProcPtr->p_ucred, theProcPtr ); + cat_releasedesc( &my_cat_desc ); if ( (myPerms & X_OK) == 0 ) @@ -574,7 +751,29 @@ break; case kHFSFileRecord: + if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */ + matched = false; + goto TestDone; + } + break; + case kHFSPlusFileRecord: + /* Check if hardlink links should be skipped. */ + if (searchBits & SRCHFS_SKIPLINKS) { + cnid_t parid = key->hfsPlus.parentID; + HFSPlusCatalogFile *filep = (HFSPlusCatalogFile *)rec; + + if ((SWAP_BE32(filep->userInfo.fdType) == kHardLinkFileType) && + (SWAP_BE32(filep->userInfo.fdCreator) == kHFSPlusCreator)) { + return (false); /* skip over link records */ + } else if ((parid == VCBTOHFS(vcb)->hfs_privdir_desc.cd_cnid) && + (filep->bsdInfo.special.linkCount == 0)) { + return (false); /* skip over unlinked files */ + } + } else if (key->hfsPlus.parentID == VCBTOHFS(vcb)->hfs_privdir_desc.cd_cnid) { + return (false); /* skip over private files */ + } + if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */ matched = false; goto TestDone; @@ -636,6 +835,42 @@ /* Convert catalog record into cat_attr format. */ cat_convertattr(VCBTOHFS(vcb), rec, &c_attr, &datafork, &rsrcfork); + if (searchBits & SRCHFS_SKIPINVISIBLE) { + int flags; + + switch (rec->recordType) { + case kHFSFolderRecord: + case kHFSPlusFolderRecord: { + struct FndrDirInfo *finder_info; + + finder_info = (struct FndrDirInfo *)&c_attr.ca_finderinfo[0]; + flags = SWAP_BE16(finder_info->frFlags); + break; + } + + case kHFSFileRecord: + case kHFSPlusFileRecord: { + struct FndrFileInfo *finder_info; + + finder_info = (struct FndrFileInfo *)&c_attr.ca_finderinfo[0]; + flags = SWAP_BE16(finder_info->fdFlags); + break; + } + + default: { + flags = kIsInvisible; + break; + } + } + + if (flags & kIsInvisible) { + matched = false; + goto TestDone; + } + } + + + /* Now that we have a record worth searching, see if it matches the search attributes */ if (rec->recordType == kHFSFileRecord || rec->recordType == kHFSPlusFileRecord) { @@ -862,7 +1097,7 @@ u_long packedBufferSize; ExtendedVCB *vcb = VTOVCB(root_vp); Boolean isHFSPlus = vcb->vcbSigWord == kHFSPlusSigWord; - u_long privateDir = VTOHFS(root_vp)->hfs_private_metadata_dir; + u_long privateDir = VTOHFS(root_vp)->hfs_privdir_desc.cd_cnid; struct attrblock attrblk; struct cat_desc c_desc = {0}; struct cat_attr c_attr = {0}; @@ -899,19 +1134,13 @@ c_desc.cd_parentcnid = key->hfs.parentID; } - /* hide open files that have been deleted */ - if ((privateDir != 0) && (c_desc.cd_parentcnid == privateDir)) { - err = 0; - goto exit; - } - attrblk.ab_attrlist = returnAttrList; attrblk.ab_attrbufpp = &rovingAttributesBuffer; attrblk.ab_varbufpp = &rovingVariableBuffer; attrblk.ab_flags = 0; attrblk.ab_blocksize = 0; - hfs_packattrblk(&attrblk, VTOHFS(root_vp), NULL, &c_desc, &c_attr, &datafork, &rsrcfork); + hfs_packattrblk(&attrblk, VTOHFS(root_vp), NULL, &c_desc, &c_attr, &datafork, &rsrcfork, a_uio->uio_procp); packedBufferSize = (char*)rovingVariableBuffer - (char*)attributesBuffer; @@ -1014,12 +1243,8 @@ ++((struct timespec *)attributeBuffer); } if ( a & ATTR_CMN_FNDRINFO ) { - bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(u_long) * 8 ); - (u_long *)attributeBuffer += 8; - } - if ( a & ATTR_CMN_BKUPTIME ) { - searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer); - ++((struct timespec *)attributeBuffer); + bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(u_long) * 8 ); + (u_long *)attributeBuffer += 8; } if ( a & ATTR_CMN_OWNERID ) { searchInfo->uid = *((uid_t *)attributeBuffer); diff -urN xnu-344.49/bsd/hfs/hfs_vfsops.c xnu-517/bsd/hfs/hfs_vfsops.c --- xnu-344.49/bsd/hfs/hfs_vfsops.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_vfsops.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -74,11 +74,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include // XXXdbg #include @@ -118,11 +121,14 @@ struct hfs_mount_args *args)); static int hfs_statfs __P((struct mount *mp, register struct statfs *sbp, struct proc *p)); +static int hfs_flushfiles __P((struct mount *, int, struct proc *)); +static int hfs_extendfs __P((struct mount *, u_int64_t, struct proc *)); /* * Called by vfs_mountroot when mounting HFS Plus as root. */ +__private_extern__ int hfs_mountroot() { @@ -146,9 +152,13 @@ } if ((error = hfs_mountfs(rootvp, mp, p, NULL))) { mp->mnt_vfc->vfc_refcount--; + + if (mp->mnt_kern_flag & MNTK_IO_XINFO) + FREE(mp->mnt_xinfo_ptr, M_TEMP); vfs_unbusy(mp, p); + vrele(rootvp); /* release the reference from bdevvp() */ - _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); + FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); return (error); } simple_lock(&mountlist_slock); @@ -208,7 +218,8 @@ if (mp->mnt_flag & MNT_UPDATE) { hfsmp = VFSTOHFS(mp); - if ((hfsmp->hfs_fs_ronly == 0) && (mp->mnt_flag & MNT_RDONLY)) { + if (((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) && + (mp->mnt_flag & MNT_RDONLY)) { /* use VFS_SYNC to push out System (btree) files */ retval = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p); @@ -221,7 +232,7 @@ if ((retval = hfs_flushfiles(mp, flags, p))) goto error_exit; - hfsmp->hfs_fs_ronly = 1; + hfsmp->hfs_flags |= HFS_READ_ONLY; retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0); /* also get the volume bitmap blocks */ @@ -229,16 +240,30 @@ retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p); if (retval) { - hfsmp->hfs_fs_ronly = 0; + hfsmp->hfs_flags &= ~HFS_READ_ONLY; goto error_exit; } + + if (hfsmp->jnl) { + hfs_global_exclusive_lock_acquire(hfsmp); + + journal_close(hfsmp->jnl); + hfsmp->jnl = NULL; + + // Note: we explicitly don't want to shutdown + // access to the jvp because we may need + // it later if we go back to being read-write. + + hfs_global_exclusive_lock_release(hfsmp); + } } if ((mp->mnt_flag & MNT_RELOAD) && (retval = hfs_reload(mp, ndp->ni_cnd.cn_cred, p))) goto error_exit; - if (hfsmp->hfs_fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { + if ((hfsmp->hfs_flags & HFS_READ_ONLY) && + (mp->mnt_kern_flag & MNTK_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. @@ -257,16 +282,61 @@ if (retval != E_NONE) goto error_exit; - /* only change hfs_fs_ronly after a successfull write */ - hfsmp->hfs_fs_ronly = 0; + // If the journal was shut-down previously because we were + // asked to be read-only, let's start it back up again now + + if ( (HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) + && hfsmp->jnl == NULL + && hfsmp->jvp != NULL) { + int flags; + + if (hfsmp->hfs_flags & HFS_NEED_JNL_RESET) { + flags = JOURNAL_RESET; + } else { + flags = 0; + } + + hfs_global_exclusive_lock_acquire(hfsmp); + + hfsmp->jnl = journal_open(hfsmp->jvp, + (hfsmp->jnl_start * HFSTOVCB(hfsmp)->blockSize) + (off_t)HFSTOVCB(hfsmp)->hfsPlusIOPosOffset, + hfsmp->jnl_size, + hfsmp->hfs_devvp, + hfsmp->hfs_phys_block_size, + flags, + 0, + hfs_sync_metadata, hfsmp->hfs_mp); + + hfs_global_exclusive_lock_release(hfsmp); + + if (hfsmp->jnl == NULL) { + retval = EINVAL; + goto error_exit; + } else { + hfsmp->hfs_flags &= ~HFS_NEED_JNL_RESET; + } + + } + + /* Only clear HFS_READ_ONLY after a successfull write */ + hfsmp->hfs_flags &= ~HFS_READ_ONLY; } - if ((hfsmp->hfs_fs_ronly == 0) && + if (((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) && (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)) { /* setup private/hidden directory for unlinked files */ - hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(HFSTOVCB(hfsmp)); + FindMetaDataDirectory(HFSTOVCB(hfsmp)); if (hfsmp->jnl) hfs_remove_orphans(hfsmp); + + /* + * Allow hot file clustering if conditions allow. + */ + if ((hfsmp->hfs_flags & HFS_METADATA_ZONE) && + (mp->mnt_flag & MNT_RDONLY) && + (mp->mnt_kern_flag & MNTK_WANTRDWR)) { + (void) hfs_recording_init(hfsmp, p); + } } if (args.fspec == 0) { @@ -374,15 +444,22 @@ hfsmp = VFSTOHFS(mp); vcb = HFSTOVCB(hfsmp); - permswitch = (((hfsmp->hfs_unknownpermissions != 0) && ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) == 0)) || - ((hfsmp->hfs_unknownpermissions == 0) && ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0))); + permswitch = (((hfsmp->hfs_flags & HFS_UNKNOWN_PERMS) && + ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) == 0)) || + (((hfsmp->hfs_flags & HFS_UNKNOWN_PERMS) == 0) && + (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS))); + /* The root filesystem must operate with actual permissions: */ if (permswitch && (mp->mnt_flag & MNT_ROOTFS) && (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)) { mp->mnt_flag &= ~MNT_UNKNOWNPERMISSIONS; /* Just say "No". */ return EINVAL; - }; - hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0); - namefix = permfix = 0; + } + if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) + hfsmp->hfs_flags |= HFS_UNKNOWN_PERMS; + else + hfsmp->hfs_flags &= ~HFS_UNKNOWN_PERMS; + + namefix = permfix = 0; /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */ if (args->hfs_timezone.tz_minuteswest != VNOVAL) { @@ -413,7 +490,7 @@ /* Change the hfs encoding value (hfs only) */ if ((HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) && - (hfsmp->hfs_encoding != (u_long)VNOVAL) && + (args->hfs_encoding != (u_long)VNOVAL) && (hfsmp->hfs_encoding != args->hfs_encoding)) { retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func); @@ -482,6 +559,7 @@ continue; } + /* Get the real uid/gid and perm mask from disk. */ if (permswitch || permfix) { cp->c_uid = cnattr.ca_uid; cp->c_gid = cnattr.ca_gid; @@ -614,7 +692,6 @@ return (error); } - /* update cnode's catalog descriptor */ (void) replace_desc(cp, &desc); } @@ -640,8 +717,10 @@ vhp = (HFSPlusVolumeHeader *) (bp->b_data + HFS_PRI_OFFSET(sectorsize)); /* Do a quick sanity check */ - if (SWAP_BE16(vhp->signature) != kHFSPlusSigWord || - SWAP_BE16(vhp->version) != kHFSPlusVersion || + if ((SWAP_BE16(vhp->signature) != kHFSPlusSigWord && + SWAP_BE16(vhp->signature) != kHFSXSigWord) || + (SWAP_BE16(vhp->version) != kHFSPlusVersion && + SWAP_BE16(vhp->version) != kHFSXVersion) || SWAP_BE32(vhp->blockSize) != vcb->blockSize) { brelse(bp); return (EIO); @@ -723,8 +802,11 @@ cat_releasedesc(&cndesc); /* Re-establish private/hidden directory for unlinked files */ - hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb); + FindMetaDataDirectory(vcb); + /* In case any volume information changed to trigger a notification */ + hfs_generate_volume_notifications(hfsmp); + return (0); } @@ -924,8 +1006,6 @@ MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK); bzero(hfsmp, sizeof(struct hfsmount)); - - simple_lock_init(&hfsmp->hfs_renamelock); /* * Init the volume information structure @@ -937,9 +1017,11 @@ hfsmp->hfs_devvp = devvp; hfsmp->hfs_phys_block_size = blksize; hfsmp->hfs_phys_block_count = blkcnt; - hfsmp->hfs_media_writeable = 1; - hfsmp->hfs_fs_ronly = ronly; - hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0); + hfsmp->hfs_flags |= HFS_WRITEABLE_MEDIA; + if (ronly) + hfsmp->hfs_flags |= HFS_READ_ONLY; + if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) + hfsmp->hfs_flags |= HFS_UNKNOWN_PERMS; for (i = 0; i < MAXQUOTAS; i++) hfsmp->hfs_qfiles[i].qf_vp = NULLVP; @@ -974,9 +1056,9 @@ /* Find out if disk media is writable. */ if (VOP_IOCTL(devvp, DKIOCISWRITABLE, (caddr_t)&iswritable, 0, cred, p) == 0) { if (iswritable) - hfsmp->hfs_media_writeable = 1; + hfsmp->hfs_flags |= HFS_WRITEABLE_MEDIA; else - hfsmp->hfs_media_writeable = 0; + hfsmp->hfs_flags &= ~HFS_WRITEABLE_MEDIA; } /* Mount a standard HFS disk */ @@ -1104,8 +1186,43 @@ if (hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred) == 0) { mp->mnt_flag |= MNT_JOURNALED; } else { - retval = EINVAL; - goto error_exit; + // if the journal failed to open, then set the lastMountedVersion + // to be "FSK!" which fsck_hfs will see and force the fsck instead + // of just bailing out because the volume is journaled. + if (ronly != 0 || devvp == rootvp) { + HFSPlusVolumeHeader *vhp; + + hfsmp->hfs_flags |= HFS_NEED_JNL_RESET; + + if (mdb_offset == 0) { + mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize); + } + + bp = NULL; + retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp); + if (retval == 0) { + vhp = (HFSPlusVolumeHeader *)(bp->b_data + HFS_PRI_OFFSET(blksize)); + + if (SWAP_BE16(vhp->signature) == kHFSPlusSigWord || SWAP_BE16(vhp->signature) == kHFSXSigWord) { + vhp->lastMountedVersion = SWAP_BE32('FSK!'); + bwrite(bp); + } else { + brelse(bp); + } + bp = NULL; + } else if (bp) { + brelse(bp); + } + } + + // if this isn't the root device just bail out. + // if it is the root device we just continue on + // in the hopes that fsck_hfs will be able to + // fix any damage that exists on the volume. + if (devvp != rootvp) { + retval = EINVAL; + goto error_exit; + } } } // XXXdbg @@ -1134,6 +1251,15 @@ hfsmp->hfs_phys_block_count *= hfsmp->hfs_phys_block_size / blksize; hfsmp->hfs_phys_block_size = blksize; + if (hfsmp->jnl) { + // close and re-open this with the new block size + journal_close(hfsmp->jnl); + hfsmp->jnl = NULL; + if (hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred) == 0) { + mp->mnt_flag |= MNT_JOURNALED; + } + } + /* Try again with a smaller block size... */ retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args); } @@ -1150,6 +1276,45 @@ mp->mnt_maxsymlinklen = 0; devvp->v_specflags |= SI_MOUNTEDON; + if (args) { + /* + * Set the free space warning levels for a non-root volume: + * + * Set the lower freespace limit (the level that will trigger a warning) + * to 5% of the volume size or 250MB, whichever is less, and the desired + * level (which will cancel the alert request) to 1/2 above that limit. + * Start looking for free space to drop below this level and generate a + * warning immediately if needed: + */ + hfsmp->hfs_freespace_notify_warninglimit = + MIN(HFS_LOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize, + (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_LOWDISKTRIGGERFRACTION); + hfsmp->hfs_freespace_notify_desiredlevel = + MIN(HFS_LOWDISKSHUTOFFLEVEL / HFSTOVCB(hfsmp)->blockSize, + (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_LOWDISKSHUTOFFFRACTION); + } else { + /* + * Set the free space warning levels for the root volume: + * + * Set the lower freespace limit (the level that will trigger a warning) + * to 1% of the volume size or 50MB, whichever is less, and the desired + * level (which will cancel the alert request) to 2% or 75MB, whichever is less. + */ + hfsmp->hfs_freespace_notify_warninglimit = + MIN(HFS_ROOTLOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize, + (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_ROOTLOWDISKTRIGGERFRACTION); + hfsmp->hfs_freespace_notify_desiredlevel = + MIN(HFS_ROOTLOWDISKSHUTOFFLEVEL / HFSTOVCB(hfsmp)->blockSize, + (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_ROOTLOWDISKSHUTOFFFRACTION); + }; + + /* + * Start looking for free space to drop below this level and generate a + * warning immediately if needed: + */ + hfsmp->hfs_notification_conditions = 0; + hfs_generate_volume_notifications(hfsmp); + if (ronly == 0) { (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0); } @@ -1214,13 +1379,16 @@ if ((retval = hfs_flushfiles(mp, flags, p)) && !force) return (retval); + if (hfsmp->hfs_flags & HFS_METADATA_ZONE) + (void) hfs_recording_suspend(hfsmp, p); + /* * Flush out the b-trees, volume bitmap and Volume Header */ - if (hfsmp->hfs_fs_ronly == 0) { + if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) { hfs_global_shared_lock_acquire(hfsmp); grabbed_lock = 1; - if (hfsmp->jnl) { + if (hfsmp->jnl) { journal_start_transaction(hfsmp->jnl); started_tr = 1; } @@ -1242,18 +1410,27 @@ } } + if (hfsmp->hfc_filevp && (hfsmp->hfc_filevp->v_flag & VSYSTEM)) { + retval = VOP_FSYNC(hfsmp->hfc_filevp, NOCRED, MNT_WAIT, p); + if (retval && !force) + goto err_exit; + } + if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) { if (!force) goto err_exit; } - + +#if 0 /* See if this volume is damaged, is so do not unmount cleanly */ if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) { HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask; } else { HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask; } - +#else + HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask; +#endif retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1); if (retval) { HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask; @@ -1280,26 +1457,45 @@ */ (void) hfsUnmount(hfsmp, p); + /* + * Last chance to dump unreferenced system files. + */ + (void) vflush(mp, NULLVP, FORCECLOSE); + if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) (void) hfs_relconverter(hfsmp->hfs_encoding); // XXXdbg if (hfsmp->jnl) { journal_close(hfsmp->jnl); + hfsmp->jnl = NULL; } if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) { - retval = VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, + retval = VOP_CLOSE(hfsmp->jvp, + hfsmp->hfs_flags & HFS_READ_ONLY ? FREAD : FREAD|FWRITE, NOCRED, p); vrele(hfsmp->jvp); - hfsmp->jvp = NULL; + hfsmp->jvp = NULL; } // XXXdbg +#ifdef HFS_SPARSE_DEV + /* Drop our reference on the backing fs (if any). */ + if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) && hfsmp->hfs_backingfs_rootvp) { + struct vnode * tmpvp; + + hfsmp->hfs_flags &= ~HFS_HAS_SPARSE_DEVICE; + tmpvp = hfsmp->hfs_backingfs_rootvp; + hfsmp->hfs_backingfs_rootvp = NULLVP; + vrele(tmpvp); + } +#endif /* HFS_SPARSE_DEV */ + hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON; retval = VOP_CLOSE(hfsmp->hfs_devvp, - hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, - NOCRED, p); + hfsmp->hfs_flags & HFS_READ_ONLY ? FREAD : FREAD|FWRITE, + NOCRED, p); if (retval && !force) return(retval); @@ -1551,9 +1747,8 @@ return (0); hfsmp = VFSTOHFS(mp); - if (hfsmp->hfs_fs_ronly != 0) { - panic("update: rofs mod"); - }; + if (hfsmp->hfs_flags & HFS_READ_ONLY) + return (EROFS); #if 0 // XXXdbg first go through and flush out any modified @@ -1590,12 +1785,7 @@ // restart our whole search if this guy is locked // or being reclaimed. - // XXXdbg - at some point this should go away or we - // need to change all file systems to have - // this same code. vget() should never return - // success if either of these conditions is - // true. - if (vp->v_tag != VT_HFS || cp == NULL) { + if (vp->v_tag != VT_HFS || cp == NULL || vp->v_flag & (VXLOCK|VORECLAIM)) { simple_unlock(&vp->v_interlock); continue; } @@ -1619,9 +1809,15 @@ } didhold = ubc_hold(vp); + + // mark the cnode so that fsync won't flush + // the journal since we're going to do that... + cp->c_flag |= C_FROMSYNC; if ((error = VOP_FSYNC(vp, cred, waitfor, p))) { allerror = error; }; + cp->c_flag &= ~C_FROMSYNC; + VOP_UNLOCK(vp, 0, p); if (didhold) ubc_rele(vp); @@ -1675,6 +1871,8 @@ #if QUOTA hfs_qsync(mp); #endif /* QUOTA */ + + hfs_hotfilesync(hfsmp, p); /* * Write back modified superblock. */ @@ -1731,7 +1929,7 @@ * Get the export permission structure for this tuple. */ np = vfs_export_lookup(mp, &VFSTOHFS(mp)->hfs_export, nam); - if (np == NULL) { + if (nam && (np == NULL)) { return EACCES; }; @@ -1755,9 +1953,23 @@ return (ESTALE); }; + if (VNAME(nvp) == NULL) { + struct cnode *cp = VTOC(nvp); + + if (nvp == cp->c_rsrc_vp) { + // the +1/-2 thing is to skip the leading "/" on the rsrc fork spec + // and to not count the trailing null byte at the end of the string. + VNAME(nvp) = add_name(_PATH_RSRCFORKSPEC+1, sizeof(_PATH_RSRCFORKSPEC)-2, 0, 0); + } else { + VNAME(nvp) = add_name(cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen, 0, 0); + } + } + *vpp = nvp; - *exflagsp = np->netc_exflags; - *credanonp = &np->netc_anon; + if (np) { + *exflagsp = np->netc_exflags; + *credanonp = &np->netc_anon; + } return (0); } @@ -1782,7 +1994,7 @@ hfsfhp = (struct hfsfid *)fhp; hfsfhp->hfsfid_len = sizeof(struct hfsfid); hfsfhp->hfsfid_pad = 0; - hfsfhp->hfsfid_cnid = cp->c_cnid; + hfsfhp->hfsfid_cnid = cp->c_fileid; hfsfhp->hfsfid_gen = cp->c_itime; return (0); @@ -1807,6 +2019,8 @@ dqinit(); #endif /* QUOTA */ + BTReserveSetup(); + /* * Allocate Catalog Iterator cache... */ @@ -1815,6 +2029,31 @@ return (0); } +static int +hfs_getmountpoint(vp, hfsmpp) + struct vnode *vp; + struct hfsmount **hfsmpp; +{ + struct hfsmount * hfsmp; + + if (vp == NULL) + return (EINVAL); + + if ((vp->v_flag & VROOT) == 0) + return (EINVAL); + + if (strcmp(vp->v_mount->mnt_stat.f_fstypename, "hfs") != 0) + return (EINVAL); + + hfsmp = VTOHFS(vp); + + if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) + return (EINVAL); + + *hfsmpp = hfsmp; + + return (0); +} // XXXdbg #include @@ -1833,17 +2072,68 @@ size_t newlen; struct proc *p; { - extern u_int32_t hfs_encodingbias; + extern u_int32_t hfs_getencodingbias(void); + extern void hfs_setencodingbias(u_int32_t); + + int error; + struct sysctl_req *req; + struct vfsidctl vc; + struct mount *mp; + struct hfsmount *hfsmp; + struct vfsquery vq; /* all sysctl names at this level are terminal */ - if (name[0] == HFS_ENCODINGBIAS) - return (sysctl_int(oldp, oldlenp, newp, newlen, - &hfs_encodingbias)); - else if (name[0] == 0x082969) { + if (name[0] == HFS_ENCODINGBIAS) { + u_int32_t bias; + + bias = hfs_getencodingbias(); + error = sysctl_int(oldp, oldlenp, newp, newlen, &bias); + if (error == 0 && newp) + hfs_setencodingbias(bias); + return (error); + + } else if (name[0] == HFS_EXTEND_FS) { + u_int64_t newsize; + + if (newp == NULL) + return (EINVAL); + if ((error = hfs_getmountpoint(p->p_fd->fd_cdir, &hfsmp))) + return (error); + error = sysctl_quad(oldp, oldlenp, newp, newlen, &newsize); + if (error) + return (error); + + error = hfs_extendfs(HFSTOVFS(hfsmp), newsize, p); + return (error); + + } else if (name[0] == HFS_ENCODINGHINT) { + size_t bufsize; + size_t bytes; + u_int32_t hint; + u_int16_t *unicode_name; + char *filename; + + bufsize = MAX(newlen * 3, MAXPATHLEN); + MALLOC(filename, char *, newlen, M_TEMP, M_WAITOK); + MALLOC(unicode_name, u_int16_t *, bufsize, M_TEMP, M_WAITOK); + + error = copyin(newp, (caddr_t)filename, newlen); + if (error == 0) { + error = utf8_decodestr(filename, newlen - 1, unicode_name, + &bytes, bufsize, 0, UTF_DECOMPOSED); + if (error == 0) { + hint = hfs_pickencoding(unicode_name, bytes / 2); + error = sysctl_int(oldp, oldlenp, NULL, NULL, &hint); + } + } + FREE(unicode_name, M_TEMP); + FREE(filename, M_TEMP); + return (error); + + } else if (name[0] == HFS_ENABLE_JOURNALING) { // make the file system journaled... struct vnode *vp = p->p_fd->fd_cdir, *jvp; - struct hfsmount *hfsmp; ExtendedVCB *vcb; int retval; struct cat_attr jnl_attr, jinfo_attr; @@ -1851,11 +2141,12 @@ void *jnl = NULL; /* Only root can enable journaling */ - if (current_proc()->p_ucred->cr_uid != 0) { + if (current_proc()->p_ucred->cr_uid != 0) { return (EPERM); } + hfsmp = VTOHFS(vp); - if (hfsmp->hfs_fs_ronly) { + if (hfsmp->hfs_flags & HFS_READ_ONLY) { return EROFS; } if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) { @@ -1893,7 +2184,7 @@ jnl = journal_create(jvp, (off_t)name[2] * (off_t)HFSTOVCB(hfsmp)->blockSize + HFSTOVCB(hfsmp)->hfsPlusIOPosOffset, - (off_t)name[3], + (off_t)((unsigned)name[3]), hfsmp->hfs_devvp, hfsmp->hfs_phys_block_size, 0, @@ -1903,7 +2194,7 @@ if (jnl == NULL) { printf("hfs: FAILED to create the journal!\n"); if (jvp && jvp != hfsmp->hfs_devvp) { - VOP_CLOSE(jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p); + VOP_CLOSE(jvp, hfsmp->hfs_flags & HFS_READ_ONLY ? FREAD : FREAD|FWRITE, FSCRED, p); } jvp = NULL; @@ -1919,6 +2210,7 @@ // save this off for the hack-y check in hfs_remove() hfsmp->jnl_start = (u_int32_t)name[2]; + hfsmp->jnl_size = (off_t)((unsigned)name[3]); hfsmp->hfs_jnlinfoblkid = jinfo_attr.ca_fileid; hfsmp->hfs_jnlfileid = jnl_attr.ca_fileid; @@ -1928,21 +2220,18 @@ hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1); return 0; - } else if (name[0] == 0x031272) { + } else if (name[0] == HFS_DISABLE_JOURNALING) { // clear the journaling bit struct vnode *vp = p->p_fd->fd_cdir; - struct hfsmount *hfsmp; void *jnl; int retval; /* Only root can disable journaling */ - if (current_proc()->p_ucred->cr_uid != 0) { + if (current_proc()->p_ucred->cr_uid != 0) { return (EPERM); } + hfsmp = VTOHFS(vp); - if (hfsmp->jnl == NULL) { - return EINVAL; - } printf("hfs: disabling journaling for mount @ 0x%x\n", vp->v_mount); @@ -1955,7 +2244,7 @@ journal_close(jnl); if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) { - VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p); + VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_flags & HFS_READ_ONLY ? FREAD : FREAD|FWRITE, FSCRED, p); } hfsmp->jnl = NULL; hfsmp->jvp = NULL; @@ -1970,7 +2259,45 @@ hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1); return 0; - } + } else if (name[0] == HFS_GET_JOURNAL_INFO) { + struct vnode *vp = p->p_fd->fd_cdir; + off_t jnl_start, jnl_size; + + hfsmp = VTOHFS(vp); + if (hfsmp->jnl == NULL) { + jnl_start = 0; + jnl_size = 0; + } else { + jnl_start = (off_t)(hfsmp->jnl_start * HFSTOVCB(hfsmp)->blockSize) + (off_t)HFSTOVCB(hfsmp)->hfsPlusIOPosOffset; + jnl_size = (off_t)hfsmp->jnl_size; + } + + if ((error = copyout((caddr_t)&jnl_start, (void *)name[1], sizeof(off_t))) != 0) { + return error; + } + if ((error = copyout((caddr_t)&jnl_size, (void *)name[2], sizeof(off_t))) != 0) { + return error; + } + + return 0; + } else if (name[0] == HFS_SET_PKG_EXTENSIONS) { + + return set_package_extensions_table((void *)name[1], name[2], name[3]); + + } else if (name[0] == VFS_CTL_QUERY) { + req = oldp; /* we're new style vfs sysctl. */ + + error = SYSCTL_IN(req, &vc, sizeof(vc)); + if (error) return (error); + + mp = vfs_getvfs(&vc.vc_fsid); + if (mp == NULL) return (ENOENT); + + hfsmp = VFSTOHFS(mp); + bzero(&vq, sizeof(vq)); + vq.vq_flags = hfsmp->hfs_notification_conditions; + return SYSCTL_OUT(req, &vq, sizeof(vq));; + }; return (EOPNOTSUPP); } @@ -1999,36 +2326,149 @@ } /* + * Check to see if a given vnode is only referenced for events: + * [ entered with vp->v_interlock locked ] + */ +static int +hfs_evtonly(struct vnode *vp) +{ + int ubc_refcount; + + ubc_refcount = UBCINFOEXISTS(vp) ? 1 : 0; + return (vp->v_usecount == (ubc_refcount + EVTONLYREFS(vp))); +} + +/* + * Check to see if all non-system vnodes for a given mountpoint are events-only + */ +static int +hfs_flush_evtonly(struct mount *mp, int flags, int dispose, struct proc *p) +{ + struct vnode *vp, *nvp; + int busy = 0; + + simple_lock(&mntvnode_slock); +loop: + for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) { + if (vp->v_mount != mp) goto loop; + nvp = vp->v_mntvnodes.le_next; + + simple_lock(&vp->v_interlock); + /* + * Skip over a vnodes marked VSYSTEM or VNOFLUSH. + */ + if ((flags & SKIPSYSTEM) && ((vp->v_flag & VSYSTEM) || (vp->v_flag & VNOFLUSH))) { + simple_unlock(&vp->v_interlock); + continue; + }; + /* + * Skip over a vnodes marked VSWAP. + */ + if ((flags & SKIPSWAP) && (vp->v_flag & VSWAP)) { + simple_unlock(&vp->v_interlock); + continue; + } + if (hfs_evtonly(vp)) { + if (dispose) { + /* "dispose" implies "forcibly", a la "FORCECLOSE": */ + simple_unlock(&mntvnode_slock); + vgonel(vp, p); + simple_lock(&mntvnode_slock); + } else { + simple_unlock(&vp->v_interlock); + }; + continue; + }; + + simple_unlock(&vp->v_interlock); + ++busy; + /* If asked to dispose, keep trying. If only checking, the answer is now known. */ + if (dispose) { + continue; + } else { + break; + }; + } + simple_unlock(&mntvnode_slock); + + return (busy == 0); +} + +/* * Flush out all the files in a filesystem. */ -int +static int hfs_flushfiles(struct mount *mp, int flags, struct proc *p) { - register struct hfsmount *hfsmp; + struct hfsmount *hfsmp; + struct vnode *skipvp = NULLVP; + struct vnode *rsrcvp; + int quotafilecnt; int i; int error; -#if QUOTA hfsmp = VFSTOHFS(mp); +#if QUOTA + /* + * The open quota files have an indirect reference on + * the root directory vnode. We must account for this + * extra reference when doing the intial vflush. + */ + quotafilecnt = 0; + if (mp->mnt_flag & MNT_QUOTA) { + + /* Find out how many quota files we have open. */ + for (i = 0; i < MAXQUOTAS; i++) { + if (hfsmp->hfs_qfiles[i].qf_vp != NULLVP) + ++quotafilecnt; + } + + /* Obtain the root vnode so we can skip over it. */ + if (hfs_chashget(hfsmp->hfs_raw_dev, kRootDirID, 0, + &skipvp, &rsrcvp) == NULL) { + skipvp = NULLVP; + } + } +#endif /* QUOTA */ + + error = vflush(mp, skipvp, SKIPSYSTEM | SKIPSWAP | flags); + /* + * If the vflush() call failed solely because there are + * some event-only vnodes in the list, then forcibly get + * rid of those vnodes before the final vflush() pass. + */ + if ((error == EBUSY) && hfs_flush_evtonly(mp, SKIPSYSTEM | SKIPSWAP, 0, p)) { + (void) hfs_flush_evtonly(mp, SKIPSYSTEM | SKIPSWAP, 1, p); + }; + error = vflush(mp, skipvp, SKIPSYSTEM | flags); + +#if QUOTA if (mp->mnt_flag & MNT_QUOTA) { - if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) + if (skipvp) { + /* + * See if there are additional references on the + * root vp besides the ones obtained from the open + * quota files and the hfs_chashget call above. + */ + if ((error == 0) && + (skipvp->v_usecount > (1 + quotafilecnt))) { + error = EBUSY; /* root directory is still open */ + } + vput(skipvp); + } + if (error && (flags & FORCECLOSE) == 0) return (error); + for (i = 0; i < MAXQUOTAS; i++) { if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP) continue; hfs_quotaoff(p, mp, i); } - /* - * Here we fall through to vflush again to ensure - * that we have gotten rid of all the system vnodes. - */ + error = vflush(mp, NULLVP, SKIPSYSTEM | flags); } #endif /* QUOTA */ - error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags)); - error = vflush(mp, NULLVP, (SKIPSYSTEM | flags)); - return (error); } @@ -2056,8 +2496,8 @@ break; } - if (index < 128) { - HFSTOVCB(hfsmp)->encodingsBitmap |= (1 << index); + if (index < 64) { + HFSTOVCB(hfsmp)->encodingsBitmap |= (u_int64_t)(1ULL << index); HFSTOVCB(hfsmp)->vcbFlags |= 0xFF00; } } @@ -2209,7 +2649,14 @@ return (retval); } - +/* + * Flush any dirty in-memory mount data to the on-disk + * volume header. + * + * Note: the on-disk volume signature is intentionally + * not flushed since the on-disk "H+" and "HX" signatures + * are always stored in-memory as "H+". + */ __private_extern__ int hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush) @@ -2223,7 +2670,12 @@ int sectorsize; int priIDSector; int critical = 0; + u_int16_t signature; + u_int16_t version; + if (hfsmp->hfs_flags & HFS_READ_ONLY) { + return(0); + } if (vcb->vcbSigWord == kHFSSigWord) return hfs_flushMDB(hfsmp, waitfor, altflush); @@ -2252,6 +2704,7 @@ } hfs_global_shared_lock_release(hfsmp); + printf("HFS: err %d reading VH blk (%s)\n", retval, vcb->vcbVN); return (retval); } @@ -2262,6 +2715,24 @@ volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data + HFS_PRI_OFFSET(sectorsize)); /* + * Sanity check what we just read. + */ + signature = SWAP_BE16 (volumeHeader->signature); + version = SWAP_BE16 (volumeHeader->version); + if ((signature != kHFSPlusSigWord && signature != kHFSXSigWord) || + (version < kHFSPlusVersion) || (version > 100) || + (SWAP_BE32 (volumeHeader->blockSize) != vcb->blockSize)) { +#if 1 + panic("HFS: corrupt VH on %s, sig 0x%04x, ver %d, blksize %d", + vcb->vcbVN, signature, version, + SWAP_BE32 (volumeHeader->blockSize)); +#endif + printf("HFS: corrupt VH blk (%s)\n", vcb->vcbVN); + brelse(bp); + return (EIO); + } + + /* * For embedded HFS+ volumes, update create date if it changed * (ie from a setattrlist call) */ @@ -2303,28 +2774,6 @@ } } -// XXXdbg - only monkey around with the volume signature on non-root volumes -// -#if 0 - if (hfsmp->jnl && - hfsmp->hfs_fs_ronly == 0 && - (HFSTOVFS(hfsmp)->mnt_flag & MNT_ROOTFS) == 0) { - - int old_sig = volumeHeader->signature; - - if (vcb->vcbAtrb & kHFSVolumeUnmountedMask) { - volumeHeader->signature = kHFSPlusSigWord; - } else { - volumeHeader->signature = kHFSJSigWord; - } - - if (old_sig != volumeHeader->signature) { - altflush = 1; - } - } -#endif -// XXXdbg - /* Note: only update the lower 16 bits worth of attributes */ volumeHeader->attributes = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb); volumeHeader->journalInfoBlock = SWAP_BE32(vcb->vcbJinfoBlock); @@ -2433,6 +2882,251 @@ vcb->vcbFlags &= 0x00FF; return (retval); +} + + +/* + * Extend a file system. + */ +static int +hfs_extendfs(struct mount *mp, u_int64_t newsize, struct proc *p) +{ + struct vnode *vp; + struct vnode *devvp; + struct buf *bp; + struct hfsmount *hfsmp; + struct filefork *fp = NULL; + ExtendedVCB *vcb; + struct cat_fork forkdata; + u_int64_t oldsize; + u_int64_t newblkcnt; + u_int32_t addblks; + u_int64_t sectorcnt; + u_int32_t sectorsize; + daddr_t prev_alt_sector; + daddr_t bitmapblks; + int error; + + hfsmp = VFSTOHFS(mp); + devvp = hfsmp->hfs_devvp; + vcb = HFSTOVCB(hfsmp); + + /* + * - HFS Plus file systems only. + * - Journaling must be enabled. + * - No embedded volumes. + */ + if ((vcb->vcbSigWord == kHFSSigWord) || + (hfsmp->jnl == NULL) || + (vcb->hfsPlusIOPosOffset != 0)) { + return (EPERM); + } + /* + * If extending file system by non-root, then verify + * ownership and check permissions. + */ + if (p->p_ucred->cr_uid != 0) { + error = hfs_root(mp, &vp); + if (error) + return (error); + error = hfs_owner_rights(hfsmp, VTOC(vp)->c_uid, p->p_ucred, p, 0); + if (error == 0) { + error = hfs_write_access(vp, p->p_ucred, p, false); + } + vput(vp); + if (error) + return (error); + + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p); + VOP_UNLOCK(devvp, 0, p); + if (error) + return (error); + } + if (VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)§orsize, 0, FSCRED, p)) { + return (ENXIO); + } + if (sectorsize != hfsmp->hfs_phys_block_size) { + return (ENXIO); + } + if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)§orcnt, 0, FSCRED, p)) { + return (ENXIO); + } + if ((sectorsize * sectorcnt) < newsize) { + printf("hfs_extendfs: not enough space on device\n"); + return (ENOSPC); + } + oldsize = (u_int64_t)hfsmp->hfs_phys_block_count * + (u_int64_t)hfsmp->hfs_phys_block_size; + + /* + * Validate new size. + */ + if ((newsize <= oldsize) || (newsize % vcb->blockSize)) { + printf("hfs_extendfs: invalid size\n"); + return (EINVAL); + } + newblkcnt = newsize / vcb->blockSize; + if (newblkcnt > (u_int64_t)0xFFFFFFFF) + return (EOVERFLOW); + + addblks = newblkcnt - vcb->totalBlocks; + + printf("hfs_extendfs: growing %s by %d blocks\n", vcb->vcbVN, addblks); + /* + * Enclose changes inside a transaction. + */ + hfs_global_shared_lock_acquire(hfsmp); + if (journal_start_transaction(hfsmp->jnl) != 0) { + hfs_global_shared_lock_release(hfsmp); + return (EINVAL); + } + + /* + * Remember the location of existing alternate VH. + */ + prev_alt_sector = (vcb->hfsPlusIOPosOffset / sectorsize) + + HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count); + + vp = vcb->allocationsRefNum; + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) { + goto out2; + } + fp = VTOF(vp); + bcopy(&fp->ff_data, &forkdata, sizeof(forkdata)); + + /* + * Calculate additional space required (if any) by allocation bitmap. + */ + bitmapblks = roundup(newblkcnt / 8, vcb->vcbVBMIOSize) / vcb->blockSize; + if (bitmapblks > fp->ff_blocks) + bitmapblks -= fp->ff_blocks; + else + bitmapblks = 0; + + if (bitmapblks > 0) { + daddr_t blkno; + daddr_t blkcnt; + + /* + * Add a new extent to the allocation bitmap file. + */ + error = AddFileExtent(vcb, fp, vcb->totalBlocks, bitmapblks); + if (error) { + printf("hfs_extendfs: error %d adding extents\n", error); + goto out; + } + blkcnt = bitmapblks; + blkno = fp->ff_blocks; + fp->ff_blocks += bitmapblks; + fp->ff_size += (u_int64_t)bitmapblks * (u_int64_t)vcb->blockSize; + VTOC(vp)->c_blocks = fp->ff_blocks; + /* + * Zero out the new bitmap blocks. + */ + { + + bp = NULL; + while (blkcnt > 0) { + error = meta_bread(vp, blkno, vcb->blockSize, NOCRED, &bp); + if (error) { + if (bp) { + brelse(bp); + } + break; + } + bzero((char *)bp->b_data, vcb->blockSize); + bp->b_flags |= B_AGE; + error = bwrite(bp); + if (error) + break; + --blkcnt; + ++blkno; + } + } + if (error) { + printf("hfs_extendfs: error %d clearing blocks\n", error); + goto out; + } + /* + * Mark the new bitmap space as allocated. + */ + error = BlockMarkAllocated(vcb, vcb->totalBlocks, bitmapblks); + if (error) { + printf("hfs_extendfs: error %d setting bitmap\n", error); + goto out; + } + } + /* + * Mark the new alternate VH as allocated. + */ + if (vcb->blockSize == 512) + error = BlockMarkAllocated(vcb, vcb->totalBlocks + addblks - 2, 2); + else + error = BlockMarkAllocated(vcb, vcb->totalBlocks + addblks - 1, 1); + if (error) { + printf("hfs_extendfs: error %d setting bitmap (VH)\n", error); + goto out; + } + /* + * Mark the old alternate VH as free. + */ + if (vcb->blockSize == 512) + (void) BlockMarkFree(vcb, vcb->totalBlocks - 2, 2); + else + (void) BlockMarkFree(vcb, vcb->totalBlocks - 1, 1); + + /* + * Adjust file system variables for new space. + */ + vcb->totalBlocks += addblks; + vcb->freeBlocks += addblks - bitmapblks; + hfsmp->hfs_phys_block_count = newsize / sectorsize; + + MarkVCBDirty(vcb); + error = hfs_flushvolumeheader(hfsmp, MNT_WAIT, HFS_ALTFLUSH); + if (error) { + printf("hfs_extendfs: couldn't flush volume headers (%d)", error); + /* + * Restore to old state. + */ + fp->ff_size -= (u_int64_t)bitmapblks * (u_int64_t)vcb->blockSize; + vcb->totalBlocks -= addblks; + vcb->freeBlocks -= addblks - bitmapblks; + hfsmp->hfs_phys_block_count = oldsize / sectorsize; + MarkVCBDirty(vcb); + if (vcb->blockSize == 512) + (void) BlockMarkAllocated(vcb, vcb->totalBlocks - 2, 2); + else + (void) BlockMarkAllocated(vcb, vcb->totalBlocks - 1, 1); + goto out; + } + /* + * Invalidate the old alternate volume header. + */ + bp = NULL; + if (meta_bread(hfsmp->hfs_devvp, prev_alt_sector, sectorsize, + NOCRED, &bp) == 0) { + journal_modify_block_start(hfsmp->jnl, bp); + bzero(bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize); + journal_modify_block_end(hfsmp->jnl, bp); + } else if (bp) { + brelse(bp); + } +out: + if (error && fp) { + /* Restore allocation fork. */ + bcopy(&forkdata, &fp->ff_data, sizeof(forkdata)); + VTOC(vp)->c_blocks = fp->ff_blocks; + + } + VOP_UNLOCK(vp, 0, p); +out2: + journal_end_transaction(hfsmp->jnl); + hfs_global_shared_lock_release(hfsmp); + + return (error); } diff -urN xnu-344.49/bsd/hfs/hfs_vfsutils.c xnu-517/bsd/hfs/hfs_vfsutils.c --- xnu-344.49/bsd/hfs/hfs_vfsutils.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_vfsutils.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -54,12 +54,16 @@ extern int count_lock_queue __P((void)); -extern uid_t console_user; static void ReleaseMetaFileVNode(struct vnode *vp); static int hfs_late_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, void *_args); +static void hfs_metadatazone_init(struct hfsmount *); +static u_int32_t hfs_hotfile_freeblocks(struct hfsmount *); + + + u_int32_t GetLogicalBlockSize(struct vnode *vp); /* BTree accessor routines */ @@ -86,6 +90,7 @@ char hfs_privdirname[] = "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data"; +__private_extern__ OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb, struct proc *p) { @@ -102,9 +107,11 @@ return (EINVAL); /* don't mount a writeable volume if its dirty, it must be cleaned by fsck_hfs */ - if ((hfsmp->hfs_fs_ronly == 0) && ((SWAP_BE16(mdb->drAtrb) & kHFSVolumeUnmountedMask) == 0)) + if (((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) && + ((SWAP_BE16(mdb->drAtrb) & kHFSVolumeUnmountedMask) == 0)) { return (EINVAL); - + } + hfsmp->hfs_flags |= HFS_STANDARD; /* * The MDB seems OK: transfer info from it into VCB * Note - the VCB starts out clear (all zeros) @@ -130,7 +137,7 @@ vcb->vcbFilCnt = SWAP_BE32 (mdb->drFilCnt); vcb->vcbDirCnt = SWAP_BE32 (mdb->drDirCnt); bcopy(mdb->drFndrInfo, vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo)); - if (!hfsmp->hfs_fs_ronly) + if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) vcb->vcbWrCnt++; /* Compensate for write of MDB on last flush */ /* convert hfs encoded name into UTF-8 string */ @@ -149,6 +156,7 @@ bzero(&cndesc, sizeof(cndesc)); cndesc.cd_parentcnid = kRootParID; + cndesc.cd_flags |= CD_ISMETA; bzero(&cnattr, sizeof(cnattr)); cnattr.ca_nlink = 1; cnattr.ca_mode = S_IFREG; @@ -163,6 +171,7 @@ fork.cf_size = SWAP_BE32(mdb->drXTFlSize); fork.cf_blocks = fork.cf_size / vcb->blockSize; fork.cf_clump = SWAP_BE32(mdb->drXTClpSiz); + fork.cf_vblocks = 0; fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drXTExtRec[0].startBlock); fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drXTExtRec[0].blockCount); fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drXTExtRec[1].startBlock); @@ -175,9 +184,7 @@ &vcb->extentsRefNum); if (error) goto MtVolErr; error = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum), - (KeyCompareProcPtr)CompareExtentKeys, - GetBTreeBlock, ReleaseBTreeBlock, - ExtendBTreeFile, SetBTreeBlockSize)); + (KeyCompareProcPtr)CompareExtentKeys)); if (error) { VOP_UNLOCK(vcb->extentsRefNum, 0, p); goto MtVolErr; @@ -192,6 +199,7 @@ fork.cf_size = SWAP_BE32(mdb->drCTFlSize); fork.cf_blocks = fork.cf_size / vcb->blockSize; fork.cf_clump = SWAP_BE32(mdb->drCTClpSiz); + fork.cf_vblocks = 0; fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drCTExtRec[0].startBlock); fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drCTExtRec[0].blockCount); fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drCTExtRec[1].startBlock); @@ -207,9 +215,7 @@ goto MtVolErr; } error = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum), - (KeyCompareProcPtr)CompareCatalogKeys, - GetBTreeBlock, ReleaseBTreeBlock, - ExtendBTreeFile, SetBTreeBlockSize)); + (KeyCompareProcPtr)CompareCatalogKeys)); if (error) { VOP_UNLOCK(vcb->catalogRefNum, 0, p); VOP_UNLOCK(vcb->extentsRefNum, 0, p); @@ -249,38 +255,57 @@ // //******************************************************************************* +__private_extern__ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, off_t embeddedOffset, u_int64_t disksize, struct proc *p, void *args) { register ExtendedVCB *vcb; struct cat_desc cndesc; struct cat_attr cnattr; + struct cat_fork cfork; UInt32 blockSize; + u_int64_t volumesize; + struct BTreeInfoRec btinfo; + u_int16_t signature; + u_int16_t version; + int i; OSErr retval; - // XXXdbg - added the kHFSJSigWord case - if ((SWAP_BE16(vhp->signature) != kHFSPlusSigWord && - SWAP_BE16(vhp->signature) != kHFSJSigWord) || - SWAP_BE16(vhp->version) != kHFSPlusVersion) { - // XXXdbg - printf("hfs: mount: sig 0x%x and version 0x%x are not HFS or HFS+.\n", - vhp->signature, vhp->version); + signature = SWAP_BE16(vhp->signature); + version = SWAP_BE16(vhp->version); + + if (signature == kHFSPlusSigWord) { + if (version != kHFSPlusVersion) { + printf("hfs_mount: invalid HFS+ version: %d\n", version); + return (EINVAL); + } + } else if (signature == kHFSXSigWord) { + if (version != kHFSXVersion) { + printf("hfs_mount: invalid HFSX version: %d\n", version); + return (EINVAL); + } + /* The in-memory signature is always 'H+'. */ + signature = kHFSPlusSigWord; + hfsmp->hfs_flags |= HFS_X; + } else { + printf("hfs_mount: invalid HFS+ sig 0x%04x\n", signature); return (EINVAL); } /* Block size must be at least 512 and a power of 2 */ blockSize = SWAP_BE32(vhp->blockSize); - if (blockSize < 512 || (blockSize & (blockSize-1)) != 0) + if (blockSize < 512 || !powerof2(blockSize)) return (EINVAL); /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */ - if (hfsmp->hfs_fs_ronly == 0 && hfsmp->jnl == NULL && (SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) == 0) + if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0 && hfsmp->jnl == NULL && + (SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) == 0) return (EINVAL); /* Make sure we can live with the physical block size. */ if ((disksize & (hfsmp->hfs_phys_block_size - 1)) || (embeddedOffset & (hfsmp->hfs_phys_block_size - 1)) || - (SWAP_BE32(vhp->blockSize) < hfsmp->hfs_phys_block_size)) { + (blockSize < hfsmp->hfs_phys_block_size)) { return (ENXIO); } /* @@ -289,13 +314,7 @@ */ vcb = HFSTOVCB(hfsmp); - vcb->vcbSigWord = SWAP_BE16(vhp->signature); - - // XXXdbg - remap this in case we've mounted a dirty journaled volume - if (vcb->vcbSigWord == kHFSJSigWord) { - vcb->vcbSigWord = kHFSPlusSigWord; - } - + vcb->vcbSigWord = signature; vcb->vcbJinfoBlock = SWAP_BE32(vhp->journalInfoBlock); vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate)); vcb->vcbAtrb = (UInt16)SWAP_BE32(vhp->attributes); @@ -310,7 +329,7 @@ bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo)); vcb->vcbAlBlSt = 0; /* hfs+ allocation blocks start at first block of volume */ - if (!hfsmp->hfs_fs_ronly) + if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */ VCB_LOCK_INIT(vcb); @@ -319,7 +338,7 @@ vcb->nextAllocation = SWAP_BE32(vhp->nextAllocation); vcb->totalBlocks = SWAP_BE32(vhp->totalBlocks); vcb->freeBlocks = SWAP_BE32(vhp->freeBlocks); - vcb->blockSize = SWAP_BE32(vhp->blockSize); + vcb->blockSize = blockSize; vcb->encodingsBitmap = SWAP_BE64(vhp->encodingsBitmap); vcb->localCreateDate = SWAP_BE32(vhp->createDate); @@ -338,6 +357,7 @@ bzero(&cndesc, sizeof(cndesc)); cndesc.cd_parentcnid = kRootParID; + cndesc.cd_flags |= CD_ISMETA; bzero(&cnattr, sizeof(cnattr)); cnattr.ca_nlink = 1; cnattr.ca_mode = S_IFREG; @@ -349,19 +369,23 @@ cndesc.cd_namelen = strlen(hfs_extname); cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID; - SWAP_HFS_PLUS_FORK_DATA (&vhp->extentsFile); - cnattr.ca_blocks = vhp->extentsFile.totalBlocks; - - retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, - (struct cat_fork *)&vhp->extentsFile, + cfork.cf_size = SWAP_BE64 (vhp->extentsFile.logicalSize); + cfork.cf_clump = SWAP_BE32 (vhp->extentsFile.clumpSize); + cfork.cf_blocks = SWAP_BE32 (vhp->extentsFile.totalBlocks); + cfork.cf_vblocks = 0; + cnattr.ca_blocks = cfork.cf_blocks; + for (i = 0; i < kHFSPlusExtentDensity; i++) { + cfork.cf_extents[i].startBlock = + SWAP_BE32 (vhp->extentsFile.extents[i].startBlock); + cfork.cf_extents[i].blockCount = + SWAP_BE32 (vhp->extentsFile.extents[i].blockCount); + } + retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork, &vcb->extentsRefNum); - SWAP_HFS_PLUS_FORK_DATA (&vhp->extentsFile); if (retval) goto ErrorExit; retval = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum), - (KeyCompareProcPtr) CompareExtentKeysPlus, - GetBTreeBlock, ReleaseBTreeBlock, - ExtendBTreeFile, SetBTreeBlockSize)); + (KeyCompareProcPtr) CompareExtentKeysPlus)); if (retval) { VOP_UNLOCK(vcb->extentsRefNum, 0, p); goto ErrorExit; @@ -374,26 +398,39 @@ cndesc.cd_namelen = strlen(hfs_catname); cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID; - SWAP_HFS_PLUS_FORK_DATA(&vhp->catalogFile); - cnattr.ca_blocks = vhp->catalogFile.totalBlocks; - - retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, - (struct cat_fork *)&vhp->catalogFile, + cfork.cf_size = SWAP_BE64 (vhp->catalogFile.logicalSize); + cfork.cf_clump = SWAP_BE32 (vhp->catalogFile.clumpSize); + cfork.cf_blocks = SWAP_BE32 (vhp->catalogFile.totalBlocks); + cfork.cf_vblocks = 0; + cnattr.ca_blocks = cfork.cf_blocks; + for (i = 0; i < kHFSPlusExtentDensity; i++) { + cfork.cf_extents[i].startBlock = + SWAP_BE32 (vhp->catalogFile.extents[i].startBlock); + cfork.cf_extents[i].blockCount = + SWAP_BE32 (vhp->catalogFile.extents[i].blockCount); + } + retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork, &vcb->catalogRefNum); - SWAP_HFS_PLUS_FORK_DATA(&vhp->catalogFile); if (retval) { VOP_UNLOCK(vcb->extentsRefNum, 0, p); goto ErrorExit; } retval = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum), - (KeyCompareProcPtr) CompareExtendedCatalogKeys, - GetBTreeBlock, ReleaseBTreeBlock, - ExtendBTreeFile, SetBTreeBlockSize)); + (KeyCompareProcPtr) CompareExtendedCatalogKeys)); if (retval) { VOP_UNLOCK(vcb->catalogRefNum, 0, p); VOP_UNLOCK(vcb->extentsRefNum, 0, p); goto ErrorExit; } + if ((hfsmp->hfs_flags & HFS_X) && + BTGetInformation(VTOF(vcb->catalogRefNum), 0, &btinfo) == 0) { + if (btinfo.keyCompareType == kHFSBinaryCompare) { + hfsmp->hfs_flags |= HFS_CASE_SENSITIVE; + /* Install a case-sensitive key compare */ + (void) BTOpenPath(VTOF(vcb->catalogRefNum), + (KeyCompareProcPtr)cat_binarykeycompare); + } + } /* * Set up Allocation file vnode @@ -402,13 +439,19 @@ cndesc.cd_namelen = strlen(hfs_vbmname); cndesc.cd_cnid = cnattr.ca_fileid = kHFSAllocationFileID; - SWAP_HFS_PLUS_FORK_DATA(&vhp->allocationFile); - cnattr.ca_blocks = vhp->allocationFile.totalBlocks; - - retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, - (struct cat_fork *)&vhp->allocationFile, + cfork.cf_size = SWAP_BE64 (vhp->allocationFile.logicalSize); + cfork.cf_clump = SWAP_BE32 (vhp->allocationFile.clumpSize); + cfork.cf_blocks = SWAP_BE32 (vhp->allocationFile.totalBlocks); + cfork.cf_vblocks = 0; + cnattr.ca_blocks = cfork.cf_blocks; + for (i = 0; i < kHFSPlusExtentDensity; i++) { + cfork.cf_extents[i].startBlock = + SWAP_BE32 (vhp->allocationFile.extents[i].startBlock); + cfork.cf_extents[i].blockCount = + SWAP_BE32 (vhp->allocationFile.extents[i].blockCount); + } + retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork, &vcb->allocationsRefNum); - SWAP_HFS_PLUS_FORK_DATA(&vhp->allocationFile); if (retval) { VOP_UNLOCK(vcb->catalogRefNum, 0, p); VOP_UNLOCK(vcb->extentsRefNum, 0, p); @@ -430,7 +473,7 @@ /* mark the volume dirty (clear clean unmount bit) */ vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; - if (hfsmp->jnl && hfsmp->hfs_fs_ronly == 0) { + if (hfsmp->jnl && (hfsmp->hfs_flags & HFS_READ_ONLY) == 0) { hfs_flushvolumeheader(hfsmp, TRUE, TRUE); } @@ -441,17 +484,6 @@ VOP_UNLOCK(vcb->catalogRefNum, 0, p); VOP_UNLOCK(vcb->extentsRefNum, 0, p); - /* setup private/hidden directory for unlinked files */ - hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb); - if (hfsmp->jnl && (hfsmp->hfs_fs_ronly == 0)) - hfs_remove_orphans(hfsmp); - - if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected - { - MarkVCBDirty( vcb ); // mark VCB dirty so it will be written - } - - // // Check if we need to do late journal initialization. This only // happens if a previous version of MacOS X (or 9) touched the disk. @@ -482,6 +514,40 @@ } } + /* + * Establish a metadata allocation zone. + */ + hfs_metadatazone_init(hfsmp); + + /* + * Make any metadata zone adjustments. + */ + if (hfsmp->hfs_flags & HFS_METADATA_ZONE) { + /* Keep the roving allocator out of the metadata zone. */ + if (vcb->nextAllocation >= hfsmp->hfs_metazone_start && + vcb->nextAllocation <= hfsmp->hfs_metazone_end) { + vcb->nextAllocation = hfsmp->hfs_metazone_end + 1; + } + } + + /* setup private/hidden directory for unlinked files */ + FindMetaDataDirectory(vcb); + if (hfsmp->jnl && ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0)) + hfs_remove_orphans(hfsmp); + + if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected + { + MarkVCBDirty( vcb ); // mark VCB dirty so it will be written + } + + + /* + * Allow hot file clustering if conditions allow. + */ + if ((hfsmp->hfs_flags & HFS_METADATA_ZONE) && + ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0)) { + (void) hfs_recording_init(hfsmp, p); + } return (0); @@ -527,13 +593,20 @@ * *************************************************************/ -short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p) +__private_extern__ +int +hfsUnmount( register struct hfsmount *hfsmp, struct proc *p) { ExtendedVCB *vcb = HFSTOVCB(hfsmp); int retval = E_NONE; InvalidateCatalogCache( vcb ); + if (hfsmp->hfc_filevp) { + ReleaseMetaFileVNode(hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + } + if (vcb->vcbSigWord == kHFSPlusSigWord) ReleaseMetaFileVNode(vcb->allocationsRefNum); @@ -545,16 +618,11 @@ /* - * Some 3rd party kexts link against hfs_getcatalog so keep a stub for now. + * Test is fork has overflow extents. */ -short -hfs_getcatalog(void *p1, u_long p2, void *p3, short p4, void *p5) -{ - return ENOENT; -} - - -int overflow_extents(struct filefork *fp) +__private_extern__ +int +overflow_extents(struct filefork *fp) { u_long blocks; @@ -583,7 +651,10 @@ } -/* __private_extern__ */ +/* + * Lock/Unlock a metadata file. + */ +__private_extern__ int hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p) { @@ -610,19 +681,19 @@ panic("hfs_lockmetafile: invalid fileID"); } - /* Release, if necesary any locked buffer caches */ - if ((flags & LK_TYPE_MASK) == LK_RELEASE) { + if ((flags & LK_TYPE_MASK) != LK_RELEASE) { + flags |= LK_RETRY; + } else if (hfsmp->jnl == NULL) { struct timeval tv = time; u_int32_t lastfsync = tv.tv_sec; (void) BTGetLastSync((FCB*)VTOF(vp), &lastfsync); numOfLockedBuffs = count_lock_queue(); - if ((numOfLockedBuffs > kMaxLockedMetaBuffers) || ((numOfLockedBuffs>1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) { + if ((numOfLockedBuffs > kMaxLockedMetaBuffers) || + ((numOfLockedBuffs > 1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) { hfs_btsync(vp, HFS_SYNCTRANS); } - } else { - flags |= LK_RETRY; } retval = lockmgr(&VTOC(vp)->c_lock, flags, &vp->v_interlock, p); @@ -645,7 +716,7 @@ void * self; pid = current_proc()->p_pid; - self = (void *) current_thread(); + self = (void *) current_act(); lkp = &VTOC(vp)->c_lock; simple_lock(&lkp->lk_interlock); @@ -680,13 +751,11 @@ * There are three ways to qualify for ownership rights on an object: * * 1. (a) Your UID matches the cnode's UID. - * (b) The object in question is owned by "unknown" and - * your UID matches the console user's UID. + * (b) The object in question is owned by "unknown" * 2. (a) Permissions on the filesystem are being ignored and * your UID matches the replacement UID. * (b) Permissions on the filesystem are being ignored and - * the replacement UID is "unknown" and - * your UID matches the console user UID. + * the replacement UID is "unknown". * 3. You are root. * */ @@ -695,11 +764,10 @@ struct proc *p, int invokesuperuserstatus) { if ((cred->cr_uid == cnode_uid) || /* [1a] */ - ((cnode_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */ + (cnode_uid == UNKNOWNUID) || /* [1b] */ ((HFSTOVFS(hfsmp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */ ((cred->cr_uid == hfsmp->hfs_uid) || /* [2a] */ - ((hfsmp->hfs_uid == UNKNOWNUID) && /* [2b] */ - (cred->cr_uid == console_user)))) || + (hfsmp->hfs_uid == UNKNOWNUID))) || /* [2b] */ (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) { /* [3] */ return (0); } else { @@ -755,8 +823,9 @@ * To make the HFS Plus filesystem follow UFS unlink semantics, a remove * of an active vnode is translated to a move/rename so the file appears * deleted. The destination folder for these move/renames is setup here - * and a reference to it is place in hfsmp->hfs_private_metadata_dir. + * and a reference to it is place in hfsmp->hfs_privdir_desc. */ +__private_extern__ u_long FindMetaDataDirectory(ExtendedVCB *vcb) { @@ -765,7 +834,9 @@ struct cnode * dcp = NULL; struct FndrDirInfo * fndrinfo; struct cat_desc out_desc = {0}; + struct proc *p = current_proc(); struct timeval tv; + cat_cookie_t cookie; int error; if (vcb->vcbSigWord != kHFSPlusSigWord) @@ -781,28 +852,52 @@ } /* Lock catalog b-tree */ - error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, current_proc()); - if (error) + if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p) != 0) return (0); error = cat_lookup(hfsmp, &hfsmp->hfs_privdir_desc, 0, NULL, &hfsmp->hfs_privdir_attr, NULL); + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + if (error == 0) { - /* Unlock catalog b-tree */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); hfsmp->hfs_metadata_createdate = hfsmp->hfs_privdir_attr.ca_itime; + hfsmp->hfs_privdir_desc.cd_cnid = hfsmp->hfs_privdir_attr.ca_fileid; + /* + * Clear the system immutable flag if set... + */ + if ((hfsmp->hfs_privdir_attr.ca_flags & SF_IMMUTABLE) && + (hfsmp->hfs_flags & HFS_READ_ONLY) == 0) { + hfsmp->hfs_privdir_attr.ca_flags &= ~SF_IMMUTABLE; + + hfs_global_shared_lock_acquire(hfsmp); + if (hfsmp->jnl) { + if ((error = journal_start_transaction(hfsmp->jnl)) != 0) { + hfs_global_shared_lock_release(hfsmp); + return (hfsmp->hfs_privdir_attr.ca_fileid); + } + } + if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p) == 0) { + (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc, + &hfsmp->hfs_privdir_attr, NULL, NULL); + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + } + if (hfsmp->jnl) { + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); + } return (hfsmp->hfs_privdir_attr.ca_fileid); - } else if (hfsmp->hfs_fs_ronly) { - /* Unlock catalog b-tree */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); + + } else if (hfsmp->hfs_flags & HFS_READ_ONLY) { + return (0); } /* Setup the default attributes */ bzero(&hfsmp->hfs_privdir_attr, sizeof(struct cat_attr)); hfsmp->hfs_privdir_attr.ca_mode = S_IFDIR; - hfsmp->hfs_privdir_attr.ca_flags = SF_IMMUTABLE; hfsmp->hfs_privdir_attr.ca_nlink = 2; hfsmp->hfs_privdir_attr.ca_itime = vcb->vcbCrDate; hfsmp->hfs_privdir_attr.ca_mtime = time.tv_sec; @@ -821,12 +916,24 @@ return (0); } } + /* Reserve some space in the Catalog file. */ + if (cat_preflight(hfsmp, CAT_CREATE, &cookie, p) != 0) { + if (hfsmp->jnl) { + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); + return (0); + } - error = cat_create(hfsmp, &hfsmp->hfs_privdir_desc, - &hfsmp->hfs_privdir_attr, &out_desc); + if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p) == 0) { + error = cat_create(hfsmp, &hfsmp->hfs_privdir_desc, + &hfsmp->hfs_privdir_attr, &out_desc); - /* Unlock catalog b-tree */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + } + + cat_postflight(hfsmp, &cookie, p); + if (error) { if (hfsmp->jnl) { journal_end_transaction(hfsmp->jnl); @@ -896,7 +1003,7 @@ if (error == 0) { return (fattr->ca_fileid); - } else if (hfsmp->hfs_fs_ronly) { + } else if (hfsmp->hfs_flags & HFS_READ_ONLY) { return (0); } } @@ -916,15 +1023,20 @@ struct FSBufferDescriptor btdata; struct HFSPlusCatalogFile filerec; struct HFSPlusCatalogKey * keyp; + struct proc *p = current_proc(); FCB *fcb; ExtendedVCB *vcb; char filename[32]; char tempname[32]; size_t namelen; + cat_cookie_t cookie = {0}; int catlock = 0; - int result, started_tr = 0; + int catreserve = 0; + int started_tr = 0; + int shared_lock = 0; + int result; - if (hfsmp->hfs_orphans_cleaned) + if (hfsmp->hfs_flags & HFS_CLEANED_ORPHANS) return; vcb = HFSTOVCB(hfsmp); @@ -937,38 +1049,34 @@ MALLOC(iterator, struct BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); bzero(iterator, sizeof(*iterator)); keyp = (HFSPlusCatalogKey*)&iterator->key; - keyp->parentID = hfsmp->hfs_private_metadata_dir; - - // XXXdbg - hfs_global_shared_lock_acquire(hfsmp); - if (hfsmp->jnl) { - if (journal_start_transaction(hfsmp->jnl) != 0) { - hfs_global_shared_lock_release(hfsmp); - return; - } - started_tr = 1; - } + keyp->parentID = hfsmp->hfs_privdir_desc.cd_cnid; - /* Lock catalog b-tree */ - result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, current_proc()); + result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); if (result) goto exit; - catlock = 1; - /* * Position the iterator at the folder thread record. * (i.e. one record before first child) */ result = BTSearchRecord(fcb, iterator, NULL, NULL, iterator); + + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); if (result) goto exit; /* Visit all the children in the HFS+ private directory. */ for (;;) { + result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (result) + goto exit; + result = BTIterateRecord(fcb, kBTreeNextRecord, iterator, &btdata, NULL); + + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); if (result) break; - if (keyp->parentID != hfsmp->hfs_private_metadata_dir) + + if (keyp->parentID != hfsmp->hfs_privdir_desc.cd_cnid) break; if (filerec.recordType != kHFSPlusFileRecord) continue; @@ -982,46 +1090,92 @@ * Delete all files named "tempxxx", where * xxx is the file's cnid in decimal. * - * Delete all files named "iNodexxx", that - * have a link count of zero. */ if (bcmp(tempname, filename, namelen) == 0) { - struct filefork fork = {0}; - struct cnode cnode = {0}; + struct filefork dfork = {0}; + struct filefork rfork = {0}; + struct cnode cnode = {0}; + + // XXXdbg + hfs_global_shared_lock_acquire(hfsmp); + shared_lock = 1; + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + goto exit; + } + started_tr = 1; + } + + /* + * Reserve some space in the Catalog file. + */ + if (cat_preflight(hfsmp, CAT_DELETE, &cookie, p) != 0) { + goto exit; + } + catreserve = 1; - // XXXdebug - //printf("hfs_remove_orphans: removing %s\n", filename); + /* Lock catalog b-tree */ + if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, + LK_EXCLUSIVE, p) != 0) { + goto exit; + } + catlock = 1; /* Build a fake cnode */ - cnode.c_desc.cd_parentcnid = hfsmp->hfs_private_metadata_dir; + cat_convertattr(hfsmp, (CatalogRecord *)&filerec, &cnode.c_attr, + &dfork.ff_data, &rfork.ff_data); + cnode.c_desc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid; cnode.c_desc.cd_nameptr = filename; cnode.c_desc.cd_namelen = namelen; - cnode.c_desc.cd_cnid = filerec.fileID; - cnode.c_attr.ca_fileid = filerec.fileID; - cnode.c_blocks = filerec.dataFork.totalBlocks + - filerec.resourceFork.totalBlocks; + cnode.c_desc.cd_cnid = cnode.c_attr.ca_fileid; + cnode.c_blocks = dfork.ff_blocks + rfork.ff_blocks; /* Position iterator at previous entry */ if (BTIterateRecord(fcb, kBTreePrevRecord, iterator, - NULL, NULL) != 0) + NULL, NULL) != 0) { break; - + } + /* Truncate the file to zero (both forks) */ - if (filerec.dataFork.totalBlocks > 0) { - fork.ff_cp = &cnode; - cnode.c_datafork = ⋔ - bcopy(&filerec.dataFork, &fork.ff_data, sizeof(struct cat_fork)); - if (TruncateFileC(vcb, (FCB*)&fork, 0, false) != 0) { - printf("error truncting data fork!\n"); - break; + if (dfork.ff_blocks > 0) { + u_int64_t fsize; + + dfork.ff_cp = &cnode; + cnode.c_datafork = &dfork; + cnode.c_rsrcfork = NULL; + fsize = (u_int64_t)dfork.ff_blocks * (u_int64_t)HFSTOVCB(hfsmp)->blockSize; + while (fsize > 0) { + if (fsize > HFS_BIGFILE_SIZE) { + fsize -= HFS_BIGFILE_SIZE; + } else { + fsize = 0; + } + + if (TruncateFileC(vcb, (FCB*)&dfork, fsize, false) != 0) { + printf("error truncting data fork!\n"); + break; + } + + // + // if we're iteratively truncating this file down, + // then end the transaction and start a new one so + // that no one transaction gets too big. + // + if (fsize > 0 && started_tr) { + journal_end_transaction(hfsmp->jnl); + if (journal_start_transaction(hfsmp->jnl) != 0) { + started_tr = 0; + break; + } + } } } - if (filerec.resourceFork.totalBlocks > 0) { - fork.ff_cp = &cnode; + + if (rfork.ff_blocks > 0) { + rfork.ff_cp = &cnode; cnode.c_datafork = NULL; - cnode.c_rsrcfork = ⋔ - bcopy(&filerec.resourceFork, &fork.ff_data, sizeof(struct cat_fork)); - if (TruncateFileC(vcb, (FCB*)&fork, 0, false) != 0) { + cnode.c_rsrcfork = &rfork; + if (TruncateFileC(vcb, (FCB*)&rfork, 0, false) != 0) { printf("error truncting rsrc fork!\n"); break; } @@ -1038,21 +1192,37 @@ (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc, &hfsmp->hfs_privdir_attr, NULL, NULL); hfs_volupdate(hfsmp, VOL_RMFILE, 0); - } - } + + /* Drop locks and end the transaction */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + cat_postflight(hfsmp, &cookie, p); + catlock = catreserve = 0; + if (started_tr) { + journal_end_transaction(hfsmp->jnl); + started_tr = 0; + } + hfs_global_shared_lock_release(hfsmp); + shared_lock = 0; + + } /* end if */ + } /* end for */ exit: - /* Unlock catalog b-tree */ - if (catlock) - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); - + if (catlock) { + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + } + if (catreserve) { + cat_postflight(hfsmp, &cookie, p); + } if (started_tr) { journal_end_transaction(hfsmp->jnl); } - hfs_global_shared_lock_release(hfsmp); + if (shared_lock) { + hfs_global_shared_lock_release(hfsmp); + } FREE(iterator, M_TEMP); - hfsmp->hfs_orphans_cleaned = 1; + hfsmp->hfs_flags |= HFS_CLEANED_ORPHANS; } @@ -1111,8 +1281,47 @@ else freeblks = 0; } + if (freeblks > vcb->loanedBlocks) + freeblks -= vcb->loanedBlocks; + else + freeblks = 0; + +#ifdef HFS_SPARSE_DEV + /* + * When the underlying device is sparse, check the + * available space on the backing store volume. + */ + if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) && hfsmp->hfs_backingfs_rootvp) { + struct statfs statbuf; /* 272 bytes */ + u_int32_t vfreeblks; + u_int32_t loanedblks; + struct mount * backingfs_mp; + + backingfs_mp = hfsmp->hfs_backingfs_rootvp->v_mount; + + if (VFS_STATFS(backingfs_mp, &statbuf, current_proc()) == 0) { + vfreeblks = statbuf.f_bavail; + /* Normalize block count if needed. */ + if (statbuf.f_bsize != vcb->blockSize) { + vfreeblks = ((u_int64_t)vfreeblks * (u_int64_t)statbuf.f_bsize) / vcb->blockSize; + } + if (vfreeblks > hfsmp->hfs_sparsebandblks) + vfreeblks -= hfsmp->hfs_sparsebandblks; + else + vfreeblks = 0; + + /* Take into account any delayed allocations. */ + loanedblks = 2 * vcb->loanedBlocks; + if (vfreeblks > loanedblks) + vfreeblks -= loanedblks; + else + vfreeblks = 0; + + freeblks = MIN(vfreeblks, freeblks); + } + } +#endif /* HFS_SPARSE_DEV */ - freeblks -= vcb->loanedBlocks; return (freeblks); } @@ -1127,9 +1336,8 @@ switch (err) { case dskFulErr: /* -34 */ + case btNoSpaceAvail: /* -32733 */ return ENOSPC; - case btNoSpaceAvail: /* -32733 */ - return EFBIG; case fxOvFlErr: /* -32750 */ return EOVERFLOW; @@ -1184,7 +1392,7 @@ void *self; if (index > 0) { - self = current_thread(); + self = current_act(); SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) { if ((entry->hi_index == index) && (entry->hi_thread == self)) @@ -1211,7 +1419,7 @@ MALLOC(entry, struct hfs_index *, len + sizeof(struct hfs_index), M_TEMP, M_WAITOK); entry->hi_index = index; - entry->hi_thread = current_thread(); + entry->hi_thread = current_act(); bcopy(namehint, entry->hi_name, len + 1); SLIST_INSERT_HEAD(&dcp->c_indexlist, entry, hi_link); } @@ -1229,7 +1437,7 @@ void *self; if (index > 0) { - self = current_thread(); + self = current_act(); SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) { if ((entry->hi_index == index) && (entry->hi_thread == self)) { @@ -1341,6 +1549,7 @@ // save this off for the hack-y check in hfs_remove() hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize); + hfsmp->jnl_size = jibp->size; if (jibp->flags & kJIJournalNeedInitMask) { printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n", @@ -1358,6 +1567,8 @@ // we'd just re-init it on the next mount. jibp->flags &= ~kJIJournalNeedInitMask; jibp->flags = SWAP_BE32(jibp->flags); + jibp->offset = SWAP_BE64(jibp->offset); + jibp->size = SWAP_BE64(jibp->size); bwrite(jinfo_bp); jinfo_bp = NULL; jibp = NULL; @@ -1382,6 +1593,9 @@ if (hfsmp->jnl && mdbp) { // reload the mdb because it could have changed // if the journal had to be replayed. + if (mdb_offset == 0) { + mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize); + } retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp); if (retval) { brelse(bp); @@ -1401,9 +1615,7 @@ // if we expected the journal to be there and we couldn't // create it or open it then we have to bail out. if (hfsmp->jnl == NULL) { - hfsmp->jnl_start = 0; - - printf("hfs: failed to open/create the journal (retval %d).\n", retval); + printf("hfs: early jnl init: failed to open/create the journal (retval %d).\n", retval); return EINVAL; } @@ -1524,6 +1736,7 @@ // save this off for the hack-y check in hfs_remove() hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize); + hfsmp->jnl_size = jibp->size; if (jibp->flags & kJIJournalNeedInitMask) { printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n", @@ -1585,11 +1798,226 @@ // if we expected the journal to be there and we couldn't // create it or open it then we have to bail out. if (hfsmp->jnl == NULL) { - hfsmp->jnl_start = 0; - - printf("hfs: failed to open/create the journal (retval %d).\n", retval); + printf("hfs: late jnl init: failed to open/create the journal (retval %d).\n", retval); return EINVAL; } return 0; } + +/* + * Calculate the allocation zone for metadata. + * + * This zone includes the following: + * Allocation Bitmap file + * Overflow Extents file + * Journal file + * Quota files + * Clustered Hot files + * Catalog file + * + * METADATA ALLOCATION ZONE + * ____________________________________________________________________________ + * | | | | | | | + * | BM | JF | OEF | CATALOG |---> | HOT FILES | + * |____|____|_____|_______________|______________________________|___________| + * + * <------------------------------- N * 128 MB -------------------------------> + * + */ +#define GIGABYTE (u_int64_t)(1024*1024*1024) + +#define OVERFLOW_DEFAULT_SIZE (4*1024*1024) +#define OVERFLOW_MAXIMUM_SIZE (128*1024*1024) +#define JOURNAL_DEFAULT_SIZE (8*1024*1024) +#define JOURNAL_MAXIMUM_SIZE (512*1024*1024) +#define HOTBAND_MINIMUM_SIZE (10*1024*1024) +#define HOTBAND_MAXIMUM_SIZE (512*1024*1024) + +static void +hfs_metadatazone_init(struct hfsmount *hfsmp) +{ + ExtendedVCB *vcb; + struct BTreeInfoRec btinfo; + u_int64_t fs_size; + u_int64_t zonesize; + u_int64_t temp; + u_int64_t filesize; + u_int32_t blk; + int items; + + vcb = HFSTOVCB(hfsmp); + fs_size = (u_int64_t)vcb->blockSize * (u_int64_t)vcb->totalBlocks; + + /* + * For volumes less than 10 GB, don't bother. + */ + if (fs_size < ((u_int64_t)10 * GIGABYTE)) + return; + /* + * Skip non-journaled volumes as well. + */ + if (hfsmp->jnl == NULL) + return; + + /* + * Start with allocation bitmap (a fixed size). + */ + zonesize = roundup(vcb->totalBlocks / 8, vcb->vcbVBMIOSize); + + /* + * Overflow Extents file gets 4 MB per 100 GB. + */ + items = fs_size / ((u_int64_t)100 * GIGABYTE); + filesize = (u_int64_t)(items + 1) * OVERFLOW_DEFAULT_SIZE; + if (filesize > OVERFLOW_MAXIMUM_SIZE) + filesize = OVERFLOW_MAXIMUM_SIZE; + zonesize += filesize; + hfsmp->hfs_overflow_maxblks = filesize / vcb->blockSize; + + /* + * Plan for at least 8 MB of journal for each + * 100 GB of disk space (up to a 512 MB). + */ + items = fs_size / ((u_int64_t)100 * GIGABYTE); + filesize = (u_int64_t)(items + 1) * JOURNAL_DEFAULT_SIZE; + if (filesize > JOURNAL_MAXIMUM_SIZE) + filesize = JOURNAL_MAXIMUM_SIZE; + zonesize += filesize; + + /* + * Catalog file gets 10 MB per 1 GB. + * + * How about considering the current catalog size (used nodes * node size) + * and the current file data size to help estimate the required + * catalog size. + */ + filesize = MIN((fs_size / 1024) * 10, GIGABYTE); + hfsmp->hfs_catalog_maxblks = filesize / vcb->blockSize; + zonesize += filesize; + + /* + * Add space for hot file region. + * + * ...for now, use 5 MB per 1 GB (0.5 %) + */ + filesize = (fs_size / 1024) * 5; + if (filesize > HOTBAND_MAXIMUM_SIZE) + filesize = HOTBAND_MAXIMUM_SIZE; + else if (filesize < HOTBAND_MINIMUM_SIZE) + filesize = HOTBAND_MINIMUM_SIZE; + /* + * Calculate user quota file requirements. + */ + items = QF_USERS_PER_GB * (fs_size / GIGABYTE); + if (items < QF_MIN_USERS) + items = QF_MIN_USERS; + else if (items > QF_MAX_USERS) + items = QF_MAX_USERS; + if (!powerof2(items)) { + int x = items; + items = 4; + while (x>>1 != 1) { + x = x >> 1; + items = items << 1; + } + } + filesize += (items + 1) * sizeof(struct dqblk); + /* + * Calculate group quota file requirements. + * + */ + items = QF_GROUPS_PER_GB * (fs_size / GIGABYTE); + if (items < QF_MIN_GROUPS) + items = QF_MIN_GROUPS; + else if (items > QF_MAX_GROUPS) + items = QF_MAX_GROUPS; + if (!powerof2(items)) { + int x = items; + items = 4; + while (x>>1 != 1) { + x = x >> 1; + items = items << 1; + } + } + filesize += (items + 1) * sizeof(struct dqblk); + hfsmp->hfs_hotfile_maxblks = filesize / vcb->blockSize; + zonesize += filesize; + + /* + * Round up entire zone to a bitmap block's worth. + * The extra space goes to the catalog file and hot file area. + */ + temp = zonesize; + zonesize = roundup(zonesize, vcb->vcbVBMIOSize * 8 * vcb->blockSize); + temp = zonesize - temp; /* temp has extra space */ + filesize += temp / 3; + hfsmp->hfs_catalog_maxblks += (temp - (temp / 3)) / vcb->blockSize; + + /* Convert to allocation blocks. */ + blk = zonesize / vcb->blockSize; + + /* The default metadata zone location is at the start of volume. */ + hfsmp->hfs_metazone_start = 1; + hfsmp->hfs_metazone_end = blk - 1; + + /* The default hotfile area is at the end of the zone. */ + hfsmp->hfs_hotfile_start = blk - (filesize / vcb->blockSize); + hfsmp->hfs_hotfile_end = hfsmp->hfs_metazone_end; + hfsmp->hfs_hotfile_freeblks = hfs_hotfile_freeblocks(hfsmp); +#if 0 + printf("HFS: metadata zone is %d to %d\n", hfsmp->hfs_metazone_start, hfsmp->hfs_metazone_end); + printf("HFS: hot file band is %d to %d\n", hfsmp->hfs_hotfile_start, hfsmp->hfs_hotfile_end); + printf("HFS: hot file band free blocks = %d\n", hfsmp->hfs_hotfile_freeblks); +#endif + hfsmp->hfs_flags |= HFS_METADATA_ZONE; +} + + +static u_int32_t +hfs_hotfile_freeblocks(struct hfsmount *hfsmp) +{ + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + int freeblocks; + + freeblocks = MetaZoneFreeBlocks(vcb); + /* Minus Extents overflow file reserve. */ + freeblocks -= + hfsmp->hfs_overflow_maxblks - VTOF(vcb->extentsRefNum)->ff_blocks; + /* Minus catalog file reserve. */ + freeblocks -= + hfsmp->hfs_catalog_maxblks - VTOF(vcb->catalogRefNum)->ff_blocks; + if (freeblocks < 0) + freeblocks = 0; + + return MIN(freeblocks, hfsmp->hfs_hotfile_maxblks); +} + +/* + * Determine if a file is a "virtual" metadata file. + * This includes journal and quota files. + */ +__private_extern__ +int +hfs_virtualmetafile(struct cnode *cp) +{ + char * filename; + + + if (cp->c_parentcnid != kHFSRootFolderID) + return (0); + + filename = cp->c_desc.cd_nameptr; + if (filename == NULL) + return (0); + + if ((strcmp(filename, ".journal") == 0) || + (strcmp(filename, ".journal_info_block") == 0) || + (strcmp(filename, ".quota.user") == 0) || + (strcmp(filename, ".quota.group") == 0) || + (strcmp(filename, ".hotfiles.btree") == 0)) + return (1); + + return (0); +} + diff -urN xnu-344.49/bsd/hfs/hfs_vnops.c xnu-517/bsd/hfs/hfs_vnops.c --- xnu-344.49/bsd/hfs/hfs_vnops.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfs_vnops.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -58,14 +60,16 @@ #define MAKE_DELETED_NAME(NAME,FID) \ (void) sprintf((NAME), "%s%d", HFS_DELETE_PREFIX, (FID)) +#define KNDETACH_VNLOCKED 0x00000001 -extern uid_t console_user; +#define CARBON_TEMP_DIR_NAME "Cleanup At Startup" -extern unsigned long strtoul(const char *, char **, int); /* Global vfs data structures for hfs */ +extern unsigned long strtoul(const char *, char **, int); + extern int groupmember(gid_t gid, struct ucred *cred); static int hfs_makenode(int mode, struct vnode *dvp, struct vnode **vpp, @@ -76,6 +80,19 @@ static int hfs_metasync(struct hfsmount *hfsmp, daddr_t node, struct proc *p); +static int hfs_removedir(struct vnode *, struct vnode *, struct componentname *, + int); + +static int hfs_removefile(struct vnode *, struct vnode *, struct componentname *, + int); + +/* Options for hfs_removedir and hfs_removefile */ +#define HFSRM_PARENT_LOCKED 0x01 +#define HFSRM_SKIP_RESERVE 0x02 +#define HFSRM_SAVE_NAME 0x04 +#define HFSRM_RENAMEOPTS 0x07 + + int hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags); int hfs_chflags(struct vnode *vp, u_long flags, struct ucred *cred, @@ -200,6 +217,8 @@ } */ *ap; { struct vnode *vp = ap->a_vp; + struct filefork *fp = VTOF(vp); + struct timeval tv; /* * Files marked append-only must be opened for appending. @@ -208,6 +227,36 @@ (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) return (EPERM); + if (ap->a_mode & O_EVTONLY) { + if (vp->v_type == VREG) { + ++VTOF(vp)->ff_evtonly_refs; + } else { + ++VTOC(vp)->c_evtonly_refs; + }; + }; + + /* + * On the first (non-busy) open of a fragmented + * file attempt to de-frag it (if its less than 20MB). + */ + if ((VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) || + !UBCISVALID(vp) || ubc_isinuse(vp, 1)) { + return (0); + } + fp = VTOF(vp); + if (fp->ff_blocks && + fp->ff_extents[7].blockCount != 0 && + fp->ff_size <= (20 * 1024 * 1024)) { + /* + * Wait until system bootup is done (3 min). + */ + microuptime(&tv); + if (tv.tv_sec < (60 * 3)) { + return (0); + } + (void) hfs_relocate(vp, VTOVCB(vp)->nextAllocation + 4096, ap->a_cred, ap->a_p); + } + return (0); } @@ -252,6 +301,14 @@ } simple_unlock(&vp->v_interlock); + if (ap->a_fflag & O_EVTONLY) { + if (vp->v_type == VREG) { + --VTOF(vp)->ff_evtonly_refs; + } else { + --VTOC(vp)->c_evtonly_refs; + }; + }; + /* * VOP_CLOSE can be called with vp locked (from vclean). * We check for this case using VOP_ISLOCKED and bail. @@ -263,7 +320,9 @@ leof = fp->ff_size; - if ((fp->ff_blocks > 0) && !ISSET(cp->c_flag, C_DELETED)) { + if ((fp->ff_blocks > 0) && + !ISSET(cp->c_flag, C_DELETED) && + ((VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) == 0)) { enum vtype our_type = vp->v_type; u_long our_id = vp->v_id; int was_nocache = ISSET(vp->v_flag, VNOCACHE_DATA); @@ -336,6 +395,8 @@ } VOP_UNLOCK(vp, 0, p); } + if ((vp->v_flag & VSYSTEM) && (vp->v_usecount == 1)) + vgone(vp); return (0); } @@ -378,7 +439,7 @@ case VDIR: case VLNK: case VREG: - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) return (EROFS); #if QUOTA if ((error = hfs_getinoquota(cp))) @@ -386,20 +447,20 @@ #endif /* QUOTA */ break; } + /* If immutable bit set, nobody gets to write it. */ + if (cp->c_flags & IMMUTABLE) + return (EPERM); } - /* If immutable bit set, nobody gets to write it. */ - if ((mode & VWRITE) && (cp->c_flags & IMMUTABLE)) - return (EPERM); /* Otherwise, user id 0 always gets access. */ - if (ap->a_cred->cr_uid == 0) + if (cred->cr_uid == 0) return (0); mask = 0; /* Otherwise, check the owner. */ - if (hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, ap->a_p, false) == 0) { + if ( (cp->c_uid == cred->cr_uid) || (cp->c_uid == UNKNOWNUID) ) { if (mode & VEXEC) mask |= S_IXUSR; if (mode & VREAD) @@ -466,6 +527,8 @@ CTIMES(cp, &tv, &tv); vap->va_type = vp->v_type; + vap->va_mode = cp->c_mode; + vap->va_nlink = cp->c_nlink; /* * [2856576] Since we are dynamically changing the owner, also * effectively turn off the set-user-id and set-group-id bits, @@ -473,9 +536,12 @@ * a security hole where set-user-id programs run as whoever is * logged on (or root if nobody is logged in yet!) */ - vap->va_mode = (cp->c_uid == UNKNOWNUID) ? cp->c_mode & ~(S_ISUID | S_ISGID) : cp->c_mode; - vap->va_nlink = cp->c_nlink; - vap->va_uid = (cp->c_uid == UNKNOWNUID) ? console_user : cp->c_uid; + if (cp->c_uid == UNKNOWNUID) { + vap->va_mode &= ~(S_ISUID | S_ISGID); + vap->va_uid = ap->a_cred->cr_uid; + } else { + vap->va_uid = cp->c_uid; + } vap->va_gid = cp->c_gid; vap->va_fsid = cp->c_dev; /* @@ -502,7 +568,6 @@ vap->va_rdev = 0; vap->va_blocksize = VTOVFS(vp)->mnt_stat.f_iosize; vap->va_filerev = 0; - vap->va_spare = 0; if (vp->v_type == VDIR) { vap->va_size = cp->c_nlink * AVERAGE_HFSDIRENTRY_SIZE; vap->va_bytes = 0; @@ -555,8 +620,19 @@ return (EINVAL); } + // XXXdbg + // don't allow people to set the attributes of symlinks + // (nfs has a bad habit of doing ths and it can cause + // problems for journaling). + // + if (vp->v_type == VLNK) { + return 0; + } + + + if (vap->va_flags != VNOVAL) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) return (EROFS); if ((error = hfs_chflags(vp, vap->va_flags, cred, p))) return (error); @@ -571,7 +647,7 @@ if (VTOHFS(vp)->jnl && cp->c_datafork) { struct HFSPlusExtentDescriptor *extd; - extd = &cp->c_datafork->ff_data.cf_extents[0]; + extd = &cp->c_datafork->ff_extents[0]; if (extd->startBlock == VTOVCB(vp)->vcbJinfoBlock || extd->startBlock == VTOHFS(vp)->jnl_start) { return EPERM; } @@ -581,7 +657,7 @@ * Go through the fields and update iff not VNOVAL. */ if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) return (EROFS); if ((error = hfs_chown(vp, vap->va_uid, vap->va_gid, cred, p))) return (error); @@ -597,7 +673,7 @@ return (EISDIR); case VLNK: case VREG: - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) return (EROFS); break; default: @@ -608,7 +684,7 @@ } cp = VTOC(vp); if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) return (EROFS); if (((error = hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, p, true)) != 0) && ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || @@ -640,10 +716,11 @@ } error = 0; if (vap->va_mode != (mode_t)VNOVAL) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) return (EROFS); error = hfs_chmod(vp, (int)vap->va_mode, cred, p); } + HFS_KNOTE(vp, NOTE_ATTRIB); return (error); } @@ -652,6 +729,7 @@ * Change the mode on a file. * cnode must be locked before calling. */ +__private_extern__ int hfs_chmod(vp, mode, cred, p) register struct vnode *vp; @@ -669,7 +747,7 @@ if (VTOHFS(vp)->jnl && cp && cp->c_datafork) { struct HFSPlusExtentDescriptor *extd; - extd = &cp->c_datafork->ff_data.cf_extents[0]; + extd = &cp->c_datafork->ff_extents[0]; if (extd->startBlock == VTOVCB(vp)->vcbJinfoBlock || extd->startBlock == VTOHFS(vp)->jnl_start) { return EPERM; } @@ -695,6 +773,7 @@ } +__private_extern__ int hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags) { @@ -712,9 +791,9 @@ case VDIR: case VLNK: case VREG: - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) return (EROFS); - break; + break; default: break; } @@ -747,6 +826,7 @@ * Change the flags on a file or directory. * cnode must be locked before calling. */ +__private_extern__ int hfs_chflags(vp, flags, cred, p) register struct vnode *vp; @@ -789,6 +869,7 @@ * Perform chown operation on cnode cp; * code must be locked prior to call. */ +__private_extern__ int hfs_chown(vp, uid, gid, cred, p) register struct vnode *vp; @@ -934,14 +1015,13 @@ { struct vnode *from_vp = ap->a_fvp; struct vnode *to_vp = ap->a_tvp; - struct vnode *from_rvp = NULL; - struct vnode *to_rvp = NULL; struct cnode *from_cp = VTOC(from_vp); struct cnode *to_cp = VTOC(to_vp); struct hfsmount *hfsmp = VTOHFS(from_vp); struct cat_desc tempdesc; struct cat_attr tempattr; int error = 0, started_tr = 0, grabbed_lock = 0; + cat_cookie_t cookie = {0}; /* The files must be on the same volume. */ if (from_vp->v_mount != to_vp->v_mount) @@ -958,45 +1038,20 @@ struct HFSPlusExtentDescriptor *extd; if (from_cp->c_datafork) { - extd = &from_cp->c_datafork->ff_data.cf_extents[0]; + extd = &from_cp->c_datafork->ff_extents[0]; if (extd->startBlock == VTOVCB(from_vp)->vcbJinfoBlock || extd->startBlock == hfsmp->jnl_start) { return EPERM; } } if (to_cp->c_datafork) { - extd = &to_cp->c_datafork->ff_data.cf_extents[0]; + extd = &to_cp->c_datafork->ff_extents[0]; if (extd->startBlock == VTOVCB(to_vp)->vcbJinfoBlock || extd->startBlock == hfsmp->jnl_start) { return EPERM; } } } - from_rvp = from_cp->c_rsrc_vp; - to_rvp = to_cp->c_rsrc_vp; - - /* If one of the resource forks is open then get the other one. */ - if (from_rvp || to_rvp) { - error = hfs_vgetrsrc(hfsmp, from_vp, &from_rvp, ap->a_p); - if (error) - return (error); - error = hfs_vgetrsrc(hfsmp, to_vp, &to_rvp, ap->a_p); - if (error) { - vrele(from_rvp); - return (error); - } - } - - /* Ignore any errors, we are doing a 'best effort' on flushing */ - if (from_vp) - (void) vinvalbuf(from_vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); - if (to_vp) - (void) vinvalbuf(to_vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); - if (from_rvp) - (void) vinvalbuf(from_rvp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); - if (to_rvp) - (void) vinvalbuf(to_rvp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); - // XXXdbg hfs_global_shared_lock_acquire(hfsmp); grabbed_lock = 1; @@ -1007,6 +1062,13 @@ started_tr = 1; } + /* + * Reserve some space in the Catalog file. + */ + if ((error = cat_preflight(hfsmp, CAT_EXCHANGE, &cookie, ap->a_p))) { + goto Err_Exit; + } + /* Lock catalog b-tree */ error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p); if (error) goto Err_Exit; @@ -1091,18 +1153,17 @@ from_cp->c_flags &= ~UF_NODUMP; from_cp->c_flag |= C_CHANGE; } - if ((to_cp->c_flags & UF_NODUMP) && (to_cp->c_parentcnid != from_cp->c_parentcnid)) { to_cp->c_flags &= ~UF_NODUMP; to_cp->c_flag |= C_CHANGE; } + HFS_KNOTE(from_vp, NOTE_ATTRIB); + HFS_KNOTE(to_vp, NOTE_ATTRIB); + Err_Exit: - if (to_rvp) - vrele(to_rvp); - if (from_rvp) - vrele(from_rvp); + cat_postflight(hfsmp, &cookie, ap->a_p); // XXXdbg if (started_tr) { @@ -1161,12 +1222,7 @@ if (vp->v_flag & VSYSTEM) { if (VTOF(vp)->fcbBTCBPtr != NULL) { // XXXdbg - if (hfsmp->jnl) { - if (BTIsDirty(VTOF(vp))) { - panic("hfs: system file vp 0x%x has dirty blocks (jnl 0x%x)\n", - vp, hfsmp->jnl); - } - } else { + if (hfsmp->jnl == NULL) { BTFlushPath(VTOF(vp)); } } @@ -1311,6 +1367,18 @@ !ISSET(cp->c_flag, C_DELETED | C_NOEXISTS)) { hfs_metasync(VTOHFS(vp), cp->c_hint, ap->a_p); } + + // make sure that we've really been called from the user + // fsync() and if so push out any pending transactions + // that this file might is a part of (and get them on + // stable storage). + if (vp->v_flag & VFULLFSYNC) { + if (hfsmp->jnl) { + journal_flush(hfsmp->jnl); + } else { + VOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE, NULL, FWRITE, NOCRED, ap->a_p); + } + } } return (retval); @@ -1443,13 +1511,25 @@ struct componentname *a_cnp; } */ *ap; { - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct proc *p = ap->a_cnp->cn_proc; + return (hfs_removedir(ap->a_dvp, ap->a_vp, ap->a_cnp, 0)); +} + +/* + * hfs_removedir + */ +static int +hfs_removedir(dvp, vp, cnp, options) + struct vnode *dvp; + struct vnode *vp; + struct componentname *cnp; + int options; +{ + struct proc *p = cnp->cn_proc; struct cnode *cp; struct cnode *dcp; struct hfsmount * hfsmp; struct timeval tv; + cat_cookie_t cookie = {0}; int error = 0, started_tr = 0, grabbed_lock = 0; cp = VTOC(vp); @@ -1465,7 +1545,6 @@ #if QUOTA (void)hfs_getinoquota(cp); #endif - // XXXdbg hfs_global_shared_lock_acquire(hfsmp); grabbed_lock = 1; @@ -1476,6 +1555,15 @@ started_tr = 1; } + if (!(options & HFSRM_SKIP_RESERVE)) { + /* + * Reserve some space in the Catalog file. + */ + if ((error = cat_preflight(hfsmp, CAT_DELETE, &cookie, p))) { + goto out; + } + } + /* * Verify the directory is empty (and valid). * (Rmdir ".." won't be valid since @@ -1520,16 +1608,22 @@ dcp->c_flag |= C_CHANGE | C_UPDATE; tv = time; (void) VOP_UPDATE(dvp, &tv, &tv, 0); + HFS_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); hfs_volupdate(hfsmp, VOL_RMDIR, (dcp->c_cnid == kHFSRootFolderID)); cp->c_mode = 0; /* Makes the vnode go away...see inactive */ cp->c_flag |= C_NOEXISTS; out: - if (dvp) + if (!(options & HFSRM_PARENT_LOCKED)) { vput(dvp); + } + HFS_KNOTE(vp, NOTE_DELETE); vput(vp); + if (!(options & HFSRM_SKIP_RESERVE)) { + cat_postflight(hfsmp, &cookie, p); + } // XXXdbg if (started_tr) { journal_end_transaction(hfsmp->jnl); @@ -1561,23 +1655,42 @@ struct componentname *a_cnp; } */ *ap; { - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; + return (hfs_removefile(ap->a_dvp, ap->a_vp, ap->a_cnp, 0)); +} + + + +/* + * hfs_removefile + * + * Similar to hfs_remove except there are additional options. + */ +static int +hfs_removefile(dvp, vp, cnp, options) + struct vnode *dvp; + struct vnode *vp; + struct componentname *cnp; + int options; +{ struct vnode *rvp = NULL; struct cnode *cp; struct cnode *dcp; struct hfsmount *hfsmp; - struct proc *p = current_proc(); + struct proc *p = cnp->cn_proc; int dataforkbusy = 0; int rsrcforkbusy = 0; int truncated = 0; struct timeval tv; + cat_cookie_t cookie = {0}; int error = 0; int started_tr = 0, grabbed_lock = 0; + int refcount, isbigfile = 0; - /* Redirect directories to rmdir */ - if (vp->v_type == VDIR) - return (hfs_rmdir(ap)); + /* Directories should call hfs_rmdir! */ + if (vp->v_type == VDIR) { + error = EISDIR; + goto out; + } cp = VTOC(vp); dcp = VTOC(dvp); @@ -1610,7 +1723,7 @@ if (hfsmp->jnl && cp->c_datafork) { struct HFSPlusExtentDescriptor *extd; - extd = &cp->c_datafork->ff_data.cf_extents[0]; + extd = &cp->c_datafork->ff_extents[0]; if (extd->startBlock == HFSTOVCB(hfsmp)->vcbJinfoBlock || extd->startBlock == hfsmp->jnl_start) { error = EPERM; goto out; @@ -1624,18 +1737,27 @@ * vnode (vp). And we took a ref on the resource vnode (rvp). * Hence set 1 in the tookref parameter of ubc_isinuse(). */ - if (UBCISVALID(vp) && ubc_isinuse(vp, 1)) + if (VTOC(vp)->c_flag & C_VPREFHELD) { + refcount = 2; + } else { + refcount = 1; + } + if (UBCISVALID(vp) && ubc_isinuse(vp, refcount)) dataforkbusy = 1; if (rvp && UBCISVALID(rvp) && ubc_isinuse(rvp, 1)) rsrcforkbusy = 1; + // need this to check if we have to break the deletion + // into multiple pieces + isbigfile = (VTOC(vp)->c_datafork->ff_size >= HFS_BIGFILE_SIZE); + /* * Carbon semantics prohibit deleting busy files. * (enforced when NODELETEBUSY is requested) */ if ((dataforkbusy || rsrcforkbusy) && - ((ap->a_cnp->cn_flags & NODELETEBUSY) || - (hfsmp->hfs_private_metadata_dir == 0))) { + ((cnp->cn_flags & NODELETEBUSY) || + (hfsmp->hfs_privdir_desc.cd_cnid == 0))) { error = EBUSY; goto out; } @@ -1654,6 +1776,15 @@ started_tr = 1; } + if (!(options & HFSRM_SKIP_RESERVE)) { + /* + * Reserve some space in the Catalog file. + */ + if ((error = cat_preflight(hfsmp, CAT_DELETE, &cookie, p))) { + goto out; + } + } + /* Remove our entry from the namei cache. */ cache_purge(vp); @@ -1695,7 +1826,7 @@ if ((cp->c_flag & C_HARDLINK) == 0) { int mode = cp->c_mode; - if (!dataforkbusy && cp->c_datafork->ff_blocks != 0) { + if (!dataforkbusy && !isbigfile && cp->c_datafork->ff_blocks != 0) { cp->c_mode = 0; /* Suppress VOP_UPDATES */ error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p); cp->c_mode = mode; @@ -1722,16 +1853,16 @@ if (cp->c_flag & C_HARDLINK) { struct cat_desc desc; - if ((ap->a_cnp->cn_flags & HASBUF) == 0 || - ap->a_cnp->cn_nameptr[0] == '\0') { + if ((cnp->cn_flags & HASBUF) == 0 || + cnp->cn_nameptr[0] == '\0') { error = ENOENT; /* name missing! */ goto out; } /* Setup a descriptor for the link */ bzero(&desc, sizeof(desc)); - desc.cd_nameptr = ap->a_cnp->cn_nameptr; - desc.cd_namelen = ap->a_cnp->cn_namelen; + desc.cd_nameptr = cnp->cn_nameptr; + desc.cd_namelen = cnp->cn_namelen; desc.cd_parentcnid = dcp->c_cnid; /* XXX - if cnid is out of sync then the wrong thread rec will get deleted. */ desc.cd_cnid = cp->c_cnid; @@ -1760,7 +1891,7 @@ bzero(&from_desc, sizeof(from_desc)); from_desc.cd_nameptr = inodename; from_desc.cd_namelen = strlen(inodename); - from_desc.cd_parentcnid = hfsmp->hfs_private_metadata_dir; + from_desc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid; from_desc.cd_flags = 0; from_desc.cd_cnid = cp->c_fileid; @@ -1768,7 +1899,7 @@ bzero(&to_desc, sizeof(to_desc)); to_desc.cd_nameptr = delname; to_desc.cd_namelen = strlen(delname); - to_desc.cd_parentcnid = hfsmp->hfs_private_metadata_dir; + to_desc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid; to_desc.cd_flags = 0; to_desc.cd_cnid = cp->c_fileid; @@ -1780,10 +1911,6 @@ /* Unlock the Catalog */ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - /* All done with component name... */ - if ((ap->a_cnp->cn_flags & (HASBUF | SAVENAME)) == (HASBUF | SAVENAME)) - FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); - if (error != 0) goto out; @@ -1793,7 +1920,7 @@ hfs_volupdate(hfsmp, VOL_RMFILE, (dcp->c_cnid == kHFSRootFolderID)); - } else if (dataforkbusy || rsrcforkbusy) { + } else if (dataforkbusy || rsrcforkbusy || isbigfile) { char delname[32]; struct cat_desc to_desc; struct cat_desc todir_desc; @@ -1808,7 +1935,7 @@ bzero(&to_desc, sizeof(to_desc)); to_desc.cd_nameptr = delname; to_desc.cd_namelen = strlen(delname); - to_desc.cd_parentcnid = hfsmp->hfs_private_metadata_dir; + to_desc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid; to_desc.cd_flags = 0; to_desc.cd_cnid = cp->c_cnid; @@ -1839,9 +1966,14 @@ } else /* Not busy */ { if (cp->c_blocks > 0) { - printf("hfs_remove: attempting to delete a non-empty file!"); +#if 0 + panic("hfs_remove: attempting to delete a non-empty file!"); +#else + printf("hfs_remove: attempting to delete a non-empty file %s\n", + cp->c_desc.cd_nameptr); error = EBUSY; goto out; +#endif } /* Lock catalog b-tree */ @@ -1852,10 +1984,10 @@ error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr); if (error && error != ENXIO && error != ENOENT && truncated) { - if ((cp->c_datafork && cp->c_datafork->ff_data.cf_size != 0) || - (cp->c_rsrcfork && cp->c_rsrcfork->ff_data.cf_size != 0)) { + if ((cp->c_datafork && cp->c_datafork->ff_size != 0) || + (cp->c_rsrcfork && cp->c_rsrcfork->ff_size != 0)) { panic("hfs: remove: couldn't delete a truncated file! (%d, data sz %lld; rsrc sz %lld)", - error, cp->c_datafork->ff_data.cf_size, cp->c_rsrcfork->ff_data.cf_size); + error, cp->c_datafork->ff_size, cp->c_rsrcfork->ff_size); } else { printf("hfs: remove: strangely enough, deleting truncated file %s (%d) got err %d\n", cp->c_desc.cd_nameptr, cp->c_attr.ca_fileid, error); @@ -1871,6 +2003,7 @@ #endif /* QUOTA */ cp->c_mode = 0; + truncated = 0; // because the catalog entry is gone cp->c_flag |= C_CHANGE | C_NOEXISTS; --cp->c_nlink; hfs_volupdate(hfsmp, VOL_RMFILE, (dcp->c_cnid == kHFSRootFolderID)); @@ -1894,39 +2027,29 @@ dcp->c_flag |= C_CHANGE | C_UPDATE; tv = time; (void) VOP_UPDATE(dvp, &tv, &tv, 0); + HFS_KNOTE(dvp, NOTE_WRITE); - // XXXdbg - if (started_tr) { - journal_end_transaction(hfsmp->jnl); - } - if (grabbed_lock) { - hfs_global_shared_lock_release(hfsmp); +out: + /* All done with component name... */ + if ((options & HFSRM_SAVE_NAME) == 0 && + (cnp != 0) && + (cnp->cn_flags & (HASBUF | SAVENAME)) == (HASBUF | SAVENAME)) { + char *tmp = cnp->cn_pnbuf; + cnp->cn_pnbuf = NULL; + cnp->cn_flags &= ~HASBUF; + FREE_ZONE(tmp, cnp->cn_pnlen, M_NAMEI); } - if (rvp) - vrele(rvp); - VOP_UNLOCK(vp, 0, p); - // XXXdbg - try to prevent the lost ubc_info panic - if ((cp->c_flag & C_HARDLINK) == 0 || cp->c_nlink == 0) { - (void) ubc_uncache(vp); + if (!(options & HFSRM_SKIP_RESERVE)) { + cat_postflight(hfsmp, &cookie, p); } - vrele(vp); - vput(dvp); - - return (0); -out: - if (rvp) - vrele(rvp); - /* Commit the truncation to the catalog record */ if (truncated) { - cp->c_flag |= C_CHANGE | C_UPDATE; - tv = time; - (void) VOP_UPDATE(vp, &tv, &tv, 0); + cp->c_flag |= C_CHANGE | C_UPDATE | C_FORCEUPDATE; + tv = time; + (void) VOP_UPDATE(vp, &tv, &tv, 0); } - vput(vp); - vput(dvp); // XXXdbg if (started_tr) { @@ -1936,6 +2059,26 @@ hfs_global_shared_lock_release(hfsmp); } + HFS_KNOTE(vp, NOTE_DELETE); + if (rvp) { + HFS_KNOTE(rvp, NOTE_DELETE); + vrele(rvp); + }; + + if (error) { + vput(vp); + } else { + VOP_UNLOCK(vp, 0, p); + // XXXdbg - try to prevent the lost ubc_info panic + if ((cp->c_flag & C_HARDLINK) == 0 || cp->c_nlink == 0) { + (void) ubc_uncache(vp); + } + vrele(vp); + } + if (!(options & HFSRM_PARENT_LOCKED)) { + vput(dvp); + } + return (error); } @@ -1950,7 +2093,7 @@ cp->c_desc.cd_nameptr = 0; cp->c_desc.cd_namelen = 0; cp->c_desc.cd_flags &= ~CD_HASBUF; - FREE(name, M_TEMP); + remove_name(name); } bcopy(cdp, &cp->c_desc, sizeof(cp->c_desc)); @@ -1963,19 +2106,11 @@ /* # -#% rename fdvp U U U -#% rename fvp U U U -#% rename tdvp L U U -#% rename tvp X U U -# - vop_rename { - IN WILLRELE struct vnode *fdvp; - IN WILLRELE struct vnode *fvp; - IN struct componentname *fcnp; - IN WILLRELE struct vnode *tdvp; - IN WILLRELE struct vnode *tvp; - IN struct componentname *tcnp; - }; +#% rename fdvp U U U +#% rename fvp U U U +#% rename tdvp L U U +#% rename tvp X U U +# */ /* * Rename a cnode. @@ -2014,53 +2149,114 @@ struct cat_desc from_desc; struct cat_desc to_desc; struct cat_desc out_desc; - struct hfsmount *hfsmp; + struct hfsmount *hfsmp = NULL; struct timeval tv; - int fdvp_locked, fvp_locked, tdvp_locked; + cat_cookie_t cookie = {0}; + int fdvp_locked, fvp_locked, tdvp_locked, tvp_locked; int tvp_deleted; int started_tr = 0, grabbed_lock = 0; int error = 0; - hfsmp = VTOHFS(tdvp); /* Establish our vnode lock state. */ tdvp_locked = 1; + tvp_locked = (tvp != 0); fdvp_locked = 0; fvp_locked = 0; tvp_deleted = 0; /* + * Check for cross-device rename. + */ + if ((fvp->v_mount != tdvp->v_mount) || + (tvp && (fvp->v_mount != tvp->v_mount))) { + error = EXDEV; + goto out; + } + + /* * When fvp matches tvp they must be case variants * or hard links. * - * For the hardlink case there can be an extra ref on fvp. + * In some cases tvp will be locked in other cases + * it be unlocked with no reference. Normalize the + * state here (unlocked with a reference) so that + * we can exit in a known state. */ if (fvp == tvp) { - if (VOP_ISLOCKED(fvp) && - (VTOC(fvp)->c_lock.lk_lockholder == p->p_pid) && - (VTOC(fvp)->c_lock.lk_lockthread == current_thread())) { - fvp_locked = 1; - vrele(fvp); /* drop the extra ref */ + if (VOP_ISLOCKED(tvp) && + (VTOC(tvp)->c_lock.lk_lockholder == p->p_pid) && + (VTOC(tvp)->c_lock.lk_lockthread == current_thread())) { + vput(tvp); } tvp = NULL; + tvp_locked = 0; + /* - * If this a hard link and its not a case - * variant then keep tvp around for removal. + * If this a hard link with different parents + * and its not a case variant then keep tvp + * around for removal. */ if ((VTOC(fvp)->c_flag & C_HARDLINK) && ((fdvp != tdvp) || (hfs_namecmp(fcnp->cn_nameptr, fcnp->cn_namelen, tcnp->cn_nameptr, tcnp->cn_namelen) != 0))) { tvp = fvp; + vref(tvp); } } /* - * Check for cross-device rename. + * The following edge case is caught here: + * (to cannot be a descendent of from) + * + * o fdvp + * / + * / + * o fvp + * \ + * \ + * o tdvp + * / + * / + * o tvp */ - if ((fvp->v_mount != tdvp->v_mount) || - (tvp && (fvp->v_mount != tvp->v_mount))) { - error = EXDEV; + if (tdcp->c_parentcnid == VTOC(fvp)->c_cnid) { + error = EINVAL; + goto out; + } + + /* + * The following two edge cases are caught here: + * (note tvp is not empty) + * + * o tdvp o tdvp + * / / + * / / + * o tvp tvp o fdvp + * \ \ + * \ \ + * o fdvp o fvp + * / + * / + * o fvp + */ + if (tvp && (tvp->v_type == VDIR) && (VTOC(tvp)->c_entries != 0)) { + error = ENOTEMPTY; + goto out; + } + + /* + * The following edge case is caught here: + * (the from child and parent are the same) + * + * o tdvp + * / + * / + * fdvp o fvp + */ + if (fdvp == fvp) { + error = EINVAL; goto out; } @@ -2073,16 +2269,7 @@ goto out; } - /* - * Be sure we are not renaming ".", "..", or an alias of ".". - */ - if ((fvp->v_type == VDIR) && - (((fcnp->cn_namelen == 1) && (fcnp->cn_nameptr[0] == '.')) || - (fdvp == fvp) || - (fcnp->cn_flags&ISDOTDOT))) { - error = EINVAL; - goto out; - } + hfsmp = VTOHFS(tdvp); /* * If the destination parent directory is "sticky", then the @@ -2090,146 +2277,123 @@ * the rename, otherwise the destination may not be changed * (except by root). This implements append-only directories. * - * Note that checks for immutable, write access, and a non-empty - * target are done by the call to VOP_REMOVE. + * Note that checks for immutable and write access are done + * by the call to VOP_REMOVE. */ if (tvp && (tdcp->c_mode & S_ISTXT) && (tcnp->cn_cred->cr_uid != 0) && (tcnp->cn_cred->cr_uid != tdcp->c_uid) && (hfs_owner_rights(hfsmp, VTOC(tvp)->c_uid, tcnp->cn_cred, p, false)) ) { - error = EPERM; - goto out; + error = EPERM; + goto out; } +#if QUOTA + if (tvp) + (void)hfs_getinoquota(VTOC(tvp)); +#endif + /* - * All done with preflighting. - * - * We now break the call into two transactions: - * 1 - Remove the destionation (if any) using VOP_REMOVE, - * which in itself is a complete transaction. - * - * 2 - Rename source to destination. - * - * Since all the preflighting is done, we assume that a - * rename failure is unlikely once part 1 is complete. - * Breaking rename into two transactions buys us a much - * simpler implementation with respect to the locking - * protocol. There are only 3 vnodes to worry about - * locking in the correct order (instead of 4). + * Lock all the vnodes before starting a journal transaction. */ /* - * Part 1 - If the destination exists then it needs to be removed. + * Simple case (same parent) - just lock child (fvp). */ - if (tvp) { - /* - * VOP_REMOVE will vput tdvp so we better bump its - * ref count and relockit, always set tvp to NULL - * afterwards to indicate that we're done with it. - */ - VREF(tdvp); - - if (tvp == fvp) { - if (fvp_locked) { - VREF(fvp); - } else { - error = vget(fvp, LK_EXCLUSIVE | LK_RETRY, p); - if (error) - goto out; - fvp_locked = 1; - } - } else { - cache_purge(tvp); - } - - /* Clear SAVENAME to keep VOP_REMOVE from smashing tcnp. */ - tcnp->cn_flags &= ~SAVENAME; - - if (tvp->v_type == VDIR) - error = VOP_RMDIR(tdvp, tvp, tcnp); - else - error = VOP_REMOVE(tdvp, tvp, tcnp); - - /* Get lock states back in sync. */ - tdvp_locked = 0; - if (tvp == fvp) - fvp_locked = 0; - tvp = NULL; /* all done with tvp */ - tvp_deleted = 1; - - if (error) - goto out; /* couldn't remove destination! */ + if (fdvp == tdvp) { + if (error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) + goto out; + fvp_locked = 1; + goto vnlocked; } - /* - * All done with tvp. - * - * For POSIX compliance, if tvp was removed the only - * error we can return from this point on is EIO. - */ /* - * Part 2 - rename source to destination + * If fdvp is the parent of tdvp then we'll need to + * drop tdvp's lock before acquiring a lock on fdvp. + * + * fdvp + * o + * / \ + * / \ + * tdvp o o fvp + * \ + * \ + * o tvp + * + * + * If the parent directories are unrelated then we'll + * need to aquire their vnode locks in vnode address + * order. Otherwise we can race with another rename + * call that involves the same vnodes except that to + * and from are switched and potentially deadlock. + * [ie rename("a/b", "c/d") vs rename("c/d", "a/b")] + * + * If its not either of the two above cases then we + * can safely lock fdvp and fvp. */ + if ((VTOC(fdvp)->c_cnid == VTOC(tdvp)->c_parentcnid) || + ((VTOC(tdvp)->c_cnid != VTOC(fdvp)->c_parentcnid) && + (fdvp < tdvp))) { - /* - * Lock the vnodes before starting a journal transaction. - */ - if (fdvp != tdvp) { - /* - * fvp is a child and must be locked last. - */ - if (fvp_locked) { - VOP_UNLOCK(fvp, 0, p); - fvp_locked = 0; + /* Drop locks on tvp and tdvp */ + if (tvp_locked) { + VOP_UNLOCK(tvp, 0, p); + tvp_locked = 0; } + VOP_UNLOCK(tdvp, 0, p); + tdvp_locked = 0; + + /* Aquire locks in correct order */ + if ((error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, p))) + goto out; + fdvp_locked = 1; + if ((error = vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY, p))) + goto out; + tdvp_locked = 1; + /* - * If fdvp is the parent of tdvp then it needs to be locked first. + * Now that the parents are locked only one thread + * can continue. So the lock order of the children + * doesn't really matter */ - if ((VTOC(fdvp)->c_cnid == VTOC(tdvp)->c_parentcnid)) { - if (tdvp_locked) { - VOP_UNLOCK(tdvp, 0, p); - tdvp_locked = 0; - } - if ((error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, p))) - goto out; - fdvp_locked = 1; - if ((error = vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY, p))) + if (tvp == fvp) { + if ((error = vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p))) goto out; - tdvp_locked = 1; - - } else /* Lock tdvp then fdvp */ { - if (!tdvp_locked) { - if ((error = vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY, p))) + tvp_locked = 1; + } else { + if (tvp) { + if ((error = vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p))) goto out; - tdvp_locked = 1; + tvp_locked = 1; } - if ((error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, p))) + if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p))) goto out; - fdvp_locked = 1; + fvp_locked = 1; } - } else if (!tdvp_locked) { - /* - * fvp is a child and must be locked last. - */ - if (fvp_locked) { - VOP_UNLOCK(fvp, 0, p); - fvp_locked = 0; - } - if ((error = vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY, p))) - goto out; - tdvp_locked = 1; - } - /* Now its safe to lock fvp */ - if (!fvp_locked) { + } else /* OK to lock fdvp and fvp */ { + if ((error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, p))) + goto out; + fdvp_locked = 1; if (error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) goto out; - fvp_locked = 1; + if (tvp == fvp) + tvp_locked = 1; + else + fvp_locked = 1; } +vnlocked: fdcp = VTOC(fdvp); fcp = VTOC(fvp); + /* + * While fvp is still locked, purge it from the name cache and + * grab it's c_cnid value. Note that the removal of tvp (below) + * can drop fvp's lock when fvp == tvp. + */ + cache_purge(fvp); + /* * When a file moves out of "Cleanup At Startup" * we can drop its NODUMP status. @@ -2238,24 +2402,13 @@ (fvp->v_type == VREG) && (fdvp != tdvp) && (fdcp->c_desc.cd_nameptr != NULL) && - (strcmp(fdcp->c_desc.cd_nameptr, "Cleanup At Startup") == 0)) { + (strcmp(fdcp->c_desc.cd_nameptr, CARBON_TEMP_DIR_NAME) == 0)) { fcp->c_flags &= ~UF_NODUMP; fcp->c_flag |= C_CHANGE; tv = time; (void) VOP_UPDATE(fvp, &tv, &tv, 0); } - hfs_global_shared_lock_acquire(hfsmp); - grabbed_lock = 1; - if (hfsmp->jnl) { - if ((error = journal_start_transaction(hfsmp->jnl)) != 0) { - goto out; - } - started_tr = 1; - } - - cache_purge(fvp); - bzero(&from_desc, sizeof(from_desc)); from_desc.cd_nameptr = fcnp->cn_nameptr; from_desc.cd_namelen = fcnp->cn_namelen; @@ -2270,6 +2423,52 @@ to_desc.cd_flags = fcp->c_desc.cd_flags & ~(CD_HASBUF | CD_DECOMPOSED); to_desc.cd_cnid = fcp->c_cnid; + hfs_global_shared_lock_acquire(hfsmp); + grabbed_lock = 1; + if (hfsmp->jnl) { + if ((error = journal_start_transaction(hfsmp->jnl)) != 0) { + goto out; + } + started_tr = 1; + } + + /* + * Reserve some space in the Catalog file. + */ + if ((error = cat_preflight(hfsmp, CAT_RENAME + CAT_DELETE, &cookie, p))) { + goto out; + } + + /* + * If the destination exists then it needs to be removed. + */ + + if (tvp) { + if (tvp != fvp) + cache_purge(tvp); + /* + * Note that hfs_removedir and hfs_removefile + * will keep tdvp locked with a reference. + * But tvp will lose its lock and reference. + */ + if (tvp->v_type == VDIR) + error = hfs_removedir(tdvp, tvp, tcnp, HFSRM_RENAMEOPTS); + else + error = hfs_removefile(tdvp, tvp, tcnp, HFSRM_RENAMEOPTS); + + if (tvp == fvp) + fvp_locked = 0; + tvp = NULL; + tvp_locked = 0; + tvp_deleted = 1; + if (error) + goto out; + } + + /* + * All done with tvp and fvp + */ + /* Lock catalog b-tree */ error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); if (error) @@ -2279,22 +2478,23 @@ /* Unlock catalog b-tree */ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - if (error) + + if (error) { goto out; + } /* Update cnode's catalog descriptor */ - replace_desc(fcp, &out_desc); + if (fvp_locked) { + replace_desc(fcp, &out_desc); + fcp->c_parentcnid = tdcp->c_cnid; + fcp->c_hint = 0; + } hfs_volupdate(hfsmp, fvp->v_type == VDIR ? VOL_RMDIR : VOL_RMFILE, (fdcp->c_cnid == kHFSRootFolderID)); hfs_volupdate(hfsmp, fvp->v_type == VDIR ? VOL_MKDIR : VOL_MKFILE, (tdcp->c_cnid == kHFSRootFolderID)); - VOP_UNLOCK(fvp, 0, p); - fcp = NULL; - fvp_locked = 0; - /* All done with fvp. */ - /* Update both parent directories. */ tv = time; if (fdvp != tdvp) { @@ -2312,6 +2512,9 @@ (void) VOP_UPDATE(tdvp, &tv, &tv, 0); out: + if (hfsmp) { + cat_postflight(hfsmp, &cookie, p); + } if (started_tr) { journal_end_transaction(hfsmp->jnl); } @@ -2319,6 +2522,14 @@ hfs_global_shared_lock_release(hfsmp); } + /* Note that if hfs_removedir or hfs_removefile was invoked above they will already have + generated a NOTE_WRITE for tdvp and a NOTE_DELETE for tvp. + */ + if (error == 0) { + HFS_KNOTE(fvp, NOTE_RENAME); + HFS_KNOTE(fdvp, NOTE_WRITE); + if (tdvp != fdvp) HFS_KNOTE(tdvp, NOTE_WRITE); + }; if (fvp_locked) { VOP_UNLOCK(fvp, 0, p); } @@ -2328,18 +2539,18 @@ if (tdvp_locked) { VOP_UNLOCK(tdvp, 0, p); } - if (tvp && (tvp != fvp)) { - if (tvp != tdvp) - VOP_UNLOCK(tvp, 0, p); - vrele(tvp); + if (tvp_locked) { + VOP_UNLOCK(tvp, 0, p); } vrele(fvp); vrele(fdvp); + if (tvp) + vrele(tvp); vrele(tdvp); /* After tvp is removed the only acceptable error is EIO */ - if ((error == ENOSPC) && tvp_deleted) + if (error && tvp_deleted) error = EIO; return (error); @@ -2441,7 +2652,6 @@ vp = *vpp; len = strlen(ap->a_target); fp = VTOF(vp); - fp->ff_clumpsize = VTOVCB(vp)->blockSize; #if QUOTA (void)hfs_getinoquota(VTOC(vp)); @@ -2570,6 +2780,10 @@ int eofflag = 0; void *user_start = NULL; int user_len; + + int ncookies=0; + u_long *cookies=NULL; + u_long *cookiep=NULL; /* We assume it's all one big buffer... */ if (uio->uio_iovcnt > 1 || uio->uio_resid < AVERAGE_HFSDIRENTRY_SIZE) @@ -2602,7 +2816,6 @@ } } - /* Create the entries for . and .. */ if (uio->uio_offset < sizeof(rootdots)) { caddr_t dep; @@ -2627,10 +2840,58 @@ goto Exit; } + if (ap->a_ncookies != NULL) { + /* + * These cookies are handles that allow NFS to restart + * scanning through a directory. If a directory is large + * enough, NFS will issue a successive readdir() with a + * uio->uio_offset that is equal to one of these cookies. + * + * The cookies that we generate are synthesized byte-offsets. + * The offset is where the dirent the dirent would be if the + * directory were an array of packed dirent structs. It is + * synthetic because that's not how directories are stored in + * HFS but other code expects that the cookie is a byte offset. + * + * We have to pre-allocate the cookies because cat_getdirentries() + * is the only one that can properly synthesize the offsets (since + * it may have to skip over entries and only it knows the true + * virtual offset of any particular directory entry). So we allocate + * a cookie table here and pass it in to cat_getdirentries(). + * + * Note that the handling of "." and ".." is mostly done here but + * cat_getdirentries() is aware of. + * + * Only the NFS server uses cookies so fortunately this code is + * not executed unless the NFS server is issuing the readdir + * request. + * + * Also note that the NFS server is the one responsible for + * free'ing the cookies even though we allocated them. Ick. + * + * We allocate a reasonable number of entries for the size of + * the buffer that we're going to fill in. cat_getdirentries() + * is smart enough to not overflow if there's more room in the + * buffer but not enough room in the cookie table. + */ + if (uio->uio_segflg != UIO_SYSSPACE) + panic("hfs_readdir: unexpected uio from NFS server"); + + ncookies = uio->uio_iov->iov_len / (AVERAGE_HFSDIRENTRY_SIZE/2); + MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP, M_WAITOK); + + *ap->a_ncookies = ncookies; + *ap->a_cookies = cookies; + } + /* If there are no children then we're done */ if (cp->c_entries == 0) { eofflag = 1; retval = 0; + if (cookies) { + cookies[0] = 0; + cookies[1] = sizeof(struct hfsdotentry); + } goto Exit; } @@ -2638,7 +2899,7 @@ retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); if (retval) goto Exit; - retval = cat_getdirentries(hfsmp, &cp->c_desc, uio, &eofflag); + retval = cat_getdirentries(hfsmp, &cp->c_desc, cp->c_entries, uio, &eofflag, cookies, ncookies); /* Unlock catalog b-tree */ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); @@ -2654,38 +2915,6 @@ } cp->c_flag |= C_ACCESS; - /* Bake any cookies */ - if (!retval && ap->a_ncookies != NULL) { - struct dirent* dpStart; - struct dirent* dpEnd; - struct dirent* dp; - int ncookies; - u_long *cookies; - u_long *cookiep; - - /* - * Only the NFS server uses cookies, and it loads the - * directory block into system space, so we can just look at - * it directly. - */ - if (uio->uio_segflg != UIO_SYSSPACE) - panic("hfs_readdir: unexpected uio from NFS server"); - dpStart = (struct dirent *)(uio->uio_iov->iov_base - (uio->uio_offset - off)); - dpEnd = (struct dirent *) uio->uio_iov->iov_base; - for (dp = dpStart, ncookies = 0; - dp < dpEnd && dp->d_reclen != 0; - dp = (struct dirent *)((caddr_t)dp + dp->d_reclen)) - ncookies++; - MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP, M_WAITOK); - for (dp = dpStart, cookiep = cookies; - dp < dpEnd; - dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { - off += dp->d_reclen; - *cookiep++ = (u_long) off; - } - *ap->a_ncookies = ncookies; - *ap->a_cookies = cookies; - } Exit:; if (hfsmp->jnl && user_start) { @@ -2761,40 +2990,28 @@ } } retval = uiomove((caddr_t)fp->ff_symlinkptr, (int)fp->ff_size, ap->a_uio); - - return (retval); -} - - -/* - * hfs abort op, called after namei() when a CREATE/DELETE isn't actually - * done. If a buffer has been saved in anticipation of a CREATE, delete it. -#% abortop dvp = = = -# - vop_abortop { - IN struct vnode *dvp; - IN struct componentname *cnp; - - */ - -/* ARGSUSED */ - -static int -hfs_abortop(ap) - struct vop_abortop_args /* { - struct vnode *a_dvp; - struct componentname *a_cnp; - } */ *ap; -{ - if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { - FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); - ap->a_cnp->cn_flags &= ~HASBUF; +#if 1 + /* + * Keep track blocks read + */ + if ((VTOHFS(vp)->hfc_stage == HFC_RECORDING) && (retval == 0)) { + + /* + * If this file hasn't been seen since the start of + * the current sampling period then start over. + */ + if (cp->c_atime < VTOHFS(vp)->hfc_timebase) + VTOF(vp)->ff_bytesread = fp->ff_size; + else + VTOF(vp)->ff_bytesread += fp->ff_size; + + // if (VTOF(vp)->ff_bytesread > fp->ff_size) + // cp->c_flag |= C_ACCESS; } - - return (0); +#endif + return (retval); } - /* * Lock an cnode. If its already locked, set the WANT bit and sleep. #% lock vp U L U @@ -2816,9 +3033,6 @@ struct vnode *vp = ap->a_vp; struct cnode *cp = VTOC(vp); - if (cp == NULL) - panic("hfs_lock: cnode in vnode is null\n"); - return (lockmgr(&cp->c_lock, ap->a_flags, &vp->v_interlock, ap->a_p)); } @@ -2842,10 +3056,12 @@ { struct vnode *vp = ap->a_vp; struct cnode *cp = VTOC(vp); - - if (cp == NULL) - panic("hfs_unlock: cnode in vnode is null\n"); - +#if 0 + if (!lockstatus(&cp->c_lock)) { + printf("hfs_unlock: vnode %s wasn't locked!\n", + cp->c_desc.cd_nameptr ? cp->c_desc.cd_nameptr : ""); + } +#endif return (lockmgr(&cp->c_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p)); } @@ -2929,6 +3145,9 @@ case _PC_PATH_MAX: *ap->a_retval = PATH_MAX; /* 1024 */ break; + case _PC_PIPE_BUF: + *ap->a_retval = PIPE_BUF; + break; case _PC_CHOWN_RESTRICTED: *ap->a_retval = 1; break; @@ -2939,7 +3158,10 @@ *ap->a_retval = kHFSPlusMaxFileNameChars; break; case _PC_CASE_SENSITIVE: - *ap->a_retval = 0; + if (VTOHFS(ap->a_vp)->hfs_flags & HFS_CASE_SENSITIVE) + *ap->a_retval = 1; + else + *ap->a_retval = 0; break; case _PC_CASE_PRESERVING: *ap->a_retval = 1; @@ -3015,12 +3237,16 @@ return (EINVAL); } - if (start < 0) - return (EINVAL); if (fl->l_len == 0) end = -1; - else + else if (fl->l_len > 0) end = start + fl->l_len - 1; + else { /* l_len is negative */ + end = start - 1; + start += fl->l_len; + } + if (start < 0) + return (EINVAL); /* * Create the hfslockf structure @@ -3098,14 +3324,14 @@ hfsmp = VTOHFS(vp); /* XXX do we really want to clear the sytem cnode flags here???? */ - if ((vp->v_flag & VSYSTEM) || - (VTOVFS(vp)->mnt_flag & MNT_RDONLY) || + if (((vp->v_flag & VSYSTEM) && (cp->c_cnid < kHFSFirstUserCatalogNodeID))|| + (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) || (cp->c_mode == 0)) { cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE); return (0); } - updateflag = cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE); + updateflag = cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE | C_FORCEUPDATE); /* Nothing to update. */ if (updateflag == 0) { @@ -3117,23 +3343,15 @@ } if (updateflag & C_ACCESS) { /* - * If only the access time is changing then defer - * updating it on-disk util later (in hfs_inactive). - * If it was recently updated then skip the update. + * When the access time is the only thing changing + * then make sure its sufficiently newer before + * committing it to disk. */ - if (updateflag == C_ACCESS) { - cp->c_flag &= ~C_ACCESS; - - /* Its going to disk or its sufficiently newer... */ - if ((cp->c_flag & C_ATIMEMOD) || - (ap->a_access->tv_sec > (cp->c_atime + ATIME_ACCURACY))) { - cp->c_atime = ap->a_access->tv_sec; - cp->c_flag |= C_ATIMEMOD; - } + if ((updateflag == C_ACCESS) && + (ap->a_access->tv_sec < (cp->c_atime + ATIME_ONDISK_ACCURACY))) { return (0); - } else { - cp->c_atime = ap->a_access->tv_sec; } + cp->c_atime = ap->a_access->tv_sec; } if (updateflag & C_UPDATE) { cp->c_mtime = ap->a_modify->tv_sec; @@ -3163,15 +3381,21 @@ * gets written to disk. * * Deleted files can defer meta data updates until inactive. + * + * If we're ever called with the C_FORCEUPDATE flag though + * we have to do the update. */ - if (ISSET(cp->c_flag, C_DELETED) || + if (ISSET(cp->c_flag, C_FORCEUPDATE) == 0 && + (ISSET(cp->c_flag, C_DELETED) || (dataforkp && cp->c_datafork->ff_unallocblocks) || - (rsrcforkp && cp->c_rsrcfork->ff_unallocblocks)) { + (rsrcforkp && cp->c_rsrcfork->ff_unallocblocks))) { if (updateflag & (C_CHANGE | C_UPDATE)) hfs_volupdate(hfsmp, VOL_UPDATE, 0); cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_UPDATE); cp->c_flag |= C_MODIFIED; + HFS_KNOTE(vp, NOTE_ATTRIB); + return (0); } @@ -3195,6 +3419,19 @@ bcopy(dataforkp, &datafork, sizeof(datafork)); datafork.cf_size = CIRCLEQ_FIRST(&cp->c_datafork->ff_invalidranges)->rl_start; dataforkp = &datafork; + } else if (dataforkp && (cp->c_datafork->ff_unallocblocks != 0)) { + // always make sure the block count and the size + // of the file match the number of blocks actually + // allocated to the file on disk + bcopy(dataforkp, &datafork, sizeof(datafork)); + // make sure that we don't assign a negative block count + if (cp->c_datafork->ff_blocks < cp->c_datafork->ff_unallocblocks) { + panic("hfs: ff_blocks %d is less than unalloc blocks %d\n", + cp->c_datafork->ff_blocks, cp->c_datafork->ff_unallocblocks); + } + datafork.cf_blocks = (cp->c_datafork->ff_blocks - cp->c_datafork->ff_unallocblocks); + datafork.cf_size = datafork.cf_blocks * HFSTOVCB(hfsmp)->blockSize; + dataforkp = &datafork; } /* @@ -3217,18 +3454,20 @@ /* Unlock the Catalog b-tree file. */ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - if (updateflag & (C_CHANGE | C_UPDATE)) + if (updateflag & (C_CHANGE | C_UPDATE | C_FORCEUPDATE)) hfs_volupdate(hfsmp, VOL_UPDATE, 0); + /* After the updates are finished, clear the flags */ + cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE | C_FORCEUPDATE); + // XXXdbg if (hfsmp->jnl) { journal_end_transaction(hfsmp->jnl); } hfs_global_shared_lock_release(hfsmp); - /* After the updates are finished, clear the flags */ - cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE | C_ATIMEMOD); - + HFS_KNOTE(vp, NOTE_ATTRIB); + return (error); } @@ -3253,6 +3492,7 @@ struct proc *p; struct cat_desc in_desc, out_desc; struct cat_attr attr; + cat_cookie_t cookie = {0}; int error, started_tr = 0, grabbed_lock = 0; enum vtype vnodetype; @@ -3339,6 +3579,17 @@ started_tr = 1; } + /* + * Reserve some space in the Catalog file. + * + * (we also add CAT_DELETE since our getnewvnode + * request can cause an hfs_inactive call to + * delete an unlinked file) + */ + if ((error = cat_preflight(hfsmp, CAT_CREATE | CAT_DELETE, &cookie, p))) { + goto exit; + } + /* Lock catalog b-tree */ error = hfs_metafilelocking(VTOHFS(dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p); if (error) @@ -3358,6 +3609,11 @@ dcp->c_flag |= C_CHANGE | C_UPDATE; tv = time; (void) VOP_UPDATE(dvp, &tv, &tv, 0); + if (vnodetype == VDIR) { + HFS_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); + } else { + HFS_KNOTE(dvp, NOTE_WRITE); + }; hfs_volupdate(hfsmp, vnodetype == VDIR ? VOL_MKDIR : VOL_MKFILE, (dcp->c_cnid == kHFSRootFolderID)); @@ -3388,6 +3644,8 @@ if (error) goto exit; + // XXXdbg + cache_enter(dvp, tvp, cnp); #if QUOTA cp = VTOC(tvp); @@ -3398,16 +3656,15 @@ */ if ((error = hfs_getinoquota(cp)) || (error = hfs_chkiq(cp, 1, cnp->cn_cred, FORCE))) { - if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { - FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); - cnp->cn_flags &= ~HASBUF; - } if (tvp->v_type == VDIR) VOP_RMDIR(dvp,tvp, cnp); else VOP_REMOVE(dvp,tvp, cnp); - return (error); + // because VOP_RMDIR and VOP_REMOVE already + // have done the vput() + dvp = NULL; + goto exit; } #endif /* QUOTA */ @@ -3432,17 +3689,22 @@ exit: cat_releasedesc(&out_desc); - if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) - FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); + cat_postflight(hfsmp, &cookie, p); + if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { + char *tmp = cnp->cn_pnbuf; + cnp->cn_pnbuf = NULL; + cnp->cn_flags &= ~HASBUF; + FREE_ZONE(tmp, cnp->cn_pnlen, M_NAMEI); + } /* * Check if a file is located in the "Cleanup At Startup" * directory. If it is then tag it as NODUMP so that we * can be lazy about zero filling data holes. */ - if ((error == 0) && (vnodetype == VREG) && + if ((error == 0) && dvp && (vnodetype == VREG) && (dcp->c_desc.cd_nameptr != NULL) && - (strcmp(dcp->c_desc.cd_nameptr, "Cleanup At Startup") == 0)) { + (strcmp(dcp->c_desc.cd_nameptr, CARBON_TEMP_DIR_NAME) == 0)) { struct vnode *ddvp; cnid_t parid; @@ -3463,11 +3725,9 @@ vput(ddvp); } } - if (dvp) vput(dvp); - // XXXdbg if (started_tr) { journal_end_transaction(hfsmp->jnl); started_tr = 0; @@ -3527,6 +3787,158 @@ } +static void +filt_hfsdetach(struct knote *kn) +{ + struct vnode *vp; + int result; + struct proc *p = current_proc(); + + vp = (struct vnode *)kn->kn_hook; + if (1) { /* ! KNDETACH_VNLOCKED */ + result = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (result) return; + }; + + result = KNOTE_DETACH(&VTOC(vp)->c_knotes, kn); + + if (1) { /* ! KNDETACH_VNLOCKED */ + VOP_UNLOCK(vp, 0, p); + }; +} + +/*ARGSUSED*/ +static int +filt_hfsread(struct knote *kn, long hint) +{ + struct vnode *vp = (struct vnode *)kn->kn_fp->f_data; + + if (hint == NOTE_REVOKE) { + /* + * filesystem is gone, so set the EOF flag and schedule + * the knote for deletion. + */ + kn->kn_flags |= (EV_EOF | EV_ONESHOT); + return (1); + } + + kn->kn_data = VTOF(vp)->ff_size - kn->kn_fp->f_offset; + return (kn->kn_data != 0); +} + +/*ARGSUSED*/ +static int +filt_hfswrite(struct knote *kn, long hint) +{ + if (hint == NOTE_REVOKE) { + /* + * filesystem is gone, so set the EOF flag and schedule + * the knote for deletion. + */ + kn->kn_flags |= (EV_EOF | EV_ONESHOT); + } + + kn->kn_data = 0; + return (1); +} + +static int +filt_hfsvnode(struct knote *kn, long hint) +{ + + if (kn->kn_sfflags & hint) + kn->kn_fflags |= hint; + if (hint == NOTE_REVOKE) { + kn->kn_flags |= EV_EOF; + return (1); + } + return (kn->kn_fflags != 0); +} + +static struct filterops hfsread_filtops = + { 1, NULL, filt_hfsdetach, filt_hfsread }; +static struct filterops hfswrite_filtops = + { 1, NULL, filt_hfsdetach, filt_hfswrite }; +static struct filterops hfsvnode_filtops = + { 1, NULL, filt_hfsdetach, filt_hfsvnode }; + +/* + # + #% kqfilt_add vp L L L + # + vop_kqfilt_add + IN struct vnode *vp; + IN struct knote *kn; + IN struct proc *p; + */ +static int +hfs_kqfilt_add(ap) + struct vop_kqfilt_add_args /* { + struct vnode *a_vp; + struct knote *a_kn; + struct proc *p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct knote *kn = ap->a_kn; + + switch (kn->kn_filter) { + case EVFILT_READ: + if (vp->v_type == VREG) { + kn->kn_fop = &hfsread_filtops; + } else { + return EINVAL; + }; + break; + case EVFILT_WRITE: + if (vp->v_type == VREG) { + kn->kn_fop = &hfswrite_filtops; + } else { + return EINVAL; + }; + break; + case EVFILT_VNODE: + kn->kn_fop = &hfsvnode_filtops; + break; + default: + return (1); + } + + kn->kn_hook = (caddr_t)vp; + + /* simple_lock(&vp->v_pollinfo.vpi_lock); */ + KNOTE_ATTACH(&VTOC(vp)->c_knotes, kn); + /* simple_unlock(&vp->v_pollinfo.vpi_lock); */ + + return (0); +} + +/* + # + #% kqfilt_remove vp L L L + # + vop_kqfilt_remove + IN struct vnode *vp; + IN uintptr_t ident; + IN struct proc *p; + */ +static int +hfs_kqfilt_remove(ap) + struct vop_kqfilt_remove_args /* { + struct vnode *a_vp; + uintptr_t ident; + struct proc *p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + uintptr_t ident = ap->a_ident; + int result; + + result = ENOTSUP; /* XXX */ + + return (result); +} + /* * Wrapper for special device reads */ @@ -3656,6 +4068,43 @@ simple_unlock(&vp->v_interlock); return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap)); } + +/* + * kqfilt_add wrapper for fifos. + * + * Fall through to hfs kqfilt_add routines if needed + */ +int +hfsfifo_kqfilt_add(ap) + struct vop_kqfilt_add_args *ap; +{ + extern int (**fifo_vnodeop_p)(void *); + int error; + + error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_kqfilt_add), ap); + if (error) + error = hfs_kqfilt_add(ap); + return (error); +} + +/* + * kqfilt_remove wrapper for fifos. + * + * Fall through to hfs kqfilt_remove routines if needed + */ +int +hfsfifo_kqfilt_remove(ap) + struct vop_kqfilt_remove_args *ap; +{ + extern int (**fifo_vnodeop_p)(void *); + int error; + + error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_kqfilt_remove), ap); + if (error) + error = hfs_kqfilt_remove(ap); + return (error); +} + #endif /* FIFO */ @@ -3706,6 +4155,7 @@ { &vop_write_desc, (VOPFUNC)hfs_write }, /* write */ { &vop_ioctl_desc, (VOPFUNC)hfs_ioctl }, /* ioctl */ { &vop_select_desc, (VOPFUNC)hfs_select }, /* select */ + { &vop_revoke_desc, (VOPFUNC)nop_revoke }, /* revoke */ { &vop_exchange_desc, (VOPFUNC)hfs_exchange }, /* exchange */ { &vop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */ { &vop_fsync_desc, (VOPFUNC)hfs_fsync }, /* fsync */ @@ -3722,7 +4172,7 @@ { &vop_readdir_desc, (VOPFUNC)hfs_readdir }, /* readdir */ { &vop_readdirattr_desc, (VOPFUNC)hfs_readdirattr }, /* readdirattr */ { &vop_readlink_desc, (VOPFUNC)hfs_readlink }, /* readlink */ - { &vop_abortop_desc, (VOPFUNC)hfs_abortop }, /* abortop */ + { &vop_abortop_desc, (VOPFUNC)nop_abortop }, /* abortop */ { &vop_inactive_desc, (VOPFUNC)hfs_inactive }, /* inactive */ { &vop_reclaim_desc, (VOPFUNC)hfs_reclaim }, /* reclaim */ { &vop_lock_desc, (VOPFUNC)hfs_lock }, /* lock */ @@ -3745,6 +4195,8 @@ { &vop_blktooff_desc, (VOPFUNC)hfs_blktooff }, /* blktooff */ { &vop_offtoblk_desc, (VOPFUNC)hfs_offtoblk }, /* offtoblk */ { &vop_cmap_desc, (VOPFUNC)hfs_cmap }, /* cmap */ + { &vop_kqfilt_add_desc, (VOPFUNC)hfs_kqfilt_add }, /* kqfilt_add */ + { &vop_kqfilt_remove_desc, (VOPFUNC)hfs_kqfilt_remove }, /* kqfilt_remove */ { NULL, (VOPFUNC)NULL } }; @@ -3776,6 +4228,7 @@ { &vop_rename_desc, (VOPFUNC)spec_rename }, /* rename */ { &vop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */ { &vop_rmdir_desc, (VOPFUNC)spec_rmdir }, /* rmdir */ + { &vop_getattrlist_desc, (VOPFUNC)hfs_getattrlist }, { &vop_symlink_desc, (VOPFUNC)spec_symlink }, /* symlink */ { &vop_readdir_desc, (VOPFUNC)spec_readdir }, /* readdir */ { &vop_readlink_desc, (VOPFUNC)spec_readlink }, /* readlink */ @@ -3834,6 +4287,7 @@ { &vop_rename_desc, (VOPFUNC)fifo_rename }, /* rename */ { &vop_mkdir_desc, (VOPFUNC)fifo_mkdir }, /* mkdir */ { &vop_rmdir_desc, (VOPFUNC)fifo_rmdir }, /* rmdir */ + { &vop_getattrlist_desc, (VOPFUNC)hfs_getattrlist }, { &vop_symlink_desc, (VOPFUNC)fifo_symlink }, /* symlink */ { &vop_readdir_desc, (VOPFUNC)fifo_readdir }, /* readdir */ { &vop_readlink_desc, (VOPFUNC)fifo_readlink }, /* readlink */ @@ -3861,6 +4315,8 @@ { &vop_blktooff_desc, (VOPFUNC)hfs_blktooff }, /* blktooff */ { &vop_offtoblk_desc, (VOPFUNC)hfs_offtoblk }, /* offtoblk */ { &vop_cmap_desc, (VOPFUNC)hfs_cmap }, /* cmap */ + { &vop_kqfilt_add_desc, (VOPFUNC)hfsfifo_kqfilt_add }, /* kqfilt_add */ + { &vop_kqfilt_remove_desc, (VOPFUNC)hfsfifo_kqfilt_remove }, /* kqfilt_remove */ { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } }; struct vnodeopv_desc hfs_fifoop_opv_desc = diff -urN xnu-344.49/bsd/hfs/hfscommon/BTree/BTree.c xnu-517/bsd/hfs/hfscommon/BTree/BTree.c --- xnu-344.49/bsd/hfs/hfscommon/BTree/BTree.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfscommon/BTree/BTree.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -155,6 +155,12 @@ */ #define kNumLeafRecSlack 10 +/* BTree accessor routines */ +extern OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block); +extern OSStatus SetBTreeBlockSize(FileReference vp, ByteCount blockSize, ItemCount minBlockCount); +extern OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF); +extern OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options); + //////////////////////////////////// Globals //////////////////////////////////// @@ -171,9 +177,6 @@ Input: filePtr - pointer to file to open as a B-tree keyCompareProc - pointer to client's KeyCompare function - getBlockProc - pointer to client's GetBlock function - releaseBlockProc - pointer to client's ReleaseBlock function - setEndOfForkProc - pointer to client's SetEOF function Result: noErr - success paramErr - required ptr was nil @@ -182,12 +185,7 @@ != noErr - failure -------------------------------------------------------------------------------*/ -OSStatus BTOpenPath (FCB *filePtr, - KeyCompareProcPtr keyCompareProc, - GetBlockProcPtr getBlockProc, - ReleaseBlockProcPtr releaseBlockProc, - SetEndOfForkProcPtr setEndOfForkProc, - SetBlockSizeProcPtr setBlockSizeProc ) +OSStatus BTOpenPath(FCB *filePtr, KeyCompareProcPtr keyCompareProc) { OSStatus err; BTreeControlBlockPtr btreePtr; @@ -196,21 +194,22 @@ ////////////////////// Preliminary Error Checking /////////////////////////// - if ( filePtr == nil || - getBlockProc == nil || - releaseBlockProc == nil || - setEndOfForkProc == nil || - setBlockSizeProc == nil ) + if ( filePtr == nil ) { return paramErr; } - if ( filePtr->fcbBTCBPtr != nil ) // already has a BTreeCB + /* + * Subsequent opens allow key compare proc to be changed. + */ + if ( filePtr->fcbBTCBPtr != nil && keyCompareProc != nil) { + btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; + btreePtr->keyCompareProc = keyCompareProc; return noErr; + } - // is file large enough to contain header node? if ( filePtr->fcbEOF < kMinNodeSize ) - return fsBTInvalidFileErr; //€€ or E_BadHeader? + return fsBTInvalidFileErr; //////////////////////// Allocate Control Block ///////////////////////////// @@ -222,9 +221,9 @@ return memFullErr; } - btreePtr->getBlockProc = getBlockProc; - btreePtr->releaseBlockProc = releaseBlockProc; - btreePtr->setEndOfForkProc = setEndOfForkProc; + btreePtr->getBlockProc = GetBTreeBlock; + btreePtr->releaseBlockProc = ReleaseBTreeBlock; + btreePtr->setEndOfForkProc = ExtendBTreeFile; btreePtr->keyCompareProc = keyCompareProc; /////////////////////////// Read Header Node //////////////////////////////// @@ -236,15 +235,20 @@ /* The minimum node size is the physical block size */ nodeRec.blockSize = VTOHFS(btreePtr->fileRefNum)->hfs_phys_block_size; + /* Start with the allocation block size for regular files. */ + if (FTOC(filePtr)->c_fileid >= kHFSFirstUserCatalogNodeID) + { + nodeRec.blockSize = FCBTOVCB(filePtr)->blockSize; + } REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false); // it is now safe to call M_ExitOnError (err) - err = setBlockSizeProc (btreePtr->fileRefNum, nodeRec.blockSize, 1); + err = SetBTreeBlockSize (btreePtr->fileRefNum, nodeRec.blockSize, 1); M_ExitOnError (err); - err = getBlockProc (btreePtr->fileRefNum, + err = GetBTreeBlock(btreePtr->fileRefNum, kHeaderNodeNum, kGetBlock, &nodeRec ); @@ -278,9 +282,12 @@ btreePtr->maxKeyLength = header->maxKeyLength; btreePtr->totalNodes = header->totalNodes; btreePtr->freeNodes = header->freeNodes; - // ignore header->clumpSize; //€€ rename this field? + if (FTOC(filePtr)->c_fileid >= kHFSFirstUserCatalogNodeID) + filePtr->ff_clumpsize = header->clumpSize; btreePtr->btreeType = header->btreeType; + btreePtr->keyCompareType = header->keyCompareType; + btreePtr->attributes = header->attributes; if ( btreePtr->maxKeyLength > 40 ) @@ -304,7 +311,7 @@ * we cannot mount using the current physical block size. */ if (btreePtr->leafRecords > 0 || - VTOHFS(btreePtr->fileRefNum)->hfs_media_writeable) + VTOHFS(btreePtr->fileRefNum)->hfs_flags & HFS_WRITEABLE_MEDIA) { err = fsBTBadNodeSize; goto ErrorExit; @@ -321,14 +328,14 @@ } else { - err = setBlockSizeProc (btreePtr->fileRefNum, btreePtr->nodeSize, 32); //€€ we should try and get this down to 8 + err = SetBTreeBlockSize (btreePtr->fileRefNum, btreePtr->nodeSize, 32); M_ExitOnError (err); /* * Need to use kTrashBlock option to force the * buffer cache to read the entire node */ - err = releaseBlockProc(btreePtr->fileRefNum, &nodeRec, kTrashBlock); + err = ReleaseBTreeBlock(btreePtr->fileRefNum, &nodeRec, kTrashBlock); ++btreePtr->numReleaseNodes; M_ExitOnError (err); @@ -1255,7 +1262,7 @@ case fsBTEmptyErr: // if tree empty add 1st leaf node - if (btreePtr->freeNodes == 0) + if (BTAvailableNodes(btreePtr) == 0) { err = ExtendBTree (btreePtr, btreePtr->totalNodes + 1); M_ExitOnError (err); @@ -1317,10 +1324,10 @@ /////////////////////// Extend File If Necessary //////////////////////////// - nodesNeeded = btreePtr->treeDepth + 1 - btreePtr->freeNodes; //€€ math limit + nodesNeeded = (SInt32)btreePtr->treeDepth + 1 - BTAvailableNodes(btreePtr); if (nodesNeeded > 0) { - nodesNeeded += btreePtr->totalNodes; + nodesNeeded += (SInt32)btreePtr->totalNodes; if (nodesNeeded > CalcMapBits (btreePtr)) // we'll need to add a map node too! ++nodesNeeded; @@ -1469,10 +1476,10 @@ //////////////////////////// Make Some Room ///////////////////////////////// - nodesNeeded = btreePtr->treeDepth + 1 - btreePtr->freeNodes; //€€ math limit + nodesNeeded = (SInt32)btreePtr->treeDepth + 1 - BTAvailableNodes(btreePtr); if (nodesNeeded > 0) { - nodesNeeded += btreePtr->totalNodes; + nodesNeeded += (SInt32)btreePtr->totalNodes; if (nodesNeeded > CalcMapBits (btreePtr)) // we'll need to add a map node too! ++nodesNeeded; @@ -1480,7 +1487,6 @@ M_ExitOnError (err); } - // XXXdbg ModifyBlockStart(btreePtr->fileRefNum, &nodeRec); @@ -1643,6 +1649,7 @@ BTreeControlBlockPtr btreePtr; TreePathTable treePathTable; BlockDescriptor nodeRec; + SInt32 nodesNeeded; UInt32 nodeNum; UInt16 index; @@ -1673,6 +1680,19 @@ M_ExitOnError (err); // record must exit for Delete + /////////////////////// Extend File If Necessary //////////////////////////// + + nodesNeeded = (SInt32)btreePtr->treeDepth + 1 - BTAvailableNodes(btreePtr); + if ((btreePtr->attributes & kBTVariableIndexKeysMask) && (nodesNeeded > 0)) + { + nodesNeeded += (SInt32)btreePtr->totalNodes; + if (nodesNeeded > CalcMapBits (btreePtr)) + ++nodesNeeded; + + err = ExtendBTree (btreePtr, nodesNeeded); + M_ExitOnError (err); + } + ///////////////////////////// Delete Record ///////////////////////////////// err = DeleteTree (btreePtr, treePathTable, &nodeRec, index, 1); @@ -1728,8 +1748,7 @@ info->numNodes = btreePtr->totalNodes; info->numFreeNodes = btreePtr->freeNodes; info->lastfsync = btreePtr->lastfsync; - info->reserved = 0; - + info->keyCompareType = btreePtr->keyCompareType; return noErr; } @@ -1940,25 +1959,10 @@ } -/*------------------------------------------------------------------------------- -Routine: BTCheckFreeSpace - -Function: Makes sure there is enough free space so that a tree operation - will succeed. - -Input: fcb - pointer file control block - -Output: none - -Result: noErr - success - --------------------------------------------------------------------------------*/ - __private_extern__ -OSStatus BTCheckFreeSpace (FCB *filePtr) +OSStatus BTHasContiguousNodes (FCB *filePtr) { BTreeControlBlockPtr btreePtr; - int nodesNeeded, err = noErr; M_ReturnErrorIf (filePtr == nil, paramErr); @@ -1969,33 +1973,85 @@ M_ReturnErrorIf (btreePtr == nil, fsBTInvalidFileErr); - // XXXdbg this is highly conservative but so much better than - // winding up with turds on your disk. - // - nodesNeeded = (btreePtr->treeDepth + 1) * 10; + return NodesAreContiguous(FCBTOVCB(filePtr), filePtr, btreePtr->nodeSize); +} + + +/*------------------------------------------------------------------------------- +Routine: BTGetUserData + +Function: Read the user data area of the b-tree header node. + +-------------------------------------------------------------------------------*/ +__private_extern__ +OSStatus +BTGetUserData(FCB *filePtr, void * dataPtr, int dataSize) +{ + BTreeControlBlockPtr btreePtr; + BlockDescriptor node; + char * offset; + OSStatus err; + + if (dataSize > kBTreeHeaderUserBytes) + return (EINVAL); + node.buffer = nil; + node.blockHeader = nil; + + btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; + if (btreePtr == nil) + return (fsBTInvalidFileErr); + + REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false); + + err = GetNode(btreePtr, kHeaderNodeNum, &node); + if (err) + return (err); - if (btreePtr->freeNodes < nodesNeeded) { - err = ExtendBTree(btreePtr, nodesNeeded + btreePtr->totalNodes - btreePtr->freeNodes); - } + offset = (char *)node.buffer + sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec); + bcopy(offset, dataPtr, dataSize); - return err; + (void) ReleaseNode(btreePtr, &node); + + return (0); } +/*------------------------------------------------------------------------------- +Routine: BTSetUserData + +Function: Write the user data area of the b-tree header node. +-------------------------------------------------------------------------------*/ __private_extern__ -OSStatus BTHasContiguousNodes (FCB *filePtr) +OSStatus +BTSetUserData(FCB *filePtr, void * dataPtr, int dataSize) { - BTreeControlBlockPtr btreePtr; - int nodesNeeded, err = noErr; - + BTreeControlBlockPtr btreePtr; + BlockDescriptor node; + char * offset; + OSStatus err; - M_ReturnErrorIf (filePtr == nil, paramErr); + if (dataSize > kBTreeHeaderUserBytes) + return (EINVAL); + node.buffer = nil; + node.blockHeader = nil; btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; + if (btreePtr == nil) + return (fsBTInvalidFileErr); + + REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false); + + err = GetNode(btreePtr, kHeaderNodeNum, &node); + if (err) + return (err); - REQUIRE_FILE_LOCK(btreePtr->fileRefNum, true); + ModifyBlockStart(btreePtr->fileRefNum, &node); - M_ReturnErrorIf (btreePtr == nil, fsBTInvalidFileErr); + offset = (char *)node.buffer + sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec); + bcopy(dataPtr, offset, dataSize); - return NodesAreContiguous(FCBTOVCB(filePtr), filePtr, btreePtr->nodeSize); + err = UpdateNode (btreePtr, &node, 0, 0); + + return (err); } + diff -urN xnu-344.49/bsd/hfs/hfscommon/BTree/BTreeAllocate.c xnu-517/bsd/hfs/hfscommon/BTree/BTreeAllocate.c --- xnu-344.49/bsd/hfs/hfscommon/BTree/BTreeAllocate.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfscommon/BTree/BTreeAllocate.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -193,6 +193,10 @@ --btreePtr->freeNodes; btreePtr->flags |= kBTHeaderDirty; + + /* Account for allocations from node reserve */ + BTUpdateReserve(btreePtr, 1); + *nodeNum = nodeNumber; return noErr; diff -urN xnu-344.49/bsd/hfs/hfscommon/BTree/BTreeMiscOps.c xnu-517/bsd/hfs/hfscommon/BTree/BTreeMiscOps.c --- xnu-344.49/bsd/hfs/hfscommon/BTree/BTreeMiscOps.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfscommon/BTree/BTreeMiscOps.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -176,7 +176,7 @@ forkSize = (UInt64)totalNodes * (UInt64)header->nodeSize; - if ( forkSize != filePtr->fcbEOF ) + if ( forkSize > filePtr->fcbEOF ) return fsBTInvalidHeaderErr; if ( header->freeNodes >= totalNodes ) diff -urN xnu-344.49/bsd/hfs/hfscommon/BTree/BTreeNodeReserve.c xnu-517/bsd/hfs/hfscommon/BTree/BTreeNodeReserve.c --- xnu-344.49/bsd/hfs/hfscommon/BTree/BTreeNodeReserve.c Thu Jan 1 01:00:00 1970 +++ xnu-517/bsd/hfs/hfscommon/BTree/BTreeNodeReserve.c Sat Oct 25 00:25:25 2003 @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include "../headers/BTreesPrivate.h" +#include "sys/malloc.h" + + +/* + * B-tree Node Reserve + * + * BTReserveSpace + * BTReleaseReserve + * BTUpdateReserve + * BTAvailableNodes + * + * Each kernel thread can have it's own reserve of b-tree + * nodes. This reserve info is kept in a hash table. + * + * Don't forget to call BTReleaseReserve when you're finished + * or you will leave stale node reserves in the hash. + */ + + +/* + * BE CAREFUL WHEN INCREASING THE SIZE OF THIS STRUCT! + * + * It must remain equal in size to the opaque cat_cookie_t + * struct (in hfs_catalog.h). + */ +struct nreserve { + LIST_ENTRY(nreserve) nr_hash; /* hash chain */ + int nr_nodecnt; /* count of nodes held in reserve */ + int nr_newnodes; /* nodes that were allocated */ + struct vnode *nr_btvp; /* b-tree file vnode */ + void *nr_tag; /* unique tag (per thread) */ +}; + +#define NR_GET_TAG() (current_act()) + +#define NR_CACHE 17 + +#define NR_HASH(btvp, tag) \ + (&nr_hashtbl[((((int)(btvp)) >> 8) ^ ((int)(tag) >> 4)) & nr_hashmask]) + +LIST_HEAD(nodereserve, nreserve) *nr_hashtbl; + +u_long nr_hashmask; + + +/* Internal Node Reserve Hash Routines (private) */ +static void nr_insert (struct vnode *, struct nreserve *nrp, int); +static void nr_delete (struct vnode *, struct nreserve *nrp, int *); +static int nr_lookup (struct vnode *); +static void nr_update (struct vnode *, int); + + +/* + * BTReserveSetup - initialize the node reserve hash table + */ +__private_extern__ +void +BTReserveSetup() +{ + if (sizeof(struct nreserve) != sizeof(cat_cookie_t)) + panic("BTReserveSetup: nreserve size != opaque struct size"); + + nr_hashtbl = hashinit(NR_CACHE, M_HFSMNT, &nr_hashmask); +} + + +/* + * BTAvailNodes - obtain the actual available nodes (for current thread) + * + */ +__private_extern__ +SInt32 +BTAvailableNodes(BTreeControlBlock *btree) +{ + SInt32 availNodes; + + availNodes = (SInt32)btree->freeNodes - (SInt32)btree->reservedNodes; + + return (availNodes + nr_lookup(btree->fileRefNum)); +} + + +/* + * BTReserveSpace - obtain a node reserve (for current thread) + * + * Used by the Catalog Layer (hfs_catalog.c) to reserve space. + */ +__private_extern__ +int +BTReserveSpace(FCB *file, int operations, void* data) +{ + BTreeControlBlock *btree; + int rsrvNodes, availNodes, totalNodes; + int height; + int inserts, deletes; + int err = 0; + + btree = (BTreeControlBlockPtr)file->fcbBTCBPtr; + + REQUIRE_FILE_LOCK(btree->fileRefNum, true); + + /* + * The node reserve is based on the number of b-tree + * operations (insert/deletes) and the height of the + * tree. + */ + height = btree->treeDepth; + inserts = operations & 0xffff; + deletes = operations >> 16; + + rsrvNodes = 1; /* allow for at least one root split */ + if (deletes) + rsrvNodes += (deletes * (height - 1)) - 1; + if (inserts) + rsrvNodes += (inserts * height) + 1; + + availNodes = btree->freeNodes - btree->reservedNodes; + + if (rsrvNodes > availNodes) { + totalNodes = rsrvNodes + btree->totalNodes - availNodes; + + /* See if we also need a map node */ + if (totalNodes > CalcMapBits(btree)) + ++totalNodes; + if ((err = ExtendBTree(btree, totalNodes))) + return (err); + } + + btree->reservedNodes += rsrvNodes; + nr_insert(btree->fileRefNum, (struct nreserve *)data, rsrvNodes); + return (0); +} + + +/* + * BTReleaseReserve - release the node reserve held by current thread + * + * Used by the Catalog Layer (hfs_catalog.c) to relinquish reserved space. + */ +__private_extern__ +int +BTReleaseReserve(FCB *file, void* data) +{ + BTreeControlBlock *btree; + int nodecnt; + + btree = (BTreeControlBlockPtr)file->fcbBTCBPtr; + + REQUIRE_FILE_LOCK(btree->fileRefNum, true); + + nr_delete(btree->fileRefNum, (struct nreserve *)data, &nodecnt); + + if (nodecnt) + btree->reservedNodes -= nodecnt; + + return (0); +} + +/* + * BTUpdateReserve - update a node reserve for allocations that occured. + */ +__private_extern__ +void +BTUpdateReserve(BTreeControlBlockPtr btreePtr, int nodes) +{ + nr_update(btreePtr->fileRefNum, nodes); +} + + +/*----------------------------------------------------------------------------*/ +/* Node Reserve Hash Functions (private) */ + + +int nrinserts = 0; +int nrdeletes = 0; + +/* + * Insert a new node reserve. + */ +static void +nr_insert(struct vnode * btvp, struct nreserve *nrp, int nodecnt) +{ + struct nodereserve *nrhead; + struct nreserve *tmp_nrp; + void * tag = NR_GET_TAG(); + + /* + * Check the cache - there may already be a reserve + */ + nrhead = NR_HASH(btvp, tag); + for (tmp_nrp = nrhead->lh_first; tmp_nrp; + tmp_nrp = tmp_nrp->nr_hash.le_next) { + if ((tmp_nrp->nr_tag == tag) && (tmp_nrp->nr_btvp == btvp)) { + nrp->nr_tag = 0; + return; + } + } + + nrp->nr_nodecnt = nodecnt; + nrp->nr_newnodes = 0; + nrp->nr_btvp = btvp; + nrp->nr_tag = tag; + LIST_INSERT_HEAD(nrhead, nrp, nr_hash); + ++nrinserts; +} + +/* + * Delete a node reserve. + */ +static void +nr_delete(struct vnode * btvp, struct nreserve *nrp, int *nodecnt) +{ + void * tag = NR_GET_TAG(); + + if (nrp->nr_tag) { + if ((nrp->nr_tag != tag) || (nrp->nr_btvp != btvp)) + panic("nr_delete: invalid NR (%08x)", nrp); + LIST_REMOVE(nrp, nr_hash); + *nodecnt = nrp->nr_nodecnt; + bzero(nrp, sizeof(struct nreserve)); + ++nrdeletes; + } else { + *nodecnt = 0; + } +} + +/* + * Lookup a node reserve. + */ +static int +nr_lookup(struct vnode * btvp) +{ + struct nodereserve *nrhead; + struct nreserve *nrp; + void* tag = NR_GET_TAG(); + + nrhead = NR_HASH(btvp, tag); + for (nrp = nrhead->lh_first; nrp; nrp = nrp->nr_hash.le_next) { + if ((nrp->nr_tag == tag) && (nrp->nr_btvp == btvp)) + return (nrp->nr_nodecnt - nrp->nr_newnodes); + } + return (0); +} + +/* + * Update a node reserve for any allocations that occured. + */ +static void +nr_update(struct vnode * btvp, int nodecnt) +{ + struct nodereserve *nrhead; + struct nreserve *nrp; + void* tag = NR_GET_TAG(); + + nrhead = NR_HASH(btvp, tag); + for (nrp = nrhead->lh_first; nrp; nrp = nrp->nr_hash.le_next) { + if ((nrp->nr_tag == tag) && (nrp->nr_btvp == btvp)) { + nrp->nr_newnodes += nodecnt; + break; + } + } +} diff -urN xnu-344.49/bsd/hfs/hfscommon/BTree/BTreeScanner.c xnu-517/bsd/hfs/hfscommon/BTree/BTreeScanner.c --- xnu-344.49/bsd/hfs/hfscommon/BTree/BTreeScanner.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfscommon/BTree/BTreeScanner.c Sat Oct 25 00:25:25 2003 @@ -25,6 +25,7 @@ * @(#)BTreeScanner.c */ #include +#include "../../hfs_endian.h" #include "../headers/BTreeScanner.h" @@ -182,6 +183,23 @@ (u_int8_t *) scanState->currentNodePtr += scanState->btcb->nodeSize; } +#if BYTE_ORDER == LITTLE_ENDIAN + { + BlockDescriptor block; + FileReference fref; + + /* Fake a BlockDescriptor */ + block.buffer = scanState->currentNodePtr; + block.blockSize = scanState->btcb->nodeSize; + block.blockReadFromDisk = 1; + block.isModified = 0; + + fref = scanState->btcb->fileRefNum; + + SWAP_BT_NODE(&block, ISHFSPLUS(VTOVCB(fref)), VTOC(fref)->c_fileid, 0); + } +#endif + // Make sure this is a valid node if ( CheckNode( scanState->btcb, scanState->currentNodePtr ) != noErr ) { diff -urN xnu-344.49/bsd/hfs/hfscommon/Catalog/CatalogIterators.c xnu-517/bsd/hfs/hfscommon/Catalog/CatalogIterators.c --- xnu-344.49/bsd/hfs/hfscommon/Catalog/CatalogIterators.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfscommon/Catalog/CatalogIterators.c Sat Oct 25 00:25:25 2003 @@ -369,7 +369,7 @@ bestIterator->volume = volume; // update the iterator's volume bestIterator->folderID = folderID; // ... and folderID - bestIterator->currentIndex = 0xFFFFFFFF; // ... and offspring index marker + bestIterator->currentIndex = 0xFFFF; // ... and offspring index marker bestIterator->currentOffset = 0xFFFFFFFF; bestIterator->nextOffset = 0xFFFFFFFF; diff -urN xnu-344.49/bsd/hfs/hfscommon/Catalog/FileIDsServices.c xnu-517/bsd/hfs/hfscommon/Catalog/FileIDsServices.c --- xnu-344.49/bsd/hfs/hfscommon/Catalog/FileIDsServices.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfscommon/Catalog/FileIDsServices.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -68,9 +68,6 @@ err = BuildCatalogKeyUTF8(vcb, destID, destName, kUndefinedStrLen, &destKey, NULL); ReturnIfError(err); - err = BTCheckFreeSpace(GetFileControlBlock(vcb->extentsRefNum)); - ReturnIfError(err); - if ( isHFSPlus ) { //-- Step 1: Check the catalog nodes for extents diff -urN xnu-344.49/bsd/hfs/hfscommon/Misc/FileExtentMapping.c xnu-517/bsd/hfs/hfscommon/Misc/FileExtentMapping.c --- xnu-344.49/bsd/hfs/hfscommon/Misc/FileExtentMapping.c Thu Sep 18 21:01:01 2003 +++ xnu-517/bsd/hfs/hfscommon/Misc/FileExtentMapping.c Sat Oct 25 00:25:25 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -250,15 +250,12 @@ kPreviousRecord = -1 }; -void HFSToHFSPlusExtents( - const HFSExtentRecord oldExtents, - HFSPlusExtentRecord newExtents); -OSErr HFSPlusToHFSExtents( +static OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents); -OSErr FindExtentRecord( +static OSErr FindExtentRecord( const ExtendedVCB *vcb, UInt8 forkType, UInt32 fileID, @@ -268,7 +265,7 @@ HFSPlusExtentRecord foundData, UInt32 *foundHint); -OSErr DeleteExtentRecord( +static OSErr DeleteExtentRecord( const ExtendedVCB *vcb, UInt8 forkType, UInt32 fileID, @@ -281,7 +278,7 @@ UInt32 *hint); -OSErr GetFCBExtentRecord( +static OSErr GetFCBExtentRecord( const FCB *fcb, HFSPlusExtentRecord extents); @@ -359,7 +356,7 @@ // fourth entry will be zeroes. // foundHint The BTree hint to find the node again //_________________________________________________________________________________ -OSErr FindExtentRecord( +static OSErr FindExtentRecord( const ExtendedVCB *vcb, UInt8 forkType, UInt32 fileID, @@ -376,7 +373,8 @@ UInt16 btRecordSize; err = noErr; - *foundHint = 0; + if (foundHint) + *foundHint = 0; fcb = GetFileControlBlock(vcb->extentsRefNum); MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); @@ -416,14 +414,15 @@ if (err == noErr) { UInt16 i; - // Copy the found key back for the caller - foundKey->keyLength = kHFSPlusExtentKeyMaximumLength; - foundKey->forkType = extentKeyPtr->forkType; - foundKey->pad = 0; - foundKey->fileID = extentKeyPtr->fileID; - foundKey->startBlock = extentKeyPtr->startBlock; - - // Copy the found data back for the caller + // Copy the found key back for the caller + if (foundKey) { + foundKey->keyLength = kHFSPlusExtentKeyMaximumLength; + foundKey->forkType = extentKeyPtr->forkType; + foundKey->pad = 0; + foundKey->fileID = extentKeyPtr->fileID; + foundKey->startBlock = extentKeyPtr->startBlock; + } + // Copy the found data back for the caller foundData[0].startBlock = extentData[0].startBlock; foundData[0].blockCount = extentData[0].blockCount; foundData[1].startBlock = extentData[1].startBlock; @@ -471,14 +470,16 @@ } if (err == noErr) { - // Copy the found key back for the caller - BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); - // Copy the found data back for the caller + // Copy the found key back for the caller + if (foundKey) + BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); + // Copy the found data back for the caller BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord)); } } - - *foundHint = btIterator->hint.nodeNum; + + if (foundHint) + *foundHint = btIterator->hint.nodeNum; FREE(btIterator, M_TEMP); return err; } @@ -499,11 +500,6 @@ err = noErr; *hint = 0; - // XXXdbg - preflight that there's enough space - err = BTCheckFreeSpace(GetFileControlBlock(vcb->extentsRefNum)); - if (err) - return err; - MALLOC(btIterator, BTreeIterator *, sizeo