]> git.saurik.com Git - apple/libc.git/commitdiff
Libc-1244.1.7.tar.gz macos-1013 macos-10131 v1244.1.7 v1244.20.1
authorApple <opensource@apple.com>
Tue, 26 Sep 2017 16:52:03 +0000 (16:52 +0000)
committerApple <opensource@apple.com>
Tue, 26 Sep 2017 16:52:03 +0000 (16:52 +0000)
187 files changed:
.gitattributes [new file with mode: 0644]
.upstream_base_commits
Libc.xcodeproj/project.pbxproj
Platforms/appletvos/Makefile.inc
Platforms/bridgeos/Makefile.inc
Platforms/iphoneos/Makefile.inc
Platforms/macosx/Makefile.inc
Platforms/watchos/Makefile.inc
darwin/init_cpu_capabilities.c [deleted file]
emulated/statvfs.c
fbsdcompat/_fbsd_compat_.h
fbsdcompat/_fpmath.h
fbsdcompat/spinlock.h
gdtoa/FreeBSD/_ldtoa.c
gdtoa/FreeBSD/gdtoa-hexnan.c
gdtoa/arith.h
gdtoa/gd_qnan.h
gen/FreeBSD/arc4random.3
gen/FreeBSD/arc4random.c
gen/FreeBSD/closedir.c
gen/FreeBSD/err.c
gen/FreeBSD/getcwd.3
gen/FreeBSD/getlogin.c
gen/FreeBSD/getmntinfo.3
gen/FreeBSD/getmntinfo.c
gen/FreeBSD/getpeereid.c
gen/FreeBSD/glob.3
gen/FreeBSD/glob.c
gen/FreeBSD/opendir.c
gen/FreeBSD/readdir.c
gen/FreeBSD/rewinddir.c
gen/FreeBSD/scandir.c
gen/FreeBSD/scandir_b.c
gen/FreeBSD/seekdir.c
gen/FreeBSD/telldir.c
gen/FreeBSD/telldir.h
gen/FreeBSD/ttyname.3
gen/FreeBSD/ttyslot.c
gen/FreeBSD/vis.c
gen/NetBSD/rb.c
gen/NetBSD/rbtree.3
gen/__dirent.h
gen/clock_gettime.c
gen/crypt.c
gen/disklabel.c
gen/fts.c
gen/getttyent.c
gen/nanosleep.c
gen/nlist.c
gen/strtofflags.c
gen/sync_volume_np.c
gen/thread_stack_pcs.c
gen/utmpx-darwin.c
include/_types.h
include/_types/_nl_item.h
include/_types/_wctrans_t.h
include/_types/_wctype_t.h
include/assert.h
include/dirent.h
include/fsproperties.h
include/glob.h
include/limits.h
include/secure/_string.h
include/secure/_strings.h [new file with mode: 0644]
include/stdint.h
include/stdio.h
include/stdlib.h
include/string.h
include/strings.h
include/sys/cdefs.h
include/sys/rbtree.h
include/time.h
include/unistd.h
include/wchar.h
libdarwin/AppleInternalVariant.plist [new file with mode: 0644]
libdarwin/dirstat.c [new file with mode: 0644]
libdarwin/dirstat.h [new file with mode: 0644]
libdarwin/dirstat_collection.c [new file with mode: 0644]
libdarwin/dirstat_collection.h [new file with mode: 0644]
libdarwin/init.c [new file with mode: 0644]
libdarwin/variant.c [new file with mode: 0644]
locale/FreeBSD/collate.c
locale/FreeBSD/gb18030.c
locale/FreeBSD/gb2312.c
locale/FreeBSD/setrunelocale.c
locale/FreeBSD/wcstod.c
locale/xlocale.c
locale/xlocale_private.h
man/manpages.lst
net/FreeBSD/inet.3
os/assumes.c
os/assumes.h
os/variant_private.h [new file with mode: 0644]
secure/chk_fail.c
stdio/FreeBSD/_flock_stub.c
stdio/FreeBSD/fgetwc.c
stdio/FreeBSD/findfp.c
stdio/FreeBSD/fmemopen.c [new file with mode: 0644]
stdio/FreeBSD/fopen.3
stdio/FreeBSD/fputs.c
stdio/FreeBSD/getdelim.c
stdio/FreeBSD/mktemp.3
stdio/FreeBSD/mktemp.c
stdio/FreeBSD/open_memstream.3 [new file with mode: 0644]
stdio/FreeBSD/open_memstream.c [new file with mode: 0644]
stdio/FreeBSD/open_wmemstream.c [new file with mode: 0644]
stdio/FreeBSD/printf.3
stdio/FreeBSD/vfprintf.c
stdio/FreeBSD/vfwprintf.c
stdio/FreeBSD/vswprintf.c
stdio/FreeBSD/xprintf_float.c
stdio/FreeBSD/xprintf_int.c
stdlib/FreeBSD/atexit.3
stdlib/FreeBSD/exit.c
stdlib/FreeBSD/getenv.c
stdlib/FreeBSD/psort.c
stdlib/FreeBSD/psort_b.c
stdlib/FreeBSD/psort_r.c
stdlib/FreeBSD/qsort.c
stdlib/FreeBSD/realpath.3
stdlib/FreeBSD/realpath.c
stdlib/FreeBSD/setenv.c
stdlib/FreeBSD/system.c
stdlib/qsort_b-fbsd.c [deleted file]
stdlib/qsort_b.c [new file with mode: 0644]
stdtime/FreeBSD/ctime.3
stdtime/FreeBSD/ftime.c
stdtime/FreeBSD/localtime.c
stdtime/FreeBSD/private.h
stdtime/FreeBSD/strftime.c
stdtime/FreeBSD/strptime.c
stdtime/FreeBSD/tzfile.5
stdtime/FreeBSD/tzfile.h
stdtime/timegm.3 [deleted file]
string/FreeBSD/strerror.c
string/FreeBSD/strlcpy.3
string/NetBSD/memset_s.3
sys/crt_externs.c
sys/gettimeofday.c
sys/settimeofday.c
tests/Makefile
tests/assumes.c [new file with mode: 0644]
tests/assumes_legacy.c [new file with mode: 0644]
tests/dir.c [new file with mode: 0644]
tests/dirstat.c [new file with mode: 0644]
tests/err.c [new file with mode: 0644]
tests/flockfile.c [new file with mode: 0644]
tests/freebsd_fmemopen.c [new file with mode: 0644]
tests/freebsd_glob.c [new file with mode: 0644]
tests/freebsd_open_memstream.c [new file with mode: 0644]
tests/freebsd_open_wmemstream.c [new file with mode: 0644]
tests/freebsd_qsort.c [new file with mode: 0644]
tests/freebsd_qsort.h [new file with mode: 0644]
tests/fts_find.c
tests/locale.c
tests/mktemp.c
tests/net.c
tests/netbsd_fmemopen.c [new file with mode: 0644]
tests/netbsd_getenv_thread.c
tests/netbsd_glob.c [new file with mode: 0644]
tests/netbsd_open_memstream.c [new file with mode: 0644]
tests/netbsd_printf.c [new file with mode: 0644]
tests/netbsd_stat.c
tests/netbsd_strerror.c [new file with mode: 0644]
tests/netbsd_vis.c
tests/os_variant.c [new file with mode: 0644]
tests/printf.c [new file with mode: 0644]
tests/psort.c
tests/qsort.c [new file with mode: 0644]
tests/qsort_perf.c [new file with mode: 0644]
tests/realpath.c [new file with mode: 0644]
tests/realpath_edge.c [new file with mode: 0644]
tests/stdio.c
tests/strerror.c [new file with mode: 0644]
tests/strlcpy.c [new file with mode: 0644]
tests/strptime.c
tests/wchar.c
util/login.c
x86_64/string/strncpy.s
xcodescripts/eos.xcconfig
xcodescripts/generate_features.pl
xcodescripts/headers.sh
xcodescripts/legacy_alias.list [new file with mode: 0644]
xcodescripts/libc.xcconfig
xcodescripts/manpages.sh
xcodescripts/patch_headers_variants.pl
xcodescripts/variants.xcconfig

diff --git a/.gitattributes b/.gitattributes
new file mode 100644 (file)
index 0000000..5012327
--- /dev/null
@@ -0,0 +1 @@
+.upstream_base_commits merge=union
index e5121036b4b515427fd387abf32723f07b8c3cda..efee8b91582db615f1d97e208a2008250944ce2b 100644 (file)
@@ -1,21 +1,29 @@
 #freebsd = https://github.com/freebsd/freebsd.git
-#openbsd = https://github.com/robertbachmann/openbsd-libc.git
+#openbsd = https://github.com/openbsd/src.git
+#netbsd = https://github.com/NetBSD/src.git
 gen/FreeBSD/basename.c freebsd lib/libc/gen/basename.c 26f49abeef12bd43e9671edee6df7b9905c97a47
 gen/FreeBSD/basename.3 freebsd lib/libc/gen/basename.3 26f49abeef12bd43e9671edee6df7b9905c97a47
 gen/FreeBSD/clock.3    freebsd lib/libc/gen/clock.3    5b882020081a138285227631c46a406c08e17bc8
 gen/FreeBSD/ctermid.3  freebsd lib/libc/gen/ctermid.3  5b882020081a138285227631c46a406c08e17bc8
 gen/FreeBSD/getbsize.c freebsd lib/libc/gen/getbsize.c 5b882020081a138285227631c46a406c08e17bc8
+gen/FreeBSD/getcwd.3   freebsd lib/libc/gen/getcwd.3   898928e8d0a0bab201c1ef232e01cafa27322dae
+gen/FreeBSD/getpeereid.c       freebsd lib/libc/gen/getpeereid.c       898928e8d0a0bab201c1ef232e01cafa27322dae
+gen/FreeBSD/glob.c     freebsd lib/libc/gen/glob.c     ececcb3d95a00665500a1f799a118fc4eaf6750b
+gen/FreeBSD/glob.3     freebsd lib/libc/gen/glob.3     ececcb3d95a00665500a1f799a118fc4eaf6750b
 gen/FreeBSD/raise3     freebsd lib/libc/gen/raise.3    6b42c90c1ff5f7c35431eced41b6213401521d3d
 gen/FreeBSD/readpassphrase.c   freebsd lib/libc/gen/readpassphrase.c   1f19a8fc755a14865a5a5b67d5fa895c4b7cf622
 gen/FreeBSD/readpassphrase.3   freebsd lib/libc/gen/readpassphrase.3   e0a2d4f15ed9e93fcb62544ed65f7a98e2339c3b
 gen/FreeBSD/times.3    freebsd lib/libc/gen/times.3    5b882020081a138285227631c46a406c08e17bc8
+gen/FreeBSD/ttyslot.c  freebsd lib/libc/gen/ttyslot.c  898928e8d0a0bab201c1ef232e01cafa27322dae
 gen/FreeBSD/unvis.c    freebsd contrib/libc-vis/unvis.c        9e3e4b88576d01efe1f56469cac79e116bb62c67
 gen/FreeBSD/unvis.3    freebsd contrib/libc-vis/unvis.3        9e3e4b88576d01efe1f56469cac79e116bb62c67
 gen/FreeBSD/usleep.3   freebsd lib/libc/gen/usleep.3   5b882020081a138285227631c46a406c08e17bc8
 gen/FreeBSD/vis.c      freebsd contrib/libc-vis/unvis.c        9e3e4b88576d01efe1f56469cac79e116bb62c67
 gen/FreeBSD/vis.3      freebsd contrib/libc-vis/unvis.3        9e3e4b88576d01efe1f56469cac79e116bb62c67
 gen/FreeBSD/vis.h      freebsd contrib/libc-vis/unvis.3        9e3e4b88576d01efe1f56469cac79e116bb62c67
-gen/fts.c      openbsd gen/fts.c       2a32c97c979d267fa99a362943265700bfcac5fd
+gen/NetBSD/rbtree.3    netbsd  share/man/man3/rbtree.3 a6d78d4a28be21d6006d3c609f31967c0e536779
+gen/fts.c      openbsd gen/fts.c       9936a0e983044822375a0d5cdebec20c3623866c
+include/glob.h freebsd include/glob.h  ececcb3d95a00665500a1f799a118fc4eaf6750b
 include/readpassphrase.h       freebsd include/readpassphrase.h        e0a2d4f15ed9e93fcb62544ed65f7a98e2339c3b
 locale/FreeBSD/ascii.c freebsd lib/libc/locale/ascii.c 93e484e00e1e2dc498a7f4c45c0019e43b8ec5b2
 locale/FreeBSD/isspecial.3     freebsd freebsd/lib/libc/locale/isspecial.3     5b882020081a138285227631c46a406c08e17bc8
@@ -23,25 +31,55 @@ locale/FreeBSD/none.c       freebsd lib/libc/locale/ascii.c 93e484e00e1e2dc498a7f4c45c
 locale/FreeBSD/setlocale.3     freebsd lib/libc/locale/setlocale.3     2131182e401759b74104a541a3b43cf2ee6a7434
 man/FreeBSD/environ.7  freebsd share/man/man7/environ.7        5b882020081a138285227631c46a406c08e17bc8
 net/FreeBSD/linkaddr.c freebsd lib/libc/net/linkaddr.c 9240f72512c0357636b2e19554d6141ee21edc5f
+stdio/FreeBSD/fopen.3  freebsd lib/libc/stdio/fopen.3  89c1fcc0d088065021703b658ef547f46b5481f0
+stdio/FreeBSD/fmemopen.c       freebsd lib/libc/stdio/fmemopen.c       89c1fcc0d088065021703b658ef547f46b5481f0
+stdio/FreeBSD/open_memstream.3 freebsd lib/libc/stdio/open_memstream.3 89c1fcc0d088065021703b658ef547f46b5481f0
+stdio/FreeBSD/open_memstream.c freebsd lib/libc/stdio/open_memstream.c 89c1fcc0d088065021703b658ef547f46b5481f0
+stdio/FreeBSD/open_wmemstream.c        freebsd lib/libc/stdio/open_wmemstream.c        89c1fcc0d088065021703b658ef547f46b5481f0
 stdio/FreeBSD/mktemp.3 freebsd lib/libc/stdio/mktemp.3 2895e1352cf3788606924d800c3a5c589520ea00
 stdio/FreeBSD/mktemp.c freebsd lib/libc/stdio/mktemp.c 2895e1352cf3788606924d800c3a5c589520ea00
 stdio/FreeBSD/printf.3 freebsd lib/libc/stdio/printf.3 cfc3df2b8f708ce8494d9d556e3472a5c8c21b8a
 stdio/FreeBSD/wprintf.3        freebsd lib/libc/stdio/wprintf.3        5b882020081a138285227631c46a406c08e17bc8
+stdlib/FreeBSD/atexit.3        freebsd lib/libc/stdlib/atexit  956381ee95fa01eefc74c9228bdc474ba267750d
 stdlib/FreeBSD/getenv.3        freebsd lib/libc/stdlib/getenv.3        3eb0ea4663f0ae19c4983e80963a121463224508
 stdlib/FreeBSD/getopt_long.3   freebsd lib/libc/stdlib/getopt_long.3   5b882020081a138285227631c46a406c08e17bc8
+stdlib/FreeBSD/qsort.c freebsd lib/libc/stdlib/qsort.c 4127dd6b50348062f74679dbb43008d0a2985a09
 stdlib/FreeBSD/reallocf.c      freebsd lib/libc/stdlib/reallocf.c      3dc97c4341b6c5a0163c12badc7f50628cecf4e6
+stdtime/FreeBSD/localtime.c    freebsd contrib/tzcode/stdtime/localtime.c      a931eab7f4cf8a9614505540fb523b59f693cc6e
+stdtime/FreeBSD/private.h      freebsd contrib/tzcode/stdtime/private.h        a931eab7f4cf8a9614505540fb523b59f693cc6e
 stdtime/FreeBSD/strptime.c     freebsd lib/libc/stdtime/strptime.c     52d53d171566c2cd975d2db86a291e516d34d9fe
 stdtime/FreeBSD/strptime.3     freebsd lib/libc/stdtime/strptime.3     52d53d171566c2cd975d2db86a291e516d34d9fe
+stdtime/FreeBSD/tzfile.h       freebsd contrib/tzcode/stdtime/tzfile.h 000663e80955a044c229f9274011b828a788ee4b
+stdtime/FreeBSD/tzfile.5       freebsd contrib/tzcode/stdtime/tzfile.5 000663e80955a044c229f9274011b828a788ee4b
 string/FreeBSD/bcmp.3  freebsd lib/libc/string/bcmp.3  408f4a1ab49f89368c80edb4485895658fc81598
 string/FreeBSD/memcmp.3        freebsd lib/libc/string/memcmp.3        3eb0ea4663f0ae19c4983e80963a121463224508
 string/FreeBSD/strcpy.3        freebsd lib/libc/string/strcpy.3        cfc3df2b8f708ce8494d9d556e3472a5c8c21b8a
+string/FreeBSD/strlcpy.3       freebsd lib/libc/string/strlcpy.3       e3c83e4556db162d5b54833d2e9974a1152394eb
 string/FreeBSD/strpbrk.3       freebsd lib/libc/string/strpbrk.3       5b882020081a138285227631c46a406c08e17bc8
 string/FreeBSD/strspn.3        freebsd lib/libc/string/strspn.3        5b882020081a138285227631c46a406c08e17bc8
 string/FreeBSD/strstr.3        freebsd lib/libc/string/strstr.3        cfc3df2b8f708ce8494d9d556e3472a5c8c21b8a
 string/FreeBSD/timingsafe_bcmp.3       freebsd lib/libc/string/timingsafe_bcmp.3       408f4a1ab49f89368c80edb4485895658fc81598
 string/FreeBSD/timingsafe_bcmp.c       freebsd lib/libc/string/timingsafe_bcmp.c       408f4a1ab49f89368c80edb4485895658fc81598
+tests/freebsd_fmemopen.c       freebsd lib/libc/tests/stdio/fmemopen2_test.c   89c1fcc0d088065021703b658ef547f46b5481f0
+tests/freebsd_glob.c   freebsd lib/libc/tests/gen/glob2_test.c ececcb3d95a00665500a1f799a118fc4eaf6750b
+tests/freebsd_open_memstream.c freebsd lib/libc/tests/stdio/open_memstream2_test.c     89c1fcc0d088065021703b658ef547f46b5481f0
+tests/freebsd_open_wmemstream.c        freebsd lib/libc/tests/stdio/open_wmemstream_test.c     89c1fcc0d088065021703b658ef547f46b5481f0
+tests/freebsd_qsort.c  freebsd ./lib/libc/tests/stdlib/qsort_test.c    4127dd6b50348062f74679dbb43008d0a2985a09
+tests/freebsd_qsort.h  freebsd ./lib/libc/tests/stdlib/test-sort.h     4127dd6b50348062f74679dbb43008d0a2985a09
+tests/netbsd_fmemopen.c        freebsd contrib/netbsd-tests/lib/libc/stdio/t_fmemopen.c        89c1fcc0d088065021703b658ef547f46b5481f0
+tests/netbsd_open_memstream.c  freebsd contrib/netbsd-tests/lib/libc/stdio/t_open_memstream.c  89c1fcc0d088065021703b658ef547f46b5481f0
 tests/netbsd_getcwd.c  freebsd contrib/netbsd-tests/lib/libc/gen/t_getcwd.c    6f5b3c1fa3e9554a26cbf6401366ff8b0f0506fe
 tests/netbsd_getenv_thread.c   freebsd contrib/netbsd-tests/lib/libc/stdlib/t_getenv_thread.c  3f09b8d0af642c2aeb96a4d667cefb7fe3bce443
+tests/netbsd_glob.c    freebsd contrib/netbsd-tests/lib/libc/gen/t_glob.c      ececcb3d95a00665500a1f799a118fc4eaf6750b
+tests/netbsd_printf.c  freebsd contrib/netbsd-tests/lib/libc/stdio/t_printf.c  6ea6500b7eba4165c351cbbfcdec7f2fe776f8ac
 tests/netbsd_stat.c    freebsd contrib/netbsd-tests/lib/libc/sys/t_stat.c      6f5b3c1fa3e9554a26cbf6401366ff8b0f0506fe
 tests/netbsd_strptime.c        freebsd contrib/netbsd-tests/lib/libc/time/t_strptime.c 52d53d171566c2cd975d2db86a291e516d34d9fe
 tests/netbsd_vis.c     freebsd contrib/netbsd-tests/lib/libc/gen/t_vis.c       52d53d171566c2cd975d2db86a291e516d34d9fe
+gen/FreeBSD/closedir.c freebsd lib/libc/gen/closedir.c b717fb9f083afdfbc50a14ced6ddc971ca583f02
+gen/FreeBSD/opendir.c  freebsd lib/libc/gen/opendir.c  6e91d78151e10ed31c475cafe6a1e1f11950c1d9
+gen/FreeBSD/readdir.c  freebsd lib/libc/gen/readdir.c  74c1506b3359ee725c9031331908b717460830dc
+gen/FreeBSD/rewinddir.c        freebsd lib/libc/gen/rewinddir.c        74c1506b3359ee725c9031331908b717460830dc
+gen/FreeBSD/scandir.c  freebsd lib/libc/gen/scandir.c  0127b103f27578fc7f9cc3389b299f221deb1d4c
+gen/FreeBSD/scandir_b.c        freebsd lib/libc/gen/scandir_b.c        0127b103f27578fc7f9cc3389b299f221deb1d4c
+gen/FreeBSD/seekdir.c  freebsd lib/libc/gen/seekdir.c  74c1506b3359ee725c9031331908b717460830dc
+gen/FreeBSD/telldir.c  freebsd lib/libc/gen/telldir.c  74c1506b3359ee725c9031331908b717460830dc
index adda4b87cb8af128ebeec8ff7ec4675d04f612a3..6802ba6191bfc1f0f0387780fbc5213aef872c0a 100644 (file)
                        name = Libc_tests;
                        productName = Libc_tests;
                };
+               926F739D1E046E55001E049D /* Libc_darwin */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = 926F739E1E046E56001E049D /* Build configuration list for PBXAggregateTarget "Libc_darwin" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               926F73A21E046E69001E049D /* PBXTargetDependency */,
+                       );
+                       name = Libc_darwin;
+                       productName = libdarwin;
+               };
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
                63D4061113DDF4340094DD56 /* strncat.c in Sources */ = {isa = PBXBuildFile; fileRef = 63D4060F13DDF4340094DD56 /* strncat.c */; };
                63D4061313DDF6A30094DD56 /* strlcat.c in Sources */ = {isa = PBXBuildFile; fileRef = 63D4061213DDF6A20094DD56 /* strlcat.c */; };
                63D4061413DDF6A30094DD56 /* strlcat.c in Sources */ = {isa = PBXBuildFile; fileRef = 63D4061213DDF6A20094DD56 /* strlcat.c */; };
+               926F73981E03E8C4001E049D /* variant.c in Sources */ = {isa = PBXBuildFile; fileRef = 926F73971E03E8C4001E049D /* variant.c */; };
+               926F739A1E03E8D6001E049D /* variant_private.h in Headers */ = {isa = PBXBuildFile; fileRef = 926F73991E03E8D6001E049D /* variant_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               92767C841E0A7E2700AB9C76 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 92767C821E0A7E2100AB9C76 /* init.c */; };
+               928841361EA75555001064D1 /* dirstat_collection.c in Sources */ = {isa = PBXBuildFile; fileRef = 928841341EA7554D001064D1 /* dirstat_collection.c */; };
+               92888B161EA5BE7400BA923E /* fmemopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 92888B0F1EA5BE6D00BA923E /* fmemopen.c */; };
+               92888B171EA5BE8000BA923E /* open_memstream.c in Sources */ = {isa = PBXBuildFile; fileRef = 92888B111EA5BE6D00BA923E /* open_memstream.c */; };
+               92888B181EA5BE8600BA923E /* open_wmemstream.c in Sources */ = {isa = PBXBuildFile; fileRef = 92888B121EA5BE6D00BA923E /* open_wmemstream.c */; };
                928BD1001D76072200EC01FC /* timingsafe_bcmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 928BD0FE1D7606EA00EC01FC /* timingsafe_bcmp.c */; };
                928BD1011D76072200EC01FC /* timingsafe_bcmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 928BD0FE1D7606EA00EC01FC /* timingsafe_bcmp.c */; };
                928BD1021D76072C00EC01FC /* timingsafe_bcmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 928BD0FE1D7606EA00EC01FC /* timingsafe_bcmp.c */; };
                928BD1071D76073600EC01FC /* timingsafe_bcmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 928BD0FE1D7606EA00EC01FC /* timingsafe_bcmp.c */; };
                928BD1081D76073600EC01FC /* timingsafe_bcmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 928BD0FE1D7606EA00EC01FC /* timingsafe_bcmp.c */; };
                92ABC7E91D375FC2000DF880 /* compatibility_hacks.c in Sources */ = {isa = PBXBuildFile; fileRef = 92ABC7E81D375FC2000DF880 /* compatibility_hacks.c */; };
+               92D763E01EA6DA3A001467FC /* dirstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 92D763DC1EA6D9FB001467FC /* dirstat.c */; };
                B10BC41C14338AEB005E4366 /* regcomp.c in Sources */ = {isa = PBXBuildFile; fileRef = B122F2B11432B95B00AF95D0 /* regcomp.c */; settings = {COMPILER_FLAGS = "-DHAVE_CONFIG_H -I$(SRCROOT)/regex/TRE -I$(SRCROOT)/regex/FreeBSD"; }; };
                B122F2C71432B95B00AF95D0 /* regcomp.c in Sources */ = {isa = PBXBuildFile; fileRef = B122F2B11432B95B00AF95D0 /* regcomp.c */; };
                B122F2C91432B95B00AF95D0 /* regexec.c in Sources */ = {isa = PBXBuildFile; fileRef = B122F2B21432B95B00AF95D0 /* regexec.c */; };
                C0E345571C582ECB00E749C2 /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C0E345581C582ECB00E749C2 /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C0E345591C582ECB00E749C2 /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C0E3455A1C582ECB00E749C2 /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C0E3455A1C582ECB00E749C2 /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C0E3455B1C582ECB00E749C2 /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C0E3455C1C582ECB00E749C2 /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C0E3455D1C582ECB00E749C2 /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C0E345C11C582ECB00E749C2 /* (null) in Sources */ = {isa = PBXBuildFile; };
                C0E345C21C582ECB00E749C2 /* (null) in Sources */ = {isa = PBXBuildFile; };
                C0E345C31C582ECB00E749C2 /* scandir_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9EB350E138F769B0075BB52 /* scandir_b.c */; settings = {COMPILER_FLAGS = "$(FreeBSD_CFLAGS) -include gen/__dirent.h"; }; };
-               C0E345C41C582ECB00E749C2 /* init_cpu_capabilities.c in Sources */ = {isa = PBXBuildFile; fileRef = C921D3831395B7DD001CE070 /* init_cpu_capabilities.c */; };
-               C0E345C51C582ECB00E749C2 /* pthread_getspecific.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3841395B7DD001CE070 /* pthread_getspecific.s */; };
-               C0E345C61C582ECB00E749C2 /* pthread_self.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3851395B7DD001CE070 /* pthread_self.s */; };
-               C0E345C71C582ECB00E749C2 /* pthread_set_self.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3861395B7DD001CE070 /* pthread_set_self.s */; };
-               C0E345C81C582ECB00E749C2 /* start_wqthread.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3871395B7DD001CE070 /* start_wqthread.s */; };
-               C0E345C91C582ECB00E749C2 /* thread_start.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3881395B7DD001CE070 /* thread_start.s */; };
                C0E345CA1C582ECB00E749C2 /* strcpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6310518613D4D966004F7BA8 /* strcpy.c */; };
                C0E345CB1C582ECB00E749C2 /* strlcpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6310518B13D4DABD004F7BA8 /* strlcpy.c */; };
                C0E345CC1C582ECB00E749C2 /* strncpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6310518E13D4DAEA004F7BA8 /* strncpy.c */; };
                C0E345DC1C582ECB00E749C2 /* libFreeBSD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C9257ED0138E1B5000B3107C /* libFreeBSD.a */; };
                C0E345DD1C582ECB00E749C2 /* libvCancelable.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C9D94360138EC3E300FB7ACC /* libvCancelable.a */; };
                C0E345DE1C582ECB00E749C2 /* libTRE.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B122F2AD1432B8E600AF95D0 /* libTRE.a */; };
-               C921D3891395B7DD001CE070 /* init_cpu_capabilities.c in Sources */ = {isa = PBXBuildFile; fileRef = C921D3831395B7DD001CE070 /* init_cpu_capabilities.c */; };
-               C921D38A1395B7DD001CE070 /* pthread_getspecific.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3841395B7DD001CE070 /* pthread_getspecific.s */; };
-               C921D38B1395B7DD001CE070 /* pthread_self.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3851395B7DD001CE070 /* pthread_self.s */; };
-               C921D38C1395B7DD001CE070 /* pthread_set_self.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3861395B7DD001CE070 /* pthread_set_self.s */; };
-               C921D38D1395B7DD001CE070 /* start_wqthread.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3871395B7DD001CE070 /* start_wqthread.s */; };
-               C921D38E1395B7DD001CE070 /* thread_start.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3881395B7DD001CE070 /* thread_start.s */; };
                C9257ED5138E1C2E00B3107C /* creat.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B535F8138D9E980028D27C /* creat.c */; };
                C9257ED6138E1C2E00B3107C /* gethostid.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B535FC138D9E980028D27C /* gethostid.c */; };
                C9257ED7138E1C2E00B3107C /* getwd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B535FE138D9E980028D27C /* getwd.c */; };
                C942123913900C8A004BA536 /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C942123A13900C8A004BA536 /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C942123B13900C8A004BA536 /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C942123C13900C8A004BA536 /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C942123C13900C8A004BA536 /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C942123D13900C8A004BA536 /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C942123E13900C8A004BA536 /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C942123F13900C8A004BA536 /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C95B80E4138F3C55004311DA /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C95B80E5138F3C55004311DA /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C95B80E6138F3C55004311DA /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C95B80E7138F3C55004311DA /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C95B80E7138F3C55004311DA /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C95B80E8138F3C55004311DA /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C95B80E9138F3C55004311DA /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C95B80EA138F3C55004311DA /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C95B838F138F52B0004311DA /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C95B8390138F52B0004311DA /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C95B8391138F52B0004311DA /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C95B8392138F52B0004311DA /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C95B8392138F52B0004311DA /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C95B8393138F52B0004311DA /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C95B8394138F52B0004311DA /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C95B8395138F52B0004311DA /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C95B8635138F53DB004311DA /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C95B8636138F53DB004311DA /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C95B8637138F53DB004311DA /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C95B8638138F53DB004311DA /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C95B8638138F53DB004311DA /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C95B8639138F53DB004311DA /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C95B863A138F53DB004311DA /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C95B863B138F53DB004311DA /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C97660B9138EC61A00741512 /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C97660BA138EC61A00741512 /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C97660BB138EC61A00741512 /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C97660BC138EC61A00741512 /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C97660BC138EC61A00741512 /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C97660BD138EC61A00741512 /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C97660BE138EC61A00741512 /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C97660BF138EC61A00741512 /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C97A71771517AF53005E1998 /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C97A71781517AF53005E1998 /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C97A71791517AF53005E1998 /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C97A717A1517AF53005E1998 /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C97A717A1517AF53005E1998 /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C97A717B1517AF53005E1998 /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C97A717C1517AF53005E1998 /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C97A717D1517AF53005E1998 /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C97A71F91517AF53005E1998 /* (null) in Sources */ = {isa = PBXBuildFile; };
                C97A71FA1517AF53005E1998 /* (null) in Sources */ = {isa = PBXBuildFile; };
                C97A71FD1517AF53005E1998 /* scandir_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9EB350E138F769B0075BB52 /* scandir_b.c */; settings = {COMPILER_FLAGS = "$(FreeBSD_CFLAGS) -include gen/__dirent.h"; }; };
-               C97A71FF1517AF53005E1998 /* init_cpu_capabilities.c in Sources */ = {isa = PBXBuildFile; fileRef = C921D3831395B7DD001CE070 /* init_cpu_capabilities.c */; };
-               C97A72001517AF53005E1998 /* pthread_getspecific.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3841395B7DD001CE070 /* pthread_getspecific.s */; };
-               C97A72011517AF53005E1998 /* pthread_self.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3851395B7DD001CE070 /* pthread_self.s */; };
-               C97A72021517AF53005E1998 /* pthread_set_self.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3861395B7DD001CE070 /* pthread_set_self.s */; };
-               C97A72031517AF53005E1998 /* start_wqthread.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3871395B7DD001CE070 /* start_wqthread.s */; };
-               C97A72041517AF53005E1998 /* thread_start.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3881395B7DD001CE070 /* thread_start.s */; };
                C97A720D1517AF53005E1998 /* strcpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6310518613D4D966004F7BA8 /* strcpy.c */; };
                C97A720E1517AF53005E1998 /* strlcpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6310518B13D4DABD004F7BA8 /* strlcpy.c */; };
                C97A720F1517AF53005E1998 /* strncpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6310518E13D4DAEA004F7BA8 /* strncpy.c */; };
                C97A72171517AF53005E1998 /* dirfd.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FB7E1B4146EF2E000843438 /* dirfd.c */; };
                C98373971395989E00E5C052 /* OSMemoryNotification.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53DAC138D9E9A0028D27C /* OSMemoryNotification.c */; };
                C98373981395989E00E5C052 /* OSThermalNotification.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53DAD138D9E9A0028D27C /* OSThermalNotification.c */; };
-               C98E2B4C139851B7002A3ABB /* init_cpu_capabilities.c in Sources */ = {isa = PBXBuildFile; fileRef = C921D3831395B7DD001CE070 /* init_cpu_capabilities.c */; };
-               C98E2B4D139851B7002A3ABB /* pthread_getspecific.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3841395B7DD001CE070 /* pthread_getspecific.s */; };
-               C98E2B4E139851B7002A3ABB /* pthread_self.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3851395B7DD001CE070 /* pthread_self.s */; };
-               C98E2B4F139851B7002A3ABB /* pthread_set_self.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3861395B7DD001CE070 /* pthread_set_self.s */; };
-               C98E2B50139851B7002A3ABB /* start_wqthread.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3871395B7DD001CE070 /* start_wqthread.s */; };
-               C98E2B51139851B7002A3ABB /* thread_start.s in Sources */ = {isa = PBXBuildFile; fileRef = C921D3881395B7DD001CE070 /* thread_start.s */; };
                C9A12853138E0BE00003880A /* gmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B5380B138D9E990028D27C /* gmon.c */; };
                C9A12854138E0C1C0003880A /* isctype.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B539E5138D9E990028D27C /* isctype.c */; };
                C9A12855138E0C1C0003880A /* iswctype.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B539E7138D9E990028D27C /* iswctype.c */; };
                C9EB31D4138F6D880075BB52 /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C9EB31D5138F6D880075BB52 /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C9EB31D6138F6D880075BB52 /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C9EB31D7138F6D880075BB52 /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C9EB31D7138F6D880075BB52 /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C9EB31D8138F6D880075BB52 /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C9EB31D9138F6D880075BB52 /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C9EB31DA138F6D880075BB52 /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C9EB347B138F75580075BB52 /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                C9EB347C138F75580075BB52 /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C9EB347D138F75580075BB52 /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C9EB347E138F75580075BB52 /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C9EB347E138F75580075BB52 /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C9EB347F138F75580075BB52 /* asctime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC2138D9E9A0028D27C /* asctime.c */; };
                C9EB3480138F75580075BB52 /* difftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC6138D9E9A0028D27C /* difftime.c */; };
                C9EB3481138F75580075BB52 /* ftime.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CC9138D9E9A0028D27C /* ftime.c */; };
                C9FA3348138E4D040089A94B /* l64a.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CAD138D9E9A0028D27C /* l64a.c */; };
                C9FA334A138E4D040089A94B /* ecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB7138D9E9A0028D27C /* ecvt.c */; };
                C9FA334B138E4D040089A94B /* gcvt.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB9138D9E9A0028D27C /* gcvt.c */; };
-               C9FA334C138E4D040089A94B /* qsort_b-fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */; };
+               C9FA334C138E4D040089A94B /* qsort_b.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CBD138D9E9A0028D27C /* qsort_b.c */; };
                C9FA334D138E4D0C0089A94B /* strfmon.c in Sources */ = {isa = PBXBuildFile; fileRef = C9B53CB2138D9E9A0028D27C /* strfmon.c */; };
                FC2ED610157D4BE80098EC69 /* inet_ntop.c in Sources */ = {isa = PBXBuildFile; fileRef = FC2ED60E157D4BE70098EC69 /* inet_ntop.c */; };
                FC2ED611157D4BE80098EC69 /* inet_ntop.c in Sources */ = {isa = PBXBuildFile; fileRef = FC2ED60E157D4BE70098EC69 /* inet_ntop.c */; };
                        remoteGlobalIDString = 3F51206A16C3174300AFB431;
                        remoteInfo = FortifySource;
                };
+               926F73A11E046E69001E049D /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = C9B53597138D9A690028D27C /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 926F73911E03E2A3001E049D;
+                       remoteInfo = libsystem_darwin.dylib;
+               };
                928F25D41BEAD2AE007B13C7 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = C9B53597138D9A690028D27C /* Project object */;
                63D4060C13DDF26A0094DD56 /* strcat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = strcat.c; sourceTree = "<group>"; };
                63D4060F13DDF4340094DD56 /* strncat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = strncat.c; sourceTree = "<group>"; };
                63D4061213DDF6A20094DD56 /* strlcat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = strlcat.c; sourceTree = "<group>"; };
+               926F73921E03E2A3001E049D /* libsystem_darwin.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_darwin.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+               926F73971E03E8C4001E049D /* variant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = variant.c; sourceTree = "<group>"; };
+               926F73991E03E8D6001E049D /* variant_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = variant_private.h; path = os/variant_private.h; sourceTree = "<group>"; };
+               92767C821E0A7E2100AB9C76 /* init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = init.c; sourceTree = "<group>"; };
+               9280EA171E59BC8A007A6F58 /* AppleInternalVariant.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AppleInternalVariant.plist; sourceTree = "<group>"; };
+               928841341EA7554D001064D1 /* dirstat_collection.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dirstat_collection.c; sourceTree = "<group>"; };
+               92888B0F1EA5BE6D00BA923E /* fmemopen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmemopen.c; sourceTree = "<group>"; };
+               92888B101EA5BE6D00BA923E /* open_memstream.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = open_memstream.3; sourceTree = "<group>"; };
+               92888B111EA5BE6D00BA923E /* open_memstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = open_memstream.c; sourceTree = "<group>"; };
+               92888B121EA5BE6D00BA923E /* open_wmemstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = open_wmemstream.c; sourceTree = "<group>"; };
                928BD0FD1D7606EA00EC01FC /* timingsafe_bcmp.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = timingsafe_bcmp.3; sourceTree = "<group>"; };
                928BD0FE1D7606EA00EC01FC /* timingsafe_bcmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = timingsafe_bcmp.c; sourceTree = "<group>"; };
                928BD1091D7608A400EC01FC /* environ.7 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = environ.7; sourceTree = "<group>"; };
                92ABC7E81D375FC2000DF880 /* compatibility_hacks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compatibility_hacks.c; sourceTree = "<group>"; };
+               92D763DC1EA6D9FB001467FC /* dirstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dirstat.c; sourceTree = "<group>"; };
+               92D763E41EA6F887001467FC /* dirstat_collection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirstat_collection.h; sourceTree = "<group>"; };
+               92D763E51EA6F887001467FC /* dirstat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirstat.h; sourceTree = "<group>"; };
                B122F2AD1432B8E600AF95D0 /* libTRE.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTRE.a; sourceTree = BUILT_PRODUCTS_DIR; };
                B122F2AF1432B95B00AF95D0 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
                B122F2B11432B95B00AF95D0 /* regcomp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = regcomp.c; sourceTree = "<group>"; };
                B1795372158B0E35008990E8 /* xprintf_exec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xprintf_exec.c; sourceTree = "<group>"; };
                B19C64591450F8B900032373 /* sync_volume_np.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sync_volume_np.3; sourceTree = "<group>"; };
                B19C645B1450F90200032373 /* sync_volume_np.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sync_volume_np.c; sourceTree = "<group>"; };
+               C00AC1181E04B7E000286B61 /* legacy_opendir_alias.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = legacy_opendir_alias.list; sourceTree = "<group>"; };
                C06E02D11CA0C9CA00B07322 /* tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = tests; sourceTree = "<group>"; };
                C0E343811C58299D00E749C2 /* skip_installhdrs.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = skip_installhdrs.sh; sourceTree = "<group>"; };
                C0E345E21C582ECB00E749C2 /* libc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libc.a; sourceTree = BUILT_PRODUCTS_DIR; };
                C0E345E31C58300F00E749C2 /* libc_static.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libc_static.xcconfig; sourceTree = "<group>"; };
                C9194B4C140E3BC700BE0C3A /* build_linklists.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build_linklists.sh; sourceTree = "<group>"; };
-               C921D3831395B7DD001CE070 /* init_cpu_capabilities.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = init_cpu_capabilities.c; sourceTree = "<group>"; };
-               C921D3841395B7DD001CE070 /* pthread_getspecific.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pthread_getspecific.s; sourceTree = "<group>"; };
-               C921D3851395B7DD001CE070 /* pthread_self.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pthread_self.s; sourceTree = "<group>"; };
-               C921D3861395B7DD001CE070 /* pthread_set_self.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pthread_set_self.s; sourceTree = "<group>"; };
-               C921D3871395B7DD001CE070 /* start_wqthread.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = start_wqthread.s; sourceTree = "<group>"; };
-               C921D3881395B7DD001CE070 /* thread_start.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = thread_start.s; sourceTree = "<group>"; };
                C9257ED0138E1B5000B3107C /* libFreeBSD.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFreeBSD.a; sourceTree = BUILT_PRODUCTS_DIR; };
                C9258105138E2D3100B3107C /* libNetBSD.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNetBSD.a; sourceTree = BUILT_PRODUCTS_DIR; };
                C925D1FB151805C6003D315B /* eos_stubs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = eos_stubs.c; sourceTree = "<group>"; };
                C9B53CB5138D9E9A0028D27C /* ecvt.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = ecvt.3; sourceTree = "<group>"; };
                C9B53CB7138D9E9A0028D27C /* ecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ecvt.c; sourceTree = "<group>"; };
                C9B53CB9138D9E9A0028D27C /* gcvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gcvt.c; sourceTree = "<group>"; };
-               C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "qsort_b-fbsd.c"; sourceTree = "<group>"; };
+               C9B53CBD138D9E9A0028D27C /* qsort_b.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = qsort_b.c; sourceTree = "<group>"; };
                C9B53CBE138D9E9A0028D27C /* strtod_l.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = strtod_l.3; sourceTree = "<group>"; };
                C9B53CBF138D9E9A0028D27C /* strtol_l.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = strtol_l.3; sourceTree = "<group>"; };
                C9B53CC2138D9E9A0028D27C /* asctime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = asctime.c; sourceTree = "<group>"; };
                C9ECE2761950E384008E8672 /* atexit_receipt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atexit_receipt.c; sourceTree = "<group>"; };
                C9FA32F8138E4A5C0089A94B /* utf2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utf2.c; sourceTree = "<group>"; };
                C9FACC591ACDBA54009F33F1 /* Makefile.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; name = Makefile.inc; path = Platforms/appletvos/Makefile.inc; sourceTree = SOURCE_ROOT; };
+               E40EA6C01EAA8F9300B2FA36 /* _strings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _strings.h; sourceTree = "<group>"; };
                E41BEA97178E72E100E348BB /* Libc.order */ = {isa = PBXFileReference; lastKnownFileType = text; path = Libc.order; sourceTree = "<group>"; };
                E4A877A6174D82FB000DBB55 /* alias.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = alias.list; sourceTree = "<group>"; };
                FC2ED60E157D4BE70098EC69 /* inet_ntop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet_ntop.c; sourceTree = "<group>"; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               926F738F1E03E2A3001E049D /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                B122F2A91432B8E600AF95D0 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                4B2C64A015519B0500342BFA /* os */ = {
                        isa = PBXGroup;
                        children = (
+                               926F73991E03E8D6001E049D /* variant_private.h */,
                                2DF67CE7184F9CD000B83A3D /* debug_private.h */,
                                2DF67CDD184F9CBE00B83A3D /* debug_private.c */,
                                4B2C64AB15519C3400342BFA /* assumes.h */,
                        name = os;
                        sourceTree = "<group>";
                };
+               926F73961E03E8C4001E049D /* libdarwin */ = {
+                       isa = PBXGroup;
+                       children = (
+                               9280EA171E59BC8A007A6F58 /* AppleInternalVariant.plist */,
+                               928841341EA7554D001064D1 /* dirstat_collection.c */,
+                               92D763E41EA6F887001467FC /* dirstat_collection.h */,
+                               92D763DC1EA6D9FB001467FC /* dirstat.c */,
+                               92D763E51EA6F887001467FC /* dirstat.h */,
+                               92767C821E0A7E2100AB9C76 /* init.c */,
+                               926F73971E03E8C4001E049D /* variant.c */,
+                       );
+                       path = libdarwin;
+                       sourceTree = "<group>";
+               };
                B122F2AE1432B95B00AF95D0 /* TRE */ = {
                        isa = PBXGroup;
                        children = (
                C9B53595138D9A690028D27C = {
                        isa = PBXGroup;
                        children = (
+                               926F73961E03E8C4001E049D /* libdarwin */,
                                C9B535AE138D9E980028D27C /* APPLE_LICENSE */,
                                C9B535AF138D9E980028D27C /* arm */,
-                               C9B535E2138D9E980028D27C /* arm */,
+                               C9B535E2138D9E980028D27C /* arm64 */,
                                C9B535F5138D9E980028D27C /* compat-43 */,
                                C9B53612138D9E980028D27C /* darwin */,
                                C9B5361D138D9E980028D27C /* db */,
                                C97A721C1517AF53005E1998 /* libc_eOS.a */,
                                3F5120F116C3174300AFB431 /* libFortifySource.a */,
                                C0E345E21C582ECB00E749C2 /* libc.a */,
+                               926F73921E03E2A3001E049D /* libsystem_darwin.dylib */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                        path = string;
                        sourceTree = "<group>";
                };
-               C9B535E2138D9E980028D27C /* arm */ = {
+               C9B535E2138D9E980028D27C /* arm64 */ = {
                        isa = PBXGroup;
                        children = (
                                C9B535EB138D9E980028D27C /* string */,
                        );
-                       path = arm;
+                       path = arm64;
                        sourceTree = "<group>";
                };
                C9B535EB138D9E980028D27C /* string */ = {
                                C9B538A9138D9E990028D27C /* _common.h */,
                                C9B538AA138D9E990028D27C /* _stdio.h */,
                                C9B538AB138D9E990028D27C /* _string.h */,
+                               E40EA6C01EAA8F9300B2FA36 /* _strings.h */,
                        );
                        path = secure;
                        sourceTree = "<group>";
                                C9B53B55138D9E990028D27C /* flags.c */,
                                C9B53B57138D9E990028D27C /* floatio.h */,
                                C9B53B58138D9E990028D27C /* flockfile.3 */,
+                               92888B0F1EA5BE6D00BA923E /* fmemopen.c */,
                                C9B53B5A138D9E990028D27C /* fopen.3 */,
                                C9B53B5C138D9E990028D27C /* fopen.c */,
                                C9B53B5E138D9E990028D27C /* fprintf.c */,
                                C9B53B9C138D9E990028D27C /* makebuf.c */,
                                C9B53B9E138D9E990028D27C /* mktemp.3 */,
                                C9B53BA0138D9E990028D27C /* mktemp.c */,
+                               92888B101EA5BE6D00BA923E /* open_memstream.3 */,
+                               92888B111EA5BE6D00BA923E /* open_memstream.c */,
+                               92888B121EA5BE6D00BA923E /* open_wmemstream.c */,
                                C9B53BA2138D9E990028D27C /* perror.c */,
                                C9B53BA3138D9E990028D27C /* printf-pos.c */,
                                C9B53BA5138D9E990028D27C /* printf.3 */,
                                C9B53CAD138D9E9A0028D27C /* l64a.c */,
                                C9B53CAF138D9E9A0028D27C /* NetBSD */,
                                C9B53CB4138D9E9A0028D27C /* OpenBSD */,
-                               C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */,
+                               C9B53CBD138D9E9A0028D27C /* qsort_b.c */,
                                C9B53CBE138D9E9A0028D27C /* strtod_l.3 */,
                                C9B53CBF138D9E9A0028D27C /* strtol_l.3 */,
                        );
                        isa = PBXGroup;
                        children = (
                                E4A877A6174D82FB000DBB55 /* alias.list */,
+                               C00AC1181E04B7E000286B61 /* legacy_opendir_alias.list */,
                                C9C2A948138DF7DD00287F00 /* libc.xcconfig */,
                                C9766153138ECF0000741512 /* variants.xcconfig */,
                                C9AE91AE1517CDAC00A2626C /* eos.xcconfig */,
                };
 /* End PBXGroup section */
 
+/* Begin PBXHeadersBuildPhase section */
+               926F73901E03E2A3001E049D /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               926F739A1E03E8D6001E049D /* variant_private.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
 /* Begin PBXLegacyTarget section */
                928F25D01BEACED7007B13C7 /* darwintests */ = {
                        isa = PBXLegacyTarget;
                        productReference = 3F5120F116C3174300AFB431 /* libFortifySource.a */;
                        productType = "com.apple.product-type.library.static";
                };
+               926F73911E03E2A3001E049D /* libsystem_darwin.dylib */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 926F73951E03E2A4001E049D /* Build configuration list for PBXNativeTarget "libsystem_darwin.dylib" */;
+                       buildPhases = (
+                               926F738E1E03E2A3001E049D /* Sources */,
+                               926F738F1E03E2A3001E049D /* Frameworks */,
+                               926F73901E03E2A3001E049D /* Headers */,
+                               9280EA241E5A5D6F007A6F58 /* Copy AppleInternalVariant.plist */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = libsystem_darwin.dylib;
+                       productName = libsystem_darwin;
+                       productReference = 926F73921E03E2A3001E049D /* libsystem_darwin.dylib */;
+                       productType = "com.apple.product-type.library.dynamic";
+               };
                B122F0E71432B8E600AF95D0 /* TRE */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = B122F2AA1432B8E600AF95D0 /* Build configuration list for PBXNativeTarget "TRE" */;
                                        925E7FE619E8945900AC7889 = {
                                                CreatedOnToolsVersion = 6.1;
                                        };
+                                       926F73911E03E2A3001E049D = {
+                                               CreatedOnToolsVersion = 8.2;
+                                               ProvisioningStyle = Automatic;
+                                       };
+                                       926F739D1E046E55001E049D = {
+                                               CreatedOnToolsVersion = 8.2;
+                                               ProvisioningStyle = Automatic;
+                                       };
                                        928F25D01BEACED7007B13C7 = {
                                                CreatedOnToolsVersion = 7.1;
                                        };
                                3F51206A16C3174300AFB431 /* FortifySource */,
                                925E7FE619E8945900AC7889 /* Libc_tests */,
                                928F25D01BEACED7007B13C7 /* darwintests */,
+                               926F739D1E046E55001E049D /* Libc_darwin */,
+                               926F73911E03E2A3001E049D /* libsystem_darwin.dylib */,
                        );
                };
 /* End PBXProject section */
                        shellPath = /bin/bash;
                        shellScript = ". \"${SCRIPT_INPUT_FILE_0}\"";
                };
+               9280EA241E5A5D6F007A6F58 /* Copy AppleInternalVariant.plist */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "Copy AppleInternalVariant.plist";
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "set -ex\nINSTALL_PATH=${DSTROOT}/System/Library/CoreServices\n\nif [ \"${PLATFORM_NAME}\" = \"macosx\" ]; then\ninstall -d ${INSTALL_PATH}\ninstall -m 0444 ${SRCROOT}/libdarwin/AppleInternalVariant.plist ${INSTALL_PATH}\nfi";
+                       showEnvVarsInLog = 0;
+               };
                B122F0E81432B8E600AF95D0 /* Generate libc-features.h */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               926F738E1E03E2A3001E049D /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               926F73981E03E8C4001E049D /* variant.c in Sources */,
+                               92D763E01EA6DA3A001467FC /* dirstat.c in Sources */,
+                               92767C841E0A7E2700AB9C76 /* init.c in Sources */,
+                               928841361EA75555001064D1 /* dirstat_collection.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                B122F0E91432B8E600AF95D0 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                                C0E345571C582ECB00E749C2 /* strfmon.c in Sources */,
                                C0E345581C582ECB00E749C2 /* ecvt.c in Sources */,
                                C0E345591C582ECB00E749C2 /* gcvt.c in Sources */,
-                               C0E3455A1C582ECB00E749C2 /* qsort_b-fbsd.c in Sources */,
+                               C0E3455A1C582ECB00E749C2 /* qsort_b.c in Sources */,
                                C0E3455B1C582ECB00E749C2 /* asctime.c in Sources */,
                                C0E3455C1C582ECB00E749C2 /* difftime.c in Sources */,
                                C0E3455D1C582ECB00E749C2 /* ftime.c in Sources */,
                                C0E345C11C582ECB00E749C2 /* (null) in Sources */,
                                C0E345C21C582ECB00E749C2 /* (null) in Sources */,
                                C0E345C31C582ECB00E749C2 /* scandir_b.c in Sources */,
-                               C0E345C41C582ECB00E749C2 /* init_cpu_capabilities.c in Sources */,
-                               C0E345C51C582ECB00E749C2 /* pthread_getspecific.s in Sources */,
-                               C0E345C61C582ECB00E749C2 /* pthread_self.s in Sources */,
-                               C0E345C71C582ECB00E749C2 /* pthread_set_self.s in Sources */,
-                               C0E345C81C582ECB00E749C2 /* start_wqthread.s in Sources */,
-                               C0E345C91C582ECB00E749C2 /* thread_start.s in Sources */,
                                C0E345CA1C582ECB00E749C2 /* strcpy.c in Sources */,
                                C0E345CB1C582ECB00E749C2 /* strlcpy.c in Sources */,
                                C0E345CC1C582ECB00E749C2 /* strncpy.c in Sources */,
                                C9257F93138E1C9700B3107C /* addr2ascii.c in Sources */,
                                C9257F94138E1C9700B3107C /* ascii2addr.c in Sources */,
                                C9257F95138E1C9700B3107C /* inet_addr.c in Sources */,
+                               92888B171EA5BE8000BA923E /* open_memstream.c in Sources */,
                                C9257F96138E1C9700B3107C /* inet_lnaof.c in Sources */,
                                C9257F97138E1C9700B3107C /* inet_makeaddr.c in Sources */,
                                C9257F98138E1C9700B3107C /* inet_net_ntop.c in Sources */,
                                C9258002138E1CC000B3107C /* wprintf.c in Sources */,
                                C9258003138E1CC000B3107C /* wscanf.c in Sources */,
                                C9258004138E1CC000B3107C /* wsetup.c in Sources */,
+                               92888B181EA5BE8600BA923E /* open_wmemstream.c in Sources */,
                                C9258005138E1CC000B3107C /* asctime.c in Sources */,
                                C9258006138E1CC000B3107C /* difftime.c in Sources */,
                                C9258007138E1CC000B3107C /* ftime.c in Sources */,
                                C925804A138E1CD200B3107C /* wcspbrk.c in Sources */,
                                C925804B138E1CD200B3107C /* wcsrchr.c in Sources */,
                                C925804C138E1CD200B3107C /* wcsspn.c in Sources */,
+                               92888B161EA5BE7400BA923E /* fmemopen.c in Sources */,
                                C925804D138E1CD200B3107C /* wcsstr.c in Sources */,
                                C925804E138E1CD200B3107C /* wcstok.c in Sources */,
                                C925804F138E1CD200B3107C /* wcswidth.c in Sources */,
                                C9FA3348138E4D040089A94B /* l64a.c in Sources */,
                                C9FA334A138E4D040089A94B /* ecvt.c in Sources */,
                                C9FA334B138E4D040089A94B /* gcvt.c in Sources */,
-                               C9FA334C138E4D040089A94B /* qsort_b-fbsd.c in Sources */,
+                               C9FA334C138E4D040089A94B /* qsort_b.c in Sources */,
                                C9D94359138EC0C600FB7ACC /* heapsort_b.c in Sources */,
                                C9D9435A138EC0C600FB7ACC /* heapsort_r.c in Sources */,
                                C9421021138F2602004BA536 /* _ldtoa.c in Sources */,
                                C942123913900C8A004BA536 /* strfmon.c in Sources */,
                                C942123A13900C8A004BA536 /* ecvt.c in Sources */,
                                C942123B13900C8A004BA536 /* gcvt.c in Sources */,
-                               C942123C13900C8A004BA536 /* qsort_b-fbsd.c in Sources */,
+                               C942123C13900C8A004BA536 /* qsort_b.c in Sources */,
                                C942123D13900C8A004BA536 /* asctime.c in Sources */,
                                C942123E13900C8A004BA536 /* difftime.c in Sources */,
                                C942123F13900C8A004BA536 /* ftime.c in Sources */,
                                C94212BA13900C8A004BA536 /* unpack.c in Sources */,
                                C94212BB13900C8A004BA536 /* unparse.c in Sources */,
                                C94212C613900C8A004BA536 /* scandir_b.c in Sources */,
-                               C98E2B4C139851B7002A3ABB /* init_cpu_capabilities.c in Sources */,
-                               C98E2B4D139851B7002A3ABB /* pthread_getspecific.s in Sources */,
-                               C98E2B4E139851B7002A3ABB /* pthread_self.s in Sources */,
-                               C98E2B4F139851B7002A3ABB /* pthread_set_self.s in Sources */,
-                               C98E2B50139851B7002A3ABB /* start_wqthread.s in Sources */,
-                               C98E2B51139851B7002A3ABB /* thread_start.s in Sources */,
                                6310518713D4D966004F7BA8 /* strcpy.c in Sources */,
                                6310518C13D4DABD004F7BA8 /* strlcpy.c in Sources */,
                                6310518F13D4DAEA004F7BA8 /* strncpy.c in Sources */,
                                C95B80E4138F3C55004311DA /* strfmon.c in Sources */,
                                C95B80E5138F3C55004311DA /* ecvt.c in Sources */,
                                C95B80E6138F3C55004311DA /* gcvt.c in Sources */,
-                               C95B80E7138F3C55004311DA /* qsort_b-fbsd.c in Sources */,
+                               C95B80E7138F3C55004311DA /* qsort_b.c in Sources */,
                                C95B80E8138F3C55004311DA /* asctime.c in Sources */,
                                C95B80E9138F3C55004311DA /* difftime.c in Sources */,
                                C95B80EA138F3C55004311DA /* ftime.c in Sources */,
                                C95B838F138F52B0004311DA /* strfmon.c in Sources */,
                                C95B8390138F52B0004311DA /* ecvt.c in Sources */,
                                C95B8391138F52B0004311DA /* gcvt.c in Sources */,
-                               C95B8392138F52B0004311DA /* qsort_b-fbsd.c in Sources */,
+                               C95B8392138F52B0004311DA /* qsort_b.c in Sources */,
                                C95B8393138F52B0004311DA /* asctime.c in Sources */,
                                C95B8394138F52B0004311DA /* difftime.c in Sources */,
                                C95B8395138F52B0004311DA /* ftime.c in Sources */,
                                C95B8635138F53DB004311DA /* strfmon.c in Sources */,
                                C95B8636138F53DB004311DA /* ecvt.c in Sources */,
                                C95B8637138F53DB004311DA /* gcvt.c in Sources */,
-                               C95B8638138F53DB004311DA /* qsort_b-fbsd.c in Sources */,
+                               C95B8638138F53DB004311DA /* qsort_b.c in Sources */,
                                C95B8639138F53DB004311DA /* asctime.c in Sources */,
                                C95B863A138F53DB004311DA /* difftime.c in Sources */,
                                C95B863B138F53DB004311DA /* ftime.c in Sources */,
                                C97A71771517AF53005E1998 /* strfmon.c in Sources */,
                                C97A71781517AF53005E1998 /* ecvt.c in Sources */,
                                C97A71791517AF53005E1998 /* gcvt.c in Sources */,
-                               C97A717A1517AF53005E1998 /* qsort_b-fbsd.c in Sources */,
+                               C97A717A1517AF53005E1998 /* qsort_b.c in Sources */,
                                C97A717B1517AF53005E1998 /* asctime.c in Sources */,
                                C97A717C1517AF53005E1998 /* difftime.c in Sources */,
                                C97A717D1517AF53005E1998 /* ftime.c in Sources */,
                                C97A71F91517AF53005E1998 /* (null) in Sources */,
                                C97A71FA1517AF53005E1998 /* (null) in Sources */,
                                C97A71FD1517AF53005E1998 /* scandir_b.c in Sources */,
-                               C97A71FF1517AF53005E1998 /* init_cpu_capabilities.c in Sources */,
-                               C97A72001517AF53005E1998 /* pthread_getspecific.s in Sources */,
-                               C97A72011517AF53005E1998 /* pthread_self.s in Sources */,
-                               C97A72021517AF53005E1998 /* pthread_set_self.s in Sources */,
-                               C97A72031517AF53005E1998 /* start_wqthread.s in Sources */,
-                               C97A72041517AF53005E1998 /* thread_start.s in Sources */,
                                C97A720D1517AF53005E1998 /* strcpy.c in Sources */,
                                C97A720E1517AF53005E1998 /* strlcpy.c in Sources */,
                                C97A720F1517AF53005E1998 /* strncpy.c in Sources */,
                                C9B53E77138DA59F0028D27C /* strcpy.s in Sources */,
                                C9B53E7A138DA59F0028D27C /* strlen.s in Sources */,
                                C9B53E7C138DA59F0028D27C /* strncpy.s in Sources */,
-                               C921D3891395B7DD001CE070 /* init_cpu_capabilities.c in Sources */,
-                               C921D38A1395B7DD001CE070 /* pthread_getspecific.s in Sources */,
-                               C921D38B1395B7DD001CE070 /* pthread_self.s in Sources */,
-                               C921D38C1395B7DD001CE070 /* pthread_set_self.s in Sources */,
-                               C921D38D1395B7DD001CE070 /* start_wqthread.s in Sources */,
-                               C921D38E1395B7DD001CE070 /* thread_start.s in Sources */,
                                63505E3D1548525D00B637D7 /* strnlen.s in Sources */,
                                639D126C15595DDE00D0403A /* strnlen.s in Sources */,
                        );
                                C97660B9138EC61A00741512 /* strfmon.c in Sources */,
                                C97660BA138EC61A00741512 /* ecvt.c in Sources */,
                                C97660BB138EC61A00741512 /* gcvt.c in Sources */,
-                               C97660BC138EC61A00741512 /* qsort_b-fbsd.c in Sources */,
+                               C97660BC138EC61A00741512 /* qsort_b.c in Sources */,
                                C97660BD138EC61A00741512 /* asctime.c in Sources */,
                                C97660BE138EC61A00741512 /* difftime.c in Sources */,
                                C97660BF138EC61A00741512 /* ftime.c in Sources */,
                                C9EB31D4138F6D880075BB52 /* strfmon.c in Sources */,
                                C9EB31D5138F6D880075BB52 /* ecvt.c in Sources */,
                                C9EB31D6138F6D880075BB52 /* gcvt.c in Sources */,
-                               C9EB31D7138F6D880075BB52 /* qsort_b-fbsd.c in Sources */,
+                               C9EB31D7138F6D880075BB52 /* qsort_b.c in Sources */,
                                C9EB31D8138F6D880075BB52 /* asctime.c in Sources */,
                                C9EB31D9138F6D880075BB52 /* difftime.c in Sources */,
                                C9EB31DA138F6D880075BB52 /* ftime.c in Sources */,
                                C9EB347B138F75580075BB52 /* strfmon.c in Sources */,
                                C9EB347C138F75580075BB52 /* ecvt.c in Sources */,
                                C9EB347D138F75580075BB52 /* gcvt.c in Sources */,
-                               C9EB347E138F75580075BB52 /* qsort_b-fbsd.c in Sources */,
+                               C9EB347E138F75580075BB52 /* qsort_b.c in Sources */,
                                C9EB347F138F75580075BB52 /* asctime.c in Sources */,
                                C9EB3480138F75580075BB52 /* difftime.c in Sources */,
                                C9EB3481138F75580075BB52 /* ftime.c in Sources */,
                        target = 3F51206A16C3174300AFB431 /* FortifySource */;
                        targetProxy = 3F51211616C318EB00AFB431 /* PBXContainerItemProxy */;
                };
+               926F73A21E046E69001E049D /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 926F73911E03E2A3001E049D /* libsystem_darwin.dylib */;
+                       targetProxy = 926F73A11E046E69001E049D /* PBXContainerItemProxy */;
+               };
                928F25D51BEAD2AE007B13C7 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 928F25D01BEACED7007B13C7 /* darwintests */;
                        };
                        name = Release;
                };
+               926F73931E03E2A4001E049D /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_ENABLE_CPP_EXCEPTIONS = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(inherited)",
+                                       "_LIBC_NO_FEATURE_VERIFICATION=1",
+                               );
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               LIBRARY_SEARCH_PATHS = /usr/lib/system;
+                               OTHER_LDFLAGS = "$(LIBSYSTEM_DARWIN_LDFLAGS)";
+                               PRIVATE_HEADERS_FOLDER_PATH = "$(DARWIN_PRIVATE_HEADERS_FOLDER_PATH)";
+                               PRODUCT_NAME = darwin;
+                               PUBLIC_HEADERS_FOLDER_PATH = "$(DARWIN_PUBLIC_HEADERS_FOLDER_PATH)";
+                               SKIP_INSTALL = NO;
+                               VERSIONING_SYSTEM = "apple-generic";
+                       };
+                       name = Debug;
+               };
+               926F73941E03E2A4001E049D /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_ENABLE_CPP_EXCEPTIONS = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(inherited)",
+                                       "_LIBC_NO_FEATURE_VERIFICATION=1",
+                               );
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               LIBRARY_SEARCH_PATHS = /usr/lib/system;
+                               OTHER_LDFLAGS = "$(LIBSYSTEM_DARWIN_LDFLAGS)";
+                               PRIVATE_HEADERS_FOLDER_PATH = "$(DARWIN_PRIVATE_HEADERS_FOLDER_PATH)";
+                               PRODUCT_NAME = darwin;
+                               PUBLIC_HEADERS_FOLDER_PATH = "$(DARWIN_PUBLIC_HEADERS_FOLDER_PATH)";
+                               SKIP_INSTALL = NO;
+                               VERSIONING_SYSTEM = "apple-generic";
+                       };
+                       name = Release;
+               };
+               926F739F1E046E56001E049D /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
+               926F73A01E046E56001E049D /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
                928F25D21BEACED7007B13C7 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        buildSettings = {
                                EXCLUDED_SOURCE_FILE_NAMES = "$(BASE_EXCLUDED_SOURCE_FILE_NAMES)";
                                EXECUTABLE_PREFIX = lib;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_OBJC_EXCEPTIONS = YES;
                                GCC_OPTIMIZATION_LEVEL = 0;
                        buildSettings = {
                                EXCLUDED_SOURCE_FILE_NAMES = "$(BASE_EXCLUDED_SOURCE_FILE_NAMES)";
                                EXECUTABLE_PREFIX = lib;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_ENABLE_OBJC_EXCEPTIONS = YES;
                                PRODUCT_NAME = NetBSD;
                        };
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               926F73951E03E2A4001E049D /* Build configuration list for PBXNativeTarget "libsystem_darwin.dylib" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               926F73931E03E2A4001E049D /* Debug */,
+                               926F73941E03E2A4001E049D /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               926F739E1E046E56001E049D /* Build configuration list for PBXAggregateTarget "Libc_darwin" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               926F739F1E046E56001E049D /* Debug */,
+                               926F73A01E046E56001E049D /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                928F25D11BEACED7007B13C7 /* Build configuration list for PBXLegacyTarget "darwintests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
index 7b485b2babda01264f2d2a97649a341c734bfbbf..aacbe5a1418bf7aaf3252e4f77874bd51691d2e0 100644 (file)
 # OSThermalNotification APIs
 FEATURE_THERM_NOTIFICATION_APIS = 1
 
-# Move localtime to /var/db/timezone
-FEATURE_MOVE_LOCALTIME = 1
-
-# Use TZDIR symlink in /var/db
-FEATURE_TZDIR_SYMLINK = 1
-
-.if RC_ProjectName _Sim$
-FEATURE_MOVE_LOCALTIME = 0
-FEATURE_TZDIR_SYMLINK = 0
-.endif
-
 # No pre-1050 variants (should match sys/cdefs.h)
 FEATURE_ONLY_1050_VARIANTS = 1
 
index dcb0cc6b860c266c8b79ea8110c4c23e66538588..ba2fd54be6fa42d452909e349a44bebcfe18d1b6 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Selectable features for Apple Watch
+# Selectable features for bridgeOS
 #
 
 # Legacy *64 APIs
 # OSThermalNotification APIs
 FEATURE_THERM_NOTIFICATION_APIS = 1
 
-# Move localtime to /var/db/timezone
-FEATURE_MOVE_LOCALTIME = 0
-
-# Use TZDIR symlink in /var/db
-FEATURE_TZDIR_SYMLINK = 0
-
 # No pre-1050 variants (should match sys/cdefs.h)
 FEATURE_ONLY_1050_VARIANTS = 1
 
index df326716c7f170bab61e454ef59e5129c7897eea..3ea7c191608be872521bebbe77c9936e61313701 100644 (file)
 # OSThermalNotification APIs
 FEATURE_THERM_NOTIFICATION_APIS = 1
 
-# Move localtime to /var/db/timezone
-FEATURE_MOVE_LOCALTIME = 1
-
-# Use TZDIR symlink in /var/db
-FEATURE_TZDIR_SYMLINK = 1
-
-.if RC_ProjectName _Sim$
-FEATURE_MOVE_LOCALTIME = 0
-FEATURE_TZDIR_SYMLINK = 0
-.endif
-
 # No pre-1050 variants (should match sys/cdefs.h)
 FEATURE_ONLY_1050_VARIANTS = 1
 
index f48843d08d0379d0b8eb43ae23c862fdb6b0f8da..9952af8738ad54fae1210e94dc9829fcbb6d5656 100644 (file)
@@ -17,12 +17,6 @@ FEATURE_LEGACY_UTMP_APIS = 1
 # OSThermalNotification APIs
 FEATURE_THERM_NOTIFICATION_APIS = 1
 
-# Move localtime to /var/db/timezone
-#FEATURE_MOVE_LOCALTIME = 1
-
-# Use TZDIR symlink in /var/db
-#FEATURE_TZDIR_SYMLINK = 1
-
 # No pre-1050 variants (should match sys/cdefs.h)
 #FEATURE_ONLY_1050_VARIANTS = 1
 
index 2253e33b2e5455788dd81f7ad1629043a40b014e..b8c36800d951206bd5cd99c558ee45c843459ca7 100644 (file)
 # OSThermalNotification APIs
 FEATURE_THERM_NOTIFICATION_APIS = 1
 
-# Move localtime to /var/db/timezone
-FEATURE_MOVE_LOCALTIME = 1
-
-# Use TZDIR symlink in /var/db
-FEATURE_TZDIR_SYMLINK = 1
-
-.if RC_ProjectName _Sim$
-FEATURE_MOVE_LOCALTIME = 0
-FEATURE_TZDIR_SYMLINK = 0
-.endif
-
 # No pre-1050 variants (should match sys/cdefs.h)
 FEATURE_ONLY_1050_VARIANTS = 1
 
diff --git a/darwin/init_cpu_capabilities.c b/darwin/init_cpu_capabilities.c
deleted file mode 100644 (file)
index 62d1df2..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * 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@
- */
-
-#define        __APPLE_API_PRIVATE
-#include <machine/cpu_capabilities.h>
-#undef __APPLE_API_PRIVATE
-
-extern int _get_cpu_capabilities(void);
-
-int _cpu_capabilities = 0;
-int _cpu_has_altivec = 0;              // DEPRECATED: use _cpu_capabilities instead
-
-__private_extern__ void
-_init_cpu_capabilities( void )
-{
-}
index 80561898b7cc9f1ab72dc05d8d47f5d5c4f867ef..56800019ca59a524ae3bc8b67b3bb54fe5dd0d8f 100644 (file)
@@ -36,12 +36,12 @@ cvt_statfs_to_statvfs(struct statfs *from, struct statvfs *to)
 {
        to->f_bsize     = from->f_iosize;
        to->f_frsize    = from->f_bsize;
-       to->f_blocks    = from->f_blocks;
-       to->f_bfree     = from->f_bfree;
-       to->f_bavail    = from->f_bavail;
-       to->f_files     = from->f_files;
-       to->f_ffree     = from->f_ffree;
-       to->f_favail    = from->f_ffree;
+       to->f_blocks    = (fsblkcnt_t)from->f_blocks;
+       to->f_bfree     = (fsblkcnt_t)from->f_bfree;
+       to->f_bavail    = (fsblkcnt_t)from->f_bavail;
+       to->f_files     = (fsfilcnt_t)from->f_files;
+       to->f_ffree     = (fsfilcnt_t)from->f_ffree;
+       to->f_favail    = (fsfilcnt_t)from->f_ffree;
        to->f_fsid      = from->f_fsid.val[0];  /* XXX bad if non-root */
        to->f_namemax   = NAME_MAX;             /* XXX should be per FS */
 
index f134d5cfdb22d2eecf8d8bc1d2f330f18738ced3..cdda374daca8316c246de2cd4dd927bee33d496b 100644 (file)
 #define                __wait                          wait
 #define                __waitpid                       waitpid
 
+/*
+ * The _GENERIC_DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry.  This returns the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+  */
 #define        _GENERIC_DIRSIZ(dp) \
     (((unsigned long)&((struct dirent *)0)->d_name + (dp)->d_namlen+1 + 3) & ~3)
 
index fcd5aa3c8d4c48e4aa3e80e922a3a177a746511e..ed38fc5f358d5c4c4116e726de0bdb785551eade 100644 (file)
@@ -70,7 +70,7 @@ union IEEEl2bits {
        (a)[0] = (uint32_t)(u).bits.manl;               \
        (a)[1] = (uint32_t)(u).bits.manh;               \
 } while(0)
-#elif defined(__arm__) 
+#elif defined(__arm__) || defined(__arm64__)
 
 union IEEEl2bits {
     long double     e;
index 4fc09017f6a52236919670b18baeee603f6c5abc..b3417cebbc690ee8ed0bc71bac6b251ae2f482a0 100644 (file)
 #ifndef _SPINLOCK_H_
 #define _SPINLOCK_H_
 #ifdef __APPLE__
-#include <pthread_spinlock.h>
+#include <os/lock.h>
 
-typedef pthread_lock_t spinlock_t;
+typedef os_unfair_lock spinlock_t;
 
-#define        _SPINLOCK_INITIALIZER   LOCK_INITIALIZER
+#define        _SPINLOCK_INITIALIZER   OS_UNFAIR_LOCK_INIT
 
 #define        _SPINLOCK(_lck)                                                 \
     do {                                                               \
-       _DO_SPINLOCK_LOCK(_lck);                                        \
+       os_unfair_lock_lock(_lck);                                      \
     } while (0)
 
 #define _SPINUNLOCK(_lck)                                              \
     do {                                                               \
-       _DO_SPINLOCK_UNLOCK(_lck);                                      \
+       os_unfair_lock_unlock(_lck);                                    \
     } while (0)
 
 #else /* ! __APPLE__ */
index 903ce10ff7d76c470168596719c8c1d6230f6142..6367839caf4e9a7461b8d7cac21cb5c8a7eb7db8 100644 (file)
@@ -46,7 +46,7 @@ char *
 __ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
     char **rve)
 {
-#if defined(__arm__) 
+#if defined(__arm__) || defined(__arm64__)
        /* On arm, double == long double, so short circuit this */
        char * ret = __dtoa((double)*ld, mode, ndigits, decpt, sign, rve);
        if (*decpt == 9999)
index 0c485b4504994798e272b00c4679e4459b1b92c2..4de26058af3b7b6bfc6d2fbf2a92a4a9a52dd9c8 100644 (file)
@@ -189,7 +189,7 @@ hexnan( CONST char **sp, CONST FPI *fpi, ULong *x0)
        else {                  /* long double */
                union IEEEl2bits u;
                u.e = nanl(cp);
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) 
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)
                x0[1] = (ULong)u.bits.manh;
                x0[0] = (ULong)u.bits.manl;
 #else
index f60614a17df9060c6ecc86550aeaa9b23bf7fbad..0f5dd9623010ad0edc15449da0db4297c134c6fc 100644 (file)
 #define IEEE_MC68k
 #endif
 #define Arith_Kind_ASL 1
+#elif defined(__arm64__)
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
 #else
 #error Unsupported architecture
 #endif
index 601fff63aa116837fde5646fd65fcd92d4050268..7c570bae16ad500193e59e787012d33a5afdbab3 100644 (file)
@@ -13,7 +13,7 @@
 #define ldus_QNAN3 0x0
 #define ldus_QNAN4 0x0
 
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) 
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)
 
 #define f_QNAN 0x7fc00000
 #define d_QNAN0 0x0
index d8d55026ace6d9df66c8a9ff7679163dcabe30eb..a6b7f3d80548acb2b45c983a9bdf0855df4ac58f 100644 (file)
@@ -61,8 +61,8 @@ described in
 .Xr random 3 ,
 and
 .Xr rand48 3 .
-They can be called in almost environments, including
-.Xr chroot 2
+They can be called in almost all environments, including
+.Xr chroot 2 ,
 and their use is encouraged over all other standard library functions for
 random numbers.
 .Pp
index e49f56b403fdc2496efa090bcf4b20f6e99676a2..d2368d79ef1821b5f8e62426f5f20e54bfa4ff2f 100644 (file)
@@ -112,7 +112,7 @@ arc4_init(void)
 
        uint8_t entropy[BUFFERSIZE];
        int ret;
-       rng_custom.ecb = ccaes_ecb_encrypt_mode();
+       rng_custom.ctr_info = ccaes_ctr_crypt_mode();
        rng_custom.keylen = 16;
        rng_custom.strictFIPS = 0;
        rng_custom.use_df = 1;
index 10bfe5ece7836c0c46e9638db76e603df51c8fc7..e69e0ec7b379331c15a4cad849590df9385583bd 100644 (file)
@@ -31,7 +31,7 @@
 static char sccsid[] = "@(#)closedir.c 8.1 (Berkeley) 6/10/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/closedir.c,v 1.13 2007/12/03 14:33:50 des Exp $");
+__FBSDID("$FreeBSD$");
 
 #include "namespace.h"
 #include <sys/types.h>
@@ -47,17 +47,13 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/closedir.c,v 1.13 2007/12/03 14:33:50 des E
 /*
  * close a directory.
  */
-int
-closedir(dirp)
-       DIR *dirp;
+static int
+_fdclosedir(DIR *dirp)
 {
        int fd;
 
        if (__isthreaded)
                _pthread_mutex_lock(&dirp->dd_lock);
-#if !__DARWIN_UNIX03
-       _seekdir(dirp, dirp->dd_rewind);        /* free seekdir storage */
-#endif /* __DARWIN_UNIX03 */
        fd = dirp->dd_fd;
        dirp->dd_fd = -1;
        dirp->dd_loc = 0;
@@ -68,5 +64,12 @@ closedir(dirp)
                _pthread_mutex_destroy(&dirp->dd_lock);
        }
        free((void *)dirp);
-       return(_close(fd));
+       return (fd);
+}
+
+int
+closedir(DIR *dirp)
+{
+
+       return (_close(_fdclosedir(dirp)));
 }
index aec34223d4934a4d0e1f0249534c0c907f602666..f763764dd9c1f201572cd7d2ba1097528e1eb59f 100644 (file)
@@ -159,6 +159,12 @@ err_set_file(void *fp)
 void
 err_set_exit(void (*ef)(int))
 {
+#ifdef __BLOCKS__
+       if (_e_err_exit.type == ERR_EXIT_BLOCK) {
+               Block_release(_e_err_exit.block);
+               _e_err_exit.block = NULL;
+       }
+#endif /* __BLOCKS__ */
        _e_err_exit.type = ef ? ERR_EXIT_FUNC : ERR_EXIT_UNDEF;
        _e_err_exit.func = ef;
 }
@@ -167,6 +173,9 @@ err_set_exit(void (*ef)(int))
 void
 err_set_exit_b(void (^ef)(int))
 {
+       if (_e_err_exit.type == ERR_EXIT_BLOCK) {
+               Block_release(_e_err_exit.block);
+       }
        _e_err_exit.type = ef ? ERR_EXIT_BLOCK : ERR_EXIT_UNDEF;
        _e_err_exit.block = Block_copy(ef);
 }
index 17f039ea0d50fb1d00ca7b3ed7e8bedfb093111b..707b8b80ebee1898edafe2bb06eb0aa7ec5362b0 100644 (file)
@@ -26,9 +26,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)getcwd.3   8.2 (Berkeley) 12/11/93
-.\" $FreeBSD: src/lib/libc/gen/getcwd.3,v 1.17 2007/01/09 00:27:53 imp Exp $
+.\" $FreeBSD$
 .\"
-.Dd November 24, 1997
+.Dd April 17, 2010
 .Dt GETCWD 3
 .Os
 .Sh NAME
@@ -60,7 +60,9 @@ If
 .Fa buf
 is
 .Dv NULL ,
-space is allocated as necessary to store the pathname.
+space is allocated as necessary to store the pathname and
+.Fa size
+is ignored.
 This space may later be
 .Xr free 3 Ns 'd .
 .Pp
@@ -108,8 +110,6 @@ The
 function
 will fail if:
 .Bl -tag -width Er
-.It Bq Er EACCES
-Read or search permission was denied for a component of the pathname.
 .It Bq Er EINVAL
 The
 .Fa size
@@ -124,6 +124,16 @@ The
 argument is greater than zero but smaller than the length of the pathname
 plus 1.
 .El
+.Pp
+The
+.Fn getcwd
+function
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Read or search permission was denied for a component of the pathname.
+This is only checked in limited cases, depending on implementation details.
+.El
 .Sh SEE ALSO
 .Xr chdir 2 ,
 .Xr fchdir 2 ,
index ce4efc2fbc6665c5828723caef29823be7d214ed..8f0d988066e41bf492c9ae9d80f1a16eee66fc7b 100644 (file)
@@ -88,7 +88,6 @@ int
 getlogin_r(char *logname, size_t namelen)
 {
        char    *result;
-       int     len;
        int     status;
 
        pthread_mutex_lock(&__logname_mutex);
index 0c8283bdd3880599840b7eb71407195cd908866d..9bf03b4a086e0e491d01731d73959628216ce71c 100644 (file)
 .\"     @(#)getmntinfo.3       8.1 (Berkeley) 6/9/93
 .\" $FreeBSD: src/lib/libc/gen/getmntinfo.3,v 1.13 2007/01/09 00:27:54 imp Exp $
 .\"
-.Dd May 4, 2010
+.Dd April 12, 2017
 .Dt GETMNTINFO 3
 .Os
 .Sh NAME
 .Nm getmntinfo
+.Nm getmntinfo_r_np
 .Nm getmntinfo64
 .Nd get information about mounted file systems
 .Sh SYNOPSIS
@@ -41,6 +42,8 @@
 .In sys/mount.h
 .Ft int
 .Fn getmntinfo "struct statfs **mntbufp" "int flags"
+.Ft int
+.Fn getmntinfo_r_np "struct statfs **mntbufp" "int flags"
 .Sh TRANSITIIONAL SYNOPSIS (NOW DEPRECATED)
 .Ft int
 .br
@@ -62,30 +65,63 @@ for more information on this macro).
 .Pp
 The
 .Fn getmntinfo
-function
-passes its
+and
+.Fn getmntinfo_r_np
+functions
+pass their
 .Fa flags
 argument transparently to
 .Xr getfsstat 2 .
+.Pp
+The
+.Fn getmntinfo
+function maintains ownership of the results buffer it allocates,
+and may overwrite or free this buffer in subsequent calls to
+.Fn getmntinfo .
+For this reason,
+.Fn getmntinfo
+is not thread-safe.
+.Pp
+The
+.Fn getmntinfo_r_np
+function is a thread-safe equivalent of
+.Fn getmntinfo
+that allocates a new results buffer on every call and transfers ownership
+of this buffer to the caller.
+The caller is responsible for freeing this memory with
+.Xr free 3 .
 .Sh RETURN VALUES
 On successful completion,
 .Fn getmntinfo
-returns a count of the number of elements in the array.
+and
+.Fn getmntinfo_r_np
+return a count of the number of elements in the array.
 The pointer to the array is stored into
 .Fa mntbufp .
 .Pp
 If an error occurs, zero is returned and the external variable
 .Va errno
 is set to indicate the error.
-Although the pointer
-.Fa mntbufp
-will be unmodified, any information previously returned by
+The
+.Fn getmntinfo
+function may modify the
+.Fa mbtbufp
+pointer even in the case of an error.
+In this situation, callers should consider any previous information
+returned by
 .Fn getmntinfo
-will be lost.
+to be lost.
+The
+.Fn getmntinfo_r_np
+function will not modify the
+.Fa mntbufp
+pointer in the case of an error.
 .Sh ERRORS
 The
 .Fn getmntinfo
-function
+and
+.Fn getmntinfo_r_np
+functions
 may fail and set errno for any of the errors specified for the library
 routines
 .Xr getfsstat 2
@@ -118,6 +154,9 @@ The
 .Fn getmntinfo
 function first appeared in
 .Bx 4.4 .
+The
+.Fn getmntinfo_r_np
+function first appeared in macOS 10.13.
 .Sh BUGS
 The
 .Fn getmntinfo
index 24b7886c6da7851258b2ed4b8386443fc81832d8..6f4bda78fe5b1d00475769260ea7262a6c890e4a 100644 (file)
@@ -36,33 +36,74 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/getmntinfo.c,v 1.5 2007/01/09 00:27:54 imp
 #include <sys/param.h>
 #include <sys/ucred.h>
 #include <sys/mount.h>
+#include <errno.h>
 #include <stdlib.h>
 
+struct getmntinfo_vars {
+       struct statfs *mntbuf;
+       int mntsize;
+       long bufsize;
+};
+
 /*
  * Return information about mounted filesystems.
  */
-int
-getmntinfo(mntbufp, flags)
-       struct statfs **mntbufp;
-       int flags;
+static int
+getmntinfo_internal(struct getmntinfo_vars *vars, int flags)
 {
-       static struct statfs *mntbuf;
-       static int mntsize;
-       static long bufsize;
 
-       if (mntsize <= 0 && (mntsize = getfsstat(0, 0, MNT_NOWAIT)) < 0)
+       if (vars->mntsize <= 0 &&
+           (vars->mntsize = getfsstat(0, 0, MNT_NOWAIT)) < 0) {
                return (0);
-       if (bufsize > 0 && (mntsize = getfsstat(mntbuf, bufsize, flags)) < 0)
+       }
+       if (vars->bufsize > 0 &&
+           (vars->mntsize =
+            getfsstat(vars->mntbuf, vars->bufsize, flags)) < 0) {
                return (0);
-       while (bufsize <= mntsize * sizeof(struct statfs)) {
-               if (mntbuf)
-                       free(mntbuf);
-               bufsize = (mntsize + 1) * sizeof(struct statfs);
-               if ((mntbuf = (struct statfs *)malloc(bufsize)) == 0)
+       }
+       while (vars->bufsize <= vars->mntsize * sizeof(struct statfs)) {
+               if (vars->mntbuf) {
+                       free(vars->mntbuf);
+               }
+               vars->bufsize = (vars->mntsize + 1) * sizeof(struct statfs);
+               if ((vars->mntbuf =
+                    (struct statfs *)malloc(vars->bufsize)) == 0) {
                        return (0);
-               if ((mntsize = getfsstat(mntbuf, bufsize, flags)) < 0)
+               }
+               if ((vars->mntsize =
+                    getfsstat(vars->mntbuf, vars->bufsize, flags)) < 0) {
                        return (0);
+               }
+       }
+       return (vars->mntsize);
+}
+
+/* Legacy version that keeps the buffer around. */
+int
+getmntinfo(struct statfs **mntbufp, int flags)
+{
+       static struct getmntinfo_vars vars;
+       int rv;
+
+       rv = getmntinfo_internal(&vars, flags);
+       /* Unconditional assignment matches legacy behavior. */
+       *mntbufp = vars.mntbuf;
+       return (rv);
+}
+
+/* Thread-safe version where the caller owns the newly-allocated buffer. */
+int
+getmntinfo_r_np(struct statfs **mntbufp, int flags)
+{
+       struct getmntinfo_vars vars = { 0 };
+       int rv, save_errno;
+
+       if ((rv = getmntinfo_internal(&vars, flags)) != 0) {
+               *mntbufp = vars.mntbuf;
+       } else {
+               save_errno = errno;
+               free(vars.mntbuf);
+               errno = save_errno;
        }
-       *mntbufp = mntbuf;
-       return (mntsize);
+       return (rv);
 }
index 5608c48932306e844c1f4b65dfdef75aaba8a75b..482dfd0b562834078941398d353cc07407a0a860 100644 (file)
@@ -46,8 +46,10 @@ getpeereid(int s, uid_t *euid, gid_t *egid)
        error = getsockopt(s, 0, LOCAL_PEERCRED, &xuc, &xuclen);
        if (error != 0)
                return (error);
-       if (xuc.cr_version != XUCRED_VERSION)
-               return (EINVAL);
+       if (xuc.cr_version != XUCRED_VERSION) {
+               errno = EINVAL;
+               return (-1);
+       }
        *euid = xuc.cr_uid;
        *egid = xuc.cr_gid;
        return (0);
index a71c96b4e79bb31e14bc3eee31f397f0f231495d..192c70c55a6f2d32df6c89160ea3e88ded1a61d6 100644 (file)
@@ -11,7 +11,7 @@
 .\" 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.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. 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.
 .\"
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)glob.3     8.3 (Berkeley) 4/16/94
-.\" $FreeBSD: src/lib/libc/gen/glob.3,v 1.32 2007/01/09 00:27:54 imp Exp $
+.\" $FreeBSD$
 .\"
-.Dd May 20, 2008
+.Dd June 11, 2017
 .Dt GLOB 3
 .Os
 .Sh NAME
 .Nm glob ,
-#ifdef UNIFDEF_BLOCKS
 .Nm glob_b ,
-#endif
 .Nm globfree
 .Nd generate pathnames matching a pattern
 .Sh SYNOPSIS
 .In glob.h
 .Ft int
-.Fo glob
-.Fa "const char *restrict pattern"
-.Fa "int flags"
-.Fa "int (*errfunc)(const char *epath, int errno)"
-.Fa "glob_t *restrict pglob"
-.Fc
-#ifdef UNIFDEF_BLOCKS
+.Fn glob "const char * restrict pattern" "int flags" "int (*errfunc)(const char *epath, int errno)" "glob_t * restrict pglob"
 .Ft int
-.Fo glob_b
-.Fa "const char *restrict pattern"
-.Fa "int flags"
-.Fa "int (^errblk)(const char *epath, int errno)"
-.Fa "glob_t *restrict pglob"
-.Fc
-#endif
+.Fn glob "const char * restrict pattern" "int flags" "int (^errblk)(const char *epath, int errno)" "glob_t * restrict pglob"
 .Ft void
-.Fo globfree
-.Fa "glob_t *pglob"
-.Fc
+.Fn globfree "glob_t *pglob"
 .Sh DESCRIPTION
 The
 .Fn glob
@@ -211,7 +195,7 @@ If
 is set, backslash escaping is disabled.
 .It Dv GLOB_NOSORT
 By default, the pathnames are sorted in ascending
-.Tn ASCII
+collation
 order;
 this flag prevents that sorting (speeding up
 .Fn glob ) .
@@ -339,7 +323,6 @@ is
 or
 .Fa errfunc
 returns zero, the error is ignored.
-#ifdef UNIFDEF_BLOCKS
 .Pp
 The
 .Fn glob_b
@@ -347,30 +330,21 @@ function is like
 .Fn glob
 except that the error callback is a block pointer instead of a function
 pointer.
-#endif
 .Pp
 The
 .Fn globfree
 function frees any space associated with
 .Fa pglob
 from a previous call(s) to
-#ifdef UNIFDEF_BLOCKS
 .Fn glob
 or
 .Fn glob_b .
-#else
-.Fn glob .
-#endif
 .Sh RETURN VALUES
 On successful completion,
 .Fn glob
-#ifdef UNIFDEF_BLOCKS
 and
 .Fn glob_b
 return zero.
-#else
-returns zero.
-#endif
 In addition, the fields of
 .Fa pglob
 contain the values described below:
@@ -379,22 +353,16 @@ contain the values described below:
 contains the total number of matched pathnames so far.
 This includes other matches from previous invocations of
 .Fn glob
-#ifdef UNIFDEF_BLOCKS
 or
 .Fn glob_b
-#endif
 if
 .Dv GLOB_APPEND
 was specified.
 .It Fa gl_matchc
 contains the number of matched pathnames in the current invocation of
-#ifdef UNIFDEF_BLOCKS
 .Fn glob
 or
 .Fn glob_b .
-#else
-.Fn glob .
-#endif
 .It Fa gl_flags
 contains a copy of the
 .Fa flags
@@ -417,10 +385,8 @@ are undefined.
 .Pp
 If
 .Fn glob
-#ifdef UNIFDEF_BLOCKS
 or
 .Fn glob_b
-#endif
 terminates due to an error, it sets errno and returns one of the
 following non-zero constants, which are defined in the include
 file
@@ -429,7 +395,7 @@ file
 .It Dv GLOB_NOSPACE
 An attempt to allocate memory failed, or if
 .Fa errno
-was 0
+was E2BIG,
 .Dv GLOB_LIMIT
 was specified in the flags and
 .Fa pglob\->gl_matchc
@@ -469,13 +435,9 @@ execvp("ls", g.gl_pathv);
 .Sh CAVEATS
 The
 .Fn glob
-#ifdef UNIFDEF_BLOCKS
 and
 .Fn glob_b
 functions
-#else
-function
-#endif
 will not match filenames that begin with a period
 unless this is specifically requested (e.g., by ".*").
 .Sh SEE ALSO
@@ -516,11 +478,9 @@ and
 .Fn globfree
 functions first appeared in
 .Bx 4.4 .
-#ifdef UNIFDEF_BLOCKS
 The
 .Fn glob_b
 function first appeared in Mac OS X 10.6.
-#endif
 .Sh BUGS
 Patterns longer than
 .Dv MAXPATHLEN
@@ -528,13 +488,9 @@ may cause unchecked errors.
 .Pp
 The
 .Fn glob
-#ifdef UNIFDEF_BLOCKS
 and
 .Fn glob_b
 functions
-#else
-function
-#endif
 may fail and set errno for any of the errors specified for the
 library routines
 .Xr stat 2 ,
index e519cc607d8950665e569ba49696c5b60c156673..8daab13a3b59699a30704de6b8c2867a2f889d01 100644 (file)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Guido van Rossum.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -13,7 +18,7 @@
  * 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.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. 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.
  *
@@ -34,7 +39,7 @@
 static char sccsid[] = "@(#)glob.c     8.3 (Berkeley) 10/13/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/glob.c,v 1.28 2010/05/12 17:44:00 gordon Exp $");
+__FBSDID("$FreeBSD$");
 
 #include "xlocale_private.h"
 
@@ -68,7 +73,7 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/glob.c,v 1.28 2010/05/12 17:44:00 gordon Ex
  * 1. Patterns with illegal byte sequences match nothing - even if
  *    GLOB_NOCHECK is specified.
  * 2. Illegal byte sequences in filenames are handled by treating them as
- *    single-byte characters with a value of the first byte of the sequence
+ *    single-byte characters with a values of such bytes of the sequence
  *    cast to wchar_t.
  * 3. State-dependent encodings are not currently supported.
  */
@@ -88,41 +93,43 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/glob.c,v 1.28 2010/05/12 17:44:00 gordon Ex
 #include <string.h>
 #include <unistd.h>
 #include <wchar.h>
+#include <malloc_private.h>
 
 #include "collate.h"
 
-#define GLOB_LIMIT_STRING      65536   /* number of readdirs */
-#define GLOB_LIMIT_STAT                128     /* number of stat system calls */
-#define GLOB_LIMIT_READDIR     16384   /* total buffer size of path strings */
-#define GLOB_LIMIT_PATH                1024    /* number of path elements */
-#define GLOB_LIMIT_BRACE       128     /* Number of brace calls */
+/*
+ * glob(3) expansion limits. Stop the expansion if any of these limits
+ * is reached. This caps the runtime in the face of DoS attacks. See
+ * also CVE-2010-2632
+ */
+#define        GLOB_LIMIT_BRACE        128     /* number of brace calls */
+#define        GLOB_LIMIT_PATH         1024    /* number of path elements */
+#define        GLOB_LIMIT_READDIR      16384   /* number of readdirs */
+#define        GLOB_LIMIT_STAT         128     /* number of stat system calls */
+#define        GLOB_LIMIT_STRING       65536   /* maximum total size for paths */
 
 struct glob_limit {
-       size_t l_string;
-       size_t l_stat;  
-       size_t l_readdir;       
-       size_t l_brace;
+       size_t  l_brace_cnt;
+       size_t  l_path_lim;
+       size_t  l_readdir_cnt;
+       size_t  l_stat_cnt;
+       size_t  l_string_cnt;
 };
 
-#define        DOLLAR          '$'
-#define        DOT             '.'
-#define        EOS             '\0'
-#define        LBRACKET        '['
-#define        NOT             '!'
-#define        QUESTION        '?'
-#define        QUOTE           '\\'
-#define        RANGE           '-'
-#define        RBRACKET        ']'
-#define        SEP             '/'
-#define        STAR            '*'
-#define        TILDE           '~'
-#define        UNDERSCORE      '_'
-#define        LBRACE          '{'
-#define        RBRACE          '}'
-#define        SLASH           '/'
-#define        COMMA           ','
-
-#ifndef DEBUG
+#define        DOT             L'.'
+#define        EOS             L'\0'
+#define        LBRACKET        L'['
+#define        NOT             L'!'
+#define        QUESTION        L'?'
+#define        QUOTE           L'\\'
+#define        RANGE           L'-'
+#define        RBRACKET        L']'
+#define        SEP             L'/'
+#define        STAR            L'*'
+#define        TILDE           L'~'
+#define        LBRACE          L'{'
+#define        RBRACE          L'}'
+#define        COMMA           L','
 
 #define        M_QUOTE         0x8000000000ULL
 #define        M_PROTECT       0x4000000000ULL
@@ -131,27 +138,19 @@ struct glob_limit {
 
 typedef uint_fast64_t Char;
 
-#else
-
-#define        M_QUOTE         0x80
-#define        M_PROTECT       0x40
-#define        M_MASK          0xff
-#define        M_CHAR          0x7f
-
-typedef char Char;
-
-#endif
-
-
 #define        CHAR(c)         ((Char)((c)&M_CHAR))
 #define        META(c)         ((Char)((c)|M_QUOTE))
-#define        M_ALL           META('*')
-#define        M_END           META(']')
-#define        M_NOT           META('!')
-#define        M_ONE           META('?')
-#define        M_RNG           META('-')
-#define        M_SET           META('[')
+#define        UNPROT(c)       ((c) & ~M_PROTECT)
+#define        M_ALL           META(L'*')
+#define        M_END           META(L']')
+#define        M_NOT           META(L'!')
+#define        M_ONE           META(L'?')
+#define        M_RNG           META(L'-')
+#define        M_SET           META(L'[')
 #define        ismeta(c)       (((c)&M_QUOTE) != 0)
+#ifdef DEBUG
+#define        isprot(c)       (((c)&M_PROTECT) != 0)
+#endif
 
 
 #define compare                __gl_compare
@@ -160,27 +159,37 @@ typedef char Char;
 #define globextend     __gl_globextend
 #define globtilde      __gl_globtilde
 #define match          __gl_match
+
 __private_extern__ int  compare(const void *, const void *);
 __private_extern__ int  g_Ctoc(const Char *, char *, size_t, locale_t);
-__private_extern__ const Char *g_strchr(const Char *, wchar_t);
-__private_extern__ int  globextend(const Char *, glob_t *, struct glob_limit *, locale_t);
-__private_extern__ const Char *        
-                globtilde(const Char *, Char *, size_t, glob_t *);
-__private_extern__ int  match(Char *, Char *, Char *, locale_t);
-
-
 static int      g_lstat(Char *, struct stat *, glob_t *, locale_t);
 static DIR     *g_opendir(Char *, glob_t *, locale_t);
+__private_extern__ const Char *g_strchr(const Char *, wchar_t);
 #ifdef notdef
 static Char    *g_strcat(Char *, const Char *);
 #endif
 static int      g_stat(Char *, struct stat *, glob_t *, locale_t);
-static int      glob0(const Char *, glob_t *, struct glob_limit *, locale_t);
+static int      glob0(const Char *, glob_t *, struct glob_limit *,
+               const char *,locale_t);
 static int      glob1(Char *, glob_t *, struct glob_limit *, locale_t);
-static int      glob2(Char *, Char *, Char *, Char *, glob_t *, struct glob_limit *, locale_t);
-static int      glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, struct glob_limit *, locale_t);
+static int      glob2(Char *, Char *, Char *, Char *, glob_t *,
+               struct glob_limit *, locale_t);
+static int      glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,
+               struct glob_limit *, locale_t);
+__private_extern__ int  globextend(const Char *, glob_t *, struct glob_limit *,
+               const char *, locale_t);
+__private_extern__ const Char *        globtilde(const Char *, Char *, size_t, glob_t *,
+               locale_t);
+static int      globexp0(const Char *, glob_t *, struct glob_limit *,
+    const char *, locale_t);
 static int      globexp1(const Char *, glob_t *, struct glob_limit *, locale_t);
-static int      globexp2(const Char *, const Char *, glob_t *, int *, struct glob_limit *, locale_t);
+static int      globexp2(const Char *, const Char *, glob_t *,
+    struct glob_limit *, locale_t);
+static int      globfinal(glob_t *, struct glob_limit *, size_t,
+    const char *, locale_t);
+__private_extern__ int  match(Char *, Char *, Char *, locale_t);
+static int      err_nomatch(glob_t *, struct glob_limit *, const char *, locale_t loc);
+static int      err_aborted(glob_t *, int, char *);
 #ifdef DEBUG
 static void     qprintf(const char *, Char *);
 #endif
@@ -188,12 +197,13 @@ static void        qprintf(const char *, Char *);
 static int
 __glob(const char *pattern, glob_t *pglob)
 {
+       struct glob_limit limit = { 0, 0, 0, 0, 0 };
        const char *patnext;
-       struct glob_limit limit = { 0, 0, 0, 0 };
        Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
        mbstate_t mbs;
        wchar_t wc;
        size_t clen;
+       int too_long;
        locale_t loc = __current_locale();
        int mb_cur_max = MB_CUR_MAX_L(loc);
 
@@ -204,18 +214,26 @@ __glob(const char *pattern, glob_t *pglob)
                if (!(pglob->gl_flags & GLOB_DOOFFS))
                        pglob->gl_offs = 0;
        }
+       if (pglob->gl_flags & GLOB_LIMIT) {
+               limit.l_path_lim = pglob->gl_matchc;
+               if (limit.l_path_lim == 0)
+                       limit.l_path_lim = GLOB_LIMIT_PATH;
+       }
        pglob->gl_matchc = 0;
 
        bufnext = patbuf;
        bufend = bufnext + MAXPATHLEN - 1;
+       too_long = 1;
        if (pglob->gl_flags & GLOB_NOESCAPE) {
                memset(&mbs, 0, sizeof(mbs));
                while (bufend - bufnext >= mb_cur_max) {
                        clen = mbrtowc_l(&wc, patnext, MB_LEN_MAX, &mbs, loc);
                        if (clen == (size_t)-1 || clen == (size_t)-2)
-                               return (GLOB_NOMATCH);
-                       else if (clen == 0)
+                               return (err_nomatch(pglob, &limit, pattern, loc));
+                       else if (clen == 0) {
+                               too_long = 0;
                                break;
+                       }
                        *bufnext++ = wc;
                        patnext += clen;
                }
@@ -223,9 +241,9 @@ __glob(const char *pattern, glob_t *pglob)
                /* Protect the quoted characters. */
                memset(&mbs, 0, sizeof(mbs));
                while (bufend - bufnext >= mb_cur_max) {
-                       if (*patnext == QUOTE) {
-                               if (*++patnext == EOS) {
-                                       *bufnext++ = QUOTE | M_PROTECT;
+                       if (*patnext == '\\') {
+                               if (*++patnext == '\0') {
+                                       *bufnext++ = QUOTE;
                                        continue;
                                }
                                prot = M_PROTECT;
@@ -233,19 +251,23 @@ __glob(const char *pattern, glob_t *pglob)
                                prot = 0;
                        clen = mbrtowc_l(&wc, patnext, MB_LEN_MAX, &mbs, loc);
                        if (clen == (size_t)-1 || clen == (size_t)-2)
-                               return (GLOB_NOMATCH);
-                       else if (clen == 0)
+                               return (err_nomatch(pglob, &limit, pattern, loc));
+                       else if (clen == 0) {
+                               too_long = 0;
                                break;
+                       }
                        *bufnext++ = wc | prot;
                        patnext += clen;
                }
        }
+       if (too_long)
+               return (err_nomatch(pglob, &limit, pattern, loc));
        *bufnext = EOS;
 
        if (pglob->gl_flags & GLOB_BRACE)
-           return globexp1(patbuf, pglob, &limit, loc);
+           return globexp0(patbuf, pglob, &limit, pattern, loc);
        else
-           return glob0(patbuf, pglob, &limit, loc);
+           return glob0(patbuf, pglob, &limit, pattern, loc);
 }
 
 int
@@ -271,6 +293,30 @@ glob_b(const char *pattern, int flags, int (^errblk)(const char *, int), glob_t
 }
 #endif /* __BLOCKS__ */
 
+static int
+globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+    const char *origpat, locale_t loc) {
+       int rv;
+       size_t oldpathc;
+
+       /* Protect a single {}, for find(1), like csh */
+       if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) {
+               if ((pglob->gl_flags & GLOB_LIMIT) &&
+                   limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+                       errno = E2BIG;
+                       return (GLOB_NOSPACE);
+               }
+               return (glob0(pattern, pglob, limit, origpat, loc));
+       }
+
+       oldpathc = pglob->gl_pathc;
+
+       if ((rv = globexp1(pattern, pglob, limit, loc)) != 0)
+               return rv;
+
+       return (globfinal(pglob, limit, oldpathc, origpat, loc));
+}
+
 /*
  * Expand recursively a glob {} pattern. When there is no more expansion
  * invoke the standard globbing routine to glob the rest of the magic
@@ -279,24 +325,18 @@ glob_b(const char *pattern, int flags, int (^errblk)(const char *, int), glob_t
 static int
 globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit, locale_t loc)
 {
-       const Char* ptr = pattern;
-       int rv;
+       const Char* ptr;
 
-       if ((pglob->gl_flags & GLOB_LIMIT) &&
-           limit->l_brace++ >= GLOB_LIMIT_BRACE) {
-               errno = 0;
-               return GLOB_NOSPACE;
+       if ((ptr = g_strchr(pattern, LBRACE)) != NULL) {
+               if ((pglob->gl_flags & GLOB_LIMIT) &&
+                   limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+                       errno = E2BIG;
+                       return (GLOB_NOSPACE);
+               }
+               return (globexp2(ptr, pattern, pglob, limit, loc));
        }
 
-       /* Protect a single {}, for find(1), like csh */
-       if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
-               return glob0(pattern, pglob, limit, loc);
-
-       while ((ptr = g_strchr(ptr, LBRACE)) != NULL)
-               if (!globexp2(ptr, pattern, pglob, &rv, limit, loc))
-                       return rv;
-
-       return glob0(pattern, pglob, limit, loc);
+       return (glob0(pattern, pglob, limit, NULL, loc));
 }
 
 
@@ -306,9 +346,10 @@ globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit, locale_t
  * If it fails then it tries to glob the rest of the pattern and returns.
  */
 static int
-globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, struct glob_limit *limit, locale_t loc)
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
+               struct glob_limit *limit, locale_t loc)
 {
-       int     i;
+       int     i, rv;
        Char   *lm, *ls;
        const Char *pe, *pm, *pm1, *pl;
        Char    patbuf[MAXPATHLEN];
@@ -320,7 +361,7 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, struct gl
        ls = lm;
 
        /* Find the balanced brace */
-       for (i = 0, pe = ++ptr; *pe; pe++)
+       for (i = 0, pe = ++ptr; *pe != EOS; pe++)
                if (*pe == LBRACKET) {
                        /* Ignore everything between [] */
                        for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
@@ -342,10 +383,8 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, struct gl
                }
 
        /* Non matching braces; just glob the pattern */
-       if (i != 0 || *pe == EOS) {
-               *rv = glob0(patbuf, pglob, limit, loc);
-               return 0;
-       }
+       if (i != 0 || *pe == EOS)
+               return (glob0(pattern, pglob, limit, NULL, loc));
 
        for (i = 0, pl = pm = ptr; pm <= pe; pm++)
                switch (*pm) {
@@ -390,7 +429,9 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, struct gl
 #ifdef DEBUG
                                qprintf("globexp2:", patbuf);
 #endif
-                               *rv = globexp1(patbuf, pglob, limit, loc);
+                               rv = globexp1(patbuf, pglob, limit, loc);
+                               if (rv)
+                                       return (rv);
 
                                /* move after the comma, to the next string */
                                pl = pm + 1;
@@ -400,8 +441,7 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, struct gl
                default:
                        break;
                }
-       *rv = 0;
-       return 0;
+       return (0);
 }
 
 
@@ -411,27 +451,37 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, struct gl
  * expand tilde from the passwd file.
  */
 __private_extern__ const Char *
-globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
+globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob, locale_t loc)
 {
        struct passwd *pwd;
-       char *h;
+       char *h, *sc;
        const Char *p;
        Char *b, *eb;
+       wchar_t wc;
+       wchar_t wbuf[MAXPATHLEN];
+       wchar_t *wbufend, *dc;
+       size_t clen;
+       mbstate_t mbs;
+       int too_long;
 
        if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
-               return pattern;
+               return (pattern);
 
        /* 
         * Copy up to the end of the string or / 
         */
        eb = &patbuf[patbuf_len - 1];
-       for (p = pattern + 1, h = (char *) patbuf;
-           h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
+       for (p = pattern + 1, b = patbuf;
+           b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++)
                continue;
 
-       *h = EOS;
+       if (*p != EOS && UNPROT(*p) != SEP)
+               return (NULL);
+
+       *b = EOS;
+       h = NULL;
 
-       if (((char *) patbuf)[0] == EOS) {
+       if (patbuf[0] == EOS) {
                /*
                 * handle a plain ~ or ~/ by expanding $HOME first (iff
                 * we're not running setuid or setgid) and then trying
@@ -444,29 +494,65 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
                            (pwd = getpwuid(getuid())) != NULL)
                                h = pwd->pw_dir;
                        else
-                               return pattern;
+                               return (pattern);
                }
        }
        else {
                /*
                 * Expand a ~user
                 */
-               if ((pwd = getpwnam((char*) patbuf)) == NULL)
-                       return pattern;
+               if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf), loc))
+                       return (NULL);
+               if ((pwd = getpwnam((char *)wbuf)) == NULL)
+                       return (pattern);
                else
                        h = pwd->pw_dir;
        }
 
        /* Copy the home directory */
-       for (b = patbuf; b < eb && *h; *b++ = *h++)
+       dc = wbuf;
+       sc = h;
+       wbufend = wbuf + MAXPATHLEN - 1;
+       too_long = 1;
+       memset(&mbs, 0, sizeof(mbs));
+       while (dc <= wbufend) {
+               clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
+               if (clen == (size_t)-1 || clen == (size_t)-2) {
+                       /* XXX See initial comment #2. */
+                       wc = (unsigned char)*sc;
+                       clen = 1;
+                       memset(&mbs, 0, sizeof(mbs));
+               }
+               if ((*dc++ = wc) == EOS) {
+                       too_long = 0;
+                       break;
+               }
+               sc += clen;
+       }
+       if (too_long)
+               return (NULL);
+
+       dc = wbuf;
+       for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT)
                continue;
+       if (*dc != EOS)
+               return (NULL);
 
        /* Append the rest of the pattern */
-       while (b < eb && (*b++ = *p++) != EOS)
-               continue;
-       *b = EOS;
+       if (*p != EOS) {
+               too_long = 1;
+               while (b <= eb) {
+                       if ((*b++ = *p++) == EOS) {
+                               too_long = 0;
+                               break;
+                       }
+               }
+               if (too_long)
+                       return (NULL);
+       } else
+               *b = EOS;
 
-       return patbuf;
+       return (patbuf);
 }
 #endif /* BUILDING_VARIANT */
 
@@ -478,23 +564,24 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
  * if things went well, nonzero if errors occurred.
  */
 static int
-glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, locale_t loc)
+glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+    const char *origpat, locale_t loc)
 {
        const Char *qpatnext;
        int err;
        size_t oldpathc;
        Char *bufnext, c, patbuf[MAXPATHLEN];
 
-       qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
+       qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob, loc);
+       if (qpatnext == NULL) {
+               errno = E2BIG;
+               return (GLOB_NOSPACE);
+       }
        oldpathc = pglob->gl_pathc;
        bufnext = patbuf;
 
        /* We don't need to check for buffer overflow any more. */
        while ((c = *qpatnext++) != EOS) {
-               if (c & M_PROTECT) {
-                       *bufnext++ = CHAR(c);
-                       continue;
-               } /* else */
                switch (c) {
                case LBRACKET:
                        c = *qpatnext;
@@ -530,7 +617,8 @@ glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, locale_t loc
                case STAR:
                        pglob->gl_flags |= GLOB_MAGCHAR;
                        /* collapse adjacent stars to one,
-                        * to avoid exponential behavior
+                        * to ensure "**" at the end continues to match the
+                        * empty string
                         */
                        if (bufnext == patbuf || bufnext[-1] != M_ALL)
                            *bufnext++ = M_ALL;
@@ -548,24 +636,23 @@ glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, locale_t loc
        if ((err = glob1(patbuf, pglob, limit, loc)) != 0)
                return(err);
 
-       /*
-        * If there was no match we are going to append the pattern
-        * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
-        * and the pattern did not contain any magic characters
-        * GLOB_NOMAGIC is there just for compatibility with csh.
-        */
-       if (pglob->gl_pathc == oldpathc) {
-               if (((pglob->gl_flags & GLOB_NOCHECK) ||
-                   ((pglob->gl_flags & GLOB_NOMAGIC) &&
-                       !(pglob->gl_flags & GLOB_MAGCHAR))))
-                       return(globextend(pattern, pglob, limit, loc));
-               else
-                       return(GLOB_NOMATCH);
-       }
+       if (origpat != NULL)
+               return (globfinal(pglob, limit, oldpathc, origpat, loc));
+
+       return (0);
+}
+
+static int
+globfinal(glob_t *pglob, struct glob_limit *limit, size_t oldpathc,
+    const char *origpat, locale_t loc) {
+       if (pglob->gl_pathc == oldpathc)
+               return (err_nomatch(pglob, limit, origpat, loc));
+
        if (!(pglob->gl_flags & GLOB_NOSORT))
                qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
                    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
-       return(0);
+
+       return (0);
 }
 
 #ifndef BUILDING_VARIANT
@@ -583,8 +670,8 @@ glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit, locale_t loc)
 
        /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
        if (*pattern == EOS)
-               return(0);
-       return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
+               return (0);
+       return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
            pattern, pglob, limit, loc));
 }
 
@@ -609,51 +696,56 @@ glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
                if (*pattern == EOS) {          /* End of pattern? */
                        *pathend = EOS;
                        if (g_lstat(pathbuf, &sb, pglob, loc))
-                               return(0);
+                               return (0);
 
                        if ((pglob->gl_flags & GLOB_LIMIT) &&
-                           limit->l_stat++ >= GLOB_LIMIT_STAT) {
-                               errno = 0;
-                               *pathend++ = SEP;
-                               *pathend = EOS;
-                               return GLOB_NOSPACE;
+                           limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) {
+                               errno = E2BIG;
+                               return (GLOB_NOSPACE);
                        }
-                       if (((pglob->gl_flags & GLOB_MARK) &&
-                           pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
-                           || (S_ISLNK(sb.st_mode) &&
-                           (g_stat(pathbuf, &sb, pglob, loc) == 0) &&
-                           S_ISDIR(sb.st_mode)))) {
-                               if (pathend + 1 > pathend_last)
-                                       return (GLOB_ABORTED);
+                       if ((pglob->gl_flags & GLOB_MARK) &&
+                                       UNPROT(pathend[-1]) != SEP &&
+                                       (S_ISDIR(sb.st_mode) ||
+                                       (S_ISLNK(sb.st_mode) &&
+                                       g_stat(pathbuf, &sb, pglob, loc) == 0 &&
+                                       S_ISDIR(sb.st_mode)))) {
+                               if (pathend + 1 > pathend_last) {
+                                       errno = E2BIG;
+                                       return (GLOB_NOSPACE);
+                               }
                                *pathend++ = SEP;
                                *pathend = EOS;
                        }
                        ++pglob->gl_matchc;
-                       return(globextend(pathbuf, pglob, limit, loc));
+                       return (globextend(pathbuf, pglob, limit, NULL, loc));
                }
 
                /* Find end of next segment, copy tentatively to pathend. */
                q = pathend;
                p = pattern;
-               while (*p != EOS && *p != SEP) {
+               while (*p != EOS && UNPROT(*p) != SEP) {
                        if (ismeta(*p))
                                anymeta = 1;
-                       if (q + 1 > pathend_last)
-                               return (GLOB_ABORTED);
+                       if (q + 1 > pathend_last) {
+                               errno = E2BIG;
+                               return (GLOB_NOSPACE);
+                       }
                        *q++ = *p++;
                }
 
                if (!anymeta) {         /* No expansion, do next segment. */
                        pathend = q;
                        pattern = p;
-                       while (*pattern == SEP) {
-                               if (pathend + 1 > pathend_last)
-                                       return (GLOB_ABORTED);
+                       while (UNPROT(*pattern) == SEP) {
+                               if (pathend + 1 > pathend_last) {
+                                       errno = E2BIG;
+                                       return (GLOB_NOSPACE);
+                               }
                                *pathend++ = *pattern++;
                        }
                } else                  /* Need expansion, recurse. */
-                       return(glob3(pathbuf, pathend, pathend_last, pattern, p,
-                           pglob, limit, loc));
+                       return(glob3(pathbuf, pathend, pathend_last, pattern,
+                                       p, pglob, limit, loc));
        }
        /* NOTREACHED */
 }
@@ -665,8 +757,8 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
 {
        struct dirent *dp;
        DIR *dirp;
-       int err;
-       char buf[MAXPATHLEN];
+       int err, too_long, saverrno, saverrno2;
+       char buf[MAXPATHLEN + MB_LEN_MAX - 1];
 
        /*
         * The readdirfunc declaration can't be prototyped, because it is
@@ -676,38 +768,40 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
         */
        struct dirent *(*readdirfunc)();
 
-       if (pathend > pathend_last)
-               return (GLOB_ABORTED);
+       if (pathend > pathend_last) {
+               errno = E2BIG;
+               return (GLOB_NOSPACE);
+       }
        *pathend = EOS;
+       if ((pglob->gl_errfunc != NULL || pglob->gl_errblk != NULL) &&
+           g_Ctoc(pathbuf, buf, sizeof(buf), loc)) {
+               errno = E2BIG;
+               return (GLOB_NOSPACE);
+       }
+
+       saverrno = errno;
        errno = 0;
 
        if ((dirp = g_opendir(pathbuf, pglob, loc)) == NULL) {
-               /* TODO: don't call for ENOENT or ENOTDIR? */
-               if (pglob->gl_errfunc) {
-                       if (g_Ctoc(pathbuf, buf, sizeof(buf), loc))
-                               return (GLOB_ABORTED);
-#ifdef __BLOCKS__
-                       if (pglob->gl_flags & _GLOB_ERR_BLOCK) {
-                               if (pglob->gl_errblk(buf, errno))
-                                       return (GLOB_ABORTED);
-                       } else
-#endif /* __BLOCKS__ */
-                       if (pglob->gl_errfunc(buf, errno))
-                               return (GLOB_ABORTED);
-               }
-               if (pglob->gl_flags & GLOB_ERR)
-                       return (GLOB_ABORTED);
-               return(0);
+               if (errno == ENOENT || errno == ENOTDIR)
+                       return (0);
+
+               err = err_aborted(pglob, errno, buf);
+               if (errno == 0)
+                       errno = saverrno;
+               return (err);
        }
 
        err = 0;
 
-       /* Search directory for matching names. */
        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
                readdirfunc = pglob->gl_readdir;
        else
                readdirfunc = readdir;
-       while ((dp = (*readdirfunc)(dirp))) {
+
+       errno = 0;
+       /* Search directory for matching names. */
+       while ((dp = (*readdirfunc)(dirp)) != NULL) {
                char *sc;
                Char *dc;
                wchar_t wc;
@@ -715,51 +809,77 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
                mbstate_t mbs;
 
                if ((pglob->gl_flags & GLOB_LIMIT) &&
-                   limit->l_readdir++ >= GLOB_LIMIT_READDIR) {
-                       errno = 0;
-                       *pathend++ = SEP;
-                       *pathend = EOS;
-                       return GLOB_NOSPACE;
+                   limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) {
+                       errno = E2BIG;
+                       err = GLOB_NOSPACE;
+                       break;
                }
 
                /* Initial DOT must be matched literally. */
-               if (dp->d_name[0] == DOT && *pattern != DOT)
+               if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) {
+                       errno = 0;
                        continue;
+               }
                memset(&mbs, 0, sizeof(mbs));
                dc = pathend;
                sc = dp->d_name;
-               while (dc < pathend_last) {
+               too_long = 1;
+               while (dc <= pathend_last) {
                        clen = mbrtowc_l(&wc, sc, MB_LEN_MAX, &mbs, loc);
                        if (clen == (size_t)-1 || clen == (size_t)-2) {
-                               wc = *sc;
+                               /* XXX See initial comment #2. */
+                               wc = (unsigned char)*sc;
                                clen = 1;
                                memset(&mbs, 0, sizeof(mbs));
                        }
-                       if ((*dc++ = wc) == EOS)
+                       if ((*dc++ = wc) == EOS) {
+                               too_long = 0;
                                break;
+                       }
                        sc += clen;
                }
-               if (!match(pathend, pattern, restpattern, loc)) {
+               if (too_long && (err = err_aborted(pglob, ENAMETOOLONG,
+                   buf))) {
+                       errno = ENAMETOOLONG;
+                       break;
+               }
+               if (too_long || !match(pathend, pattern, restpattern, loc)) {
                        *pathend = EOS;
+                       errno = 0;
                        continue;
                }
+               if (errno == 0)
+                       errno = saverrno;
                err = glob2(pathbuf, --dc, pathend_last, restpattern,
                    pglob, limit, loc);
                if (err)
                        break;
+               errno = 0;
        }
 
+       saverrno2 = errno;
        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
                (*pglob->gl_closedir)(dirp);
        else
                closedir(dirp);
-       return(err);
+       errno = saverrno2;
+
+       if (err)
+               return (err);
+
+       if (dp == NULL && errno != 0 &&
+           (err = err_aborted(pglob, errno, buf)))
+               return (err);
+
+       if (errno == 0)
+               errno = saverrno;
+       return (0);
 }
 
 
 #ifndef BUILDING_VARIANT
 /*
- * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
+ * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
  * add the new item, and update gl_pathc.
  *
  * This assumes the BSD realloc, which only copies the block when its size
@@ -773,28 +893,26 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
  *     gl_pathv points to (gl_offs + gl_pathc + 1) items.
  */
 __private_extern__ int
-globextend(const Char *path, glob_t *pglob, struct glob_limit *limit, locale_t loc)
+globextend(const Char *path, glob_t *pglob, struct glob_limit *limit,
+               const char *origpat, locale_t loc)
 {
        char **pathv;
-       size_t i, newsize, len;
+       size_t i, newn, len;
        char *copy;
        const Char *p;
 
-       newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
        if ((pglob->gl_flags & GLOB_LIMIT) &&
-           newsize > GLOB_LIMIT_PATH * sizeof(*pathv))
-               goto nospace;
-       pathv = pglob->gl_pathv ?
-                   realloc((char *)pglob->gl_pathv, newsize) :
-                   malloc(newsize);
-       if (pathv == NULL) {
-               if (pglob->gl_pathv) {
-                       free(pglob->gl_pathv);
-                       pglob->gl_pathv = NULL;
-               }
-               return(GLOB_NOSPACE);
+           pglob->gl_matchc > limit->l_path_lim) {
+               errno = E2BIG;
+               return (GLOB_NOSPACE);
        }
 
+       newn = 2 + pglob->gl_pathc + pglob->gl_offs;
+       /* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */
+       pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv));
+       if (pathv == NULL)
+               return (GLOB_NOSPACE);
+
        if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
                /* first time around -- clear initial gl_offs items */
                pathv += pglob->gl_offs;
@@ -803,81 +921,100 @@ globextend(const Char *path, glob_t *pglob, struct glob_limit *limit, locale_t l
        }
        pglob->gl_pathv = pathv;
 
-       for (p = path; *p++;)
-               continue;
-       len = MB_CUR_MAX_L(loc) * (size_t)(p - path);   /* XXX overallocation */
-       limit->l_string += len;
-       if ((copy = malloc(len)) != NULL) {
-               if (g_Ctoc(path, copy, len, loc)) {
+       if (origpat != NULL)
+               copy = strdup(origpat);
+       else {
+               for (p = path; *p++ != EOS;)
+                       continue;
+               len = MB_CUR_MAX_L(loc) * (size_t)(p - path); /* XXX overallocation */
+               if ((copy = malloc(len)) != NULL) {
+                       if (g_Ctoc(path, copy, len, loc)) {
+                               free(copy);
+                               errno = E2BIG;
+                               return (GLOB_NOSPACE);
+                       }
+               }
+       }
+       if (copy != NULL) {
+               limit->l_string_cnt += strlen(copy) + 1;
+               if ((pglob->gl_flags & GLOB_LIMIT) &&
+                   limit->l_string_cnt >= GLOB_LIMIT_STRING) {
                        free(copy);
+                       errno = E2BIG;
                        return (GLOB_NOSPACE);
                }
                pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
        }
        pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
-
-       if ((pglob->gl_flags & GLOB_LIMIT) &&
-           (newsize + limit->l_string) >= GLOB_LIMIT_STRING)
-               goto nospace;
-
-       return(copy == NULL ? GLOB_NOSPACE : 0);
-nospace:
-       errno = 0;
-       return GLOB_NOSPACE;
+       return (copy == NULL ? GLOB_NOSPACE : 0);
 }
 
 /*
- * pattern matching function for filenames.  Each occurrence of the *
- * pattern causes a recursion level.
+ * pattern matching function for filenames.
  */
 __private_extern__ int
 match(Char *name, Char *pat, Char *patend, locale_t loc)
 {
        int ok, negate_range;
-       Char c, k;
-
-       while (pat < patend) {
-               c = *pat++;
-               switch (c & M_MASK) {
-               case M_ALL:
-                       if (pat == patend)
-                               return(1);
-                       do
-                           if (match(name, pat, patend, loc))
-                                   return(1);
-                       while (*name++ != EOS);
-                       return(0);
-               case M_ONE:
-                       if (*name++ == EOS)
-                               return(0);
-                       break;
-               case M_SET:
-                       ok = 0;
-                       if ((k = *name++) == EOS)
-                               return(0);
-                       if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
-                               ++pat;
-                       while (((c = *pat++) & M_MASK) != M_END)
-                               if ((*pat & M_MASK) == M_RNG) {
-                                       if (loc->__collate_load_error ?
-                                           CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
-                                              __collate_range_cmp(CHAR(c), CHAR(k), loc) <= 0
-                                           && __collate_range_cmp(CHAR(k), CHAR(pat[1]), loc) <= 0
-                                          )
+       Char c, k, *nextp, *nextn;
+
+       nextn = NULL;
+       nextp = NULL;
+
+       while (1) {
+               while (pat < patend) {
+                       c = *pat++;
+                       switch (c & M_MASK) {
+                       case M_ALL:
+                               if (pat == patend)
+                                       return (1);
+                               if (*name == EOS)
+                                       return (0);
+                               nextn = name + 1;
+                               nextp = pat - 1;
+                               break;
+                       case M_ONE:
+                               if (*name++ == EOS)
+                                       goto fail;
+                               break;
+                       case M_SET:
+                               ok = 0;
+                               if ((k = *name++) == EOS)
+                                       goto fail;
+                               negate_range = ((*pat & M_MASK) == M_NOT);
+                               if (negate_range != 0)
+                                       ++pat;
+                               while (((c = *pat++) & M_MASK) != M_END)
+                                       if ((*pat & M_MASK) == M_RNG) {
+                                               if (loc->__collate_load_error ?
+                                                       CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
+                                                          __collate_range_cmp(CHAR(c), CHAR(k), loc) <= 0
+                                                       && __collate_range_cmp(CHAR(k), CHAR(pat[1]), loc) <= 0
+                                                  ) {
+                                                       ok = 1;
+                                               }
+                                               pat += 2;
+                                       } else if (c == k)
                                                ok = 1;
-                                       pat += 2;
-                               } else if (c == k)
-                                       ok = 1;
-                       if (ok == negate_range)
-                               return(0);
-                       break;
-               default:
-                       if (*name++ != c)
-                               return(0);
-                       break;
+                               if (ok == negate_range)
+                                       goto fail;
+                               break;
+                       default:
+                               if (*name++ != c)
+                                       goto fail;
+                               break;
+                       }
                }
+               if (*name == EOS)
+                       return (1);
+
+       fail:
+               if (nextn == NULL)
+                       break;
+               pat = nextp;
+               name = nextn;
        }
-       return(*name == EOS);
+       return (0);
 }
 
 /* Free allocated data belonging to a glob_t structure. */
@@ -901,25 +1038,27 @@ globfree(glob_t *pglob)
 static DIR *
 g_opendir(Char *str, glob_t *pglob, locale_t loc)
 {
-       char buf[MAXPATHLEN];
+       char buf[MAXPATHLEN + MB_LEN_MAX - 1];
 
-       if (!*str)
+       if (*str == EOS)
                strcpy(buf, ".");
        else {
-               if (g_Ctoc(str, buf, sizeof(buf), loc))
+               if (g_Ctoc(str, buf, sizeof(buf), loc)) {
+                       errno = ENAMETOOLONG;
                        return (NULL);
+               }
        }
 
        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
-               return((*pglob->gl_opendir)(buf));
+               return ((*pglob->gl_opendir)(buf));
 
-       return(opendir(buf));
+       return (opendir(buf));
 }
 
 static int
 g_lstat(Char *fn, struct stat *sb, glob_t *pglob, locale_t loc)
 {
-       char buf[MAXPATHLEN];
+       char buf[MAXPATHLEN + MB_LEN_MAX - 1];
 
        if (g_Ctoc(fn, buf, sizeof(buf), loc)) {
                errno = ENAMETOOLONG;
@@ -927,21 +1066,21 @@ g_lstat(Char *fn, struct stat *sb, glob_t *pglob, locale_t loc)
        }
        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
                return((*pglob->gl_lstat)(buf, sb));
-       return(lstat(buf, sb));
+       return (lstat(buf, sb));
 }
 
 static int
 g_stat(Char *fn, struct stat *sb, glob_t *pglob, locale_t loc)
 {
-       char buf[MAXPATHLEN];
+       char buf[MAXPATHLEN + MB_LEN_MAX - 1];
 
        if (g_Ctoc(fn, buf, sizeof(buf), loc)) {
                errno = ENAMETOOLONG;
                return (-1);
        }
        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
-               return((*pglob->gl_stat)(buf, sb));
-       return(stat(buf, sb));
+               return ((*pglob->gl_stat)(buf, sb));
+       return (stat(buf, sb));
 }
 
 #ifndef BUILDING_VARIANT
@@ -966,9 +1105,13 @@ g_Ctoc(const Char *str, char *buf, size_t len, locale_t loc)
        memset(&mbs, 0, sizeof(mbs));
        while (len >= mb_cur_max) {
                clen = wcrtomb_l(buf, *str, &mbs, loc);
-               if (clen == (size_t)-1)
-                       return (1);
-               if (*str == L'\0')
+               if (clen == (size_t)-1) {
+                       /* XXX See initial comment #2. */
+                       *buf = (char)CHAR(*str);
+                       clen = 1;
+                       memset(&mbs, 0, sizeof(mbs));
+               }
+               if (CHAR(*str) == EOS)
                        return (0);
                str++;
                buf += clen;
@@ -978,21 +1121,53 @@ g_Ctoc(const Char *str, char *buf, size_t len, locale_t loc)
 }
 #endif /* !BUILDING_VARIANT */
 
+static int
+err_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat, locale_t loc) {
+       /*
+        * If there was no match we are going to append the origpat
+        * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+        * and the origpat did not contain any magic characters
+        * GLOB_NOMAGIC is there just for compatibility with csh.
+        */
+       if ((pglob->gl_flags & GLOB_NOCHECK) ||
+           ((pglob->gl_flags & GLOB_NOMAGIC) &&
+           !(pglob->gl_flags & GLOB_MAGCHAR)))
+               return (globextend(NULL, pglob, limit, origpat, loc));
+       return (GLOB_NOMATCH);
+}
+
+static int
+err_aborted(glob_t *pglob, int err, char *buf) {
+#ifdef __BLOCKS__
+       if (pglob->gl_flags & _GLOB_ERR_BLOCK && pglob->gl_errblk(buf, errno)) {
+               return (GLOB_ABORTED);
+       } else
+#endif /* __BLOCKS__ */
+       if (pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, errno)) {
+               return (GLOB_ABORTED);
+       } else if (pglob->gl_flags & GLOB_ERR) {
+               return (GLOB_ABORTED);
+       }
+       return (0);
+}
+
 #ifdef DEBUG
 static void
 qprintf(const char *str, Char *s)
 {
        Char *p;
 
-       (void)printf("%s:\n", str);
-       for (p = s; *p; p++)
-               (void)printf("%c", CHAR(*p));
-       (void)printf("\n");
-       for (p = s; *p; p++)
-               (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
-       (void)printf("\n");
-       for (p = s; *p; p++)
-               (void)printf("%c", ismeta(*p) ? '_' : ' ');
-       (void)printf("\n");
+       (void)printf("%s\n", str);
+       if (s != NULL) {
+               for (p = s; *p != EOS; p++)
+                       (void)printf("%c", (char)CHAR(*p));
+               (void)printf("\n");
+               for (p = s; *p != EOS; p++)
+                       (void)printf("%c", (isprot(*p) ? '\\' : ' '));
+               (void)printf("\n");
+               for (p = s; *p != EOS; p++)
+                       (void)printf("%c", (ismeta(*p) ? '_' : ' '));
+               (void)printf("\n");
+       }
 }
 #endif
index 05f7f925d247bd62c4389ff76c6a429b4e4d7bd8..4242906248bb520b4f6974bfc2f94423502d3ef5 100644 (file)
@@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$");
 
 #include "telldir.h"
 
-static DIR * __opendir_common(int, const char *, int);
+static DIR * __opendir_common(int, int, bool);
 
 /*
  * Open a directory.
@@ -76,21 +76,32 @@ fdopendir(int fd)
                errno = ENOTDIR;
                return (NULL);
        }
+       /* Make sure CLOEXEC is set on the fd */
        if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
                return (NULL);
-       return (__opendir_common(fd, NULL, DTF_HIDEW|DTF_NODUP));
+       return (__opendir_common(fd, DTF_HIDEW|DTF_NODUP, true));
 }
 
 DIR *
 __opendir2(const char *name, int flags)
 {
        int fd;
+       DIR *dir;
+       int saved_errno;
 
+       if ((flags & (__DTF_READALL | __DTF_SKIPREAD)) != 0)
+               return (NULL);
        if ((fd = _open(name,
            O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)) == -1)
                return (NULL);
 
-       return __opendir_common(fd, name, flags);
+       dir = __opendir_common(fd, flags, false);
+       if (dir == NULL) {
+               saved_errno = errno;
+               _close(fd);
+               errno = saved_errno;
+       }
+       return (dir);
 }
 
 static int
@@ -101,11 +112,186 @@ opendir_compar(const void *p1, const void *p2)
            (*(const struct dirent **)p2)->d_name));
 }
 
+/*
+ * For a directory at the top of a unionfs stack, the entire directory's
+ * contents are read and cached locally until the next call to rewinddir().
+ * For the fdopendir() case, the initial seek position must be preserved.
+ * For rewinddir(), the full directory should always be re-read from the
+ * beginning.
+ *
+ * If an error occurs, the existing buffer and state of 'dirp' is left
+ * unchanged.
+ */
+bool
+_filldir(DIR *dirp, bool use_current_pos)
+{
+       struct dirent **dpv;
+       char *buf, *ddptr, *ddeptr;
+       off_t pos;
+       int fd2, incr, len, n, saved_errno, space;
+       
+       len = 0;
+       space = 0;
+       buf = NULL;
+       ddptr = NULL;
+
+       /*
+        * Use the system page size if that is a multiple of DIRBLKSIZ.
+        * Hopefully this can be a big win someday by allowing page
+        * trades to user space to be done by _getdirentries().
+        */
+       incr = getpagesize();
+       if ((incr % DIRBLKSIZ) != 0) 
+               incr = DIRBLKSIZ;
+
+       /*
+        * The strategy here is to read all the directory
+        * entries into a buffer, sort the buffer, and
+        * remove duplicate entries by setting the inode
+        * number to zero.
+        *
+        * We reopen the directory because _getdirentries()
+        * on a MNT_UNION mount modifies the open directory,
+        * making it refer to the lower directory after the
+        * upper directory's entries are exhausted.
+        * This would otherwise break software that uses
+        * the directory descriptor for fchdir or *at
+        * functions, such as fts.c.
+        */
+       if ((fd2 = openat(dirp->dd_fd, ".", O_RDONLY | O_CLOEXEC)) == -1)
+               return (false);
+
+       if (use_current_pos) {
+               pos = lseek(dirp->dd_fd, 0, SEEK_CUR);
+               if (pos == -1 || lseek(fd2, pos, SEEK_SET) == -1) {
+                       saved_errno = errno;
+                       _close(fd2);
+                       errno = saved_errno;
+                       return (false);
+               }
+       }
+
+       do {
+               /*
+                * Always make at least DIRBLKSIZ bytes
+                * available to _getdirentries
+                */
+               if (space < DIRBLKSIZ) {
+                       space += incr;
+                       len += incr;
+                       buf = reallocf(buf, len);
+                       if (buf == NULL) {
+                               saved_errno = errno;
+                               _close(fd2);
+                               errno = saved_errno;
+                               return (false);
+                       }
+                       ddptr = buf + (len - space);
+               }
+
+#if __DARWIN_64_BIT_INO_T
+               n = (int)__getdirentries64(fd2, ddptr, space, &dirp->dd_td->seekoff);
+#else /* !__DARWIN_64_BIT_INO_T */
+               n = _getdirentries(fd2, ddptr, space, &dirp->dd_seek);
+#endif /* __DARWIN_64_BIT_INO_T */
+               if (n > 0) {
+                       ddptr += n;
+                       space -= n;
+               }
+               if (n < 0) {
+                       saved_errno = errno;
+                       _close(fd2);
+                       errno = saved_errno;
+                       return (false);
+               }
+       } while (n > 0);
+       _close(fd2);
+
+       ddeptr = ddptr;
+
+       /*
+        * There is now a buffer full of (possibly) duplicate
+        * names.
+        */
+       dirp->dd_buf = buf;
+
+       /*
+        * Go round this loop twice...
+        *
+        * Scan through the buffer, counting entries.
+        * On the second pass, save pointers to each one.
+        * Then sort the pointers and remove duplicate names.
+        */
+       for (dpv = NULL;;) {
+               n = 0;
+               ddptr = buf;
+               while (ddptr < ddeptr) {
+                       struct dirent *dp;
+
+                       dp = (struct dirent *) ddptr;
+                       if ((long)dp & 03L)
+                               break;
+                       if ((dp->d_reclen <= 0) ||
+                           (dp->d_reclen > (ddeptr + 1 - ddptr)))
+                               break;
+                       ddptr += dp->d_reclen;
+                       if (dp->d_fileno) {
+                               if (dpv)
+                                       dpv[n] = dp;
+                               n++;
+                       }
+               }
+
+               if (dpv) {
+                       struct dirent *xp;
+
+                       /*
+                        * This sort must be stable.
+                        */
+                       mergesort(dpv, n, sizeof(*dpv), opendir_compar);
+
+                       dpv[n] = NULL;
+                       xp = NULL;
+
+                       /*
+                        * Scan through the buffer in sort order,
+                        * zapping the inode number of any
+                        * duplicate names.
+                        */
+                       for (n = 0; dpv[n]; n++) {
+                               struct dirent *dp = dpv[n];
+
+                               if ((xp == NULL) ||
+                                   strcmp(dp->d_name, xp->d_name)) {
+                                       xp = dp;
+                               } else {
+                                       dp->d_fileno = 0;
+                               }
+                               if (dp->d_type == DT_WHT &&
+                                   (dirp->dd_flags & DTF_HIDEW))
+                                       dp->d_fileno = 0;
+                       }
+
+                       free(dpv);
+                       break;
+               } else {
+                       dpv = malloc((n+1) * sizeof(struct dirent *));
+                       if (dpv == NULL)
+                               break;
+               }
+       }
+
+       dirp->dd_len = len;
+       dirp->dd_size = ddptr - dirp->dd_buf;
+       return (true);
+}
+
+
 /*
  * Common routine for opendir(3), __opendir2(3) and fdopendir(3).
  */
 static DIR *
-__opendir_common(int fd, const char *name, int flags)
+__opendir_common(int fd, int flags, bool use_current_pos)
 {
        DIR *dirp;
        int incr;
@@ -115,6 +301,11 @@ __opendir_common(int fd, const char *name, int flags)
        if ((dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL)
                return (NULL);
 
+       dirp->dd_buf = NULL;
+       dirp->dd_fd = fd;
+       dirp->dd_flags = flags;
+       dirp->dd_loc = 0;
+       dirp->dd_lock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
        dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR));
        LIST_INIT(&dirp->dd_td->td_locq);
        dirp->dd_td->td_loccnt = 0;
@@ -143,172 +334,49 @@ __opendir_common(int fd, const char *name, int flags)
        }
 
        if (unionstack) {
-               int len = 0;
-               int space = 0;
-               char *buf = 0;
-               char *ddptr = 0;
-               char *ddeptr;
-               int n;
-               struct dirent **dpv;
-
-               /*
-                * The strategy here is to read all the directory
-                * entries into a buffer, sort the buffer, and
-                * remove duplicate entries by setting the inode
-                * number to zero.
-                */
-
-               do {
+               if (!_filldir(dirp, use_current_pos))
+                       goto fail;
+               dirp->dd_flags |= __DTF_READALL;
+       } else {
+               dirp->dd_len = incr;
+               dirp->dd_buf = malloc(dirp->dd_len);
+               if (dirp->dd_buf == NULL)
+                       goto fail;
+               if (use_current_pos) {
                        /*
-                        * Always make at least DIRBLKSIZ bytes
-                        * available to _getdirentries
+                        * Read the first batch of directory entries
+                        * to prime dd_seek.  This also checks if the
+                        * fd passed to fdopendir() is a directory.
                         */
-                       if (space < DIRBLKSIZ) {
-                               space += incr;
-                               len += incr;
-                               buf = reallocf(buf, len);
-                               if (buf == NULL)
-                                       goto fail;
-                               ddptr = buf + (len - space);
-                       }
-
 #if __DARWIN_64_BIT_INO_T
-                       n = (int)__getdirentries64(fd, ddptr, space, &dirp->dd_td->seekoff);
+                       dirp->dd_size = (long)__getdirentries64(dirp->dd_fd,
+                           dirp->dd_buf, dirp->dd_len, &dirp->dd_td->seekoff);
 #else /* !__DARWIN_64_BIT_INO_T */
-                       n = _getdirentries(fd, ddptr, space, &dirp->dd_seek);
+                       dirp->dd_size = _getdirentries(dirp->dd_fd,
+                           dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
 #endif /* __DARWIN_64_BIT_INO_T */
-                       if (n > 0) {
-                               ddptr += n;
-                               space -= n;
-                       }
-               } while (n > 0);
-
-               ddeptr = ddptr;
-               flags |= __DTF_READALL;
-
-               /*
-                * Re-open the directory.
-                * This has the effect of rewinding back to the
-                * top of the union stack and is needed by
-                * programs which plan to fchdir to a descriptor
-                * which has also been read -- see fts.c.
-                */
-               if (flags & DTF_REWIND) {
-                       (void)_close(fd);
-                       if ((fd = _open(name, O_RDONLY | O_DIRECTORY)) == -1) {
-                               saved_errno = errno;
-                               free(buf);
-                               free(dirp);
-                               errno = saved_errno;
-                               return (NULL);
-                       }
-               }
-
-               /*
-                * There is now a buffer full of (possibly) duplicate
-                * names.
-                */
-               dirp->dd_buf = buf;
-
-               /*
-                * Go round this loop twice...
-                *
-                * Scan through the buffer, counting entries.
-                * On the second pass, save pointers to each one.
-                * Then sort the pointers and remove duplicate names.
-                */
-               for (dpv = 0;;) {
-                       n = 0;
-                       ddptr = buf;
-                       while (ddptr < ddeptr) {
-                               struct dirent *dp;
-
-                               dp = (struct dirent *) ddptr;
-                               if ((long)dp & 03L)
-                                       break;
-                               if ((dp->d_reclen <= 0) ||
-                                   (dp->d_reclen > (ddeptr + 1 - ddptr)))
-                                       break;
-                               ddptr += dp->d_reclen;
-                               if (dp->d_fileno) {
-                                       if (dpv)
-                                               dpv[n] = dp;
-                                       n++;
-                               }
+                       if (dirp->dd_size < 0) {
+                               if (errno == EINVAL)
+                                       errno = ENOTDIR;
+                               goto fail;
                        }
-
-                       if (dpv) {
-                               struct dirent *xp;
-
-                               /*
-                                * This sort must be stable.
-                                */
-                               mergesort(dpv, n, sizeof(*dpv),
-                                   opendir_compar);
-
-                               dpv[n] = NULL;
-                               xp = NULL;
-
-                               /*
-                                * Scan through the buffer in sort order,
-                                * zapping the inode number of any
-                                * duplicate names.
-                                */
-                               for (n = 0; dpv[n]; n++) {
-                                       struct dirent *dp = dpv[n];
-
-                                       if ((xp == NULL) ||
-                                           strcmp(dp->d_name, xp->d_name)) {
-                                               xp = dp;
-                                       } else {
-                                               dp->d_fileno = 0;
-                                       }
-                                       if (dp->d_type == DT_WHT &&
-                                           (flags & DTF_HIDEW))
-                                               dp->d_fileno = 0;
-                               }
-
-                               free(dpv);
-                               break;
-                       } else {
-                               dpv = malloc((n+1) * sizeof(struct dirent *));
-                               if (dpv == NULL)
-                                       break;
-                       }
-               }
-
-               dirp->dd_len = len;
-               dirp->dd_size = ddptr - dirp->dd_buf;
-       } else {
-               dirp->dd_len = incr;
-               dirp->dd_size = 0;
-               dirp->dd_buf = malloc(dirp->dd_len);
-               if (dirp->dd_buf == NULL)
-                       goto fail;
+                       dirp->dd_flags |= __DTF_SKIPREAD;
+               } else {
+                       dirp->dd_size = 0;
 #if __DARWIN_64_BIT_INO_T
-               dirp->dd_td->seekoff = 0;
+                       dirp->dd_td->seekoff = 0;
 #else /* !__DARWIN_64_BIT_INO_T */
-               dirp->dd_seek = 0;
+                       dirp->dd_seek = 0;
 #endif /* __DARWIN_64_BIT_INO_T */
-               flags &= ~DTF_REWIND;
+               }
        }
 
-       dirp->dd_loc = 0;
-       dirp->dd_fd = fd;
-       dirp->dd_flags = flags;
-       dirp->dd_lock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
-
-       /*
-        * Set up seek point for rewinddir.
-        */
-       dirp->dd_rewind = telldir(dirp);
-
        return (dirp);
 
 fail:
        saved_errno = errno;
+       free(dirp->dd_buf);
        free(dirp);
-       (void)_close(fd);
        errno = saved_errno;
        return (NULL);
 }
index 3875cefa2a987e0bd99c914b03cd03a723990190..aa8443b6c12c63a7f0e654ede0c367010ce57829 100644 (file)
@@ -31,7 +31,7 @@
 static char sccsid[] = "@(#)readdir.c  8.3 (Berkeley) 9/29/94";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/readdir.c,v 1.15 2008/05/05 14:05:23 kib Exp $");
+__FBSDID("$FreeBSD$");
 
 #include "namespace.h"
 #include <sys/param.h>
@@ -39,7 +39,6 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/readdir.c,v 1.15 2008/05/05 14:05:23 kib Ex
 #include <errno.h>
 #include <string.h>
 #include <pthread.h>
-#include <unistd.h>
 #include "un-namespace.h"
 
 #include "libc_private.h"
@@ -49,29 +48,36 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/readdir.c,v 1.15 2008/05/05 14:05:23 kib Ex
  * get next entry in a directory.
  */
 struct dirent *
-_readdir_unlocked(dirp, skip)
-       DIR *dirp;
-       int skip;
+_readdir_unlocked(DIR *dirp, int skip)
 {
        struct dirent *dp;
+       long initial_seek;
+       long initial_loc = 0;
 
        for (;;) {
                if (dirp->dd_loc >= dirp->dd_size) {
                        if (dirp->dd_flags & __DTF_READALL)
                                return (NULL);
+                       initial_loc = dirp->dd_loc;
+                       dirp->dd_flags &= ~__DTF_SKIPREAD;
                        dirp->dd_loc = 0;
                }
-               if (dirp->dd_loc == 0 && !(dirp->dd_flags & __DTF_READALL)) {
+               if (dirp->dd_loc == 0 &&
+                   !(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) {
 #if __DARWIN_64_BIT_INO_T
-                       dirp->dd_size = __getdirentries64(dirp->dd_fd,
+                       initial_seek = dirp->dd_td->seekoff;
+                       dirp->dd_size = (long)__getdirentries64(dirp->dd_fd,
                            dirp->dd_buf, dirp->dd_len, &dirp->dd_td->seekoff);
 #else /* !__DARWIN_64_BIT_INO_T */
+                       initial_seek = dirp->dd_seek;
                        dirp->dd_size = _getdirentries(dirp->dd_fd,
                            dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
 #endif /* __DARWIN_64_BIT_INO_T */
                        if (dirp->dd_size <= 0)
                                return (NULL);
+                       _fixtelldir(dirp, initial_seek, initial_loc);
                }
+               dirp->dd_flags &= ~__DTF_SKIPREAD;
                dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
                if ((long)dp & 03L)     /* bogus pointer check */
                        return (NULL);
@@ -88,8 +94,7 @@ _readdir_unlocked(dirp, skip)
 }
 
 struct dirent *
-readdir(dirp)
-       DIR *dirp;
+readdir(DIR *dirp)
 {
        struct dirent   *dp;
 
@@ -104,10 +109,7 @@ readdir(dirp)
 }
 
 int
-readdir_r(dirp, entry, result)
-       DIR *dirp;
-       struct dirent *entry;
-       struct dirent **result;
+readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
 {
        struct dirent *dp;
        int saved_errno;
index bdbb33e68d359cb23e41cfd0702ad27cb31486ba..97067d3fd6e8020028e2fc08dbb8244f7be716d6 100644 (file)
 static char sccsid[] = "@(#)rewinddir.c        8.1 (Berkeley) 6/8/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/rewinddir.c,v 1.6 2007/01/09 00:27:55 imp Exp $");
+__FBSDID("$FreeBSD$");
 
+#include "namespace.h"
 #include <sys/types.h>
 #include <dirent.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "un-namespace.h"
 
+#include "libc_private.h"
 #include "telldir.h"
 
 void
-rewinddir(dirp)
-       DIR *dirp;
+rewinddir(DIR *dirp)
 {
 
-       _seekdir(dirp, dirp->dd_rewind);
-       dirp->dd_rewind = telldir(dirp);
+       if (__isthreaded)
+               _pthread_mutex_lock(&dirp->dd_lock);
+       dirp->dd_flags &= ~__DTF_SKIPREAD; /* current contents are invalid */
+       if (dirp->dd_flags & __DTF_READALL)
+               _filldir(dirp, false);
+       else {
+               (void) lseek(dirp->dd_fd, 0, SEEK_SET);
+#if __DARWIN_64_BIT_INO_T
+               dirp->dd_td->seekoff = 0;
+#else /* !__DARWIN_64_BIT_INO_T */
+               dirp->dd_seek = 0;
+#endif /* __DARWIN_64_BIT_INO_T */
+       }
+       dirp->dd_loc = 0;
+       _reclaim_telldir(dirp);
+       if (__isthreaded)
+               _pthread_mutex_unlock(&dirp->dd_lock);
 }
index 814f996d333aab28f84846f327a9eb601c2c8b33..b47983e253fb37e25d37556561b30c37ebef48f5 100644 (file)
@@ -31,7 +31,7 @@
 static char sccsid[] = "@(#)scandir.c  8.3 (Berkeley) 1/2/94";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/scandir.c,v 1.9 2008/03/16 19:08:53 das Exp $");
+__FBSDID("$FreeBSD$");
 
 /*
  * Scan the directory dirname calling select to make a list of selected
@@ -47,24 +47,38 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/scandir.c,v 1.9 2008/03/16 19:08:53 das Exp
 #include "un-namespace.h"
 
 /*
- * The _GENERIC_DIRSIZ macro is the minimum record length which will hold the directory
+ * The DIRSIZ macro is the minimum record length which will hold the directory
  * entry.  This requires the amount of space in struct dirent without the
  * d_name field, plus enough space for the name and a terminating nul byte
  * (dp->d_namlen + 1), rounded up to a 4 byte boundary.
  */
+#undef DIRSIZ
+#define DIRSIZ(dp)                                                     \
+       ((sizeof(struct dirent) - sizeof(dp)->d_name) +                 \
+           (((dp)->d_namlen + 1 + 3) &~ 3))
 
 int
-scandir(dirname, namelist, select, _dcomp)
-       const char *dirname;
-       struct dirent ***namelist;
-       int (*select)(const struct dirent *);
-       int (*_dcomp)(const struct dirent **, const struct dirent **);
+#ifdef I_AM_SCANDIR_B
+scandir_b(const char *dirname, struct dirent ***namelist,
+    int (^select)(const struct dirent *),
+    int (^_dcomp)(const struct dirent **, const struct dirent **))
+#else
+scandir(const char *dirname, struct dirent ***namelist,
+    int (*select)(const struct dirent *),
+    int (*_dcomp)(const struct dirent **, const struct dirent **))
+#endif
 {
        struct dirent *d, *p, **names = NULL;
        size_t nitems = 0;
        long arraysz;
        DIR *dirp;
-       int (*dcomp)(const void *, const void *) = (void *)_dcomp; /* see <rdar://problem/10293482> */
+
+       /* see <rdar://problem/10293482> */
+#ifdef I_AM_SCANDIR_B
+       int (^dcomp)(const void *, const void *) = (void *)_dcomp;
+#else
+       int (*dcomp)(const void *, const void *) = (void *)_dcomp;
+#endif
 
        if ((dirp = opendir(dirname)) == NULL)
                return(-1);
@@ -75,12 +89,12 @@ scandir(dirname, namelist, select, _dcomp)
                goto fail;
 
        while ((d = readdir(dirp)) != NULL) {
-               if (select != NULL && !(*select)(d))
+               if (select != NULL && !select(d))
                        continue;       /* just selected names */
                /*
                 * Make a minimum size copy of the data
                 */
-               p = (struct dirent *)malloc(_GENERIC_DIRSIZ(d));
+               p = (struct dirent *)malloc(DIRSIZ(d));
                if (p == NULL)
                        goto fail;
                p->d_fileno = d->d_fileno;
@@ -108,26 +122,32 @@ scandir(dirname, namelist, select, _dcomp)
        }
        closedir(dirp);
        if (nitems && dcomp != NULL)
+#ifdef I_AM_SCANDIR_B
+               qsort_b(names, nitems, sizeof(struct dirent *), dcomp);
+#else
                qsort(names, nitems, sizeof(struct dirent *), dcomp);
+#endif
        *namelist = names;
-       return(nitems);
+       return (int) (nitems);
 
 fail:
        while (nitems > 0)
                free(names[--nitems]);
        free(names);
        closedir(dirp);
-       return -1;
+       return (-1);
 }
 
+#ifndef I_AM_SCANDIR_B
 /*
  * Alphabetic order comparison routine for those who want it.
+ * POSIX 2008 requires that alphasort() uses strcoll().
  */
 int
-alphasort(d1, d2)
-       const struct dirent **d1;
-       const struct dirent **d2;
+alphasort(const struct dirent **d1, const struct dirent **d2)
 {
-       return(strcmp((*(struct dirent **)d1)->d_name,
-           (*(struct dirent **)d2)->d_name));
+
+       return (strcoll((*d1)->d_name, (*d2)->d_name));
 }
+#endif // I_AM_SCANDIR_B
+
index e13b9178fd3ab2cdeb64882d325d3f512401fe5d..92a7727b9bb565ed86cec6b47edc0186240fc96c 100644 (file)
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
+/*-
+ * Copyright (c) 2014 David Chisnall
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * 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.
- * 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
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+ * 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)
  * 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.
+ *
+ * $FreeBSD$
  */
+#ifdef __BLOCKS__
+#define I_AM_SCANDIR_B
+#include "scandir.c"
+#endif /* __BLOCKS__ */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)scandir.c  8.3 (Berkeley) 1/2/94";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/scandir.c,v 1.9 2008/03/16 19:08:53 das Exp $");
-
-/*
- * Scan the directory dirname calling select to make a list of selected
- * directory entries then sort using qsort and compare routine dcomp.
- * Returns the number of entries and a pointer to a list of pointers to
- * struct dirent (through namelist). Returns -1 if there were any errors.
- */
-
-#include "namespace.h"
-#include <dirent.h>
-#include <stdlib.h>
-#include <string.h>
-#include "un-namespace.h"
-
-/*
- * The _GENERIC_DIRSIZ macro is the minimum record length which will hold the directory
- * entry.  This requires the amount of space in struct dirent without the
- * d_name field, plus enough space for the name and a terminating nul byte
- * (dp->d_namlen + 1), rounded up to a 4 byte boundary.
- */
-
-int
-scandir_b(dirname, namelist, select, _dcomp)
-       const char *dirname;
-       struct dirent ***namelist;
-       int (^select)(const struct dirent *);
-       int (^_dcomp)(const struct dirent **, const struct dirent **);
-{
-       struct dirent *d, *p, **names = NULL;
-       size_t nitems = 0;
-       long arraysz;
-       DIR *dirp;
-       int (^dcomp)(const void *, const void *) = (void *)_dcomp; /* see <rdar://problem/10293482> */
-
-       if ((dirp = opendir(dirname)) == NULL)
-               return(-1);
-
-       arraysz = 32;   /* initial estimate of the array size */
-       names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
-       if (names == NULL)
-               goto fail;
-
-       while ((d = readdir(dirp)) != NULL) {
-               if (select != NULL && !select(d))
-                       continue;       /* just selected names */
-               /*
-                * Make a minimum size copy of the data
-                */
-               p = (struct dirent *)malloc(_GENERIC_DIRSIZ(d));
-               if (p == NULL)
-                       goto fail;
-               p->d_fileno = d->d_fileno;
-               p->d_type = d->d_type;
-               p->d_reclen = d->d_reclen;
-               p->d_namlen = d->d_namlen;
-               bcopy(d->d_name, p->d_name, p->d_namlen + 1);
-               /*
-                * Check to make sure the array has space left and
-                * realloc the maximum size.
-                */
-               if (nitems >= arraysz) {
-                       struct dirent **names2;
-
-                       names2 = (struct dirent **)realloc((char *)names,
-                               (arraysz * 2) * sizeof(struct dirent *));
-                       if (names2 == NULL) {
-                               free(p);
-                               goto fail;
-                       }
-                       names = names2;
-                       arraysz *= 2;
-               }
-               names[nitems++] = p;
-       }
-       closedir(dirp);
-       if (nitems && dcomp != NULL)
-               qsort_b(names, nitems, sizeof(struct dirent *), dcomp);
-       *namelist = names;
-       return(nitems);
-
-fail:
-       while (nitems > 0)
-               free(names[--nitems]);
-       free(names);
-       closedir(dirp);
-       return -1;
-}
index cfadd8c011329bf31bf02ca5d236533b821dd69e..71eb393285eb49fedebacf07e352b8d1f69f1abb 100644 (file)
@@ -31,7 +31,7 @@
 static char sccsid[] = "@(#)seekdir.c  8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/seekdir.c,v 1.7 2007/12/03 14:33:51 des Exp $");
+__FBSDID("$FreeBSD$");
 
 #include "namespace.h"
 #include <sys/param.h>
@@ -47,9 +47,7 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/seekdir.c,v 1.7 2007/12/03 14:33:51 des Exp
  * _seekdir is in telldir.c so that it can share opaque data structures.
  */
 void
-seekdir(dirp, loc)
-       DIR *dirp;
-       long loc;
+seekdir(DIR *dirp, long loc)
 {
        if (__isthreaded)
                _pthread_mutex_lock(&dirp->dd_lock);
index 355ed50e4fc2615fab9646f8b7ccd4717ec16468..c447a37b5ef7a6d04921863db6df661ec084f9c3 100644 (file)
@@ -31,7 +31,7 @@
 static char sccsid[] = "@(#)telldir.c  8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/telldir.c,v 1.11 2008/05/05 14:05:23 kib Exp $");
+__FBSDID("$FreeBSD$");
 
 #include "namespace.h"
 #include <sys/param.h>
@@ -45,62 +45,46 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/telldir.c,v 1.11 2008/05/05 14:05:23 kib Ex
 #include "libc_private.h"
 #include "telldir.h"
 
-/*
- * The option SINGLEUSE may be defined to say that a telldir
- * cookie may be used only once before it is freed. This option
- * is used to avoid having memory usage grow without bound.
- */
-#if !__DARWIN_UNIX03
-#define SINGLEUSE
-#endif /* !__DARWIN_UNIX03 */
-
 /*
  * return a pointer into a directory
  */
 long
-telldir(dirp)
-       DIR *dirp;
+telldir(DIR *dirp)
 {
        struct ddloc *lp;
+       long idx;
 
-#if __DARWIN_UNIX03
        if (__isthreaded)
                _pthread_mutex_lock(&dirp->dd_lock);
        LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) {
-               if (
 #if __DARWIN_64_BIT_INO_T
-                   (lp->loc_seek == dirp->dd_td->seekoff)
+               if (lp->loc_seek == dirp->dd_td->seekoff &&
 #else /* !__DARWIN_64_BIT_INO_T */
-                   (lp->loc_seek == dirp->dd_seek)
+               if (lp->loc_seek == dirp->dd_seek &&
 #endif /* __DARWIN_64_BIT_INO_T */
-                   && (lp->loc_loc == dirp->dd_loc))
-                       goto found;
-       }
-       if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) {
-               if (__isthreaded)
-                       _pthread_mutex_unlock(&dirp->dd_lock);
-               return (-1);
+                   lp->loc_loc == dirp->dd_loc)
+                       break;
        }
-#else /* !__DARWIN_UNIX03 */
-       if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
-               return (-1);
-       if (__isthreaded)
-               _pthread_mutex_lock(&dirp->dd_lock);
-#endif /* __DARWIN_UNIX03 */
-       lp->loc_index = dirp->dd_td->td_loccnt++;
+       if (lp == NULL) {
+               lp = malloc(sizeof(struct ddloc));
+               if (lp == NULL) {
+                       if (__isthreaded)
+                               _pthread_mutex_unlock(&dirp->dd_lock);
+                       return (-1);
+               }
+               lp->loc_index = dirp->dd_td->td_loccnt++;
 #if __DARWIN_64_BIT_INO_T
-       lp->loc_seek = dirp->dd_td->seekoff;
+               lp->loc_seek = dirp->dd_td->seekoff;
 #else /* !__DARWIN_64_BIT_INO_T */
-       lp->loc_seek = dirp->dd_seek;
+               lp->loc_seek = dirp->dd_seek;
 #endif /* __DARWIN_64_BIT_INO_T */
-       lp->loc_loc = dirp->dd_loc;
-       LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
-#if __DARWIN_UNIX03
-found:
-#endif /* __DARWIN_UNIX03 */
+               lp->loc_loc = dirp->dd_loc;
+               LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
+       }
+       idx = lp->loc_index;
        if (__isthreaded)
                _pthread_mutex_unlock(&dirp->dd_lock);
-       return (lp->loc_index);
+       return (idx);
 }
 
 /*
@@ -108,9 +92,7 @@ found:
  * Only values returned by "telldir" should be passed to seekdir.
  */
 void
-_seekdir(dirp, loc)
-       DIR *dirp;
-       long loc;
+_seekdir(DIR *dirp, long loc)
 {
        struct ddloc *lp;
        struct dirent *dp;
@@ -121,14 +103,28 @@ _seekdir(dirp, loc)
        }
        if (lp == NULL)
                return;
-       if (lp->loc_loc == dirp->dd_loc && 
 #if __DARWIN_64_BIT_INO_T
-           lp->loc_seek == dirp->dd_td->seekoff
+       if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_td->seekoff)
 #else /* !__DARWIN_64_BIT_INO_T */
-           lp->loc_seek == dirp->dd_seek
+       if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
 #endif /* __DARWIN_64_BIT_INO_T */
-       )
-               goto found;
+               return;
+
+       /* If it's within the same chunk of data, don't bother reloading. */
+#if __DARWIN_64_BIT_INO_T
+       if (lp->loc_seek == dirp->dd_td->seekoff) {
+#else /* !__DARWIN_64_BIT_INO_T */
+       if (lp->loc_seek == dirp->dd_seek) {
+#endif /* __DARWIN_64_BIT_INO_T */
+               /*
+                * If we go back to 0 don't make the next readdir
+                * trigger a call to getdirentries().
+                */
+               if (lp->loc_loc == 0)
+                       dirp->dd_flags |= __DTF_SKIPREAD;
+               dirp->dd_loc = lp->loc_loc;
+               return;
+       }
        (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET);
 #if __DARWIN_64_BIT_INO_T
        dirp->dd_td->seekoff = lp->loc_seek;
@@ -136,16 +132,40 @@ _seekdir(dirp, loc)
        dirp->dd_seek = lp->loc_seek;
 #endif /* __DARWIN_64_BIT_INO_T */
        dirp->dd_loc = 0;
+       dirp->dd_flags &= ~__DTF_SKIPREAD; /* current contents are invalid */
        while (dirp->dd_loc < lp->loc_loc) {
                dp = _readdir_unlocked(dirp, 0);
                if (dp == NULL)
                        break;
        }
-found:;
-#ifdef SINGLEUSE
-       LIST_REMOVE(lp, loc_lqe);
-       free((caddr_t)lp);
-#endif
+}
+
+/*
+ * After readdir returns the last entry in a block, a call to telldir
+ * returns a location that is after the end of that last entry.
+ * However, that location doesn't refer to a valid directory entry.
+ * Ideally, the call to telldir would return a location that refers to
+ * the first entry in the next block.  That location is not known
+ * until the next block is read, so readdir calls this function after
+ * fetching a new block to fix any such telldir locations.
+ */
+void
+_fixtelldir(DIR *dirp, long oldseek, long oldloc)
+{
+       struct ddloc *lp;
+
+       lp = LIST_FIRST(&dirp->dd_td->td_locq);
+       if (lp != NULL) {
+               if (lp->loc_loc == oldloc &&
+                   lp->loc_seek == oldseek) {
+#if __DARWIN_64_BIT_INO_T
+                       lp->loc_seek = dirp->dd_td->seekoff;
+#else /* !__DARWIN_64_BIT_INO_T */
+                       lp->loc_seek = dirp->dd_seek;
+#endif /* __DARWIN_64_BIT_INO_T */
+                       lp->loc_loc = dirp->dd_loc;
+               }
+       }
 }
 
 #ifndef BUILDING_VARIANT
@@ -153,8 +173,7 @@ found:;
  * Reclaim memory for telldir cookies which weren't used.
  */
 void
-_reclaim_telldir(dirp)
-       DIR *dirp;
+_reclaim_telldir(DIR *dirp)
 {
        struct ddloc *lp;
        struct ddloc *templp;
@@ -167,4 +186,4 @@ _reclaim_telldir(dirp)
        }
        LIST_INIT(&dirp->dd_td->td_locq);
 }
-#endif /* !BUILDING_VARIANT */
+#endif
index c1f0ad07b6e1c34e03ab84e825d75c8ef8dd2af2..271981eba39ef130d7878d18032477c6c863e76f 100644 (file)
@@ -36,6 +36,7 @@
 #define        _TELLDIR_H_
 
 #include <sys/queue.h>
+#include <stdbool.h>
 
 /*
  * One of these structures is malloced to describe the current directory
@@ -69,9 +70,13 @@ struct _telldir {
 #if __DARWIN_64_BIT_INO_T
 size_t         __getdirentries64(int fd, void *buf, size_t bufsize, __darwin_off_t *basep);
 #endif /* __DARWIN_64_BIT_INO_T */
+__attribute__ ((visibility ("hidden")))
+bool           _filldir(DIR *, bool) __DARWIN_INODE64(_filldir);
 struct dirent  *_readdir_unlocked(DIR *, int) __DARWIN_INODE64(_readdir_unlocked);
 void           _reclaim_telldir(DIR *);
 void           _seekdir(DIR *, long) __DARWIN_ALIAS_I(_seekdir);
+__attribute__ ((visibility ("hidden")))
+void        _fixtelldir(DIR *dirp, long oldseek, long oldloc) __DARWIN_INODE64(_fixtelldir);
 long           telldir(DIR *) __DARWIN_ALIAS_I(telldir);
 
 #endif
index 0012549ecc807fd55f83c4a965014b39d4c03f38..0d023a80391be8b3e1ee79e1196a886dbe03051a 100644 (file)
@@ -9,10 +9,6 @@
 .\" 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.
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)ttyname.3  8.1 (Berkeley) 6/4/93
-.\" $FreeBSD: src/lib/libc/gen/ttyname.3,v 1.10 2002/12/18 13:33:02 ru Exp $
+.\" $FreeBSD$
 .\"
-.Dd June 4, 1993
+.Dd July 18, 2014
 .Dt TTYNAME 3
 .Os
 .Sh NAME
-.Nm isatty ,
 .Nm ttyname ,
-.Nm ttyslot
+.Nm ttyname_r ,
+.Nm isatty
 .Nd get name of associated terminal (tty) from file descriptor
 .Sh LIBRARY
 .Lb libc
 .Sh SYNOPSIS
 .In unistd.h
-.Ft int
-.Fo isatty
-.Fa "int fildes"
-.Fc
 .Ft char *
-.Fo ttyname
-.Fa "int fildes"
-.Fc
+.Fn ttyname "int fd"
+.Ft int
+.Fn ttyname_r "int fd" "char *buf" "size_t len"
 .Ft int
-.Fo ttyslot
-.Fa void
-.Fc
+.Fn isatty "int fd"
 .Sh DESCRIPTION
-These functions operate on the system file descriptors for terminal
-type devices.
-These descriptors are not related to the standard
-.Tn I/O
-.Dv FILE
-typedef, but refer to the special device files found in
-.Pa /dev
-and named
-.Pa /dev/tty Ns Ar xx
-and for which an entry exists
-in the initialization file
-.Pa /etc/ttys .
-(See
-.Xr ttys 5 . )
+These functions operate on file descriptors for terminal type devices.
 .Pp
 The
 .Fn isatty
 function
 determines if the file descriptor
-.Fa fildes
+.Fa fd
 refers to a valid
 terminal type device.
 .Pp
@@ -89,47 +66,73 @@ a file descriptor for which
 is true.
 .Pp
 The
-.Fn ttyslot
+.Fn ttyname
 function
-fetches the current process' control terminal number from the
-.Xr ttys 5
-file entry.
+returns the name stored in a static buffer which will be overwritten
+on subsequent calls.
+The
+.Fn ttyname_r
+function
+takes a buffer and length as arguments to avoid this problem.
 .Sh RETURN VALUES
 The
+.Fn isatty
+function returns 1 if
+.Fa fd
+refers to a terminal type device;
+otherwise, it returns 0 and may set
+.Va errno
+to indicate the error.
+The
 .Fn ttyname
 function
 returns the null terminated name if the device is found and
 .Fn isatty
-is true; otherwise, a
+is true; otherwise
+a
 .Dv NULL
 pointer is returned.
+The
+.Fn ttyname_r
+function returns 0 if successful.
+Otherwise an error number is returned.
+.Sh ERRORS
+These functions may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid file descriptor.
+.It Bq Er ENOTTY
+The file associated with
+.Fa fd
+is not a terminal.
+.El
 .Pp
+Additionally,
+.Fn ttyname_r
+may fail if:
+.Bl -tag -width Er
+.It Bq Er ERANGE
 The
-.Fn ttyslot
-function returns the unit number of the device file if found;
-otherwise, the value zero is returned.
-.Sh FILES
-.Bl -tag -width /etc/ttys -compact
-.It Pa /dev/\(**
-.It Pa /etc/ttys
+.Fa bufsize
+argument
+is smaller than the length of the string to be returned.
 .El
 .Sh SEE ALSO
 .Xr ioctl 2 ,
 .Xr ttys 5
 .Sh HISTORY
-A
-.Fn isatty ,
-.Fn ttyname ,
+The
+.Fn isatty
 and
-.Fn ttyslot
-function
+.Fn ttyname
+functions
 appeared in
 .At v7 .
-.Sh BUGS
 The
-.Fn ttyname
-function leaves its result in an internal static object and returns
-a pointer to that object.
-Subsequent calls to
-.Fn ttyname
-will modify the same object.
+.Fn ttyname_r
+function
+appeared in
+.Fx 6.0 .
index a553e163068b3938dad1029335a06224f716fe6c..d437a48cd1164124da5fd4527c402bc98868e801 100644 (file)
@@ -31,7 +31,7 @@
 static char sccsid[] = "@(#)ttyslot.c  8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/gen/ttyslot.c,v 1.6 2009/02/12 19:00:13 ed Exp $");
+__FBSDID("$FreeBSD$");
 
 #include <paths.h>
 #include <ttyent.h>
@@ -42,24 +42,6 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/ttyslot.c,v 1.6 2009/02/12 19:00:13 ed Exp
 int
 ttyslot()
 {
-       struct ttyent *ttyp;
-       int slot;
-       int cnt;
-       char *name;
 
-       setttyent();
-       for (cnt = 0; cnt < 3; ++cnt)
-               if ( (name = ttyname(cnt)) ) {
-                       if (strncmp(name, _PATH_DEV, sizeof _PATH_DEV - 1) != 0)
-                               break;
-                       name += sizeof _PATH_DEV - 1;
-                       for (slot = 1; (ttyp = getttyent()); ++slot)
-                               if (!strcmp(ttyp->ty_name, name)) {
-                                       endttyent();
-                                       return(slot);
-                               }
-                       break;
-               }
-       endttyent();
-       return(0);
+       return (0);
 }
index f48f1730309843c0c09525b7fa0ad03c220f1c89..23e0bbc70ab5f6ee02e617918b2517bb41051fc5 100644 (file)
@@ -101,7 +101,7 @@ static wchar_t *do_svis(wchar_t *, wint_t, int, wint_t, const wchar_t *);
 
 #define MAXEXTRAS      10
 
-_Static_assert(MB_LEN_MAX <= sizeof(uint64_t));
+_Static_assert(MB_LEN_MAX <= sizeof(uint64_t), "MB_LEN_MAX is less than 64-bits");
 
 /*
  * This is do_hvis, for HTTP style (RFC 1808)
index 5fa261abd9ec9959d4d30e6b818b2ea03ff8a443..46221c716133e1f51ffdeba051a176725c9a09e1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: rb.c,v 1.11 2011/06/20 09:11:16 mrg Exp $      */
+/*     $NetBSD: rb.c,v 1.13 2014/08/22 17:19:48 matt Exp $     */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
index cc7deedcf766aac68f3ff17fa46be52819e3a809..399eecad174f9b548a6942bcfa7e6e230e348966 100644 (file)
@@ -1,4 +1,4 @@
-.\"     $NetBSD: rbtree.3,v 1.7 2012/08/19 19:31:13 wiz Exp $
+.\"     $NetBSD: rbtree.3,v 1.12 2016/08/30 05:12:00 dholland Exp $
 .\"
 .\" Copyright (c) 2010 The NetBSD Foundation, Inc.
 .\" All rights reserved.
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd August 19, 2012
+.Dd August 29, 2016
 .Dt RBTREE 3
 .Os
 .Sh NAME
-.Nm rbtree
+.Nm rbtree ,
+.Nm rb_tree_init ,
+.Nm rb_tree_insert_node ,
+.Nm rb_tree_remove_node ,
+.Nm rb_tree_find_node ,
+.Nm rb_tree_find_node_geq ,
+.Nm rb_tree_find_node_leq ,
+.Nm rb_tree_iterate ,
+.Nm rb_tree_count ,
+.Nm RB_TREE_MIN ,
+.Nm RB_TREE_MAX ,
+.Nm RB_TREE_FOREACH ,
+.Nm RB_TREE_FOREACH_REVERSE
 .Nd red-black tree
 .Sh LIBRARY
 .Lb libc
 .Fn rb_tree_iterate "rb_tree_t *rbt" "void *rb" "const unsigned int direction"
 .Ft size_t
 .Fn rb_tree_count "rb_tree_t *rbt"
+.Ft void *
+.Fn RB_TREE_MIN "rb_tree_t *rbt"
+.Ft void *
+.Fn RB_TREE_MAX "rb_tree_t *rbt"
+.Fn RB_TREE_FOREACH "void *rb" "rb_tree_t *rbt"
+.Fn RB_TREE_FOREACH_REVERSE "void *rb" "rb_tree_t *rbt"
 .Sh DESCRIPTION
 .Nm
 provides red-black trees.
@@ -79,7 +97,7 @@ The maximum height of a red-black tree is 2lg (n+1).
 A red-black tree.
 .It Vt typedef signed int \
 (* rbto_compare_nodes_fn)(void *context, const void *node1, const void *node2);
-The node-comparison operator.
+The node-comparison function.
 Defines an ordering on nodes.
 Returns a negative value if the first node
 .Ar node1
@@ -96,7 +114,7 @@ and the second node
 are identical according to the ordering.
 .It Vt typedef signed int \
 (* rbto_compare_key_fn)(void *context, const void *node, const void *key);
-The node-key comparison operator.
+The node-key comparison function.
 Defines the order of nodes and keys.
 Returns a negative value if the node
 .Ar node
@@ -112,12 +130,12 @@ is identical to the key
 .Ar key
 according to the ordering.
 .It Vt rb_tree_ops_t
-Defines the operator for comparing two nodes in the same tree,
-the operator for comparing a node in the tree with a key,
+Defines the function for comparing two nodes in the same tree,
+the function for comparing a node in the tree with a key,
 the offset of member
 .Vt rb_node_t
-within a node,
-and the opaque context passed to the operators.
+within the node type,
+and the opaque context pointer passed to the comparison functions.
 Members of
 .Vt rb_tree_ops_t
 are
@@ -129,13 +147,22 @@ are
 .Ed
 .It Vt rb_node_t
 A node in a red-black tree has this structure as a member.
+The offset of the
+.Vt rb_node_t
+member in the caller's node structure should be provided as
+.Va rbto_node_offset .
+(None of the functions in the
+.Nm
+interface are meant to take pointers directly to the
+.Vt rb_node_t
+member.)
 .El
 .Sh FUNCTIONS
 .Bl -tag -width compact
 .It Fn rb_tree_init "rbt" "ops"
 Initialize the red-black tree
 .Fa rbt .
-Let the comparison operators given by
+Let the comparison functions given by
 .Fa ops
 define the order of nodes in the tree for
 the purposes of insertion, search, and iteration.
@@ -194,7 +221,7 @@ or, if
 .Fa rb
 is
 .Dv NULL ,
-return the last node in
+return the first node in
 .Fa rbt
 or, if the tree is empty, return
 .Dv NULL .
@@ -211,47 +238,67 @@ or, if
 .Fa rb
 is
 .Dv NULL ,
-return the first node in
+return the last node in
 .Fa rbt
 or, if the tree is empty, return
 .Dv NULL .
 .It Fn rb_tree_count "rbt"
 Return the number of nodes in the tree
 .Fa rbt .
-If 
+If
 .Fa rbt
 is
 .Dv NULL ,
 0 is returned.
+.It Fn RB_TREE_MIN "rbt"
+Return the first node in
+.Fa rbt ,
+i.e. the node with the least key, or
+.Dv NULL
+if
+.Fa rbt
+is empty.
+.It Fn RB_TREE_MAX "rbt"
+Return the last node in
+.Fa rbt ,
+i.e. the node with the greatest key, or
+.Dv NULL
+if
+.Fa rbt
+is empty.
+.It Fn RB_TREE_FOREACH "rb" "rbt"
+.Nm RB_TREE_FOREACH
+is a macro to be used in the place of a
+.Dv for
+header preceding a statement to traverse the nodes in
+.Fa rbt
+from least to greatest, assigning
+.Fa rb
+to each node in turn and executing the statement.
+.It Fn RB_TREE_FOREACH_REVERSE "rb" "rbt"
+.Nm RB_TREE_FOREACH_REVERSE
+is a macro to be used in the place of a
+.Dv for
+header preceding a statement to traverse the nodes in
+.Fa rbt
+from greatest to least, assigning
+.Fa rb
+to each node in turn and executing the statement.
 .El
-.Sh IMPLEMENTATION DETAILS
-.Nx 6.0
-included a version of this API that returned the wrong result when using
-.Fn rb_tree_iterate
-to find the first or last node.
-This implementation does not have this bug.
-If you wish to maintain portability with
-.Nx 6.0 , 
-it is recomended that you use the 
-.Fn RB_TREE_MIN
-and 
-.Fn RB_TREE_MAX
-macros rather than using
-.Fn rb_tree_iterate
-directly.
 .Sh SEE ALSO
-.Xr queue 3
+.Xr queue 3 ,
+.Xr tree 3
 .Sh HISTORY
 The
 .Nm
 interface first appeared in
 .Nx 6.0 .
 .Sh AUTHORS
-.An Matt Thomas Aq matt@NetBSD.org
+.An Matt Thomas Aq Mt matt@NetBSD.org
 wrote
 .Nm .
 .Pp
-.An Niels Provos Aq provos@citi.umich.edu
+.An Niels Provos Aq Mt provos@citi.umich.edu
 wrote the
 .Xr tree 3
 manual page.
index 8c3407c18ceb3c03c1af7e110fd0f45bb07091d5..79d4164e8a971b9c8ebe8a213f930b097695f89e 100644 (file)
@@ -10,7 +10,6 @@
 #define        dd_buf          __dd_buf
 #define        dd_len          __dd_len
 #define        dd_seek         __dd_seek
-#define        dd_rewind       __dd_rewind
 #define        dd_flags        __dd_flags
 #define        dd_lock         __dd_lock
 #define        dd_td           __dd_td
index 7be0ad78aeb21c855dc560797678da7a0c5b6681..783a2517237917db1fa67ce7cd09c82060c5e9c0 100644 (file)
@@ -214,8 +214,10 @@ clock_settime(clockid_t clk_id, const struct timespec *tp)
 {
     switch(clk_id){
     case CLOCK_REALTIME: {
-        struct timeval tv;
-        TIMESPEC_TO_TIMEVAL(&tv,tp)
+        struct timeval tv = {
+            .tv_sec = (time_t)tp->tv_sec,
+            .tv_usec = (suseconds_t)(tp->tv_nsec / NSEC_PER_USEC)
+        };
         return settimeofday(&tv, NULL);
     }
     default:
index 6743885d6262917083d499b63f13eaa608b6feca..606431ab1a5d1f1bb9f85c3b75278307fdaa9786 100644 (file)
@@ -346,7 +346,7 @@ STATIC void permute(cp, out, p, chars_in)
 #ifndef BUILDING_VARIANT
 __private_extern__ int __crypt_des_setkey_called = 0;
 #else /* BUILDING_VARIANT */
-__private_extern__ int __crypt_des_setkey_called;
+extern int __crypt_des_setkey_called;
 #endif /* BUILDING_VARIANT */
 
 /* =====  (mostly) Standard DES Tables ==================== */
index b88f91d0c91b14bbcf8aa89d22fc00ce2dcc7a7e..fe90e212f5bec381be0408a1a145c0b8c86c1362 100644 (file)
@@ -73,7 +73,7 @@
 #ifdef unused
 static int     error(int);
 #endif // unused
-static int     gettype(char *, char **);
+static int     gettype(const char *, const char **);
 
 struct disklabel *
 getdiskbyname(const char *name)
@@ -121,7 +121,7 @@ getdiskbyname(const char *name)
                dp->d_flags |= D_BADSECT;
 
 #define getnumdflt(field, dname, dflt) \
-        { long f; (field) = (cgetnum(buf, dname, &f) == -1) ? (dflt) : f; }
+        { long f; (field) = (typeof(field))((cgetnum(buf, dname, &f) == -1) ? (dflt) : f); }
 
        getnumdflt(dp->d_secsize, "se", DEV_BSIZE);
        cgetnum(buf, "nt",(long *) &dp->d_ntracks);
@@ -184,15 +184,13 @@ getdiskbyname(const char *name)
 }
 
 static int
-gettype(t, names)
-       char *t;
-       char **names;
+gettype(const char *t, const char **names)
 {
-       register char **nm;
+       const char **nm;
 
        for (nm = names; *nm; nm++)
                if (strcasecmp(t, *nm) == 0)
-                       return (nm - names);
+                       return (int)(nm - names);
        if (isdigit(*t))
                return (atoi(t));
        return (0);
index 729ec79349f46210d687d04b1fde86f9d45cc324..040abccb379df1552ae69bdd5da9f26fe90145a1 100644 (file)
--- a/gen/fts.c
+++ b/gen/fts.c
@@ -54,7 +54,6 @@
 #include <sys/param.h>
 #include <sys/stat.h>
 
-#include <assert.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
 #include <sys/vnode.h>
 #include <sys/attr.h>
+#include <os/assumes.h>
 
 #ifdef __BLOCKS__
 #include <Block.h>
 #endif /* __BLOCKS__ */
 #include <malloc_private.h>
 
-static FTSENT  *fts_alloc(FTS *, char *, int);
+static FTSENT  *fts_alloc(FTS *, char *, ssize_t);
 static FTSENT  *fts_build(FTS *, int);
 static void     fts_lfree(FTSENT *);
 static void     fts_load(FTS *, FTSENT *);
@@ -141,7 +141,7 @@ __fts_open(char * const *argv, FTS *sp)
        FTSENT *p, *root;
        int nitems;
        FTSENT *parent, *tmp;
-       int len;
+       ssize_t len;
 
        /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
        if (ISSET(FTS_LOGICAL))
@@ -161,12 +161,7 @@ __fts_open(char * const *argv, FTS *sp)
 
        /* Allocate/initialize root(s). */
        for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
-               /* Don't allow zero-length paths. */
-               if ((len = strlen(*argv)) == 0) {
-                       errno = ENOENT;
-                       goto mem3;
-               }
-
+               len = strlen(*argv);
                if ((p = fts_alloc(sp, *argv, len)) == NULL)
                        goto mem3;
                p->fts_level = FTS_ROOTLEVEL;
@@ -278,7 +273,7 @@ fts_open_b(char * const *argv, int options, int (^compar)(const FTSENT **, const
 static void
 fts_load(FTS *sp, FTSENT *p)
 {
-       int len;
+       ssize_t len;
        char *cp;
 
        /*
@@ -642,7 +637,7 @@ fts_children(FTS *sp, int instr)
        return (sp->fts_child);
 }
 
-typedef struct __attribute__((packed)) {
+typedef struct __attribute__((packed)) __attribute__((__aligned__(4))) {
        uint32_t length;
 
        /* common attributes */
@@ -717,7 +712,7 @@ advance_directory(dir_handle *handle)
 {
        if (handle->done) return true;
 
-       assert(handle->dirfd != -1);
+       os_assert(handle->dirfd != -1);
        handle->entry_count = getattrlistbulk(handle->dirfd, &handle->requested_attrs,
                        handle->attrbuf, ATTR_BUF_SIZE, FSOPT_PACK_INVAL_ATTRS);
        if (handle->entry_count == -1) {
@@ -840,18 +835,26 @@ read_dirent(dir_handle *handle, dir_entry *entry)
                curattr_stat = handle->curattr;
                handle->cur_entry++;
                handle->curattr = (attrListAttributes*)(((char*)curattr_stat) + curattr_stat->length);
+               os_assert((handle->cur_entry == handle->entry_count) ||
+                               (void*)handle->curattr + handle->curattr->length <= (void*)handle->attrbuf + ATTR_BUF_SIZE);
 
+               os_assert(curattr_stat->name.attr_length > 0);
                entry->d_name = ((char*)&curattr_stat->name) + curattr_stat->name.attr_dataoffset;
                /* attr_length includes the null terminator, but readdir's d_namlen doesn't. */
                entry->d_namlen = curattr_stat->name.attr_length - 1;
+               os_assert((void*)entry->d_name + curattr_stat->name.attr_length <= (void*)handle->attrbuf + ATTR_BUF_SIZE);
        } else {
                curattr_nostat = handle->curattr_nostat;
                handle->cur_entry++;
                handle->curattr_nostat = (attrListAttributes_nostat*)(((char*)curattr_nostat) + curattr_nostat->length);
+               os_assert((handle->cur_entry == handle->entry_count) ||
+                               (void*)handle->curattr + handle->curattr->length <= (void*)handle->attrbuf + ATTR_BUF_SIZE);
 
+               os_assert(curattr_nostat->name.attr_length > 0);
                entry->d_name = ((char*)&curattr_nostat->name) + curattr_nostat->name.attr_dataoffset;
                /* attr_length includes the null terminator, but readdir's d_namlen doesn't. */
                entry->d_namlen = curattr_nostat->name.attr_length - 1;
+               os_assert((void*)entry->d_name + curattr_nostat->name.attr_length <= (void*)handle->attrbuf + ATTR_BUF_SIZE);
        }
 
        int stat_type = 0;
@@ -907,6 +910,12 @@ read_dirent(dir_handle *handle, dir_entry *entry)
                        requiredFile &= ~ATTR_FILE_DEVTYPE;
                }
 
+               if ((curattr_stat->attrset.commonattr & ATTR_CMN_CRTIME) == 0) {
+                       /* Many (most?) file systems don't support create time (see vn_stat_noauth in xnu) */
+                       curattr_stat->st_birthtimespec.tv_sec = curattr_stat->st_birthtimespec.tv_nsec = 0;
+                       requiredCommon &= ~ ATTR_CMN_CRTIME;
+               }
+
                if ((curattr_stat->attrset.commonattr & requiredCommon) != requiredCommon ||
                                (curattr_stat->attrset.fileattr & requiredFile) != requiredFile) {
                        /* Some of our required attributes are missing. */
@@ -1410,7 +1419,7 @@ fts_sort(FTS *sp, FTSENT *head, int nitems)
 }
 
 static FTSENT *
-fts_alloc(FTS *sp, char *name, int namelen)
+fts_alloc(FTS *sp, char *name, ssize_t namelen)
 {
        FTSENT *p;
        size_t len;
@@ -1543,11 +1552,22 @@ fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
                ret = -1;
                goto bail;
        }
+       /*
+        * On Darwin this check causes us to not correctly descend into automounts,
+        * since the mount point and trigger will have a different devices and
+        * inodes.  It would be preferable to find a way to use
+        * ATTR_DIR_MOUNTSTATUS and DIR_MNTSTATUS_TRIGGER to detect these cases,
+        * but plumbing that through will be challenging.  Instead, will just
+        * disable it for now.
+        */
+#if 0
        if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
                errno = ENOENT;         /* disinformation */
                ret = -1;
                goto bail;
        }
+#endif
+
        ret = fchdir(newfd);
 bail:
        oerrno = errno;
index d40361429e776114065dc95e07f94490e6e8763a..25a1498483d3505b484b8697705a23a27aacfb16 100644 (file)
@@ -262,8 +262,8 @@ restart:
                goto restart;
 
        /* seq->first is already less than slot, so just leave it */
-       seq->count = e - b + 1;
-       seq->index = b;
+       seq->count = (int)(e - b + 1);
+       seq->index = (int)(b);
        /*
         * The fmt string contains the characters before the bracket, the
         * a format specifier (either decimal or hex) and any characters
index 71ad76c4434207ca28894aff757d6d00ea3a21fd..934707eefb81ddd96a735d693264d510bd3919e2 100644 (file)
@@ -52,7 +52,7 @@ void _init_clock_port(void) {
                abort();
        }
        
-       kr = semaphore_create(mach_task_self_, &clock_sem, SYNC_POLICY_FIFO, 0);
+       kr = semaphore_create(mach_task_self(), &clock_sem, SYNC_POLICY_FIFO, 0);
        if (kr != KERN_SUCCESS) {
                abort();
        }
index a4f7c537d5ecff83a9e1d71788c0941c65e0535c..817c043490d0ed79831e4cfcc7079c877ae70372 100644 (file)
@@ -62,6 +62,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
+#include <malloc_private.h>
 
 /* Stuff lifted from <a.out.h> and <sys/exec.h> since they are gone */
 /*
@@ -183,8 +184,8 @@ __fdnlist(fd, list)
                fh.nfat_arch = OSSwapBigToHostInt32(fh.nfat_arch);
 
                /* Read in the fat archs */
-               fat_archs = (struct fat_arch *)malloc(fh.nfat_arch *
-                                                     sizeof(struct fat_arch));
+               fat_archs = (struct fat_arch *)reallocarray(NULL, fh.nfat_arch,
+                               sizeof(struct fat_arch));
                if (fat_archs == NULL) {
                        return (-1);
                }
@@ -216,7 +217,6 @@ __fdnlist(fd, list)
                fap = cpusubtype_getbestarch(hbi.cpu_type, hbi.cpu_subtype,
                                             fat_archs, fh.nfat_arch);
 #else
-#warning       Use the cpusubtype functions!!!
                fap = NULL;
                for (i = 0; i < fh.nfat_arch; i++) {
                        if (fat_archs[i].cputype == hbi.cpu_type) {
index e6b98dfe2fae1b38421be804e92c72ad491edaee..0df9996c27028df27f20f1edae95bdf46132a441 100644 (file)
@@ -56,7 +56,6 @@
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)stat_flags.c       8.1 (Berkeley) 5/31/93";
-#else
 static const char rcsid[] =
   "$FreeBSD: src/lib/libc/gen/strtofflags.c,v 1.18.2.1 2000/06/28 01:52:24 joe Exp $";
 #endif
@@ -95,6 +94,7 @@ static struct {
        { "noopaque",           UF_OPAQUE,      0 },
        { "nohidden",           UF_HIDDEN,      0 },
        { "nocompressed",       UF_COMPRESSED,  0 },
+       { "nodatavault",        UF_DATAVAULT,   0 },
 };
 #define longestflaglen 12
 #define nmappings      (sizeof(mapping) / sizeof(mapping[0]))
index a87e257df57d48e9b5506dd3135be4839f0a7227..7e2d6383b8c6df92c23182a0803bc1cc78d34292 100644 (file)
@@ -55,7 +55,7 @@ sync_volume_np(const char *path, int flags) {
                full_sync |= FSCTL_SYNC_WAIT;
 
        terrno = errno;
-       rv = (fsctl(path, FSCTL_SYNC_VOLUME, &full_sync, 0) == -1) ? errno : 0;
+       rv = (fsctl(path, FSIOC_SYNC_VOLUME, &full_sync, 0) == -1) ? errno : 0;
        errno = terrno;
        return rv;
 }
index 10760654342474a6e38d31c3ba87b4c19bede3a6..53a7b5f2895d5e110bfd3911a9759c89e23bcfb2 100644 (file)
@@ -29,7 +29,7 @@
 #include <stdlib.h>
 #include "stack_logging.h"
 
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) 
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)
 #define FP_LINK_OFFSET 1
 #elif defined(__ppc__) || defined(__ppc64__)
 #define FP_LINK_OFFSET 2
@@ -40,7 +40,7 @@
 #define        INSTACK(a)      ((a) >= stackbot && (a) <= stacktop)
 #if defined(__ppc__) || defined(__ppc64__) || defined(__x86_64__)
 #define        ISALIGNED(a)    ((((uintptr_t)(a)) & 0xf) == 0)
-#elif defined(__arm__) 
+#elif defined(__arm__) || defined(__arm64__)
 #define        ISALIGNED(a)    ((((uintptr_t)(a)) & 0x1) == 0)
 #elif defined(__i386__)
 #define        ISALIGNED(a)    ((((uintptr_t)(a)) & 0xf) == 8)
@@ -68,7 +68,7 @@ _thread_stack_pcs(vm_address_t *buffer, unsigned max, unsigned *nb, unsigned ski
      * optimization).  We now inline the code to get the stack frame pointer,
      * so we are consistent about the stack frame.
      */
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) 
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)
     frame = __builtin_frame_address(0);
 #elif defined(__ppc__) || defined(__ppc64__)
     /* __builtin_frame_address IS BROKEN IN BEAKER: RADAR #2340421 */
index 485fa5dd158899d195f93d74bbe86e0ae4e9c5ef..d9e555a79c1444df40864fa9337745d1e2c1a8e9 100644 (file)
 #include <ttyent.h>
 #endif /* UTMP_COMPAT */
 
-#if ASL_API_VERSION < 20131108
-#include <asl_private.h>
-#include <asl_store.h>
-#endif
-
 __private_extern__ const char __utx_magic__[UTMPX_MAGIC] = __UTX_MAGIC__;
 
 extern const char _utmpx_vers[];       /* in utmpx.c */
 
-#if ASL_API_VERSION < 20131108
-static void msg2lastlogx(const aslmsg, struct lastlogx *);
-static void msg2utmpx(const aslmsg, struct utmpx *);
-static void utmpx2msg(const struct utmpx *, aslmsg);
-#else
 static void msg2lastlogx(asl_object_t, struct lastlogx *);
 static void msg2utmpx(asl_object_t, struct utmpx *);
 static void utmpx2msg(const struct utmpx *, asl_object_t);
-#endif
 
 static size_t pw_size = 0;
 
@@ -85,6 +74,9 @@ static size_t pw_size = 0;
 /* indirection causes argument to be substituted before stringification */
 #define STR(x)         __STRING(x)
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
 #ifdef UTMP_COMPAT
 static char *
 _pwnam_r(const char *user, struct passwd *pw)
@@ -149,27 +141,12 @@ getlastlogx(uid_t uid, struct lastlogx *lx)
 struct lastlogx *
 getlastlogxbyname(const char *user, struct lastlogx *lx)
 {
-#if ASL_API_VERSION < 20131108
-       aslmsg m;
-       asl_msg_t *qm[1];
-       asl_search_result_t query, *res;
-       uint32_t status;
-       asl_store_t *store = NULL;
-       uint64_t cmax;
-#else
        asl_object_t m, query, res;
        size_t cmax;
-#endif
        struct lastlogx *result = NULL;
 
        if (!user || !*user) return NULL;
 
-#if ASL_API_VERSION < 20131108
-       status = asl_store_open_read(NULL, &store);
-       if (status != 0) return NULL;
-       if (store == NULL) return NULL;
-#endif
-
        /*
         * We search for the last LASTLOG_FACILITY entry that has the
         * ut_user entry matching the user's name.
@@ -177,20 +154,12 @@ getlastlogxbyname(const char *user, struct lastlogx *lx)
        m = asl_new(ASL_TYPE_QUERY);
        if (m == NULL)
        {
-#if ASL_API_VERSION < 20131108
-               asl_store_close(store);
-#endif
                return NULL;
        }
 
        asl_set_query(m, FACILITY, LASTLOG_FACILITY, ASL_QUERY_OP_EQUAL);
        asl_set_query(m, "ut_user", user, ASL_QUERY_OP_EQUAL);
 
-#if ASL_API_VERSION < 20131108
-       qm[0] = (asl_msg_t *)m;
-       query.count = 1;
-       query.msg = qm;
-#else
        query = asl_new(ASL_TYPE_LIST);
        if (query == NULL)
        {
@@ -200,35 +169,20 @@ getlastlogxbyname(const char *user, struct lastlogx *lx)
 
        asl_append(query, m);
        asl_release(m);
-#endif
 
        res = NULL;
        cmax = 0;
 
-#if ASL_API_VERSION < 20131108
-       asl_store_match_timeout(store, &query, &res, &cmax, -1, 1, -1, ASL_QUERY_TIMEOUT);
-       asl_store_close(store);
-       asl_free(m);
-#else
        res = asl_match(NULL, query, &cmax, -1, 1, ASL_QUERY_TIMEOUT, ASL_MATCH_DIRECTION_REVERSE);
        asl_release(query);
-#endif
 
        if (res == NULL) return NULL;
 
-#if ASL_API_VERSION < 20131108
-       m = aslresponse_next(res);
-#else
        m = asl_next(res);
-#endif
 
        if (m == NULL)
        {
-#if ASL_API_VERSION < 20131108
-               aslresponse_free(res);
-#else
                asl_release(res);
-#endif
                return NULL;
        }
 
@@ -236,39 +190,28 @@ getlastlogxbyname(const char *user, struct lastlogx *lx)
        {
                if ((lx = (struct lastlogx *)malloc(sizeof(*lx))) == NULL)
                {
-#if ASL_API_VERSION < 20131108
-                       aslresponse_free(res);
-#else
                        asl_release(res);
-#endif
                        return NULL;
                }
        }
 
        msg2lastlogx(m, lx);
-#if ASL_API_VERSION < 20131108
-       aslresponse_free(res);
-#else
        asl_release(res);
-#endif
        result = lx;
 
        return result;
 }
 
-#define IGET(e,p)      if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
-                               u->p##_##e = strtol(cp, NULL, 10);
-#define LGET(e,p)      IGET(e,p)
-#define SGET(e,p)      if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
-                               strncpy(u->p##_##e, cp, sizeof(u->p##_##e))
+#define IGET(e,p)      do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
+                               u->p##_##e = (int)strtol(cp, NULL, 10); } while (0)
+#define LGET(e,p)      do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
+                               u->p##_##e = strtol(cp, NULL, 10); } while (0)
+#define SGET(e,p)      do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
+                               strncpy(u->p##_##e, cp, sizeof(u->p##_##e)); } while (0)
 
 /* fill in a struct lastlogx from an ASL message */
 static void
-#if ASL_API_VERSION < 20131108
-msg2lastlogx(const aslmsg m, struct lastlogx *u)
-#else
 msg2lastlogx(asl_object_t m, struct lastlogx *u)
-#endif
 {
        const char *cp;
 
@@ -281,11 +224,7 @@ msg2lastlogx(asl_object_t m, struct lastlogx *u)
 
 /* fill in a struct utmpx from an ASL message */
 static void
-#if ASL_API_VERSION < 20131108
-msg2utmpx(aslmsg m, struct utmpx *u)
-#else
 msg2utmpx(asl_object_t m, struct utmpx *u)
-#endif
 {
        const char *cp;
 
@@ -302,11 +241,7 @@ msg2utmpx(asl_object_t m, struct utmpx *u)
 
 /* fill in an ASL message from a struct utmpx */
 static void
-#if ASL_API_VERSION < 20131108
-utmpx2msg(const struct utmpx *u, aslmsg m)
-#else
 utmpx2msg(const struct utmpx *u, asl_object_t m)
-#endif
 {
        char buf[_UTX_HOSTSIZE + 1];    /* the largest string in struct utmpx */
        const char *cp;
@@ -359,23 +294,14 @@ static const char *utmpx_types[] = {
 __private_extern__ void
 _utmpx_asl(const struct utmpx *u)
 {
-#if ASL_API_VERSION < 20131108
-       aslclient asl = asl_open(NULL, NULL, ASL_OPT_NO_REMOTE); /* could be NULL, but still works */
-       aslmsg m;
-#else
        asl_object_t asl = asl_open(NULL, NULL, ASL_OPT_NO_REMOTE);
        asl_object_t m;
-#endif
        char msg[64];
 
        if (u->ut_type == EMPTY)
                return;
        if ((m = asl_new(ASL_TYPE_MSG)) == NULL) {
-#if ASL_API_VERSION < 20131108
-               asl_close(asl);
-#else
                asl_release(asl);
-#endif
                return;
        }
        /*
@@ -416,13 +342,8 @@ _utmpx_asl(const struct utmpx *u)
        }
        asl_set(m, ASL_KEY_MSG, msg);
        asl_send(asl, m);
-#if ASL_API_VERSION < 20131108
-       asl_free(m);
-       asl_close(asl);
-#else
        asl_release(m);
        asl_release(asl);
-#endif
 }
 
 #define UT_USER        (1 << 0)
@@ -506,7 +427,7 @@ _utmpx_working_copy(const struct utmpx *utx, struct utmpx *temp, int onlyid)
        /* UT_ID is set only if we already know we need to add it */
        if ((which & UT_ID)) {
                char *cp;
-               int i = sizeof(temp->ut_line);
+               ssize_t i = sizeof(temp->ut_line);
 
                for(cp = temp->ut_line; i > 0 && *cp; i--)
                        cp++;
@@ -560,11 +481,7 @@ static struct {
 static struct {
        uint64_t start;
        int dir;
-#if ASL_API_VERSION < 20131108
-       asl_search_result_t *res;
-#else
        asl_object_t res;
-#endif
        char *str;
        uint32_t len;
        char inited;
@@ -657,11 +574,7 @@ end_asl(void)
 {
        if (wtmp_asl.res != NULL)
        {
-#if ASL_API_VERSION < 20131108
-               aslresponse_free(wtmp_asl.res);
-#else
                asl_release(wtmp_asl.res);
-#endif
                wtmp_asl.res = NULL;
        }
 
@@ -685,28 +598,16 @@ end_file(void)
 static struct utmpx *
 get_asl(void)
 {
-#if ASL_API_VERSION < 20131108
-       aslmsg m;
-#else
        asl_object_t m;
-#endif
        static struct utmpx utx;
 
        if (wtmp_asl.inited == 0) set_asl(-1);
        if (wtmp_asl.done != 0) return NULL;
 
-#if ASL_API_VERSION < 20131108
-       m = aslresponse_next(wtmp_asl.res);
-#else
        m = asl_next(wtmp_asl.res);
-#endif
        if (m == NULL)
        {
-#if ASL_API_VERSION < 20131108
-               aslresponse_free(wtmp_asl.res);
-#else
                asl_release(wtmp_asl.res);
-#endif
                wtmp_asl.res = NULL;
                wtmp_asl.done = 1;
                return NULL;
@@ -811,17 +712,8 @@ _set_dir(int forward)
 static void
 set_asl(int forward)
 {
-#if ASL_API_VERSION < 20131108
-       aslmsg q0, q1;
-       asl_msg_t *m[2];
-       asl_search_result_t query;
-       asl_store_t *store = NULL;
-       uint32_t status;
-       uint64_t cmax;
-#else
        asl_object_t q0, q1, query;
        size_t cmax;
-#endif
 
        _set_dir(forward);
 
@@ -830,20 +722,10 @@ set_asl(int forward)
 
        if (wtmp_asl.res != NULL)
        {
-#if ASL_API_VERSION < 20131108
-               aslresponse_free(wtmp_asl.res);
-#else
                asl_release(wtmp_asl.res);
-#endif
                wtmp_asl.res = NULL;
        }
 
-#if ASL_API_VERSION < 20131108
-       status = asl_store_open_read(NULL, &store);
-       if (status != 0) return;
-       if (store == NULL) return;
-#endif
-
        /*
         * Create a search query that matches either UTMPX_FACILITY
         * or LASTLOG_FACILITY.
@@ -856,22 +738,12 @@ set_asl(int forward)
        q1 = asl_new(ASL_TYPE_QUERY);
        if (q1 == NULL)
        {
-#if ASL_API_VERSION < 20131108
-               asl_free(q0);
-#else
                asl_release(q0);
-#endif
                return;
        }
 
        asl_set_query(q1, FACILITY, LASTLOG_FACILITY, ASL_QUERY_OP_EQUAL);
 
-#if ASL_API_VERSION < 20131108
-       m[0] = (asl_msg_t *)q0;
-       m[1] = (asl_msg_t *)q1;
-       query.count = 2;
-       query.msg = m;
-#else
        query = asl_new(ASL_TYPE_LIST);
        if (query == NULL)
        {
@@ -885,19 +757,11 @@ set_asl(int forward)
 
        asl_release(q0);
        asl_release(q1);
-#endif
 
        cmax = 0;
 
-#if ASL_API_VERSION < 20131108
-       asl_store_match_timeout(store, &query, &(wtmp_asl.res), &cmax, wtmp_asl.start, 0, wtmp_asl.dir, ASL_QUERY_TIMEOUT);
-       asl_store_close(store);
-       asl_free(q0);
-       asl_free(q1);
-#else
        wtmp_asl.res = asl_match(NULL, query, &cmax, wtmp_asl.start, 0, ASL_QUERY_TIMEOUT, wtmp_asl.dir);
        asl_release(query);
-#endif
        
        if (wtmp_asl.res == NULL) return;
 
@@ -1325,3 +1189,5 @@ _closeutx(utmpx_t u)
        free(U);
        return 0;
 }
+
+#pragma clang diagnostic pop
index 63402831aef0d0b71764d8c8c2ef086e6acb4e9d..83cd510175e1ff29ad915d7a5c4f177059dfa446 100644 (file)
@@ -25,6 +25,7 @@
 #define __TYPES_H_
 
 #include <sys/_types.h>
+#include <machine/_types.h> /* __uint32_t */
 
 #if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7
 #define __strfmonlike(fmtarg, firstvararg) \
index ca4531eaf1eb1a5c14162df1f4f3f3187d087ca8..4339653ce102046a05b2cff715f1bd78443dcdf6 100644 (file)
@@ -28,5 +28,6 @@
 
 #ifndef _NL_ITEM
 #define _NL_ITEM 
+#include <_types.h>
 typedef __darwin_nl_item nl_item;
 #endif /* _NL_ITEM */
\ No newline at end of file
index 1d3df0b2fa025ad410d865d14c11abbf779db784..2b664352ff3f5e085a2174a8d43802564af26f0a 100644 (file)
@@ -28,5 +28,6 @@
 
 #ifndef _WCTRANS_T 
 #define _WCTRANS_T 
+#include <_types.h>
 typedef        __darwin_wctrans_t wctrans_t;
 #endif /* _WCTRANS_T */
\ No newline at end of file
index 650ebc4ac5992b369b07fc9136d7e96b31eed514..8d76a5d7239ed99e3e62bda2267dac2f65a1e2b7 100644 (file)
@@ -28,5 +28,6 @@
 
 #ifndef _WCTYPE_T
 #define _WCTYPE_T 
+#include <_types.h>
 typedef __darwin_wctype_t wctype_t;
 #endif /* _WCTYPE_T */
\ No newline at end of file
index 67ae0fd6a729c90e6daab1a06f92efa6ace93d7c..7c81e755e95ee53816916bc356444bd89a9f2af0 100644 (file)
@@ -73,7 +73,7 @@ __END_DECLS
 #else /* __GNUC__ */
 
 __BEGIN_DECLS
-void __assert_rtn(const char *, const char *, int, const char *) __dead2;
+void __assert_rtn(const char *, const char *, int, const char *) __dead2 __disable_tail_calls;
 #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) < 1070)
 void __eprintf(const char *, const char *, unsigned, const char *) __dead2;
 #endif
index bd84e6d2c63341509b1b64c0b421bc94a33fd9dc..c105526bfc6002d73e7dd7c3f27b2c1b29d80052 100644 (file)
@@ -65,6 +65,7 @@
 #include <sys/dirent.h>
 #include <sys/cdefs.h>
 #include <Availability.h>
+#include <sys/_pthread/_pthread_types.h> /* __darwin_pthread_mutex_t */
 
 struct _telldir;               /* forward reference */
 
@@ -76,7 +77,7 @@ typedef struct {
        char    *__dd_buf;      /* data buffer */
        int     __dd_len;       /* size of data buffer */
        long    __dd_seek;      /* magic cookie returned */
-       long    __dd_rewind;    /* magic cookie for rewinding */
+       __unused long   __padding; /* (__dd_rewind space left for bincompat) */
        int     __dd_flags;     /* flags for readdir */
        __darwin_pthread_mutex_t __dd_lock; /* for thread locking */
        struct _telldir *__dd_td; /* telldir position recording */
@@ -92,6 +93,7 @@ typedef struct {
 #define DTF_NODUP      0x0002  /* don't return duplicate names */
 #define DTF_REWIND     0x0004  /* rewind after reading union stack */
 #define __DTF_READALL  0x0008  /* everything has been read */
+#define        __DTF_SKIPREAD  0x0010  /* assume internal buffer is populated */
 
 #endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
 
index 7e90bd9122fff02d8775c91fa6533cb3846d4490..d0ccc2786e645e102389e04c73f30a85057f705f 100644 (file)
@@ -51,6 +51,8 @@
 #define kFSSubTypeKey                "FSSubType"
 #define kFSXMLOutputArgumentKey      "FSXMLOutputArgument"
 
+#define kFSEncryptNameKey                       "FSEncryptionName"
+       /* Deprecated - use kFSEncryptNameKey for HFS/APFS */
 #define        kFSCoreStorageEncryptNameKey "FSCoreStorageEncryptionName"
 
 #endif /* _FSPROPERTIES_H_ */
index 06314af3170f60774c9f040b04a442f8d5c6416c..4f2b6843be3e262b1e1a6736cdecf5aa50bf7a4c 100644 (file)
  * 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
+ * 3. 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.
  *
index b7d202d2727144a2522f2a942eacc21a326293c8..2ed444e09d12e7254f242bf5322eb2a70ec0fee3 100644 (file)
 
 #define PTHREAD_DESTRUCTOR_ITERATIONS  4
 #define PTHREAD_KEYS_MAX               512
-#if defined(__arm__) 
+#if defined(__arm__) || defined(__arm64__)
 #define PTHREAD_STACK_MIN              16384
 #else
 #define PTHREAD_STACK_MIN              8192
index c1ff94b1040f0ca42db7047c60c9cbe4938742d6..08e228d6ad74d26fde9de66640395a5c47929331 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2007,2017 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
 #ifndef _SECURE__STRING_H_
 #define _SECURE__STRING_H_
 
-#include <Availability.h>
 #include <sys/cdefs.h>
+#include <Availability.h>
 #include <secure/_common.h>
 
 #if _USE_FORTIFY_LEVEL > 0
 
-#ifndef __has_builtin
-#define _undef__has_builtin
-#define __has_builtin(x) 0
-#endif
-
 /* <rdar://problem/12622659> */
 #if defined(__clang__) && \
-    ((defined(__apple_build_version__) && __apple_build_version__ >= 4260006) || \
-     (!defined(__apple_build_version__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 3))))
+               ((defined(__apple_build_version__) && __apple_build_version__ >= 4260006) || \
+               (!defined(__apple_build_version__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 3))))
 #define __HAS_FIXED_CHK_PROTOTYPES 1
 #else
 #define __HAS_FIXED_CHK_PROTOTYPES 0
 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
 #if __has_builtin(__builtin___memccpy_chk) && __HAS_FIXED_CHK_PROTOTYPES
 #undef memccpy
-#define memccpy(dest, src, c, len)                                  \
-  __builtin___memccpy_chk (dest, src, c, len, __darwin_obsz0 (dest))
+/* void *memccpy(void *dst, const void *src, int c, size_t n) */
+#define memccpy(dest, ...) \
+               __builtin___memccpy_chk (dest, __VA_ARGS__, __darwin_obsz0 (dest))
 #endif
 #endif
 
 #if __has_builtin(__builtin___memcpy_chk) || defined(__GNUC__)
 #undef memcpy
-#define memcpy(dest, src, len)                                 \
-  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
+/* void *memcpy(void *dst, const void *src, size_t n) */
+#define memcpy(dest, ...) \
+               __builtin___memcpy_chk (dest, __VA_ARGS__, __darwin_obsz0 (dest))
 #endif
 
 #if __has_builtin(__builtin___memmove_chk) || defined(__GNUC__)
 #undef memmove
-#define memmove(dest, src, len)                                        \
-  __builtin___memmove_chk (dest, src, len, __darwin_obsz0 (dest))
+/* void *memmove(void *dst, const void *src, size_t len) */
+#define memmove(dest, ...) \
+               __builtin___memmove_chk (dest, __VA_ARGS__, __darwin_obsz0 (dest))
 #endif
 
 #if __has_builtin(__builtin___memset_chk) || defined(__GNUC__)
 #undef memset
-#define memset(dest, val, len)                                 \
-  __builtin___memset_chk (dest, val, len, __darwin_obsz0 (dest))
+/* void *memset(void *b, int c, size_t len) */
+#define memset(dest, ...) \
+               __builtin___memset_chk (dest, __VA_ARGS__, __darwin_obsz0 (dest))
 #endif
 
 #if __has_builtin(__builtin___strcpy_chk) || defined(__GNUC__)
 #undef strcpy
-#define strcpy(dest, src)                                      \
-  __builtin___strcpy_chk (dest, src, __darwin_obsz (dest))
+/* char *strcpy(char *dst, const char *src) */
+#define strcpy(dest, ...) \
+               __builtin___strcpy_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
 #endif
 
 #if __DARWIN_C_LEVEL >= 200809L
 #if __has_builtin(__builtin___stpcpy_chk) || defined(__GNUC__)
 #undef stpcpy
-#define stpcpy(dest, src)                                      \
-  __builtin___stpcpy_chk (dest, src, __darwin_obsz (dest))
+/* char *stpcpy(char *dst, const char *src) */
+#define stpcpy(dest, ...) \
+               __builtin___stpcpy_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
 #endif
 
 #if __has_builtin(__builtin___stpncpy_chk) || __APPLE_CC__ >= 5666 || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
 #undef stpncpy
-#define stpncpy(dest, src, len)                                        \
-  __builtin___stpncpy_chk (dest, src, len, __darwin_obsz (dest))
+/* char *stpncpy(char *dst, const char *src, size_t n) */
+#define stpncpy(dest, ...) \
+               __builtin___stpncpy_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
 #endif
 #endif /* _DARWIN_C_LEVEL >= 200809L */
 
 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
 #if __has_builtin(__builtin___strlcpy_chk) && __HAS_FIXED_CHK_PROTOTYPES
 #undef strlcpy
-#define strlcpy(dest, src, len)                                 \
-  __builtin___strlcpy_chk (dest, src, len, __darwin_obsz (dest))
+/* size_t strlcpy(char *dst, const char *source, size_t size) */
+#define strlcpy(dest, ...) \
+               __builtin___strlcpy_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
 #endif
 
 #if __has_builtin(__builtin___strlcat_chk) && __HAS_FIXED_CHK_PROTOTYPES
 #undef strlcat
-#define strlcat(dest, src, len)                                 \
-  __builtin___strlcat_chk (dest, src, len, __darwin_obsz (dest))
+/* size_t strlcat(char *dst, const char *source, size_t size) */
+#define strlcat(dest, ...) \
+               __builtin___strlcat_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
 #endif
 #endif /* __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 */
 #endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
 
 #if __has_builtin(__builtin___strncpy_chk) || defined(__GNUC__)
 #undef strncpy
-#define strncpy(dest, src, len)                                        \
-  __builtin___strncpy_chk (dest, src, len, __darwin_obsz (dest))
+/* char *strncpy(char *dst, const char *src, size_t n) */
+#define strncpy(dest, ...) \
+               __builtin___strncpy_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
 #endif
 
 #if __has_builtin(__builtin___strcat_chk) || defined(__GNUC__)
 #undef strcat
-#define strcat(dest, src)                                      \
-  __builtin___strcat_chk (dest, src, __darwin_obsz (dest))
+/* char *strcat(char *s1, const char *s2) */
+#define strcat(dest, ...) \
+               __builtin___strcat_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
 #endif
 
 #if ! (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 32000)
 #if __has_builtin(__builtin___strncat_chk) || defined(__GNUC__)
 #undef strncat
-#define strncat(dest, src, len)                                        \
-  __builtin___strncat_chk (dest, src, len, __darwin_obsz (dest))
-#endif
+/* char *strncat(char *s1, const char *s2, size_t n) */
+#define strncat(dest, ...) \
+               __builtin___strncat_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
 #endif
-
-#ifdef _undef__has_builtin
-#undef _undef__has_builtin
-#undef __has_builtin
 #endif
 
 #undef __HAS_FIXED_CHK_PROTOTYPES
diff --git a/include/secure/_strings.h b/include/secure/_strings.h
new file mode 100644 (file)
index 0000000..9069e59
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * 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 _STRINGS_H_
+# error "Never use <secure/_strings.h> directly; include <strings.h> instead."
+#endif
+
+#ifndef _SECURE__STRINGS_H_
+#define _SECURE__STRINGS_H_
+
+#include <sys/cdefs.h>
+#include <Availability.h>
+#include <secure/_common.h>
+
+#if _USE_FORTIFY_LEVEL > 0
+
+/* bcopy and bzero */
+
+/* Removed in Issue 7 */
+#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200809L
+
+#if __has_builtin(__builtin___memmove_chk) || defined(__GNUC__)
+#undef bcopy
+/* void        bcopy(const void *src, void *dst, size_t len) */
+#define bcopy(src, dest, ...) \
+               __builtin___memmove_chk (dest, src, __VA_ARGS__, __darwin_obsz0 (dest))
+#endif
+
+#if __has_builtin(__builtin___memset_chk) || defined(__GNUC__)
+#undef bzero
+/* void        bzero(void *s, size_t n) */
+#define bzero(dest, ...) \
+               __builtin___memset_chk (dest, 0, __VA_ARGS__, __darwin_obsz0 (dest))
+#endif
+
+#endif
+
+#endif /* _USE_FORTIFY_LEVEL > 0 */
+#endif /* _SECURE__STRINGS_H_ */
index c0e570a9942899fe401b5d236e2ea1474b2eb36e..b4f027e3c1c40c1d769ab21f48430d98a24734a1 100644 (file)
@@ -61,6 +61,10 @@ typedef uint64_t        uint_fast64_t;
 /* 7.18.2 Limits of specified-width integer types:
  *   These #defines specify the minimum and maximum limits
  *   of each of the types declared above.
+ *
+ *   They must have "the same type as would an expression that is an
+ *   object of the corresponding type converted according to the integer
+ *   promotion".
  */
 
 
@@ -121,17 +125,16 @@ typedef uint64_t        uint_fast64_t;
 /* 7.18.2.4 Limits of integer types capable of holding object pointers */
 
 #if __WORDSIZE == 64
-#define INTPTR_MIN       INT64_MIN
-#define INTPTR_MAX       INT64_MAX
+#define INTPTR_MAX        9223372036854775807L
 #else
-#define INTPTR_MIN        INT32_MIN
-#define INTPTR_MAX        INT32_MAX
+#define INTPTR_MAX        2147483647L
 #endif
+#define INTPTR_MIN        (-INTPTR_MAX-1)
 
 #if __WORDSIZE == 64
-#define UINTPTR_MAX      UINT64_MAX
+#define UINTPTR_MAX       18446744073709551615UL
 #else
-#define UINTPTR_MAX       UINT32_MAX
+#define UINTPTR_MAX       4294967295UL
 #endif
 
 /* 7.18.2.5 Limits of greatest-width integer types */
@@ -149,11 +152,7 @@ typedef uint64_t        uint_fast64_t;
 #define PTRDIFF_MAX       INT32_MAX
 #endif
 
-#if __WORDSIZE == 64
-#define SIZE_MAX         UINT64_MAX
-#else
-#define SIZE_MAX          UINT32_MAX
-#endif
+#define SIZE_MAX          UINTPTR_MAX
 
 #if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1
 #define RSIZE_MAX         (SIZE_MAX >> 1)
@@ -191,8 +190,8 @@ typedef uint64_t        uint_fast64_t;
 #define INT32_C(v)   (v)
 #define INT64_C(v)   (v ## LL)
 
-#define UINT8_C(v)   (v ## U)
-#define UINT16_C(v)  (v ## U)
+#define UINT8_C(v)   (v)
+#define UINT16_C(v)  (v)
 #define UINT32_C(v)  (v ## U)
 #define UINT64_C(v)  (v ## ULL)
 
index d0cf7a50c15029ba0b3e3cf4ef7900e11a469879..a9b35cd734be237914e16392da3165ef42da2a34 100644 (file)
@@ -503,6 +503,8 @@ int dprintf(int, const char * __restrict, ...) __printflike(2, 3) __OSX_AVAILABL
 int    vdprintf(int, const char * __restrict, va_list) __printflike(2, 0) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
 ssize_t getdelim(char ** __restrict __linep, size_t * __restrict __linecapp, int __delimiter, FILE * __restrict __stream) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
 ssize_t getline(char ** __restrict __linep, size_t * __restrict __linecapp, FILE * __restrict __stream) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
+FILE *fmemopen(void * __restrict __buf, size_t __size, const char * __restrict __mode) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
+FILE *open_memstream(char **__bufp, size_t *__sizep) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
 __END_DECLS
 #endif /* __DARWIN_C_LEVEL >= 200809L */
 
index c04d3a7edb5c99eb0d008b190a1b0e2a2fa7f346..a8e5d8d56112253914f7923e8db70d160ac087c4 100644 (file)
@@ -129,6 +129,14 @@ extern int __mb_cur_max;
 #define LIBC_ABORT(f,...)      abort_report_np("%s:%s:%u: " f, __FILE__, __func__, __LINE__, ## __VA_ARGS__)
 //End-Libc
 
+#ifndef __alloc_size
+#if __has_attribute(alloc_size)
+#define __alloc_size(...) __attribute__((alloc_size(__VA_ARGS__)))
+#else
+#define __alloc_size(...)
+#endif
+#endif // __alloc_size
+
 __BEGIN_DECLS
 void    abort(void) __dead2;
 int     abs(int) __pure2;
@@ -142,7 +150,7 @@ long long
 #endif /* !__DARWIN_NO_LONG_LONG */
 void   *bsearch(const void *__key, const void *__base, size_t __nel,
            size_t __width, int (* _Nonnull __compar)(const void *, const void *));
-void   *calloc(size_t __count, size_t __size) __result_use_check;
+void   *calloc(size_t __count, size_t __size) __result_use_check __alloc_size(1,2);
 div_t   div(int, int) __pure2;
 void    exit(int) __dead2;
 void    free(void *);
@@ -154,7 +162,7 @@ long long
         llabs(long long);
 lldiv_t         lldiv(long long, long long);
 #endif /* !__DARWIN_NO_LONG_LONG */
-void   *malloc(size_t __size) __result_use_check;
+void   *malloc(size_t __size) __result_use_check __alloc_size(1);
 int     mblen(const char *__s, size_t __n);
 size_t  mbstowcs(wchar_t * __restrict , const char * __restrict, size_t);
 int     mbtowc(wchar_t * __restrict, const char * __restrict, size_t);
@@ -162,7 +170,7 @@ int          posix_memalign(void **__memptr, size_t __alignment, size_t __size) __OSX_A
 void    qsort(void *__base, size_t __nel, size_t __width,
            int (* _Nonnull __compar)(const void *, const void *));
 int     rand(void) __swift_unavailable("Use arc4random instead.");
-void   *realloc(void *__ptr, size_t __size) __result_use_check;
+void   *realloc(void *__ptr, size_t __size) __result_use_check __alloc_size(2);
 void    srand(unsigned) __swift_unavailable("Use arc4random instead.");
 double  strtod(const char *, char **) __DARWIN_ALIAS(strtod);
 float   strtof(const char *, char **) __DARWIN_ALIAS(strtof);
@@ -190,7 +198,7 @@ unsigned long long
 #endif
 
 __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable")
-__OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0,__MAC_NA,__IPHONE_2_0,__IPHONE_8_0, "Use posix_spawn APIs instead.")
+__API_AVAILABLE(macos(10.0)) __IOS_PROHIBITED
 __WATCHOS_PROHIBITED __TVOS_PROHIBITED
 int     system(const char *) __DARWIN_ALIAS_C(system);
 //Begin-Libc
@@ -384,7 +392,7 @@ int  sradixsort(const unsigned char **__base, int __nel, const unsigned char *__
            unsigned __endbyte);
 void    sranddev(void);
 void    srandomdev(void);
-void   *reallocf(void *__ptr, size_t __size);
+void   *reallocf(void *__ptr, size_t __size) __alloc_size(2);
 #if !__DARWIN_NO_LONG_LONG
 long long
         strtoq(const char *__str, char **__endptr, int __base);
@@ -392,7 +400,7 @@ unsigned long long
         strtouq(const char *__str, char **__endptr, int __base);
 #endif /* !__DARWIN_NO_LONG_LONG */
 extern char *suboptarg;                /* getsubopt(3) external variable */
-void   *valloc(size_t);
+void   *valloc(size_t) __alloc_size(1);
 #endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */
 
 /* Poison the following routines if -fshort-wchar is set */
index 93d545c04e3429d08985ed9f3f038776c43604a2..6fe4b8d6f1983c3252fc552056779430c18cadfc 100644 (file)
@@ -175,10 +175,8 @@ char       *strsep(char **__stringp, const char *__delim);
 /* SUS places swab() in unistd.h.  It is listed here for source compatibility */
 void    swab(const void * __restrict, void * __restrict, ssize_t);
 
-#ifndef __CUDACC__
 __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1)
 __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1)
-#endif
 int    timingsafe_bcmp(const void *__b1, const void *__b2, size_t __len);
 __END_DECLS
 
index 0c59530a22796555dbfec919ea7dcb6c9ba088d2..c0e915f8ac35949d5f29ac8a6904b8ea17679ec1 100644 (file)
@@ -92,5 +92,10 @@ __END_DECLS
 #include <string.h>
 #endif
 
+#if defined (__GNUC__) && _FORTIFY_SOURCE > 0 && !defined (__cplusplus)
+/* Security checking functions.  */
+#include <secure/_strings.h>
+#endif
+
 #endif  /* _STRINGS_H_ */
 
index cf18a94775ba74607b0da240c4866df6a1e1751d..451bb22f0664afc23e20522b1ef42de71b0a5ca5 100644 (file)
@@ -34,7 +34,7 @@
  */
 #include_next <sys/cdefs.h>
 #ifndef _LIBC_NO_FEATURE_VERIFICATION
-#if defined(__arm__) || defined(__i386__) || defined(__x86_64__)
+#if defined(__arm64__) || defined(__arm__) || defined(__i386__) || defined(__x86_64__)
 #  include "libc-features.h"
 #else
 #  error "Unknown architecture."
index e74b017a422deb175c5a5578c8d2cf657afbadb0..b57f32e11e66babd7640c06842de09866f0424fc 100644 (file)
@@ -52,9 +52,16 @@ __BEGIN_DECLS
 #define RB_TREE_FOREACH(N, T) \
     for ((N) = RB_TREE_MIN(T); (N); \
        (N) = rb_tree_iterate((T), (N), RB_DIR_RIGHT))
+#define RB_TREE_FOREACH_SAFE(N, T, TVAR) \
+    for ((N) = RB_TREE_MIN(T); (N) && ((TVAR) = rb_tree_iterate((T), (N), RB_DIR_RIGHT)); \
+       (N) = (TVAR))
 #define RB_TREE_FOREACH_REVERSE(N, T) \
     for ((N) = RB_TREE_MAX(T); (N); \
        (N) = rb_tree_iterate((T), (N), RB_DIR_LEFT))
+#define RB_TREE_FOREACH_REVERSE_SAFE(N, T, TVAR) \
+    for ((N) = RB_TREE_MAX(T); (N) && ((TVAR) = rb_tree_iterate((T), (N), RB_DIR_LEFT)); \
+       (N) = (TVAR))
+
 
 /*
  * rbto_compare_nodes_fn:
index dedea0b79fcc4b11629c724d4b523caff6c19d28..51442efdb286eec2ff7819bf85a7b66f29249b2a 100644 (file)
@@ -81,7 +81,7 @@ struct tm {
        int     tm_wday;        /* days since Sunday [0-6] */
        int     tm_yday;        /* days since January 1 [0-365] */
        int     tm_isdst;       /* Daylight Savings Time flag */
-       long    tm_gmtoff;      /* offset from CUT in seconds */
+       long    tm_gmtoff;      /* offset from UTC in seconds */
        char    *tm_zone;       /* timezone abbreviation */
 };
 
index 43842478b1198b3bc363cd39c019a70299787f57..7896f8d2aae8d05ed7575f20a4871b8e0e1b3ccb 100644 (file)
@@ -839,10 +839,22 @@ int        mkostemps(char *path, int slen, int oflags)
 int     mkstemp_dprotected_np(char *path, int dpclass, int dpflags)
                __OSX_UNAVAILABLE __IOS_AVAILABLE(10.0)
                __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0);
+char   *mkdtempat_np(int dfd, char *path)
+               __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0)
+               __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0);
+int     mkstempsat_np(int dfd, char *path, int slen)
+               __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0)
+               __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0);
+int     mkostempsat_np(int dfd, char *path, int slen, int oflags)
+               __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0)
+               __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0);
 int     nfssvc(int, void *);
 int     profil(char *, size_t, unsigned long, unsigned int);
+
+__deprecated_msg("Use of per-thread security contexts is error-prone and discouraged.")
 int     pthread_setugid_np(uid_t, gid_t);
 int     pthread_getugid_np( uid_t *, gid_t *);
+
 int     reboot(int);
 int     revoke(const char *);
 
@@ -950,7 +962,10 @@ int        setattrlist(const char*,void*,void*,size_t,unsigned long) __DARWIN_ALIAS(set
 int    setattrlist(const char*,void*,void*,size_t,unsigned long) LIBC_ALIAS(setattrlist);
 #endif /* !LIBC_ALIAS_SETATTRLIST */
 //End-Libc
-int exchangedata(const char*,const char*,unsigned long) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
+int exchangedata(const char*,const char*,unsigned long)
+               __OSX_DEPRECATED(10.0, 10.13, "use renamex_np with the RENAME_SWAP flag")
+               __IOS_DEPRECATED(2.0, 11.0, "use renamex_np with the RENAME_SWAP flag")
+               __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
 int    getdirentriesattr(int,void*,void*,size_t,unsigned long*,unsigned long*,unsigned long*,unsigned long) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
 
 #endif /* __LP64__ */
index bd16be11f00ae17c64e3598abd654ef3130f641d..1e514ae37432a3becb4d12be0b44b34bf5971930 100644 (file)
@@ -211,6 +211,7 @@ int     wcsncasecmp(const wchar_t *, const wchar_t *, size_t n) __OSX_AVAILABLE_
 size_t  wcsnlen(const wchar_t *, size_t) __pure __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
 size_t  wcsnrtombs(char * __restrict, const wchar_t ** __restrict, size_t,
             size_t, mbstate_t * __restrict);
+FILE *open_wmemstream(wchar_t ** __bufp, size_t * __sizep) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
 __END_DECLS
 #endif /* __DARWIN_C_LEVEL >= 200809L */
 
diff --git a/libdarwin/AppleInternalVariant.plist b/libdarwin/AppleInternalVariant.plist
new file mode 100644 (file)
index 0000000..554c06f
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>AppleInternal</key>
+       <true/>
+</dict>
+</plist>
diff --git a/libdarwin/dirstat.c b/libdarwin/dirstat.c
new file mode 100644 (file)
index 0000000..d0b5edf
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2017 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * 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 <strings.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/fsctl.h>
+#include <sys/vnode.h>
+#include <sys/errno.h>
+
+#include <os/assumes.h>
+
+#include <TargetConditionals.h>
+
+#include "dirstat.h"
+#include "dirstat_collection.h"
+
+#if !TARGET_OS_SIMULATOR
+#define HAS_APFS
+#endif
+
+#ifdef HAS_APFS
+#include <apfs/apfs_fsctl.h>
+#endif
+
+#if DEBUG
+#define DEBUGPRINT(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DEBUGPRINT(...) do { } while(0)
+#endif
+
+static int
+fdirstat_fallback(int fd, int flags, struct dirstat *ds);
+
+#ifdef HAS_APFS
+static int
+fdirstat(int fd, int flags, struct dirstat *ds)
+{
+       struct apfs_dir_stats_ext dstats = {0};
+       if (flags & DIRSTAT_FAST_ONLY) {
+               dstats.flags |= APFS_DIR_STATS_FAST_PATH;
+       }
+
+       int err = ffsctl(fd, APFSIOC_GET_DIR_STATS_EXT, &dstats, 0);
+       if (err == -1) {
+               if (errno == ENOENT) {
+                       // <rdar://problem/31696225>
+                       errno = ENOTSUP;
+               }
+               return -1;
+       }
+
+       ds->total_size = dstats.total_size;
+       ds->descendants = dstats.num_children;
+
+       return 0;
+}
+#endif
+
+int
+dirstatat_np(int dfd, const char *path, int flags, struct dirstat *ds_out, size_t ds_size)
+{
+#ifdef HAS_APFS
+       // <rdar://problem/32794924>
+       // Until APFS directory sizing is fixed, only the fallback path is
+       // available.
+       flags |= DIRSTAT_FORCE_FALLBACK;
+
+       // FORCE_FALLBACK trumps FAST_ONLY.  Make sure to set errno accordingly in
+       // the case that a confused caller asks for both.
+       if ((flags & (DIRSTAT_FAST_ONLY)) && (flags & DIRSTAT_FORCE_FALLBACK)) {
+               errno = ENOTSUP;
+               return -1;
+       }
+#endif
+
+       int fd = openat(dfd, path, O_RDONLY | O_DIRECTORY);
+       DEBUGPRINT("Opened %d:%s as %d\n", dfd, path, fd);
+       if (fd == -1) return -1;
+
+       struct dirstat ds = {};
+       int ret = -1;
+
+#ifdef HAS_APFS
+       if (!(flags & DIRSTAT_FORCE_FALLBACK)) {
+               ret = fdirstat(fd, flags, &ds);
+       }
+
+       if (ret == -1 && ((flags & DIRSTAT_FORCE_FALLBACK) || ((errno == ENOTTY) && !(flags & DIRSTAT_FAST_ONLY)))) {
+               ret = fdirstat_fallback(fd, flags, &ds);
+       }
+#else
+       ret = fdirstat_fallback(fd, flags, &ds);
+#endif
+       int saved_errno = errno;
+
+       if (ds_size >= sizeof(ds)) {
+               memcpy(ds_out, &ds, sizeof(ds));
+       } else {
+               memcpy(ds_out, &ds, ds_size);
+       }
+
+       close(fd);
+
+       errno = saved_errno;
+       return ret;
+}
+
+int
+dirstat_np(const char *path, int flags, struct dirstat *ds, size_t ds_size)
+{
+       return dirstatat_np(AT_FDCWD, path, flags, ds, ds_size);
+}
+
+#pragma mark Fallback
+
+struct dirqueue_entry {
+       STAILQ_ENTRY(dirqueue_entry) entries;
+       char *path;
+};
+
+static int
+fdirstat_fallback(int parent_fd, int flags, struct dirstat *ds)
+{
+       int reterror = 0;
+
+       /*
+        * This method of gathering disk usage is the fastest by far over other
+        * methods using fts or opendir/readdir + getattrlist or stat to gather
+        * information about filesystem usage.  That's because this method avoids
+        * creating vnodes for each item in a directory.  We implement a recursive
+        * filesystem search by appending each directory child found to a
+        * processing queue, and then process each child directory in that queue on
+        * a FIFO basis resulting in a breadth-first traversal of the filesystem.
+        * This keeps our actual implementation iterative to avoid deep filesystem
+        * hierarchies overflowing our stack.
+        */
+
+       dirstat_fileid_set_t fileid_seen = _dirstat_fileid_set_create();
+       STAILQ_HEAD(, dirqueue_entry) dirqueue_head = STAILQ_HEAD_INITIALIZER(dirqueue_head);
+
+       struct attrlist attrlist = {
+               .bitmapcount = ATTR_BIT_MAP_COUNT,
+               .commonattr =  ATTR_CMN_RETURNED_ATTRS | ATTR_CMN_ERROR |
+                               ATTR_CMN_NAME | ATTR_CMN_OBJTYPE | ATTR_CMN_FILEID,
+               .dirattr = ATTR_DIR_ENTRYCOUNT,
+               .fileattr = ATTR_FILE_LINKCOUNT | ATTR_FILE_ALLOCSIZE |
+                               ATTR_FILE_DATAALLOCSIZE,
+       };
+
+       typedef struct {
+               /*
+                * fields are in order of possible return in buffer (but note that data
+                * is packed in the actual buffer, and only relevant fields are
+                * returned)
+                */
+               uint32_t length;
+               attribute_set_t returned;       //ATTR_CMN_RETURNED_ATTRS
+               uint32_t error;                 //ATTR_CMN_ERROR
+               attrreference_t item_name_info; //ATTR_CMN_NAME
+               fsobj_type_t type;              //ATTR_CMN_OBJTYPE
+               uint64_t fileid;                //ATTR_CMN_FILEID
+               union {
+                       struct {
+                               u_int32_t entry_count;  //ATTR_DIR_ENTRYCOUNT
+                       };
+                       struct {
+                               u_int32_t link_count;   //ATTR_FILE_LINKCOUNT
+                               off_t alloc_size;       //ATTR_FILE_ALLOCSIZE
+                               off_t data_alloc_size;  //ATTR_FILE_DATAALLOCSIZE
+                       };
+               };
+       } max_attr_entry_t;
+
+       size_t attrbuf_len = (32 * 1024);
+       char *attrbuf = alloca(attrbuf_len);
+
+#ifdef HAS_APFS
+       os_assert(!(flags & DIRSTAT_FAST_ONLY));
+#endif
+
+       do {
+               int fd = -1;
+               char *path;
+
+               if (STAILQ_EMPTY(&dirqueue_head)) {
+                       fd = parent_fd;
+                       path = NULL;
+               } else {
+                       struct dirqueue_entry *dqe = STAILQ_FIRST(&dirqueue_head);
+                       STAILQ_REMOVE_HEAD(&dirqueue_head, entries);
+                       path = dqe->path;
+                       free(dqe);
+
+                       fd = openat(parent_fd, path, O_RDONLY | O_DIRECTORY);
+
+                       if (fd < 0) {
+                               DEBUGPRINT( "Unable to open directory %d:%s => %s\n", parent_fd, path, strerror(errno));
+                               continue;
+                       }
+               }
+
+               while (1) {
+                       int ret_entry_count = getattrlistbulk(fd, &attrlist, attrbuf, attrbuf_len, 0);
+                       if (-1 == ret_entry_count) {
+                               if (fd == parent_fd) {
+                                       reterror = errno;
+                               }
+                               DEBUGPRINT( "getattrlistbulk on in %s returned error %s\n", path, strerror(errno));
+                               break;
+                       } else if (0 == ret_entry_count) {
+                               break;
+                       } else {
+                               char *cursor = NULL; //pointer into attrbuf
+                               char *entry_start = attrbuf;
+
+                               for (int index = 0; index < ret_entry_count; index++) {
+                                       max_attr_entry_t attrs = {0};
+                                       char *name = NULL;
+
+                                       cursor = entry_start;
+
+                                       memcpy(&attrs.length, cursor, sizeof(attrs.length));
+                                       cursor += sizeof(attrs.length);
+
+                                       /* set starting point for next entry */
+                                       entry_start += attrs.length;
+
+                                       memcpy(&attrs.returned, cursor, sizeof(attrs.returned));
+                                       cursor += sizeof(attrs.returned);
+
+                                       if (attrs.returned.commonattr & ATTR_CMN_ERROR) {
+                                               memcpy(&attrs.error, cursor, sizeof(attrs.error));
+                                               cursor += sizeof(attrs.error);
+                                       }
+
+                                       if (attrs.error) {
+                                               DEBUGPRINT( "Got error %s while processing in %s\n", strerror(errno), path);
+                                               continue;
+                                       }
+
+                                       if (attrs.returned.commonattr & ATTR_CMN_NAME) {
+                                               memcpy(&attrs.item_name_info, cursor, sizeof(attrs.item_name_info));
+                                               name = cursor + attrs.item_name_info.attr_dataoffset;
+                                               if (name + attrs.item_name_info.attr_length > entry_start) {
+                                                       name = NULL;
+                                               }
+                                               cursor += sizeof(attrs.item_name_info);
+                                       }
+
+                                       if (attrs.returned.commonattr & ATTR_CMN_OBJTYPE) {
+                                               memcpy(&attrs.type, cursor, sizeof(attrs.type));
+                                               cursor += sizeof(attrs.type);
+                                       }
+
+                                       if (attrs.returned.commonattr & ATTR_CMN_FILEID) {
+                                               memcpy(&attrs.fileid, cursor, sizeof(attrs.fileid));
+                                               cursor += sizeof(attrs.fileid);
+                                       }
+
+                                       if (VDIR == attrs.type) {
+                                               if (attrs.returned.dirattr & ATTR_DIR_ENTRYCOUNT) {
+                                                       memcpy(&attrs.entry_count, cursor, sizeof(attrs.entry_count));
+                                                       cursor += sizeof(attrs.entry_count);
+                                               } else {
+                                                       // Fake it so we go down the right path below
+                                                       attrs.entry_count = -1;
+                                               }
+
+                                               // avoid descending into empty directories
+                                               if (attrs.entry_count && name) {
+                                                       struct dirqueue_entry *dqe = malloc(sizeof(struct dirqueue_entry));
+                                                       if (path == NULL) {
+                                                               dqe->path = strdup(name);
+                                                       } else {
+                                                               asprintf(&dqe->path, "%s/%s", path, name);
+                                                       }
+
+                                                       if (dqe->path != NULL) {
+                                                               STAILQ_INSERT_TAIL(&dirqueue_head, dqe, entries);
+                                                       } else {
+                                                               DEBUGPRINT( "Unable to create dqe\n");
+                                                               free(dqe);
+                                                       }
+                                               } else if (attrs.entry_count != 0) {
+                                                       DEBUGPRINT( "Failed to get name for item in %s\n", path);
+                                               } else if (attrs.entry_count == 0) {
+                                                       // Empty directory, nothing to do
+                                               }
+                                       } else {
+                                               off_t object_size = 0;
+
+                                               if (attrs.returned.fileattr & ATTR_FILE_LINKCOUNT) {
+                                                       memcpy(&attrs.link_count, cursor, sizeof(attrs.link_count));
+                                                       cursor += sizeof(attrs.link_count);
+                                               }
+
+                                               if (attrs.returned.fileattr & ATTR_FILE_ALLOCSIZE) {
+                                                       memcpy(&attrs.alloc_size, cursor, sizeof(attrs.alloc_size));
+                                                       cursor += sizeof(attrs.alloc_size);
+                                                       object_size = attrs.alloc_size;
+                                               }
+
+                                               if (attrs.returned.fileattr & ATTR_FILE_DATAALLOCSIZE) {
+                                                       memcpy(&attrs.data_alloc_size, cursor, sizeof(attrs.data_alloc_size));
+                                                       cursor += sizeof(attrs.data_alloc_size);
+                                                       if (0 == object_size) {
+                                                               object_size = attrs.data_alloc_size;
+                                                       }
+                                               }
+
+                                               if (1 == attrs.link_count) {
+                                                       ds->total_size += object_size;
+                                               } else {
+                                                       bool new_fileid = _dirstat_fileid_set_add(fileid_seen, attrs.fileid);
+                                                       if (new_fileid) {
+                                                               ds->total_size += object_size;
+                                                       } else {
+                                                               DEBUGPRINT( "Skipping hardlinked file at %s/%s\n", path, name);
+                                                       }
+                                               }
+                                       }
+                                       ds->descendants++;
+                               }
+                       }
+               }
+
+               if (path) {
+                       close(fd);
+                       free(path);
+               }
+       } while (!STAILQ_EMPTY(&dirqueue_head));
+
+       _dirstat_fileid_set_destroy(fileid_seen);
+
+       if (reterror) {
+               errno = reterror;
+               return -1;
+       } else {
+               return 0;
+       }
+}
diff --git a/libdarwin/dirstat.h b/libdarwin/dirstat.h
new file mode 100644 (file)
index 0000000..d3235de
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+#ifndef __DIRSTAT_H__
+#define __DIRSTAT_H__
+
+#include <sys/types.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+/* Fail if the file system does not support fast directory sizing on the provided directory */
+#define DIRSTAT_FAST_ONLY 0x1
+
+/* Do not use filesystem support for directory sizing. */
+#define DIRSTAT_FORCE_FALLBACK 0x2
+
+/*
+ * NOT ABI: the size of this structure may grow.  You must pass the current
+ * size of this structure in as the dirstat_size argument to the functions
+ * below.
+ */
+struct dirstat {
+       off_t total_size;
+       uint64_t descendants;
+};
+
+/* Returns -1 on error and sets errno.  Does not cross file-system boundaries. */
+__API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0))
+int dirstat_np(const char *path, int flags, struct dirstat *ds, size_t dirstat_size);
+
+__API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0))
+int dirstatat_np(int dfd, const char *path, int flags, struct dirstat *ds, size_t dirstat_size);
+
+__END_DECLS
+
+#endif // __DIRSTAT_H__
diff --git a/libdarwin/dirstat_collection.c b/libdarwin/dirstat_collection.c
new file mode 100644 (file)
index 0000000..890cb45
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Newcomb.
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2017 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * 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@
+ */
+
+/*
+ * Taken from file_cmds:du.c
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "dirstat_collection.h"
+
+struct fileid_entry {
+    struct fileid_entry *next;
+    struct fileid_entry *previous;
+    //int links;
+    uint64_t fileid;
+};
+
+
+struct dirstat_fileid_set_s {
+       struct fileid_entry **buckets;
+       struct fileid_entry *free_list;
+       size_t number_buckets;
+       unsigned long number_entries;
+       bool stop_allocating;
+};
+
+static const size_t links_hash_initial_size = 8192;
+
+dirstat_fileid_set_t
+_dirstat_fileid_set_create(void)
+{
+    dirstat_fileid_set_t ds = calloc(1, sizeof(dirstat_fileid_set_s));
+    ds->number_buckets = links_hash_initial_size;
+       ds->buckets = calloc(ds->number_buckets, sizeof(ds->buckets[0]));
+    if (ds->buckets == NULL) {
+        free(ds);
+        return NULL;
+    }
+    return ds;
+}
+
+void
+_dirstat_fileid_set_destroy(dirstat_fileid_set_t ds)
+{
+       struct fileid_entry *le;
+    for (size_t i = 0; i < ds->number_buckets; i++) {
+        while (ds->buckets[i] != NULL) {
+            le = ds->buckets[i];
+            ds->buckets[i] = le->next;
+            free(le);
+        }
+    }
+    free(ds->buckets);
+    free(ds);
+}
+
+bool
+_dirstat_fileid_set_add(dirstat_fileid_set_t ds, uint64_t fileid)
+{
+       struct fileid_entry *le, **new_buckets;
+       size_t i, new_size;
+       int hash;
+
+       /* If the hash table is getting too full, enlarge it. */
+       if (ds->number_entries > ds->number_buckets * 10 && !ds->stop_allocating) {
+               new_size = ds->number_buckets * 2;
+               new_buckets = calloc(new_size, sizeof(struct fileid_entry *));
+
+               /* Try releasing the free list to see if that helps. */
+               if (new_buckets == NULL && ds->free_list != NULL) {
+                       while (ds->free_list != NULL) {
+                               le = ds->free_list;
+                               ds->free_list = le->next;
+                               free(le);
+                       }
+                       new_buckets = calloc(new_size, sizeof(new_buckets[0]));
+               }
+
+               if (new_buckets == NULL) {
+                       ds->stop_allocating = 1;
+               } else {
+                       for (i = 0; i < ds->number_buckets; i++) {
+                               while (ds->buckets[i] != NULL) {
+                                       /* Remove entry from old bucket. */
+                                       le = ds->buckets[i];
+                                       ds->buckets[i] = le->next;
+
+                                       /* Add entry to new bucket. */
+                                       hash = (int)(fileid % new_size);
+
+                                       if (new_buckets[hash] != NULL)
+                                               new_buckets[hash]->previous =
+                                                   le;
+                                       le->next = new_buckets[hash];
+                                       le->previous = NULL;
+                                       new_buckets[hash] = le;
+                               }
+                       }
+                       free(ds->buckets);
+                       ds->buckets = new_buckets;
+                       ds->number_buckets = new_size;
+               }
+       }
+
+       /* Try to locate this entry in the hash table. */
+       hash = (int)(fileid % ds->number_buckets);
+       for (le = ds->buckets[hash]; le != NULL; le = le->next) {
+               if (le->fileid == fileid) {
+#if 0 // TODO
+                       /*
+                        * Save memory by releasing an entry when we've seen
+                        * all of its links.
+                        */
+                       if (--le->links <= 0) {
+                               if (le->previous != NULL)
+                                       le->previous->next = le->next;
+                               if (le->next != NULL)
+                                       le->next->previous = le->previous;
+                               if (buckets[hash] == le)
+                                       buckets[hash] = le->next;
+                               number_entries--;
+                               /* Recycle this node through the free list */
+                               if (stop_allocating) {
+                                       free(le);
+                               } else {
+                                       le->next = free_list;
+                                       free_list = le;
+                               }
+                       }
+#endif
+                       return true;
+               }
+       }
+
+       if (ds->stop_allocating)
+               return false;
+
+       /* Add this entry to the links cache. */
+       if (ds->free_list != NULL) {
+               /* Pull a node from the free list if we can. */
+               le = ds->free_list;
+               ds->free_list = le->next;
+       } else {
+               /* Malloc one if we have to. */
+               le = malloc(sizeof(struct fileid_entry));
+    }
+       if (le == NULL) {
+               ds->stop_allocating = 1;
+               return false;
+       }
+       le->fileid = fileid;
+       ds->number_entries++;
+       le->next = ds->buckets[hash];
+       le->previous = NULL;
+       if (ds->buckets[hash] != NULL)
+               ds->buckets[hash]->previous = le;
+       ds->buckets[hash] = le;
+       return false;
+}
diff --git a/libdarwin/dirstat_collection.h b/libdarwin/dirstat_collection.h
new file mode 100644 (file)
index 0000000..18aff57
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * 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 <sys/cdefs.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+__BEGIN_DECLS
+
+typedef struct dirstat_fileid_set_s dirstat_fileid_set_s;
+typedef dirstat_fileid_set_s *dirstat_fileid_set_t;
+
+dirstat_fileid_set_t _dirstat_fileid_set_create(void);
+void _dirstat_fileid_set_destroy(dirstat_fileid_set_t set);
+bool _dirstat_fileid_set_add(dirstat_fileid_set_t set, uint64_t fileid);
+
+__END_DECLS
diff --git a/libdarwin/init.c b/libdarwin/init.c
new file mode 100644 (file)
index 0000000..ba68629
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * 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@
+ */
+
+void
+__libdarwin_init(void)
+{
+}
diff --git a/libdarwin/variant.c b/libdarwin/variant.c
new file mode 100644 (file)
index 0000000..927ac28
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2016 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <dispatch/dispatch.h>
+#include <xpc/xpc.h>
+#include <xpc/private.h>
+#include <System/sys/csr.h>
+#include <System/machine/cpu_capabilities.h>
+
+#include <os/assumes.h>
+#include <os/variant_private.h>
+
+enum variant_property {
+       VP_ALL = 0,
+       VP_CONTENT,
+       VP_DIAGNOSTICS,
+       VP_UI,
+       VP_SECURITY,
+       VP_MAX
+};
+
+enum check_status {
+       S_UNKNOWN = 0,
+       S_NO = 2,
+       S_YES = 3
+};
+
+static bool
+status2bool(enum check_status status) {
+       switch (status) {
+       case S_NO:
+               return false;
+       case S_YES:
+               return true;
+       default:
+               os_crash("os_variant had unexpected status");
+       }
+}
+
+#define VAR_FILE_LEGACY "/var/db/disableAppleInternal"
+
+#if TARGET_OS_OSX
+#define VAR_FILE_OVERRIDE "/var/db/os_variant_override"
+#else
+#define VAR_FILE_OVERRIDE "/usr/share/misc/os_variant_override"
+#endif
+
+#if !TARGET_OS_SIMULATOR
+#define INTERNAL_CONTENT_PATH "/System/Library/CoreServices/AppleInternalVariant.plist"
+#else
+#define INTERNAL_CONTENT_PATH "/AppleInternal"
+#endif
+
+#define SYSTEM_VERSION_PLIST_PATH "/System/Library/CoreServices/SystemVersion.plist"
+#define SYSTEM_VERSION_PLIST_KEY "ReleaseType"
+
+#if TARGET_OS_IPHONE
+#define INTERNAL_SETTINGS_PATH "/AppleInternal/Library/PreferenceBundles/Internal Settings.bundle"
+#else
+#define INTERNAL_DIAGS_PROFILE_PATH "/var/db/ConfigurationProfiles/Settings/com.apple.InternalDiagnostics.plist"
+#endif
+
+#if !TARGET_OS_SIMULATOR
+#define CACHE_SYSCTL_NAME "kern.osvariant_status"
+
+static void _restore_cached_check_status(uint64_t status);
+static uint64_t _get_cached_check_status(void);
+
+static char * _read_file(const char *path, size_t *size_out)
+{
+       char *buf = NULL;
+
+       int fd = open(path, O_RDONLY);
+       if (fd == -1) return NULL;
+
+       struct stat sb;
+       int rc = fstat(fd, &sb);
+       if (rc != 0 || sb.st_size == 0) {
+               goto error;
+       }
+
+       size_t size_limit = (size_out && *size_out != 0) ? *size_out : 1024;
+       size_t size = (size_t)sb.st_size;
+       if (size_out) *size_out = (size_t)sb.st_size;
+       if (size > size_limit) {
+               goto error;
+       }
+
+       buf = malloc(size + 1);
+       if (!buf) {
+               goto error;
+       }
+
+       ssize_t bytes_read = read(fd, buf, size);
+       buf[size] = '\0';
+
+
+       if (bytes_read == (ssize_t)size) {
+               close(fd);
+               return buf;
+       }
+
+error:
+       close(fd);
+       free(buf);
+       return NULL;
+}
+
+static xpc_object_t read_plist(const char *path)
+{
+       size_t size = 16 * 1024;
+       uint8_t *buf = (uint8_t*)_read_file(path, &size);
+       if (!buf) return NULL;
+
+       xpc_object_t plist = xpc_create_from_plist(buf, size);
+       if (plist && xpc_get_type(plist) != XPC_TYPE_DICTIONARY) {
+               xpc_release(plist);
+               plist = NULL;
+       }
+
+       free(buf);
+
+       return plist;
+}
+#endif
+
+#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+static enum check_status internal_content = S_UNKNOWN;
+#endif
+#if !TARGET_OS_SIMULATOR
+static enum check_status can_has_debugger = S_UNKNOWN;
+#if TARGET_OS_IPHONE
+static enum check_status internal_release_type = S_UNKNOWN;
+#else // TARGET_OS_IPHONE
+static enum check_status internal_diags_profile = S_UNKNOWN;
+#endif // TARGET_OS_IPHONE
+#endif // !TARGET_OS_SIMULATOR
+
+static bool disabled_status[VP_MAX] = {};
+
+static void _parse_disabled_status(char *test_string)
+{
+#if TARGET_OS_SIMULATOR
+#pragma unused(test_string)
+#else // TARGET_OS_SIMULATOR
+       char *override_str = NULL;
+
+       bzero(disabled_status, sizeof(disabled_status));
+
+       if (test_string != NULL) {
+               /* used for unit tests */
+               override_str = strdup(test_string);
+       } else {
+               if (access(VAR_FILE_LEGACY, F_OK) == 0) {
+                       goto disable_all;
+               } else if (access(VAR_FILE_OVERRIDE, F_OK) != 0) {
+                       return;
+               }
+
+               override_str = _read_file(VAR_FILE_OVERRIDE, NULL);
+       }
+
+       if (override_str == NULL) goto disable_all;
+
+       char *token, *string = override_str;
+       while ((token = strsep(&string, ",\n")) != NULL) {
+               if (strcmp(token, "content") == 0) {
+                       disabled_status[VP_CONTENT] = true;
+               } else if (strcmp(token, "diagnostics") == 0) {
+                       disabled_status[VP_DIAGNOSTICS] = true;
+               } else if (strcmp(token, "ui") == 0) {
+                       disabled_status[VP_UI] = true;
+               } else if (strcmp(token, "security") == 0) {
+                       disabled_status[VP_SECURITY] = true;
+               }
+       }
+
+       free(override_str);
+       return;
+
+disable_all:
+       for (int i = 0; i < VP_MAX; i++) {
+               disabled_status[i] = true;
+       }
+#endif //!TARGET_OS_SIMULATOR
+}
+
+#if !TARGET_OS_SIMULATOR
+static bool _load_cached_status(void)
+{
+       uint64_t status = 0;
+       size_t status_size = sizeof(status);
+       int ret = sysctlbyname(CACHE_SYSCTL_NAME, &status, &status_size, NULL, 0);
+       if (ret != 0) {
+               return false;
+       }
+
+       if (status) {
+               _restore_cached_check_status(status);
+               return true;
+       }
+
+       if (status == 0 && getpid() == 1) {
+               /*
+                * Looks like we are in launchd; try to set the status.
+                *
+                * We don't actually care if this works because we'll have warmed our state.
+                */
+               status = _get_cached_check_status();
+               sysctlbyname(CACHE_SYSCTL_NAME, NULL, 0, &status, status_size);
+               return true;
+       }
+
+       return false;
+}
+#endif
+
+static void _initialize_status(void * __unused ctx)
+{
+#if !TARGET_OS_SIMULATOR
+       if (!_load_cached_status()) {
+               _parse_disabled_status(NULL);
+       }
+#else
+       _parse_disabled_status(NULL);
+#endif
+}
+
+static bool _check_disabled(enum variant_property variant_property)
+{
+       static dispatch_once_t disabled_status_pred;
+       dispatch_once_f(&disabled_status_pred, NULL, _initialize_status);
+
+       return disabled_status[variant_property];
+}
+
+#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+static bool _check_internal_content(void)
+{
+       if (internal_content == S_UNKNOWN) {
+#if !TARGET_OS_SIMULATOR
+               const char * path = INTERNAL_CONTENT_PATH;
+#else
+               char *simulator_root = getenv("IPHONE_SIMULATOR_ROOT");
+               char *to_free = NULL, *path = NULL;
+               if (simulator_root) {
+                       asprintf(&path, "%s/%s", simulator_root, INTERNAL_CONTENT_PATH);
+                       if (path == NULL) {
+                               return false;
+                       }
+                       to_free = path;
+               }
+#endif
+               internal_content = (access(path, F_OK) == 0) ? S_YES : S_NO;
+#if TARGET_OS_SIMULATOR
+               free(to_free);
+#endif
+       }
+       return status2bool(internal_content);
+}
+#endif // !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+
+#if TARGET_OS_IPHONE
+
+/*
+ * This set of criteria was taken from copyInternalBuild in MobileGestalt.c
+ */
+static bool _check_internal_release_type(void)
+{
+#if TARGET_OS_SIMULATOR
+       return _check_internal_content();
+#else // TARGET_OS_SIMULATOR
+       if (internal_release_type == S_UNKNOWN) {
+               xpc_object_t system_version_plist = read_plist(SYSTEM_VERSION_PLIST_PATH);
+               if (system_version_plist) {
+                       const char *release_type =
+                                       xpc_dictionary_get_string(system_version_plist,
+                                                       SYSTEM_VERSION_PLIST_KEY);
+
+                       if (release_type == NULL) {
+                               /*
+                                * Confusingly, customer images are just completely missing this key.
+                                */
+                               internal_release_type = S_NO;
+                       } else if (strcmp(release_type, "Internal") == 0 ||
+                                       strcmp(release_type, "Lite Internal") == 0 ||
+                                       strcmp(release_type, "NonUI") == 0) {
+                               internal_release_type = S_YES;
+                       } else {
+                               internal_release_type = S_NO;
+                       }
+
+                       xpc_release(system_version_plist);
+               } else {
+                       internal_release_type = (access(INTERNAL_SETTINGS_PATH, F_OK) == 0) ? S_YES : S_NO;
+               }
+       }
+
+       return status2bool(internal_release_type);
+#endif // TARGET_OS_SIMULATOR
+}
+
+#else
+
+static bool _check_internal_diags_profile() {
+       static enum check_status internal_diags_profile = S_UNKNOWN;
+
+       if (internal_diags_profile == S_UNKNOWN) {
+               xpc_object_t profile_settings = read_plist(INTERNAL_DIAGS_PROFILE_PATH);
+               if (profile_settings) {
+                       internal_diags_profile = xpc_dictionary_get_bool(profile_settings, "AppleInternal") ? S_YES : S_NO;
+                       xpc_release(profile_settings);
+               } else {
+                       internal_diags_profile = S_NO;
+               }
+       }
+
+       return status2bool(internal_diags_profile);
+}
+
+#endif
+
+static bool _check_can_has_debugger(void)
+{
+#if TARGET_OS_SIMULATOR
+       return _check_internal_content();
+#else
+       if (can_has_debugger == S_UNKNOWN) {
+#if TARGET_OS_IPHONE
+               can_has_debugger = *((uint32_t *)_COMM_PAGE_DEV_FIRM) ? S_YES : S_NO;
+#else
+               /*
+                * The comm page bit does exist on macOS, but also requires kernel
+                * debugging in the CSR configuration.  We don't need to be that strict
+                * here.
+                */
+               can_has_debugger = (csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0) ? S_YES : S_NO;
+#endif
+       }
+       return status2bool(can_has_debugger);
+#endif // TARGET_OS_SIMULATOR
+}
+
+// For unit tests
+#ifndef VARIANT_SKIP_EXPORTED
+
+bool
+os_variant_has_internal_content(const char * __unused subsystem)
+{
+       if (_check_disabled(VP_CONTENT)) {
+               return false;
+       }
+
+#if TARGET_OS_IPHONE
+       return _check_internal_release_type();
+#else
+       return _check_internal_content();
+#endif
+}
+
+
+bool
+os_variant_has_internal_diagnostics(const char * __unused subsystem)
+{
+       if (_check_disabled(VP_DIAGNOSTICS)) {
+               return false;
+       }
+
+#if TARGET_OS_IPHONE
+       return _check_internal_release_type();
+#else
+       return _check_internal_content() || _check_internal_diags_profile();
+#endif
+}
+
+bool
+os_variant_has_internal_ui(const char * __unused subsystem)
+{
+       if (_check_disabled(VP_UI)) {
+               return false;
+       }
+
+#if TARGET_OS_IPHONE
+       return _check_internal_release_type();
+#else
+       return _check_internal_content();
+#endif
+}
+
+bool
+os_variant_allows_internal_security_policies(const char * __unused subsystem)
+{
+       if (_check_disabled(VP_SECURITY)) {
+               return false;
+       }
+
+       return _check_can_has_debugger();
+}
+
+#endif // VARIANT_SKIP_EXPORTED
+
+#define STATUS_INITIAL_BITS 0x70000000F0000000ULL
+#define STATUS_BIT_WIDTH 2
+#define STATUS_SET 0x2
+#define STATUS_MASK 0x3
+
+enum status_flags_positions {
+       SFP_INTERNAL_CONTENT = 0,
+       SFP_CAN_HAS_DEBUGGER = 1,
+       SFP_INTERNAL_RELEASE_TYPE = 2,
+       SFP_INTERNAL_DIAGS_PROFILE = 3
+};
+
+#if !TARGET_OS_SIMULATOR
+static uint64_t _get_cached_check_status(void)
+{
+       uint64_t res = STATUS_INITIAL_BITS;
+
+#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+       _check_internal_content();
+       if (internal_content != S_UNKNOWN)
+               res |= internal_content << SFP_INTERNAL_CONTENT * STATUS_BIT_WIDTH;
+#endif
+
+       _check_can_has_debugger();
+       if (can_has_debugger != S_UNKNOWN)
+               res |= can_has_debugger << SFP_CAN_HAS_DEBUGGER * STATUS_BIT_WIDTH;
+
+#if TARGET_OS_IPHONE
+       _check_internal_release_type();
+       if (internal_release_type != S_UNKNOWN)
+               res |= internal_release_type << SFP_INTERNAL_RELEASE_TYPE * STATUS_BIT_WIDTH;
+#else
+       _check_internal_diags_profile();
+       if (internal_diags_profile != S_UNKNOWN)
+               res |= internal_diags_profile << SFP_INTERNAL_DIAGS_PROFILE * STATUS_BIT_WIDTH;
+#endif
+
+       _parse_disabled_status(NULL);
+       for (int i = 0; i < VP_MAX; i++) {
+               if (disabled_status[i]) {
+                       res |= 0x1ULL << (i + 32);
+               }
+       }
+
+       return res;
+}
+
+static void _restore_cached_check_status(uint64_t status)
+{
+#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+       if ((status >> (SFP_INTERNAL_CONTENT * STATUS_BIT_WIDTH)) & STATUS_SET)
+               internal_content = (status >> (SFP_INTERNAL_CONTENT * STATUS_BIT_WIDTH)) & STATUS_MASK;
+#endif
+       if ((status >> (SFP_CAN_HAS_DEBUGGER * STATUS_BIT_WIDTH)) & STATUS_SET)
+               can_has_debugger = (status >> (SFP_CAN_HAS_DEBUGGER * STATUS_BIT_WIDTH)) & STATUS_MASK;
+#if TARGET_OS_IPHONE
+       if ((status >> (SFP_INTERNAL_RELEASE_TYPE * STATUS_BIT_WIDTH)) & STATUS_SET)
+               internal_release_type = (status >> (SFP_INTERNAL_RELEASE_TYPE * STATUS_BIT_WIDTH)) & STATUS_MASK;
+#else
+       if ((status >> (SFP_INTERNAL_DIAGS_PROFILE * STATUS_BIT_WIDTH)) & STATUS_SET)
+               internal_diags_profile = (status >> (SFP_INTERNAL_DIAGS_PROFILE * STATUS_BIT_WIDTH)) & STATUS_MASK;
+#endif
+
+       for (int i = 0; i < VP_MAX; i++) {
+               disabled_status[i] = (status >> (32 + i)) & 0x1;
+       }
+}
+#endif // !TARGET_OS_SIMULATOR
index d468783ae4c1d7190e004cd5b60f411504cab4e3..028c182f1910d1e477cae7cda06b2c20ee35db4b 100644 (file)
@@ -72,6 +72,7 @@ int __collate_load_error = 1;
 __private_extern__ int
 __collate_load_tables(const char *encoding, locale_t loc)
 {
+       int fd;
        FILE *fp;
        int i, saverr, chains, z;
        char strbuf[STR_LEN], buf[PATH_MAX];
@@ -111,7 +112,12 @@ __collate_load_tables(const char *encoding, locale_t loc)
        /* Range checking not needed, encoding has fixed size */
        (void)strcpy(buf, encoding);
        (void)strcat(buf, "/LC_COLLATE");
-       if ((fp = fdopen(__open_path_locale(buf), "r")) == NULL) {
+       fd = __open_path_locale(buf);
+       if (fd == -1) {
+               return (_LDP_ERROR);
+       }
+       if ((fp = fdopen(fd, "r")) == NULL) {
+               close(fd);
                return (_LDP_ERROR);
        }
 
index 46624658710ee438937ddf794238b775bfc655d0..baeaada1bb84614ea6d475b9aee7046f1a7fef0d 100644 (file)
@@ -97,7 +97,7 @@ _GB18030_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
        }
 
        ncopy = MIN(MIN(n, GB18030_MB_CUR_MAX), sizeof(gs->bytes) - gs->count);
-       strncpy(gs->bytes + gs->count, s, ncopy);
+       strncpy((char*)(gs->bytes + gs->count), s, ncopy);
        ocount = gs->count;
        gs->count += ncopy;
        s = (char *)gs->bytes;
index 559ada45e35cac1b8a43be0c86c5a2c25a089a8d..dea5a92faec2f1f00a5cdf7e32cbc50ec9146486 100644 (file)
@@ -114,7 +114,7 @@ _GB2312_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
        }
 
        ncopy = MIN(MIN(n, GB2312_MB_CUR_MAX), sizeof(gs->bytes) - gs->count);
-       strncpy(gs->bytes + gs->count, s, ncopy);
+       strncpy((char*)(gs->bytes + gs->count), s, ncopy);
        ocount = gs->count;
        gs->count += ncopy;
        s = (char *)gs->bytes;
index 213a62b9d4eaf8cb73dd9b50424fb0c3d8a0bc8e..852109cf50d5566826d5f3cdde607cd77039aec5 100644 (file)
@@ -66,7 +66,7 @@ __setrunelocale(const char *encoding, locale_t loc)
        static struct __xlocale_st_runelocale *CachedRuneLocale;
        extern int __mb_cur_max;
        extern int __mb_sb_limit;
-       static pthread_lock_t cache_lock = LOCK_INITIALIZER;
+       static os_unfair_lock cache_lock = OS_UNFAIR_LOCK_INIT;
 
        /*
         * The "C" and "POSIX" locale are always here.
@@ -86,7 +86,7 @@ __setrunelocale(const char *encoding, locale_t loc)
        /*
         * If the locale name is the same as our cache, use the cache.
         */
-       LOCK(cache_lock);
+       os_unfair_lock_lock(&cache_lock);
        if (CachedRuneLocale != NULL &&
            strcmp(encoding, CachedRuneLocale->__ctype_encoding) == 0) {
                XL_RELEASE(loc->__lc_ctype);
@@ -97,10 +97,10 @@ __setrunelocale(const char *encoding, locale_t loc)
                        __mb_cur_max = loc->__lc_ctype->__mb_cur_max;
                        __mb_sb_limit = loc->__lc_ctype->__mb_sb_limit;
                }
-               UNLOCK(cache_lock);
+               os_unfair_lock_unlock(&cache_lock);
                return (0);
        }
-       UNLOCK(cache_lock);
+       os_unfair_lock_unlock(&cache_lock);
 
        /*
         * Slurp the locale file into the cache.
@@ -169,11 +169,11 @@ __setrunelocale(const char *encoding, locale_t loc)
                        __mb_cur_max = loc->__lc_ctype->__mb_cur_max;
                        __mb_sb_limit = loc->__lc_ctype->__mb_sb_limit;
                }
-               LOCK(cache_lock);
+               os_unfair_lock_lock(&cache_lock);
                XL_RELEASE(CachedRuneLocale);
                CachedRuneLocale = xrl;
                XL_RETAIN(CachedRuneLocale);
-               UNLOCK(cache_lock);
+               os_unfair_lock_unlock(&cache_lock);
        } else
                XL_RELEASE(xrl);
 
index 3ecc75a0ca2a78982de59eb7c394b6bc51fbdac0..0089af006bf899e86a7a16b3256389ebf48c60a6 100644 (file)
@@ -29,6 +29,7 @@ __FBSDID("$FreeBSD: src/lib/libc/locale/wcstod.c,v 1.4 2004/04/07 09:47:56 tjr E
 
 #include "xlocale_private.h"
 
+#include <string.h>
 #include <stdlib.h>
 #include <wchar.h>
 #include <wctype.h>
index 1e1c443d8c014e31793707e3f6ff8ac33b48d5bd..6efb9a579ee288df117d1e76ab24434d917b6a66 100644 (file)
@@ -32,7 +32,7 @@
        0, XPERMANENT,                  \
        {}, {}, {}, {}, {},             \
        {}, {}, {}, {}, {},             \
-       LOCK_INITIALIZER,               \
+       OS_UNFAIR_LOCK_INIT,            \
        XMAGIC,                         \
        1, 0, 0, 0, 0, 0, 1, 1, 0,      \
        NULL,                           \
@@ -105,7 +105,7 @@ _duplocale(locale_t loc)
                return NULL;
        new->__refcount = 1;
        new->__free_extra = (__free_extra_t)_releaselocale;
-       new->__lock = LOCK_INITIALIZER;
+       new->__lock = OS_UNFAIR_LOCK_INIT;
        if (loc == NULL)
                loc = __current_locale();
        else if (loc == LC_GLOBAL_LOCALE)
@@ -114,7 +114,7 @@ _duplocale(locale_t loc)
                *new = __c_locale;
                new->__refcount = 1;
                new->__free_extra = (__free_extra_t)_releaselocale;
-               new->__lock = LOCK_INITIALIZER;
+               new->__lock = OS_UNFAIR_LOCK_INIT;
                return new;
        }
        XL_LOCK(loc);
index 2301aa0ff2feeb3307a4dfb1a8af223d3c1954f4..ba9feb2e51d4a4074e66de0029a52e66823c0e15 100644 (file)
@@ -32,8 +32,8 @@
 #include <locale.h>
 #include <libkern/OSAtomic.h>
 #include <pthread.h>
-#include <pthread_spinlock.h>
 #include <limits.h>
+#include <os/lock.h>
 #include "setlocale.h"
 #include "collate.h"
 #include "runetype.h"
@@ -132,7 +132,7 @@ struct _xlocale {
        __darwin_mbstate_t __mbs_wcsnrtombs;
        __darwin_mbstate_t __mbs_wcsrtombs;
        __darwin_mbstate_t __mbs_wctomb;
-       pthread_lock_t __lock;
+       os_unfair_lock __lock;
 /* magic (Here up to the end is copied when duplicating locale_t's) */
        int64_t __magic;
 /* flags */
@@ -175,7 +175,7 @@ struct _xlocale {
                                        (x) = &__global_locale; \
                                }
 
-#define XL_LOCK(x)     LOCK((x)->__lock);
+#define XL_LOCK(x)     os_unfair_lock_lock(&(x)->__lock);
 #define        XL_RELEASE(x)   if ((x) && (x)->__free_extra != XPERMANENT && OSAtomicDecrement32Barrier(&(x)->__refcount) == 0) { \
                                if ((x)->__free_extra) \
                                        (*(x)->__free_extra)((x)); \
@@ -183,7 +183,7 @@ struct _xlocale {
                                (x) = NULL; \
                        }
 #define        XL_RETAIN(x)    if ((x) && (x)->__free_extra != XPERMANENT) { OSAtomicIncrement32Barrier(&(x)->__refcount); }
-#define XL_UNLOCK(x)   UNLOCK((x)->__lock);
+#define XL_UNLOCK(x)   os_unfair_lock_unlock(&(x)->__lock);
 
 __attribute__((visibility("hidden")))
 extern struct __xlocale_st_runelocale _DefaultRuneXLocale;
index d2d41a5c9e8a02ac56f1985df2b587e7e8105562..4621befa31ba3c313f7f7aa6ef173446c9d1c180 100644 (file)
@@ -74,9 +74,10 @@ catopen.3 catopen.3
 clock.3 clock.3
 clock_gettime.3 clock_gettime.3 clock_settime.3 clock_getres.3 clock_gettime_nsec_np.3
 confstr.3 confstr.3
+open_memstream.3 open_memstream.3 open_wmemstream.3
 crypt.3 crypt.3 encrypt.3 setkey.3
 ctermid.3 ctermid.3 ctermid_r.3
-ctime.3 ctime.3 asctime.3 asctime_r.3 asctime_r.3 ctime_r.3 difftime.3 gmtime.3 gmtime.3 gmtime_r.3 gmtime_r.3 localtime.3 localtime_r.3 mktime.3 mktime.3
+ctime.3 ctime.3 asctime.3 asctime_r.3 asctime_r.3 ctime_r.3 difftime.3 gmtime.3 gmtime.3 gmtime_r.3 gmtime_r.3 localtime.3 localtime_r.3 mktime.3 mktime.3 timegm.3 timelocal.3
 ctype.3 ctype.3
 ctype_l.3 ctype_l.3
 daemon.3 daemon.3
@@ -105,7 +106,7 @@ flockfile.3 flockfile.3 ftrylockfile.3 funlockfile.3
 fmtcheck.3 fmtcheck.3
 fmtmsg.3 fmtmsg.3
 fnmatch.3 fnmatch.3
-fopen.3 fopen.3 fdopen.3 freopen.3
+fopen.3 fopen.3 fdopen.3 freopen.3 fmemopen.3
 fparseln.3 fparseln.3
 fputs.3 fputs.3 puts.3
 fputws.3 fputws.3 fputws_l.3
@@ -130,7 +131,7 @@ gethostname.3 gethostname.3 sethostname.3
 getlastlogx.3 getlastlogx.3 getlastlogxbyname.3 getutmp.3 getutmpx.3 utmpxname.3
 getline.3 getline.3 getdelim.3
 getloadavg.3 getloadavg.3
-getmntinfo.3 getmntinfo.3
+getmntinfo.3 getmntinfo.3 getmntinfo_r_np.3
 getopt.3 getopt.3
 getopt_long.3 getopt_long.3 getopt_long_only.3
 getpagesize.3 getpagesize.3
@@ -205,7 +206,7 @@ memset.3 memset.3
 memset_s.3 memset_s.3
 memset_pattern.3 memset_pattern.3 memset_pattern4.3 memset_pattern8.3 memset_pattern16.3
 mkpath_np.3 mkpath_np.3
-mktemp.3 mktemp.3 mkdtemp.3 mkstemp.3 mkstemps.3
+mktemp.3 mktemp.3 mkdtemp.3 mkstemp.3 mkstemps.3 mkostemp.3 mkostemps.3 mkdtempat_np.3 mkstempsat_np.3 mkostempsat_np.3
 mpool.3 mpool.3 mpool_close.3 mpool_filter.3 mpool_get.3 mpool_new.3 mpool_open.3 mpool_put.3 mpool_sync.3
 multibyte.3 multibyte.3
 newlocale.3 newlocale.3
@@ -233,7 +234,7 @@ raise.3 raise.3
 rand.3 rand.3 rand_r.3 srand.3 sranddev.3
 rand48.3 rand48.3 _rand48.3 drand48.3 erand48.3 jrand48.3 lcong48.3 lrand48.3 mrand48.3 nrand48.3 seed48.3 srand48.3
 random.3 random.3 initstate.3 setstate.3 srandom.3 srandomdev.3
-rbtree.3 rbtree.3
+rbtree.3 rbtree.3 rb_tree_init.3 rb_tree_insert_node.3 rb_tree_remove_node.3 rb_tree_find_node.3 rb_tree_find_node_geq.3 rb_tree_find_node_leq.3 rb_tree_iterate.3 rb_tree_count.3 RB_TREE_MIN.3 RB_TREE_MAX.3 RB_TREE_FOREACH.3 RB_TREE_FOREACH_REVERSE.3
 readpassphrase.3 readpassphrase.3
 realpath.3 realpath.3
 recno.3 recno.3
@@ -299,7 +300,6 @@ tcsetattr.3 tcsetattr.3 cfgetispeed.3 cfgetospeed.3 cfmakeraw.3 cfsetispeed.3 cf
 tcsetpgrp.3 tcsetpgrp.3
 time.3 time.3
 time2posix.3 time2posix.3 posix2time.3
-timegm.3 timegm.3 timelocal.3
 times.3 times.3
 timezone.3 timezone.3
 timingsafe_bcmp.3 timingsafe_bcmp.3
index a679b745c862c44e4b887f040ee7822732289a37..de22fa2687db0497047422a9e5c4b973f4983a91 100644 (file)
@@ -39,7 +39,6 @@
 .Nm inet_netof ,
 .Nm inet_network ,
 .Nm inet_ntoa ,
-.Nm inet_ntoa_r ,
 .Nm inet_ntop ,
 .Nm inet_pton
 .Nd Internet address manipulation routines
 .Fo inet_ntoa
 .Fa "struct in_addr in"
 .Fc
-.Ft char *
-.Fo inet_ntoa_r
-.Fa "struct in_addr in"
-.Fa "char *buf"
-.Fa "socklen_t size"
-.Fc
 .Ft const char *
 .Fo inet_ntop
 .Fa "int af"
@@ -171,10 +164,6 @@ string representing the address in
 .Ql .\&
 notation.
 The routine
-.Fn inet_ntoa_r
-is the reentrant version of
-.Fn inet_ntoa .
-The routine
 .Fn inet_makeaddr
 takes an Internet network number and a local
 network address and constructs an Internet address
index e51d3995edfb4934a612d64ee73b7bae59a7bfea..455fd47570ab0102d37d40115b3e186cf2a8b89d 100644 (file)
@@ -32,6 +32,7 @@
 #include <mach-o/getsect.h>
 #include <pthread.h>
 #include <sys/types.h>
+#include <sys/reason.h>
 #include <execinfo.h>
 #include <stdio.h>
 #include <dlfcn.h>
 #include <string.h>
 #include "os/assumes.h"
 #include <os/debug_private.h>
+#include <os/log.h>
+#include <os/log_private.h>
+#include <os/reason_private.h>
+
+#include <CrashReporterClient.h>
+#define os_set_crash_message(arg) CRSetCrashLogMessage(arg)
 
 #define OSX_ASSUMES_LOG_REDIRECT_SECT_NAME "__osx_log_func"
 #define os_atomic_cmpxchg(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
@@ -239,6 +246,32 @@ _os_crash_impl(const char *message) {
        }
 }
 
+__attribute__((always_inline))
+static inline bool
+_os_crash_fmt_impl(os_log_pack_t pack, size_t pack_size)
+{
+       /*
+        * We put just the format string into the CrashReporter buffer so that we
+        * can get at least that on customer builds.
+        */
+       const char *message = pack->olp_format;
+       _os_crash_impl(message);
+
+       char *(*_os_log_pack_send_and_compose)(os_log_pack_t, os_log_t,
+                       os_log_type_t, char *, size_t) = NULL;
+       _os_log_pack_send_and_compose = dlsym(RTLD_DEFAULT, "os_log_pack_send_and_compose");
+       if (!_os_log_pack_send_and_compose) return false;
+
+       os_log_t __os_log_default = NULL;
+       __os_log_default = dlsym(RTLD_DEFAULT, "_os_log_default");
+       if (!__os_log_default) return false;
+
+       char *composed = _os_log_pack_send_and_compose(pack, __os_log_default,
+                       OS_LOG_TYPE_FAULT, NULL, 0);
+
+       abort_with_payload(OS_REASON_LIBSYSTEM, OS_REASON_LIBSYSTEM_CODE_FAULT, pack, pack_size, composed, 0);
+}
+
 __attribute__((always_inline))
 static inline void
 _os_assumes_log_impl(uint64_t code)
@@ -286,25 +319,6 @@ _os_assert_log_impl(uint64_t code)
                result = strdup(message);
        }
 
-#if LIBC_NO_LIBCRASHREPORTERCLIENT
-       /* There is no crash report information facility on embedded, which is
-        * really regrettable. Fortunately, all we need to capture is the value
-        * which tripped up the assertion. We can just stuff that into the thread's 
-        * name.
-        */
-       char name[64];
-       (void)pthread_getname_np(pthread_self(), name, sizeof(name));
-
-       char newname[64];
-       if (strlen(name) == 0) {
-               (void)snprintf(newname, sizeof(newname), "[Fatal bug: 0x%llx]", code);
-       } else {
-               (void)snprintf(newname, sizeof(newname), "%s [Fatal bug: 0x%llx]", name, code);
-       }
-
-       (void)pthread_setname_np(newname);
-#endif
-
        return result;
 }
 
@@ -353,6 +367,11 @@ void _os_crash(const char *message)
        _os_crash_impl(message);
 }
 
+void _os_crash_fmt(os_log_pack_t pack, size_t pack_size)
+{
+       _os_crash_fmt_impl(pack, pack_size);
+}
+
 void
 _os_assumes_log(uint64_t code)
 {
index c120f4ec08f896bc8e17a4d703b71283ca0223c7..b25abbd7f024e411d81c433276274e589f3390f6 100644 (file)
@@ -24,6 +24,7 @@
 #define __OS_ASSUMES_H__
 
 #include <sys/cdefs.h>
+#include <stdalign.h>
 
 __BEGIN_DECLS
 
@@ -50,41 +51,68 @@ __BEGIN_DECLS
 #define __OS_COMPILETIME_ASSERT__(e) (e)
 #endif /* __GNUC__ */
 
+#pragma mark os_crash
 
-/* os_crash() is like os_hardware_trap(), except you get to pass in a crash
+/*
+ * os_crash() is like os_hardware_trap(), except you get to pass in a crash
  * message, and it can be redirected to a callback function using
- * os_set_crash_callback() */
-#define os_crash(msg) \
+ * os_set_crash_callback()
+ */
+
+#define __os_crash_simple(msg) \
        ({               \
                _os_crash(msg);                 \
                os_hardware_trap();             \
        })
 
-/* This is useful for clients who wish for the messages generated by assumes()
- * failures to go somewhere other than (or in addition to) the system log. If
- * you don't wish for the message to be logged to the system log, then return
- * true (to indicate that the message has been handled). If you want the default
- * behavior, return false.
- */
-typedef bool (*os_redirect_t)(const char *);
-struct _os_redirect_assumes_s {
-       os_redirect_t redirect;
-};
+#if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE)
+#include <os/log_private.h>
+
+#define __os_crash_fmt(...) \
+       ({ \
+               const size_t size = os_log_pack_size(__VA_ARGS__); \
+               uint8_t buf[size] __attribute__((aligned(alignof(os_log_pack_s)))); \
+               os_log_pack_t pack = (os_log_pack_t)&buf; \
+               os_log_pack_fill(pack, size, errno, __VA_ARGS__); \
+               _os_crash_fmt(pack, size); \
+               os_hardware_trap(); \
+       })
 
-#define OS_ASSUMES_REDIRECT_SEG "__DATA"
-#define OS_ASSUMES_REDIRECT_SECT "__os_assumes_log"
+#define __os_crash_N(msg) __os_crash_simple(msg)
+#define __os_crash_Y(...) __os_crash_fmt(__VA_ARGS__)
 
-#define os_redirect_assumes(func) \
-       __attribute__((__used__)) \
-       __attribute__((__section__(OS_ASSUMES_REDIRECT_SEG "," OS_ASSUMES_REDIRECT_SECT))) \
-       static struct _os_redirect_assumes_s _os_redirect_##func = { \
-               .redirect = &func, \
-       };
+// Returns Y if >1 argument, N if just one argument.
+#define __thirty_second_argument(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
+               _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, \
+               _26, _27, _28, _29, _30, _31, _32, ...) _32
+#define __has_more_than_one_argument(...) __thirty_second_argument(__VA_ARGS__, \
+               Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, \
+               Y, Y, Y, Y, Y, Y, Y, N, EXTRA)
+
+#define __os_crash_invoke(variant, ...) \
+        OS_CONCAT(__os_crash_, variant)(__VA_ARGS__)
+
+#define os_crash(...) \
+       __os_crash_invoke(__has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__)
+
+extern void
+_os_crash_fmt(os_log_pack_t, size_t);
+
+#else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
 
+#define os_crash(msg) __os_crash_simple(msg)
+
+#endif // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
+
+/*
+ * An executable can register a callback to be made upon a crash using the
+ * os_set_crash_callback function.  If a crash callback is not set, the symbol
+ * `os_crash_function` will be called in the main binary, if it exists.
+ */
 
 typedef void (*os_crash_callback_t) (const char *);
 
-/* private.  use os_get_crash_callback and os_set_crash_callback */
+/* private: use accessors below */
 extern os_crash_callback_t _os_crash_callback;
 
 static inline os_crash_callback_t
@@ -97,96 +125,189 @@ os_set_crash_callback(os_crash_callback_t callback) {
        _os_crash_callback = callback;
 }
 
-/* The asl_message argument is a _SIMPLE_STRING that, when given to _simple_asl_send(), will
- * direct the message to the MessageTracer diagnostic messages store rather than
- * the default system log store.
- */
-typedef bool (*os_log_callout_t)(_SIMPLE_STRING asl_message, void *ctx, const char *);
+#pragma mark os_assert
 
-#include <CrashReporterClient.h>
-#define os_set_crash_message(arg) CRSetCrashLogMessage(arg)
+#if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE)
 
-#define os_assumes(e) __extension__({ \
-       __typeof__(e) _e = os_fastpath(e); \
-       if (!_e) { \
-               if (os_constant(e)) { \
-                       __OS_COMPILETIME_ASSERT__(e); \
-               } \
-               _os_assumes_log((uint64_t)(uintptr_t)_e); \
-               _os_avoid_tail_call(); \
+#define _os_assert_crash(value, expression) ({ \
+               os_crash("assertion failure: \"" expression "\" -> %lld", value); \
+})
+
+#define _os_assert_crash_errno(value, expression) ({ \
+               os_crash("assertion failure: \"" expression "\" -> %{errno}d", value); \
+})
+
+#else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
+
+#define _os_assert_crash(e, ...) ({ \
+               char *_fail_message = _os_assert_log(e); \
+               os_crash(_fail_message); \
+               free(_fail_message); \
+})
+
+#define _os_assert_crash_errno(...) _os_assert_crash(__VA_ARGS__)
+
+#endif // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
+
+#define __os_assert(e) __extension__({ \
+       __typeof__(e) _e = (e); \
+       if (os_unlikely(!_e)) { \
+               if (os_constant(e)) { __OS_COMPILETIME_ASSERT__((e)); } \
+               _os_assert_crash((uint64_t)(uintptr_t)_e, #e); \
        } \
-       _e; \
 })
 
-#define os_assumes_zero(e) __extension__({ \
-       __typeof__(e) _e = os_slowpath(e); \
-       if (_e) { \
-               if (os_constant(e)) { \
-                       __OS_COMPILETIME_ASSERT__(!(e)); \
-               } \
-               _os_assumes_log((uint64_t)(uintptr_t)_e); \
-               _os_avoid_tail_call(); \
+#define __os_assert_zero(e) __extension__({ \
+       __typeof__(e) _e = (e); \
+       if (os_unlikely(_e)) { \
+               if (os_constant(e)) { __OS_COMPILETIME_ASSERT__(!(e)); } \
+               _os_assert_crash((uint64_t)(uintptr_t)_e, #e); \
        } \
-       _e; \
 })
 
-/* This variant is for use with old-style POSIX APIs that return -1 on failure
+/*
+ * This variant is for use with old-style POSIX APIs that return -1 on failure
  * and set errno. If the return code is -1, the value logged will be as though
- * os_assumes_zero(errno) was used. It encapsulates the following pattern:
+ * os_assert_zero(errno) was used. It encapsulates the following pattern:
  *
  * int tubes[2];
  * if (pipe(tubes) == -1) {
- *     (void)os_assumes_zero(errno);
+ *     (void)os_assert_zero(errno);
  * }
  */
-#define posix_assumes_zero(e) __extension__({ \
-       __typeof__(e) _e = os_slowpath(e); \
-       if (_e == (typeof(e))-1) { \
-               _os_assumes_log((uint64_t)(uintptr_t)errno); \
-               _os_avoid_tail_call(); \
+#define __posix_assert_zero(e) __extension__({ \
+       __typeof__(e) _e = (e); \
+       if (os_unlikely(_e == (__typeof__(e))-1)) { \
+               _os_assert_crash_errno(errno, #e); \
        } \
-       _e; \
 })
 
-#define os_assert(e) __extension__({ \
+#if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE)
+
+#define __os_assert_msg(e, fmt, ...) __extension__({ \
+       __typeof__(e) _e = (e); \
+       if (os_unlikely(!_e)) { \
+               os_crash("assertion failure: " fmt, ##__VA_ARGS__); \
+       } \
+})
+
+#define __os_assert_zero_msg(e, fmt, ...) __extension__({ \
+       __typeof__(e) _e = (e); \
+       if (os_unlikely(_e)) { \
+               os_crash("assertion failure (%lld): " fmt, value, ##__VA_ARGS__); \
+       } \
+})
+
+#define __posix_assert_zero_msg(e, fmt, ...) __extension__({ \
+       __typeof__(e) _e = (e); \
+       if (os_unlikely(_e == (__typeof__(e))-1)) { \
+               os_crash("assertion failure (%{errno}d): " fmt, errno, ##__VA_ARGS__); \
+       } \
+})
+
+#define __os_assert_N(e) __os_assert(e)
+#define __os_assert_Y(...) __os_assert_msg(__VA_ARGS__)
+#define __os_assert_zero_N(e) __os_assert_zero(e)
+#define __os_assert_zero_Y(...) __os_assert_zero_msg(__VA_ARGS__)
+#define __posix_assert_zero_N(e) __posix_assert_zero(e)
+#define __posix_assert_zero_Y(...) __posix_assert_zero_msg(__VA_ARGS__)
+
+#define __os_assert_invoke(function, variant, ...) \
+        OS_CONCAT(function, variant)(__VA_ARGS__)
+
+#define os_assert(...) \
+       __os_assert_invoke(__os_assert_, \
+                       __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__)
+#define os_assert_zero(...) \
+       __os_assert_invoke(__os_assert_zero_, \
+                       __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__)
+#define posix_assert_zero(...) \
+       __os_assert_invoke(__posix_assert_zero_, \
+                       __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__)
+
+#else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
+
+#define os_assert(e) __os_assert(e)
+#define os_assert_zero(e) __os_assert_zero(e)
+#define posix_assert_zero(e) __posix_assert_zero(e)
+
+#endif
+
+#pragma mark os_assumes
+
+
+#define os_assumes(e) __extension__({ \
        __typeof__(e) _e = os_fastpath(e); \
        if (!_e) { \
                if (os_constant(e)) { \
                        __OS_COMPILETIME_ASSERT__(e); \
                } \
-\
-               char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)_e); \
-               os_crash(_fail_message);             \
-               free(_fail_message); \
+               _os_assumes_log((uint64_t)(uintptr_t)_e); \
+               _os_avoid_tail_call(); \
        } \
+       _e; \
 })
 
-#define os_assert_zero(e) __extension__({ \
+#define os_assumes_zero(e) __extension__({ \
        __typeof__(e) _e = os_slowpath(e); \
        if (_e) { \
                if (os_constant(e)) { \
                        __OS_COMPILETIME_ASSERT__(!(e)); \
                } \
-\
-               char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)_e); \
-               os_crash(_fail_message);             \
-               free(_fail_message); \
+               _os_assumes_log((uint64_t)(uintptr_t)_e); \
+               _os_avoid_tail_call(); \
        } \
+       _e; \
 })
 
-#define posix_assert_zero(e) __extension__({ \
+#define posix_assumes_zero(e) __extension__({ \
        __typeof__(e) _e = os_slowpath(e); \
        if (_e == (__typeof__(e))-1) { \
-               char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)errno); \
-               os_crash(_fail_message);             \
-               free(_fail_message); \
+               _os_assumes_log((uint64_t)(uintptr_t)errno); \
+               _os_avoid_tail_call(); \
        } \
+       _e; \
 })
 
-/* These are for defining your own assumes()-like wrapper calls so that you can
+#pragma mark assumes redirection
+
+/* This is useful for clients who wish for the messages generated by assumes()
+ * failures to go somewhere other than (or in addition to) the system log. If
+ * you don't wish for the message to be logged to the system log, then return
+ * true (to indicate that the message has been handled). If you want the default
+ * behavior, return false.
+ */
+typedef bool (*os_redirect_t)(const char *);
+struct _os_redirect_assumes_s {
+       os_redirect_t redirect;
+};
+
+#define OS_ASSUMES_REDIRECT_SEG "__DATA"
+#define OS_ASSUMES_REDIRECT_SECT "__os_assumes_log"
+
+#define os_redirect_assumes(func) \
+       __attribute__((__used__)) \
+       __attribute__((__section__(OS_ASSUMES_REDIRECT_SEG "," OS_ASSUMES_REDIRECT_SECT))) \
+       static struct _os_redirect_assumes_s _os_redirect_##func = { \
+               .redirect = &func, \
+       };
+
+#pragma mark _ctx variants
+
+/*
+ * These are for defining your own assumes()-like wrapper calls so that you can
  * log additional information, such as the about-PID, sender, etc. They're
  * generally not useful for direct inclusion in your code.
  */
+
+/*
+ * The asl_message argument is a _SIMPLE_STRING that, when given to _simple_asl_send(), will
+ * direct the message to the MessageTracer diagnostic messages store rather than
+ * the default system log store.
+ */
+typedef bool (*os_log_callout_t)(_SIMPLE_STRING asl_message, void *ctx, const char *);
+
+
 #define os_assumes_ctx(f, ctx, e) __extension__({ \
        __typeof__(e) _e = os_fastpath(e); \
        if (!_e) { \
@@ -255,6 +376,8 @@ typedef bool (*os_log_callout_t)(_SIMPLE_STRING asl_message, void *ctx, const ch
        } \
 })
 
+#pragma mark internal symbols
+
 __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0)
 extern void
 _os_crash(const char *);
diff --git a/os/variant_private.h b/os/variant_private.h
new file mode 100644 (file)
index 0000000..f9826cd
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+#ifndef __OS_VARIANT_H__
+#define __OS_VARIANT_H__
+
+#include <stdbool.h>
+
+#include <os/base.h>
+#include <os/availability.h>
+
+/*! @header
+ * OS Variant SPI
+ *
+ * Provides a mechanism to determine the currently running OS variant.
+ *
+ * Any of these APIs may be overridden to its non-internal behavior on a
+ * device by creating on override file.  On macOS, this file is placed
+ * at:
+ *    /var/db/os_variant_override
+ * On embedded platforms, this file is placed at:
+ *    /usr/share/misc/os_variant_override
+ *
+ * Individual internal behaviors can be selectively disabled (ie.
+ * individual os_variant_has_internal_*() predicates can be overriden to
+ * false) by writing the file with a comma- or newline-delimited list of
+ * names to disable.  To disable all internal behaviors, empty the file.
+ *
+ * Each of these functions takes a constant string argument for the requesting
+ * subsystem.  This should be a reverse-DNS string describing the subsystem
+ * performing the check.  This may be used in the future for auditing and
+ * selective overriding of checks.
+ *
+ */
+
+__BEGIN_DECLS
+
+/*!
+ * @function os_variant_has_internal_content
+ *
+ * @abstract returns whether this system variant has internal content installed
+ * ("content")
+ *
+ * @result
+ * Returns true if this build has this property.  False otherwise or upon error.
+ */
+API_AVAILABLE(macosx(10.13), ios(11.0), tvos(11.0), watchos(4.0))
+OS_EXPORT OS_WARN_RESULT
+bool
+os_variant_has_internal_content(const char *subsystem);
+
+/*!
+ * @function os_variant_has_internal_diagnostics
+ *
+ * @abstract returns whether this system variant has internal diagnostics
+ * enabled ("diagnostics")
+ *
+ * @description
+ *
+ * Internal diagnostics include behaviors that emit extra diagnostic or
+ * debugging information when an error occurs.
+ *
+ * On macOS, this check will look for presence of AppleInternal content or the
+ * AppleInternalDiagnostics profile to be installed.
+ *
+ * On embedded platforms, this check will look for an internal install variant
+ * in a manner similar to the MobileGestalt check for InternalBuild.
+ *
+ * @result
+ * Returns true if this build has this property.  False otherwise or upon error.
+ */
+API_AVAILABLE(macosx(10.13), ios(11.0), tvos(11.0), watchos(4.0))
+OS_EXPORT OS_WARN_RESULT
+bool
+os_variant_has_internal_diagnostics(const char *subsystem);
+
+/*!
+ * @function os_variant_has_internal_ui
+ *
+ * @abstract returns whether this system variant has internal UI visible ("ui")
+ *
+ * @description
+ *
+ * Internal UI includes debug menus and internal settings.
+ *
+ * On macOS, this will check for the presence of AppleInternal content.  On
+ * embedded platforms, this check will look for an internal install variant in
+ * a manor similar to the MobileGestalt check for InternalBuild.
+ *
+ * @result
+ * Returns true if this build has this property.  False otherwise or upon error.
+ */
+API_AVAILABLE(macosx(10.13), ios(11.0), tvos(11.0), watchos(4.0))
+OS_EXPORT OS_WARN_RESULT
+bool
+os_variant_has_internal_ui(const char *subsystem);
+
+/*!
+ * @function os_variant_allows_internal_security_policies
+ *
+ * @abstract returns whether this system variant allows internal security policies
+ * ("security")
+ *
+ * @description
+ *
+ * On macOS, this will check the CSR status for whether AppleInternal policies
+ * are enabled.
+ *
+ * On embedded platforms, this will check for a build/device combination that
+ * allows for removal of codesigning and debugging restrictions.  This usually
+ * returns whether the hardware is development fused and may return true on
+ * such hardware even if a customer build is installed.
+ *
+ * n.b. The result of this API should /not/ be used to automatically enable
+ * relaxed security policies, only to signal that other mechanisms to enable
+ * them are allowed, e.g. a "defaults write".
+ *
+ * @result
+ * Returns true if this build has this property.  False otherwise or upon error.
+ */
+API_AVAILABLE(macosx(10.13), ios(11.0), tvos(11.0), watchos(4.0))
+OS_EXPORT OS_WARN_RESULT
+bool
+os_variant_allows_internal_security_policies(const char *subsystem);
+
+__END_DECLS
+
+#endif // __os_variant_H__
index 29401b886dafaff4fc867ee335f3a5a9b9e852dd..db859a6e6bdc9b5463ba36fc6a9c86b29602ea17 100644 (file)
 #include <stdlib.h>
 #include <TargetConditionals.h>
 
+
+#if !defined(PR_13085474_CHECK)
+#define PR_13085474_CHECK 1
+
+/* Some shipped applications fail this check and were tested against
+ * versions of these functions that supported overlapping buffers.
+ *
+ * We would rather let such applications run, using the old memmove
+ * implementation, than abort() because they can't use the new
+ * implementation.
+ */
+
+#include <libkern/OSAtomic.h>
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_priv.h>
+#define DYLD_OS_VERSION(major, minor, tiny) ((((major) & 0xffff) << 16) | (((minor) & 0xff) << 8) | ((tiny) & 0xff))
+#if TARGET_OS_IPHONE
+#define START_VERSION DYLD_OS_VERSION(7,0,0)
+#else
+#define START_VERSION DYLD_OS_VERSION(10,9,0)
+#endif
+#endif /* !PR_13085474_CHECK */
+
+/* For PR_13085474_CHECK set, we initialize __chk_assert_no_overlap to
+ * a value neither 0 or 1.  We call _dyld_register_func_for_add_image()
+ * to register a callback, and use the non-one value of
+ * __chk_assert_no_overlap to skip sdk version checks (but we do
+ * perform overlap checks).  To detect if the main program was built
+ * prior to START_VERSION, we call dyld_get_program_sdk_version(),
+ * which we do before setting up the callback (since we don't need it
+ * if the main program is older).
+ *
+ * After _dyld_register_func_for_add_image() returns, we set
+ * __chk_assert_no_overlap to 1, which enables the sdk version checking
+ * for subsequent loaded shared objects.  If we then find an old version,
+ * we set __chk_assert_no_overlap to 0 to turn off overlap checking.
+ *
+ * If PR_13085474_CHECK is zero, then we never do any sdk version checking
+ * and always do overlap checks.
+ */
+__attribute__ ((visibility ("hidden")))
+uint32_t __chk_assert_no_overlap
+#if PR_13085474_CHECK
+                                 = 42;
+#else
+                                 = 1;
+#endif
+
+#if PR_13085474_CHECK
+static void
+__chk_assert_no_overlap_callback(const struct mach_header *mh, intptr_t vmaddr_slide __unused) {
+  if (__chk_assert_no_overlap != 1) return;
+  if (dyld_get_sdk_version(mh) < START_VERSION) OSAtomicAnd32(0U, &__chk_assert_no_overlap);
+}
+#endif
+
+__attribute__ ((visibility ("hidden")))
+void __chk_init(void) {
+#if PR_13085474_CHECK
+  if (dyld_get_program_sdk_version() < START_VERSION) {
+    __chk_assert_no_overlap = 0;
+  } else {
+    _dyld_register_func_for_add_image(__chk_assert_no_overlap_callback);
+    __chk_assert_no_overlap = 1;
+  }
+#endif
+}
+
+__attribute__ ((noreturn))
+static void
+__chk_fail (const char *message)
+{
+  syslog(LOG_CRIT, "%s", message);
+  abort_report_np("%s", message);
+}
+
+__attribute__ ((visibility ("hidden")))
+__attribute__ ((noreturn))
+void
+__chk_fail_overflow (void) {
+  __chk_fail("detected buffer overflow");
+}
+
+__attribute__ ((visibility ("hidden")))
+__attribute__ ((noreturn))
+void
+__chk_fail_overlap (void) {
+  __chk_fail("detected source and destination buffer overlap");
+}
+
+
+__attribute__ ((visibility ("hidden")))
+void
+__chk_overlap (const void *_a, size_t an, const void *_b, size_t bn) {
+  uintptr_t a = (uintptr_t)_a;
+  uintptr_t b = (uintptr_t)_b;
+
+  if (__builtin_expect(an == 0 || bn == 0, 0)) {
+    return;
+  } else if (__builtin_expect(a == b, 0)) {
+    __chk_fail_overlap();
+  } else if (a < b) {
+    if (__builtin_expect(a + an > b, 0))
+      __chk_fail_overlap();
+  } else { // b < a
+    if (__builtin_expect(b + bn > a, 0))
+      __chk_fail_overlap();
+  }
+}
index a556da385199a5e9acec7d8d6ccdc00b37f94cfc..330830f9e8d7c0a87407be55cfcae9df47c59176 100644 (file)
@@ -38,6 +38,7 @@
 __FBSDID("$FreeBSD: src/lib/libc/stdio/_flock_stub.c,v 1.16 2008/04/17 22:17:53 jhb Exp $");
 
 #include "namespace.h"
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -46,7 +47,6 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/_flock_stub.c,v 1.16 2008/04/17 22:17:53
 
 #include "local.h"
 
-
 /*
  * Weak symbols for externally visible functions in this file:
  */
@@ -58,7 +58,10 @@ __weak_reference(_funlockfile, funlockfile);
 void
 _flockfile(FILE *fp)
 {
+       // <rdar://problem/21533199> - preserve errno.
+       int save_errno = errno;
        _pthread_mutex_lock(&fp->_fl_mutex);
+       errno = save_errno;
 }
 
 /*
@@ -75,14 +78,20 @@ _ftrylockfile(FILE *fp)
 {
        int     ret = 0;
 
+       // <rdar://problem/21533199> - preserve errno.
+       int save_errno = errno;
        if (_pthread_mutex_trylock(&fp->_fl_mutex) != 0)
                ret = -1;
-       
+       errno = save_errno;
+
        return (ret);
 }
 
 void 
 _funlockfile(FILE *fp)
 {
+       // <rdar://problem/21533199> - preserve errno.
+       int save_errno = errno;
        _pthread_mutex_unlock(&fp->_fl_mutex);
+       errno = save_errno;
 }
index ead24c34a6f8265b0900fe39b957722b9d36aba1..709244f24d7a94a2628c792ace4ab815508de55d 100644 (file)
@@ -89,7 +89,7 @@ __fgetwc(FILE *fp, locale_t loc)
                return (wc);
        }
        do {
-               nconv = __mbrtowc(&wc, fp->_p, fp->_r, &fp->_mbstate, loc);
+               nconv = __mbrtowc(&wc, (char*)fp->_p, fp->_r, &fp->_mbstate, loc);
                if (nconv == (size_t)-1)
                        break;
                else if (nconv == (size_t)-2)
index 1f515abd01e3424970031925cb8f3f61cfa9968a..f5a31f51756c802fc4d6b5b82dac883a031365a8 100644 (file)
@@ -119,18 +119,19 @@ static pthread_mutex_t filelist_lock = PTHREAD_MUTEX_INITIALIZER;
 #define FILELIST_UNLOCK()      do { pthread_mutex_unlock(&filelist_lock); } while(0)
 
 static struct glue *
-moreglue(n)
-       int n;
+moreglue(int n)
 {
        struct glue *g;
        FILE *p;
        struct __sFILEX *fx;
+       size_t align;
 
-       g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE) +
+       align = __alignof__( (struct { FILE f; struct __sFILEX s; }){} );
+       g = (struct glue *)malloc(sizeof(*g) + align + n * sizeof(FILE) +
            n * sizeof(struct __sFILEX));
        if (g == NULL)
                return (NULL);
-       p = (FILE *)ALIGN(g + 1);
+       p = (FILE *)roundup((uintptr_t)(g + 1), align);
        fx = (struct __sFILEX *)&p[n];
        g->next = NULL;
        g->niobs = n;
@@ -158,13 +159,14 @@ __sfp(int count)
        pthread_once(&__sdidinit, __sinit);
 
        if (count) {
-               if (__scounted >= __stream_max) {
-                       if (__scounted >= (__stream_max = sysconf(_SC_STREAM_MAX))){
+               int32_t new = OSAtomicIncrement32(&__scounted);
+               if (new > __stream_max) {
+                       if (new > (__stream_max = sysconf(_SC_STREAM_MAX))){
+                               OSAtomicDecrement32(&__scounted);
                                errno = EMFILE;
                                return NULL;
                        }
                }
-               OSAtomicIncrement32(&__scounted);
        }
        /*
         * The list must be locked because a FILE may be updated.
@@ -261,7 +263,7 @@ f_prealloc(void)
  * The name `_cleanup' is, alas, fairly well known outside stdio.
  */
 void
-_cleanup()
+_cleanup(void)
 {
        /* (void) _fwalk(fclose); */
        (void) _fwalk(__sflush);                /* `cheating' */
@@ -271,7 +273,7 @@ _cleanup()
  * __sinit() is called whenever stdio's internal variables must be set up.
  */
 void
-__sinit()
+__sinit(void)
 {
 #if !TARGET_OS_EMBEDDED
        int i;
diff --git a/stdio/FreeBSD/fmemopen.c b/stdio/FreeBSD/fmemopen.c
new file mode 100644 (file)
index 0000000..bcf187d
--- /dev/null
@@ -0,0 +1,262 @@
+/*-
+ * Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
+ * 
+ * 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.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "local.h"
+
+struct fmemopen_cookie
+{
+       char    *buf;   /* pointer to the memory region */
+       bool     own;   /* did we allocate the buffer ourselves? */
+       char     bin;   /* is this a binary buffer? */
+       size_t   size;  /* buffer length in bytes */
+       size_t   len;   /* data length in bytes */
+       size_t   off;   /* current offset into the buffer */
+};
+
+static int     fmemopen_read(void *cookie, char *buf, int nbytes);
+static int     fmemopen_write(void *cookie, const char *buf, int nbytes);
+static fpos_t  fmemopen_seek(void *cookie, fpos_t offset, int whence);
+static int     fmemopen_close(void *cookie);
+
+FILE *
+fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
+{
+       struct fmemopen_cookie *ck;
+       FILE *f;
+       int flags, rc;
+
+       /*
+        * POSIX says we shall return EINVAL if size is 0.
+        */
+       if (size == 0) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
+       /*
+        * Retrieve the flags as used by open(2) from the mode argument, and
+        * validate them.
+        */
+       rc = __sflags(mode, &flags);
+       if (rc == 0) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
+       /*
+        * There's no point in requiring an automatically allocated buffer
+        * in write-only mode.
+        */
+       if (!(flags & O_RDWR) && buf == NULL) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       
+       ck = malloc(sizeof(struct fmemopen_cookie));
+       if (ck == NULL) {
+               return (NULL);
+       }
+
+       ck->off  = 0;
+       ck->size = size;
+
+       /* Check whether we have to allocate the buffer ourselves. */
+       ck->own = ((ck->buf = buf) == NULL);
+       if (ck->own) {
+               ck->buf = malloc(size);
+               if (ck->buf == NULL) {
+                       free(ck);
+                       return (NULL);
+               }
+       }
+
+       /*
+        * POSIX distinguishes between w+ and r+, in that w+ is supposed to
+        * truncate the buffer.
+        */
+       if (ck->own || mode[0] == 'w') {
+               ck->buf[0] = '\0';
+       }
+
+       /* Check for binary mode. */
+       ck->bin = strchr(mode, 'b') != NULL;
+
+       /*
+        * The size of the current buffer contents is set depending on the
+        * mode:
+        * 
+        * for append (text-mode), the position of the first NULL byte, or the
+        * size of the buffer if none is found
+        *
+        * for append (binary-mode), the size of the buffer
+        * 
+        * for read, the size of the buffer
+        * 
+        * for write, 0
+        */
+       switch (mode[0]) {
+       case 'a':
+               ck->off = ck->len = strnlen(ck->buf, ck->size);
+               break;
+       case 'r':
+               ck->len = size;
+               break;
+       case 'w':
+               ck->len = 0;
+               break;
+       }
+
+       f = funopen(ck,
+           flags & O_WRONLY ? NULL : fmemopen_read, 
+           flags & O_RDONLY ? NULL : fmemopen_write,
+           fmemopen_seek, fmemopen_close);
+
+       if (f == NULL) {
+               if (ck->own)
+                       free(ck->buf);
+               free(ck);
+               return (NULL);
+       }
+
+       if (mode[0] == 'a')
+               f->_flags |= __SAPP;
+
+       /*
+        * Turn off buffering, so a write past the end of the buffer
+        * correctly returns a short object count.
+        */
+       setvbuf(f, NULL, _IONBF, 0);
+
+       return (f);
+}
+
+static int
+fmemopen_read(void *cookie, char *buf, int nbytes)
+{
+       struct fmemopen_cookie *ck = cookie;
+
+       if (nbytes > ck->len - ck->off)
+               nbytes = ck->len - ck->off;
+
+       if (nbytes == 0)
+               return (0);
+
+       memcpy(buf, ck->buf + ck->off, nbytes);
+
+       ck->off += nbytes;
+
+       return (nbytes);
+}
+
+static int
+fmemopen_write(void *cookie, const char *buf, int nbytes)
+{
+       struct fmemopen_cookie *ck = cookie;
+
+       if (nbytes > ck->size - ck->off)
+               nbytes = ck->size - ck->off;
+
+       if (nbytes == 0)
+               return (0);
+
+       memcpy(ck->buf + ck->off, buf, nbytes);
+
+       ck->off += nbytes;
+
+       if (ck->off > ck->len)
+               ck->len = ck->off;
+
+       /*
+        * We append a NULL byte if all these conditions are met:
+        * - the buffer is not binary
+        * - the buffer is not full
+        * - the data just written doesn't already end with a NULL byte
+        */
+       if (!ck->bin && ck->off < ck->size && ck->buf[ck->off - 1] != '\0')
+               ck->buf[ck->off] = '\0';
+
+       return (nbytes);
+}
+
+static fpos_t
+fmemopen_seek(void *cookie, fpos_t offset, int whence)
+{
+       struct fmemopen_cookie *ck = cookie;
+
+
+       switch (whence) {
+       case SEEK_SET:
+               if (offset > ck->size) {
+                       errno = EINVAL;
+                       return (-1);
+               }
+               ck->off = offset;
+               break;
+
+       case SEEK_CUR:
+               if (ck->off + offset > ck->size) {
+                       errno = EINVAL;
+                       return (-1);
+               }
+               ck->off += offset;
+               break;
+
+       case SEEK_END:
+               if (offset > 0 || -offset > ck->len) {
+                       errno = EINVAL;
+                       return (-1);
+               }
+               ck->off = ck->len + offset;
+               break;
+
+       default:
+               errno = EINVAL;
+               return (-1);
+       }
+
+       return (ck->off);
+}
+
+static int
+fmemopen_close(void *cookie)
+{
+       struct fmemopen_cookie *ck = cookie;
+
+       if (ck->own)
+               free(ck->buf);
+
+       free(ck);
+
+       return (0);
+}
index ab304e9b4fc5efc367625dd43162a418bc79198d..e057f350cae369371b938c6c8be2c69dcd523420 100644 (file)
@@ -13,7 +13,7 @@
 .\" 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.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. 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.
 .\"
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)fopen.3    8.1 (Berkeley) 6/4/93
-.\" $FreeBSD: src/lib/libc/stdio/fopen.3,v 1.21 2009/09/09 19:38:19 ed Exp $
+.\" $FreeBSD$
 .\"
-.Dd January 26, 2003
+.Dd January 30, 2013
 .Dt FOPEN 3
 .Os
 .Sh NAME
-.Nm fdopen ,
 .Nm fopen ,
-.Nm freopen
+.Nm fdopen ,
+.Nm freopen ,
+.Nm fmemopen
 .Nd stream open functions
 .Sh LIBRARY
 .Lb libc
 .Sh SYNOPSIS
 .In stdio.h
 .Ft FILE *
-.Fo fdopen
-.Fa "int fildes"
-.Fa "const char *mode"
-.Fc
+.Fn fopen "const char * restrict path" "const char * restrict mode"
 .Ft FILE *
-.Fo fopen
-.Fa "const char *restrict filename"
-.Fa "const char *restrict mode"
-.Fc
+.Fn fdopen "int fildes" "const char *mode"
 .Ft FILE *
-.Fo freopen
-.Fa "const char *restrict filename"
-.Fa "const char *restrict mode"
-.Fa "FILE *restrict stream"
-.Fc
+.Fn freopen "const char *path" "const char *mode" "FILE *stream"
+.Ft FILE *
+.Fn fmemopen "void *restrict *buf" "size_t size" "const char * restrict mode"
 .Sh DESCRIPTION
 The
 .Fn fopen
 function
 opens the file whose name is the string pointed to by
-.Fa filename
+.Fa path
 and associates a stream with it.
 .Pp
 The argument
 .Fa mode
-points to a string beginning with one of the following
-sequences (Additional characters may follow these sequences.):
+points to a string beginning with one of the following letters:
 .Bl -tag -width indent
 .It Dq Li r
-Open text file for reading.
-The stream is positioned at the beginning of the file.
-.It Dq Li r+
-Open for reading and writing.
+Open for reading.
 The stream is positioned at the beginning of the file.
+Fail if the file does not exist.
 .It Dq Li w
-Truncate to zero length or create text file for writing.
-The stream is positioned at the beginning of the file.
-.It Dq Li w+
-Open for reading and writing.
-The file is created if it does not exist, otherwise it is truncated.
+Open for writing.
 The stream is positioned at the beginning of the file.
+Create the file if it does not exist.
 .It Dq Li a
 Open for writing.
-The file is created if it does not exist.
-The stream is positioned at the end of the file.
-Subsequent writes to the file will always end up at the then current
-end of file, irrespective of any intervening
-.Xr fseek 3
-or similar.
-.It Dq Li a+
-Open for reading and writing.
-The file is created if it does not exist.
 The stream is positioned at the end of the file.
 Subsequent writes to the file will always end up at the then current
 end of file, irrespective of any intervening
 .Xr fseek 3
 or similar.
+Create the file if it does not exist.
 .El
 .Pp
+An optional
+.Dq Li +
+following
+.Dq Li r ,
+.Dq Li w ,
+or
+.Dq Li a
+opens the file for both reading and writing.
+An optional
+.Dq Li x
+following
+.Dq Li w
+or
+.Dq Li w+
+causes the
+.Fn fopen
+call to fail if the file already exists.
+An optional
+.Dq Li e
+following the above
+causes the
+.Fn fopen
+call to set the
+.Dv FD_CLOEXEC
+flag on the underlying file descriptor.
+.Pp
 The
 .Fa mode
-string can also include the letter ``b'' either as last character or
-as a character between the characters in any of the two-character strings
-described above.
+string can also include the letter
+.Dq Li b
+after either the
+.Dq Li +
+or the first letter.
 This is strictly for compatibility with
 .St -isoC
-and has no effect; the ``b'' is ignored.
-.Pp
-Finally, as an extension to the standards (and thus may not be portable),
-.Fa mode
-string may end with the letter ``x'', which insists on creating a new file
-when used with ``w'' or ``a''.
-If
-.Fa path
-exists, then an error is returned (this is the equivalent of specifying
-.Dv O_EXCL
-with
-.Xr open 2 ) .
+and has effect only for
+.Fn fmemopen
+; otherwise
+.Dq Li b
+is ignored.
 .Pp
 Any created files will have mode
-.Pf \\*q Dv S_IRUSR
+.Do Dv S_IRUSR
 \&|
 .Dv S_IWUSR
 \&|
@@ -135,12 +135,11 @@ Any created files will have mode
 \&|
 .Dv S_IROTH
 \&|
-.Dv S_IWOTH Ns \\*q
+.Dv S_IWOTH Dc
 .Pq Li 0666 ,
 as modified by the process'
 umask value (see
 .Xr umask 2 ) .
-.\" C11 Â§7.21.5.3p7
 .Pp
 Reads and writes may be intermixed on read/write streams in any order; however, 
 a file positioning function must be called when switching between output and
@@ -152,6 +151,14 @@ function associates a stream with the existing file descriptor,
 .Fa fildes .
 The mode
 of the stream must be compatible with the mode of the file descriptor.
+The
+.Dq Li x
+mode option is ignored.
+If the
+.Dq Li e
+mode option is present, the
+.Dv FD_CLOEXEC
+flag is set, otherwise it remains unchanged.
 When the stream is closed via
 .Xr fclose 3 ,
 .Fa fildes
@@ -161,7 +168,7 @@ The
 .Fn freopen
 function
 opens the file whose name is the string pointed to by
-.Fa filename
+.Fa path
 and associates the stream pointed to by
 .Fa stream
 with it.
@@ -173,7 +180,7 @@ argument is used just as in the
 function.
 .Pp
 If the
-.Fa filename
+.Fa path
 argument is
 .Dv NULL ,
 .Fn freopen
@@ -182,29 +189,12 @@ attempts to re-open the file associated with
 with a new mode.
 The new mode must be compatible with the mode that the stream was originally
 opened with:
-.Bl -bullet -offset indent
-.It
-Streams originally opened with mode
-.Dq Li r
-can only be reopened with that same mode.
-.It
-Streams originally opened with mode
-.Dq Li a
-can be reopened with the same mode, or mode
-.Dq Li w .
-.It
-Streams originally opened with mode
-.Dq Li w
-can be reopened with the same mode, or mode
-.Dq Li a .
-.It
-Streams originally opened with mode
-.Dq Li r+ ,
-.Dq Li w+ ,
-or
-.Dq Li a+
-can be reopened with any mode.
-.El
+Streams open for reading can only be re-opened for reading,
+streams open for writing can only be re-opened for writing,
+and streams open for reading and writing can be re-opened in any mode.
+The
+.Dq Li x
+mode option is not meaningful in this context.
 .Pp
 The primary use of the
 .Fn freopen
@@ -214,12 +204,47 @@ standard text stream
 .Dv ( stderr , stdin ,
 or
 .Dv stdout ) .
+.Pp
+The
+.Fn fmemopen
+function
+associates the buffer given by the
+.Fa buf
+and
+.Fa size
+arguments with a stream.
+The
+.Fa buf
+argument is either a null pointer or a pointer to a buffer that
+is at least
+.Fa size
+bytes long.
+If a null pointer is specified as the
+.Fa buf
+argument,
+.Fn fmemopen
+allocates
+.Fa size
+bytes of memory, and this allocation is automatically freed when the stream is
+closed.
+If a non-null pointer is specified, the caller retains ownership of
+the buffer and is responsible for disposing of it after the stream has been
+closed.
+Buffers can be opened in text-mode (default) or binary-mode
+(if
+.Dq Li b
+is present in the second or third position of the
+.Fa mode
+argument). Buffers opened in text-mode make sure that writes are terminated with
+a NULL byte, if the last write hasn't filled up the whole buffer. Buffers
+opened in binary-mode never append a NULL byte.
 .Sh RETURN VALUES
 Upon successful completion
 .Fn fopen ,
 .Fn fdopen ,
-and
 .Fn freopen
+and
+.Fn fmemopen
 return a
 .Tn FILE
 pointer.
@@ -237,16 +262,18 @@ argument
 to
 .Fn fopen ,
 .Fn fdopen ,
+.Fn freopen ,
 or
-.Fn freopen
+.Fn fmemopen
 was invalid.
 .El
 .Pp
 The
 .Fn fopen ,
-.Fn fdopen
-and
+.Fn fdopen ,
 .Fn freopen
+and
+.Fn fmemopen
 functions
 may also fail and set
 .Va errno
@@ -279,6 +306,15 @@ for any of the errors specified for the routines
 .Xr fclose 3
 and
 .Xr fflush 3 .
+.Pp
+The
+.Fn fmemopen
+function
+may also fail and set
+.Va errno
+if the
+.Fa size
+argument is 0.
 .Sh SEE ALSO
 .Xr open 2 ,
 .Xr fclose 3 ,
@@ -292,9 +328,26 @@ and
 .Fn freopen
 functions
 conform to
-.St -isoC .
+.St -isoC ,
+with the exception of the
+.Dq Li x
+mode option which conforms to
+.St -isoC-2011 .
 The
 .Fn fdopen
 function
 conforms to
 .St -p1003.1-88 .
+The
+.Dq Li e
+mode option does not conform to any standard
+but is also supported by glibc.
+The
+.Fn fmemopen
+function
+conforms to
+.St -p1003.1-2008 .
+The
+.Dq Li b
+mode does not conform to any standard
+but is also supported by glibc.
index 163541bec88ff73d8a2157aa7e41069b2747ca79..0cd58efeb8e726ff1cea0159dccf05e3655e3f61 100644 (file)
@@ -45,7 +45,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/fputs.c,v 1.12 2007/01/09 00:28:06 imp Ex
 #include "local.h"
 
 // 3340719: __puts_null__ is used if string is NULL.  Defined in puts.c
-__private_extern__ char const __puts_null__[];
+extern char const __puts_null__[];
 
 /*
  * Write the given string to the given file.
index 02ff26dfecbbe41652d2fd07ff0c307ea9caa9e0..705231a3965414bbece85d09c802d5e2227bbb15 100644 (file)
@@ -142,7 +142,7 @@ getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim,
 
        linelen = 0;
        while ((endp = memchr(fp->_p, delim, fp->_r)) == NULL) {
-               if (sappend(linep, &linelen, linecapp, fp->_p, fp->_r))
+               if (sappend(linep, &linelen, linecapp, (char*)fp->_p, fp->_r))
                        goto error;
                if (__srefill(fp)) {
                        if (__sferror(fp))
@@ -151,7 +151,7 @@ getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim,
                }
        }
        endp++; /* snarf the delimiter, too */
-       if (sappend(linep, &linelen, linecapp, fp->_p, endp - fp->_p))
+       if (sappend(linep, &linelen, linecapp, (char*)fp->_p, endp - fp->_p))
                goto error;
        fp->_r -= endp - fp->_p;
        fp->_p = endp;
index d4072c63189e74570c9adcb7c04067d500482672..3a55c7f8f27521b9dfdef6c192c41a2a84527cd8 100644 (file)
 .Nm mktemp ,
 .Nm mkstemp ,
 .Nm mkdtemp ,
+.Nm mkdtempat_np ,
 .Nm mkstemps ,
+.Nm mkstempsat_np ,
 .Nm mkostemp ,
-.Nm mkostemps
+.Nm mkostemps ,
+.Nm mkostempsat_np
 .Nd make temporary file name (unique)
 .Sh LIBRARY
 .Lb libc
 .Fo mkdtemp
 .Fa "char *template"
 .Fc
+.Ft char *
+.Fo mkdtempat_np
+.Fa "int dfd"
+.Fa "char *template"
+.Fc
 .Ft int
 .Fo mkstemps
 .Fa "char *template"
 .Fa "int suffixlen"
 .Fc
 .Ft int
+.Fo mkstempsat_np
+.Fa "int dfd"
+.Fa "char *template"
+.Fa "int suffixlen"
+.Fc
+.Ft int
 .Fo mkostemp
 .Fa "char *template"
 .Fa "int oflags"
 .Fa "int suffixlen"
 .Fa "int oflags"
 .Fc
+.Ft int
+.Fo mkostempsat_np
+.Fa "int dfd"
+.Fa "char *template"
+.Fa "int suffixlen"
+.Fa "int oflags"
+.Fc
 .Sh DESCRIPTION
 The
 .Fn mktemp
@@ -147,6 +168,25 @@ and
 .Fn mkostemps
 functions
 are told the length of the suffix string.
+.Pp
+The
+.Fn mkdtempat_np ,
+.Fn mkstempsat_np ,
+and
+.Fn mkostempsat_np
+functions
+act the same as
+.Fn mkdtemp ,
+.Fn mkstemps ,
+and
+.Fn mkostemps
+respectively,
+except in the case where the
+.Ar path
+specifies a relative path.
+In this case, path is treated as relative to the directory associated with the file descriptor
+.Ar fd
+instead of the current working directory.
 .Sh RETURN VALUES
 The
 .Fn mktemp
index 08b0aec4f0b11fdef236927d496c04e9f704f81a..001cf3e2a7012852762f573ef4743c9e4bfb57e8 100644 (file)
@@ -33,6 +33,7 @@ static char sccsid[] = "@(#)mktemp.c  8.1 (Berkeley) 6/4/93";
 #include <sys/cdefs.h>
 
 #include "namespace.h"
+#include <assert.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -60,19 +61,19 @@ typedef enum {
  * Otherwise return FTPP_TRY_NEXT.
  */
 typedef find_temp_path_progress_t (*find_temp_path_action_t)(
-               char *path, void *ctx, void *result);
+               int dfd, char *path, void *ctx, void *result);
 
-static int find_temp_path(char *path, int slen, bool stat_base_dir,
+static int find_temp_path(int dfd, char *path, int slen, bool stat_base_dir,
                find_temp_path_action_t action, void *action_ctx, void *action_result);
 
 static find_temp_path_progress_t _mkostemps_action(
-               char *path, void *ctx, void *result);
+               int dfd, char *path, void *ctx, void *result);
 static find_temp_path_progress_t _mktemp_action(
-               char *path, void *ctx, void *result);
+               int dfd, char *path, void *ctx, void *result);
 static find_temp_path_progress_t _mkdtemp_action(
-               char *path, void *ctx, void *result);
+               int dfd, char *path, void *ctx, void *result);
 static find_temp_path_progress_t _mkstemp_dprotected_np_action(
-               char *path, void *ctx, void *result);
+               int dfd, char *path, void *ctx, void *result);
 
 static const char padchar[] =
 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -85,7 +86,18 @@ mkostemps(char *path, int slen, int oflags)
                errno = EINVAL;
                return -1;
        }
-       return (find_temp_path(path, slen, TRUE, _mkostemps_action, &oflags, &fd) ? fd : -1);
+       return (find_temp_path(AT_FDCWD, path, slen, TRUE, _mkostemps_action, &oflags, &fd) ? fd : -1);
+}
+
+int
+mkostempsat_np(int dfd, char *path, int slen, int oflags)
+{
+       int fd;
+       if (oflags & ~ALLOWED_MKOSTEMP_FLAGS) {
+               errno = EINVAL;
+               return -1;
+       }
+       return (find_temp_path(dfd, path, slen, TRUE, _mkostemps_action, &oflags, &fd) ? fd : -1);
 }
 
 int
@@ -93,7 +105,15 @@ mkstemps(char *path, int slen)
 {
        int fd;
 
-       return (find_temp_path(path, slen, TRUE, _mkostemps_action, NULL, &fd) ? fd : -1);
+       return (find_temp_path(AT_FDCWD, path, slen, TRUE, _mkostemps_action, NULL, &fd) ? fd : -1);
+}
+
+int
+mkstempsat_np(int dfd, char *path, int slen)
+{
+       int fd;
+
+       return (find_temp_path(dfd, path, slen, TRUE, _mkostemps_action, NULL, &fd) ? fd : -1);
 }
 
 int
@@ -104,7 +124,7 @@ mkostemp(char *path, int oflags)
                errno = EINVAL;
                return -1;
        }
-       return (find_temp_path(path, 0, TRUE, _mkostemps_action, &oflags, &fd) ? fd : -1);
+       return (find_temp_path(AT_FDCWD, path, 0, TRUE, _mkostemps_action, &oflags, &fd) ? fd : -1);
 }
 
 int
@@ -112,20 +132,27 @@ mkstemp(char *path)
 {
        int fd;
 
-       return (find_temp_path(path, 0, TRUE, _mkostemps_action, NULL, &fd) ? fd : -1);
+       return (find_temp_path(AT_FDCWD, path, 0, TRUE, _mkostemps_action, NULL, &fd) ? fd : -1);
 }
 
 char *
 mkdtemp(char *path)
 {
-       return (find_temp_path(path, 0, TRUE, _mkdtemp_action, NULL, NULL) ?
+       return (find_temp_path(AT_FDCWD, path, 0, TRUE, _mkdtemp_action, NULL, NULL) ?
+                       path : (char *)NULL);
+}
+
+char *
+mkdtempat_np(int dfd, char *path)
+{
+       return (find_temp_path(dfd, path, 0, TRUE, _mkdtemp_action, NULL, NULL) ?
                        path : (char *)NULL);
 }
 
 char *
 _mktemp(char *path)
 {
-       return (find_temp_path(path, 0, FALSE, _mktemp_action, NULL, NULL) ?
+       return (find_temp_path(AT_FDCWD, path, 0, FALSE, _mktemp_action, NULL, NULL) ?
                        path : (char *)NULL);
 }
 
@@ -144,7 +171,7 @@ mkstemp_dprotected_np(char *path, int class, int dpflags)
        int fd;
        int ctx[2] = { class, dpflags };
 
-       return (find_temp_path(path, 0, TRUE, _mkstemp_dprotected_np_action, &ctx, &fd) ? fd : -1);
+       return (find_temp_path(AT_FDCWD, path, 0, TRUE, _mkstemp_dprotected_np_action, &ctx, &fd) ? fd : -1);
 }
 
 /* For every path matching a given template, invoke an action. Depending on
@@ -152,7 +179,7 @@ mkstemp_dprotected_np(char *path, int class, int dpflags)
  * Returns 1 if succeeds, 0 and sets errno if fails.
  */
 static int
-find_temp_path(char *path, int slen, bool stat_base_dir,
+find_temp_path(int dfd, char *path, int slen, bool stat_base_dir,
                find_temp_path_action_t action, void *action_ctx, void *action_result)
 {
        char *start, *trv, *suffp, *carryp;
@@ -198,7 +225,7 @@ find_temp_path(char *path, int slen, bool stat_base_dir,
                for (; trv > path; --trv) {
                        if (*trv == '/') {
                                *trv = '\0';
-                               rval = stat(path, &sbuf);
+                               rval = fstatat(dfd, path, &sbuf, 0);
                                *trv = '/';
                                if (rval != 0)
                                        return (0);
@@ -212,7 +239,7 @@ find_temp_path(char *path, int slen, bool stat_base_dir,
        }
 
        for (;;) {
-               switch (action(path, action_ctx, action_result)) {
+               switch (action(dfd, path, action_ctx, action_result)) {
                case FTPP_DONE:
                        return (1);
                case FTPP_ERROR:
@@ -252,10 +279,10 @@ find_temp_path(char *path, int slen, bool stat_base_dir,
 }
 
 static find_temp_path_progress_t
-_mkostemps_action(char *path, void *ctx, void *result)
+_mkostemps_action(int dfd, char *path, void *ctx, void *result)
 {
        int oflags = (ctx != NULL) ? *((int *) ctx) : 0;
-       int fd = _open(path, O_CREAT|O_EXCL|O_RDWR|oflags, 0600);
+       int fd = openat(dfd, path, O_CREAT|O_EXCL|O_RDWR|oflags, 0600);
        if (fd >= 0) {
                *((int *) result) = fd;
                return FTPP_DONE;
@@ -266,10 +293,10 @@ _mkostemps_action(char *path, void *ctx, void *result)
 }
 
 static find_temp_path_progress_t
-_mktemp_action(char *path, void *ctx __unused, void *result __unused)
+_mktemp_action(int dfd, char *path, void *ctx __unused, void *result __unused)
 {
        struct stat sbuf;
-       if (lstat(path, &sbuf)) {
+       if (fstatat(dfd, path, &sbuf, AT_SYMLINK_NOFOLLOW)) {
                // stat failed
                return (errno == ENOENT) ?
                                FTPP_DONE : // path is vacant, done
@@ -279,9 +306,9 @@ _mktemp_action(char *path, void *ctx __unused, void *result __unused)
 }
 
 static find_temp_path_progress_t
-_mkdtemp_action(char *path, void *ctx __unused, void *result __unused)
+_mkdtemp_action(int dfd, char *path, void *ctx __unused, void *result __unused)
 {
-       if (mkdir(path, 0700) == 0)
+       if (mkdirat(dfd, path, 0700) == 0)
                return FTPP_DONE;
        return (errno == EEXIST) ?
                        FTPP_TRY_NEXT :
@@ -289,8 +316,10 @@ _mkdtemp_action(char *path, void *ctx __unused, void *result __unused)
 }
 
 static find_temp_path_progress_t
-_mkstemp_dprotected_np_action(char *path, void *ctx, void *result)
+_mkstemp_dprotected_np_action(int dfd, char *path, void *ctx, void *result)
 {
+       assert(dfd == AT_FDCWD);
+
        int class = ((int *) ctx)[0];
        int dpflags = ((int *) ctx)[1];
        int fd = open_dprotected_np(path, O_CREAT|O_EXCL|O_RDWR, class, dpflags, 0600);
diff --git a/stdio/FreeBSD/open_memstream.3 b/stdio/FreeBSD/open_memstream.3
new file mode 100644 (file)
index 0000000..8e2c1e9
--- /dev/null
@@ -0,0 +1,155 @@
+.\" Copyright (c) 2013 Hudson River Trading LLC
+.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 1, 2015
+.Dt OPEN_MEMSTREAM 3
+.Os
+.Sh NAME
+.Nm open_memstream ,
+.Nm open_wmemstream
+.Nd dynamic memory buffer stream open functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft FILE *
+.Fn open_memstream "char **bufp" "size_t *sizep"
+.In wchar.h
+.Ft FILE *
+.Fn open_wmemstream "wchar_t **bufp" "size_t *sizep"
+.Sh DESCRIPTION
+The
+.Fn open_memstream
+and
+.Fn open_wmemstream
+functions create a write-only, seekable stream backed by a dynamically
+allocated memory buffer.
+The
+.Fn open_memstream
+function creates a byte-oriented stream,
+while the
+.Fn open_wmemstream
+function creates a wide-oriented stream.
+.Pp
+Each stream maintains a current position and size.
+Initially,
+the position and size are set to zero.
+Each write begins at the current position and advances it the number of
+successfully written bytes for
+.Fn open_memstream
+or wide characters for
+.Fn open_wmemstream .
+If a write moves the current position beyond the length of the buffer,
+the length of the buffer is extended and a null character is appended to the
+buffer.
+.Pp
+A stream's buffer always contains a null character at the end of the buffer
+that is not included in the current length.
+.Pp
+If a stream's current position is moved beyond the current length via a
+seek operation and a write is performed,
+the characters between the current length and the current position are filled
+with null characters before the write is performed.
+.Pp
+After a successful call to
+.Xr fclose 3
+or
+.Xr fflush 3 ,
+the pointer referenced by
+.Fa bufp
+will contain the start of the memory buffer and the variable referenced by
+.Fa sizep
+will contain the smaller of the current position and the current buffer length.
+.Pp
+After a successful call to
+.Xr fflush 3 ,
+the pointer referenced by
+.Fa bufp
+and the variable referenced by
+.Fa sizep
+are only valid until the next write operation or a call to
+.Xr fclose 3 .
+.Pp
+Once a stream is closed,
+the allocated buffer referenced by
+.Fa bufp
+should be released via a call to
+.Xr free 3
+when it is no longer needed.
+.Sh IMPLEMENTATION NOTES
+Internally all I/O streams are effectively byte-oriented,
+so using wide-oriented operations to write to a stream opened via
+.Fn open_wmemstream
+results in wide characters being expanded to a stream of multibyte characters
+in stdio's internal buffers.
+These multibyte characters are then converted back to wide characters when
+written into the stream.
+As a result,
+the wide-oriented streams maintain an internal multibyte character conversion
+state that is cleared on any seek opertion that changes the current position.
+This should have no effect as long as wide-oriented output operations are used
+on a wide-oriented stream.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn open_memstream
+and
+.Fn open_wmemstream
+return a
+.Tn FILE
+pointer.
+Otherwise,
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa bufp
+or
+.Fa sizep
+argument was
+.Dv NULL .
+.It Bq Er ENOMEM
+Memory for the stream or buffer could not be allocated.
+.El
+.Sh SEE ALSO
+.Xr fclose 3 ,
+.Xr fflush 3 ,
+.Xr fopen 3 ,
+.Xr free 3 ,
+.Xr fseek 3 ,
+.Xr stdio 3 ,
+.Xr sbuf 9
+.Sh STANDARDS
+The
+.Fn open_memstream
+and
+.Fn open_wmemstream
+functions conform to
+.St -p1003.1-2008 .
diff --git a/stdio/FreeBSD/open_memstream.c b/stdio/FreeBSD/open_memstream.c
new file mode 100644 (file)
index 0000000..a2d9bda
--- /dev/null
@@ -0,0 +1,210 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#ifdef DEBUG
+#include <stdint.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+/* XXX: There is no FPOS_MAX.  This assumes fpos_t is an off_t. */
+#define        FPOS_MAX        OFF_MAX
+
+struct memstream {
+       char **bufp;
+       size_t *sizep;
+       ssize_t len;
+       fpos_t offset;
+};
+
+static int
+memstream_grow(struct memstream *ms, fpos_t newoff)
+{
+       char *buf;
+       ssize_t newsize;
+
+       if (newoff < 0 || newoff >= SSIZE_MAX)
+               newsize = SSIZE_MAX - 1;
+       else
+               newsize = newoff;
+       if (newsize > ms->len) {
+               buf = realloc(*ms->bufp, newsize + 1);
+               if (buf != NULL) {
+#ifdef DEBUG
+                       fprintf(stderr, "MS: %p growing from %zd to %zd\n",
+                           ms, ms->len, newsize);
+#endif
+                       memset(buf + ms->len + 1, 0, newsize - ms->len);
+                       *ms->bufp = buf;
+                       ms->len = newsize;
+                       return (1);
+               }
+               return (0);
+       }
+       return (1);
+}
+
+static void
+memstream_update(struct memstream *ms)
+{
+
+       assert(ms->len >= 0 && ms->offset >= 0);
+       *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
+}
+
+static int
+memstream_write(void *cookie, const char *buf, int len)
+{
+       struct memstream *ms;
+       ssize_t tocopy;
+
+       ms = cookie;
+       if (!memstream_grow(ms, ms->offset + len))
+               return (-1);
+       tocopy = ms->len - ms->offset;
+       if (len < tocopy)
+               tocopy = len;
+       memcpy(*ms->bufp + ms->offset, buf, tocopy);
+       ms->offset += tocopy;
+       memstream_update(ms);
+#ifdef DEBUG
+       fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy);
+#endif
+       return (tocopy);
+}
+
+static fpos_t
+memstream_seek(void *cookie, fpos_t pos, int whence)
+{
+       struct memstream *ms;
+#ifdef DEBUG
+       fpos_t old;
+#endif
+
+       ms = cookie;
+#ifdef DEBUG
+       old = ms->offset;
+#endif
+       switch (whence) {
+       case SEEK_SET:
+               /* _fseeko() checks for negative offsets. */
+               assert(pos >= 0);
+               ms->offset = pos;
+               break;
+       case SEEK_CUR:
+               /* This is only called by _ftello(). */
+               assert(pos == 0);
+               break;
+       case SEEK_END:
+               if (pos < 0) {
+                       if (pos + ms->len < 0) {
+#ifdef DEBUG
+                               fprintf(stderr,
+                                   "MS: bad SEEK_END: pos %jd, len %zd\n",
+                                   (intmax_t)pos, ms->len);
+#endif
+                               errno = EINVAL;
+                               return (-1);
+                       }
+               } else {
+                       if (FPOS_MAX - ms->len < pos) {
+#ifdef DEBUG
+                               fprintf(stderr,
+                                   "MS: bad SEEK_END: pos %jd, len %zd\n",
+                                   (intmax_t)pos, ms->len);
+#endif
+                               errno = EOVERFLOW;
+                               return (-1);
+                       }
+               }
+               ms->offset = ms->len + pos;
+               break;
+       }
+       memstream_update(ms);
+#ifdef DEBUG
+       fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos,
+           whence, (intmax_t)old, (intmax_t)ms->offset);
+#endif
+       return (ms->offset);
+}
+
+static int
+memstream_close(void *cookie)
+{
+
+       free(cookie);
+       return (0);
+}
+
+FILE *
+open_memstream(char **bufp, size_t *sizep)
+{
+       struct memstream *ms;
+       int save_errno;
+       FILE *fp;
+
+       if (bufp == NULL || sizep == NULL) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       *bufp = calloc(1, 1);
+       if (*bufp == NULL)
+               return (NULL);
+       ms = malloc(sizeof(*ms));
+       if (ms == NULL) {
+               save_errno = errno;
+               free(*bufp);
+               *bufp = NULL;
+               errno = save_errno;
+               return (NULL);
+       }
+       ms->bufp = bufp;
+       ms->sizep = sizep;
+       ms->len = 0;
+       ms->offset = 0;
+       memstream_update(ms);
+       fp = funopen(ms, NULL, memstream_write, memstream_seek,
+           memstream_close);
+       if (fp == NULL) {
+               save_errno = errno;
+               free(ms);
+               free(*bufp);
+               *bufp = NULL;
+               errno = save_errno;
+               return (NULL);
+       }
+       fwide(fp, -1);
+       return (fp);
+}
diff --git a/stdio/FreeBSD/open_wmemstream.c b/stdio/FreeBSD/open_wmemstream.c
new file mode 100644 (file)
index 0000000..948a90b
--- /dev/null
@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#ifdef DEBUG
+#include <stdint.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <malloc_private.h>
+
+/* XXX: There is no FPOS_MAX.  This assumes fpos_t is an off_t. */
+#define        FPOS_MAX        OFF_MAX
+
+struct wmemstream {
+       wchar_t **bufp;
+       size_t *sizep;
+       ssize_t len;
+       fpos_t offset;
+       mbstate_t mbstate;
+};
+
+static int
+wmemstream_grow(struct wmemstream *ms, fpos_t newoff)
+{
+       wchar_t *buf;
+       ssize_t newsize;
+
+       if (newoff < 0 || newoff >= SSIZE_MAX / sizeof(wchar_t))
+               newsize = SSIZE_MAX / sizeof(wchar_t) - 1;
+       else
+               newsize = newoff;
+       if (newsize > ms->len) {
+               buf = reallocarray(*ms->bufp, newsize + 1, sizeof(wchar_t));
+               if (buf != NULL) {
+#ifdef DEBUG
+                       fprintf(stderr, "WMS: %p growing from %zd to %zd\n",
+                           ms, ms->len, newsize);
+#endif
+                       wmemset(buf + ms->len + 1, 0, newsize - ms->len);
+                       *ms->bufp = buf;
+                       ms->len = newsize;
+                       return (1);
+               }
+               return (0);
+       }
+       return (1);
+}
+
+static void
+wmemstream_update(struct wmemstream *ms)
+{
+
+       assert(ms->len >= 0 && ms->offset >= 0);
+       *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
+}
+
+/*
+ * Based on a starting multibyte state and an input buffer, determine
+ * how many wchar_t's would be output.  This doesn't use mbsnrtowcs()
+ * so that it can handle embedded null characters.
+ */
+static size_t
+wbuflen(const mbstate_t *state, const char *buf, int len)
+{
+       mbstate_t lenstate;
+       size_t charlen, count;
+
+       count = 0;
+       lenstate = *state;
+       while (len > 0) {
+               charlen = mbrlen(buf, len, &lenstate);
+               if (charlen == (size_t)-1)
+                       return (-1);
+               if (charlen == (size_t)-2)
+                       break;
+               if (charlen == 0)
+                       /* XXX: Not sure how else to handle this. */
+                       charlen = 1;
+               len -= charlen;
+               buf += charlen;
+               count++;
+       }
+       return (count);
+}
+
+static int
+wmemstream_write(void *cookie, const char *buf, int len)
+{
+       struct wmemstream *ms;
+       ssize_t consumed, wlen;
+       size_t charlen;
+
+       ms = cookie;
+       wlen = wbuflen(&ms->mbstate, buf, len);
+       if (wlen < 0) {
+               errno = EILSEQ;
+               return (-1);
+       }
+       if (!wmemstream_grow(ms, ms->offset + wlen))
+               return (-1);
+
+       /*
+        * This copies characters one at a time rather than using
+        * mbsnrtowcs() so it can properly handle embedded null
+        * characters.
+        */
+       consumed = 0;
+       while (len > 0 && ms->offset < ms->len) {
+               charlen = mbrtowc(*ms->bufp + ms->offset, buf, len,
+                   &ms->mbstate);
+               if (charlen == (size_t)-1) {
+                       if (consumed == 0) {
+                               errno = EILSEQ;
+                               return (-1);
+                       }
+                       /* Treat it as a successful short write. */
+                       break;
+               }
+               if (charlen == 0)
+                       /* XXX: Not sure how else to handle this. */
+                       charlen = 1;
+               if (charlen == (size_t)-2) {
+                       consumed += len;
+                       len = 0;
+               } else {
+                       consumed += charlen;
+                       buf += charlen;
+                       len -= charlen;
+                       ms->offset++;
+               }
+       }
+       wmemstream_update(ms);
+#ifdef DEBUG
+       fprintf(stderr, "WMS: write(%p, %d) = %zd\n", ms, len, consumed);
+#endif
+       return (consumed);
+}
+
+static fpos_t
+wmemstream_seek(void *cookie, fpos_t pos, int whence)
+{
+       struct wmemstream *ms;
+       fpos_t old;
+
+       ms = cookie;
+       old = ms->offset;
+       switch (whence) {
+       case SEEK_SET:
+               /* _fseeko() checks for negative offsets. */
+               assert(pos >= 0);
+               ms->offset = pos;
+               break;
+       case SEEK_CUR:
+               /* This is only called by _ftello(). */
+               assert(pos == 0);
+               break;
+       case SEEK_END:
+               if (pos < 0) {
+                       if (pos + ms->len < 0) {
+#ifdef DEBUG
+                               fprintf(stderr,
+                                   "WMS: bad SEEK_END: pos %jd, len %zd\n",
+                                   (intmax_t)pos, ms->len);
+#endif
+                               errno = EINVAL;
+                               return (-1);
+                       }
+               } else {
+                       if (FPOS_MAX - ms->len < pos) {
+#ifdef DEBUG
+                               fprintf(stderr,
+                                   "WMS: bad SEEK_END: pos %jd, len %zd\n",
+                                   (intmax_t)pos, ms->len);
+#endif
+                               errno = EOVERFLOW;
+                               return (-1);
+                       }
+               }
+               ms->offset = ms->len + pos;
+               break;
+       }
+       /* Reset the multibyte state if a seek changes the position. */
+       if (ms->offset != old)
+               memset(&ms->mbstate, 0, sizeof(ms->mbstate));
+       wmemstream_update(ms);
+#ifdef DEBUG
+       fprintf(stderr, "WMS: seek(%p, %jd, %d) %jd -> %jd\n", ms,
+           (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset);
+#endif
+       return (ms->offset);
+}
+
+static int
+wmemstream_close(void *cookie)
+{
+
+       free(cookie);
+       return (0);
+}
+
+FILE *
+open_wmemstream(wchar_t **bufp, size_t *sizep)
+{
+       struct wmemstream *ms;
+       int save_errno;
+       FILE *fp;
+
+       if (bufp == NULL || sizep == NULL) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       *bufp = calloc(1, sizeof(wchar_t));
+       if (*bufp == NULL)
+               return (NULL);
+       ms = malloc(sizeof(*ms));
+       if (ms == NULL) {
+               save_errno = errno;
+               free(*bufp);
+               *bufp = NULL;
+               errno = save_errno;
+               return (NULL);
+       }
+       ms->bufp = bufp;
+       ms->sizep = sizep;
+       ms->len = 0;
+       ms->offset = 0;
+       memset(&ms->mbstate, 0, sizeof(mbstate_t));
+       wmemstream_update(ms);
+       fp = funopen(ms, NULL, wmemstream_write, wmemstream_seek,
+           wmemstream_close);
+       if (fp == NULL) {
+               save_errno = errno;
+               free(ms);
+               free(*bufp);
+               *bufp = NULL;
+               errno = save_errno;
+               return (NULL);
+       }
+       fwide(fp, 1);
+       return (fp);
+}
index 850fa989ef576f90999ad7cd361ac52bdc86e3c0..380ffeb7a3432d083fa3cee70a84b1f651fd6b99 100644 (file)
@@ -692,6 +692,11 @@ integer indicated by the
 .Vt "int *"
 (or variant) pointer argument.
 No argument is converted.
+The
+.Fa format
+argument must be in write-protected memory if this specifier is used; see
+.Sx SECURITY CONSIDERATIONS
+below.
 .It Cm %
 A
 .Ql %
@@ -931,6 +936,21 @@ This holds true even if the string was built using a function like
 as the resulting string may still contain user-supplied conversion specifiers
 for later interpolation by
 .Fn printf .
+For this reason, a
+.Fa format
+argument containing
+.Cm %n
+is assumed to be untrustworthy if located in writable memory (i.e. memory with
+protection PROT_WRITE; see
+.Xr mprotect 2 )
+and any attempt to use such an argument is fatal.
+Practically, this means that
+.Cm %n
+is permitted in literal
+.Fa format
+strings but disallowed in
+.Fa format
+strings located in normal stack- or heap-allocated memory.
 .Pp
 Always use the proper secure idiom:
 .Pp
index 701e2ab9934963351c898254aaae52efe112127b..2e707ef2417134c0a51b9d902cf058dfb120c8e6 100644 (file)
@@ -64,6 +64,10 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das
 #include <stdarg.h>
 #include "un-namespace.h"
 
+#include <os/assumes.h>
+#include <mach-o/dyld_priv.h>
+#include <mach/vm_region.h>
+
 #include "libc_private.h"
 #include "local.h"
 #include "fvwrite.h"
@@ -308,6 +312,26 @@ vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
 #error "BUF must be large enough to format a uintmax_t"
 #endif
 
+__private_extern__ bool
+__printf_is_memory_read_only(void *addr, size_t __unused size)
+{
+       vm_address_t address = addr;
+       vm_size_t vmsize = 0;
+       vm_region_basic_info_data_64_t info;
+       mach_msg_type_number_t info_cnt = VM_REGION_BASIC_INFO_COUNT_64;
+       memory_object_name_t object = MACH_PORT_NULL;
+       kern_return_t kr = KERN_SUCCESS;
+
+       kr = vm_region_64(mach_task_self(),
+                       &address,
+                       &vmsize,
+                       VM_REGION_BASIC_INFO_64,
+                       (vm_region_info_t) &info,
+                       &info_cnt,
+                       &object);
+       return (kr == KERN_SUCCESS) && !(info.protection & VM_PROT_WRITE);
+}
+
 /*
  * Non-MT-safe version
  */
@@ -316,15 +340,19 @@ __vfprintf(FILE *fp, locale_t loc, const char *fmt0, va_list ap)
 {
        char *fmt;              /* format string */
        int ch;                 /* character from fmt */
-       int n, n2;              /* handy integer (short term usage) */
+       ssize_t n, n2;          /* handy integer (short term usage) */
        char *cp;               /* handy char pointer (short term usage) */
        int flags;              /* flags as above */
-       int ret;                /* return value accumulator */
-       int width;              /* width from format (%8d), or 0 */
-       int prec;               /* precision from format; <0 for N/A */
+       ssize_t ret;            /* return value accumulator */
+       ssize_t width;          /* width from format (%8d), or 0 */
+       ssize_t prec;           /* precision from format; <0 for N/A */
        char sign;              /* sign prefix (' ', '+', '-', or \0) */
        struct grouping_state gs; /* thousands' grouping info */
 
+#ifndef ALLOW_DYNAMIC_PERCENT_N
+       bool static_format_checked = false;
+#endif // ALLOW_DYNAMIC_PERCENT_N
+
 #ifndef NO_FLOATING_POINT
        /*
         * We can decompose the printed representation of floating
@@ -364,9 +392,9 @@ __vfprintf(FILE *fp, locale_t loc, const char *fmt0, va_list ap)
        uintmax_t ujval;        /* %j, %ll, %q, %t, %z integers */
        int base;               /* base for [diouxX] conversion */
        int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
-       int realsz;             /* field size expanded by dprec, sign, etc */
-       int size;               /* size of converted field or string */
-       int prsize;             /* max size of printed field */
+       ssize_t realsz;         /* field size expanded by dprec, sign, etc */
+       ssize_t size;           /* size of converted field or string */
+       ssize_t prsize;             /* max size of printed field */
        const char *xdigs;      /* digits for %[xX] conversion */
        struct io_state io;     /* I/O buffering state */
        char buf[BUF];          /* buffer with space for digits of uintmax_t */
@@ -492,8 +520,9 @@ __vfprintf(FILE *fp, locale_t loc, const char *fmt0, va_list ap)
                for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
                        /* void */;
                if ((n = fmt - cp) != 0) {
-                       if ((unsigned)ret + n > INT_MAX) {
+                       if (ret + n >= INT_MAX) {
                                ret = EOF;
+                               errno = EOVERFLOW;
                                goto error;
                        }
                        PRINT(cp, n);
@@ -833,7 +862,17 @@ fp_common:
                        void *ptr = GETARG(void *);
                        if (ptr == NULL)
                                continue;
-                       else if (flags & LLONGINT)
+
+#ifndef ALLOW_DYNAMIC_PERCENT_N
+                       if (!static_format_checked) {
+                               static_format_checked = __printf_is_memory_read_only((void*)fmt0, strlen(fmt0));
+                       }
+                       if (!static_format_checked) {
+                               os_crash("%n used in a non-immutable format string");
+                       }
+#endif // ALLOW_DYNAMIC_PERCENT_N
+
+                       if (flags & LLONGINT)
                                *(long long *)ptr = ret;
                        else if (flags & SIZET)
                                *(ssize_t *)ptr = (ssize_t)ret;
@@ -904,7 +943,15 @@ fp_common:
                                }
                        } else if ((cp = GETARG(char *)) == NULL)
                                cp = "(null)";
-                       size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
+                       {
+                               size_t cp_len = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
+                               if (cp_len < INT_MAX) {
+                                       size = cp_len;
+                               } else {
+                                       ret = EOF;
+                                       goto error;
+                               }
+                       }
                        sign = '\0';
                        break;
                case 'U':
@@ -976,7 +1023,7 @@ number:                    if ((dprec = prec) >= 0)
                        }
                        size = buf + BUF - cp;
                        if (size > BUF) /* should never happen */
-                               LIBC_ABORT("size (%d) > BUF (%d)", size, BUF);
+                               LIBC_ABORT("size (%zd) > BUF (%d)", size, BUF);
                        if ((flags & GROUPING) && size != 0)
                                size += grouping_init(&gs, size, loc);
                        break;
@@ -1301,8 +1348,9 @@ number:                   if ((dprec = prec) >= 0)
                        realsz += 2;
 
                prsize = width > realsz ? width : realsz;
-               if ((unsigned)ret + prsize > INT_MAX) {
+               if (ret + prsize >= INT_MAX) {
                        ret = EOF;
+                       errno = EOVERFLOW;
                        goto error;
                }
 
@@ -1395,7 +1443,7 @@ error:
                ret = EOF;
        if ((argtable != NULL) && (argtable != statargtable))
                free (argtable);
-       return (ret);
+       return (ret < 0 || ret >= INT_MAX) ? -1 : (int)ret;
        /* NOTREACHED */
 }
 
index f623fff3e4e7dcda7fb15685173fe8d3e2041ce6..176a11ca7294b8c0402abe0f85cf46a26d5b3bd3 100644 (file)
@@ -64,6 +64,9 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.42 2009/11/25 04:27:55 wo
 #include <errno.h>
 #include "un-namespace.h"
 
+#include <os/assumes.h>
+#include <mach-o/dyld_priv.h>
+
 #include "libc_private.h"
 #include "local.h"
 #include "fvwrite.h"
@@ -373,6 +376,9 @@ vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
        return vfwprintf_l(fp, __current_locale(), fmt0, ap);
 }
 
+// Defined in vfprintf.c
+bool __printf_is_memory_read_only(void *addr, size_t size);
+
 /*
  * The size of the buffer we use as scratch space for integer
  * conversions, among other things.  We need enough space to
@@ -392,14 +398,15 @@ __vfwprintf(FILE *fp, locale_t loc, const wchar_t *fmt0, va_list ap)
 {
        wchar_t *fmt;           /* format string */
        wchar_t ch;             /* character from fmt */
-       int n, n2;              /* handy integer (short term usage) */
+       ssize_t n, n2;          /* handy integer (short term usage) */
        wchar_t *cp;            /* handy char pointer (short term usage) */
        int flags;              /* flags as above */
-       int ret;                /* return value accumulator */
-       int width;              /* width from format (%8d), or 0 */
-       int prec;               /* precision from format; <0 for N/A */
+       ssize_t ret;            /* return value accumulator */
+       ssize_t width;          /* width from format (%8d), or 0 */
+       ssize_t prec;           /* precision from format; <0 for N/A */
        wchar_t sign;           /* sign prefix (' ', '+', '-', or \0) */
        struct grouping_state gs; /* thousands' grouping info */
+
 #ifndef NO_FLOATING_POINT
        /*
         * We can decompose the printed representation of floating
@@ -438,9 +445,9 @@ __vfwprintf(FILE *fp, locale_t loc, const wchar_t *fmt0, va_list ap)
        uintmax_t ujval;        /* %j, %ll, %q, %t, %z integers */
        int base;               /* base for [diouxX] conversion */
        int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
-       int realsz;             /* field size expanded by dprec, sign, etc */
-       int size;               /* size of converted field or string */
-       int prsize;             /* max size of printed field */
+       ssize_t realsz;         /* field size expanded by dprec, sign, etc */
+       ssize_t size;           /* size of converted field or string */
+       ssize_t prsize;             /* max size of printed field */
        const char *xdigs;      /* digits for [xX] conversion */
        struct io_state io;     /* I/O buffering state */
        wchar_t buf[BUF];       /* buffer with space for digits of uintmax_t */
@@ -561,8 +568,9 @@ __vfwprintf(FILE *fp, locale_t loc, const wchar_t *fmt0, va_list ap)
                for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
                        /* void */;
                if ((n = fmt - cp) != 0) {
-                       if ((unsigned)ret + n > INT_MAX) {
+                       if (ret + n > INT_MAX) {
                                ret = EOF;
+                               errno = EOVERFLOW;
                                goto error;
                        }
                        PRINT(cp, n);
@@ -893,7 +901,8 @@ fp_common:
                        void *ptr = GETARG(void *);
                        if (ptr == NULL)
                                continue;
-                       else if (flags & LLONGINT)
+
+                       if (flags & LLONGINT)
                                *(long long *)ptr = ret;
                        else if (flags & SIZET)
                                *(ssize_t *)ptr = (ssize_t)ret;
@@ -970,6 +979,11 @@ fp_common:
                        size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp);
 #else
                        size = wcslen(cp);
+                       if (size >= INT_MAX) {
+                               ret = EOF;
+                               errno = EOVERFLOW;
+                               goto error;
+                       }
                        if(prec >= 0 && prec < size)
                                size = prec;
 #endif
@@ -1044,7 +1058,7 @@ number:                   if ((dprec = prec) >= 0)
                        }
                        size = buf + BUF - cp;
                        if (size > BUF) /* should never happen */
-                               LIBC_ABORT("size (%d) > BUF (%d)", size, BUF);
+                               LIBC_ABORT("size (%zd) > BUF (%d)", size, BUF);
                        if ((flags & GROUPING) && size != 0)
                                size += grouping_init(&gs, size, loc);
                        break;
@@ -1367,8 +1381,9 @@ number:                   if ((dprec = prec) >= 0)
                        realsz += 2;
 
                prsize = width > realsz ? width : realsz;
-               if ((unsigned)ret + prsize > INT_MAX) {
+               if (ret + prsize > INT_MAX) {
                        ret = EOF;
+                       errno = EOVERFLOW;
                        goto error;
                }
 
@@ -1458,6 +1473,6 @@ error:
                ret = EOF;
        if ((argtable != NULL) && (argtable != statargtable))
                free (argtable);
-       return (ret);
+       return (ret < 0 || ret >= INT_MAX) ? -1 : (int)ret;
        /* NOTREACHED */
 }
index 4227e74d93b93f04308858354d386605e9454249..9129639a585bda7a968fe4f748c01d3979b2f409 100644 (file)
@@ -79,7 +79,7 @@ vswprintf_l(wchar_t * __restrict s, size_t n, locale_t loc,
                return (-1);
        }
        *f._p = '\0';
-       mbp = f._bf._base;
+       mbp = (char*)f._bf._base;
        /*
         * XXX Undo the conversion from wide characters to multibyte that
         * fputwc() did in __vfwprintf().
index 9f4c60e621a733b27469fb24dbeb29720a8f7d7d..217956e3ab1bb3c0c98c329a84d646f10f5b1669 100644 (file)
@@ -36,6 +36,7 @@
 #include <namespace.h>
 #include "xlocale_private.h"
 #include <stdio.h>
+#include <string.h>
 #include <wchar.h>
 #include <assert.h>
 #include <locale.h>
index fb644511d0ec54192da7929405d85cd76b981d04..ce33d2ac8bb2f9bca180477df5241f6403fd0ea8 100644 (file)
@@ -269,8 +269,8 @@ __printf_render_int(struct __printf_io *io, const struct printf_info *pi, const
        const union arg *argp;
        char buf[BUF];
        char *p, *pe;
-       char ns, l;
-       int rdx, sign, zext, ngrp;
+       char ns;
+       int rdx, sign, zext, ngrp, l;
        const char *nalt, *digit;
        const char *thousands_sep;      /* locale specific thousands separator */
        int thousands_sep_len;          /* locale specific thousands separator length */
index b3d978ba97bcf44dade06274faff283fbb90ffd2..9d60aa81fe5b79b260e4af2da11f1e20536621b8 100644 (file)
@@ -13,7 +13,7 @@
 .\" 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.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. 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.
 .\"
@@ -30,9 +30,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)atexit.3   8.1 (Berkeley) 6/4/93
-.\" $FreeBSD: src/lib/libc/stdlib/atexit.3,v 1.11 2007/01/09 00:28:09 imp Exp $
+.\" $FreeBSD$
 .\"
-.Dd May 20, 2008
+.Dd September 6, 2002
 .Dt ATEXIT 3
 .Os
 .Sh NAME
 .Sh SYNOPSIS
 .In stdlib.h
 .Ft int
-.Fn atexit "void (*func)(void)"
+.Fn atexit "void (*function)(void)"
 #ifdef UNIFDEF_BLOCKS
 .Ft int
-.Fn atexit_b "void (^block)(void)"
+.Fn atexit_b "void (^function)(void)"
 #endif
 .Sh DESCRIPTION
 The
 .Fn atexit
 function
-registers the function
-.Fa func
+registers the given
+.Fa function
 to be called at program exit, whether via
 .Xr exit 3
 or via return from the program's
 .Fn main .
 Functions so registered are called in reverse order;
 no arguments are passed.
+.Pp
+If the provided
+.Fa function
+is located in a library that has been dynamically loaded (e.g. by
+.Fn dlopen ) Ns ,
+it will be called when the library is unloaded (due to a call
+to
+.Fn dlclose )
+or at program exit.
 #ifdef UNIFDEF_BLOCKS
 .Pp
 The
@@ -77,18 +86,18 @@ block might go out of scope when the subroutine returns.
 .Ed
 #endif
 .Pp
-These callbacks must not call
+These functions must not call
 .Fn exit ;
 if it should be necessary to terminate the process while in such a
 function, the
 .Xr _exit 2
 function should be used.
-(Alternatively, the callbacks may cause abnormal
+(Alternatively, the function may cause abnormal
 process termination, for example by calling
 .Xr abort 3 . )
 .Pp
-At least 32 callbacks can always be registered;
-more are allowed as long as sufficient memory can be allocated.
+At least 32 functions can always be registered,
+and more are allowed as long as sufficient memory can be allocated.
 .\" XXX {ATEXIT_MAX} is not implemented yet
 .Sh RETURN VALUES
 #ifdef UNIFDEF_BLOCKS
index e61834e1e368600da72dcf017632591fd29ab60e..ba66bc6644ff357674b69163510e8ec001a4c9e8 100644 (file)
@@ -55,3 +55,11 @@ extern void _tlv_exit();
 void
 exit(int status)
 {
+#if !TARGET_IPHONE_SIMULATOR && (__i386__ || __x86_64__)
+       _tlv_exit(); // C++11 requires thread_local objects to be destroyed before global objects
+#endif
+       __cxa_finalize(NULL);
+       if (__cleanup)
+               (*__cleanup)();
+       __exit(status);
+}
index bde7421158357a1012895caa2aff28dcfe2054ca..c012578ad46397d6fc448f3e67ca030638cde988 100644 (file)
@@ -83,21 +83,13 @@ static os_unfair_lock __environ_lock_obj = OS_UNFAIR_LOCK_INIT;
 __private_extern__ void
 __environ_lock(void)
 {
-#if TARGET_OS_IOS && !TARGET_OS_SIMULATOR
-       os_unfair_lock_lock_with_options_4Libc(
+       os_unfair_lock_lock_with_options(
                        &__environ_lock_obj, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);
-#else // TARGET_OS_IOS && !TARGET_OS_SIMULATOR
-       os_unfair_lock_lock(&__environ_lock_obj);
-#endif // TARGET_OS_IOS && !TARGET_OS_SIMULATOR
 }
 __private_extern__ void
 __environ_unlock(void)
 {
-#if TARGET_OS_IOS && !TARGET_OS_SIMULATOR
-       os_unfair_lock_unlock_4Libc(&__environ_lock_obj);
-#else // TARGET_OS_IOS && !TARGET_OS_SIMULATOR
        os_unfair_lock_unlock(&__environ_lock_obj);
-#endif // TARGET_OS_IOS && !TARGET_OS_SIMULATOR
 }
 __private_extern__ void
 __environ_lock_fork_child(void)
index cb6f707aa4cea70963e60edc0b7a4dadf1090757..e9251ab945e16bea668babe5d6821f04db9ac8e2 100644 (file)
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das E
 #include <libkern/OSAtomic.h>
 #include <sys/mman.h>
 #include <errno.h>
+#include <os/lock.h>
 #define __APPLE_API_PRIVATE
 #include <machine/cpu_capabilities.h>
 
@@ -95,7 +96,7 @@ struct shared {
     size_t turnoff;
     dispatch_queue_t queue;
     dispatch_group_t group;
-    OSSpinLock sharedlock;
+    os_unfair_lock sharedlock;
 };
 
 static union args *
@@ -103,7 +104,7 @@ getargs(struct shared *shared)
 {
     union args *args;
 
-    OSSpinLockLock(&shared->sharedlock);
+    os_unfair_lock_lock(&shared->sharedlock);
     if(!shared->freelist) {
        struct page *page;
        union args *prev;
@@ -121,17 +122,17 @@ getargs(struct shared *shared)
     }
     args = shared->freelist;
     shared->freelist = args->next;
-    OSSpinLockUnlock(&shared->sharedlock);
+    os_unfair_lock_unlock(&shared->sharedlock);
     return args;
 }
 
 static void
 returnargs(struct shared *shared, union args *args)
 {
-    OSSpinLockLock(&shared->sharedlock);
+    os_unfair_lock_lock(&shared->sharedlock);
     args->next = shared->freelist;
     shared->freelist = args;
-    OSSpinLockUnlock(&shared->sharedlock);
+    os_unfair_lock_unlock(&shared->sharedlock);
 }
 
 /*
@@ -374,7 +375,7 @@ psort(void *a, size_t n, size_t es, cmp_t *cmp)
                union args *args;
 
                bzero(&shared, sizeof(shared));
-               shared.sharedlock = OS_SPINLOCK_INIT;
+               shared.sharedlock = OS_UNFAIR_LOCK_INIT;
                if ((args = getargs(&shared)) != NULL) {
                        struct page *p, *pp;
 #ifdef I_AM_PSORT_R
index cb6f707aa4cea70963e60edc0b7a4dadf1090757..e9251ab945e16bea668babe5d6821f04db9ac8e2 100644 (file)
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das E
 #include <libkern/OSAtomic.h>
 #include <sys/mman.h>
 #include <errno.h>
+#include <os/lock.h>
 #define __APPLE_API_PRIVATE
 #include <machine/cpu_capabilities.h>
 
@@ -95,7 +96,7 @@ struct shared {
     size_t turnoff;
     dispatch_queue_t queue;
     dispatch_group_t group;
-    OSSpinLock sharedlock;
+    os_unfair_lock sharedlock;
 };
 
 static union args *
@@ -103,7 +104,7 @@ getargs(struct shared *shared)
 {
     union args *args;
 
-    OSSpinLockLock(&shared->sharedlock);
+    os_unfair_lock_lock(&shared->sharedlock);
     if(!shared->freelist) {
        struct page *page;
        union args *prev;
@@ -121,17 +122,17 @@ getargs(struct shared *shared)
     }
     args = shared->freelist;
     shared->freelist = args->next;
-    OSSpinLockUnlock(&shared->sharedlock);
+    os_unfair_lock_unlock(&shared->sharedlock);
     return args;
 }
 
 static void
 returnargs(struct shared *shared, union args *args)
 {
-    OSSpinLockLock(&shared->sharedlock);
+    os_unfair_lock_lock(&shared->sharedlock);
     args->next = shared->freelist;
     shared->freelist = args;
-    OSSpinLockUnlock(&shared->sharedlock);
+    os_unfair_lock_unlock(&shared->sharedlock);
 }
 
 /*
@@ -374,7 +375,7 @@ psort(void *a, size_t n, size_t es, cmp_t *cmp)
                union args *args;
 
                bzero(&shared, sizeof(shared));
-               shared.sharedlock = OS_SPINLOCK_INIT;
+               shared.sharedlock = OS_UNFAIR_LOCK_INIT;
                if ((args = getargs(&shared)) != NULL) {
                        struct page *p, *pp;
 #ifdef I_AM_PSORT_R
index cb6f707aa4cea70963e60edc0b7a4dadf1090757..e9251ab945e16bea668babe5d6821f04db9ac8e2 100644 (file)
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das E
 #include <libkern/OSAtomic.h>
 #include <sys/mman.h>
 #include <errno.h>
+#include <os/lock.h>
 #define __APPLE_API_PRIVATE
 #include <machine/cpu_capabilities.h>
 
@@ -95,7 +96,7 @@ struct shared {
     size_t turnoff;
     dispatch_queue_t queue;
     dispatch_group_t group;
-    OSSpinLock sharedlock;
+    os_unfair_lock sharedlock;
 };
 
 static union args *
@@ -103,7 +104,7 @@ getargs(struct shared *shared)
 {
     union args *args;
 
-    OSSpinLockLock(&shared->sharedlock);
+    os_unfair_lock_lock(&shared->sharedlock);
     if(!shared->freelist) {
        struct page *page;
        union args *prev;
@@ -121,17 +122,17 @@ getargs(struct shared *shared)
     }
     args = shared->freelist;
     shared->freelist = args->next;
-    OSSpinLockUnlock(&shared->sharedlock);
+    os_unfair_lock_unlock(&shared->sharedlock);
     return args;
 }
 
 static void
 returnargs(struct shared *shared, union args *args)
 {
-    OSSpinLockLock(&shared->sharedlock);
+    os_unfair_lock_lock(&shared->sharedlock);
     args->next = shared->freelist;
     shared->freelist = args;
-    OSSpinLockUnlock(&shared->sharedlock);
+    os_unfair_lock_unlock(&shared->sharedlock);
 }
 
 /*
@@ -374,7 +375,7 @@ psort(void *a, size_t n, size_t es, cmp_t *cmp)
                union args *args;
 
                bzero(&shared, sizeof(shared));
-               shared.sharedlock = OS_SPINLOCK_INIT;
+               shared.sharedlock = OS_UNFAIR_LOCK_INIT;
                if ((args = getargs(&shared)) != NULL) {
                        struct page *p, *pp;
 #ifdef I_AM_PSORT_R
index 1d0e3c54f46e2a4a8a40b780f2537c00389810ed..b1c5257721b4f88127adf1fc3c2bbba7aadde602 100644 (file)
@@ -10,7 +10,7 @@
  * 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.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. 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.
  *
@@ -31,8 +31,9 @@
 static char sccsid[] = "@(#)qsort.c    8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das Exp $");
+__FBSDID("$FreeBSD$");
 
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -41,52 +42,54 @@ typedef int          cmp_t(void *, const void *, const void *);
 #else
 typedef int             cmp_t(const void *, const void *);
 #endif
-#ifdef I_AM_QSORT_B
-static inline char     *med3(char *, char *, char *, cmp_t ^, void *) __attribute__((always_inline));
-#else
-static inline char     *med3(char *, char *, char *, cmp_t *, void *) __attribute__((always_inline));
-#endif
-static inline void      swapfunc(char *, char *, int, int) __attribute__((always_inline));
+static inline char     *med3(char *, char *, char *, cmp_t *, void *);
+static inline void      swapfunc(char *, char *, size_t, int, int);
 
-#define min(a, b)      (a) < (b) ? a : b
+#define        MIN(a, b)       ((a) < (b) ? a : b)
 
 /*
  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
  */
-#define swapcode(TYPE, parmi, parmj, n) {              \
-       long i = (n) / sizeof (TYPE);                   \
-       TYPE *pi = (TYPE *) (parmi);            \
-       TYPE *pj = (TYPE *) (parmj);            \
+#define        swapcode(TYPE, parmi, parmj, n) {               \
+       size_t i = (n) / sizeof (TYPE);                 \
+       TYPE *pi = (TYPE *) (parmi);            \
+       TYPE *pj = (TYPE *) (parmj);            \
        do {                                            \
                TYPE    t = *pi;                \
                *pi++ = *pj;                            \
                *pj++ = t;                              \
-        } while (--i > 0);                             \
+       } while (--i > 0);                              \
 }
 
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
-       es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+#define        SWAPINIT(TYPE, a, es) swaptype_ ## TYPE =       \
+       ((char *)a - (char *)0) % sizeof(TYPE) ||       \
+       es % sizeof(TYPE) ? 2 : es == sizeof(TYPE) ? 0 : 1;
 
 static inline void
-swapfunc(a, b, n, swaptype)
-       char *a, *b;
-       int n, swaptype;
+swapfunc(char *a, char *b, size_t n, int swaptype_long, int swaptype_int)
 {
-       if(swaptype <= 1)
+       if (swaptype_long <= 1)
                swapcode(long, a, b, n)
+       else if (swaptype_int <= 1)
+               swapcode(int, a, b, n)
        else
                swapcode(char, a, b, n)
 }
 
-#define swap(a, b)                                     \
-       if (swaptype == 0) {                            \
+#define        swap(a, b)                                      \
+       if (swaptype_long == 0) {                       \
                long t = *(long *)(a);                  \
                *(long *)(a) = *(long *)(b);            \
                *(long *)(b) = t;                       \
+       } else if (swaptype_int == 0) {                 \
+               int t = *(int *)(a);                    \
+               *(int *)(a) = *(int *)(b);              \
+               *(int *)(b) = t;                        \
        } else                                          \
-               swapfunc(a, b, es, swaptype)
+               swapfunc(a, b, es, swaptype_long, swaptype_int)
 
-#define vecswap(a, b, n)       if ((n) > 0) swapfunc(a, b, n, swaptype)
+#define        vecswap(a, b, n)                                \
+       if ((n) > 0) swapfunc(a, b, n, swaptype_long, swaptype_int)
 
 #ifdef I_AM_QSORT_R
 #define        CMP(t, x, y) (cmp((t), (x), (y)))
@@ -94,14 +97,11 @@ swapfunc(a, b, n, swaptype)
 #define        CMP(t, x, y) (cmp((x), (y)))
 #endif
 
+/*
+ * Find the median of 3 elements
+ */
 static inline char *
-med3(char *a, char *b, char *c,
-#ifdef I_AM_QSORT_B
-cmp_t ^cmp,
-#else
-cmp_t *cmp,
-#endif
-void *thunk
+med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
 #ifndef I_AM_QSORT_R
 __unused
 #endif
@@ -109,7 +109,7 @@ __unused
 {
        return CMP(thunk, a, b) < 0 ?
               (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
-              :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
+             :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
 }
 
 #ifdef __LP64__
@@ -122,63 +122,97 @@ __unused
 int __heapsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *));
 #endif
 
-static void
-_qsort(void *a, size_t n, size_t es,
+/*
+ * Simple insertion sort routine.
+ */
+static bool
+_isort(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp, int swap_limit, int swaptype_long, int swaptype_int)
+{
+       int swap_cnt = 0;
+       for (char *pm = (char *)a + es; pm < (char *)a + n * es; pm += es) {
+               for (char *pl = pm; pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+                               pl -= es) {
+                       swap(pl, pl - es);
+                       if (swap_limit && ++swap_cnt > swap_limit) return false;
+               }
+       }
+       return true;
+}
+
 #ifdef I_AM_QSORT_R
-void *thunk,
-#else
-#define thunk  NULL
-#endif
-#ifdef I_AM_QSORT_B
-cmp_t ^cmp,
+static void
+_qsort(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp, int depth_limit)
 #else
-cmp_t *cmp,
+#define        thunk NULL
+static void
+_qsort(void *a, size_t n, size_t es, cmp_t *cmp, int depth_limit)
 #endif
-int depth_limit)
 {
        char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
-       size_t d, r;
+       size_t d1, d2;
        int cmp_result;
-       int swaptype, swap_cnt;
+       int swaptype_long, swaptype_int, swap_cnt;
 
 loop:
+       SWAPINIT(long, a, es);
+       SWAPINIT(int, a, es);
+       swap_cnt = 0;
+
        if (depth_limit-- <= 0) {
-#ifdef I_AM_QSORT_B
-               heapsort_b(a, n, es, cmp);
-#elif defined(I_AM_QSORT_R)
+               /*
+                * We've hit our recursion limit, switch to heapsort
+                */
+#ifdef I_AM_QSORT_R
                __heapsort_r(a, n, es, thunk, cmp);
 #else
                heapsort(a, n, es, cmp);
 #endif
                return;
        }
-       SWAPINIT(a, es);
-       swap_cnt = 0;
-       if (n < 7) {
-               for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
-                       for (pl = pm; 
-                            pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
-                            pl -= es)
-                               swap(pl, pl - es);
+
+       if (n <= 7) {
+               /*
+                * For sufficiently small inputs, we'll just insertion sort.
+                *
+                * Pass 0 as swap limit, since this must complete.
+                */
+               _isort(a, n, es, thunk, cmp, 0, swaptype_long, swaptype_int);
                return;
        }
+
+       /*
+        * Compute the pseudomedian.  Small arrays use 3 samples, large ones use 9.
+        */
+       pl = a;
        pm = (char *)a + (n / 2) * es;
-       if (n > 7) {
-               pl = a;
-               pn = (char *)a + (n - 1) * es;
-               if (n > 40) {
-                       d = (n / 8) * es;
-                       pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
-                       pm = med3(pm - d, pm, pm + d, cmp, thunk);
-                       pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
-               }
-               pm = med3(pl, pm, pn, cmp, thunk);
+       pn = (char *)a + (n - 1) * es;
+       if (n > 40) {
+               size_t d = (n / 8) * es;
+
+               pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
+               pm = med3(pm - d, pm, pm + d, cmp, thunk);
+               pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
        }
+       pm = med3(pl, pm, pn, cmp, thunk);
+
+       /*
+        * Pull the median to the front, starting us with:
+        *
+        * +-+-------------+
+        * |=|      ?      |
+        * +-+-------------+
+        * a pa,pb         pc,pd
+        */
        swap(a, pm);
        pa = pb = (char *)a + es;
-
        pc = pd = (char *)a + (n - 1) * es;
+
        for (;;) {
+               /*
+                * - Move b forward while it's less than the median
+                * - Move c backwards while it's greater than the median
+                * - When equal to the median, swap to the outside
+                */
                while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
                        if (cmp_result == 0) {
                                swap_cnt = 1;
@@ -203,45 +237,78 @@ loop:
                pc -= es;
        }
 
+       /*
+        * Now we've got:
+        *
+        * +---+-----+-----+---+
+        * | = |  <  |  >  | = |
+        * +---+-----+-----+---+
+        * a   pa  pc,pb   pd  pn
+        *
+        * So swap the '=' into the middle
+        */
+
        pn = (char *)a + n * es;
-       r = min(pa - (char *)a, pb - pa);
-       vecswap(a, pb - r, r);
-       r = min(pd - pc, pn - pd - es);
-       vecswap(pb, pn - r, r);
+       d1 = MIN(pa - (char *)a, pb - pa);
+       vecswap(a, pb - d1, d1);
+       d1 = MIN(pd - pc, pn - pd - es);
+       vecswap(pb, pn - d1, d1);
+
+       /*
+        * +-----+---+---+-----+
+        * |  <  |   =   |  >  |
+        * +-----+---+---+-----+
+        * a                   pn
+        */
 
        if (swap_cnt == 0) {  /* Switch to insertion sort */
-               r = 1 + n / 4; /* n >= 7, so r >= 2 */
-               for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
-                       for (pl = pm; 
-                            pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
-                            pl -= es) {
-                               swap(pl, pl - es);
-                               if (++swap_cnt > r) goto nevermind;
-                       }
+               int r = 1 + n / 4; /* n > 7, so r >= 2 */
+               if (!_isort(a, n, es, thunk, cmp, r, swaptype_long, swaptype_int)) {
+                       goto nevermind;
+               }
                return;
        }
-
 nevermind:
-       if ((r = pb - pa) > es)
+
+       d1 = pb - pa;
+       d2 = pd - pc;
+       if (d1 <= d2) {
+               /* Recurse on left partition, then iterate on right partition */
+               if (d1 > es) {
+#ifdef I_AM_QSORT_R
+                       _qsort(a, d1 / es, es, thunk, cmp, depth_limit);
+#else
+                       _qsort(a, d1 / es, es, cmp, depth_limit);
+#endif
+               }
+               if (d2 > es) {
+                       /* Iterate rather than recurse to save stack space */
+                       /* qsort(pn - d2, d2 / es, es, cmp); */
+                       a = pn - d2;
+                       n = d2 / es;
+                       goto loop;
+               }
+       } else {
+               /* Recurse on right partition, then iterate on left partition */
+               if (d2 > es) {
 #ifdef I_AM_QSORT_R
-               _qsort(a, r / es, es, thunk, cmp, depth_limit);
+                       _qsort(pn - d2, d2 / es, es, thunk, cmp, depth_limit);
 #else
-               _qsort(a, r / es, es, cmp, depth_limit);
+                       _qsort(pn - d2, d2 / es, es, cmp, depth_limit);
 #endif
-       if ((r = pd - pc) > es) {
-               /* Iterate rather than recurse to save stack space */
-               a = pn - r;
-               n = r / es;
-               goto loop;
+               }
+               if (d1 > es) {
+                       /* Iterate rather than recurse to save stack space */
+                       /* qsort(a, d1 / es, es, cmp); */
+                       n = d1 / es;
+                       goto loop;
+               }
        }
-/*             qsort(pn - r, r / es, es, cmp);*/
 }
 
 void
 #ifdef I_AM_QSORT_R
 qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
-#elif defined(I_AM_QSORT_B)
-qsort_b(void *a, size_t n, size_t es, cmp_t ^cmp)
 #else
 qsort(void *a, size_t n, size_t es, cmp_t *cmp)
 #endif
index bce1dae00a9aef3aec8374289227566246681509..740857b4edfa4aab347d3075f2b56744f0ea6efa 100644 (file)
@@ -98,7 +98,7 @@ returns
 If
 .Fa resolved_name
 was non-NULL, it will
-contains the pathname which caused the problem.
+contain the pathname which caused the problem.
 .Sh VARIANTS
 Defining 
 .Dv _DARWIN_C_SOURCE
index 13c4e6f1ed0b55af7e0ec8e8879dfc35e370b6f5..3ce9d8b995eb642d8f8687cfbe8b7a83fde0812b 100644 (file)
@@ -65,7 +65,7 @@ __private_extern__ const struct attrlist _rp_alist = {
        0,
 };
 #else /* BUILDING_VARIANT */
-__private_extern__ const struct attrlist _rp_alist;
+extern const struct attrlist _rp_alist;
 #endif /* BUILDING_VARIANT */
 
 extern char * __private_getcwd(char *, size_t, int);
@@ -82,10 +82,11 @@ realpath(const char *path, char inresolved[PATH_MAX])
 {
        struct attrs attrs;
        struct stat sb;
-       char *p, *q, *s;
-       size_t left_len, resolved_len, save_resolved_len;
+       char *p, *q;
+       size_t left_len, resolved_len, save_resolved_len, next_token_len;
        unsigned symlinks;
-       int serrno, slen, useattrs, islink;
+       int serrno, useattrs, islink;
+       ssize_t slen;
        char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
        dev_t dev, lastdev;
        struct statfs sfs;
@@ -171,16 +172,18 @@ error_return:
                 * and its length.
                 */
                p = strchr(left, '/');
-               s = p ? p : left + left_len;
-               if (s - left >= sizeof(next_token)) {
-                       errno = ENAMETOOLONG;
-                       goto error_return;
+               next_token_len = p ? p - left : left_len;
+               memcpy(next_token, left, next_token_len);
+               next_token[next_token_len] = '\0';
+
+               if (p != NULL) {
+                       left_len -= next_token_len + 1;
+                       memmove(left, p + 1, left_len + 1);
+               } else {
+                       left[0] = '\0';
+                       left_len = 0;
                }
-               memcpy(next_token, left, s - left);
-               next_token[s - left] = '\0';
-               left_len -= s - left;
-               if (p != NULL)
-                       memmove(left, s + 1, left_len + 1);
+
                if (resolved[resolved_len - 1] != '/') {
                        if (resolved_len + 1 >= PATH_MAX) {
                                errno = ENAMETOOLONG;
@@ -189,11 +192,12 @@ error_return:
                        resolved[resolved_len++] = '/';
                        resolved[resolved_len] = '\0';
                }
-               if (next_token[0] == '\0')
+               if (next_token[0] == '\0') {
+                       /* Handle consequential slashes. */
                        continue;
-               else if (strcmp(next_token, ".") == 0)
+               } else if (strcmp(next_token, ".") == 0) {
                        continue;
-               else if (strcmp(next_token, "..") == 0) {
+               else if (strcmp(next_token, "..") == 0) {
                        /*
                         * Strip the last path component except when we have
                         * single "/"
@@ -296,8 +300,14 @@ error_return:
                                errno = ELOOP;
                                goto error_return;
                        }
-                       slen = readlink(resolved, symlink, sizeof(symlink) - 1);
-                       if (slen < 0) {
+                       slen = readlink(resolved, symlink, sizeof(symlink));
+                       if (slen <= 0 || slen >= sizeof(symlink)) {
+                               if (slen < 0)
+                                       ; /* keep errno from readlink(2) call */
+                               else if (slen == 0)
+                                       errno = ENOENT;
+                               else
+                                       errno = ENAMETOOLONG;
                                goto error_return;
                        }
                        symlink[slen] = '\0';
@@ -305,9 +315,8 @@ error_return:
                                resolved[1] = 0;
                                resolved_len = 1;
                                lastdev = rootdev;
-                       } else if (resolved_len > 1) {
+                       } else {
                                /* Strip the last path component. */
-                               resolved[resolved_len - 1] = '\0';
                                q = strrchr(resolved, '/') + 1;
                                *q = '\0';
                                resolved_len = q - resolved;
@@ -328,7 +337,7 @@ error_return:
                                        symlink[slen + 1] = 0;
                                }
                                left_len = strlcat(symlink, left, sizeof(symlink));
-                               if (left_len >= sizeof(left)) {
+                               if (left_len >= sizeof(symlink)) {
                                        errno = ENAMETOOLONG;
                                        goto error_return;
                                }
index 75a5a0db9fb66a13c30d61799141e3b652f26c6b..7f08fcad0679afa4e9848b4db2ccd44ca068bf2a 100644 (file)
@@ -42,15 +42,15 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/setenv.c,v 1.14 2007/05/01 16:02:41 ache
 #include <fcntl.h>
 
 struct owned_ptr;
-__private_extern__ char *__findenv_locked(const char *, int *, char **);
-__private_extern__ int __setenv_locked(const char *, const char *, int, int, char ***, struct owned_ptr *);
-__private_extern__ void __unsetenv_locked(const char *, char **, struct owned_ptr *);
+extern char *__findenv_locked(const char *, int *, char **);
+extern int __setenv_locked(const char *, const char *, int, int, char ***, struct owned_ptr *);
+extern void __unsetenv_locked(const char *, char **, struct owned_ptr *);
 
-__private_extern__ void __environ_lock(void);
-__private_extern__ void __environ_unlock(void);
+extern void __environ_lock(void);
+extern void __environ_unlock(void);
 
-__private_extern__ struct owned_ptr *__env_owned;
-__private_extern__ int __init__env_owned_locked(int);
+extern struct owned_ptr *__env_owned;
+extern int __init__env_owned_locked(int);
 
 /*
  * _cthread_init_routine used to be called from crt1.o to initialize threads.
index 61ef03cbf5bdd8885ffeafea8dc8fa8c13509f56..b4e96eff751e1bb610d9fd0c3c1568d68392647d 100644 (file)
@@ -54,7 +54,9 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/system.c,v 1.11 2007/01/09 00:28:10 imp
 #if __DARWIN_UNIX03
 #include <pthread.h>
 
+#if !(TARGET_OS_IPHONE && (TARGET_OS_SIMULATOR || !TARGET_OS_IOS))
 static pthread_mutex_t __systemfn_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
 extern int __unix_conforming;
 #endif /* __DARWIN_UNIX03 */
 
diff --git a/stdlib/qsort_b-fbsd.c b/stdlib/qsort_b-fbsd.c
deleted file mode 100644 (file)
index 17c0c50..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * This file is in the public domain.  Originally written by Garrett
- * A. Wollman.
- *
- * $FreeBSD: src/lib/libc/stdlib/qsort_r.c,v 1.1 2002/09/10 02:04:49 wollman Exp $
- */
-#define I_AM_QSORT_B
-#include "FreeBSD/qsort.c"
diff --git a/stdlib/qsort_b.c b/stdlib/qsort_b.c
new file mode 100644 (file)
index 0000000..734070b
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+#include <Block_private.h>
+
+typedef int cmp_t(const void *, const void *);
+
+void
+qsort_b(void *base, size_t nel, size_t width, cmp_t ^cmp_b)
+{
+    void *cmp_f = ((struct Block_layout *)cmp_b)->invoke;
+       qsort_r(base, nel, width, cmp_b, (void*)cmp_f);
+}
index 1cd4fcd86167c148fe61bb396e1ffca37989bdf1..65dd91f36f2666f2e8b6a5364cc909a7efed4dd3 100644 (file)
@@ -44,7 +44,8 @@
 .Nm localtime ,
 .Nm localtime_r ,
 .Nm mktime ,
-.Nm timegm
+.Nm timegm ,
+.Nm timelocal
 .Nd transform binary date and time values
 .Sh LIBRARY
 .Lb libc
@@ -73,6 +74,8 @@
 .Fn mktime "struct tm *timeptr"
 .Ft time_t
 .Fn timegm "struct tm *timeptr"
+.Ft time_t
+.Fn timelocal "struct tm *timeptr"
 .Sh DESCRIPTION
 The functions
 .Fn ctime ,
@@ -204,6 +207,16 @@ function interprets the input structure
 as representing Universal Coordinated Time
 .Pq Tn UTC .
 .Pp
+The
+.Fn timelocal
+function is like
+.Fn timegm ,
+but uses the current timezone setting.
+This makes
+.Fn timelocal
+equivalent to
+.Fn mktime .
+.Pp
 The original values of the
 .Fa tm_wday
 and
index 6bb3f03970efcc1a6c87a6a0459a926229390fc4..7e3195d9debddf58783ab15444cb7b98b5ed33cb 100644 (file)
@@ -28,7 +28,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef lint
+#if 0
 static char rcsid[] = "$FreeBSD: /repoman/r/ncvs/src/lib/libcompat/4.1/ftime.c,v 1.5 1999/08/28 00:04:12 peter Exp $";
 #endif /* not lint */
 
index c814a30fbf1160646bcf783200953f87745f7ca5..6c7bd19bb69727bcafbb21f423ab4094cc9df9d3 100644 (file)
@@ -1,20 +1,19 @@
 /*
 ** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+** 1996-06-05 by Arthur David Olson.
 */
 
 #include <sys/cdefs.h>
 #ifndef lint
 #ifndef NOID
-static char    elsieid[] __unused = "@(#)localtime.c   7.78";
+static char    elsieid[] __unused = "@(#)localtime.c   8.14";
 #endif /* !defined NOID */
 #endif /* !defined lint */
-__FBSDID("$FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.43 2008/04/01 06:56:11 davidxu Exp $");
+__FBSDID("$FreeBSD: head/contrib/tzcode/stdtime/localtime.c 289027 2015-10-08 11:42:15Z rodrigc $");
 
 /*
-** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
-** POSIX-style TZ environment variable handling from Guy Harris
-** (guy@auspex.com).
+** Leap second handling from Bradley White.
+** POSIX-style TZ environment variable handling from Guy Harris.
 */
 
 /*LINTLIBRARY*/
@@ -22,10 +21,10 @@ __FBSDID("$FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.43 2008/04/01 06:56:11
 #include "namespace.h"
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <errno.h>
 #include <time.h>
 #include <fcntl.h>
 #include <pthread.h>
-#include <errno.h>
 #ifdef NOTIFY_TZ
 //#define NOTIFY_TZ_DEBUG
 //#define NOTIFY_TZ_DEBUG_FILE "/var/log/localtime.debug"
@@ -42,6 +41,21 @@ __FBSDID("$FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.43 2008/04/01 06:56:11
 #include "un-namespace.h"
 
 #include "tzfile.h"
+#include "float.h"     /* for FLT_MAX and DBL_MAX */
+
+#ifndef TZ_ABBR_MAX_LEN
+/* UNIX03 requires this to be the same as sysconf(_SC_TZNAME_MAX) */
+#define TZ_ABBR_MAX_LEN        255
+#endif /* !defined TZ_ABBR_MAX_LEN */
+
+#ifndef TZ_ABBR_CHAR_SET
+#define TZ_ABBR_CHAR_SET \
+       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
+#endif /* !defined TZ_ABBR_CHAR_SET */
+
+#ifndef TZ_ABBR_ERR_CHAR
+#define TZ_ABBR_ERR_CHAR       '_'
+#endif /* !defined TZ_ABBR_ERR_CHAR */
 
 #include "libc_private.h"
 
@@ -88,23 +102,23 @@ __FBSDID("$FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.43 2008/04/01 06:56:11
 **     5.      They might reference tm.TM_ZONE after calling offtime.
 ** What's best to do in the above cases is open to debate;
 ** for now, we just set things up so that in any of the five cases
-** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
+** WILDABBR is used. Another possibility: initialize tzname[0] to the
 ** string "tzname[0] used before set", and similarly for the other cases.
-** And another:  initialize tzname[0] to "ERA", with an explanation in the
+** And another: initialize tzname[0] to "ERA", with an explanation in the
 ** manual page of what this "time zone abbreviation" means (doing this so
 ** that tzname[0] has the "normal" length of three characters).
 */
 #define WILDABBR       "   "
 #endif /* !defined WILDABBR */
 
-static const char              wildabbr[] = "WILDABBR";
+__used static const char               wildabbr[] = WILDABBR;
 
 /*
  * In June 2004 it was decided UTC was a more appropriate default time
  * zone than GMT.
  */
 
-static const char      gmt[] = "UTC";
+__used static const char       gmt[] = "UTC";
 
 /*
 ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
@@ -144,6 +158,8 @@ struct state {
        int             timecnt;
        int             typecnt;
        int             charcnt;
+       int             goback;
+       int             goahead;
        time_t          ats[TZ_MAX_TIMES];
        unsigned char   types[TZ_MAX_TIMES];
        struct ttinfo   ttis[TZ_MAX_TYPES];
@@ -203,7 +219,11 @@ void                       tzset_basic(int);
 
 #if !BUILDING_VARIANT
 static long            detzcode(const char * codep);
+static time_t          detzcode64(const char * codep);
+static int             differ_by_repeat(time_t t1, time_t t0);
 static const char *    getzname(const char * strp, char **name, size_t *len);
+static const char *    getqzname(const char * strp, const int delim)
+  ATTRIBUTE_PURE;
 static const char *    getnum(const char * strp, int * nump, int min,
                                int max);
 static const char *    getsecs(const char * strp, long * secsp);
@@ -222,6 +242,10 @@ static void                gmtsub(const time_t * timep, long offset,
                                struct tm * tmp);
 #endif /* __LP64__ */
 static int             increment_overflow(int * number, int delta);
+static int             leaps_thru_end_of(int y) ATTRIBUTE_PURE;
+static int             long_increment_overflow(long * number, int delta);
+static int             long_normalize_overflow(long * tensptr,
+                               int * unitsptr, int base);
 static int             normalize_overflow(int * tensptr, int * unitsptr,
                                int base);
 #ifdef NOTIFY_TZ
@@ -258,11 +282,13 @@ static void               timesub(const time_t * timep, long offset,
 static int             tmcomp(const struct tm * atmp,
                                const struct tm * btmp);
 static time_t          transtime(time_t janfirst, int year,
-                               const struct rule * rulep, long offset);
+                                 const struct rule * rulep, long offset)
+  ATTRIBUTE_PURE;
+static int             typesequiv(const struct state * sp, int a, int b);
 #ifdef NOTIFY_TZ
-static int             tzload(const char * name, struct state * sp, char *path);
+static int             tzload(const char * name, struct state * sp, char *path, int doextend);
 #else /* ! NOTIFY_TZ */
-static int             tzload(const char * name, struct state * sp);
+static int             tzload(const char * name, struct state * sp, int doextend);
 #endif /* NOTIFY_TZ */
 static int             tzparse(const char * name, struct state * sp,
                                int lastditch);
@@ -289,10 +315,15 @@ static char               lcl_TZname[TZ_STRLEN_MAX + 1];
 #define gmt_is_set    (gmt_notify.is_set)
 #else /* ! NOTIFY_TZ */
 static int             lcl_is_set;
-static int             gmt_is_set;
 #endif /* NOTIFY_TZ */
+static pthread_once_t  gmt_once = PTHREAD_ONCE_INIT;
 __private_extern__ pthread_rwlock_t    lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER;
-static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t  gmtime_once = PTHREAD_ONCE_INIT;
+static pthread_key_t   gmtime_key;
+static int             gmtime_key_error;
+static pthread_once_t  localtime_once = PTHREAD_ONCE_INIT;
+static pthread_key_t   localtime_key;
+static int             localtime_key_error;
 
 char *                 tzname[2] = {
        (char *)wildabbr,
@@ -304,7 +335,7 @@ char *                      tzname[2] = {
 **     Except for the strftime function, these functions [asctime,
 **     ctime, gmtime, localtime] return values in one of two static
 **     objects: a broken-down time structure and an array of char.
-** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
+** Thanks to Paul Eggert for noting this.
 */
 
 static struct tm       tm;
@@ -353,18 +384,29 @@ static const char notify_tz_name[] = NOTIFY_TZ_NAME;
 #endif /* NOTIFY_TZ */
 
 static long
-detzcode(codep)
-const char * const     codep;
+detzcode(const char *const codep)
 {
        long    result;
        int     i;
 
-       result = (codep[0] & 0x80) ? ~0L : 0L;
+       result = (codep[0] & 0x80) ? ~0L : 0;
        for (i = 0; i < 4; ++i)
                result = (result << 8) | (codep[i] & 0xff);
        return result;
 }
 
+static time_t
+detzcode64(const char *const codep)
+{
+       register time_t result;
+       register int    i;
+
+       result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
+       for (i = 0; i < 8; ++i)
+               result = result * 256 + (codep[i] & 0xff);
+       return result;
+}
+
 static void
 settzname(void)
 {
@@ -452,6 +494,24 @@ settzname(void)
                }
 #endif /* defined(ALTZONE) || defined(USG_COMPAT) */
        }
+       /*
+       ** Finally, scrub the abbreviations.
+       ** First, replace bogus characters.
+       */
+       for (i = 0; i < sp->charcnt; ++i)
+               if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
+                       sp->chars[i] = TZ_ABBR_ERR_CHAR;
+       /*
+       ** Second, truncate long abbreviations.
+       */
+       for (i = 0; i < sp->typecnt; ++i) {
+               register const struct ttinfo * const    ttisp = &sp->ttis[i];
+               register char *                         cp = &sp->chars[ttisp->tt_abbrind];
+
+               if (strlen(cp) > TZ_ABBR_MAX_LEN &&
+                       strcmp(cp, GRANDPARENTED) != 0)
+                               *(cp + TZ_ABBR_MAX_LEN) = '\0';
+       }
 }
 
 #ifdef NOTIFY_TZ
@@ -549,21 +609,48 @@ notify_register_tz(char *file, notify_tz_t *p)
 }
 #endif /* NOTIFY_TZ */
 
+static int
+differ_by_repeat(const time_t t1, const time_t t0)
+{
+       int_fast64_t _t0 = t0;
+       int_fast64_t _t1 = t1;
+
+       if (TYPE_INTEGRAL(time_t) &&
+               TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
+                       return 0;
+       //turn ((int_fast64_t)(t1 - t0) == SECSPERREPEAT);
+       return _t1 - _t0 == SECSPERREPEAT;
+}
+
 static int
 #ifdef NOTIFY_TZ
-tzload(name, sp, path)
+tzload(name, sp, path, doextend)
 #else /* ! NOTIFY_TZ */
-tzload(name, sp)
+tzload(name, sp, doextend)
 #endif /* NOTIFY_TZ */
 const char *           name;
 struct state * const   sp;
 #ifdef NOTIFY_TZ
 char *                 path; /* copy full path if non-NULL */
 #endif /* NOTIFY_TZ */
+register const int     doextend;
 {
        const char *    p;
        int             i;
        int             fid;
+       int             stored;
+       int             nread;
+       int             res;
+       union {
+               struct tzhead   tzhead;
+               char            buf[2 * sizeof(struct tzhead) +
+                                       2 * sizeof *sp +
+                                       4 * TZ_MAX_TIMES];
+       } *u;
+
+       u = NULL;
+       res = -1;
+       sp->goback = sp->goahead = FALSE;
 
 #ifdef NOTIFY_TZ_DEBUG
        NOTIFY_TZ_PRINTF("tzload: name=%s\n", name);
@@ -589,16 +676,24 @@ char *                    path; /* copy full path if non-NULL */
                ** to hold the longest file name string that the implementation
                ** guarantees can be opened."
                */
-               char            fullname[FILENAME_MAX + 1];
+               char            *fullname;
+
+               fullname = malloc(FILENAME_MAX + 1);
+               if (fullname == NULL)
+                       goto out;
 
                if (name[0] == ':')
                        ++name;
                doaccess = name[0] == '/';
                if (!doaccess) {
-                       if ((p = TZDIR) == NULL)
+                       if ((p = TZDIR) == NULL) {
+                               free(fullname);
                                return -1;
-                       if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
+                       }
+                       if (strlen(p) + 1 + strlen(name) >= FILENAME_MAX) {
+                               free(fullname);
                                return -1;
+                       }
                        (void) strcpy(fullname, p);
                        (void) strcat(fullname, "/");
                        (void) strcat(fullname, name);
@@ -616,60 +711,66 @@ char *                    path; /* copy full path if non-NULL */
                        strcpy(path, name);
                }
 #endif /* NOTIFY_TZ */
-               if (doaccess && access(name, R_OK) != 0)
+               if (doaccess && access(name, R_OK) != 0) {
+                       free(fullname);
                        return -1;
-               if ((fid = _open(name, OPEN_MODE)) == -1)
+               }
+               if ((fid = _open(name, OPEN_MODE)) == -1) {
+                       free(fullname);
                        return -1;
+               }
                if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
+                       free(fullname);
                        _close(fid);
                        return -1;
                }
+               free(fullname);
        }
-       {
-               struct tzhead * tzhp;
-               union {
-                       struct tzhead   tzhead;
-                       char            buf[sizeof *sp + sizeof *tzhp];
-               } u;
+       u = malloc(sizeof(*u));
+       if (u == NULL)
+               goto out;
+#ifdef NOTIFY_TZ_DEBUG
+       NOTIFY_TZ_PRINTF("tzload: reading %s\n", name);
+#endif /* NOTIFY_TZ_DEBUG */
+       nread = _read(fid, u->buf, sizeof u->buf);
+       if (_close(fid) < 0 || nread <= 0)
+               goto out;
+       for (stored = 4; stored <= 8; stored *= 2) {
                int             ttisstdcnt;
                int             ttisgmtcnt;
 
-#ifdef NOTIFY_TZ_DEBUG
-               NOTIFY_TZ_PRINTF("tzload: reading %s\n", name);
-#endif /* NOTIFY_TZ_DEBUG */
-               i = _read(fid, u.buf, sizeof u.buf);
-               if (_close(fid) != 0)
-                       return -1;
-               ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
-               ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
-               sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
-               sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
-               sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
-               sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
-               p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
+               ttisstdcnt = (int) detzcode(u->tzhead.tzh_ttisstdcnt);
+               ttisgmtcnt = (int) detzcode(u->tzhead.tzh_ttisgmtcnt);
+               sp->leapcnt = (int) detzcode(u->tzhead.tzh_leapcnt);
+               sp->timecnt = (int) detzcode(u->tzhead.tzh_timecnt);
+               sp->typecnt = (int) detzcode(u->tzhead.tzh_typecnt);
+               sp->charcnt = (int) detzcode(u->tzhead.tzh_charcnt);
+               p = u->tzhead.tzh_charcnt + sizeof u->tzhead.tzh_charcnt;
                if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
                        sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
                        sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
                        sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
                        (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
                        (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
-                               return -1;
-               if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
+                               goto out;
+               if (nread - (p - u->buf) <
+                       sp->timecnt * stored +          /* ats */
                        sp->timecnt +                   /* types */
-                       sp->typecnt * (4 + 2) +         /* ttinfos */
+                       sp->typecnt * 6 +               /* ttinfos */
                        sp->charcnt +                   /* chars */
-                       sp->leapcnt * (4 + 4) +         /* lsinfos */
+                       sp->leapcnt * (stored + 4) +    /* lsinfos */
                        ttisstdcnt +                    /* ttisstds */
                        ttisgmtcnt)                     /* ttisgmts */
-                               return -1;
+                               goto out;
                for (i = 0; i < sp->timecnt; ++i) {
-                       sp->ats[i] = detzcode(p);
-                       p += 4;
+                       sp->ats[i] = (stored == 4) ?
+                               detzcode(p) : detzcode64(p);
+                       p += stored;
                }
                for (i = 0; i < sp->timecnt; ++i) {
                        sp->types[i] = (unsigned char) *p++;
                        if (sp->types[i] >= sp->typecnt)
-                               return -1;
+                               goto out;
                }
                for (i = 0; i < sp->typecnt; ++i) {
                        struct ttinfo * ttisp;
@@ -679,11 +780,11 @@ char *                    path; /* copy full path if non-NULL */
                        p += 4;
                        ttisp->tt_isdst = (unsigned char) *p++;
                        if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
-                               return -1;
+                               goto out;
                        ttisp->tt_abbrind = (unsigned char) *p++;
                        if (ttisp->tt_abbrind < 0 ||
                                ttisp->tt_abbrind > sp->charcnt)
-                                       return -1;
+                                       goto out;
                }
                for (i = 0; i < sp->charcnt; ++i)
                        sp->chars[i] = *p++;
@@ -692,8 +793,9 @@ char *                      path; /* copy full path if non-NULL */
                        struct lsinfo * lsisp;
 
                        lsisp = &sp->lsis[i];
-                       lsisp->ls_trans = detzcode(p);
-                       p += 4;
+                       lsisp->ls_trans = (stored == 4) ?
+                               detzcode(p) : detzcode64(p);
+                       p += stored;
                        lsisp->ls_corr = detzcode(p);
                        p += 4;
                }
@@ -707,7 +809,7 @@ char *                      path; /* copy full path if non-NULL */
                                ttisp->tt_ttisstd = *p++;
                                if (ttisp->tt_ttisstd != TRUE &&
                                        ttisp->tt_ttisstd != FALSE)
-                                               return -1;
+                                               goto out;
                        }
                }
                for (i = 0; i < sp->typecnt; ++i) {
@@ -720,11 +822,134 @@ char *                   path; /* copy full path if non-NULL */
                                ttisp->tt_ttisgmt = *p++;
                                if (ttisp->tt_ttisgmt != TRUE &&
                                        ttisp->tt_ttisgmt != FALSE)
-                                               return -1;
+                                               goto out;
                        }
                }
+               /*
+               ** Out-of-sort ats should mean we're running on a
+               ** signed time_t system but using a data file with
+               ** unsigned values (or vice versa).
+               */
+               for (i = 0; i < sp->timecnt - 2; ++i)
+                       if (sp->ats[i] > sp->ats[i + 1]) {
+                               ++i;
+                               if (TYPE_SIGNED(time_t)) {
+                                       /*
+                                       ** Ignore the end (easy).
+                                       */
+                                       sp->timecnt = i;
+                               } else {
+                                       /*
+                                       ** Ignore the beginning (harder).
+                                       */
+                                       register int    j;
+
+                                       for (j = 0; j + i < sp->timecnt; ++j) {
+                                               sp->ats[j] = sp->ats[j + i];
+                                               sp->types[j] = sp->types[j + i];
+                                       }
+                                       sp->timecnt = j;
+                               }
+                               break;
+                       }
+               /*
+               ** If this is an old file, we're done.
+               */
+               if (u->tzhead.tzh_version[0] == '\0')
+                       break;
+               nread -= p - u->buf;
+               for (i = 0; i < nread; ++i)
+                       u->buf[i] = p[i];
+               /*
+               ** If this is a narrow integer time_t system, we're done.
+               */
+               if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
+                       break;
        }
-       return 0;
+       if (doextend && nread > 2 &&
+               u->buf[0] == '\n' && u->buf[nread - 1] == '\n' &&
+               sp->typecnt + 2 <= TZ_MAX_TYPES) {
+                       struct state    *ts;
+                       register int    result;
+
+                       ts = malloc(sizeof(*ts));
+                       if (ts == NULL)
+                               goto out;
+                       u->buf[nread - 1] = '\0';
+                       result = tzparse(&u->buf[1], ts, FALSE);
+                       if (result == 0 && ts->typecnt == 2 &&
+                               sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) {
+                                       for (i = 0; i < 2; ++i)
+                                               ts->ttis[i].tt_abbrind +=
+                                                       sp->charcnt;
+                                       for (i = 0; i < ts->charcnt; ++i)
+                                               sp->chars[sp->charcnt++] =
+                                                       ts->chars[i];
+                                       i = 0;
+                                       while (i < ts->timecnt &&
+                                               ts->ats[i] <=
+                                               sp->ats[sp->timecnt - 1])
+                                                       ++i;
+                                       while (i < ts->timecnt &&
+                                           sp->timecnt < TZ_MAX_TIMES) {
+                                               sp->ats[sp->timecnt] =
+                                                       ts->ats[i];
+                                               sp->types[sp->timecnt] =
+                                                       sp->typecnt +
+                                                       ts->types[i];
+                                               ++sp->timecnt;
+                                               ++i;
+                                       }
+                                       sp->ttis[sp->typecnt++] = ts->ttis[0];
+                                       sp->ttis[sp->typecnt++] = ts->ttis[1];
+                       }
+                       free(ts);
+       }
+       if (sp->timecnt > 1) {
+               for (i = 1; i < sp->timecnt; ++i)
+                       if (typesequiv(sp, sp->types[i], sp->types[0]) &&
+                               differ_by_repeat(sp->ats[i], sp->ats[0])) {
+                                       sp->goback = TRUE;
+                                       break;
+                               }
+               for (i = sp->timecnt - 2; i >= 0; --i)
+                       if (typesequiv(sp, sp->types[sp->timecnt - 1],
+                               sp->types[i]) &&
+                               differ_by_repeat(sp->ats[sp->timecnt - 1],
+                               sp->ats[i])) {
+                                       sp->goahead = TRUE;
+                                       break;
+               }
+       }
+       res = 0;
+out:
+       free(u);
+       return (res);
+}
+
+static int
+typesequiv(sp, a, b)
+const struct state * const     sp;
+const int                      a;
+const int                      b;
+{
+       register int    result;
+
+       if (sp == NULL ||
+               a < 0 || a >= sp->typecnt ||
+               b < 0 || b >= sp->typecnt)
+                       result = FALSE;
+       else {
+               register const struct ttinfo *  ap = &sp->ttis[a];
+               register const struct ttinfo *  bp = &sp->ttis[b];
+               result = ap->tt_gmtoff == bp->tt_gmtoff &&
+                       ap->tt_isdst == bp->tt_isdst &&
+                       ap->tt_ttisstd == bp->tt_ttisstd &&
+                       ap->tt_ttisgmt == bp->tt_ttisgmt &&
+                       strcmp(&sp->chars[ap->tt_abbrind],
+                       &sp->chars[bp->tt_abbrind]) == 0;
+       }
+       return result;
 }
 
 static const int       mon_lengths[2][MONSPERYEAR] = {
@@ -738,7 +963,7 @@ static const int    year_lengths[2] = {
 
 /*
 ** Given a pointer into a time zone string, scan until a character that is not
-** a valid character in a zone name is found.  Return a pointer to that
+** a valid character in a zone name is found. Return a pointer to that
 ** character.
 */
 
@@ -764,6 +989,25 @@ size_t *   len;
        return strp;
 }
 
+/*
+** Given a pointer into an extended time zone string, scan until the ending
+** delimiter of the zone name is located. Return a pointer to the delimiter.
+**
+** As with getzname above, the legal character set is actually quite
+** restricted, with other characters producing undefined results.
+** We don't do any checking here; checking is done later in common-case code.
+*/
+
+static const char *
+getqzname(register const char *strp, const int delim)
+{
+       register int    c;
+
+       while ((c = *strp) != '\0' && c != delim)
+               ++strp;
+       return strp;
+}
+
 /*
 ** Given a pointer into a time zone string, extract a number from that string.
 ** Check that the number is within a specified range; if it is not, return
@@ -829,7 +1073,7 @@ long * const               secsp;
                *secsp += num * SECSPERMIN;
                if (*strp == ':') {
                        ++strp;
-                       /* `SECSPERMIN' allows for leap seconds.  */
+                       /* `SECSPERMIN' allows for leap seconds. */
                        strp = getnum(strp, &num, 0, SECSPERMIN);
                        if (strp == NULL)
                                return NULL;
@@ -868,7 +1112,7 @@ long * const               offsetp;
 
 /*
 ** Given a pointer into a time zone string, extract a rule in the form
-** date[/time].  See POSIX section 8 for the format of "date" and "time".
+** date[/time]. See POSIX section 8 for the format of "date" and "time".
 ** If a valid rule is not found, return NULL.
 ** Otherwise, return a pointer to the first character not part of the rule.
 */
@@ -987,7 +1231,7 @@ const long                         offset;
                        dow += DAYSPERWEEK;
 
                /*
-               ** "dow" is the day-of-week of the first day of the month.  Get
+               ** "dow" is the day-of-week of the first day of the month. Get
                ** the day-of-month (zero-origin) of the first "dow" day of the
                ** month.
                */
@@ -1010,7 +1254,7 @@ const long                                offset;
 
        /*
        ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
-       ** question.  To get the Epoch-relative time of the specified local
+       ** question. To get the Epoch-relative time of the specified local
        ** time on that day, add the transition time and the current offset
        ** from UTC.
        */
@@ -1049,8 +1293,6 @@ const int                 lastditch;
                stdoffset = 0;
        } else {
                name = getzname(name, (char **)&stdname, &stdlen);
-               if (stdlen < 3)
-                       return -1;
                if (*name == '\0')
                        return -1;      /* was "stdoffset = 0;" */
                else {
@@ -1060,17 +1302,24 @@ const int                       lastditch;
                }
        }
 #ifdef NOTIFY_TZ
-       load_result = tzload(TZDEFRULES, sp, NULL);
+       load_result = tzload(TZDEFRULES, sp, NULL, FALSE);
 #else /* !NOTIFY_TZ */
-       load_result = tzload(TZDEFRULES, sp);
+       load_result = tzload(TZDEFRULES, sp, FALSE);
 #endif /* NOTIFY_TZ */
        if (load_result != 0)
                sp->leapcnt = 0;                /* so, we're off a little */
        if (*name != '\0') {
-               dstname = name;
-               name = getzname(name, (char **)&dstname, &dstlen);
-               if (dstlen < 3)
-                       return -1;
+               if (*name == '<') {
+                       dstname = ++name;
+                       name = getqzname(name, '>');
+                       if (*name != '>')
+                               return -1;
+                       dstlen = name - dstname;
+                       name++;
+               } else {
+                       dstname = name;
+                       name = getzname(name, (char **)&dstname, &dstlen);
+               }
                if (*name != '\0' && *name != ',' && *name != ';') {
                        name = getoffset(name, &dstoffset);
                        if (name == NULL)
@@ -1097,11 +1346,8 @@ const int                        lastditch;
                                return -1;
                        sp->typecnt = 2;        /* standard time and DST */
                        /*
-                       ** Two transitions per year, from EPOCH_YEAR to 2037.
+                       ** Two transitions per year, from EPOCH_YEAR forward.
                        */
-                       sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
-                       if (sp->timecnt > TZ_MAX_TIMES)
-                               return -1;
                        sp->ttis[0].tt_gmtoff = -dstoffset;
                        sp->ttis[0].tt_isdst = 1;
                        sp->ttis[0].tt_abbrind = stdlen + 1;
@@ -1111,7 +1357,12 @@ const int                        lastditch;
                        atp = sp->ats;
                        typep = sp->types;
                        janfirst = 0;
-                       for (year = EPOCH_YEAR; year <= 2037; ++year) {
+                       sp->timecnt = 0;
+                       for (year = EPOCH_YEAR;
+                           sp->timecnt + 2 <= TZ_MAX_TIMES;
+                           ++year) {
+                               time_t  newfirst;
+
                                starttime = transtime(janfirst, year, &start,
                                        stdoffset);
                                endtime = transtime(janfirst, year, &end,
@@ -1127,8 +1378,13 @@ const int                        lastditch;
                                        *atp++ = endtime;
                                        *typep++ = 1;   /* DST ends */
                                }
-                               janfirst += year_lengths[isleap(year)] *
+                               sp->timecnt += 2;
+                               newfirst = janfirst;
+                               newfirst += year_lengths[isleap(year)] *
                                        SECSPERDAY;
+                               if (newfirst <= janfirst)
+                                       break;
+                               janfirst = newfirst;
                        }
                } else {
                        long    theirstdoffset;
@@ -1251,9 +1507,9 @@ char *path;
 #endif /* NOTIFY_TZ */
 {
 #ifdef NOTIFY_TZ
-       if (tzload(gmt, sp, path) != 0)
+       if (tzload(gmt, sp, path, TRUE) != 0)
 #else /* ! NOTIFY_TZ */
-       if (tzload(gmt, sp) != 0)
+       if (tzload(gmt, sp, TRUE) != 0)
 #endif /* NOTIFY_TZ */
                (void) tzparse(gmt, sp, TRUE);
 }
@@ -1264,20 +1520,20 @@ tzsetwall_basic(int rdlocked)
 #ifdef NOTIFY_TZ
        notify_check_tz(&lcl_notify);
 #else
-    if (TZDEFAULT) {
-        static struct timespec last_mtimespec = {0, 0};
-        struct stat statbuf;
-
-        if (lstat(TZDEFAULT, &statbuf) == 0) {
-            if (statbuf.st_mtimespec.tv_sec > last_mtimespec.tv_sec ||
-                (statbuf.st_mtimespec.tv_sec == last_mtimespec.tv_sec &&
-                 statbuf.st_mtimespec.tv_nsec > last_mtimespec.tv_nsec)) {
-               /* Trigger resetting the local TZ */
-                    lcl_is_set = 0;
-            }
-            last_mtimespec = statbuf.st_mtimespec;
-        }
-    }
+       if (TZDEFAULT) {
+               static struct timespec last_mtimespec = {0, 0};
+               struct stat statbuf;
+
+               if (lstat(TZDEFAULT, &statbuf) == 0) {
+                       if (statbuf.st_mtimespec.tv_sec > last_mtimespec.tv_sec ||
+                               (statbuf.st_mtimespec.tv_sec == last_mtimespec.tv_sec &&
+                               statbuf.st_mtimespec.tv_nsec > last_mtimespec.tv_nsec)) {
+                               /* Trigger resetting the local TZ */
+                               lcl_is_set = 0;
+                       }
+                       last_mtimespec = statbuf.st_mtimespec;
+               }
+       }
 #endif /* NOTIFY_TZ */
        if (!rdlocked)
                _RWLOCK_RDLOCK(&lcl_rwlock);
@@ -1299,7 +1555,7 @@ tzsetwall_basic(int rdlocked)
 
 #ifdef ALL_STATE
        if (lclptr == NULL) {
-               lclptr = (struct state *) malloc(sizeof *lclptr);
+               lclptr = calloc(1, sizeof *lclptr);
                if (lclptr == NULL) {
                        settzname();    /* all we can do */
                        _RWLOCK_UNLOCK(&lcl_rwlock);
@@ -1312,16 +1568,16 @@ tzsetwall_basic(int rdlocked)
 #ifdef NOTIFY_TZ
        {
                char            fullname[FILENAME_MAX + 1];
-               if (tzload((char *) NULL, lclptr, fullname) != 0)
+               if (tzload((char *) NULL, lclptr, fullname, TRUE) != 0)
                        /*
                         * If fullname is empty (an error occurred) then
                         * default to the UTC path
                         */
                        gmtload(lclptr, *fullname ? NULL : fullname);
-               notify_register_tz(fullname, &lcl_notify);
+                       notify_register_tz(fullname, &lcl_notify);
        }
 #else /* ! NOTIFY_TZ */
-       if (tzload((char *) NULL, lclptr) != 0)
+       if (tzload((char *) NULL, lclptr, TRUE) != 0)
                gmtload(lclptr);
 #endif /* NOTIFY_TZ */
        settzname();
@@ -1373,7 +1629,7 @@ tzset_basic(int rdlocked)
 
 #ifdef ALL_STATE
        if (lclptr == NULL) {
-               lclptr = (struct state *) malloc(sizeof *lclptr);
+               lclptr = (struct state *) calloc(1, sizeof *lclptr);
                if (lclptr == NULL) {
                        settzname();    /* all we can do */
                        _RWLOCK_UNLOCK(&lcl_rwlock);
@@ -1399,7 +1655,7 @@ tzset_basic(int rdlocked)
 #endif /* NOTIFY_TZ */
        } else
 #ifdef NOTIFY_TZ
-         {
+       {
                char            fullname[FILENAME_MAX + 1];
                /*
                 * parsedOK indicates whether tzparse() was called and
@@ -1408,17 +1664,17 @@ tzset_basic(int rdlocked)
                 * notifications.
                 */
                int             parsedOK = FALSE;
-               if (tzload(name, lclptr, fullname) != 0)
+               if (tzload(name, lclptr, fullname, TRUE) != 0)
                        if (name[0] == ':' || !(parsedOK = tzparse(name, lclptr, FALSE) == 0))
                                /*
                                 * If fullname is empty (an error occurred) then
                                 * default to the UTC path
                                 */
                                (void) gmtload(lclptr, *fullname ? NULL : fullname);
-               notify_register_tz(parsedOK ? NULL : fullname, &lcl_notify);
-         }
+                               notify_register_tz(parsedOK ? NULL : fullname, &lcl_notify);
+       }
 #else /* ! NOTIFY_TZ */
-         if (tzload(name, lclptr) != 0)
+       if (tzload(name, lclptr, TRUE) != 0)
                if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
                        (void) gmtload(lclptr);
 #endif /* NOTIFY_TZ */
@@ -1441,7 +1697,7 @@ tzset(void)
 /*
 ** The easy way to behave "as if no library function calls" localtime
 ** is to not call it--so we drop its guts into "localsub", which can be
-** freely called.  (And no, the PANS doesn't require the above behavior--
+** freely called. (And no, the PANS doesn't require the above behavior--
 ** but it *is* desirable.)
 **
 ** The unused offset argument is for the benefit of mktime variants.
@@ -1453,15 +1709,15 @@ __private_extern__ struct tm *
 #else /* !__LP64__ */
 __private_extern__ void
 #endif /* __LP64__ */
-localsub(timep, offset, tmp)
-const time_t * const   timep;
-const long             offset;
-struct tm * const      tmp;
+localsub(const time_t *const timep, const long offset, struct tm *const tmp)
 {
        struct state *          sp;
        const struct ttinfo *   ttisp;
        int                     i;
-       const time_t                    t = *timep;
+#ifdef __LP64__
+       struct tm *             result;
+#endif /* __LP64__ */
+       const time_t            t = *timep;
 
 #ifdef NOTIFY_TZ_DEBUG
        NOTIFY_TZ_PRINTF("localsub called\n");
@@ -1477,6 +1733,62 @@ struct tm * const        tmp;
 #endif /* __LP64__ */
        }
 #endif /* defined ALL_STATE */
+       if ((sp->goback && t < sp->ats[0]) ||
+               (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
+                       time_t                  newt = t;
+                       register time_t         seconds;
+                       register time_t         tcycles;
+                       register int_fast64_t   icycles;
+
+                       if (t < sp->ats[0])
+                               seconds = sp->ats[0] - t;
+                       else    seconds = t - sp->ats[sp->timecnt - 1];
+                       --seconds;
+                       tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
+                       ++tcycles;
+                       icycles = tcycles;
+                       if (tcycles - icycles >= 1 || icycles - tcycles >= 1) {
+#ifdef __LP64__
+                               return NULL;
+#else /* !__LP64__ */
+                               return;
+#endif /* __LP64__ */
+                       }
+                       seconds = icycles;
+                       seconds *= YEARSPERREPEAT;
+                       seconds *= AVGSECSPERYEAR;
+                       if (t < sp->ats[0])
+                               newt += seconds;
+                       else    newt -= seconds;
+                       if (newt < sp->ats[0] ||
+                               newt > sp->ats[sp->timecnt - 1])
+#ifdef __LP64__
+                                       return NULL;    /* "cannot happen" */
+                       result = localsub(&newt, offset, tmp);
+                       if (result == tmp) {
+#else /* !__LP64__ */
+                                       return;
+                       localsub(&newt, offset, tmp);
+                       {
+#endif /* __LP64__ */
+                               register time_t newy;
+
+                               newy = tmp->tm_year;
+                               if (t < sp->ats[0])
+                                       newy -= icycles * YEARSPERREPEAT;
+                               else    newy += icycles * YEARSPERREPEAT;
+                               tmp->tm_year = newy;
+                               if (tmp->tm_year != newy)
+#ifdef __LP64__
+                                       return NULL;
+                       }
+                       return result;
+#else /* !__LP64__ */
+                                       return;
+                       }
+                       return;
+#endif /* __LP64__ */
+       }
        if (sp->timecnt == 0 || t < sp->ats[0]) {
                i = 0;
                while (sp->ttis[i].tt_isdst)
@@ -1485,10 +1797,17 @@ struct tm * const       tmp;
                                break;
                        }
        } else {
-               for (i = 1; i < sp->timecnt; ++i)
-                       if (t < sp->ats[i])
-                               break;
-               i = sp->types[i - 1];
+               register int    lo = 1;
+               register int    hi = sp->timecnt;
+
+               while (lo < hi) {
+                       register int    mid = (lo + hi) >> 1;
+
+                       if (t < sp->ats[mid])
+                               hi = mid;
+                       else    lo = mid + 1;
+               }
+               i = (int) sp->types[lo - 1];
        }
        ttisp = &sp->ttis[i];
        /*
@@ -1498,7 +1817,8 @@ struct tm * const tmp;
        **      timesub(&t, 0L, sp, tmp);
        */
 #ifdef __LP64__
-       if (timesub(&t, ttisp->tt_gmtoff, sp, tmp) == NULL)
+       result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+       if (result == NULL)
                return NULL;
 #else /* !__LP64__ */
        timesub(&t, ttisp->tt_gmtoff, sp, tmp);
@@ -1509,29 +1829,28 @@ struct tm * const       tmp;
        tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
 #endif /* defined TM_ZONE */
 #ifdef __LP64__
-       return tmp;
+       return result;
 #endif /* __LP64__ */
 }
 
+static void
+localtime_key_init(void)
+{
+
+       localtime_key = __LIBC_PTHREAD_KEY_LOCALTIME;
+       localtime_key_error = pthread_key_init_np(localtime_key, free);
+}
+
 struct tm *
-localtime(timep)
-const time_t * const   timep;
+localtime(const time_t *const timep)
 {
-       static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
-       static pthread_key_t localtime_key = -1;
        struct tm *p_tm;
 
        if (__isthreaded != 0) {
-               if (localtime_key == (pthread_key_t)-1) {
-                       _pthread_mutex_lock(&localtime_mutex);
-                       if (localtime_key == (pthread_key_t)-1) {
-                               localtime_key = __LIBC_PTHREAD_KEY_LOCALTIME;
-                               if (pthread_key_init_np(localtime_key, free) < 0) {
-                                       _pthread_mutex_unlock(&localtime_mutex);
-                                       return(NULL);
-                               }
-                       }
-                       _pthread_mutex_unlock(&localtime_mutex);
+               _pthread_once(&localtime_once, localtime_key_init);
+               if (localtime_key_error != 0) {
+                       errno = localtime_key_error;
+                       return(NULL);
                }
                p_tm = _pthread_getspecific(localtime_key);
                if (p_tm == NULL) {
@@ -1565,17 +1884,39 @@ const time_t * const    timep;
 */
 
 struct tm *
-localtime_r(const time_t * const __restrict timep, struct tm * __restrict tm)
+localtime_r(const time_t *const __restrict timep, struct tm * __restrict tmp)
 {
        _RWLOCK_RDLOCK(&lcl_rwlock);
        tzset_basic(1);
 #ifdef __LP64__
-       tm = localsub(timep, 0L, tm);
+       tmp = localsub(timep, 0L, tmp);
 #else /* !__LP64__ */
-       localsub(timep, 0L, tm);
+       localsub(timep, 0L, tmp);
 #endif /* __LP64__ */
        _RWLOCK_UNLOCK(&lcl_rwlock);
-       return tm;
+       return tmp;
+}
+
+static void
+gmt_init(void)
+{
+
+#ifdef ALL_STATE
+#ifdef NOTIFY_TZ
+       if (gmtptr == NULL)
+#endif /* NOTIFY_TZ */
+               gmtptr = (struct state *) calloc(1, sizeof *gmtptr);
+       if (gmtptr != NULL)
+#endif /* defined ALL_STATE */
+#ifdef NOTIFY_TZ
+       {
+               char            fullname[FILENAME_MAX + 1];
+               gmtload(gmtptr, fullname);
+               notify_register_tz(fullname, &gmt_notify);
+       }
+#else /* ! NOTIFY_TZ */
+               gmtload(gmtptr);
+#endif /* NOTIFY_TZ */
 }
 
 /*
@@ -1592,37 +1933,20 @@ const time_t * const    timep;
 const long             offset;
 struct tm * const      tmp;
 {
+#ifdef __LP64__
+       register struct tm *    result;
+#endif /* __LP64__ */
+
 #ifdef NOTIFY_TZ_DEBUG
        NOTIFY_TZ_PRINTF("gmtsub called\n");
 #endif /* NOTIFY_TZ_DEBUG */
 #ifdef NOTIFY_TZ
        notify_check_tz(&gmt_notify);
 #endif /* NOTIFY_TZ */
-       if (!gmt_is_set) {
-               _MUTEX_LOCK(&gmt_mutex);
-               if (!gmt_is_set) {
-#ifdef ALL_STATE
-#ifdef NOTIFY_TZ
-                       if (gmtptr == NULL)
-#endif /* NOTIFY_TZ */
-                               gmtptr = (struct state *) malloc(sizeof *gmtptr);
-                       if (gmtptr != NULL)
-#endif /* defined ALL_STATE */
-#ifdef NOTIFY_TZ
-                       {
-                               char            fullname[FILENAME_MAX + 1];
-                               gmtload(gmtptr, fullname);
-                               notify_register_tz(fullname, &gmt_notify);
-                       }
-#else /* ! NOTIFY_TZ */
-                               gmtload(gmtptr);
-#endif /* NOTIFY_TZ */
-                       gmt_is_set = TRUE;
-               }
-               _MUTEX_UNLOCK(&gmt_mutex);
-       }
+       pthread_once(&gmt_once, gmt_init);
 #ifdef __LP64__
-       if(timesub(timep, offset, gmtptr, tmp) == NULL)
+       result = timesub(timep, offset, gmtptr, tmp);
+       if (result == NULL)
                return NULL;
 #else /* !__LP64__ */
        timesub(timep, offset, gmtptr, tmp);
@@ -1634,7 +1958,7 @@ struct tm * const tmp;
        ** but this is no time for a treasure hunt.
        */
        if (offset != 0)
-               tmp->TM_ZONE = wildabbr;
+               tmp->TM_ZONE = (char*)wildabbr;
        else {
 #ifdef ALL_STATE
                if (gmtptr == NULL)
@@ -1647,29 +1971,28 @@ struct tm * const       tmp;
        }
 #endif /* defined TM_ZONE */
 #ifdef __LP64__
-       return tmp;
+       return result;
 #endif /* __LP64__ */
 }
 
+static void
+gmtime_key_init(void)
+{
+       
+       gmtime_key = __LIBC_PTHREAD_KEY_GMTIME;
+       gmtime_key_error = pthread_key_init_np(gmtime_key, free);
+}
+
 struct tm *
-gmtime(timep)
-const time_t * const   timep;
+gmtime(const time_t *const timep)
 {
-       static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
-       static pthread_key_t gmtime_key = -1;
        struct tm *p_tm;
 
        if (__isthreaded != 0) {
-               if (gmtime_key == (pthread_key_t)-1) {
-                       _pthread_mutex_lock(&gmtime_mutex);
-                       if (gmtime_key == (pthread_key_t)-1) {
-                               gmtime_key = __LIBC_PTHREAD_KEY_GMTIME;
-                               if (pthread_key_init_np(gmtime_key, free) < 0) {
-                                       _pthread_mutex_unlock(&gmtime_mutex);
-                                       return(NULL);
-                               }
-                       }
-                       _pthread_mutex_unlock(&gmtime_mutex);
+               _pthread_once(&gmtime_once, gmtime_key_init);
+               if (gmtime_key_error != 0) {
+                       errno = gmtime_key_error;
+                       return(NULL);
                }
                /*
                 * Changed to follow POSIX.1 threads standard, which
@@ -1704,25 +2027,21 @@ const time_t * const    timep;
 */
 
 struct tm *
-gmtime_r(timep, tm)
-const time_t * const   timep;
-struct tm *            tm;
+gmtime_r(const time_t *const timep, struct tm *tmp)
 {
 
 #ifdef __LP64__
-       return gmtsub(timep, 0L, tm);
+       return gmtsub(timep, 0L, tmp);
 #else /* !__LP64__ */
-       gmtsub(timep, 0L, tm);
-       return tm;
+       gmtsub(timep, 0L, tmp);
+       return tmp;
 #endif /* __LP64__ */
 }
 
 #ifdef STD_INSPIRED
 
 struct tm *
-offtime(timep, offset)
-const time_t * const   timep;
-const long             offset;
+offtime(const time_t *const timep, const long offset)
 {
 #ifdef __LP64__
        return gmtsub(timep, offset, &tm);
@@ -1734,6 +2053,23 @@ const long               offset;
 
 #endif /* defined STD_INSPIRED */
 
+/*
+** Return the number of leap years through the end of the given year
+** where, to make the math easy, the answer for year zero is defined as zero.
+*/
+
+__unused static int
+leaps_thru_end_of(y)
+register const int     y;
+{
+#ifdef __LP64__
+       return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
+               -(leaps_thru_end_of(-(y + 1)) + 1);
+#else /* !__LP64__ */
+       return (y / 4 - y / 100 + y / 400);
+#endif /* __LP64__ */
+}
+
 #ifdef __LP64__
 static struct tm *
 #else /* !__LP64__ */
@@ -1857,13 +2193,12 @@ struct tm * const               tmp;
 }
 
 char *
-ctime(timep)
-const time_t * const   timep;
+ctime(const time_t *const timep)
 {
 /*
 ** Section 4.12.3.2 of X3.159-1989 requires that
 **     The ctime function converts the calendar time pointed to by timer
-**     to local time in the form of a string.  It is equivalent to
+**     to local time in the form of a string. It is equivalent to
 **             asctime(localtime(timer))
 */
 #ifdef __LP64__
@@ -1883,11 +2218,9 @@ const time_t * const     timep;
 }
 
 char *
-ctime_r(timep, buf)
-const time_t * const   timep;
-char *                 buf;
+ctime_r(const time_t *const timep, char *buf)
 {
-       struct tm       tm;
+       struct tm       mytm;
 
 #ifdef __LP64__
        /*
@@ -1895,11 +2228,11 @@ char *                  buf;
         * that exceeds 32-bits in size (won't fit in struct tm), so localtime_r
         * will return NULL.
         */
-       if (localtime_r(timep, &tm) == NULL)
+       if (localtime_r(timep, &mytm) == NULL)
                return NULL;
-       return asctime_r(&tm, buf);
+       return asctime_r(&mytm, buf);
 #else /* !__LP64__ */
-       return asctime_r(localtime_r(timep, &tm), buf);
+       return asctime_r(localtime_r(timep, &mytm), buf);
 #endif /* __LP64__ */
 }
 
@@ -1907,8 +2240,7 @@ char *                    buf;
 ** Adapted from code provided by Robert Elz, who writes:
 **     The "best" way to do mktime I think is based on an idea of Bob
 **     Kridle's (so its said...) from a long time ago.
-**     [kridle@xinet.com as of 1996-01-16.]
-**     It does a binary search of the time_t space.  Since time_t's are
+**     It does a binary search of the time_t space. Since time_t's are
 **     just 32 bits, its a max of 32 iterations (even at 64 bits it
 **     would still be very reasonable).
 */
@@ -1918,7 +2250,7 @@ char *                    buf;
 #endif /* !defined WRONG */
 
 /*
-** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
+** Simplified normalize logic courtesy Paul Eggert.
 */
 
 static int
@@ -1934,10 +2266,19 @@ int     delta;
 }
 
 static int
-normalize_overflow(tensptr, unitsptr, base)
-int * const    tensptr;
-int * const    unitsptr;
-const int      base;
+long_increment_overflow(number, delta)
+long * number;
+int    delta;
+{
+       long    number0;
+
+       number0 = *number;
+       *number += delta;
+       return (*number < number0) != (delta < 0);
+}
+
+static int
+normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
 {
        int     tensdelta;
 
@@ -1948,6 +2289,18 @@ const int        base;
        return increment_overflow(tensptr, tensdelta);
 }
 
+static int
+long_normalize_overflow(long *const tensptr, int *const unitsptr, const int base)
+{
+       register int    tensdelta;
+
+       tensdelta = (*unitsptr >= 0) ?
+               (*unitsptr / base) :
+               (-1 - (-1 - *unitsptr) / base);
+       *unitsptr -= tensdelta * base;
+       return long_increment_overflow(tensptr, tensdelta);
+}
+
 static int
 tmcomp(atmp, btmp)
 const struct tm * const atmp;
@@ -1971,29 +2324,28 @@ const struct tm * const btmp;
 }
 
 static time_t
-time2sub(tmp, funcp, offset, okayp, do_norm_secs, unix03)
-struct tm * const      tmp;
+time2sub(struct tm *const tmp,
 #ifdef __LP64__
-struct tm *(* const    funcp)(const time_t*, long, struct tm*);
+        struct tm *(*const funcp)(const time_t *, long, struct tm *),
 #else /* !__LP64__ */
-void (* const          funcp)(const time_t*, long, struct tm*);
+        void(*funcp) (const time_t *, long, struct tm*),
 #endif /* __LP64__ */
-const long             offset;
-int * const            okayp;
-const int              do_norm_secs;
-int                    unix03;
+        const long offset,
+        int *const okayp,
+        const int do_norm_secs,
+        int unix03)
 {
        const struct state *    sp;
        int                     dir;
-       int                     bits;
-       int                     i, j ;
+       int                     i, j;
        int                     saved_seconds;
-       time_t                          newt;
-       time_t                          t;
-       struct tm                       yourtm, mytm;
-#ifdef __LP64__
-       long                            year, il;
-#endif /* __LP64__ */
+       long                    li;
+       time_t                  lo;
+       time_t                  hi;
+       long                    y;
+       time_t                  newt;
+       time_t                  t;
+       struct tm               yourtm, mytm;
 
        *okayp = FALSE;
        yourtm = *tmp;
@@ -2006,76 +2358,49 @@ int                     unix03;
                return WRONG;
        if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
                return WRONG;
-       if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
+       y = yourtm.tm_year;
+       if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
                return WRONG;
        /*
-       ** Turn yourtm.tm_year into an actual year number for now.
+       ** Turn y into an actual year number for now.
        ** It is converted back to an offset from TM_YEAR_BASE later.
        */
-#ifdef __LP64__
-       year = (long)yourtm.tm_year + TM_YEAR_BASE;
-#else /* !__LP64__ */
-       if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
+       if (long_increment_overflow(&y, TM_YEAR_BASE))
                return WRONG;
-#endif /* __LP64__ */
        while (yourtm.tm_mday <= 0) {
-#ifdef __LP64__
-               year--;
-               il = year + (1 < yourtm.tm_mon);
-               yourtm.tm_mday += year_lengths[isleap(il)];
-#else /* !__LP64__ */
-               if (increment_overflow(&yourtm.tm_year, -1))
+               if (long_increment_overflow(&y, -1))
                        return WRONG;
-               i = yourtm.tm_year + (1 < yourtm.tm_mon);
-               yourtm.tm_mday += year_lengths[isleap(i)];
-#endif /* __LP64__ */
+               li = y + (1 < yourtm.tm_mon);
+               yourtm.tm_mday += year_lengths[isleap(li)];
        }
        while (yourtm.tm_mday > DAYSPERLYEAR) {
-#ifdef __LP64__
-               il = year + (1 < yourtm.tm_mon);
-               yourtm.tm_mday -= year_lengths[isleap(il)];
-               year++;
-#else /* !__LP64__ */
-               i = yourtm.tm_year + (1 < yourtm.tm_mon);
-               yourtm.tm_mday -= year_lengths[isleap(i)];
-               if (increment_overflow(&yourtm.tm_year, 1))
+               li = y + (1 < yourtm.tm_mon);
+               yourtm.tm_mday -= year_lengths[isleap(li)];
+               if (long_increment_overflow(&y, 1))
                        return WRONG;
-#endif /* __LP64__ */
        }
        for ( ; ; ) {
-#ifdef __LP64__
-               i = mon_lengths[isleap(year)][yourtm.tm_mon];
-#else /* !__LP64__ */
-               i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
-#endif /* __LP64__ */
+               i = mon_lengths[isleap(y)][yourtm.tm_mon];
                if (yourtm.tm_mday <= i)
                        break;
                yourtm.tm_mday -= i;
                if (++yourtm.tm_mon >= MONSPERYEAR) {
                        yourtm.tm_mon = 0;
-#ifdef __LP64__
-                       year++;
-#else /* !__LP64__ */
-                       if (increment_overflow(&yourtm.tm_year, 1))
+                       if (long_increment_overflow(&y, 1))
                                return WRONG;
-#endif /* __LP64__ */
                }
        }
-#ifdef __LP64__
-       year -= TM_YEAR_BASE;
-       if (year > INT_MAX || year < INT_MIN)
+       if (long_increment_overflow(&y, -TM_YEAR_BASE))
                return WRONG;
-       yourtm.tm_year = year;
-#else /* !__LP64__ */
-       if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
+       yourtm.tm_year = y;
+       if (yourtm.tm_year != y)
                return WRONG;
-#endif /* __LP64__ */
        /* Don't go below 1900 for POLA */
        if (yourtm.tm_year < 0)
                return WRONG;
        if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
                saved_seconds = 0;
-       else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
+       else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
                /*
                ** We can't set tm_sec to 0, because that might push the
                ** time below the minimum representable time.
@@ -2093,52 +2418,61 @@ int                     unix03;
                yourtm.tm_sec = 0;
        }
        /*
-       ** Divide the search space in half
-       ** (this works whether time_t is signed or unsigned).
-       */
-#ifdef __LP64__
-       /* optimization: see if the value is 31-bit (signed) */
-       t = (((time_t) 1) << (TYPE_BIT(int) - 1)) - 1;
-       bits = ((*funcp)(&t, offset, &mytm) == NULL || tmcomp(&mytm, &yourtm) < 0) ? TYPE_BIT(time_t) - 1 : TYPE_BIT(int) - 1;
-#else /* !__LP64__ */
-       bits = TYPE_BIT(time_t) - 1;
-#endif /* __LP64__ */
-       /*
-       ** In 64-bit, we now return an error if we cannot represent the
-       ** struct tm value in a time_t.  And tmcomp() is fixed to avoid
-       ** overflow in tm_year.  So we only put a cap on bits because time_t
-       ** can't be larger that 56 bit (when tm_year == INT_MAX).
+       ** Do a binary search (this works whatever time_t's type is).
        */
-       if (bits > 56)
-               bits = 56;
-       /*
-       ** If time_t is signed, then 0 is just above the median,
-       ** assuming two's complement arithmetic.
-       ** If time_t is unsigned, then (1 << bits) is just above the median.
-       */
-       t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
+       if (!TYPE_SIGNED(time_t)) {
+               lo = 0;
+               hi = lo - 1;
+       } else if (!TYPE_INTEGRAL(time_t)) {
+               if (sizeof(time_t) > sizeof(float))
+                       hi = (time_t) DBL_MAX;
+               else    hi = (time_t) FLT_MAX;
+               lo = -hi;
+       } else {
+               lo = 1;
+               for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
+                       lo *= 2;
+               hi = -(lo + 1);
+       }
        for ( ; ; ) {
+               t = lo / 2 + hi / 2;
+               if (t < lo)
+                       t = lo;
+               else if (t > hi)
+                       t = hi;
 #ifdef __LP64__
                if ((*funcp)(&t, offset, &mytm) == NULL) {
-                   /* we overflowed, so t is too big */
-                   dir = 1;
-                   goto skip_tmcomp;
-               }
+                       /*
+                       ** Assume that t is too extreme to be represented in
+                       ** a struct tm; arrange things so that it is less
+                       ** extreme on the next pass.
+                       */
+                       dir = (t > 0) ? 1 : -1;
+               } else  dir = tmcomp(&mytm, &yourtm);
 #else /* !__LP64__ */
                (*funcp)(&t, offset, &mytm);
-#endif /* __LP64__ */
                dir = tmcomp(&mytm, &yourtm);
-#ifdef __LP64__
-skip_tmcomp:
+               // If we have searched the entire space without a match, exit
+               if (dir != 0 && t == lo && t == hi)
+                       return WRONG;
 #endif /* __LP64__ */
                if (dir != 0) {
-                       if (bits-- < 0)
+                       if (t == lo) {
+                               ++t;
+                               if (t <= lo)
+                                       return WRONG;
+                               ++lo;
+                       } else if (t == hi) {
+                               --t;
+                               if (t >= hi)
+                                       return WRONG;
+                               --hi;
+                       }
+                       if (lo > hi)
                                return WRONG;
-                       if (bits < 0)
-                               --t; /* may be needed if new t is minimal */
-                       else if (dir > 0)
-                               t -= ((time_t) 1) << bits;
-                       else    t += ((time_t) 1) << bits;
+                       if (dir > 0)
+                               hi = t;
+                       else    lo = t;
                        continue;
                }
                sp = (funcp == localsub) ? lclptr : gmtptr;
@@ -2166,7 +2500,7 @@ skip_tmcomp:
                                        sp->ttis[i].tt_gmtoff;
 #ifdef __LP64__
                                if ((*funcp)(&newt, offset, &mytm) == NULL)
-                                       return WRONG;
+                                       continue;
 #else /* !__LP64__ */
                                (*funcp)(&newt, offset, &mytm);
 #endif /* __LP64__ */
@@ -2194,21 +2528,20 @@ label:
 #else /* !__LP64__ */
        (*funcp)(&t, offset, tmp);
 #endif /* __LP64__ */
-       *okayp = TRUE;
+               *okayp = TRUE;
        return t;
 }
 
 static time_t
-time2(tmp, funcp, offset, okayp, unix03)
-struct tm * const      tmp;
+time2(struct tm * const        tmp,
 #ifdef __LP64__
-struct tm *(* const    funcp)(const time_t*, long, struct tm*);
+      struct tm * (*const funcp)(const time_t *, long, struct tm *),
 #else /* !__LP64__ */
-void (* const          funcp)(const time_t*, long, struct tm*);
+      void (*const funcp)(const time_t *, long, struct tm *),
 #endif /* __LP64__ */
-const long             offset;
-int * const            okayp;
-int                    unix03;
+      const long offset,
+      int *const okayp,
+      int unix03)
 {
        time_t  t;
 
@@ -2225,9 +2558,9 @@ __private_extern__ time_t
 time1(tmp, funcp, offset, unix03)
 struct tm * const      tmp;
 #ifdef __LP64__
-struct tm *(* const    funcp)(const time_t *, long, struct tm *);
+struct tm * (* const  funcp)(const time_t *, long, struct tm *);
 #else /* !__LP64__ */
-void (* const          funcp)(const time_t *, long, struct tm *);
+void (* const  funcp)(const time_t *, long, struct tm *);
 #endif /* __LP64__ */
 const long             offset;
 int                    unix03;
@@ -2242,12 +2575,17 @@ int                     unix03;
        int                             types[TZ_MAX_TYPES];
        int                             okay;
 
+       if (tmp == NULL) {
+               errno = EINVAL;
+               return WRONG;
+       }
+
        if (tmp->tm_isdst > 1)
                tmp->tm_isdst = 1;
        t = time2(tmp, funcp, offset, &okay, unix03);
 #ifdef PCTS
        /*
-       ** PCTS code courtesy Grant Sullivan (grant@osf.org).
+       ** PCTS code courtesy Grant Sullivan.
        */
        if (okay)
                return t;
@@ -2264,7 +2602,7 @@ int                       unix03;
        ** We try to divine the type they started from and adjust to the
        ** type they need.
        */
-       sp = (funcp == localsub) ? lclptr : gmtptr;
+       sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
 #ifdef ALL_STATE
        if (sp == NULL)
                return WRONG;
@@ -2299,12 +2637,11 @@ int                     unix03;
        return WRONG;
 }
 #else  /* BUILDING_VARIANT */
-__private_extern__ pthread_rwlock_t    lcl_rwlock;
+extern pthread_rwlock_t        lcl_rwlock;
 #endif /* BUILDING_VARIANT */
 
 time_t
-mktime(tmp)
-struct tm * const      tmp;
+mktime(struct tm *const tmp)
 {
        time_t mktime_return_value;
        int serrno = errno;
@@ -2320,27 +2657,26 @@ struct tm * const       tmp;
 #ifdef STD_INSPIRED
 
 time_t
-timelocal(tmp)
-struct tm * const      tmp;
+timelocal(struct tm *const tmp)
 {
-       tmp->tm_isdst = -1;     /* in case it wasn't initialized */
+       if (tmp != NULL)
+               tmp->tm_isdst = -1;     /* in case it wasn't initialized */
        return mktime(tmp);
 }
 
 time_t
-timegm(tmp)
-struct tm * const      tmp;
+timegm(struct tm *const tmp)
 {
-       tmp->tm_isdst = 0;
+       if (tmp != NULL)
+               tmp->tm_isdst = 0;
        return time1(tmp, gmtsub, 0L, __DARWIN_UNIX03);
 }
 
 time_t
-timeoff(tmp, offset)
-struct tm * const      tmp;
-const long             offset;
+timeoff(struct tm *const tmp, const long offset)
 {
-       tmp->tm_isdst = 0;
+       if (tmp != NULL)
+               tmp->tm_isdst = 0;
        return time1(tmp, gmtsub, offset, __DARWIN_UNIX03);
 }
 
@@ -2354,8 +2690,7 @@ const long                offset;
 */
 
 long
-gtime(tmp)
-struct tm * const      tmp;
+gtime(struct tm *const tmp)
 {
        const time_t    t = mktime(tmp);
 
@@ -2381,8 +2716,7 @@ struct tm * const tmp;
 */
 
 static long
-leapcorr(timep)
-time_t *       timep;
+leapcorr(time_t *timep)
 {
        struct state *          sp;
        struct lsinfo * lp;
@@ -2399,16 +2733,14 @@ time_t *        timep;
 }
 
 time_t
-time2posix(t)
-time_t t;
+time2posix(time_t t)
 {
        tzset();
        return t - leapcorr(&t);
 }
 
 time_t
-posix2time(t)
-time_t t;
+posix2time(time_t t)
 {
        time_t  x;
        time_t  y;
@@ -2416,7 +2748,7 @@ time_t    t;
        tzset();
        /*
        ** For a positive leap second hit, the result
-       ** is not unique.  For a negative leap second
+       ** is not unique. For a negative leap second
        ** hit, the corresponding time doesn't exist,
        ** so we return an adjacent second.
        */
index d1d821eb313fc68fc8bb1cca4e815845e85318c2..3a54608cc43ab3cda9bf02fa40f7f6e205c49be2 100644 (file)
@@ -6,7 +6,7 @@
 ** This file is in the public domain, so clarified as of
 ** 1996-06-05 by Arthur David Olson.
 **
-** $FreeBSD: src/lib/libc/stdtime/private.h,v 1.11 2009/05/23 06:31:50 edwin Exp $
+** $FreeBSD: head/contrib/tzcode/stdtime/private.h 289027 2015-10-08 11:42:15Z rodrigc $
 */
 
 /* Stuff moved from Makefile.inc to reduce clutter */
@@ -173,6 +173,12 @@ typedef long               int_fast64_t;
 #define INT32_MIN (-1 - INT32_MAX)
 #endif /* !defined INT32_MIN */
 
+#if 2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)
+# define ATTRIBUTE_PURE __attribute__ ((__pure__))
+#else
+# define ATTRIBUTE_PURE /* empty */
+#endif
+
 /*
 ** Workarounds for compilers/systems.
 */
@@ -191,13 +197,8 @@ extern char *      asctime_r(struct tm const *, char *);
 ** Private function declarations.
 */
 
-char *         icalloc(int nelem, int elsize);
 char *         icatalloc(char * old, const char * new);
 char *         icpyalloc(const char * string);
-char *         imalloc(int n);
-void *         irealloc(void * pointer, int size);
-void           icfree(char * pointer);
-void           ifree(char * pointer);
 const char *   scheck(const char * string, const char * format);
 
 /*
index 8acb0a415f512991d0a5738456b3e9fcc2d9cb1a..ccf1d077670a509a371348328a181e4e0ec836c0 100644 (file)
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#ifndef lint
-#ifndef NOID
+#if 0
 static const char      elsieid[] = "@(#)strftime.3     8.3";
 /*
 ** Based on the UCB version with the ID appearing below.
 ** This is ANSIish only when "multibyte character == plain character".
 */
-#endif /* !defined NOID */
-#endif /* !defined lint */
+#endif
 
 #include "xlocale_private.h"
 
@@ -53,7 +51,7 @@ __private_extern__ char *     _fmt(const char *, const struct tm *, char *, const ch
                        int *, struct lc_time_T *, locale_t);
 
 extern char *  tzname[];
-__private_extern__ long __darwin_altzone;              /* DST timezone offset */
+extern long __darwin_altzone;          /* DST timezone offset */
 #define altzone __darwin_altzone
 __private_extern__ long _st_get_timezone(void);
 
index 2220c5dac2626479f3d2869f50360c1b2d6cd62d..d237bdd61c4a3a8989226e7e2cc6b4a08953ef3e 100644 (file)
@@ -319,10 +319,11 @@ label:
                         * XXX This is bogus if parsed before hour-related
                         * specifiers.
                         */
+                       if (tm->tm_hour > 12)
+                               return (NULL);
+
                        len = strlen(tptr->am);
                        if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {
-                               if (tm->tm_hour > 12)
-                                       return (NULL);
                                if (tm->tm_hour == 12)
                                        tm->tm_hour = 0;
                                buf += len;
@@ -331,8 +332,6 @@ label:
 
                        len = strlen(tptr->pm);
                        if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {
-                               if (tm->tm_hour > 12)
-                                       return (NULL);
                                if (tm->tm_hour != 12)
                                        tm->tm_hour += 12;
                                buf += len;
@@ -391,12 +390,11 @@ label:
                                return (NULL);
 
                        i = *buf - '0';
-                       if (i > 6 + (c == 'u'))
+                       if (i < 0 || i > 7 || (c == 'u' && i < 1) ||
+                           (c == 'w' && i > 6))
                                return (NULL);
-                       if (i == 7)
-                               i = 0;
 
-                       tm->tm_wday = i;
+                       tm->tm_wday = i % 7;
                        flags |= FLAG_WDAY;
                        buf++;
 
@@ -698,35 +696,46 @@ label:
                            TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1);
                        flags |= FLAG_YDAY;
                } else if (flags & FLAG_WEEK){
+                       int day_offset = week_kind == WEEK_U ? TM_SUNDAY : TM_MONDAY;
+                       int fwo = first_wday_of(tm->tm_year + TM_YEAR_BASE);
+
+                       /* No incomplete week (week 0). */
+                       if (week_number == 0 && fwo == day_offset)
+                               return (NULL);
+
                        if (!(flags & FLAG_WDAY)) {
-                               tm->tm_wday = week_kind == WEEK_U ? TM_SUNDAY : TM_MONDAY;
+                               /*
+                                * Set the date to the first Sunday (or Monday)
+                                * of the specified week of the year.
+                                */
+                               tm->tm_wday = day_offset;
                                flags |= FLAG_WDAY;
                        }
 
-                       struct tm t = {0};
-                       t.tm_mday = week_kind == WEEK_V ? 4 : 1;
-                       t.tm_hour = 12; /* avoid any DST effects */
-                       t.tm_year = tm->tm_year;
-                       if (timegm(&t) == (time_t)-1) return 0;
-
-                       int off = t.tm_wday;
-                       int wday = tm->tm_wday;
+                       /*
+                        * Start our yday at the first day of the relevant week type.
+                        */
+                       int tmpyday = (7 - fwo + day_offset) % 7;
 
-                       if (week_kind != WEEK_U) {
-                               off = (off + 6) % 7;
-                               wday = (wday + 6) % 7;
+                       /*
+                        * ISO Weeks start counting from the first week with at least
+                        * four days.  If our first week had that, subtract off a week.
+                        */
+                       if (week_kind == WEEK_V && fwo > TM_MONDAY && fwo <= TM_THURSDAY) {
+                               tmpyday -= 7;
                        }
-
-                       if (week_kind == WEEK_V) {
-                               t.tm_mday = 7 * week_number + wday - off - 3;
-                       } else {
-                               if(off == 0) off = 7;
-                               t.tm_mday = 7 * week_number + wday - off + 1;
+                       /* Advance the relevant number of weeks */
+                       tmpyday += (week_number - 1) * 7;
+                       /* And go to the right day of week */
+                       tmpyday += (tm->tm_wday - day_offset + 7) % 7;
+
+                       /* Impossible yday for incomplete week (week 0). */
+                       if (tmpyday < 0) {
+                               if (flags & FLAG_WDAY)
+                                       return (NULL);
+                               tmpyday = 0;
                        }
-                       if (timegm(&t) == (time_t)-1) return 0;
-
-                       tm->tm_yday = t.tm_yday;
-
+                       tm->tm_yday = tmpyday;
                        flags |= FLAG_YDAY;
                }
        }
@@ -755,13 +764,8 @@ label:
                        flags |= FLAG_MDAY;
                }
                if (!(flags & FLAG_WDAY)) {
-                       i = 0;
-                       wday_offset = first_wday_of(tm->tm_year);
-                       while (i++ <= tm->tm_yday) {
-                               if (wday_offset++ >= 6)
-                                       wday_offset = 0;
-                       }
-                       tm->tm_wday = wday_offset;
+                       wday_offset = first_wday_of(tm->tm_year + TM_YEAR_BASE);
+                       tm->tm_wday = (wday_offset + tm->tm_yday) % 7;
                        flags |= FLAG_WDAY;
                }
        }
index 6dcbc27490368f34acc26f943ed1eac3f7025d33..60187eb43fd657e03aaf72c1b7c907163475fca2 100644 (file)
@@ -1,4 +1,4 @@
-.\" $FreeBSD: src/lib/libc/stdtime/tzfile.5,v 1.10 2001/07/10 13:41:23 ru Exp $
+.\" $FreeBSD: head/contrib/tzcode/stdtime/tzfile.5 259446 2013-12-16 01:58:12Z bjk $
 .Dd September 13, 1994
 .Dt TZFILE 5
 .Os
@@ -14,7 +14,9 @@ begin with the magic characters
 .Dq Li TZif
 to identify them as
 time zone information files,
-followed by sixteen bytes reserved for future use,
+followed by a character identifying the version of the file's format
+(as of 2005, either an ASCII NUL or a '2')
+followed by fifteen bytes containing zeroes reserved for future use,
 followed by four four-byte values
 written in a ``standard'' byte order
 (the high-order byte of the value is written first).
@@ -56,7 +58,9 @@ each one tells which of the different types of ``local time'' types
 described in the file is associated with the same-indexed transition time.
 These values serve as indices into an array of
 .Fa ttinfo
-structures that appears next in the file;
+structures (with
+.Fa tzh_typecnt
+entries) that appears next in the file;
 these structures are defined as follows:
 .Pp
 .Bd -literal -offset indent
@@ -129,10 +133,20 @@ if either
 .Li tzh_timecnt
 is zero or the time argument is less than the first transition time recorded
 in the file.
+.Pp
+For version-2-format time zone files,
+the above header and data is followed by a second header and data,
+identical in format except that eight bytes are used for each
+transition time or leap second time.
+After the second header and data comes a newline-enclosed,
+POSIX-TZ-environment-variable-style string for use in handling instants
+after the last transition time stored in the file
+(with nothing between the newlines if there is no POSIX representation for
+such instants).
 .Sh SEE ALSO
 .Xr ctime 3 ,
 .Xr time2posix 3 ,
 .Xr zic 8
-.\" @(#)tzfile.5       7.2
+.\" @(#)tzfile.5       8.3
 .\" This file is in the public domain, so clarified as of
-.\" 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+.\" 1996-06-05 by Arthur David Olson.
index aff38e7fd7540633c9549615798c2fa4317eb278..11281331e2652e757bcfb8ad36306efd4c80877f 100644 (file)
@@ -4,9 +4,9 @@
 
 /*
 ** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+** 1996-06-05 by Arthur David Olson.
 **
-** $FreeBSD: src/lib/libc/stdtime/tzfile.h,v 1.8 2002/03/22 23:42:05 obrien Exp $
+** $FreeBSD: head/contrib/tzcode/stdtime/tzfile.h 192625 2009-05-23 06:31:50Z edwin $
 */
 
 /*
@@ -24,7 +24,7 @@
 #ifndef lint
 #ifndef NOID
 /*
-static char    tzfilehid[] = "@(#)tzfile.h     7.14";
+static char    tzfilehid[] = "@(#)tzfile.h     8.1";
 */
 #endif /* !defined NOID */
 #endif /* !defined lint */
@@ -33,21 +33,29 @@ static char tzfilehid[] = "@(#)tzfile.h     7.14";
 ** Information about time zone files.
 */
 
-#ifndef TZDIR
-#ifdef UNIFDEF_TZDIR_SYMLINK
-#define TZDIR  "/var/db/timezone/zoneinfo" /* Time zone object file directory */
-#else /* !UNIFDEF_TZDIR_SYMLINK */
-#define TZDIR  "/usr/share/zoneinfo" /* Time zone object file directory */
-#endif /* UNIFDEF_TZDIR_SYMLINK */
-#endif /* !defined TZDIR */
+#include <TargetConditionals.h>
+#include <Availability.h>
 
+/* Time zone object file directory */
+#ifndef TZDIR
+# if TARGET_OS_SIMULATOR || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_13)
+#  define TZDIR   "/usr/share/zoneinfo"
+# else
+#  define TZDIR   "/var/db/timezone/zoneinfo"
+# endif
+#endif
+
+/* No gurantee is made that the TZDEFAULT symlink will have TZDIR as a prefix.
+ * However, clients can assume that the final path component of the prefix will
+ * be "zoneinfo"
+ */
 #ifndef TZDEFAULT
-#ifdef UNIFDEF_MOVE_LOCALTIME
-#define TZDEFAULT      "/var/db/timezone/localtime"
-#else /* !UNIFDEF_MOVE_LOCALTIME */
-#define TZDEFAULT      "/etc/localtime"
-#endif /* UNIFDEF_MOVE_LOCALTIME */
-#endif /* !defined TZDEFAULT */
+# if TARGET_OS_SIMULATOR || TARGET_OS_OSX
+#  define TZDEFAULT       "/etc/localtime"
+# else
+#  define TZDEFAULT       "/var/db/timezone/localtime"
+# endif
+#endif
 
 #ifndef TZDEFRULES
 #define TZDEFRULES     "posixrules"
@@ -60,8 +68,9 @@ static char   tzfilehid[] = "@(#)tzfile.h     7.14";
 #define        TZ_MAGIC        "TZif"
 
 struct tzhead {
-       char    tzh_magic[4];           /* TZ_MAGIC */
-       char    tzh_reserved[16];       /* reserved for future use */
+       char    tzh_magic[4];           /* TZ_MAGIC */
+       char    tzh_version[1];         /* '\0' or '2' as of 2005 */
+       char    tzh_reserved[15];       /* reserved--must be zero */
        char    tzh_ttisgmtcnt[4];      /* coded number of trans. time flags */
        char    tzh_ttisstdcnt[4];      /* coded number of trans. time flags */
        char    tzh_leapcnt[4];         /* coded number of leap seconds */
@@ -95,19 +104,23 @@ struct tzhead {
 **                                     assumed to be local time
 */
 
+/*
+** If tzh_version is '2' or greater, the above is followed by a second instance
+** of tzhead and a second instance of the data in which each coded transition
+** time uses 8 rather than 4 chars,
+** then a POSIX-TZ-environment-variable-style string for use in handling
+** instants after the last transition time stored in the file
+** (with nothing between the newlines if there is no POSIX representation for
+** such instants).
+*/
+
 /*
 ** In the current implementation, "tzset()" refuses to deal with files that
 ** exceed any of the limits below.
 */
 
 #ifndef TZ_MAX_TIMES
-/*
-** The TZ_MAX_TIMES value below is enough to handle a bit more than a
-** year's worth of solar time (corrected daily to the nearest second) or
-** 138 years of Pacific Presidential Election time
-** (where there are three time zone transitions every fourth year).
-*/
-#define TZ_MAX_TIMES   370
+#define TZ_MAX_TIMES   1200
 #endif /* !defined TZ_MAX_TIMES */
 
 #ifndef TZ_MAX_TYPES
@@ -117,7 +130,7 @@ struct tzhead {
 #ifdef NOSOLAR
 /*
 ** Must be at least 14 for Europe/Riga as of Jan 12 1995,
-** as noted by Earl Chew <earl@hpato.aus.hp.com>.
+** as noted by Earl Chew.
 */
 #define TZ_MAX_TYPES   20      /* Maximum number of local time types */
 #endif /* !defined NOSOLAR */
@@ -168,11 +181,6 @@ struct tzhead {
 #define EPOCH_YEAR     1970
 #define EPOCH_WDAY     TM_THURSDAY
 
-/*
-** Accurate only for the past couple of centuries;
-** that will probably do.
-*/
-
 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
 
 /*
@@ -189,26 +197,4 @@ struct tzhead {
 
 #define isleap_sum(a, b)       isleap((a) % 400 + (b) % 400)
 
-#ifndef USG
-
-/*
-** Use of the underscored variants may cause problems if you move your code to
-** certain System-V-based systems; for maximum portability, use the
-** underscore-free variants.  The underscored variants are provided for
-** backward compatibility only; they may disappear from future versions of
-** this file.
-*/
-
-#define SECS_PER_MIN   SECSPERMIN
-#define MINS_PER_HOUR  MINSPERHOUR
-#define HOURS_PER_DAY  HOURSPERDAY
-#define DAYS_PER_WEEK  DAYSPERWEEK
-#define DAYS_PER_NYEAR DAYSPERNYEAR
-#define DAYS_PER_LYEAR DAYSPERLYEAR
-#define SECS_PER_HOUR  SECSPERHOUR
-#define SECS_PER_DAY   SECSPERDAY
-#define MONS_PER_YEAR  MONSPERYEAR
-
-#endif /* !defined USG */
-
 #endif /* !defined TZFILE_H */
diff --git a/stdtime/timegm.3 b/stdtime/timegm.3
deleted file mode 100644 (file)
index e5f3fbc..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-.\" Copyright (C) 2001 Andries Brouwer <aeb@cwi.nl>
-.\"
-.\" Permission is granted to make and distribute verbatim copies of this
-.\" manual provided the copyright notice and this permission notice are
-.\" preserved on all copies.
-.\"
-.\" Permission is granted to copy and distribute modified versions of this
-.\" manual under the conditions for verbatim copying, provided that the
-.\" entire resulting derived work is distributed under the terms of a
-.\" permission notice identical to this one
-.\" 
-.\" Since the Linux kernel and libraries are constantly changing, this
-.\" manual page may be incorrect or out-of-date.  The author(s) assume no
-.\" responsibility for errors or omissions, or for damages resulting from
-.\" the use of the information contained herein.  The author(s) may not
-.\" have taken the same level of care in the production of this manual,
-.\" which is licensed free of charge, as they might when working
-.\" professionally.
-.\" 
-.\" Formatted or processed versions of this manual, if unaccompanied by
-.\" the source, must acknowledge the copyright and authors of this work.
-.\"
-.TH TIMEGM 3 2001-12-26 "GNU" "Linux Programmer's Manual"
-.SH NAME
-timegm, timelocal \- inverses for gmtime and localtime
-.SH SYNOPSIS
-.nf
-.B #include <time.h>
-.sp
-.BI "time_t timelocal (struct tm *" tm );
-.sp
-.BI "time_t timegm (struct tm *" tm );
-.SH DESCRIPTION
-The functions
-.B timelocal()
-and
-.B timegm()
-are the inverses to
-.BR localtime (3)
-and
-.BR gmtime (3).
-.SH NOTES
-These functions are GNU extensions.
-The
-.B timelocal()
-function is equivalent to the POSIX standard function
-.BR mktime (3).
-There is no reason to ever use it.
-.LP
-For a portable version of
-.BR timegm() ,
-set the
-.B TZ
-environment variable to UTC, call
-.B mktime()
-and restore the value of
-.BR TZ .
-Something like
-
-.RS
-.nf
-#include <time.h>
-#include <stdlib.h>
-
-time_t my_timegm (struct tm *tm) {
-    time_t ret;
-    char *tz;
-
-    tz = getenv("TZ");
-    setenv("TZ", "", 1);
-    tzset();
-    ret = mktime(tm);
-    if (tz)
-        setenv("TZ", tz, 1);
-    else
-        unsetenv("TZ");
-    tzset();
-    return ret;
-}
-.fi
-.RE
-.SH "SEE ALSO"
-.BR gmtime (3),
-.BR localtime (3),
-.BR mktime (3),
-.BR tzset (3)
index 46144e36ba583e5df72736082e3f3324f36cf606..968943414e99f750202fd2fe7e14ec6dae1e1e6c 100644 (file)
@@ -53,7 +53,6 @@ __FBSDID("$FreeBSD: src/lib/libc/string/strerror.c,v 1.16 2007/01/09 00:28:12 im
  */
 #define        EBUFSIZE        (20 + 2 + sizeof(UPREFIX))
 
-#ifndef BUILDING_VARIANT
 /*
  * Doing this by hand instead of linking with stdio(3) avoids bloat for
  * statically linked binaries.
@@ -117,31 +116,26 @@ strerror_r(int errnum, char *strerrbuf, size_t buflen)
        return (retval);
 }
 
-__private_extern__ char *__strerror_ebuf = NULL;
-#else /* BUILDING_VARIANT */
-__private_extern__ void __errstr(int, char *, size_t);
-
-extern char *__strerror_ebuf;
-#endif /* !BUILDING_VARIANT */
+static char *__strerror_ebuf = NULL;
 
 char *
 strerror(int num)
 {
-       // Dynamically allocate a big buffer to receive the text then shrink it
-       // down to the actual size needed.
-       size_t ebufsiz = NL_TEXTMAX;
+#if !defined(NLS)
+       if (num >= 0 && num < sys_nerr) {
+               return (char*)sys_errlist[num];
+       }
+#endif
 
        if (__strerror_ebuf == NULL) {
-               __strerror_ebuf = calloc(1, ebufsiz);
+               __strerror_ebuf = calloc(1, NL_TEXTMAX);
                if (__strerror_ebuf == NULL) {
                        return NULL;
                }
        }
-       
-       if (strerror_r(num, __strerror_ebuf, ebufsiz) != 0) {
-#if !__DARWIN_UNIX03
+
+       if (strerror_r(num, __strerror_ebuf, NL_TEXTMAX) != 0) {
                errno = EINVAL;
-#endif
        }
        return __strerror_ebuf;
 }
index 3cf8bc203f0d8b518d650e2b0ed220fbcada0c8e..30a758840ce782be466b11a1bbb007bed762d5f1 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: strlcpy.3,v 1.19 2007/05/31 19:19:32 jmc Exp $
+.\"    $OpenBSD: strlcpy.3,v 1.26 2013/09/30 12:02:35 millert Exp $
 .\"
 .\" Copyright (c) 1998, 2000 Todd C. Miller <Todd.Miller@courtesan.com>
 .\"
@@ -25,9 +25,9 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libc/string/strlcpy.3,v 1.16 2009/04/07 13:42:53 trasz Exp $
+.\" $FreeBSD$
 .\"
-.Dd June 22, 1998
+.Dd February 26, 2016
 .Dt STRLCPY 3
 .Os
 .Sh NAME
 .Sh SYNOPSIS
 .In string.h
 .Ft size_t
-.Fn strlcpy "char * restrict dst" "const char * restrict src" "size_t size"
+.Fn strlcpy "char * restrict dst" "const char * restrict src" "size_t dstsize"
 .Ft size_t
-.Fn strlcat "char * restrict dst" "const char * restrict src" "size_t size"
+.Fn strlcat "char * restrict dst" "const char * restrict src" "size_t dstsize"
 .Sh DESCRIPTION
 The
 .Fn strlcpy
 and
 .Fn strlcat
-functions copy and concatenate strings respectively.
-They are designed
-to be safer, more consistent, and less error prone replacements for
+functions copy and concatenate strings with the
+same input parameters and output result as
+.Xr snprintf 3 .
+They are designed to be safer, more consistent, and less error
+prone replacements for the easily misused functions
 .Xr strncpy 3
 and
 .Xr strncat 3 .
-Unlike those functions,
-.Fn strlcpy
-and
-.Fn strlcat
-take the full size of the buffer (not just the length) and guarantee to
-NUL-terminate the result (as long as
-.Fa size
-is larger than 0 or, in the case of
-.Fn strlcat ,
-as long as there is at least one byte free in
-.Fa dst ) .
-Note that a byte for the NUL should be included in
-.Fa size .
-Also note that
+.Pp
 .Fn strlcpy
 and
 .Fn strlcat
-only operate on true
-.Dq C
-strings.
-This means that for
-.Fn strlcpy
-.Fa src
-must be NUL-terminated and for
-.Fn strlcat
-both
-.Fa src
-and
-.Fa dst
-must be NUL-terminated.
+take the full size of the destination buffer and guarantee
+NUL-termination if there is room.
+Note that room for the NUL should be included in
+.Fa dstsize .
 .Pp
-The
 .Fn strlcpy
-function copies up to
-.Fa size
-- 1 characters from the NUL-terminated string
+copies up to
+.Fa dstsize
+\- 1 characters from the string
 .Fa src
 to
 .Fa dst ,
-NUL-terminating the result.
+NUL-terminating the result if
+.Fa dstsize
+is not 0.
 .Pp
-The
 .Fn strlcat
-function appends the NUL-terminated string
+appends string
 .Fa src
 to the end of
 .Fa dst .
 It will append at most
-.Fa size
-- strlen(dst) - 1 bytes, NUL-terminating the result.
+.Fa dstsize
+\- strlen(dst) \- 1 characters.
+It will then NUL-terminate, unless
+.Fa dstsize
+is 0 or the original
+.Fa dst
+string was longer than
+.Fa dstsize
+(in practice this should not happen
+as it means that either
+.Fa dstsize
+is incorrect or that
+.Fa dst
+is not a proper string).
 .Pp
-The source and destination strings should not overlap, as the
-behavior is undefined.
+If the
+.Fa src
+and
+.Fa dst
+strings overlap, the behavior is undefined.
 .Sh RETURN VALUES
-The
+Besides quibbles over the return type
+.Pf ( Va size_t
+versus
+.Va int )
+and signal handler safety
+.Pf ( Xr snprintf 3
+is not entirely safe on some systems), the
+following two are equivalent:
+.Bd -literal -offset indent
+n = strlcpy(dst, src, len);
+n = snprintf(dst, len, "%s", src);
+.Ed
+.Pp
+Like
+.Xr snprintf 3 ,
+the
 .Fn strlcpy
 and
 .Fn strlcat
-functions return the total length of the string they tried to
-create.
+functions return the total length of the string they tried to create.
 For
 .Fn strlcpy
 that means the length of
@@ -124,29 +133,12 @@ that means the initial length of
 plus
 the length of
 .Fa src .
-While this may seem somewhat confusing, it was done to make
-truncation detection simple.
 .Pp
-Note however, that if
-.Fn strlcat
-traverses
-.Fa size
-characters without finding a NUL, the length of the string is considered
-to be
-.Fa size
-and the destination string will not be NUL-terminated (since there was
-no space for the NUL).
-This keeps
-.Fn strlcat
-from running off the end of a string.
-In practice this should not happen (as it means that either
-.Fa size
-is incorrect or that
-.Fa dst
-is not a proper
-.Dq C
-string).
-The check exists to prevent potential security problems in incorrect code.
+If the return value is
+.Cm >=
+.Va dstsize ,
+the output string has been truncated.
+It is the caller's responsibility to handle this.
 .Sh EXAMPLES
 The following code fragment illustrates the simple case:
 .Bd -literal -offset indent
@@ -172,7 +164,7 @@ if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
 .Ed
 .Pp
 Since it is known how many characters were copied the first time, things
-can be sped up a bit by using a copy instead of an append
+can be sped up a bit by using a copy instead of an append:
 .Bd -literal -offset indent
 char *dir, *file, pname[MAXPATHLEN];
 size_t n;
@@ -204,5 +196,5 @@ and
 .Fn strlcat
 functions first appeared in
 .Ox 2.4 ,
-and made their appearance in
+and
 .Fx 3.3 .
index 9b1f662c79b807c276943e7032516004cd96cfbd..3c25e7e11ab451bf03751c57d9eb05af1784118d 100644 (file)
@@ -52,7 +52,7 @@ into each of the first
 bytes of the memory buffer whose starting address is given by
 .Fa s .
 .Pp
-It is a runtime-consrtaints violation if
+It is a runtime-constraints violation if
 .Fa s
 is a null pointer,
 or if either of
index a78524ff1c0cfd865128735a2a3776a1bd310d42..982e2db00839dbad7badab975d82ec48f5039bd2 100644 (file)
@@ -33,7 +33,7 @@
         static type * var ## _pointer = 0
 #define DECLARE_PROGNAME(var, type)                            \
         static type * var ## _pointer = 0;                     \
-        static type _priv_ ## var = 0
+        __unused static type _priv_ ## var = 0
 #define USE_VAR(var) (var ## _pointer)
 #else
 #define DECLARE_VAR(var, type) extern type var
index 56d9312675909dce8811132af14d6405d55e19cd..95a8da3cdeefff7aa0b5a09d6aa5c8529ded885c 100644 (file)
@@ -47,9 +47,9 @@ int gettimeofday (struct timeval *tp, void *vtzp)
        struct timeval atv;
 
        if (tp == NULL) {
-           if (tzp == NULL)
-               return  (0);
-           tp = &atv;
+               if (tzp == NULL)
+                       return  (0);
+               tp = &atv;
        }
 
        if (__commpage_gettimeofday(tp)) {              /* first try commpage */
index 9ebd7a127e8cf09dfef3d95e959faa3362dee069..3eb4766834ba457eb2b40ec35d2b0d2332630528 100644 (file)
@@ -24,6 +24,9 @@
 #include <sys/time.h>
 #include <notify.h>
 #include <notify_keys.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "_simple.h"
 
 #ifndef kNotifyClockSet
 #define kNotifyClockSet "com.apple.system.clock_set"
@@ -40,5 +43,10 @@ settimeofday(const struct timeval *tp, const struct timezone *tzp)
        int ret = __settimeofday(tp, tzp);
        if (ret == 0) notify_post(kNotifyClockSet);
 
+       char *msg = NULL;
+       asprintf(&msg, "settimeofday({%#lx,%#x}) == %d", tp->tv_sec, tp->tv_usec, ret);
+       _simple_asl_log(ASL_LEVEL_NOTICE, "com.apple.settimeofday", msg);
+       free(msg);
+
        return ret;
 }
index 4165350090588269ff26931df5fd9ae48d80dfbc..2b2f5be6be36986f5f75446aa5259ae451142e56 100644 (file)
@@ -7,12 +7,34 @@ endif
 
 include $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.common
 
-OTHER_CFLAGS := -DDARWINTEST -Weverything -Wno-vla -Wno-missing-field-initializers -Wno-padded -Wno-gnu-flexible-array-initializer --std=gnu11 -Wno-gnu-empty-initializer
+ifeq ($(PLATFORM),BridgeOS)
+EXCLUDED_SOURCES += locale.c
+endif
+
+WARNING_CFLAGS := -Weverything \
+       -Wno-vla -Wno-missing-field-initializers -Wno-padded \
+       -Wno-gnu-flexible-array-initializer -Wno-gnu-empty-initializer \
+       -Wno-partial-availability -Wno-used-but-marked-unused \
+       -Wno-reserved-id-macro -fmacro-backtrace-limit=0 \
+       -Wno-c++98-compat
+OTHER_CFLAGS := -DDARWINTEST --std=gnu11 $(WARNING_CFLAGS)
 OTHER_LDFLAGS := -ldarwintest_utils
+ASAN_DYLIB_PATH := /usr/local/lib/sanitizers/
 
 nxheap: OTHER_CFLAGS += -Wno-cast-align
 strlcat: OTHER_CFLAGS += -Wno-pointer-arith
 psort: OTHER_CFLAGS += -Wno-cast-qual -Wno-sign-conversion
 net: OTHER_CFLAGS += -Wno-sign-conversion -Wno-cast-align -Wno-incompatible-pointer-types-discards-qualifiers -Wno-sign-compare
+printf: OTHER_CFLAGS += -Wno-format-nonliteral
+strlcpy: OTHER_CFLAGS += -D_FORTIFY_SOURCE=0
+realpath_edge: OTHER_CFLAGS += -fsanitize=address -I../fbsdcompat
+realpath_edge: OTHER_LDFLAGS += -Wl,-rpath -Wl,$(ASAN_DYLIB_PATH)
+qsort freebsd_qsort: OTHER_CFLAGS += -Wno-unused-function
+ifeq ($(PLATFORM),MacOSX)
+qsort_perf: OTHER_CFLAGS += -Wno-sign-compare -Wno-sign-conversion -Wno-cast-align -Wno-shorten-64-to-32
+else
+EXCLUDED_SOURCES += qsort_perf.c
+endif
 
 include $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.targets
+
diff --git a/tests/assumes.c b/tests/assumes.c
new file mode 100644 (file)
index 0000000..caf3442
--- /dev/null
@@ -0,0 +1,40 @@
+#define OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE 1
+#include <os/assumes.h>
+
+#include <darwintest.h>
+
+void os_crash_function(const char *message);
+
+static const char *expected_message = NULL;
+
+void os_crash_function(const char *message) {
+       if (expected_message) {
+               T_ASSERT_EQ_STR(message, expected_message, NULL);
+               T_END;
+       } else {
+               T_PASS("Got crash message: %s", message);
+               T_END;
+       }
+}
+
+T_DECL(os_crash_sanity, "sanity check for os_crash")
+{
+       expected_message = "My AWESOME assertion message.";
+       os_crash(expected_message);
+}
+
+extern int two;
+int two = 2;
+
+T_DECL(os_assert_no_msg, "sanity check for os_assert w/o a message")
+{
+       expected_message = "assertion failure: \"two + two == 5\" -> %lld";
+       os_assert(two + two == 5);
+}
+
+#define DOGMA "Today, we celebrate the first glorious anniversary of the Information Purification Directives."
+T_DECL(os_assert_msg, "sanity check for os_assert with a message")
+{
+       expected_message = "assertion failure: " DOGMA;
+       os_assert(two + two == 5, DOGMA);
+}
diff --git a/tests/assumes_legacy.c b/tests/assumes_legacy.c
new file mode 100644 (file)
index 0000000..772d4f9
--- /dev/null
@@ -0,0 +1,23 @@
+#include <os/assumes.h>
+
+#include <darwintest.h>
+
+void os_crash_function(const char *message);
+
+static const char *expected_message = NULL;
+
+void os_crash_function(const char *message) {
+       if (expected_message) {
+               T_ASSERT_EQ_STR(message, expected_message, NULL);
+               T_END;
+       } else {
+               T_PASS("Got crash message: %s", message);
+               T_END;
+       }
+}
+
+T_DECL(os_crash_sanity, "sanity check for os_crash")
+{
+       expected_message = "My AWESOME assertion message.";
+       os_crash(expected_message);
+}
diff --git a/tests/dir.c b/tests/dir.c
new file mode 100644 (file)
index 0000000..a359b44
--- /dev/null
@@ -0,0 +1,258 @@
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+T_DECL(seekdir_basic, "seekdir")
+{
+       const char *path = dt_tmpdir();
+       // make sure there are a couple of entries in the dir aside from . and ..
+       int fd = open(path, O_RDONLY | O_DIRECTORY);
+       openat(fd, "a", O_CREAT | O_WRONLY, 0600);
+       openat(fd, "b", O_CREAT | O_WRONLY, 0600);
+       openat(fd, "c", O_CREAT | O_WRONLY, 0600);
+
+       DIR *dirp = fdopendir(fd);
+       struct dirent *entry = NULL;
+
+       T_ASSERT_NOTNULL(dirp, NULL);
+
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); // .
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); // ..
+
+       // we can get any entry -- no ordering
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       // remember position for the second entry
+       long second_pos = telldir(dirp);
+       // read the second entry
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       char *second_name = strdup(entry->d_name);
+       T_ASSERT_NOTNULL(second_name, NULL);
+       // read the third entry
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+
+       // go back to the second entry and read it
+       seekdir(dirp, second_pos);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+
+       // make sure the name matches the old copy
+       T_ASSERT_EQ_STR(second_name, entry->d_name, NULL);
+
+       // return to 2nd once again, reinitializing second_pos and re-reading
+       seekdir(dirp, second_pos);
+       second_pos = telldir(dirp);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+
+       // make sure the name matches the old copy
+       T_ASSERT_EQ_STR(second_name, entry->d_name, NULL);
+
+       // verify that last pos
+       seekdir(dirp, second_pos);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_EQ_STR(second_name, entry->d_name, NULL);
+
+       free(second_name);
+       T_ASSERT_POSIX_ZERO(closedir(dirp), NULL);
+}
+
+T_DECL(readdir, "readdir")
+{
+       const char *path = dt_tmpdir();
+       int fd = open(path, O_RDONLY | O_DIRECTORY);
+       openat(fd, "foobarbaz", O_CREAT | O_WRONLY, 0600);
+
+       DIR *dirp = fdopendir(fd);
+       T_ASSERT_NOTNULL(dirp, NULL);
+
+       struct dirent *entry = NULL;
+       while ((entry = readdir(dirp)) != NULL) {
+               if (strcmp(entry->d_name, "foobarbaz")) {
+                       break;
+               }
+       }
+
+       T_ASSERT_NOTNULL(entry, "found the entry");
+
+       T_ASSERT_POSIX_ZERO(closedir(dirp), NULL);
+}
+
+T_DECL(tell_seek_tell, "tell-seek-tell returns the same location")
+{
+       // http://pubs.opengroup.org/onlinepubs/009695399/functions/telldir.html
+       // If the most recent operation on the directory stream was a seekdir(),
+       // the directory position returned from the telldir() shall be the same as
+       // that supplied as a loc argument for seekdir().
+
+       const char *path = dt_tmpdir();
+       // make sure there are a couple of entries in the dir aside from . and ..
+       {
+               int fd = open(path, O_RDONLY | O_DIRECTORY);
+               openat(fd, "a", O_CREAT | O_WRONLY, 0600);
+               openat(fd, "b", O_CREAT | O_WRONLY, 0600);
+               openat(fd, "c", O_CREAT | O_WRONLY, 0600);
+               close(fd);
+       }
+
+       DIR *dirp = opendir(path);
+       T_ASSERT_NOTNULL(dirp, NULL);
+       struct dirent *entry = NULL;
+
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       long pos1 = telldir(dirp);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       seekdir(dirp, pos1);
+       long pos2 = telldir(dirp);
+
+       T_ASSERT_EQ(pos1, pos2, NULL);
+
+       T_ASSERT_POSIX_ZERO(closedir(dirp), NULL);
+}
+
+T_DECL(rewinddir, "rewinddir")
+{
+       const char *path = dt_tmpdir();
+       // make sure there are a couple of entries in the dir aside from . and ..
+       {
+               int fd = open(path, O_RDONLY | O_DIRECTORY);
+               openat(fd, "a", O_CREAT | O_WRONLY, 0600);
+               openat(fd, "b", O_CREAT | O_WRONLY, 0600);
+               openat(fd, "c", O_CREAT | O_WRONLY, 0600);
+               close(fd);
+       }
+
+       DIR *dirp = opendir(path);
+       T_ASSERT_NOTNULL(dirp, NULL);
+       struct dirent *entry = NULL;
+
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       char *third_name = strdup(entry->d_name);
+
+       rewinddir(dirp);
+
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+
+       T_ASSERT_EQ_STR(third_name, entry->d_name, NULL);
+
+       free(third_name);
+       T_ASSERT_POSIX_ZERO(closedir(dirp), NULL);
+}
+
+
+T_DECL(rewinddir_dup, "rewinddir dup")
+{
+       // An older implementation of rewinddir failed to seek the fd which was
+       // passed to fdopendir()
+
+       const char *path = dt_tmpdir();
+       // make sure there are a couple of entries in the dir aside from . and ..
+       int fd = open(path, O_RDONLY | O_DIRECTORY);
+       openat(fd, "a", O_CREAT | O_WRONLY, 0600);
+       openat(fd, "b", O_CREAT | O_WRONLY, 0600);
+       openat(fd, "c", O_CREAT | O_WRONLY, 0600);
+
+       // prep an fd with a non-zero seek
+       DIR *dirp = fdopendir(fd);
+       T_ASSERT_NOTNULL(dirp, NULL);
+       struct dirent *entry = NULL;
+
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+
+       // remember the entry name and dup the fd
+       char *third_name = strdup(entry->d_name);
+       int fd2 = dup(fd);
+
+       T_ASSERT_POSIX_ZERO(closedir(dirp), NULL);
+
+       dirp = fdopendir(fd2);
+       // rewind back to 0
+       rewinddir(dirp);
+
+       T_ASSERT_NOTNULL(dirp, NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+       T_ASSERT_NOTNULL(entry = readdir(dirp), NULL);
+
+       T_ASSERT_EQ_STR(third_name, entry->d_name, NULL);
+
+       free(third_name);
+       T_ASSERT_POSIX_ZERO(closedir(dirp), NULL);
+}
+
+static int
+_select_abc(const struct dirent *entry)
+{
+       return strcmp(entry->d_name, "a") == 0 ||
+                       strcmp(entry->d_name, "b") == 0 ||
+                       strcmp(entry->d_name, "c") == 0;
+}
+
+T_DECL(scandir, "scandir")
+{
+       const char *path = dt_tmpdir();
+       {
+               int fd = open(path, O_RDONLY | O_DIRECTORY);
+               openat(fd, "a", O_CREAT | O_WRONLY, 0600);
+               openat(fd, "b", O_CREAT | O_WRONLY, 0600);
+               openat(fd, "c", O_CREAT | O_WRONLY, 0600);
+               close(fd);
+       }
+
+       struct dirent **entries = NULL;
+       int found = scandir(path, &entries, _select_abc, alphasort);
+
+       T_ASSERT_EQ(found, 3, NULL);
+
+       T_ASSERT_EQ_STR(entries[0]->d_name, "a", NULL);
+       T_ASSERT_EQ_STR(entries[1]->d_name, "b", NULL);
+       T_ASSERT_EQ_STR(entries[2]->d_name, "c", NULL);
+
+       free(entries[0]);
+       free(entries[1]);
+       free(entries[2]);
+       free(entries);
+}
+
+T_DECL(scandir_b, "scandir_b")
+{
+       const char *path = dt_tmpdir();
+       {
+               int fd = open(path, O_RDONLY | O_DIRECTORY);
+               openat(fd, "a", O_CREAT | O_WRONLY, 0600);
+               openat(fd, "b", O_CREAT | O_WRONLY, 0600);
+               openat(fd, "c", O_CREAT | O_WRONLY, 0600);
+               close(fd);
+       }
+
+       const struct dirent **entries = NULL;
+       int found = scandir_b(path, &entries,
+                       ^(const struct dirent *entry) {
+                               return strcmp(entry->d_name, "a") == 0 ||
+                                               strcmp(entry->d_name, "b") == 0 ||
+                                               strcmp(entry->d_name, "c") == 0;
+                       },
+                       ^(const struct dirent **d1, const struct dirent **d2) {
+                               return strcoll((*d1)->d_name, (*d2)->d_name);
+                       });
+
+       T_ASSERT_EQ(found, 3, NULL);
+
+       T_ASSERT_EQ_STR(entries[0]->d_name, "a", NULL);
+       T_ASSERT_EQ_STR(entries[1]->d_name, "b", NULL);
+       T_ASSERT_EQ_STR(entries[2]->d_name, "c", NULL);
+
+       free(entries[0]);
+       free(entries[1]);
+       free(entries[2]);
+       free(entries);
+}
diff --git a/tests/dirstat.c b/tests/dirstat.c
new file mode 100644 (file)
index 0000000..1a7a09e
--- /dev/null
@@ -0,0 +1,120 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirstat.h>
+#include <darwintest.h>
+#include <darwintest_utils.h>
+#include <sys/stat.h>
+
+#include <TargetConditionals.h>
+
+#if !TARGET_OS_SIMULATOR
+#define HAS_APFS
+#endif
+
+#ifdef HAS_APFS
+#include <apfs/apfs_fsctl.h>
+#endif
+
+T_DECL(dirstat, "Runs dirstat(3)")
+{
+       bool fast_only = false;
+       bool force_fallback = false;
+       char *path = "/System/Library/Frameworks";
+
+       // <rdar://problem/26400444> Libdarwintest passes argv without progname and flags starting in argv[0]
+       optind = 0;
+
+       int ch;
+       while ((ch = getopt(argc, argv, "fup:")) != -1){
+               switch (ch){
+                       case 'f':
+                               fast_only = true;
+                               break;
+                       case 'u':
+                               force_fallback = true;
+                               break;
+                       case 'p':
+                               path = optarg;
+                               break;
+                       case '?':
+                               T_ASSERT_FAIL("Usage: [-f] [-p <path>]");
+               }
+       }
+
+       T_LOG("Path: %s", path);
+
+       int flags = 0;
+       if (fast_only) {
+               T_LOG("Using DIRSTAT_FAST_ONLY");
+               flags |= DIRSTAT_FAST_ONLY;
+       }
+       if (force_fallback) {
+               T_LOG("Using DIRSTAT_FORCE_FALLBACK");
+               flags |= DIRSTAT_FORCE_FALLBACK;
+       }
+
+       struct dirstat ds = {0};
+
+       T_ASSERT_POSIX_SUCCESS(dirstat_np(path, flags, &ds, sizeof(ds)), NULL);
+
+       T_LOG("Size: %zd bytes", ds.total_size);
+       T_LOG("Descendants: %llu objects", ds.descendants);
+}
+
+T_DECL(dirstat_fallback, "Tests dirstat(3) fallback")
+{
+       char *path = "/System/Library/Frameworks";
+
+       struct dirstat ds = {0};
+
+       off_t native_size = 0;
+       off_t fallback_size = 0;
+
+       T_LOG("dirstat_np(\"%s\", 0, ...)", path);
+       T_EXPECT_POSIX_SUCCESS(dirstat_np(path, 0, &ds, sizeof(ds)), NULL);
+       T_LOG("Size: %zd bytes", ds.total_size);
+       T_LOG("Descendants: %llu objects", ds.descendants);
+       native_size = ds.total_size;
+
+       T_LOG("dirstat_np(\"%s\", DIRSTAT_FORCE_FALLBACK, ...)", path);
+       T_EXPECT_POSIX_SUCCESS(dirstat_np(path, DIRSTAT_FORCE_FALLBACK, &ds, sizeof(ds)), NULL);
+       T_LOG("Size: %zd bytes", ds.total_size);
+       T_LOG("Descendants: %llu objects", ds.descendants);
+       fallback_size = ds.total_size;
+
+       T_EXPECT_EQ(native_size, fallback_size, "Native and fallback sizes match");
+}
+
+T_DECL(dirstat_flags, "Tests dirstat(3)'s behavior flags")
+{
+       int err;
+       struct dirstat ds = {0};
+
+       char *not_fast = "/System/Library/Frameworks";
+
+       T_LOG("dirstat_np(\"%s\", DIRSTAT_FAST_ONLY, ...)", not_fast);
+       T_EXPECT_EQ(dirstat_np(not_fast, DIRSTAT_FAST_ONLY, &ds, sizeof(ds)), -1, "Fast-only fails on non-fast-enabled directory");
+
+#ifdef HAS_APFS
+       char *fast_tmpdir;
+       uint64_t flags = 0;
+
+       T_SETUPBEGIN;
+       T_ASSERT_NE(asprintf(&fast_tmpdir, "%s/%s", dt_tmpdir(), "fast-XXXXXX"), -1, "Generate fast dir stats directory name");
+       T_ASSERT_EQ((void *)mkdtemp(fast_tmpdir), (void *)fast_tmpdir, "Make fast dir stats directory");
+       err = fsctl(fast_tmpdir, APFSIOC_MAINTAIN_DIR_STATS, &flags, 0);
+       if (err != 0) {
+               rmdir(fast_tmpdir);
+               free(fast_tmpdir);
+               T_SKIP("Couldn't enable fast dir stats for directory (not on APFS?)");
+       }
+       T_SETUPEND;
+
+       T_LOG("dirstat_np(\"%s\", DIRSTAT_FAST_ONLY, ...)", fast_tmpdir);
+       T_EXPECTFAIL;
+       T_EXPECT_POSIX_SUCCESS(dirstat_np(fast_tmpdir, DIRSTAT_FAST_ONLY, &ds, sizeof(ds)), "Fast-only works on fast-enabled directory");
+
+       T_ASSERT_POSIX_SUCCESS(rmdir(fast_tmpdir), NULL);
+       free(fast_tmpdir);
+#endif
+}
diff --git a/tests/err.c b/tests/err.c
new file mode 100644 (file)
index 0000000..436e5d1
--- /dev/null
@@ -0,0 +1,25 @@
+#include <Block.h>
+#include <darwintest.h>
+#include <err.h>
+
+#define ITERATIONS 100
+
+T_DECL(err_multiple_exit_b, "Repeated set exit blocks doesn't leak copied blocks")
+{
+       int __block num = 0;
+       for (int i = 0; i < ITERATIONS; ++i) {
+               err_set_exit_b(^(int j) { num += j; });
+       }
+       err_set_exit_b(NULL);
+       // Dummy expect is necessary to run leaks on this test.
+       T_EXPECT_NULL(NULL, "DUMMY EXPECT");
+}
+
+T_DECL(err_multiple_exit, "Setting exit w/o block after setting exit with block doesn't leak copied block")
+{
+       int __block num = 0;
+       err_set_exit_b(^(int j) { num += j; });
+       err_set_exit(NULL);
+       // Dummy expect is necessary to run leaks on this test.
+       T_EXPECT_NULL(NULL, "DUMMY EXPECT");
+}
diff --git a/tests/flockfile.c b/tests/flockfile.c
new file mode 100644 (file)
index 0000000..f150172
--- /dev/null
@@ -0,0 +1,26 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "darwintest.h"
+
+T_DECL(flockfile_preserve_errno, "flockfile preserves errno")
+{
+       errno = EBUSY;
+       flockfile(stderr);
+       T_ASSERT_EQ(errno, EBUSY, "flockfile preserves errno");
+}
+
+T_DECL(funlockfile_preserve_errno, "funlockfile preserves errno")
+{
+       errno = EBUSY;
+       funlockfile(stderr);
+       T_ASSERT_EQ(errno, EBUSY, "funlockfile preserves errno");
+}
+
+T_DECL(ftrylockfile_preserve_errno, "ftrylockfile preserves errno")
+{
+       errno = EBUSY;
+       ftrylockfile(stderr);
+       T_ASSERT_EQ(errno, EBUSY, "ftrylockfile preserves errno");
+}
+
diff --git a/tests/freebsd_fmemopen.c b/tests/freebsd_fmemopen.c
new file mode 100644 (file)
index 0000000..0e59a37
--- /dev/null
@@ -0,0 +1,268 @@
+/*-
+Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
+
+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.
+
+THIS SOFTWARE IS PROVIDED BY AUTHOR 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 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.
+*/
+
+/*
+ * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
+ * a FILE * retrieved using fmemopen()
+ */
+
+#include <sys/cdefs.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#include <darwintest.h>
+
+T_DECL(freebsd_fmemopen_test_preexisting, "")
+{
+       /* Use a pre-existing buffer. */
+       char buf[512];
+       char buf2[512];
+       char str[]  = "Test writing some stuff";
+       char str2[] = "AAAAAAAAA";
+       char str3[] = "AAAA writing some stuff";
+       FILE *fp;
+       size_t nofw, nofr;
+       int rc;
+
+       /* Open a FILE * using fmemopen. */
+       fp = fmemopen(buf, sizeof(buf), "w");
+       T_ASSERT_NOTNULL(fp, NULL);
+
+       /* Write to the buffer. */
+       nofw = fwrite(str, 1, sizeof(str), fp);
+       T_ASSERT_EQ(nofw, sizeof(str), NULL);
+
+       /* Close the FILE *. */
+       rc = fclose(fp);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+
+       /* Re-open the FILE * to read back the data. */
+       fp = fmemopen(buf, sizeof(buf), "r");
+       T_ASSERT_NOTNULL(fp, NULL);
+
+       /* Read from the buffer. */
+       bzero(buf2, sizeof(buf2));
+       nofr = fread(buf2, 1, sizeof(buf2), fp);
+       T_ASSERT_EQ(nofr, sizeof(buf2), NULL);
+
+       /*
+        * Since a write on a FILE * retrieved by fmemopen
+        * will add a '\0' (if there's space), we can check
+        * the strings for equality.
+        */
+       T_ASSERT_EQ_STR(str, buf2, NULL);
+
+       /* Close the FILE *. */
+       rc = fclose(fp);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+
+       /* Now open a FILE * on the first 4 bytes of the string. */
+       fp = fmemopen(str, 4, "w");
+       T_ASSERT_NOTNULL(fp, NULL);
+
+       /*
+        * Try to write more bytes than we shoud, we'll get a short count (4).
+        */
+       nofw = fwrite(str2, 1, sizeof(str2), fp);
+       T_ASSERT_EQ(nofw, 4UL, NULL);
+
+       /* Close the FILE *. */
+       rc = fclose(fp);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+
+       /* Check that the string was not modified after the first 4 bytes. */
+       T_ASSERT_EQ_STR(str, str3, NULL);
+}
+
+T_DECL(freebsd_fmemopen_test_autoalloc, "")
+{
+       /* Let fmemopen allocate the buffer. */
+       FILE *fp;
+       long pos;
+       size_t nofw, i;
+       int rc;
+
+       /* Open a FILE * using fmemopen. */
+       fp = fmemopen(NULL, 512, "w+");
+       T_ASSERT_NOTNULL(fp, NULL);
+
+       /* fill the buffer */
+       for (i = 0; i < 512; i++) {
+               nofw = fwrite("a", 1, 1, fp);
+               T_ASSERT_EQ(nofw, 1UL, NULL);
+       }
+
+       /* Get the current position into the stream. */
+       pos = ftell(fp);
+       T_ASSERT_EQ(pos, 512L, NULL);
+
+       /* Try to write past the end, we should get a short object count (0) */
+       nofw = fwrite("a", 1, 1, fp);
+       T_ASSERT_POSIX_ZERO(nofw, NULL);
+
+       /* Close the FILE *. */
+       rc = fclose(fp);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+
+       /* Open a FILE * using a wrong mode */
+       fp = fmemopen(NULL, 512, "r");
+       T_ASSERT_NULL(fp, NULL);
+
+       fp = fmemopen(NULL, 512, "w");
+       T_ASSERT_NULL(fp, NULL);
+}
+
+T_DECL(freebsd_fmemopen_test_data_length, "")
+{
+       /*
+        * Here we test that a read operation doesn't go past the end of the
+        * data actually written, and that a SEEK_END seeks from the end of the
+        * data, not of the whole buffer.
+        */
+       FILE *fp;
+       char buf[512] = {'\0'};
+       char str[]  = "Test data length. ";
+       char str2[] = "Do we have two sentences?";
+       char str3[sizeof(str) + sizeof(str2) -1];
+       long pos;
+       size_t nofw, nofr;
+       int rc;
+
+       /* Open a FILE * for updating our buffer. */
+       fp = fmemopen(buf, sizeof(buf), "w+");
+       T_ASSERT_NOTNULL(fp, NULL);
+
+       /* Write our string into the buffer. */
+       nofw = fwrite(str, 1, sizeof(str), fp);
+       T_ASSERT_EQ(nofw, sizeof(str), NULL);
+
+       /* Now seek to the end and check that ftell gives us sizeof(str). */
+       rc = fseek(fp, 0, SEEK_END);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+       pos = ftell(fp);
+       T_ASSERT_EQ(pos, (long)sizeof(str), NULL);
+
+       /* Close the FILE *. */
+       rc = fclose(fp);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+
+       /* Reopen the buffer for appending. */
+       fp = fmemopen(buf, sizeof(buf), "a+");
+       T_ASSERT_NOTNULL(fp, NULL);
+
+       /* We should now be writing after the first string. */
+       nofw = fwrite(str2, 1, sizeof(str2), fp);
+       T_ASSERT_EQ(nofw, sizeof(str2), NULL);
+
+       /* Rewind the FILE *. */
+       rc = fseek(fp, 0, SEEK_SET);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+
+       /* Make sure we're at the beginning. */
+       pos = ftell(fp);
+       T_ASSERT_EQ(pos, 0L, NULL);
+
+       /* Read the whole buffer. */
+       nofr = fread(str3, 1, sizeof(buf), fp);
+       T_ASSERT_EQ(nofr, sizeof(str3), NULL);
+
+       /* Make sure the two strings are there. */
+       T_ASSERT_EQ(strncmp(str3, str, sizeof(str) - 1), 0, NULL);
+       T_ASSERT_EQ(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)), 0, NULL);
+
+       /* Close the FILE *. */
+       rc = fclose(fp);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+}
+
+T_DECL(freebsd_fmemopen_test_binary, "")
+{
+       /*
+        * Make sure that NULL bytes are never appended when opening a buffer
+        * in binary mode.
+        */
+
+       FILE *fp;
+       char buf[20];
+       char str[] = "Test";
+       size_t nofw;
+       int rc;
+
+       /* Pre-fill the buffer. */
+       memset(buf, 'A', sizeof(buf));
+
+       /* Open a FILE * in binary mode. */
+       fp = fmemopen(buf, sizeof(buf), "w+b");
+       T_ASSERT_NOTNULL(fp, NULL);
+
+       /* Write some data into it. */
+       nofw = fwrite(str, 1, strlen(str), fp);
+       T_ASSERT_EQ(nofw, strlen(str), NULL);
+
+       /* Make sure that the buffer doesn't contain any NULL bytes. */
+       for (size_t i = 0; i < sizeof(buf); i++)
+               T_ASSERT_NE(buf[i], '\0', NULL);
+
+       /* Close the FILE *. */
+       rc = fclose(fp);
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+}
+
+T_DECL(freebsd_fmemopen_test_append_binary_pos, "")
+{
+       /*
+        * For compatibility with other implementations (glibc), we set the
+        * position to 0 when opening an automatically allocated binary stream
+        * for appending.
+        */
+
+       FILE *fp;
+
+       fp = fmemopen(NULL, 16, "ab+");
+       T_ASSERT_NOTNULL(fp, NULL);
+       T_ASSERT_EQ(ftell(fp), 0L, NULL);
+       fclose(fp);
+
+       /* Make sure that a pre-allocated buffer behaves correctly. */
+       char buf[] = "Hello";
+       fp = fmemopen(buf, sizeof(buf), "ab+");
+       T_ASSERT_NOTNULL(fp, NULL);
+       T_ASSERT_EQ(ftell(fp), (long)strlen(buf), NULL);
+       fclose(fp);
+}
+
+T_DECL(freebsd_fmemopen_test_size_0, "")
+{
+       /* POSIX mandates that we return EINVAL if size is 0. */
+
+       FILE *fp;
+
+       fp = fmemopen(NULL, 0, "r+");
+       T_ASSERT_NULL(fp, NULL);
+       T_ASSERT_EQ(errno, EINVAL, NULL);
+}
diff --git a/tests/freebsd_glob.c b/tests/freebsd_glob.c
new file mode 100644 (file)
index 0000000..428213c
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 Dell EMC Isilon
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+/*
+ * Derived from Russ Cox' pathological case test program used for the
+ * https://research.swtch.com/glob article.
+ */
+T_DECL(glob_pathological_test, "Russ Cox's pathological test program")
+{
+       struct timespec t, t2;
+       glob_t g;
+       const char *longname = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+           "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+       char pattern[1000], *p;
+       double dt;
+       unsigned i, j, k, mul = 10;
+       int fd, rc;
+
+       T_SETUPBEGIN;
+       rc = chdir(dt_tmpdir());
+       T_ASSERT_POSIX_ZERO(rc, NULL);
+       fd = open(longname, O_CREAT | O_RDWR, 0666);
+       T_ASSERT_POSIX_SUCCESS(fd, NULL);
+       T_SETUPEND;
+
+       /*
+        * Test up to 100 a* groups.  Exponential implementations typically go
+        * bang at i=7 or 8.
+        */
+       for (i = 0; i < 100; i++) {
+               /*
+                * Create a*...b pattern with i 'a*' groups.
+                */
+               p = pattern;
+               for (k = 0; k < i; k++) {
+                       *p++ = 'a';
+                       *p++ = '*';
+               }
+               *p++ = 'b';
+               *p = '\0';
+
+               clock_gettime(CLOCK_MONOTONIC_RAW, &t);
+               for (j = 0; j < mul; j++) {
+                       memset(&g, 0, sizeof g);
+                       rc = glob(pattern, 0, 0, &g);
+                       if (rc == GLOB_NOSPACE || rc == GLOB_ABORTED) {
+                               T_ASSERT_EQ(rc, GLOB_NOMATCH,
+                                   "an unexpected error occurred: "
+                                   "rc=%d errno=%d", rc, errno);
+                               /* NORETURN */
+                       }
+
+                       if (rc != GLOB_NOMATCH) {
+                           T_FAIL("A bogus match occurred: '%s' ~ '%s'", pattern, g.gl_pathv ? g.gl_pathv[0] : "(NULL)");
+                       }
+                       globfree(&g);
+               }
+               clock_gettime(CLOCK_MONOTONIC_RAW, &t2);
+
+               t2.tv_sec -= t.tv_sec;
+               t2.tv_nsec -= t.tv_nsec;
+               dt = t2.tv_sec + (double)t2.tv_nsec/1e9;
+               dt /= mul;
+
+               T_ASSERT_LE(dt, 1.0, "glob(3) completes in reasonable time (%d): %.9f sec/match", i,
+                   dt);
+
+               if (dt >= 0.0001)
+                       mul = 1;
+       }
+}
diff --git a/tests/freebsd_open_memstream.c b/tests/freebsd_open_memstream.c
new file mode 100644 (file)
index 0000000..381c28c
--- /dev/null
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <darwintest.h>
+
+static char *buf;
+static size_t len;
+
+static void
+assert_stream(const char *contents)
+{
+       T_EXPECT_EQ(strlen(contents), len,
+                       "bad length %zd for \"%s\"\n", len, contents);
+    T_EXPECT_EQ(strncmp(buf, contents, strlen(contents)), 0,
+                       "bad buffer \"%s\" for \"%s\"\n", buf, contents);
+}
+
+T_DECL(freebsd_open_memstream_open_group_test, "")
+{
+       FILE *fp;
+       off_t eob;
+
+       fp = open_memstream(&buf, &len);
+       T_ASSERT_NOTNULL(fp, "open_memstream failed");
+
+       fprintf(fp, "hello my world");
+       fflush(fp);
+       assert_stream("hello my world");
+       eob = ftello(fp);
+       rewind(fp);
+       fprintf(fp, "good-bye");
+       fseeko(fp, eob, SEEK_SET);
+       fclose(fp);
+       assert_stream("good-bye world");
+       free(buf);
+}
+
+T_DECL(freebsd_open_memstream_simple_tests, "")
+{
+       static const char zerobuf[] =
+           { 'f', 'o', 'o', 0, 0, 0, 0, 'b', 'a', 'r', 0 };
+       char c;
+       FILE *fp;
+
+       fp = open_memstream(&buf, NULL);
+       T_ASSERT_NULL(fp, "open_memstream did not fail");
+       T_ASSERT_EQ(errno, EINVAL, "open_memstream didn't fail with EINVAL");
+       fp = open_memstream(NULL, &len);
+       T_ASSERT_NULL(fp, "open_memstream did not fail");
+       T_ASSERT_EQ(errno, EINVAL, "open_memstream didn't fail with EINVAL");
+       fp = open_memstream(&buf, &len);
+       T_ASSERT_NOTNULL(fp, "open_memstream failed, errno=%d", errno);
+       fflush(fp);
+       assert_stream("");
+       if (fwide(fp, 0) >= 0)
+               printf("stream is not byte-oriented\n");
+
+       fprintf(fp, "fo");
+       fflush(fp);
+       assert_stream("fo");
+       fputc('o', fp);
+       fflush(fp);
+       assert_stream("foo");
+       rewind(fp);
+       fflush(fp);
+       assert_stream("");
+       fseek(fp, 0, SEEK_END);
+       fflush(fp);
+       assert_stream("foo");
+
+       /*
+        * Test seeking out past the current end.  Should zero-fill the
+        * intermediate area.
+        */
+       fseek(fp, 4, SEEK_END);
+       fprintf(fp, "bar");
+       fflush(fp);
+
+       /*
+        * Can't use assert_stream() here since this should contain
+        * embedded null characters.
+        */
+       if (len != 10)
+               printf("bad length %zd for zero-fill test\n", len);
+       else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
+               printf("bad buffer for zero-fill test\n");
+
+       fseek(fp, 3, SEEK_SET);
+       fprintf(fp, " in ");
+       fflush(fp);
+       assert_stream("foo in ");
+       fseek(fp, 0, SEEK_END);
+       fflush(fp);
+       assert_stream("foo in bar");
+
+       rewind(fp);
+       if (fread(&c, sizeof(c), 1, fp) != 0)
+               printf("fread did not fail\n");
+       else if (!ferror(fp))
+               printf("error indicator not set after fread\n");
+       else
+               clearerr(fp);
+
+       fseek(fp, 4, SEEK_SET);
+       fprintf(fp, "bar baz");
+       fclose(fp);
+       assert_stream("foo bar baz");
+       free(buf);
+}
+
+T_DECL(freebsd_open_memstream_seek_tests, "")
+{
+       FILE *fp;
+
+       fp = open_memstream(&buf, &len);
+       T_ASSERT_NOTNULL(fp, "open_memstream failed: %d", errno);
+
+#define SEEK_FAIL(offset, whence, error) do {                  \
+       errno = 0;                                              \
+       T_ASSERT_NE(fseeko(fp, (offset), (whence)), 0,  \
+           "fseeko(%s, %s) did not fail, set pos to %jd",      \
+           __STRING(offset), __STRING(whence), \
+           (intmax_t)ftello(fp));                              \
+       T_ASSERT_EQ(errno, (error),                     \
+           "fseeko(%s, %s) failed with %d rather than %s",     \
+           __STRING(offset), __STRING(whence), errno,          \
+           __STRING(error));                                   \
+} while (0)
+
+#define SEEK_OK(offset, whence, result) do {                   \
+       T_ASSERT_EQ(fseeko(fp, (offset), (whence)), 0,  \
+           "fseeko(%s, %s) failed: %s",                        \
+           __STRING(offset), __STRING(whence), strerror(errno)); \
+       T_ASSERT_EQ(ftello(fp), (off_t)(result),                        \
+           "fseeko(%s, %s) seeked to %jd rather than %s",      \
+           __STRING(offset), __STRING(whence),                 \
+           (intmax_t)ftello(fp), __STRING(result));            \
+} while (0)
+
+       SEEK_FAIL(-1, SEEK_SET, EINVAL);
+       SEEK_FAIL(-1, SEEK_CUR, EINVAL);
+       SEEK_FAIL(-1, SEEK_END, EINVAL);
+       fprintf(fp, "foo");
+       SEEK_OK(-1, SEEK_CUR, 2);
+       SEEK_OK(0, SEEK_SET, 0);
+       SEEK_OK(-1, SEEK_END, 2);
+       SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
+       SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
+       fclose(fp);
+}
diff --git a/tests/freebsd_open_wmemstream.c b/tests/freebsd_open_wmemstream.c
new file mode 100644 (file)
index 0000000..4996cff
--- /dev/null
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <darwintest.h>
+
+static wchar_t *buf;
+static size_t len;
+
+static void
+assert_stream(const wchar_t *contents)
+{
+       if (wcslen(contents) != len)
+               printf("bad length %zd for \"%ls\"\n", len, contents);
+       else if (wcsncmp(buf, contents, wcslen(contents)) != 0)
+               printf("bad buffer \"%ls\" for \"%ls\"\n", buf, contents);
+}
+
+T_DECL(freebsd_open_wmemstream_open_group_test, "")
+{
+       FILE *fp;
+       off_t eob;
+
+       fp = open_wmemstream(&buf, &len);
+       T_ASSERT_NOTNULL(fp, "open_wmemstream failed");
+
+       fwprintf(fp, L"hello my world");
+       fflush(fp);
+       assert_stream(L"hello my world");
+       eob = ftello(fp);
+       rewind(fp);
+       fwprintf(fp, L"good-bye");
+       fseeko(fp, eob, SEEK_SET);
+       fclose(fp);
+       assert_stream(L"good-bye world");
+       free(buf);
+}
+
+T_DECL(freebsd_open_wmemstream_simple_tests, "")
+{
+       static const wchar_t zerobuf[] =
+           { L'f', L'o', L'o', 0, 0, 0, 0, L'b', L'a', L'r', 0 };
+       wchar_t c;
+       FILE *fp;
+
+       fp = open_wmemstream(&buf, NULL);
+       T_ASSERT_NULL(fp, "open_wmemstream did not fail");
+       T_ASSERT_EQ(errno, EINVAL, "open_wmemstream didn't fail with EINVAL");
+       fp = open_wmemstream(NULL, &len);
+       T_ASSERT_NULL(fp, "open_wmemstream did not fail");
+       T_ASSERT_EQ(errno, EINVAL, "open_wmemstream didn't fail with EINVAL");
+       fp = open_wmemstream(&buf, &len);
+       T_ASSERT_NOTNULL(fp, "open_memstream failed, errno=%d", errno);
+       fflush(fp);
+       assert_stream(L"");
+       if (fwide(fp, 0) <= 0)
+               printf("stream is not wide-oriented\n");
+
+       fwprintf(fp, L"fo");
+       fflush(fp);
+       assert_stream(L"fo");
+       fputwc(L'o', fp);
+       fflush(fp);
+       assert_stream(L"foo");
+       rewind(fp);
+       fflush(fp);
+       assert_stream(L"");
+       fseek(fp, 0, SEEK_END);
+       fflush(fp);
+       assert_stream(L"foo");
+
+       /*
+        * Test seeking out past the current end.  Should zero-fill the
+        * intermediate area.
+        */
+       fseek(fp, 4, SEEK_END);
+       fwprintf(fp, L"bar");
+       fflush(fp);
+
+       /*
+        * Can't use assert_stream() here since this should contain
+        * embedded null characters.
+        */
+       if (len != 10)
+               printf("bad length %zd for zero-fill test\n", len);
+       else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
+               printf("bad buffer for zero-fill test\n");
+
+       fseek(fp, 3, SEEK_SET);
+       fwprintf(fp, L" in ");
+       fflush(fp);
+       assert_stream(L"foo in ");
+       fseek(fp, 0, SEEK_END);
+       fflush(fp);
+       assert_stream(L"foo in bar");
+
+       rewind(fp);
+       if (fread(&c, sizeof(c), 1, fp) != 0)
+               printf("fread did not fail\n");
+       else if (!ferror(fp))
+               printf("error indicator not set after fread\n");
+       else
+               clearerr(fp);
+
+       fseek(fp, 4, SEEK_SET);
+       fwprintf(fp, L"bar baz");
+       fclose(fp);
+       assert_stream(L"foo bar baz");
+       free(buf);
+}
+
+T_DECL(freebsd_open_wmemstream_seek_tests, "")
+{
+       FILE *fp;
+
+       fp = open_wmemstream(&buf, &len);
+       T_ASSERT_NOTNULL(fp, "open_wmemstream failed, errno=%d", errno);
+
+#define SEEK_FAIL(offset, whence, error) do {                  \
+       errno = 0;                                              \
+       T_ASSERT_NE(fseeko(fp, (offset), (whence)), 0,  \
+           "fseeko(%s, %s) did not fail, set pos to %jd",      \
+           __STRING(offset), __STRING(whence), \
+           (intmax_t)ftello(fp));                              \
+       T_ASSERT_EQ(errno, (error),                     \
+           "fseeko(%s, %s) failed with %d rather than %s",     \
+           __STRING(offset), __STRING(whence), errno,          \
+           __STRING(error));                                   \
+} while (0)
+
+#define SEEK_OK(offset, whence, result) do {                   \
+       T_ASSERT_EQ(fseeko(fp, (offset), (whence)), 0,  \
+           "fseeko(%s, %s) failed: %s",                        \
+           __STRING(offset), __STRING(whence), strerror(errno)); \
+       T_ASSERT_EQ(ftello(fp), (off_t)(result),                        \
+           "fseeko(%s, %s) seeked to %jd rather than %s",      \
+           __STRING(offset), __STRING(whence),                 \
+           (intmax_t)ftello(fp), __STRING(result));            \
+} while (0)
+
+       SEEK_FAIL(-1, SEEK_SET, EINVAL);
+       SEEK_FAIL(-1, SEEK_CUR, EINVAL);
+       SEEK_FAIL(-1, SEEK_END, EINVAL);
+       fwprintf(fp, L"foo");
+       SEEK_OK(-1, SEEK_CUR, 2);
+       SEEK_OK(0, SEEK_SET, 0);
+       SEEK_OK(-1, SEEK_END, 2);
+       SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
+       SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
+       fclose(fp);
+}
diff --git a/tests/freebsd_qsort.c b/tests/freebsd_qsort.c
new file mode 100644 (file)
index 0000000..68954e2
--- /dev/null
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+/*
+ * Test for qsort() routine.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <darwintest.h>
+
+#include "freebsd_qsort.h"
+
+T_DECL(qsort, "qsort sanity check")
+{
+       int testvector[IVEC_LEN];
+       int sresvector[IVEC_LEN];
+       size_t i, j;
+
+       for (j = 2; j < IVEC_LEN; j++) {
+               /* Populate test vectors */
+               for (i = 0; i < j; i++) {
+                       testvector[i] = sresvector[i] = initvector[i];
+        }
+
+               /* Sort using qsort(3) */
+               qsort(testvector, j, sizeof(testvector[0]), sorthelp);
+               /* Sort using reference slow sorting routine */
+               ssort(sresvector, (int)j);
+
+               /* Compare results */
+               for (i = 0; i < j; i++){
+            T_QUIET;
+            T_EXPECT_EQ(testvector[i], sresvector[i],
+                "item at index %zd should match", i);
+        }
+       }
+}
+
+T_DECL(qsort_b, "qsort_b sanity check")
+{
+       int testvector[IVEC_LEN];
+       int sresvector[IVEC_LEN];
+       size_t i, j;
+
+       for (j = 2; j < IVEC_LEN; j++) {
+               /* Populate test vectors */
+               for (i = 0; i < j; i++) {
+                       testvector[i] = sresvector[i] = initvector[i];
+        }
+
+               /* Sort using qsort(3) */
+               qsort_b(testvector, j, sizeof(testvector[0]), sorthelp_b);
+               /* Sort using reference slow sorting routine */
+               ssort(sresvector, (int)j);
+
+               /* Compare results */
+               for (i = 0; i < j; i++){
+            T_QUIET;
+            T_EXPECT_EQ(testvector[i], sresvector[i],
+                "item at index %zd should match", i);
+        }
+       }
+}
diff --git a/tests/freebsd_qsort.h b/tests/freebsd_qsort.h
new file mode 100644 (file)
index 0000000..1349995
--- /dev/null
@@ -0,0 +1,312 @@
+/*-
+ * Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TEST_SORT_H
+#define _TEST_SORT_H
+
+#include <sys/param.h>
+
+#define  nitems(x)   (sizeof((x)) / sizeof((x)[0]))
+
+static int
+sorthelp(const void *a, const void *b)
+{
+       const int *oa, *ob;
+
+       oa = a;
+       ob = b;
+       /* Don't use "return *oa - *ob" since it's easy to cause overflow! */
+       if (*oa > *ob)
+               return (1);
+       if (*oa < *ob)
+               return (-1);
+       return (0);
+}
+
+static int
+szsorthelp(void *sz, const void *a, const void *b)
+{
+       size_t elmsz = (size_t)sz;
+       return memcmp(a, b, elmsz);
+}
+
+static int (^sorthelp_b)(const void *a, const void *b) =
+               ^(const void *a, const void *b){
+       const int *oa, *ob;
+
+       oa = a;
+       ob = b;
+       /* Don't use "return *oa - *ob" since it's easy to cause overflow! */
+       if (*oa > *ob)
+               return (1);
+       if (*oa < *ob)
+               return (-1);
+       return (0);
+};
+
+/* Reference sorting routine (slooow!) */
+static void
+ssort(int v[], int nmemb)
+{
+       int i, j, k;
+
+       for (i = 0; i < nmemb; i++) {
+               for (j = i + 1; j < nmemb; j++) {
+                       if (v[j] < v[i]) {
+                               k = v[i];
+                               v[i] = v[j];
+                               v[j] = k;
+                       }
+               }
+       }
+}
+
+/* with element size */
+static void
+szsort(char v[], size_t nmemb, size_t sz)
+{
+       size_t i, j;
+       char temp[sz];
+
+       for (i = 0; i < nmemb; i++) {
+               for (j = i + 1; j < nmemb; j++) {
+                       if (memcmp(v + (j * sz), v + (i * sz), sz) < 0) {
+                               memcpy(temp, v + (i * sz), sz);
+                               memcpy(v + (i * sz), v + (j * sz), sz);
+                               memcpy(v + (j * sz), temp, sz);
+                       }
+               }
+       }
+}
+
+/* Some random data */
+static int initvector[1024] = {
+       599853225, 371951333, -428880425, 1450668530, 85530178, -460170550,
+       -270680269, 717137591, 106244401, -1138072905, -113532586,
+       599690958, 464993720, 107690177, 24249019, -1151018550, 794225588,
+       1494905642, -62951716, -734531757, 1197251494, 1020063925,
+       -634536734, -216634704, 617366508, -18840190, 481010395,
+       -1555785724, 128221950, -1747743676, 1119012320, -252160437,
+       617137855, 1159833073, -106647920, -1570719046, -769400990,
+       -130308848, 1186546396, 215253591, 445832488, 160263176, 777264170,
+       -274636650, -696134447, 1057957088, -626175254, 188632134,
+       -98941793, -1602334908, -373717125, 885013862, 571258221,
+       -399572192, 407761463, -733249776, 12094800, -367046815, 178974501,
+       -452638559, -516580143, -94282073, 1411115180, -1151792797,
+       1442815268, 1106583674, 515269284, -74019972, 598818901, 696848474,
+       -657910766, -287309335, 1538095746, 143543003, 851444033,
+       -947573348, 296222973, 1339592140, -947505360, 872027891,
+       -418844714, -583075597, -324758197, -964531573, 1016795914,
+       -866842580, -304084402, -286930819, 338975583, 803597943,
+       -452483372, 1525283506, -1185830826, -596405894, 905191340,
+       -1638026278, 106749913, 582771197, -730713796, 56052422,
+       1498040174, 644967266, 182541575, 280483468, -1932835017,
+       -435546874, 940106007, 1753388509, -340355019, -231577358,
+       -714879035, 1051182949, 204261785, 1321346243, -895289878,
+       -240369893, 566608506, -350777580, -1384849829, -876816409,
+       1013787299, -1408035937, -222626650, 1708168486, -645148461,
+       1854654, -393012507, 179327030, -1607975548, -715202732, 730588290,
+       246968517, -550975254, -101136772, -174103176, 1188941016,
+       2004650834, -1501389866, -2021225998, 1219042515, -464113898,
+       268565342, 126451123, -1045877126, -198918003, 310177444,
+       1578314812, 1828867082, 453336898, -908485523, 749777130,
+       -1028565802, 61360571, 241484853, -175693399, 1816211059,
+       533940889, -1496933703, 385185125, -821132413, -8923391,
+       -1429546239, 46190992, 449247332, -20432494, 778761611, -178782699,
+       -811194695, -632276211, 70196094, 890817525, -1447776908,
+       -323783741, -62333222, 954929503, 247668507, -1394420605,
+       367913886, 1364926759, 1298781924, 357923028, -73644747,
+       -319744305, 61718202, -1454549286, 387493522, 2018321449,
+       861026653, 289973298, 1755939093, -84772204, 43425266, -1325753781,
+       -679938775, 1228500370, -763816405, 548903035, 1765563727,
+       425183052, 1424621863, -188287424, 554385654, 751831998,
+       1377088085, 66622090, 139224450, -1305816167, 650140724, 593988868,
+       -444913321, 589045097, 1261428989, 101292769, -780376786,
+       559307348, 1644593236, -1838606833, 53570301, -680576100,
+       -44969538, 268718267, -632104125, 276904628, 626299449, -11761453,
+       545899086, -1027343598, -432251872, 539353494, -399575006,
+       -568383580, -677802882, 1296513472, 801202048, 806425805, 1983363,
+       850487421, 38046173, 1535399484, 1998285544, -1301751898,
+       -46561973, 56545408, -1107662676, 456041145, -452923904,
+       -262219453, -371849200, 392524281, 1650231392, 1185585356,
+       126610511, -1125389657, 1015981177, -1318481342, -213835789,
+       1263484054, -654361441, 1408272041, -231555284, -1121778152,
+       -395512897, 332277674, -349703586, 1809474399, -223731607,
+       -1342224737, 736165236, 67535587, 89879082, 471445838, 423788300,
+       -384354470, 907475706, 154886390, -1406736539, -8558766,
+       -203405718, -422127884, 1048520863, 747418501, 87438975, 727668160,
+       -914936981, 428266976, -455742009, -949014605, 487159058,
+       -262526850, -309451504, -76928461, 1072951428, -1370953830,
+       238231681, -1831047244, -405735199, -35941848, 469048670,
+       505307987, -660553590, 876537439, -314195871, 999234339,
+       -1405846240, -579885695, 629067031, 863481510, -742301385,
+       -1723403128, -153070386, 782682839, -343111818, -877101810,
+       1438467302, -319951459, -1585702508, -338381888, 484108815,
+       -1726935191, -749923706, 1657932127, -816151395, -566321865,
+       -133542331, 84961164, 598275578, 1302065347, -533098653,
+       -1766383037, 53169714, -464201288, 617735133, 862536123,
+       -141730724, -1967377125, -1023736305, -1012511106, 64484992,
+       -1250856831, 426409332, -355670055, -298251663, -867634978,
+       -776124819, 74018333, -425385214, -108004251, -1192766130,
+       1294193867, -109867195, -78667637, 1164855393, -826007552,
+       -522528066, 1160283046, -1095276403, -1218917472, -396475366,
+       -77394733, -425603169, 251928357, -393559355, 1488845184,
+       898455978, -773338691, -37627855, -345014717, 204298578, 209084274,
+       1047080643, -414348222, 26496664, 705759824, 575149152, 604904761,
+       624988690, 1446041250, 1000757225, -1354896151, 1422958189,
+       -1607165311, -832757521, 365074225, 1171764999, 1200795217,
+       -203957828, 23166236, -846818698, -547439867, -790192498,
+       -122123561, 914298013, 66225525, -36163174, -480698856,
+       -1269421818, 624641703, 254923102, 1564329013, -583609221,
+       -649433551, -743396069, 1182455435, 102658744, 285599336,
+       692480463, -852737563, -660090184, 1374350065, 72300985, 690541659,
+       -1194212957, -1151816525, 157415641, 487398246, 1030153072,
+       933723020, 1359181027, -1303457764, -1543773272, 774306017,
+       -854382652, 755485667, -864943584, -63242545, -1271480354,
+       157720215, -205001173, 889984130, -581583822, -473779111,
+       -932136577, 735326252, 428638717, 1888884222, 561493709,
+       -1966427364, -1710208603, 340121869, 918894036, 927172509,
+       904178436, 1476687667, 90796414, 651591731, -550913123, -42218158,
+       637756529, 1091478400, 124976584, -48739309, -798898083, 393581349,
+       -1078624722, -789291577, 1010582542, -512317005, 1222773656,
+       466454593, 1183558811, 822782663, -851624703, -850404012,
+       1473672600, 852527073, 1073953362, 137635828, 936104739, -86567759,
+       -882563252, 1845232980, -737978404, -104703380, 149802989,
+       -349118325, 1479797538, 1966007488, 1254228842, 414304661,
+       -790805785, 31583329, -76864151, 558202855, -1447047313, 716720607,
+       -404224238, -54107627, 1747385914, -657407390, 202940208,
+       1083067056, -532861378, 163426933, -130289277, 1301785258,
+       -302920320, -637947485, -644895903, -1668027530, 391890467,
+       -126586485, -536836984, -1154536413, -339505118, -1187229462,
+       -670985870, -601310813, -1350055158, -482479784, 139847714,
+       -253955849, 5190414, -542857077, 1175835684, -584165057,
+       1132775766, -592091269, -891445655, -340995936, 736395810,
+       779967964, 515095845, -1138437307, -259226729, -167820100,
+       -801611617, -282451622, -1313679283, -1436126694, 1258773990,
+       -717601098, -583559645, -1307478759, 1238647247, 1589011223,
+       -1029216445, -107030650, 400152690, -1349079913, 1428582247,
+       21546946, 208807686, -169450574, -1086213374, -1242715198,
+       669098277, 416626722, -1122525014, -1389466669, -391843085,
+       -56318357, 421040094, 212303518, 738666684, -1185364904,
+       -506192760, 646735912, -1424722633, 745226976, 1019191717,
+       -190891744, -310320868, -373655022, -665117060, 830760000,
+       583906512, -330536027, 611092636, -321344259, -1255008904,
+       -777959046, -523043472, 88896910, 346062204, -163734816, 336635665,
+       906060268, -128891583, 740952564, 916767203, 296514859, 198670559,
+       358136672, -152253676, 12038867, -1469916749, -1020980597,
+       -897143313, 354240970, -97959800, 814172811, 1983363241, 264990663,
+       105154676, 1060463014, 430172143, 375111946, -824526943,
+       -708877751, -1377442616, -236559551, 684724584, 1602131358,
+       -42140186, -763499840, -605167, 98575879, -376577598, 1689746083,
+       -777973879, -1396984691, -187780326, 281040966, 1858859521,
+       158395760, 1022807978, -218458812, 811779708, 1495113833,
+       1192561226, 629539535, -1365196683, -1120253162, 1091681956,
+       134286445, 1172218369, -34093658, -137087343, -27869226,
+       -180889478, 55705436, 52362743, -1745516232, -926564477,
+       -513701675, -1666272054, 1457952810, 843953275, -478275722,
+       -1240291080, 101859661, -1606687523, 916365333, 314713310,
+       -22002688, 1019022641, -1171741314, -129050627, -211955813,
+       -1020176299, 1357865293, -609819628, 724533854, -1141449545,
+       22285231, -97731145, -302329687, 191910894, -1300709885,
+       -644951895, 640448036, -1289009824, 1445456129, 846416471,
+       1821291740, -1639640821, -712724532, -447475807, 132156847,
+       258067455, 324301319, 278586969, -1544082357, 636007277, 977122066,
+       127462480, 365126129, 1086276825, -432124148, 896598926,
+       -388550179, 273357331, -845018695, -1089465389, 384439820,
+       -558419772, 1476422025, 730712769, 190665059, -764968927,
+       -789708218, 637873581, 348429858, 1386000168, -638123594,
+       -842010345, -607926448, 19535163, -742771490, -18323344, 246155488,
+       350409468, 1290907730, -492566468, 300358636, 501876267, 252441807,
+       1233551975, -1431067042, 517177374, -1540299707, -948380761,
+       1253997663, 693795998, 148707823, 152894502, 98729538, -30042824,
+       -563057441, 723726409, 367338961, 1395435261, 217868876,
+       1220652431, 953572083, -1134905155, -734486813, -587470130,
+       -864647866, 1030737023, 781798521, -321076732, -460548153,
+       122681678, -873728847, -1286304399, -75472885, 113390881,
+       -1556849198, -1070802176, 924389470, 957478910, 5974049, 709413506,
+       476334647, 572869787, 776298405, -8822420, -99326499, -707855342,
+       -1187216303, 668038414, 262454769, -1120293198, -32011040,
+       249812104, -101835410, 1082281087, -570183855, -954535179,
+       1384361473, -983199686, 2017611313, 328926483, -878162849,
+       -1202254181, -225604951, 966898955, 247213529, -1257544612,
+       -197005970, -1039902730, -1947925142, 1752780907, -313410699,
+       -464474556, 416580338, -1063356643, -292212702, 57509168,
+       1034124629, 1059212593, 468522867, 845369497, 1872717306,
+       -1216544764, -1419907623, 1376869956, -66585488, -1590974467,
+       -367070705, -1456529060, 791844031, 336217635, -1106832215,
+       1476739427, -751018210, -1411671555, -1880387375, -1714242595,
+       1169006474, -479442380, -892267555, -1471250266, -267888858,
+       808634418, 1324777189, -585449929, 1127186951, 468768901,
+       -2002989138, -52352849, 186493053, 1258464606, 117157186,
+       445919258, 908401949, -1112221136, 863904453, -942718649,
+       796754809, -38943966, -781978872, -56814078, 1273857459,
+       -1781920832, 209979504, 811828269, -1150814437, 850061883,
+       -532968763, 252506408, -885025629, 391567580, -1295702482,
+       574894420, 1462248349, 1622584325, -88443443, -1122006092,
+       -169758578, 456282338, -443233309, 436693483, -956563815,
+       -480221349, 435252860, -1114099391, 1060053979, -470893945,
+       -1273682879, -734596176, 639950927, -1278648701, 306274747,
+       -410562146, 1137869228, -1970746553, 1313830798, 1248071822,
+       -247297704, 1015218053, -1607348116, -261817613, -821413148,
+       -782942639, -628711083, 240953091, -629550668, -1584736319,
+       856616893, -186759752, 197905373, 541638393, 603407919, -278480495,
+       410077039, 544065371, -1509627427, 402918436, -450463799,
+       -131169308, 249920630, 1079548609, -927911828, 1444577689,
+       -353002528, -224292462, 1247795279, -790844631, -40427503,
+       59829765, -332587567, 1319862109, -1261340753, 121711726,
+       1342756342, -643495787, 100326201, -934436714, -69134888,
+       -898880561, -379524737, -577234570, -805827092, -1575493557,
+       -289920678, -476605057, 1235714994, -317239591, 418553949,
+       410053338, -204985448, 1206503615, 202610372, -932244873,
+       782207875, -288661931, -806814809, 1270953679, 2060991595,
+       -311412846, 327279979, 1148562672, 55239149, -610114433,
+       -1511688434, 87619740, -433503545, 326150519, -581293393,
+       -97417688, -289736140, -1543886029, -1251976119, 1585774446,
+       1570011421, 432602745, 486343696, -834680922, 265004849,
+       -1132107706, 502627197, -815873818, 249635389, 1985714127,
+       -1095817653, -130743522, -645266828, -334621094, 199921747,
+       1059256177, 378031303, 1519740920, 925540689, 1405957844,
+       1387748290, -56138046, -770637828, -187984510, -1361735163,
+       1294823206, -608941238, 451860688, -510549867, 1143516283,
+       -779090703, 1459305047, -600335915, -1684168049, 1516622316,
+       -631733335, -4360068, 499778796, 587600402, -1296000335, -37959743,
+       -1084203927, 1162902556, 246374600, -515103645, 341724568,
+       -702303954, 452229900, 485108287, 1170048553, -1510148355,
+       611133912, 1997927484, -142022671, -724776653, -336090522,
+       708283514, -1409637378, -2052637687, 376055110, 226628105,
+       -1714452033, -1776158002, 369167930, 1800807012, 710680889,
+       -69951947, -1223849766, -1862239787, 218536127, -656411794,
+       -1202269188, 609634805, -224425858, 519797951, 284223080,
+       869408930, 270750206, -544967439, 2097168510, 31650971, -600985417,
+       -165303097, -257809088, -1043223971, 1827891621, -156827355,
+       499719603
+};
+
+#define        IVEC_LEN        (nitems(initvector))
+
+#endif
index 1c0bc31ae0126f4fb2cf76e22baf2a9119e4c247..4dcb26f989ce6750d4f365e407f134ddc63a8669 100644 (file)
@@ -20,6 +20,7 @@
 
 int fts_find_main(int argc, char *argv[]);
 
+#ifndef DARWINTEST
 static char *
 stat_str(struct stat *st)
 {
@@ -33,6 +34,7 @@ stat_str(struct stat *st)
                        st->st_blocks, st->st_blksize, st->st_flags, st->st_gen);
        return charbuf;
 }
+#endif // DARWINTEST
 
 int
 fts_find_main(int argc, char *argv[])
@@ -42,6 +44,8 @@ fts_find_main(int argc, char *argv[])
 
        bool print_children = false;
        int fts_options = FTS_COMFOLLOW | FTS_XDEV;
+       optind = 1;
+       optreset = 1;
 
        int ch;
        while ((ch = getopt(argc, argv, "lpcdsS")) != -1){
@@ -94,7 +98,7 @@ fts_find_main(int argc, char *argv[])
                        printf("%s (%s): 0x%x\n", ftse->fts_path, ftse->fts_name, ftse->fts_info);
                        if (!(fts_options & (FTS_NOSTAT|FTS_NOSTAT_TYPE))) printf("\t\t%s\n", stat_str(ftse->fts_statp));
                }
-#endif
+#endif // DARWINTEST
                if (print_children){
                        FTSENT *child = fts_children(fts, 0);
                        while (child){
@@ -103,7 +107,7 @@ fts_find_main(int argc, char *argv[])
                                        printf("\t%s (%s): 0x%x\n", child->fts_path, child->fts_name, child->fts_info);
                                        if (!(fts_options & (FTS_NOSTAT|FTS_NOSTAT_TYPE))) printf("\t\t%s\n", stat_str(child->fts_statp));
                                }
-#endif
+#endif // DARWINTEST
                                child = child->fts_link;
                        }
                }
@@ -123,4 +127,32 @@ T_DECL(fts_find, "A find(1) example in fts"){
                T_FAIL("fts_find() exited with error");
        }
 }
-#endif
+
+T_DECL(fts_find_empty_path, "Test result for empty path"){
+       char *paths[] = {"/System", "", NULL};
+
+       FTS *fts = fts_open_b(paths, 0, ^(const FTSENT **a, const FTSENT **b){
+               return strcmp((*a)->fts_name, (*b)->fts_name);
+       });
+       if (fts == NULL) {
+               T_FAIL("fts_open() failed");
+               return;
+       }
+
+       // The first entry name should be the empty string, because of the sort
+       // order. The second entry should be "System".
+       FTSENT *entry = fts_read(fts);
+       T_ASSERT_NOTNULL(entry, "First fts_read() returned NULL");
+       T_ASSERT_EQ_STR(entry->fts_name, "", "First entry name is empty");
+       T_ASSERT_EQ((int)entry->fts_info, FTS_NS, "First fts_info is FTS_NS");
+       T_ASSERT_EQ(entry->fts_errno, ENOENT, "First fts_errno is ENOENT");
+
+       entry = fts_read(fts);
+       T_ASSERT_NOTNULL(entry, "Second fts_read() returned NULL");
+       T_ASSERT_EQ_STR(entry->fts_name, "System", "Second entry name is System");
+       T_ASSERT_EQ((int)entry->fts_info, FTS_D, "Second fts_info is FTS_D");
+       T_ASSERT_EQ(entry->fts_errno, 0, "Second fts_errno is 0");
+
+       fts_close(fts);
+}
+#endif // DARWINTEST
index 3ec6e897836b2932411751497905da10f9544e55..d3aa4bf19f429cd936baf03be9cdda43f414875d 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <darwintest.h>
 
-T_DECL(PR_23679075, "converts a cyrillic a to uppercase")
+T_DECL(locale_PR_23679075, "converts a cyrillic a to uppercase")
 {
        locale_t loc = newlocale(LC_COLLATE_MASK|LC_CTYPE_MASK, "ru_RU", 0);
        T_ASSERT_NOTNULL(loc, "newlocale(LC_COLLATE_MASK|LC_CTYPE_MASK, \"ru_RU\", 0) should return a locale");
@@ -16,7 +16,7 @@ T_DECL(PR_23679075, "converts a cyrillic a to uppercase")
        freelocale(loc);
 }
 
-T_DECL(PR_24165555, "swprintf with Russian chars")
+T_DECL(locale_PR_24165555, "swprintf with Russian chars")
 {
     setlocale(LC_ALL, "ru_RU.UTF-8");
 
@@ -26,3 +26,9 @@ T_DECL(PR_24165555, "swprintf with Russian chars")
 
     setlocale(LC_ALL, "");
 }
+
+T_DECL(locale_PR_28774201, "return code on bad locale")
+{
+    T_EXPECT_NULL(newlocale(LC_COLLATE_MASK | LC_CTYPE_MASK, "foobar", NULL), NULL);
+    T_EXPECT_EQ(errno, ENOENT, NULL);
+}
index ff26ddcb778019f497ce65c7d74b0ba05d3bde35..96f9beb611615ed234e5caf2e0ee279de819e09e 100644 (file)
@@ -18,7 +18,7 @@ static const char template[] = TEMPLATE_BASE TEMPLATE_XS;
 
 static void test_mkostemp(int oflags);
 
-T_DECL(test_mkstemp, "basic mkstemp test")
+T_DECL(mkstemp, "basic mkstemp test")
 {
        char path[sizeof(template)];
        struct stat path_stat;
@@ -89,7 +89,7 @@ T_DECL(two_mkstemp_calls, "two mkstemp calls return different paths and fds")
                        "close must succeed for the second fd");
 }
 
-T_DECL(test_mktemp, "basic mktemp test")
+T_DECL(mktemp, "basic mktemp test")
 {
        char path[sizeof(template)];
 
@@ -103,7 +103,7 @@ T_DECL(test_mktemp, "basic mktemp test")
                        template, path);
 }
 
-T_DECL(test_mkdtemp, "basic mkdtemp test")
+T_DECL(mkdtemp, "basic mkdtemp test")
 {
        char path[sizeof(template)];
        struct stat dstat;
@@ -198,7 +198,7 @@ test_mkostemp(int oflags)
 // always does T_SKIP on OS X yields another issue. The compiler starts
 // demanding to mark the test function definition as noreturn. Just
 // don't compile the testcase for OS X.
-T_DECL(test_mkstemp_dprotected_np, "basic mkstemp_dprotected_np test")
+T_DECL(mkstemp_dprotected_np, "basic mkstemp_dprotected_np test")
 {
        char path[sizeof(template)];
        int fd;
index b173c253273f7806d61156f7c64787a00ca665ee..758ee488aa553dec81705bb93ea8d7a106853d71 100644 (file)
@@ -97,10 +97,7 @@ T_DECL(link_ntoa_overflow, "link_ntoa try to overflow")
 T_DECL(inet_ntop, "inet_ntop")
 {
        char *addresses4[] = { "1.2.3.4", "10.0.0.1", "2.2.2.2" };
-       char *addresses6[] = {
-               "2001:db8:85a3::8a2e:370:7334",
-               "::1", "::"
-       };
+       char *addresses6[] = { "2001:db8:85a3::8a2e:370:7334", "::1", "::" };
        for (int i = 0; i < sizeof(addresses4)/sizeof(addresses4[0]); i++){
                struct in_addr addr4;
                char buf[64];
@@ -114,7 +111,70 @@ T_DECL(inet_ntop, "inet_ntop")
                char buf[64];
                T_EXPECT_EQ(inet_pton(AF_INET6, addresses6[i], &addr6), 1, "inet_pton(AF_INET6, %s)", addresses6[i]);
                char *str = inet_ntop(AF_INET6, &addr6, buf, sizeof(buf));
-               T_EXPECT_NOTNULL(str, "inet_ntop(AF_INET) of %s", addresses6[i]);
+               T_EXPECT_NOTNULL(str, "inet_ntop(AF_INET6) of %s", addresses6[i]);
                T_EXPECT_EQ_STR(str, addresses6[i], "round-trip of %s", addresses6[i]);
        }
 }
+
+struct testcase {
+       const char *in_addr;
+       const char *expected_out_addr;
+};
+
+static const struct testcase test_addrs[] = {
+       { "1:2:3:4:5::1.2.3.4", "1:2:3:4:5:0:102:304" },
+       { "1:0:3:0:5:0:7:8", "1:0:3:0:5:0:7:8" },
+       { "0:0:3:0:0:0:7:8", "0:0:3::7:8" },
+       { "0:0:3:0:5:0:7:8", "::3:0:5:0:7:8" },
+       { "0:0:0:0:0:0:0:0", "::" },
+       { "0:0:0:0:0:1:0:0", "::1:0:0" },
+       { "1:0:0:0:0:0:0:0", "1::" },
+       { "0:0:0:1:0:0:0:0", "0:0:0:1::" },
+       { "1:0:0:0:0:0:0:1", "1::1" },
+       { "1:2:3:4:5:6:0:0", "1:2:3:4:5:6::" },
+       { "1:2:3:4:5:0:0:0", "1:2:3:4:5::" },
+};
+
+T_DECL(inet_ntop_resolve_zeroes, "Check for proper behavior when shortening zeroes w/ inet_ntop")
+{
+       // Take ip addrs as text, convert to binary and back.
+       // Upon converting back, they should adhere to the IPv6 guidelines.
+       for (int i = 0; i < sizeof(test_addrs)/sizeof(struct testcase); ++i) {
+               struct in6_addr addr6;
+               char buf[64];
+               char *in_addr = test_addrs[i].in_addr;
+               char *expected_out_addr = test_addrs[i].expected_out_addr;
+               T_EXPECT_EQ(inet_pton(AF_INET6, in_addr, &addr6), 1, "inet_pton(AF_INET6, %s)", in_addr);
+               char *str = inet_ntop(AF_INET6, &addr6, buf, sizeof(buf));
+               T_EXPECT_NOTNULL(str, "inet_ntop(AF_INET6) of %s", in_addr);
+               // <rdar://problem/32825795> Single-zero tests will fail until change
+               // implemented.
+               if (i < 2) {
+                       T_EXPECTFAIL;
+               }
+               T_EXPECT_EQ_STR(str, expected_out_addr, NULL);
+       }
+
+       // Same test, but step through the possible range of ipv6 values.
+       for (int i = 0x0; i < 0x10000; ++i) {
+               struct in6_addr addr6;
+               char buf[64];
+               char in_addr[64];
+               sprintf(in_addr, "1:1:1:1:1:1:1:%x", i);
+               char *expected_out_addr = in_addr;
+               T_QUIET;
+               T_EXPECT_EQ(inet_pton(AF_INET6, in_addr, &addr6), 1, "inet_pton(AF_INET6, %s)", in_addr);
+               char *str = inet_ntop(AF_INET6, &addr6, buf, sizeof(buf));
+               T_QUIET;
+               T_EXPECT_NOTNULL(str, "inet_ntop(AF_INET6) of %s", in_addr);
+               T_QUIET;
+               // <rdar://problem/32825795>
+               if (i == 0) {
+                       T_PASS("Never displayed"); // Cancel out the T_QUIET
+                       T_EXPECTFAIL;
+               }
+               T_EXPECT_EQ_STR(str, expected_out_addr, NULL);
+       }
+       T_PASS("Passed ipv6 value testing");
+
+}
diff --git a/tests/netbsd_fmemopen.c b/tests/netbsd_fmemopen.c
new file mode 100644 (file)
index 0000000..4cf79ff
--- /dev/null
@@ -0,0 +1,1010 @@
+/* $NetBSD: t_fmemopen.c,v 1.4 2013/10/19 17:45:00 christos Exp $ */
+
+/*-
+ * Copyright (c)2010 Takehiko NOZAKI,
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <darwintest.h>
+
+static const char *mode_rwa[] = {
+    "r", "rb", "r+", "rb+", "r+b",
+    "w", "wb", "w+", "wb+", "w+b",
+    "a", "ab", "a+", "ab+", "a+b",
+    NULL
+};
+
+static const char *mode_r[] = { "r", "rb", "r+", "rb+", "r+b", NULL };
+static const char *mode_w[] = { "w", "wb", "w+", "wb+", "w+b", NULL };
+static const char *mode_a[] = { "a", "ab", "a+", "ab+", "a+b", NULL };
+
+static struct testcase {
+       const char *s;
+       off_t n;
+} testcases[] = {
+#define TESTSTR(s)     { s, sizeof(s)-1 }
+       TESTSTR("\0he quick brown fox jumps over the lazy dog"),
+       TESTSTR("T\0e quick brown fox jumps over the lazy dog"),
+       TESTSTR("Th\0 quick brown fox jumps over the lazy dog"),
+       TESTSTR("The\0quick brown fox jumps over the lazy dog"),
+       TESTSTR("The \0uick brown fox jumps over the lazy dog"),
+       TESTSTR("The q\0ick brown fox jumps over the lazy dog"),
+       TESTSTR("The qu\0ck brown fox jumps over the lazy dog"),
+       TESTSTR("The qui\0k brown fox jumps over the lazy dog"),
+       TESTSTR("The quic\0 brown fox jumps over the lazy dog"),
+       TESTSTR("The quick\0brown fox jumps over the lazy dog"),
+       TESTSTR("The quick \0rown fox jumps over the lazy dog"),
+       TESTSTR("The quick b\0own fox jumps over the lazy dog"),
+       TESTSTR("The quick br\0wn fox jumps over the lazy dog"),
+       TESTSTR("The quick bro\0n fox jumps over the lazy dog"),
+       TESTSTR("The quick brow\0 fox jumps over the lazy dog"),
+       TESTSTR("The quick brown\0fox jumps over the lazy dog"),
+       TESTSTR("The quick brown \0ox jumps over the lazy dog"),
+       TESTSTR("The quick brown f\0x jumps over the lazy dog"),
+       TESTSTR("The quick brown fo\0 jumps over the lazy dog"),
+       TESTSTR("The quick brown fox\0jumps over the lazy dog"),
+       TESTSTR("The quick brown fox \0umps over the lazy dog"),
+       TESTSTR("The quick brown fox j\0mps over the lazy dog"),
+       TESTSTR("The quick brown fox ju\0ps over the lazy dog"),
+       TESTSTR("The quick brown fox jum\0s over the lazy dog"),
+       TESTSTR("The quick brown fox jump\0 over the lazy dog"),
+       TESTSTR("The quick brown fox jumps\0over the lazy dog"),
+       TESTSTR("The quick brown fox jumps \0ver the lazy dog"),
+       TESTSTR("The quick brown fox jumps o\0er the lazy dog"),
+       TESTSTR("The quick brown fox jumps ov\0r the lazy dog"),
+       TESTSTR("The quick brown fox jumps ove\0 the lazy dog"),
+       TESTSTR("The quick brown fox jumps over\0the lazy dog"),
+       TESTSTR("The quick brown fox jumps over \0he lazy dog"),
+       TESTSTR("The quick brown fox jumps over t\0e lazy dog"),
+       TESTSTR("The quick brown fox jumps over th\0 lazy dog"),
+       TESTSTR("The quick brown fox jumps over the\0lazy dog"),
+       TESTSTR("The quick brown fox jumps over the \0azy dog"),
+       TESTSTR("The quick brown fox jumps over the l\0zy dog"),
+       TESTSTR("The quick brown fox jumps over the la\0y dog"),
+       TESTSTR("The quick brown fox jumps over the laz\0 dog"),
+       TESTSTR("The quick brown fox jumps over the lazy\0dog"),
+       TESTSTR("The quick brown fox jumps over the lazy \0og"),
+       TESTSTR("The quick brown fox jumps over the lazy d\0g"),
+       TESTSTR("The quick brown fox jumps over the lazy do\0"),
+       TESTSTR("The quick brown fox jumps over the lazy dog"),
+       { NULL, 0 },
+};
+
+T_DECL(netbsd_fmemopen_test00, "")
+{
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       for (p = &mode_rwa[0]; *p != NULL; ++p) {
+               fp = fmemopen(&buf[0], sizeof(buf), *p);
+/*
+ * Upon successful completion, fmemopen() shall return a pointer to the
+ * object controlling the stream.
+ */
+               T_EXPECT_NOTNULL(fp, NULL);
+
+               T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+       }
+}
+
+T_DECL(netbsd_fmemopen_test01, "")
+{
+       const char **p;
+       const char *mode[] = {
+           "r+", "rb+", "r+b",
+           "w+", "wb+", "w+b",
+           "a+", "ab+", "a+b",
+           NULL
+       };
+       FILE *fp;
+
+       for (p = &mode[0]; *p != NULL; ++p) {
+/*
+ * If a null pointer is specified as the buf argument, fmemopen() shall
+ * allocate size bytes of memory as if by a call to malloc().
+ */
+               fp = fmemopen(NULL, BUFSIZ, *p);
+               T_EXPECT_NOTNULL(fp, NULL);
+
+/*
+ * If buf is a null pointer, the initial position shall always be set
+ * to the beginning of the buffer.
+ */
+               T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+               T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+       }
+}
+
+T_DECL(netbsd_fmemopen_test02, "")
+{
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       for (p = &mode_r[0]; *p != NULL; ++p) {
+
+               memset(&buf[0], 0x1, sizeof(buf));
+               fp = fmemopen(&buf[0], sizeof(buf), *p);
+               T_EXPECT_NOTNULL(fp, NULL);
+
+/*
+ * This position is initially set to either the beginning of the buffer
+ * (for r and w modes)
+ */
+               T_EXPECT_EQ((unsigned char)buf[0], 0x1, NULL);
+               T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+/*
+ * The stream also maintains the size of the current buffer contents.
+ * For modes r and r+ the size is set to the value given by the size argument.
+ */
+#if !defined(__GLIBC__)
+               T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)0, SEEK_END), NULL);
+               T_EXPECT_EQ(ftello(fp), (off_t)sizeof(buf), NULL);
+#endif
+               T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+       }
+}
+
+T_DECL(netbsd_fmemopen_test03, "")
+{
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+       for (p = &mode_w[0]; *p != NULL; ++p) {
+
+               memset(&buf[0], 0x1, sizeof(buf));
+               fp = fmemopen(&buf[0], sizeof(buf), *p);
+               T_EXPECT_NOTNULL(fp, NULL);
+
+/*
+ * This position is initially set to either the beginning of the buffer
+ * (for r and w modes)
+ */
+               T_EXPECT_EQ(buf[0], '\0', NULL);
+               T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+/*
+ * For modes w and w+ the initial size is zero
+ */
+               T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)0, SEEK_END), NULL);
+               T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+               T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+       }
+}
+
+T_DECL(netbsd_fmemopen_test04, "")
+{
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+/*
+ * or to the first null byte in the buffer (for a modes)
+ */
+       for (p = &mode_a[0]; *p != NULL; ++p) {
+
+               memset(&buf[0], 0x1, sizeof(buf));
+               fp = fmemopen(&buf[0], sizeof(buf), *p);
+               T_EXPECT_NOTNULL(fp, NULL);
+
+               T_EXPECT_EQ((unsigned char)buf[0], 0x1, NULL);
+
+/* If no null byte is found in append mode,
+ * the initial position is set to one byte after the end of the buffer.
+ */
+#if !defined(__GLIBC__)
+               T_EXPECT_EQ(ftello(fp), (off_t)sizeof(buf), NULL);
+#endif
+
+/*
+ * and for modes a and a+ the initial size is either the position of the
+ * first null byte in the buffer or the value of the size argument
+ * if no null byte is found.
+ */
+#if !defined(__GLIBC__)
+               T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)0, SEEK_END), NULL);
+               T_EXPECT_EQ(ftello(fp), (off_t)sizeof(buf), NULL);
+#endif
+
+               T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+       }
+}
+
+T_DECL(netbsd_fmemopen_test05, "")
+{
+       const char **p;
+       FILE *fp;
+       char buf[BUFSIZ];
+
+       for (p = &mode_rwa[0]; *p != NULL; ++p) {
+/*
+ * Otherwise, a null pointer shall be returned, and errno shall be set
+ * to indicate the error.
+ */
+               errno = 0;
+               fp = fmemopen(NULL, (size_t)0, *p);
+               T_EXPECT_NULL(fp, NULL);
+               T_EXPECT_EQ(errno, EINVAL, NULL);
+
+               errno = 0;
+               fp = fmemopen((void *)&buf[0], 0, *p);
+               T_EXPECT_NULL(fp, NULL);
+               T_EXPECT_EQ(errno, EINVAL, NULL);
+       }
+}
+
+T_DECL(netbsd_fmemopen_test06, "")
+{
+       const char **p;
+       const char *mode[] = { "", " ", "???", NULL };
+       FILE *fp;
+
+       for (p = &mode[0]; *p != NULL; ++p) {
+/*
+ * The value of the mode argument is not valid.
+ */
+               fp = fmemopen(NULL, 1, *p);
+               T_EXPECT_NULL(fp, NULL);
+               T_EXPECT_EQ(errno, EINVAL, NULL);
+       }
+}
+
+T_DECL(netbsd_fmemopen_test07, "")
+{
+#if !defined(__GLIBC__)
+       const char **p;
+       const char *mode[] = {
+           "r", "rb",
+           "w", "wb",
+           "a", "ab",
+           NULL
+       };
+       FILE *fp;
+
+       for (p = &mode[0]; *p != NULL; ++p) {
+/*
+ * Because this feature is only useful when the stream is opened for updating
+ * (because there is no way to get a pointer to the buffer) the fmemopen()
+ * call may fail if the mode argument does not include a '+' . 
+ */
+               errno = 0;
+               fp = fmemopen(NULL, 1, *p);
+               T_EXPECT_NULL(fp, NULL);
+               T_EXPECT_EQ(errno, EINVAL, NULL);
+       }
+#endif
+}
+
+T_DECL(netbsd_fmemopen_test08, "")
+{
+#if !defined(__GLIBC__)
+       const char **p;
+       const char *mode[] = {
+           "r+", "rb+", "r+b",
+           "w+", "wb+", "w+b",
+           "a+", "ab+", "a+b",
+           NULL
+       };
+       FILE *fp;
+
+       for (p = &mode[0]; *p != NULL; ++p) {
+/*
+ * The buf argument is a null pointer and the allocation of a buffer of
+ * length size has failed.
+ */
+               fp = fmemopen(NULL, SIZE_MAX, *p);
+               T_EXPECT_NULL(fp, NULL);
+               T_EXPECT_EQ(errno, ENOMEM, NULL);
+       }
+#endif
+}
+
+/*
+ * test09 - test14:
+ * An attempt to seek a memory buffer stream to a negative position or to a
+ * position larger than the buffer size given in the size argument shall fail.
+ */
+
+T_DECL(netbsd_fmemopen_test09, "")
+{
+       struct testcase *t;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+       off_t i;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               for (p = &mode_rwa[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf[0], t->s, t->n);
+                       fp = fmemopen(&buf[0], (size_t)t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+
+/*
+ * test fmemopen_seek(SEEK_SET)
+ */
+                       /* zero */
+                       T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)0, SEEK_SET), NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+                       /* positive */
+                       for (i = (off_t)1; i <= (off_t)t->n; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, i, SEEK_SET), NULL);
+                               T_EXPECT_EQ(ftello(fp), i, NULL);
+                       }
+                       /* positive + OOB */
+                       T_EXPECT_EQ(fseeko(fp, t->n + 1, SEEK_SET), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), t->n, NULL);
+
+                       /* negative + OOB */
+                       T_EXPECT_EQ(fseeko(fp, (off_t)-1, SEEK_SET), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), t->n, NULL);
+
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+static const char *mode_rw[] = {
+    "r", "rb", "r+", "rb+", "r+b",
+    "w", "wb", "w+", "wb+", "w+b",
+    NULL
+};
+
+T_DECL(netbsd_fmemopen_test10, "")
+{
+       struct testcase *t;
+       off_t i;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               for (p = &mode_rw[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf[0], t->s, t->n);
+                       fp = fmemopen(&buf[0], (size_t)t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+
+/*
+ * test fmemopen_seek(SEEK_CUR)
+ */
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+                       /* zero */
+                       T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)0, SEEK_CUR), NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+                       /* negative & OOB */
+                       T_EXPECT_EQ(fseeko(fp, (off_t)-1, SEEK_CUR), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+                       /* positive */
+                       for (i = 0; i < (off_t)t->n; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)1, SEEK_CUR), NULL);
+                               T_EXPECT_EQ(ftello(fp), i + 1, NULL);
+                       }
+
+                       /* positive & OOB */
+                       T_EXPECT_EQ(fseeko(fp, (off_t)1, SEEK_CUR), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+T_DECL(netbsd_fmemopen_test11, "")
+{
+       struct testcase *t;
+       off_t len, rest, i;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       /* test fmemopen_seek(SEEK_CUR) */
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               len = (off_t)strnlen(t->s, (size_t)t->n);
+               rest = (off_t)t->n - len;
+               for (p = &mode_a[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf[0], t->s, t->n);
+                       fp = fmemopen(&buf[0], (size_t)t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+/*
+ * test fmemopen_seek(SEEK_CUR)
+ */
+#if defined(__GLIBC__)
+                       if (i < (off_t)t->n) {
+#endif
+                       /* zero */
+                       T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)0, SEEK_CUR), NULL);
+                       T_EXPECT_EQ(ftello(fp), len, NULL);
+
+                       /* posive */
+                       for (i = (off_t)1; i <= rest; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)1, SEEK_CUR), NULL);
+                               T_EXPECT_EQ(ftello(fp), len + i, NULL);
+                       }
+
+                       /* positive + OOB */
+                       T_EXPECT_EQ(fseeko(fp, (off_t)1, SEEK_CUR), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+
+                       /* negative */
+                       for (i = (off_t)1; i <= (off_t)t->n; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)-1, SEEK_CUR), NULL);
+                               T_EXPECT_EQ(ftello(fp), (off_t)t->n - i, NULL);
+                       }
+
+                       /* negative + OOB */
+                       T_EXPECT_EQ(fseeko(fp, (off_t)-1, SEEK_CUR), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+#if defined(__GLIBC__)
+                       }
+#endif
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+#if 0
+T_DECL(netbsd_fmemopen_test12, "")
+{
+       struct testcase *t;
+       off_t len, rest, i;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       /* test fmemopen_seek(SEEK_END) */
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               len = (off_t)strnlen(t->s, t->n);
+               rest = t->n - len;
+               for (p = &mode_r[0]; *p != NULL; ++p) {
+
+                       memcpy(buf, t->s, t->n);
+                       fp = fmemopen(&buf[0], t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+
+/*
+ * test fmemopen_seek(SEEK_END)
+ */
+#if !defined(__GLIBC__)
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+                       /* zero */
+                       T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)0, SEEK_END), NULL);
+                       T_EXPECT_EQ(ftello(fp), len, NULL);
+
+                       /* positive + OOB */
+                       T_EXPECT_EQ(fseeko(fp, rest + 1, SEEK_END), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), len, NULL);
+
+                       /* negative + OOB */
+                       T_EXPECT_EQ(fseeko(fp, -(len + 1), SEEK_END), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), len, NULL);
+
+                       /* positive */
+                       for (i = 1; i <= rest; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, i, SEEK_END), NULL);
+                               T_EXPECT_EQ(ftello(fp), len + i, NULL);
+                       }
+
+                       /* negative */
+                       for (i = 1; i < len; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, -i, SEEK_END), NULL);
+                               T_EXPECT_EQ(ftello(fp), len - i, NULL);
+                       }
+#endif
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+#endif // 0
+
+T_DECL(netbsd_fmemopen_test13, "")
+{
+       struct testcase *t;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       /* test fmemopen_seek(SEEK_END) */
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               for (p = &mode_w[0]; *p != NULL; ++p) {
+
+                       memcpy(buf, t->s, t->n);
+                       fp = fmemopen(&buf[0], (size_t)t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+/*
+ * test fmemopen_seek(SEEK_END)
+ */
+#if !defined(__GLIBC__)
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+                       T_EXPECT_EQ(buf[0], '\0', NULL);
+
+                       /* zero */
+                       T_EXPECT_POSIX_ZERO(fseeko(fp, (off_t)0, SEEK_END), NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+                       /* positive + OOB */
+                       T_EXPECT_EQ(fseeko(fp, (off_t)t->n + 1, SEEK_END), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+
+                       /* negative + OOB */
+                       T_EXPECT_EQ(fseeko(fp, -1, SEEK_END), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+#endif
+
+#if 0
+                       /* positive */
+                       for (int i = 1; i <= t->n; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, i, SEEK_END), NULL);
+                               T_EXPECT_EQ(ftello(fp), i, NULL);
+                       }
+#endif
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+T_DECL(netbsd_fmemopen_test14, "")
+{
+       struct testcase *t;
+       off_t len, rest, i;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       /* test fmemopen_seek(SEEK_END) */
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               len = (off_t)strnlen(t->s, (size_t)t->n);
+               rest = (off_t)t->n - len;
+               for (p = &mode_a[0]; *p != NULL; ++p) {
+
+                       memcpy(buf, t->s, t->n);
+                       fp = fmemopen(&buf[0], (size_t)t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+/*
+ * test fmemopen_seek(SEEK_END)
+ */
+#if !defined(__GLIBC__)
+                       T_EXPECT_EQ(ftello(fp), len, NULL);
+
+                       /* zero */
+                       T_EXPECT_POSIX_ZERO(fseeko(fp, 0, SEEK_END), NULL);
+                       T_EXPECT_EQ(ftello(fp), len, NULL);
+
+                       /* positive + OOB */
+                       T_EXPECT_EQ(fseeko(fp, rest + 1, SEEK_END), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), len, NULL);
+
+                       /* negative + OOB */
+                       T_EXPECT_EQ(fseeko(fp, -(len + 1), SEEK_END), -1, NULL);
+                       T_EXPECT_EQ(ftello(fp), len, NULL);
+
+#if 0
+                       /* positive */
+                       for (i = 1; i <= rest; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, i, SEEK_END), NULL);
+                               T_EXPECT_EQ(ftello(fp), len + i, NULL);
+                       }
+#endif
+
+                       /* negative */
+                       for (i = 1; i < len; ++i) {
+                               T_EXPECT_POSIX_ZERO(fseeko(fp, -i, SEEK_END), NULL);
+                               T_EXPECT_EQ(ftello(fp), len - i, NULL);
+                       }
+#endif
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+#if 0
+
+static const char *mode_rw1[] = {
+    "r", "rb", "r+", "rb+", "r+b",
+    "w+", "wb+",
+    NULL
+};
+
+/* test15 - 18:
+ * When a stream open for writing is flushed or closed, a null byte is written
+ * at the current position or at the end of the buffer, depending on the size
+ * of the contents.
+ */
+
+T_DECL(netbsd_fmemopen_test15, "")
+{
+       struct testcase *t;
+       const char **p;
+       char buf0[BUFSIZ];
+       FILE *fp;
+       int i;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               for (p = &mode_rw1[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf0[0], t->s, t->n);
+                       fp = fmemopen(&buf0[0], t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+/*
+ * test fmemopen_read + fgetc(3)
+ */
+                       for (i = 0; i < t->n; ++i) {
+                               T_EXPECT_EQ(ftello(fp), (off_t)i, NULL);
+                               T_EXPECT_EQ(fgetc(fp), buf0[i], NULL);
+                               T_EXPECT_EQ(feof(fp), 0, NULL);
+                               T_EXPECT_EQ(ftello(fp), (off_t)i + 1, NULL);
+                       }
+                       T_EXPECT_EQ(fgetc(fp), EOF, NULL);
+                       T_EXPECT_NE(feof(fp), 0, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+T_DECL(netbsd_fmemopen_test16, "")
+{
+       struct testcase *t;
+       const char **p;
+       char buf0[BUFSIZ], buf1[BUFSIZ];
+       FILE *fp;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               for (p = &mode_rw1[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf0[0], t->s, t->n);
+                       buf1[t->n] = 0x1;
+                       fp = fmemopen(&buf0[0], t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+/*
+ * test fmemopen_read + fread(4)
+ */
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+                       T_EXPECT_EQ(fread(&buf1[0], 1, sizeof(buf1), fp), (size_t)t->n, NULL);
+                       T_EXPECT_NE(feof(fp), 0, NULL);
+                       T_EXPECT_EQ(memcmp(&buf0[0], &buf1[0], t->n), 0, NULL);
+                       T_EXPECT_EQ((unsigned char)buf1[t->n], 0x1, NULL);
+
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+const char *mode_a1[] = { "a+", "ab+", NULL };
+
+T_DECL(netbsd_fmemopen_test17, "")
+{
+       struct testcase *t;
+       size_t len;
+       int i;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               len = strnlen(t->s, t->n);
+               for (p = &mode_a1[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf[0], t->s, t->n);
+                       fp = fmemopen(&buf[0], t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+/*
+ * test fmemopen_read + fgetc(3)
+ */
+#if defined(__GLIBC__)
+                       if (i < t->n) {
+#endif
+                       for (i = len; i < t->n; ++i) {
+                               T_EXPECT_EQ(ftello(fp), (off_t)i, NULL);
+                               T_EXPECT_EQ(fgetc(fp), buf[i], NULL);
+                               T_EXPECT_EQ(feof(fp), 0, NULL);
+                               T_EXPECT_EQ(ftello(fp), (off_t)i + 1, NULL);
+                       }
+                       T_EXPECT_EQ(fgetc(fp), EOF, NULL);
+                       T_EXPECT_NE(feof(fp), 0, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+                       rewind(fp);
+                       for (i = 0; i < t->n; ++i) {
+                               T_EXPECT_EQ(ftello(fp), (off_t)i, NULL);
+                               T_EXPECT_EQ(fgetc(fp), buf[i], NULL);
+                               T_EXPECT_EQ(feof(fp), 0, NULL);
+                               T_EXPECT_EQ(ftello(fp), (off_t)i + 1, NULL);
+                       }
+                       T_EXPECT_EQ(fgetc(fp), EOF, NULL);
+                       T_EXPECT_NE(feof(fp), 0, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+#if defined(__GLIBC__)
+                       }
+#endif
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+T_DECL(netbsd_fmemopen_test18, "")
+{
+       struct testcase *t;
+       size_t len;
+       const char **p;
+       char buf0[BUFSIZ], buf1[BUFSIZ];
+       FILE *fp;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               len = strnlen(t->s, t->n);
+               for (p = &mode_a1[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf0[0], t->s, t->n);
+                       buf1[t->n - len] = 0x1;
+                       fp = fmemopen(&buf0[0], t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+/*
+ * test fmemopen_read + fread(3)
+ */
+#if defined(__GLIBC__)
+                       if (i < t->n) {
+#endif
+                       T_EXPECT_EQ(ftello(fp), (off_t)len, NULL);
+                       T_EXPECT_EQ(fread(&buf1[0], 1, sizeof(buf1), fp)
+                          , t->n - len, NULL);
+                       T_EXPECT_NE(feof(fp), 0, NULL);
+                       T_EXPECT_FALSE(memcmp(&buf0[len], &buf1[0], t->n - len));
+                       T_EXPECT_EQ((unsigned char)buf1[t->n - len], 0x1, NULL);
+                       rewind(fp);
+                       buf1[t->n] = 0x1;
+                       T_EXPECT_EQ(ftello(fp), (off_t)0, NULL);
+                       T_EXPECT_EQ(fread(&buf1[0], 1, sizeof(buf1), fp)
+                          , (size_t)t->n, NULL);
+                       T_EXPECT_NE(feof(fp), 0, NULL);
+                       T_EXPECT_FALSE(memcmp(&buf0[0], &buf1[0], t->n));
+                       T_EXPECT_EQ((unsigned char)buf1[t->n], 0x1, NULL);
+#if defined(__GLIBC__)
+                       }
+#endif
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+/*
+ * test19 - test22:
+ * If a stream open for update is flushed or closed and the last write has
+ * advanced the current buffer size, a null byte is written at the end of the
+ * buffer if it fits.
+ */
+
+const char *mode_rw2[] = {
+    "r+", "rb+", "r+b",
+    "w", "wb", "w+", "wb+", "w+b",
+    NULL
+};
+
+T_DECL(netbsd_fmemopen_test19, "")
+{
+       struct testcase *t;
+       int i;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               for (p = &mode_rw2[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf[0], t->s, t->n);
+                       buf[t->n] = 0x1;
+                       fp = fmemopen(&buf[0], t->n + 1, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+                       setbuf(fp, NULL);
+/*
+ * test fmemopen_write + fputc(3)
+ */
+                       for (i = 0; i < t->n; ++i) {
+                               T_EXPECT_EQ(ftello(fp), (off_t)i, NULL);
+                               T_EXPECT_EQ(fputc(t->s[i], fp), t->s[i], NULL);
+                               T_EXPECT_EQ(buf[i], t->s[i], NULL);
+                               T_EXPECT_EQ(ftello(fp), (off_t)i + 1, NULL);
+                               T_EXPECT_EQ(buf[i], t->s[i], NULL);
+#if !defined(__GLIBC__)
+                               T_EXPECT_EQ(buf[i + 1], '\0', NULL);
+#endif
+                       }
+
+/* don't accept non nul character at end of buffer */
+                       T_EXPECT_EQ(fputc(0x1, fp), EOF, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+                       T_EXPECT_EQ(feof(fp), 0, NULL);
+
+/* accept nul character at end of buffer */
+                       T_EXPECT_EQ(fputc('\0', fp), '\0', NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n + 1, NULL);
+                       T_EXPECT_EQ(feof(fp), 0, NULL);
+
+/* reach EOF */
+                       T_EXPECT_EQ(fputc('\0', fp), EOF, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n + 1, NULL);
+
+                       /* compare */
+                       T_EXPECT_EQ(memcmp(&buf[0], t->s, t->n), 0, NULL);
+                       T_EXPECT_EQ(buf[t->n], '\0', NULL);
+
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+T_DECL(netbsd_fmemopen_test20, "")
+{
+       struct testcase *t;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               for (p = &mode_rw2[0]; *p != NULL; ++p) {
+
+                       memcpy(&buf[0], t->s, t->n);
+                       buf[t->n] = 0x1;
+                       fp = fmemopen(&buf[0], t->n + 1, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+                       setbuf(fp, NULL);
+                       T_EXPECT_EQ(fwrite(t->s, 1, t->n, fp), (size_t)t->n, NULL);
+/*
+ * test fmemopen_write + fwrite(3)
+ */
+#if !defined(__GLIBC__)
+                       T_EXPECT_EQ(buf[t->n], '\0', NULL);
+
+/* don't accept non nul character at end of buffer */
+                       T_EXPECT_EQ(fwrite("\x1", 1, 1, fp), 0, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+                       T_EXPECT_EQ(feof(fp), 0, NULL);
+#endif
+
+/* accept nul character at end of buffer */
+                       T_EXPECT_EQ(fwrite("\x0", 1, 1, fp), 1, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n + 1, NULL);
+                       T_EXPECT_EQ(feof(fp), 0, NULL);
+
+/* reach EOF */
+                       T_EXPECT_EQ(fputc('\0', fp), EOF, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n + 1, NULL);
+
+/* compare */
+                       T_EXPECT_EQ(memcmp(&buf[0], t->s, t->n), 0, NULL);
+                       T_EXPECT_EQ(buf[t->n], '\0', NULL);
+
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+T_DECL(netbsd_fmemopen_test21, "")
+{
+       struct testcase *t;
+       int len, i;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       for (t = &testcases[0]; t->s != NULL; ++t) {
+               len = strnlen(t->s, t->n);
+               for (p = &mode_a[0]; *p != NULL; ++p) {
+                       memcpy(&buf[0], t->s, t->n);
+                       fp = fmemopen(&buf[0], t->n, *p);
+                       T_EXPECT_NOTNULL(fp, NULL);
+                       setbuf(fp, NULL);
+/*
+ * test fmemopen_write + fputc(3)
+ */
+                       if (len < t->n) {
+                               for (i = len; i < t->n - 1; ++i) {
+                                       T_EXPECT_EQ(ftello(fp), (off_t)i, NULL);
+                                       T_EXPECT_EQ(fputc(t->s[i - len], fp)
+                                          , t->s[i - len], NULL);
+                                       T_EXPECT_EQ(buf[i], t->s[i - len], NULL);
+                                       T_EXPECT_EQ(ftello(fp), (off_t)i + 1, NULL);
+#if !defined(__GLIBC__)
+                                       T_EXPECT_EQ(buf[i + 1], '\0', NULL);
+#endif
+                               }
+
+/* don't accept non nul character at end of buffer */
+                               T_EXPECT_EQ(ftello(fp), (off_t)t->n - 1, NULL);
+                               T_EXPECT_EQ(fputc(0x1, fp), EOF, NULL);
+                               T_EXPECT_EQ(ftello(fp), (off_t)t->n - 1, NULL);
+
+/* accept nul character at end of buffer */
+                               T_EXPECT_EQ(ftello(fp), (off_t)t->n - 1, NULL);
+                               T_EXPECT_EQ(fputc('\0', fp), '\0', NULL);
+                               T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+                       }
+
+/* reach EOF */
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+                       T_EXPECT_EQ(fputc('\0', fp), EOF, NULL);
+                       T_EXPECT_EQ(ftello(fp), (off_t)t->n, NULL);
+
+                       T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+               }
+       }
+}
+
+T_DECL(netbsd_fmemopen_test22, "")
+{
+       struct testcase *t0, *t1;
+       size_t len0, len1, nleft;
+       const char **p;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       for (t0 = &testcases[0]; t0->s != NULL; ++t0) {
+               len0 = strnlen(t0->s, t0->n);
+               for (t1 = &testcases[0]; t1->s != NULL; ++t1) {
+                       len1 = strnlen(t1->s, t1->n);
+                       for (p = &mode_a[0]; *p != NULL; ++p) {
+
+                               memcpy(&buf[0], t0->s, t0->n);
+                               fp = fmemopen(&buf[0], t0->n, *p);
+                               T_EXPECT_NOTNULL(fp, NULL);
+                               setbuf(fp, NULL);
+/*
+ * test fmemopen_write + fwrite(3)
+ */
+                               nleft = t0->n - len0;
+#if !defined(__GLIBC__)
+                               if (nleft == 0 || len1 == nleft - 1) {
+                                       T_EXPECT_EQ(fwrite(t1->s, 1, t1->n, fp)
+                                          , nleft, NULL);
+                                       T_EXPECT_EQ(ftell(fp), t1->n, NULL);
+                               } else {
+                                       T_EXPECT_EQ(fwrite(t1->s, 1, t1->n, fp)
+                                          , nleft - 1, NULL);
+                                       T_EXPECT_EQ(ftell(fp), t1->n - 1, NULL);
+                               }
+#endif
+                               T_EXPECT_POSIX_ZERO(fclose(fp), NULL);
+                       }
+               }
+       }
+}
+#endif //0
index bfab97bd8ebc33e7aedfa393204d13948e2eed4e..927bdffce918f5fb004a98fed34857a1e91d7fa8 100644 (file)
@@ -147,7 +147,8 @@ T_DECL(setenv_thread, "Test concurrent access by setenv(3)")
        T_PASS("setenv_thread() completed successfully");
 }
 
-T_DECL(unsetenv_thread, "Test unsetenv(3) with threads")
+T_DECL(unsetenv_thread, "Test unsetenv(3) with threads",
+               T_META_ENVVAR("MallocStackLogging=lite"))
 {
        pthread_t threads[THREADED_NUM_THREADS];
        time_t endtime = time(NULL) + THREADED_RUN_TIME;
diff --git a/tests/netbsd_glob.c b/tests/netbsd_glob.c
new file mode 100644 (file)
index 0000000..fcebdb1
--- /dev/null
@@ -0,0 +1,249 @@
+/*     $NetBSD: t_glob.c,v 1.5 2017/01/14 20:47:41 christos Exp $      */
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_glob.c,v 1.5 2017/01/14 20:47:41 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <darwintest.h>
+
+#define  __arraycount(__x)   (sizeof(__x) / sizeof(__x[0]))
+
+#ifdef DEBUG
+#define DPRINTF(a) printf a
+#else
+#define DPRINTF(a)
+#endif
+
+struct gl_file {
+       const char *name;
+       int dir;
+};
+
+static struct gl_file a[] = {
+       { "1", 0 },
+       { "b", 1 },
+       { "3", 0 },
+       { "4", 0 },
+};
+
+static struct gl_file b[] = {
+       { "x", 0 },
+       { "y", 0 },
+       { "z", 0 },
+       { "w", 0 },
+};
+
+struct gl_dir {
+       const char *name;       /* directory name */
+       const struct gl_file *dir;
+       size_t len, pos;
+};
+
+static struct gl_dir d[] = {
+       { "a", a, __arraycount(a), 0 },
+       { "a/b", b, __arraycount(b), 0 },
+};
+
+#ifdef GLOB_STAR
+static const char *glob_star[] = {
+    "a/1", "a/3", "a/4", "a/b", "a/b/w", "a/b/x", "a/b/y", "a/b/z",
+};
+#endif
+
+static const char *glob_star_not[] = {
+       "a/1", "a/3", "a/4", "a/b",
+};
+
+static void
+trim(char *buf, size_t len, const char *name)
+{
+       char *path = buf, *epath = buf + len;
+       while (path < epath && (*path++ = *name++) != '\0')
+               continue;
+       path--;
+       while (path > buf && *--path == '/')
+               *path = '\0';
+}
+
+static void *
+gl_opendir(const char *dir)
+{
+       size_t i;
+       char buf[MAXPATHLEN];
+       trim(buf, sizeof(buf), dir);
+
+       for (i = 0; i < __arraycount(d); i++)
+               if (strcmp(buf, d[i].name) == 0) {
+                       DPRINTF(("opendir %s %zu\n", buf, i));
+                       return &d[i];
+               }
+       errno = ENOENT;
+       return NULL;
+}
+
+static struct dirent *
+gl_readdir(void *v)
+{
+       static struct dirent dir;
+       struct gl_dir *dd = v;
+       if (dd->pos < dd->len) {
+               const struct gl_file *f = &dd->dir[dd->pos++];
+               strcpy(dir.d_name, f->name);
+               dir.d_namlen = (uint16_t)strlen(f->name);
+               dir.d_ino = dd->pos;
+               dir.d_type = f->dir ? DT_DIR : DT_REG;
+               DPRINTF(("readdir %s %d\n", dir.d_name, dir.d_type));
+#if defined(__FreeBSD__) || defined(__APPLE__)
+               dir.d_reclen = (uint16_t)-1; /* Does not have _DIRENT_RECLEN */
+#else
+               dir.d_reclen = _DIRENT_RECLEN(&dir, dir.d_namlen);
+#endif
+               return &dir;
+       }
+       return NULL;
+}
+
+static int
+gl_stat(const char *name , struct stat *st)
+{
+       char buf[MAXPATHLEN];
+       trim(buf, sizeof(buf), name);
+       memset(st, 0, sizeof(*st));
+
+       if (strcmp(buf, "a") == 0 || strcmp(buf, "a/b") == 0) {
+               st->st_mode |= S_IFDIR;
+               return 0;
+       }
+
+       if (buf[0] == 'a' && buf[1] == '/') {
+               struct gl_file *f;
+               size_t offs, count;
+
+               if (buf[2] == 'b' && buf[3] == '/') {
+                       offs = 4;
+                       count = __arraycount(b);
+                       f = b;
+               } else {
+                       offs = 2;
+                       count = __arraycount(a);
+                       f = a;
+               }
+               
+               for (size_t i = 0; i < count; i++)
+                       if (strcmp(f[i].name, buf + offs) == 0)
+                               return 0;
+       }
+       DPRINTF(("stat %s %d\n", buf, st->st_mode));
+       errno = ENOENT;
+       return -1;
+}
+
+static int
+gl_lstat(const char *name , struct stat *st)
+{
+       return gl_stat(name, st);
+}
+
+static void
+gl_closedir(void *v)
+{
+       struct gl_dir *dd = v;
+       dd->pos = 0;
+       DPRINTF(("closedir %p\n", dd));
+}
+
+static void
+run(const char *p, int flags, const char **res, size_t len)
+{
+       glob_t gl;
+       size_t i;
+
+       memset(&gl, 0, sizeof(gl));
+       gl.gl_opendir = gl_opendir;
+       gl.gl_readdir = gl_readdir;
+       gl.gl_closedir = gl_closedir;
+       gl.gl_stat = gl_stat;
+       gl.gl_lstat = gl_lstat;
+
+       T_ASSERT_POSIX_ZERO(glob(p, GLOB_ALTDIRFUNC | flags, NULL, &gl), NULL);
+
+       for (i = 0; i < gl.gl_pathc; i++)
+               DPRINTF(("%s\n", gl.gl_pathv[i]));
+
+       T_EXPECT_EQ(len, gl.gl_pathc, NULL);
+       for (i = 0; i < gl.gl_pathc; i++)
+               T_EXPECT_EQ_STR(gl.gl_pathv[i], res[i], NULL);
+
+       globfree(&gl);
+}
+
+
+#ifdef GLOB_STAR
+T_DECL(glob_star, "Test glob(3) ** with GLOB_STAR")
+{
+       run("a/**", GLOB_STAR, glob_star, __arraycount(glob_star));
+}
+#endif
+
+T_DECL(glob_star_not, "Test glob(3) ** without GLOB_STAR")
+{
+       run("a/**", 0, glob_star_not, __arraycount(glob_star_not));
+}
+
+#if 0
+/*
+ * Remove this test for now - the GLOB_NOCHECK return value has been
+ * re-defined to return a modified pattern in revision 1.33 of glob.c
+ *
+ *     ATF_TP_ADD_TC(tp, glob_nocheck);
+ */
+T_DECL(glob_nocheck, "Test glob(3) pattern with backslash and GLOB_NOCHECK")
+{
+       static const char pattern[] = { 'f', 'o', 'o', '\\', ';', 'b', 'a',
+           'r', '\0' };
+       static const char *glob_nocheck[] = {
+           pattern
+       };
+       run(pattern, GLOB_NOCHECK, glob_nocheck, __arraycount(glob_nocheck));
+}
+#endif
diff --git a/tests/netbsd_open_memstream.c b/tests/netbsd_open_memstream.c
new file mode 100644 (file)
index 0000000..08dc642
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Based on the OpenBSD test
+ * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_open_memstream.c,v 1.2 2014/10/19 11:17:43 justin Exp $");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <darwintest.h>
+
+#define OFFSET 16384
+
+static const char start[] = "start";
+static const char hello[] = "hello";
+
+T_DECL(netbsd_open_memstream_test_open_memstream, "")
+{
+       FILE    *fp;
+       char    *buf = (char *)0xff;
+       size_t   size = 0;
+       off_t    off;
+       int      i;
+
+       fp = open_memstream(&buf, &size);
+       T_ASSERT_NOTNULL(fp, NULL);
+
+       off = ftello(fp);
+       T_EXPECT_EQ(off, 0LL, NULL);
+
+       T_EXPECT_POSIX_ZERO(fflush(fp), NULL);
+       T_EXPECT_EQ(size, 0UL, NULL);
+       T_EXPECT_NE((void*)buf, (void *)0xff, NULL);
+       T_EXPECT_EQ(fseek(fp, -6, SEEK_SET), -1, NULL);
+       T_EXPECT_POSIX_ZERO(fseek(fp, OFFSET, SEEK_SET), NULL);
+       T_EXPECT_NE(fprintf(fp, hello), EOF, NULL);
+       T_EXPECT_NE(fflush(fp), EOF, NULL);
+       T_EXPECT_EQ(size, OFFSET + sizeof(hello)-1, NULL);
+       T_EXPECT_POSIX_ZERO(fseek(fp, 0, SEEK_SET), NULL);
+       T_EXPECT_NE(fprintf(fp, start), EOF, NULL);
+       T_EXPECT_NE(fflush(fp), EOF, NULL);
+       T_EXPECT_EQ(size, sizeof(start)-1, NULL);
+
+       /* Needed for sparse files */
+       T_EXPECT_EQ(strncmp(buf, start, sizeof(start)-1), 0, NULL);
+       for (i = sizeof(start)-1; i < OFFSET; i++)
+               T_EXPECT_EQ(buf[i], '\0', NULL);
+
+       T_EXPECT_EQ(memcmp(buf + OFFSET, hello, sizeof(hello)-1), 0, NULL);
+
+       /* verify that simply seeking past the end doesn't increase the size */
+       T_EXPECT_POSIX_ZERO(fseek(fp, 100, SEEK_END), NULL);
+       T_EXPECT_NE(fflush(fp), EOF, NULL);
+       T_EXPECT_EQ(size, OFFSET + sizeof(hello)-1, NULL);
+       T_EXPECT_POSIX_ZERO(fseek(fp, 8, SEEK_SET), NULL);
+       T_EXPECT_EQ(ftell(fp), 8L, NULL);
+
+       /* Try to seek backward */
+       T_EXPECT_POSIX_ZERO(fseek(fp, -1, SEEK_CUR), NULL);
+       T_EXPECT_EQ(ftell(fp), 7L, NULL);
+       T_EXPECT_POSIX_ZERO(fseek(fp, 5, SEEK_CUR), NULL);
+       T_EXPECT_NE(fclose(fp), EOF, NULL);
+       T_EXPECT_EQ(size, 12UL, NULL);
+
+       free(buf);
+}
diff --git a/tests/netbsd_printf.c b/tests/netbsd_printf.c
new file mode 100644 (file)
index 0000000..81c2196
--- /dev/null
@@ -0,0 +1,102 @@
+/* $NetBSD: t_printf.c,v 1.8 2012/04/11 16:21:42 jruoho Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include "darwintest.h"
+
+T_DECL(netbsd_snprintf_c99, "Test printf(3) C99 conformance (PR lib/22019)")
+{
+       char s[4];
+
+       (void)memset(s, '\0', sizeof(s));
+       (void)snprintf(s, sizeof(s), "%#.o", 0);
+       (void)printf("printf = %#.o\n", 0);
+       (void)fprintf(stderr, "snprintf = %s", s);
+
+       T_ASSERT_EQ(strlen(s), (size_t)1, NULL);
+       T_ASSERT_EQ(s[0], '0', NULL);
+}
+
+T_DECL(netbsd_snprintf_dotzero, "PR lib/32951: %%.0f formats (0.0,0.5] to \"0.\"")
+{
+       char s[4];
+
+       T_WITH_ERRNO; T_EXPECT_EQ(snprintf(s, sizeof(s), "%.0f", 0.1), 1, NULL);
+       T_EXPECT_EQ_STR(s, "0", NULL);
+}
+
+T_DECL(netbsd_snprintf_float, "test that floating conversions don't leak memory")
+{
+       union {
+               double d;
+               uint64_t bits;
+       } u;
+       uint32_t ul, uh;
+       time_t now;
+       char buf[1000];
+       struct rlimit rl;
+
+       rl.rlim_cur = rl.rlim_max = 1 * 1024 * 1024;
+       T_WITH_ERRNO; T_EXPECT_NE(setrlimit(RLIMIT_AS, &rl), -1, NULL);
+       rl.rlim_cur = rl.rlim_max = 1 * 1024 * 1024;
+       T_EXPECT_POSIX_SUCCESS(setrlimit(RLIMIT_DATA, &rl), NULL);
+
+       time(&now);
+       srand((unsigned int)now);
+       for (size_t i = 0; i < 10000; i++) {
+               ul = (uint32_t)rand();
+               uh = (uint32_t)rand();
+               u.bits = (uint64_t)uh << 32 | ul;
+               T_EXPECT_POSIX_SUCCESS(snprintf(buf, sizeof buf, " %.2f", u.d), NULL);
+       }
+}
+
+T_DECL(netbsd_sprintf_zeropad, "Test output format zero padding (PR lib/44113)")
+{
+       char str[1024];
+
+       T_WITH_ERRNO; T_EXPECT_EQ(sprintf(str, "%010f", 0.0), 10, NULL);
+       T_EXPECT_EQ_STR(str, "000.000000", NULL);
+
+       /* ieeefp */
+#ifndef __vax__
+       /* printf(3) should ignore zero padding for nan/inf */
+       T_WITH_ERRNO; T_EXPECT_EQ(sprintf(str, "%010f", NAN), 10, NULL);
+       T_EXPECT_EQ_STR(str, "       nan", NULL);
+       T_WITH_ERRNO; T_EXPECT_EQ(sprintf(str, "%010f", INFINITY), 10, NULL);
+       T_EXPECT_EQ_STR(str, "       inf", NULL);
+#endif
+}
index a2dc5f9c1525ba532d923e990d1b4faf2b840e08..bc0661d56b8d2d91575b94bdd52f63943f14b674 100644 (file)
@@ -134,7 +134,7 @@ ATF_TC_HEAD(stat_err, tc)
        atf_tc_set_md_var(tc, "descr", "Test errors from the stat(2) family");
 }
 
-ATF_TC_BODY(stat_err, tc)
+T_DECL(stat_err, "")
 {
        char buf[NAME_MAX + 1];
        struct stat st;
@@ -175,7 +175,7 @@ ATF_TC_HEAD(stat_mtime, tc)
        atf_tc_set_md_var(tc, "descr", "Test modification times with stat(2)");
 }
 
-ATF_TC_BODY(stat_mtime, tc)
+T_DECL(stat_mtime, "")
 {
        struct stat sa, sb;
        int fd[3];
@@ -188,17 +188,17 @@ ATF_TC_BODY(stat_mtime, tc)
 
                fd[i] = open(path, O_WRONLY | O_CREAT);
 
-               ATF_REQUIRE(fd[i] != -1);
-               ATF_REQUIRE(write(fd[i], "X", 1) == 1);
-               ATF_REQUIRE(stat(path, &sa) == 0);
+               T_ASSERT_POSIX_SUCCESS(fd[i], NULL);
+               T_ASSERT_EQ(write(fd[i], "X", 1), 1, NULL);
+               T_ASSERT_POSIX_ZERO(stat(path, &sa), NULL);
 
                (void)sleep(1);
 
-               ATF_REQUIRE(write(fd[i], "X", 1) == 1);
-               ATF_REQUIRE(stat(path, &sb) == 0);
+               T_ASSERT_EQ(write(fd[i], "X", 1), 1, NULL);
+               T_ASSERT_POSIX_ZERO(stat(path, &sb), NULL);
 
-               ATF_REQUIRE(close(fd[i]) == 0);
-               ATF_REQUIRE(unlink(path) == 0);
+               T_ASSERT_POSIX_ZERO(close(fd[i]), NULL);
+               T_ASSERT_POSIX_ZERO(unlink(path), NULL);
 
                if (sa.st_mtime == sb.st_mtime)
                        atf_tc_fail("mtimes did not change");
@@ -217,7 +217,7 @@ ATF_TC_HEAD(stat_perm, tc)
        atf_tc_set_md_var(tc, "require.user", "root");
 }
 
-ATF_TC_BODY(stat_perm, tc)
+T_DECL(stat_perm, "")
 {
        struct stat sa, sb;
        gid_t gid;
@@ -232,9 +232,9 @@ ATF_TC_BODY(stat_perm, tc)
 
        fd = open(path, O_RDONLY | O_CREAT);
 
-       ATF_REQUIRE(fd != -1);
-       ATF_REQUIRE(fstat(fd, &sa) == 0);
-       ATF_REQUIRE(stat(path, &sb) == 0);
+       T_ASSERT_POSIX_SUCCESS(fd, NULL);
+       T_ASSERT_POSIX_ZERO(fstat(fd, &sa), NULL);
+       T_ASSERT_POSIX_ZERO(stat(path, &sb), NULL);
 
        if (gid != sa.st_gid || sa.st_gid != sb.st_gid)
                atf_tc_fail("invalid GID");
@@ -242,8 +242,8 @@ ATF_TC_BODY(stat_perm, tc)
        if (uid != sa.st_uid || sa.st_uid != sb.st_uid)
                atf_tc_fail("invalid UID");
 
-       ATF_REQUIRE(close(fd) == 0);
-       ATF_REQUIRE(unlink(path) == 0);
+       T_ASSERT_POSIX_ZERO(close(fd), NULL);
+       T_ASSERT_POSIX_ZERO(unlink(path), NULL);
 }
 
 ATF_TC_CLEANUP(stat_perm, tc)
@@ -257,7 +257,7 @@ ATF_TC_HEAD(stat_size, tc)
        atf_tc_set_md_var(tc, "descr", "Test file sizes with stat(2)");
 }
 
-ATF_TC_BODY(stat_size, tc)
+T_DECL(stat_size, "")
 {
        struct stat sa, sb, sc;
        const size_t n = 10;
@@ -273,10 +273,10 @@ ATF_TC_BODY(stat_size, tc)
                (void)memset(&sb, 0, sizeof(struct stat));
                (void)memset(&sc, 0, sizeof(struct stat));
 
-               ATF_REQUIRE(fstat(fd, &sa) == 0);
-               ATF_REQUIRE(write(fd, "X", 1) == 1);
-               ATF_REQUIRE(fstat(fd, &sb) == 0);
-               ATF_REQUIRE(stat(path, &sc) == 0);
+               T_ASSERT_POSIX_ZERO(fstat(fd, &sa), NULL);
+               T_ASSERT_EQ(write(fd, "X", 1), 1, NULL);
+               T_ASSERT_POSIX_ZERO(fstat(fd, &sb), NULL);
+               T_ASSERT_POSIX_ZERO(stat(path, &sc), NULL);
 
                if (sa.st_size + 1 != sb.st_size)
                        atf_tc_fail("invalid file size");
@@ -285,8 +285,8 @@ ATF_TC_BODY(stat_size, tc)
                        atf_tc_fail("stat(2) and fstat(2) mismatch");
        }
 
-       ATF_REQUIRE(close(fd) == 0);
-       ATF_REQUIRE(unlink(path) == 0);
+       T_ASSERT_POSIX_ZERO(close(fd), NULL);
+       T_ASSERT_POSIX_ZERO(unlink(path), NULL);
 }
 
 ATF_TC_CLEANUP(stat_size, tc)
@@ -301,7 +301,7 @@ ATF_TC_HEAD(stat_socket, tc)
            "a socket (PR kern/46077)");
 }
 
-ATF_TC_BODY(stat_socket, tc)
+T_DECL(stat_socket, "")
 {
        struct sockaddr_in addr;
        struct stat st;
@@ -316,9 +316,9 @@ ATF_TC_BODY(stat_socket, tc)
 
        flags = fcntl(fd, F_GETFL);
 
-       ATF_REQUIRE(flags != -1);
-       ATF_REQUIRE(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1);
-       ATF_REQUIRE(inet_pton(AF_INET, "127.0.0.1", &iaddr) == 1);
+       T_ASSERT_POSIX_SUCCESS(flags, NULL);
+       T_ASSERT_POSIX_SUCCESS(fcntl(fd, F_SETFL, flags | O_NONBLOCK), NULL);
+       T_ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &iaddr), 1, NULL);
 
        addr.sin_port = htons(42);
        addr.sin_family = AF_INET;
@@ -344,7 +344,7 @@ ATF_TC_HEAD(stat_symlink, tc)
        atf_tc_set_md_var(tc, "descr", "Test symbolic links with stat(2)");
 }
 
-ATF_TC_BODY(stat_symlink, tc)
+T_DECL(stat_symlink, "")
 {
        const char *pathlink = "pathlink";
        struct stat sa, sb;
@@ -356,9 +356,9 @@ ATF_TC_BODY(stat_symlink, tc)
        fd = open(path, O_WRONLY | O_CREAT);
 
        ATF_REQUIRE(fd >= 0);
-       ATF_REQUIRE(symlink(path, pathlink) == 0);
-       ATF_REQUIRE(stat(pathlink, &sa) == 0);
-       ATF_REQUIRE(lstat(pathlink, &sb) == 0);
+       T_ASSERT_POSIX_ZERO(symlink(path, pathlink), NULL);
+       T_ASSERT_POSIX_ZERO(stat(pathlink, &sa), NULL);
+       T_ASSERT_POSIX_ZERO(lstat(pathlink, &sb), NULL);
 
        if (S_ISLNK(sa.st_mode) != 0)
                atf_tc_fail("stat(2) detected symbolic link");
@@ -369,8 +369,8 @@ ATF_TC_BODY(stat_symlink, tc)
        if (sa.st_mode == sb.st_mode)
                atf_tc_fail("inconsistencies between stat(2) and lstat(2)");
 
-       ATF_REQUIRE(unlink(path) == 0);
-       ATF_REQUIRE(unlink(pathlink) == 0);
+       T_ASSERT_POSIX_ZERO(unlink(path), NULL);
+       T_ASSERT_POSIX_ZERO(unlink(pathlink), NULL);
 }
 
 ATF_TC_CLEANUP(stat_symlink, tc)
diff --git a/tests/netbsd_strerror.c b/tests/netbsd_strerror.c
new file mode 100644 (file)
index 0000000..f9b0815
--- /dev/null
@@ -0,0 +1,105 @@
+/* $NetBSD: t_strerror.c,v 1.3 2011/05/10 06:55:27 jruoho Exp $ */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jukka Ruohonen.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_strerror.c,v 1.3 2011/05/10 06:55:27 jruoho Exp $");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "darwintest.h"
+
+T_DECL(netbsd_strerror_basic, "A basic test of strerror(3)")
+{
+       int i;
+
+       for (i = 1; i < sys_nerr; i++)
+               T_EXPECT_NULL(strstr(strerror(i), "Unknown error:"), NULL);
+
+       for (; i < sys_nerr + 10; i++)
+               T_EXPECT_NOTNULL(strstr(strerror(i), "Unknown error:"), NULL);
+}
+
+T_DECL(netbsd_strerror_err, "Test errors from strerror(3)")
+{
+       (void)setlocale(LC_ALL, "C");
+
+       errno = 0;
+
+       T_ASSERT_NOTNULL(strstr(strerror(INT_MAX), "Unknown error:"), NULL);
+       T_ASSERT_EQ(errno, EINVAL, NULL);
+
+       errno = 0;
+
+       T_ASSERT_NOTNULL(strstr(strerror(INT_MIN), "Unknown error:"), NULL);
+       T_ASSERT_EQ(errno, EINVAL, NULL);
+}
+
+T_DECL(netbsd_strerror_r_basic, "A basic test of strerror_r(3)")
+{
+       char buf[512];
+       int i;
+
+       (void)setlocale(LC_ALL, "C");
+
+       for (i = 1; i < sys_nerr; i++) {
+               T_ASSERT_EQ(strerror_r(i, buf, sizeof(buf)), 0, NULL);
+               T_ASSERT_NULL(strstr(buf, "Unknown error:"), NULL);
+       }
+
+       for (; i < sys_nerr + 10; i++) {
+               T_ASSERT_EQ(strerror_r(i, buf, sizeof(buf)), EINVAL, NULL);
+               T_ASSERT_NOTNULL(strstr(buf, "Unknown error:"), NULL);
+       }
+}
+
+T_DECL(netbsd_strerror_r_err, "Test errors from strerror_r(3)")
+{
+       char buf[512];
+       int rv;
+
+       (void)setlocale(LC_ALL, "C");
+
+       rv = strerror_r(EPERM, buf, 1);
+       T_ASSERT_EQ(rv, ERANGE, NULL);
+
+       rv = strerror_r(INT_MAX, buf, sizeof(buf));
+
+       T_ASSERT_EQ(rv, EINVAL, NULL);
+       T_ASSERT_NOTNULL(strstr(buf, "Unknown error:"), NULL);
+
+       rv = strerror_r(INT_MIN, buf, sizeof(buf));
+
+       T_ASSERT_EQ(rv, EINVAL, NULL);
+       T_ASSERT_NOTNULL(strstr(buf, "Unknown error:"), NULL);
+}
index 067096490920be9c96e88d3b79e42e8d229b552c..07e0775d5de70cb7443f2c4cbdcdd9701ae103ac 100644 (file)
@@ -76,7 +76,7 @@ T_DECL(strvis_basic, "strvis(3)")
                        if (dstbuf[j] != (char)j)
                                T_FAIL("Failed for style %x, char %d [%d]", styles[i], j, dstbuf[j]);
                if (dstbuf[SIZE] != '\0')
-                       T_FAIL("Failed for style %x, the result must be null-terminated [%d]", dstbuf[SIZE]);
+                       T_FAIL("Failed for style %x, the result must be null-terminated [%d]", styles[i], dstbuf[SIZE]);
        }
        free(dstbuf);
        free(srcbuf);
diff --git a/tests/os_variant.c b/tests/os_variant.c
new file mode 100644 (file)
index 0000000..3717f6d
--- /dev/null
@@ -0,0 +1,155 @@
+#include <os/variant_private.h>
+
+#include <darwintest.h>
+
+/*
+ * Most of these are MAYFAIL because the test might sometimes run on non-internal devices.
+ */
+
+T_DECL(os_variant_basic, "Just calls all the APIs")
+{
+       T_MAYFAIL;
+       T_EXPECT_TRUE(os_variant_has_internal_content("com.apple.Libc.tests"), NULL);
+
+       T_MAYFAIL;
+       T_EXPECT_TRUE(os_variant_has_internal_diagnostics("com.apple.Libc.tests"), NULL);
+
+       T_MAYFAIL;
+       T_EXPECT_TRUE(os_variant_has_internal_ui("com.apple.Libc.tests"), NULL);
+
+       T_MAYFAIL;
+       T_EXPECT_TRUE(os_variant_allows_internal_security_policies("com.apple.Libc.tests"), NULL);
+}
+
+#define VARIANT_SKIP_EXPORTED
+
+#include "../libdarwin/variant.c"
+
+T_DECL(os_variant_detailed, "Looks at individual checks")
+{
+       T_MAYFAIL;
+       T_EXPECT_FALSE(_check_disabled(VP_ALL), NULL);
+
+       T_MAYFAIL;
+       T_EXPECT_FALSE(_check_disabled(VP_CONTENT), NULL);
+
+       T_MAYFAIL;
+       T_EXPECT_FALSE(_check_disabled(VP_DIAGNOSTICS), NULL);
+
+       T_MAYFAIL;
+       T_EXPECT_FALSE(_check_disabled(VP_UI), NULL);
+
+       T_MAYFAIL;
+       T_EXPECT_FALSE(_check_disabled(VP_SECURITY), NULL);
+
+#if !TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+       T_MAYFAIL;
+       T_EXPECT_TRUE(_check_internal_content(), NULL);
+#endif
+
+#if TARGET_OS_IPHONE
+       T_MAYFAIL;
+       T_EXPECT_TRUE(_check_internal_release_type(), NULL);
+#else
+       T_MAYFAIL;
+       T_EXPECT_FALSE(_check_internal_diags_profile(), NULL);
+#endif
+
+       T_MAYFAIL;
+       T_EXPECT_TRUE(_check_can_has_debugger(), NULL);
+}
+
+T_DECL(os_variant_override_parse, "Checks the parsing of the override file")
+{
+       // Warm up the dispatch_once
+       _check_disabled(VP_ALL);
+
+       T_LOG("Override: NULL"); // Live system
+       _parse_disabled_status(NULL);
+       T_MAYFAIL; T_EXPECT_FALSE(_check_disabled(VP_CONTENT), NULL);
+       T_MAYFAIL; T_EXPECT_FALSE(_check_disabled(VP_DIAGNOSTICS), NULL);
+       T_MAYFAIL; T_EXPECT_FALSE(_check_disabled(VP_UI), NULL);
+       T_MAYFAIL; T_EXPECT_FALSE(_check_disabled(VP_SECURITY), NULL);
+
+       T_LOG("Override: \"content\"");
+       _parse_disabled_status("content");
+       T_EXPECT_TRUE(_check_disabled(VP_CONTENT), NULL);
+       T_EXPECT_FALSE(_check_disabled(VP_DIAGNOSTICS), NULL);
+       T_EXPECT_FALSE(_check_disabled(VP_UI), NULL);
+       T_EXPECT_FALSE(_check_disabled(VP_SECURITY), NULL);
+
+       T_LOG("Override: \"ui\"");
+       _parse_disabled_status("ui");
+       T_EXPECT_FALSE(_check_disabled(VP_CONTENT), NULL);
+       T_EXPECT_FALSE(_check_disabled(VP_DIAGNOSTICS), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_UI), NULL);
+       T_EXPECT_FALSE(_check_disabled(VP_SECURITY), NULL);
+
+       T_LOG("Override: \"security,diagnostics\"");
+       _parse_disabled_status("security,diagnostics");
+       T_EXPECT_FALSE(_check_disabled(VP_CONTENT), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_DIAGNOSTICS), NULL);
+       T_EXPECT_FALSE(_check_disabled(VP_UI), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_SECURITY), NULL);
+
+       T_LOG("Override: \"content,diagnostics,ui,security\"");
+       _parse_disabled_status("content,diagnostics,ui,security");
+       T_EXPECT_TRUE(_check_disabled(VP_CONTENT), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_DIAGNOSTICS), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_UI), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_SECURITY), NULL);
+
+       T_LOG("Override: \"diagnostics\\n"); // Now check newline-handling.
+       _parse_disabled_status("diagnostics\n");
+       T_EXPECT_FALSE(_check_disabled(VP_CONTENT), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_DIAGNOSTICS), NULL);
+       T_EXPECT_FALSE(_check_disabled(VP_UI), NULL);
+       T_EXPECT_FALSE(_check_disabled(VP_SECURITY), NULL);
+
+       T_LOG("Override: \"content,diagnostics\\nui,security\\n\"");
+       _parse_disabled_status("content,diagnostics\nui,security\n");
+       T_EXPECT_TRUE(_check_disabled(VP_CONTENT), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_DIAGNOSTICS), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_UI), NULL);
+       T_EXPECT_TRUE(_check_disabled(VP_SECURITY), NULL);
+}
+
+T_DECL(os_status_cache, "Checks saving and restoring of state")
+{
+       uint64_t status = 0;
+       size_t status_size = sizeof(status);
+       int ret = sysctlbyname(CACHE_SYSCTL_NAME, &status, &status_size, NULL, 0);
+       T_EXPECT_POSIX_ZERO(ret, "sysctlbyname(kern.osvariant_status)");
+       T_EXPECT_GT(status, 0ULL, "Kernel's status has bits set");
+       T_EXPECT_EQ(status & STATUS_INITIAL_BITS, STATUS_INITIAL_BITS, "Kernel's status has initial bits set");
+
+       T_MAYFAIL;
+       T_EXPECT_TRUE(_check_can_has_debugger(), NULL);
+
+       status = _get_cached_check_status();
+       T_LOG("Cached status: %llx", status);
+
+       T_EXPECT_EQ(status & STATUS_INITIAL_BITS, STATUS_INITIAL_BITS, "Our status has initial bits set");
+
+       _restore_cached_check_status(status);
+
+       T_MAYFAIL;
+       T_EXPECT_TRUE(os_variant_allows_internal_security_policies(NULL), NULL);
+
+       status = STATUS_INITIAL_BITS |
+                       (S_NO << (SFP_CAN_HAS_DEBUGGER * STATUS_BIT_WIDTH));
+       T_LOG("Restoring status without can_has_debugger: %llx", status);
+       _restore_cached_check_status(status);
+
+       T_EXPECT_FALSE(_check_can_has_debugger(), NULL);
+
+       // Trigger dispatch_once internally with known state
+       _check_disabled(VP_SECURITY);
+
+       status = STATUS_INITIAL_BITS |
+                       (0x1ULL << (VP_SECURITY + 32));
+       T_LOG("Restoring status with override: %llx", status);
+       _restore_cached_check_status(status);
+
+       T_EXPECT_TRUE(_check_disabled(VP_SECURITY), NULL);
+}
diff --git a/tests/printf.c b/tests/printf.c
new file mode 100644 (file)
index 0000000..ab7f1b5
--- /dev/null
@@ -0,0 +1,66 @@
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <os/assumes.h>
+
+#include "darwintest.h"
+#include "darwintest_utils.h"
+
+static void crash_callback(const char *str) {
+       T_PASS("Crashed with \"%s\"", str);
+       T_END;
+}
+
+T_DECL(sprintf_percent_n, "Test of %n")
+{
+       char str[1024];
+       int len, ret;
+
+       char *fmt = "%010d%n";
+
+       T_EXPECT_POSIX_SUCCESS((ret = snprintf(str, sizeof(str), fmt, 0, &len)), NULL);
+       T_EXPECT_EQ(len, ret, NULL);
+
+       char fmt_buf[32];
+       strlcpy(fmt_buf, fmt, sizeof(fmt_buf));
+
+       os_set_crash_callback(crash_callback);
+       snprintf(str, sizeof(str), fmt_buf, 0, &len);
+       T_ASSERT_FAIL("Should have crashed on dynamic %%n");
+}
+
+#if !TARGET_OS_IPHONE
+#define STRSIZE (1024 * 1024 * 256)
+
+T_DECL(printf_PR_30663523, "Test for PR-30663523",
+               T_META_CHECK_LEAKS(NO))
+{
+       char *temp_path;
+       asprintf(&temp_path, "%s/%s", dt_tmpdir(), "big_file");
+
+       {
+               char *x = calloc(1, 0x80000001);
+               memset(x, 0x41, 0x80000001);
+
+               FILE *f = fopen(temp_path, "w");
+               int len = fprintf(f, "%s", x);
+               T_EXPECT_EQ(len, EOF, "fprintf should return EOF when string is longer than INT_MAX");
+               fclose(f);
+       }
+
+       {
+               char *x = calloc(1, STRSIZE);
+               memset(x, 0x41, STRSIZE - 1);
+
+               FILE *f = fopen(temp_path, "w");
+               int len = fprintf(f, "%s%s%s%s%s%s%s%s%s%s", x,x,x,x,x,x,x,x,x,x);
+               T_EXPECT_EQ(len, EOF, "fprintf should return EOF when output string is longer than INT_MAX");
+               fclose(f);
+       }
+}
+#endif // !TARGET_OS_IPHONE
index 41986e1d0c60d439cb9de47d40ea2ab9172abb9c..17a9a1b70a34446d53d787859e90c99453d34c54 100644 (file)
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <sys/time.h>
 #include <mach/clock_types.h>
+#include <TargetConditionals.h>
 
 #include <darwintest.h>
 
@@ -17,10 +18,14 @@ T_DECL(psort, "psort(3)")
 {
        struct timeval tv_start, tv_stop;
        struct rusage ru_start, ru_stop;
-       unsigned long pwt, put, qwt, qut;
+       uint64_t pwt, put, qwt, qut;
 
        T *buf, *sorted;
+#if TARGET_OS_BRIDGE
+       const size_t nel = 2048000;
+#else
        const size_t nel = 20480000;
+#endif
        const size_t width = sizeof(T), bufsiz = nel * width;
 
        buf = malloc(bufsiz);
@@ -38,6 +43,7 @@ T_DECL(psort, "psort(3)")
                        ((uint64_t)tv_start.tv_sec * USEC_PER_SEC + tv_start.tv_usec);
        put = ((uint64_t)ru_stop.ru_utime.tv_sec * USEC_PER_SEC + ru_stop.ru_utime.tv_usec) -
                        ((uint64_t)ru_start.ru_utime.tv_sec * USEC_PER_SEC + ru_start.ru_utime.tv_usec);
+       T_LOG("psort: wall-time=%llu us; user-time=%llu us", pwt, put);
 
        getrusage(RUSAGE_SELF, &ru_start);
        gettimeofday(&tv_start, NULL);
@@ -49,16 +55,17 @@ T_DECL(psort, "psort(3)")
                        ((uint64_t)tv_start.tv_sec * USEC_PER_SEC + tv_start.tv_usec);
        qut = ((uint64_t)ru_stop.ru_utime.tv_sec * USEC_PER_SEC + ru_stop.ru_utime.tv_usec) -
                        ((uint64_t)ru_start.ru_utime.tv_sec * USEC_PER_SEC + ru_start.ru_utime.tv_usec);
+       T_LOG("qsort: wall-time=%llu us; user-time=%llu us", qwt, qut);
 
-       bool match = true;
        for (size_t i = 0; i < nel; i++) {
-               if (!(match = (buf[i] == sorted[i]))) break;
+               if (buf[i] != sorted[i]) {
+                       T_ASSERT_EQ(buf[i], sorted[i], NULL);
+               }
        }
 
        free(sorted);
        free(buf);
 
-       T_MAYFAIL; T_EXPECT_LE((double)pwt/qwt, 1.0, "psort/qsort wall time");
-       T_MAYFAIL; T_EXPECT_LE((double)qut/put, 1.0, "qsort/psort user time");
-       T_EXPECT_TRUE(match, "psort matches qsort");
+       T_EXPECT_LE((double)pwt/qwt, 1.2, "psort/qsort wall time");
+       T_EXPECT_LE((double)qut/put, 1.2, "qsort/psort user time");
 }
diff --git a/tests/qsort.c b/tests/qsort.c
new file mode 100644 (file)
index 0000000..d345b68
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Randomized test for qsort() routine.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+#include "freebsd_qsort.h"
+
+#define BUFLEN (32 * 1024)
+
+static int tests = 10;
+
+T_DECL(qsort_random, "qsort random test", T_META_CHECK_LEAKS(NO))
+{
+       char testvector[BUFLEN];
+       char sresvector[BUFLEN];
+    size_t i;
+
+    while (--tests >= 0) {
+        size_t elmsize = (tests % 32) + 1;
+        size_t elmcount = sizeof(testvector) / elmsize;
+        T_LOG("%d: size = %zu, count = %zu", tests, elmsize, elmcount);
+
+        /* Populate test vectors */
+        arc4random_buf(testvector, sizeof(testvector));
+        memcpy(sresvector, testvector, sizeof(testvector));
+
+        /* Sort using qsort(3) */
+        qsort_r(testvector, elmcount, elmsize, (void*)elmsize, szsorthelp);
+        /* Sort using reference slow sorting routine */
+        szsort(sresvector, elmcount, elmsize);
+
+        /* Compare results */
+        for (i = 0; i < elmcount; i++){
+            if (memcmp(testvector + (i * elmsize), sresvector + (i * elmsize), elmsize) != 0) {
+                T_LOG("testvector =");
+                dt_print_hex_dump((uint8_t*)testvector, sizeof(testvector));
+                T_LOG("sresvector =");
+                dt_print_hex_dump((uint8_t*)sresvector, sizeof(sresvector));
+                T_ASSERT_FAIL("%d: item at index %zd should match", tests, i);
+                break;
+            }
+        }
+        if (i == elmcount) {
+            T_PASS("%d: Sorted successfully.", tests);
+        }
+    }
+}
diff --git a/tests/qsort_perf.c b/tests/qsort_perf.c
new file mode 100644 (file)
index 0000000..5827aee
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Randomized test for qsort() routine.
+ *
+ * Includes code derived from stdlib/FreeBSD/qsort.c and the copyright header
+ * in that file applies.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+static void qsort1(void *aa, size_t n, size_t es,
+        int (*cmp)(const void *, const void *));
+
+static int
+cmp_int(const void *aa, const void *bb)
+{
+    int a, b;
+
+    a = *(const int *)aa;
+    b = *(const int *)bb;
+    return(a - b);
+}
+
+#define nelm 1000000
+
+T_DECL(qsort_perf, "qsort perf test", T_META_CHECK_LEAKS(NO))
+{
+    int i;
+    int arr[nelm];
+    int save[nelm];
+    uint64_t time_elapsed;
+
+    // ----- 25-75 -----
+
+    int k = nelm/4;
+    for (i = 0; i < k; i++) {
+        save[i] = i;
+    }
+    for (i = k; i < nelm; i++) {
+        save[i] = i - k;
+    }
+
+    bcopy(save, arr, sizeof(arr));
+    dt_timer_start("25-75 (qsort)");
+    qsort(arr, nelm, sizeof(arr[0]), cmp_int);
+    time_elapsed = dt_timer_stop("25-75 (qsort)");
+    T_LOG("25-75 (qsort): %lld ms", time_elapsed / NSEC_PER_MSEC);
+    for (i = 1; i < nelm; i++) {
+        if(arr[i - 1] > arr[i]) {
+            T_ASSERT_FAIL("arr[%d]=%d > arr[%d]=%d", i - 1, arr[i - 1], i, arr[i]);
+            break;
+        }
+    }
+
+    bcopy(save, arr, sizeof(arr));
+    dt_timer_start("25-75 (Bentley)");
+    qsort1(arr, nelm, sizeof(arr[0]), cmp_int);
+    time_elapsed = dt_timer_stop("25-75 (Bentley)");
+    T_LOG("25-75 (Bentley): %lld ms", time_elapsed / NSEC_PER_MSEC);
+    for (i = 1; i < nelm; i++) {
+        if(arr[i - 1] > arr[i]) {
+            T_ASSERT_FAIL("arr[%d]=%d > arr[%d]=%d", i - 1, arr[i - 1], i, arr[i]);
+            break;
+        }
+    }
+    // ----- 50-50 -----
+
+    k = nelm/2;
+    for (i = 0; i < k; i++) {
+        save[i] = i;
+    }
+    for (i = k; i < nelm; i++) {
+        save[i] = i - k;
+    }
+
+    bcopy(save, arr, sizeof(arr));
+    dt_timer_start("50-50 (qsort)");
+    qsort(arr, nelm, sizeof(arr[0]), cmp_int);
+    time_elapsed = dt_timer_stop("50-50 (qsort)");
+    T_LOG("50-50 (qsort): %lld ms", time_elapsed / NSEC_PER_MSEC);
+    for (i = 1; i < nelm; i++) {
+        if(arr[i - 1] > arr[i]) {
+            T_ASSERT_FAIL("arr[%d]=%d > arr[%d]=%d", i - 1, arr[i - 1], i, arr[i]);
+            break;
+        }
+    }
+
+    bcopy(save, arr, sizeof(arr));
+    dt_timer_start("50-50 (Bentley)");
+    qsort1(arr, nelm, sizeof(arr[0]), cmp_int);
+    time_elapsed = dt_timer_stop("50-50 (Bentley)");
+    T_LOG("50-50 (Bentley): %lld ms", time_elapsed / NSEC_PER_MSEC);
+    for (i = 1; i < nelm; i++) {
+        if(arr[i - 1] > arr[i]) {
+            T_ASSERT_FAIL("arr[%d]=%d > arr[%d]=%d", i - 1, arr[i - 1], i, arr[i]);
+            break;
+        }
+    }
+
+    // ----- median-of-3 killer -----
+
+    k = nelm / 2;
+    for (i = 1; i <= k; i++) {
+        if(i % 2 == 1) {
+            save[i - 1] = i;
+            save[i] = k + i;
+        }
+        save[k + i - 1] = 2 * i;
+    }
+
+    bcopy(save, arr, sizeof(arr));
+    dt_timer_start("median-of-3 killer (qsort)");
+    qsort(arr, nelm, sizeof(arr[0]), cmp_int);
+    time_elapsed = dt_timer_stop("median-of-3 killer (qsort)");
+    T_LOG("median-of-3 (qsort): %lld ms", time_elapsed / NSEC_PER_MSEC);
+    for (i = 1; i < nelm; i++) {
+        if(arr[i - 1] > arr[i]) {
+            T_ASSERT_FAIL("arr[%d]=%d > arr[%d]=%d", i - 1, arr[i - 1], i, arr[i]);
+        }
+    }
+
+    bcopy(save, arr, sizeof(arr));
+    dt_timer_start("median-of-3 killer (Bentley)");
+    qsort1(arr, nelm, sizeof(arr[0]), cmp_int);
+    time_elapsed = dt_timer_stop("median-of-3 killer (Bentley)");
+    T_LOG("median-of-3 (Bentley): %lld ms", time_elapsed / NSEC_PER_MSEC);
+    for (i = 1; i < nelm; i++) {
+        if(arr[i - 1] > arr[i]) {
+            T_ASSERT_FAIL("arr[%d]=%d > arr[%d]=%d", i - 1, arr[i - 1], i, arr[i]);
+        }
+    }
+
+    // ----- random -----
+
+    for (i = 0; i < nelm; i++) {
+        save[i] = random();
+    }
+
+    bcopy(save, arr, sizeof(arr));
+    dt_timer_start("random (qsort)");
+    qsort(arr, nelm, sizeof(arr[0]), cmp_int);
+    time_elapsed = dt_timer_stop("random (qsort)");
+    T_LOG("random (qsort): %lld ms", time_elapsed / NSEC_PER_MSEC);
+    for (i = 1; i < nelm; i++) {
+        if(arr[i - 1] > arr[i]) {
+            T_ASSERT_FAIL("arr[%d]=%d > arr[%d]=%d", i - 1, arr[i - 1], i, arr[i]);
+        }
+    }
+
+
+    bcopy(save, arr, sizeof(arr));
+    dt_timer_start("random (Bentley)");
+    qsort1(arr, nelm, sizeof(arr[0]), cmp_int);
+    time_elapsed = dt_timer_stop("random (Bentley)");
+    T_LOG("random (Bentley): %lld ms", time_elapsed / NSEC_PER_MSEC);
+    for (i = 1; i < nelm; i++) {
+        if(arr[i - 1] > arr[i]) {
+            T_ASSERT_FAIL("arr[%d]=%d > arr[%d]=%d", i - 1, arr[i - 1], i, arr[i]);
+        }
+    }
+
+    T_PASS("All tests completed successfully.");
+}
+
+/* qsort1 -- qsort interface implemented by faster quicksort */
+
+#define SWAPINIT(a, es) swaptype =                            \
+    (a - (char*) 0) % sizeof(long) || es % sizeof(long) ? 2 : \
+    es == sizeof(long) ? 0 : 1;
+#define swapcode(TYPE, parmi, parmj, n) {  \
+    long i = (n) / sizeof(TYPE);           \
+    register TYPE *pi = (TYPE *) (parmi);  \
+    register TYPE *pj = (TYPE *) (parmj);  \
+    do {                                   \
+        register TYPE t = *pi;             \
+        *pi++ = *pj;                       \
+        *pj++ = t;                         \
+    } while (--i > 0);                     \
+}
+static void swapfunc(char *a, char *b, int n, int swaptype)
+{   if (swaptype <= 1) swapcode(long, a, b, n)
+    else swapcode(char, a, b, n)
+}
+#define swap(a, b)                         \
+    if (swaptype == 0) {                   \
+        long t = * (long *) (a);           \
+        * (long *) (a) = * (long *) (b);   \
+        * (long *) (b) = t;                \
+    } else                                 \
+        swapfunc(a, b, es, swaptype)
+#define vecswap(a, b, n) if (n > 0) swapfunc(a, b, n, swaptype)
+
+#define min(x, y) ((x)<=(y) ? (x) : (y))
+
+static char *med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+    return cmp(a, b) < 0 ?
+            (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ) )
+            : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ) );
+}
+
+static void
+qsort1(void *aa, size_t n, size_t es,
+      int (*cmp)(const void *, const void *))
+{
+       char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+       int  d, r, swaptype;
+       char *a = aa;
+
+       SWAPINIT(a, es);
+       if (n < 7) { /* Insertion sort on small arrays */
+               for (pm = a + es; pm < a + n*es; pm += es)
+                       for (pl = pm; pl > a && cmp(pl-es, pl) > 0; pl -= es)
+                               swap(pl, pl-es);
+               return;
+       }
+       pm = a + (n/2) * es;
+       if (n > 7) {
+               pl = a;
+               pn = a + (n-1) * es;
+               if (n > 40) { /* On big arrays, pseudomedian of 9 */
+                       d = (n/8) * es;
+                       pl = med3(pl, pl+d, pl+2*d, cmp);
+                       pm = med3(pm-d, pm, pm+d, cmp);
+                       pn = med3(pn-2*d, pn-d, pn, cmp);
+               }
+               pm = med3(pl, pm, pn, cmp); /* On mid arrays, med of 3 */
+       }
+       swap(a, pm); /* On tiny arrays, partition around middle */
+       pa = pb = a + es;
+       pc = pd = a + (n-1)*es;
+       for (;;) {
+               while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+                       if (r == 0) { swap(pa, pb); pa += es; }
+                       pb += es;
+               }
+               while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+                       if (r == 0) { swap(pc, pd); pd -= es; }
+                       pc -= es;
+               }
+               if (pb > pc) break;
+               swap(pb, pc);
+               pb += es;
+               pc -= es;
+       }
+       pn = a + n*es;
+       r = min(pa-a,  pb-pa);    vecswap(a,  pb-r, r);
+       r = min(pd-pc, pn-pd-es); vecswap(pb, pn-r, r);
+       if ((r = pb-pa) > es) qsort1(a, r/es, es, cmp);
+       if ((r = pd-pc) > es) qsort1(pn-r, r/es, es, cmp);
+}
diff --git a/tests/realpath.c b/tests/realpath.c
new file mode 100644 (file)
index 0000000..6a4c153
--- /dev/null
@@ -0,0 +1,135 @@
+/* $NetBSD: t_realpath.c,v 1.2 2012/03/27 07:54:58 njoly Exp $ */
+
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jukka Ruohonen.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_realpath.c,v 1.2 2012/03/27 07:54:58 njoly Exp $");
+
+#include <sys/param.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+struct testcase {
+       const char *path;
+       const char *result;
+};
+
+static const struct testcase paths[] = {
+       { "/",                  "/"             },
+       { "///////",            "/"             },
+       { "",                   NULL            },
+       { "       ",            NULL            },
+       { "/      ",            NULL            },
+       { "      /",            NULL            },
+       { "/usr/bin///",        "/usr/bin"      },
+       { "///////usr",         "/usr"          },
+       { "/a/b/c/d/e",         NULL            },
+       { "    /usr/bin    ",   NULL            },
+       { "\\//////usr//bin",   NULL            },
+       { "//usr//bin//",       "/usr/bin"      },
+       { "//////usr//bin//",   "/usr/bin"      },
+       { "/usr/bin//////////", "/usr/bin"      },
+};
+
+T_DECL(realpath_basic, "Resolve various short directory paths")
+{
+       char buf[MAXPATHLEN];
+       char *ptr;
+       size_t i;
+
+       size_t num_cases = sizeof(paths) / sizeof(struct testcase);
+       for (i = 0; i < num_cases; i++) {
+
+               (void)memset(buf, '\0', sizeof(buf));
+
+               ptr = realpath(paths[i].path, buf);
+
+               if (paths[i].result == NULL) {
+                       T_EXPECT_NULL(ptr, NULL);
+               } else {
+                       T_EXPECT_EQ_STR(ptr, paths[i].result, "Real path matches expected path");
+               }
+       }
+}
+
+T_DECL(realpath_trailing, "Trailing . and .. should fail after non-directories")
+{
+       char result[MAXPATHLEN] = { 0 };
+
+       T_EXPECT_NULL(realpath("/usr/null/.", result), NULL);
+       T_EXPECT_NULL(realpath("/usr/null/..", result), NULL);
+}
+
+T_DECL(realpath_huge, "Test realpath with maximum path size")
+{
+       char result[MAXPATHLEN] = { 0 };
+       char buffer[MAXPATHLEN] = { 0 };
+
+       (void)memset(buffer, '/', sizeof(buffer) - 1);
+
+       T_EXPECT_NOTNULL(realpath(buffer, result), NULL);
+       T_EXPECT_EQ(strlen(result), (size_t) 1, NULL);
+       T_EXPECT_EQ(result[0], '/', NULL);
+}
+
+T_DECL(realpath_symlink, "Resolve symlinked paths")
+{
+       char *resolved_tmpdir;
+       char path[MAXPATHLEN] = { 0 };
+       char slnk[MAXPATHLEN] = { 0 };
+       char resb[MAXPATHLEN] = { 0 };
+       int fd;
+
+       // We have to use the realpath for this symlink test.
+       // Otherwise, when trying to resolve a symlink, it won't match.
+       resolved_tmpdir = realpath(dt_tmpdir(), NULL);
+       snprintf(path, sizeof(path), "%s%s", resolved_tmpdir, "/real");
+       snprintf(slnk, sizeof(path), "%s%s", resolved_tmpdir, "/sym");
+
+       fd = open(path, O_RDONLY | O_CREAT, 0600);
+
+       T_WITH_ERRNO;
+       T_ASSERT_GE(fd, 0, NULL);
+       T_ASSERT_POSIX_ZERO(symlink(path, slnk), NULL);
+       T_ASSERT_POSIX_ZERO(close(fd), NULL);
+
+       T_ASSERT_NOTNULL(realpath(slnk, resb), NULL);
+       T_ASSERT_EQ_STR(resb, path, NULL);
+
+       T_ASSERT_POSIX_ZERO(unlink(path), NULL);
+       T_ASSERT_POSIX_ZERO(unlink(slnk), NULL);
+       free(resolved_tmpdir);
+}
diff --git a/tests/realpath_edge.c b/tests/realpath_edge.c
new file mode 100644 (file)
index 0000000..a98c76c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 Jan Kokemüller
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <darwintest.h>
+
+// Required for ASan
+#include "../fbsdcompat/_fbsd_compat_.h"
+#include "../stdlib/FreeBSD/realpath.c"
+#include "../gen/FreeBSD/getcwd.c"
+
+
+T_DECL(realpath_buffer_overflow, "Test for out of bounds read from 'left' array (compile realpath.c with '-fsanitize=address')")
+{
+       char path[MAXPATHLEN] = { 0 };
+       char resb[MAXPATHLEN] = { 0 };
+       size_t i;
+
+       path[0] = 'a';
+       path[1] = '/';
+       for (i = 2; i < sizeof(path) - 1; ++i) {
+               path[i] = 'a';
+       }
+
+       T_ASSERT_NULL(realpath(path, resb), NULL);
+}
+
index d0e96b2c99b37ff6287ebb86552cd676f57ef4c9..dc0f1b55434cef6e3d629738b912a727fbe61393 100644 (file)
@@ -8,7 +8,7 @@
 
 #define FILE_LIMIT 100
 
-T_DECL(PR_22813396, "STREAM_MAX is affected by changes to RLIMIT_NOFILE")
+T_DECL(stdio_PR_22813396, "STREAM_MAX is affected by changes to RLIMIT_NOFILE")
 {
        struct rlimit theLimit;
        getrlimit( RLIMIT_NOFILE, &theLimit );
@@ -34,3 +34,33 @@ T_DECL(PR_22813396, "STREAM_MAX is affected by changes to RLIMIT_NOFILE")
        f = fdopen(0, "r");
        T_EXPECT_NOTNULL(f, "fdopen succeed after RLIMIT_NOFILE increased");
 }
+
+T_DECL(stdio_PR_22813396_close, "STREAM_MAX is enforced properly after fclose")
+{
+       struct rlimit theLimit;
+       getrlimit( RLIMIT_NOFILE, &theLimit );
+       theLimit.rlim_cur = FILE_LIMIT;
+       setrlimit( RLIMIT_NOFILE, &theLimit );
+
+       long stream_max = sysconf(_SC_STREAM_MAX);
+       T_EXPECT_EQ_LONG(stream_max, (long)FILE_LIMIT, "stream_max = FILE_LIMIT");
+
+       FILE *f;
+       for(int i = 3; i < stream_max - 1; i++) {
+               if((f = fdopen(0, "r")) == NULL) {
+                       T_FAIL("Failed after %d streams", i);
+               }
+       }
+
+       // the last stream is for dup(0), it needs to be fclose'd
+       FILE *dupf = NULL;
+       T_EXPECT_NOTNULL(dupf = fdopen(dup(0), "r"), NULL);
+
+       T_EXPECT_NULL(f = fdopen(0, "r"), "fdopen fail after stream_max streams");
+
+       T_EXPECT_POSIX_ZERO(fclose(dupf), "fclose succeeds");
+
+       f = fdopen(0, "r");
+       T_WITH_ERRNO; T_EXPECT_NOTNULL(f, "fdopen succeed after fclose");
+}
+
diff --git a/tests/strerror.c b/tests/strerror.c
new file mode 100644 (file)
index 0000000..dc847c8
--- /dev/null
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2001 Wes Peters <wes@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "darwintest.h"
+
+static char buf[64];
+static char *sret;
+static int iret;
+
+T_DECL(strerror, "")
+{
+       //T_DECL(strerror_unknown_error, "")
+       errno = 0;
+       sret = strerror(INT_MAX);
+       snprintf(buf, sizeof(buf), "Unknown error: %d", INT_MAX);
+       T_EXPECT_EQ_STR(sret, buf, NULL);
+       T_EXPECT_EQ(errno, EINVAL, NULL);
+
+       //T_DECL(strerror_no_error, "")
+       errno = 0;
+       sret = strerror(0);
+       T_EXPECT_EQ_STR(sret, "Undefined error: 0", NULL);
+       T_EXPECT_EQ(errno, 0, NULL);
+
+       //T_DECL(strerror_EPERM_test, "")
+       errno = 0;
+       sret = strerror(EPERM);
+       T_EXPECT_EQ_STR(sret, "Operation not permitted", NULL);
+       T_EXPECT_EQ(errno, 0, NULL);
+
+       //T_DECL(strerror_EPFNOSUPPORT_test, "")
+       errno = 0;
+       sret = strerror(EPFNOSUPPORT);
+       T_EXPECT_EQ_STR(sret, "Protocol family not supported", NULL);
+       T_EXPECT_EQ(errno, 0, NULL);
+
+       //T_DECL(strerror_ELAST_test, "")
+       errno = 0;
+       sret = strerror(ELAST);
+       T_EXPECT_EQ(errno, 0, NULL);
+}
+
+T_DECL(strerror_r, "")
+{
+       memset(buf, '*', sizeof(buf));
+       iret = strerror_r(-1, buf, sizeof(buf));
+       T_EXPECT_EQ_STR(buf, "Unknown error: -1", NULL);
+       T_EXPECT_EQ(iret, EINVAL, NULL);
+
+       //T_DECL(strerror_r__EPERM_one_byte_short, "")
+       memset(buf, '*', sizeof(buf));
+       /* One byte too short. */
+       iret = strerror_r(EPERM, buf, strlen("Operation not permitted"));
+       T_EXPECT_EQ_STR(buf, "Operation not permitte", NULL);
+       T_EXPECT_EQ(iret, ERANGE, NULL);
+
+       //T_DECL(strerror_r__EPERM_unknown_error_one_byte_short, "")
+       memset(buf, '*', sizeof(buf));
+       /* One byte too short. */
+       iret = strerror_r(-1, buf, strlen("Unknown error: -1"));
+       T_EXPECT_EQ_STR(buf, "Unknown error: -", NULL);
+       T_EXPECT_EQ(iret, EINVAL, NULL);
+
+       //T_DECL(strerror_r__EPERM_unknown_error_two_bytes_short, "")
+       memset(buf, '*', sizeof(buf));
+       /* Two bytes too short. */
+       iret = strerror_r(-2, buf, strlen("Unknown error: -2") - 1);
+       T_EXPECT_EQ_STR(buf, "Unknown error: ", NULL);
+       T_EXPECT_EQ(iret, EINVAL, NULL);
+
+       //T_DECL(strerror_r__EPERM_unknown_error_three_bytes_short, "")
+       memset(buf, '*', sizeof(buf));
+       /* Three bytes too short. */
+       iret = strerror_r(-2, buf, strlen("Unknown error: -2") - 2);
+       T_EXPECT_EQ_STR(buf, "Unknown error:", NULL);
+       T_EXPECT_EQ(iret, EINVAL, NULL);
+
+       //T_DECL(strerror_r__EPERM_unknown_error_12345_one_byte_short, "")
+       memset(buf, '*', sizeof(buf));
+       /* One byte too short. */
+       iret = strerror_r(12345, buf, strlen("Unknown error: 12345"));
+       T_EXPECT_EQ_STR(buf, "Unknown error: 1234", NULL);
+       T_EXPECT_EQ(iret, EINVAL, NULL);
+
+       //T_DECL(strerror_r__no_error, "")
+       memset(buf, '*', sizeof(buf));
+       iret = strerror_r(0, buf, sizeof(buf));
+       T_EXPECT_EQ_STR(buf, "Undefined error: 0", NULL);
+       T_EXPECT_EQ(iret, 0, NULL);
+
+       //T_DECL(strerror_r__EDEADLK, "")
+       memset(buf, '*', sizeof(buf));
+       iret = strerror_r(EDEADLK, buf, sizeof(buf));
+       T_EXPECT_EQ_STR(buf, "Resource deadlock avoided", NULL);
+       T_EXPECT_EQ(iret, 0, NULL);
+
+       //T_DECL(strerror_r__EPROCLIM, "")
+       memset(buf, '*', sizeof(buf));
+       iret = strerror_r(EPROCLIM, buf, sizeof(buf));
+       T_EXPECT_EQ_STR(buf, "Too many processes", NULL);
+       T_EXPECT_EQ(iret, 0, NULL);
+}
diff --git a/tests/strlcpy.c b/tests/strlcpy.c
new file mode 100644 (file)
index 0000000..c90945a
--- /dev/null
@@ -0,0 +1,11 @@
+#include <string.h>
+
+#include <darwintest.h>
+
+T_DECL(strlcpy_PR_30745460, "Test return value of strlcpy(2)",
+               T_META_CHECK_LEAKS(NO))
+{
+       char buf[1];
+       T_EXPECT_EQ(strlcpy(buf, "text", 1), 4UL, NULL);
+       T_EXPECT_EQ(strlcpy(NULL, "text", 0), 4UL, NULL);
+}
index 804c5ec0ffc1c0ccab4619f9935a0169fc8e3055..7cbca30b5bfd12e58a08e3ef19b695f0fcd45190 100644 (file)
@@ -3,8 +3,34 @@
 #include <darwintest.h>
 #include <darwintest_utils.h>
 
-T_DECL(PR_27004626, "strptime() should fail when a %t doesn't match anything")
+T_DECL(strptime_PR_27004626, "strptime() should fail when a %t doesn't match anything")
 {
        struct tm tm;
        T_ASSERT_NULL(strptime("there'snotemplateforthis", "%t", &tm), NULL);
 }
+
+T_DECL(strptime_PR_29381762, "strptime() sets the tm_wday field incorrectly")
+{
+       time_t epoch = 0;
+       struct tm t = *localtime(&epoch);
+
+       T_LOG("2015-01-01 12:00:00 -> Thursday");
+       (void)strptime("2015-01-01 12:00:00", "%F %T", &t);
+       T_EXPECT_EQ(t.tm_wday, 4, NULL);
+
+       T_LOG("2015-04-19 12:00:00 -> Sunday");
+       (void)strptime("2015-04-19 12:00:00", "%F %T", &t);
+       T_EXPECT_EQ(t.tm_wday, 0, NULL);
+
+       T_LOG("2009-03-03 12:00:00 -> Tuesday");
+       (void)strptime("2009-03-03 12:00:00", "%F %T", &t);
+       T_EXPECT_EQ(t.tm_wday, 2, NULL);
+
+       T_LOG("1990-02-15 12:00:00 -> Thursday");
+       (void)strptime("1990-02-15 12:00:00", "%F %T", &t);
+       T_EXPECT_EQ(t.tm_wday, 4, NULL);
+
+       T_LOG("1993-03-02 12:00:00 -> Sunday");
+       (void)strptime("1993-03-02 12:00:00", "%F %T", &t);
+       T_EXPECT_EQ(t.tm_wday, 2, NULL);
+}
index 07d9aaa224442974d2644ffe1c1db3b4800324c2..f76dd14e8da1df35d3cc5d86db6cb9534f7ca553 100644 (file)
@@ -9,7 +9,7 @@
  * Test courtesy of Roel Standaert
  * Source: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=209907 
  */
-T_DECL(PR_26556792, "wcsrtombs neglects to set src pointer on EILSEQ error")
+T_DECL(wchar_PR_26556792, "wcsrtombs neglects to set src pointer on EILSEQ error")
 {
     char out[64];
     wchar_t *in = L"Hello! \x20AC Hello!";
@@ -21,7 +21,7 @@ T_DECL(PR_26556792, "wcsrtombs neglects to set src pointer on EILSEQ error")
 }
 
 
-T_DECL(PR_26828480, "double free in __vfwprintf")
+T_DECL(wchar_PR_26828480, "double free in __vfwprintf")
 {
     wchar_t *test;
     int ret;
index 39fcf076ef5c22d23532002c414e3d206c48b370..c1599cd2535be8747840cd85dfd019958b942e4a 100644 (file)
@@ -58,6 +58,9 @@
 #include <utmpx.h>
 #include <utmpx-darwin.h>
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
 void
 login(struct utmp *ut)
 {
@@ -70,3 +73,5 @@ login(struct utmp *ut)
        pututxline(&ux);
        endutxent();
 }
+
+#pragma clang diagnostic pop
index f18ca3456819314c9c25798f120139befaca3051..72e2bf7e673734ff07fb47f3e2b48a6f5533a7cd 100644 (file)
@@ -174,9 +174,9 @@ LFound0:
 
 LZeroBuffer:
        movq    %rdx,%rsi               // remaining buffer size (2nd argument)
-       subq    $8,%rsp                 // align stack to 16B before call
+       pushq   %r8                             // save r8 and align stack to 16B
        call    _bzero
-       addq    $8,%rsp                 // restore stack
+       popq    %r8
 
 LDone:
        movq    %r8,%rax                // original dest ptr is return value
index f2cbedd0ec3b7077d8e0374e12c940d7d9ce81e1..d86e479bb0d82dbbdf8ec896c8097a76e1052f12 100644 (file)
@@ -17,10 +17,12 @@ EXCLUDED_SOURCE_FILE_NAMES = *
 EXCLUDED_SOURCE_FILE_NAMES[sdk=iphoneos*] = $(VARIANT_EOS_EXCLUDED_FILES)
 EXCLUDED_SOURCE_FILE_NAMES[sdk=watchos*] = $(VARIANT_EOS_EXCLUDED_FILES)
 EXCLUDED_SOURCE_FILE_NAMES[sdk=appletvos*] = $(VARIANT_EOS_EXCLUDED_FILES)
+EXCLUDED_SOURCE_FILE_NAMES[sdk=bridgeos*] = $(VARIANT_EOS_EXCLUDED_FILES)
 INCLUDED_SOURCE_FILE_NAMES =
 INCLUDED_SOURCE_FILE_NAMES[sdk=iphoneos*] = $(VARIANT_EOS_INCLUDED_FILES)
 INCLUDED_SOURCE_FILE_NAMES[sdk=watchos*] = $(VARIANT_EOS_INCLUDED_FILES)
 INCLUDED_SOURCE_FILE_NAMES[sdk=appletvos*] = $(VARIANT_EOS_INCLUDED_FILES)
+INCLUDED_SOURCE_FILE_NAMES[sdk=bridgeos*] = $(VARIANT_EOS_INCLUDED_FILES)
 VARIANT_PREPROCESSOR_MACROS = -UBUILDING_VARIANT -DVARIANT_STATIC -DVARIANT_EOS -DVARIANT_CANCELABLE -DVARIANT_DARWINEXTSN -U__DARWIN_NON_CANCELABLE -D__DARWIN_NON_CANCELABLE=0
 
 SYSTEM_FRAMEWORK_HEADERS = $(DERIVED_FILES_DIR)/System.framework/Versions/B/PrivateHeaders
index e2d689f5e31697fd275fa562e40dd66d509034fd..0704fcd6b3f323ba34e56b7149adb891e41c4488 100755 (executable)
@@ -80,16 +80,11 @@ for my $arch (split(/ /, $ENV{"ARCHS"}))
        }
 
        elsif ($unifdef == 1) {
-               if ($platformName eq "macosx") {
-                       $unifdefs{"__OSX_OPEN_SOURCE__"} = 1;
-               }
                # assume FEATURE_BLOCKS was on by default
                $unifdefs{"UNIFDEF_BLOCKS"} = 1;
                $unifdefs{"UNIFDEF_LEGACY_64_APIS"} = defined($features{"FEATURE_LEGACY_64_APIS"});
                $unifdefs{"UNIFDEF_LEGACY_RUNE_APIS"} = defined($features{"FEATURE_LEGACY_RUNE_APIS"});
                $unifdefs{"UNIFDEF_LEGACY_UTMP_APIS"} = defined($features{"FEATURE_LEGACY_UTMP_APIS"});
-               $unifdefs{"UNIFDEF_MOVE_LOCALTIME"} = defined($features{"FEATURE_MOVE_LOCALTIME"});
-               $unifdefs{"UNIFDEF_TZDIR_SYMLINK"} = defined($features{"FEATURE_TZDIR_SYMLINK"});
                
                my $output = "";
                for my $d (keys %unifdefs) {
@@ -128,7 +123,9 @@ for my $arch (split(/ /, $ENV{"ARCHS"}))
 
                my $shortarch = $arch;
                $shortarch =~ s/armv\d+[a-z]?/arm/g;
-               $shortarch =~ s/arm64_32/arm64/g;
+
+               # map all arm64 subtypes to arm64
+               $shortarch =~ s/arm64[_a-z0-9]?/arm64/g;
 
                printf HEADER "#if !defined(__".$shortarch."__)\n";
                printf HEADER "#error Mismatched libc-features.h architecture\n";
@@ -152,18 +149,6 @@ for my $arch (split(/ /, $ENV{"ARCHS"}))
                        printf HEADER "/* #undef UNIFDEF_LEGACY_UTMP_APIS */\n";
                }
 
-               if (defined($features{"FEATURE_MOVE_LOCALTIME"})) {
-                       printf HEADER "#define UNIFDEF_MOVE_LOCALTIME 1\n";
-               } else {
-                       printf HEADER "/* #undef UNIFDEF_MOVE_LOCALTIME */\n";
-               }
-
-               if (defined($features{"FEATURE_TZDIR_SYMLINK"})) {
-                       printf HEADER "#define UNIFDEF_TZDIR_SYMLINK 1\n";
-               } else {
-                       printf HEADER "/* #undef UNIFDEF_TZDIR_SYMLINK */\n";
-               }
-
                if (defined($features{"FEATURE_ONLY_1050_VARIANTS"})) {
                        printf HEADER "#if !__DARWIN_ONLY_VERS_1050\n";
                        printf HEADER "#  error Feature mismatch: __DARWIN_ONLY_VERS_1050 == 0\n";
@@ -212,12 +197,6 @@ for my $arch (split(/ /, $ENV{"ARCHS"}))
                        printf HEADER "/* #undef NOTIFY_TZ */\n";
                }
 
-               if (defined($features{"FEATURE_NO_LIBCRASHREPORTERCLIENT"})) {
-                       printf HEADER "#define LIBC_NO_LIBCRASHREPORTERCLIENT 1\n";
-               } else {
-                       printf HEADER "/* #undef LIBC_NO_LIBCRASHREPORTERCLIENT */\n";
-               }
-
                if (defined($features{"FEATURE_SMALL_STDIOBUF"})) {
                        printf HEADER "#define FEATURE_SMALL_STDIOBUF 1\n";
                } else {
index d447595b7db5c6750b2764dedafc8f32a237653d..64d1da8445d214547d2d0e302a44bb5113e9b493 100755 (executable)
@@ -143,7 +143,7 @@ fi
 INC_PROTO_INSTHDRS=( routed.h rwhod.h talkd.h timed.h )
 PROTO_INSTHDRS=( "${INC_PROTO_INSTHDRS[@]/#/${SRCROOT}/include/protocols/}" )
 
-INC_SECURE_INSTHDRS=( _common.h _string.h _stdio.h )
+INC_SECURE_INSTHDRS=( _common.h _string.h _strings.h _stdio.h )
 SECURE_INSTHDRS=( "${INC_SECURE_INSTHDRS[@]/#/${SRCROOT}/include/secure/}" )
 
 SYS_INSTHDRS=( ${SRCROOT}/include/sys/acl.h ${SRCROOT}/include/sys/statvfs.h )
@@ -180,6 +180,7 @@ LOCALHDRS=(
        ${SRCROOT}/darwin/libc_private.h
        ${SRCROOT}/gen/utmpx_thread.h
        ${SRCROOT}/nls/FreeBSD/msgcat.h
+       ${SRCROOT}/libdarwin/dirstat.h
 )
 
 OS_LOCALHDRS=( ${SRCROOT}/os/assumes.h ${SRCROOT}/os/debug_private.h )
diff --git a/xcodescripts/legacy_alias.list b/xcodescripts/legacy_alias.list
new file mode 100644 (file)
index 0000000..fe2ecc4
--- /dev/null
@@ -0,0 +1,19 @@
+# (i386 only)
+# There used to be legacy versions of various funciotns, but we've removed them
+# and just given everyone the UNIX2003 behavior. The legacy variant doesn't
+# build those functions anymore, they are just aliased to corresponding 32-bit
+# non-legacy symbols. e.g.:
+#      _opendir                                        legacy, aliased to _opendir$UNIX2003
+#      _opendir$UNIX2003                       32-bit inodes
+#      _opendir$INODE64$UNIX2003       64-bit inodes
+
+___opendir2$UNIX2003   ___opendir2
+__seekdir$UNIX2003             __seekdir
+_closedir$UNIX2003             _closedir
+_fdopendir$UNIX2003            _fdopendir
+_opendir$UNIX2003              _opendir
+_rewinddir$UNIX2003            _rewinddir
+_seekdir$UNIX2003              _seekdir
+_telldir$UNIX2003              _telldir
+
+_strerror$UNIX2003             _strerror
index 3559c3499829650174f2464b468d94fbba4a7f9c..a7a10814c14d638809fbe0a83493989d472a5fbe 100644 (file)
@@ -1,7 +1,7 @@
 #include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig"
 
 // Standard settings
-SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator iphoneosnano iphonesimulatornano
+SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator iphoneosnano iphonesimulatornano bridgeos
 SRCROOT_SEARCH_PATHS = $(SRCROOT) $(SRCROOT)/include $(SRCROOT)/gen $(SRCROOT)/locale $(SRCROOT)/locale/FreeBSD $(SRCROOT)/stdtime/FreeBSD $(SRCROOT)/darwin
 SYSTEM_FRAMEWORK_HEADERS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
 HEADER_SEARCH_PATHS = $($(TARGET_NAME)_SEARCH_PATHS) $(DERIVED_FILES_DIR)/dtrace $(SRCROOT_SEARCH_PATHS) $(SYSTEM_FRAMEWORK_HEADERS) $(SDKROOT)/usr/local/include $(inherited)
@@ -24,7 +24,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES;
 GCC_WARN_UNUSED_VARIABLE = YES;
 GCC_WARN_ABOUT_RETURN_TYPE = YES;
 //WARNING_CFLAGS = -Wall -Wextra
-WARNING_CFLAGS = -Wall -Werror=incompatible-pointer-types -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-nullability-completeness
+WARNING_CFLAGS = -Wall -Werror -Wno-error=shorten-64-to-32 -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-nullability-completeness
 
 COPY_PHASE_STRIP = NO
 SKIP_INSTALL = YES
@@ -46,6 +46,9 @@ INSTALL_PATH = /usr/lib/system
 PUBLIC_HEADERS_FOLDER_PATH = /usr/include
 PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include
 
+DARWIN_PUBLIC_HEADERS_FOLDER_PATH = /usr/include/os
+DARWIN_PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/os
+
 // Simulator
 BASE_PREPROCESSOR_MACROS = __LIBC__ __DARWIN_UNIX03=1 __DARWIN_64_BIT_INO_T=1 __DARWIN_NON_CANCELABLE=1 __DARWIN_VERS_1050=1 _FORTIFY_SOURCE=0
 OTHER_CFLAGS = -fdollars-in-identifiers -fno-common -fverbose-asm $($(TARGET_NAME)_CFLAGS) $(VARIANT_PREPROCESSOR_MACROS)
@@ -53,23 +56,28 @@ OTHER_CFLAGS_debug = -fstack-protector -fno-inline -O0 -DDEBUG=1
 SIM_SUFFIX[sdk=*simulator*] = _sim
 
 GCC_PREPROCESSOR_DEFINITIONS = $(BASE_PREPROCESSOR_MACROS)
-GCC_PREPROCESSOR_DEFINITIONS[sdk=iphone*] = $(BASE_PREPROCESSOR_MACROS) LIBC_NO_LIBCRASHREPORTERCLIENT=1
 
 // libsystem_c.dylib linking
 CR_LDFLAGS = -lCrashReporterClient
 LIBCOMPILER_RT_LDFLAGS = -lcompiler_rt
 LIBMALLOC_LDFLAGS = -lsystem_malloc
+LIBC_LDFLAGS = -lsystem_c
+LIBDISPATCH_LDFLAGS = -ldispatch
+LIBXPC_LDFLAGS = -lxpc
 LIBPLATFORM_LDFLAGS = -lsystem$(SIM_SUFFIX)_platform
 LIBPTHREAD_LDFLAGS = -lsystem$(SIM_SUFFIX)_pthread
 LIBSYSCALL_LDFLAGS = -lsystem$(SIM_SUFFIX)_kernel
 LIBM_LDFLAGS = -lsystem$(SIM_SUFFIX)_m
 LIBDYLD_LDFLAGS = -ldyld
-LIBSYSTEM_C_LDFLAGS = -all_load -nostdlib -L/usr/lib/system -umbrella System $(CR_LDFLAGS) $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBM_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(UPWARD_LDFLAGS) -Wl,-interposable_list,$(DERIVED_FILES_DIR)/interposable.list -Wl,-unexported_symbols_list,$(DERIVED_FILES_DIR)/unexport.list -Wl,-alias_list,$(SRCROOT)/xcodescripts/alias.list -Wl,-order_file,$(SRCROOT)/xcodescripts/Libc.order -Wl,-sectalign,__DATA,__data,1000 @$(BUILT_PRODUCTS_DIR)/$(CURRENT_VARIANT).linklist
+LIBSYSTEM_C_LDFLAGS = -all_load -nostdlib -L/usr/lib/system -umbrella System $(CR_LDFLAGS) $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBM_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(UPWARD_LDFLAGS) $(LIBSYSTEM_C_EXTRA_LDFLAGS_$(CURRENT_ARCH)) -Wl,-interposable_list,$(DERIVED_FILES_DIR)/interposable.list -Wl,-unexported_symbols_list,$(DERIVED_FILES_DIR)/unexport.list -Wl,-alias_list,$(SRCROOT)/xcodescripts/alias.list -Wl,-order_file,$(SRCROOT)/xcodescripts/Libc.order -Wl,-sectalign,__DATA,__data,1000 @$(BUILT_PRODUCTS_DIR)/$(CURRENT_VARIANT).linklist
+LIBSYSTEM_C_EXTRA_LDFLAGS_i386 = -Wl,-alias_list,$(SRCROOT)/xcodescripts/legacy_alias.list
 
 // TODO: Remove upward links - mostly <rdar://problem/13183469>, macho is for assumes.c
 UPWARD_LDFLAGS = -Wl,-upward-ldispatch -Wl,-upward-llaunch -Wl,-upward-lmacho -Wl,-upward-lsystem_asl -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_info -Wl,-upward-lsystem_notify -Wl,-upward-lxpc -Wl,-upward-lcorecrypto
 UPWARD_LDFLAGS[sdk=*simulator*] = -Wl,-upward-ldispatch -Wl,-upward-lmacho_sim -Wl,-upward-lsystem_asl -Wl,-upward-lsystem_sim_blocks -Wl,-upward-lsystem_sim_info -Wl,-upward-lsystem_notify -Wl,-upward-lxpc -Wl,-upward-lcorecrypto
 
+LIBSYSTEM_DARWIN_LDFLAGS = -all_load -nostdlib -L/usr/lib/system -umbrella System $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBM_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBC_LDFLAGS) $(LIBDISPATCH_LDFLAGS) $(LIBXPC_LDFLAGS)
+
 // libPlatform.a architectures
 ARCH_FAMILY = $(ARCH_FAMILY_$(CURRENT_ARCH))
 ARCH_FAMILY_x86_64 = x86_64
@@ -79,6 +87,8 @@ ARCH_FAMILY_armv7 = arm
 ARCH_FAMILY_armv7s = arm
 ARCH_FAMILY_armv7f = arm
 ARCH_FAMILY_armv7k = arm
+ARCH_FAMILY_arm64 = arm64
+ARCH_FAMILY_arm64_32 = arm64
 
 // Platform target
 Platform_INCLUDED_SOURCE_FILE_NAMES = $(Platform_INCLUDED_SOURCE_FILE_NAMES_gen) $(Platform_INCLUDED_SOURCE_FILE_NAMES_stdlib) $(Platform_INCLUDED_SOURCE_FILE_NAMES_string)
@@ -98,6 +108,9 @@ FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7s = $(FreeBSD_INCLUDED_SOURCE_FILE_NAMES
 FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7k = $(FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7)
 FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7f = $(FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7)
 FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv6 = $(FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7)
+FreeBSD_INCLUDED_SOURCE_FILE_NAMES_arm64 = $(FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7)
+FreeBSD_INCLUDED_SOURCE_FILE_NAMES_arm64_32 = $(FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7)
+FreeBSD_INCLUDED_SOURCE_FILE_NAMES_arm64e = $(FreeBSD_INCLUDED_SOURCE_FILE_NAMES_armv7)
 
 // NetBSD target
 NetBSD_CFLAGS = -include $(SRCROOT)/nbsdcompat/_nbsd_compat_.h
@@ -116,6 +129,9 @@ BASE_EXCLUDED_SOURCE_FILE_NAMES_armv7s = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_armv7
 BASE_EXCLUDED_SOURCE_FILE_NAMES_armv7k = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_armv7)
 BASE_EXCLUDED_SOURCE_FILE_NAMES_armv7f = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_armv7)
 BASE_EXCLUDED_SOURCE_FILE_NAMES_armv6 = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_armv7)
+BASE_EXCLUDED_SOURCE_FILE_NAMES_arm64 = strlen.c strnlen.c kvm.c nlist.c
+BASE_EXCLUDED_SOURCE_FILE_NAMES_arm64_32 = strlen.c strnlen.c kvm.c nlist.c
+BASE_EXCLUDED_SOURCE_FILE_NAMES_arm64e = strlen.c strnlen.c kvm.c nlist.c
 
 // Rune support isn't included on iOS but there's no better way to exclude their complication
 BASE_EXCLUDED_SOURCE_FILE_NAMES_macosx = OSMemoryNotification.c
@@ -125,6 +141,7 @@ BASE_EXCLUDED_SOURCE_FILE_NAMES_appletvos = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_ip
 BASE_EXCLUDED_SOURCE_FILE_NAMES_appletvsimulator = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_iphonesimulator)
 BASE_EXCLUDED_SOURCE_FILE_NAMES_watchos = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_iphoneos)
 BASE_EXCLUDED_SOURCE_FILE_NAMES_watchsimulator = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_iphonesimulator)
+BASE_EXCLUDED_SOURCE_FILE_NAMES_bridgeos = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_iphoneos)
 
 // TODO: Remove these legacy platform names:
 BASE_EXCLUDED_SOURCE_FILE_NAMES_iphoneosnano = $(BASE_EXCLUDED_SOURCE_FILE_NAMES_watchos)
index 317cf2e6dac26000019ef377648f9c5273c70f9b..32054df1e46732d9bd839edc860c69bdc9a09bc3 100644 (file)
@@ -2,6 +2,7 @@
 
 if [ "$ACTION" = installhdrs ]; then exit 0; fi
 if [ "${PLATFORM_NAME}" != "macosx" ]; then exit 0; fi
+if [ "${SKIP_MANPAGES}" = "YES" ]; then exit 0; fi
 
 UNIFDEF_FLAGS=`${SRCROOT}/xcodescripts/generate_features.pl --unifdef`
 MANPAGES_LIST="${SRCROOT}/man/manpages.lst"
index 24da935346365dba1ae8dfe947a2001804464323..a71d758e3e517efa3c3ab9c122abc4a8e87939af 100644 (file)
@@ -71,6 +71,9 @@ sub process {
                        my $sym;
                        if($n > 0) {
                                my($sym) = ($save[$n - 1] =~ /__DARWIN_(?:10\d+|ALIAS|EXTSN|INODE64)[^(]*\(([^)]*)\)/);
+                               if($save[$n - 1] =~ /__DARWIN_ALIAS_STARTING/) {
+                                       undef $sym;
+                               }
                                if(defined($sym)) {
                                        if(defined($path)) {
                                                print "  $path\n";
index 6134dccf710d6a25dbfa4f039f8435ac63aba28a..415f81c354b8b0f98b4fd3f062d77893629c8d7d 100644 (file)
@@ -44,18 +44,17 @@ VARIANT_LEGACY_MACROS = -U__DARWIN_UNIX03 -D__DARWIN_UNIX03=0 -U__DARWIN_64_BIT_
 
 VARIANT_LEGACY_INCLUDE = $(VARIANT_LEGACY_INCLUDE_$(PLATFORM_NAME))
 VARIANT_LEGACY_INCLUDE_macosx = $(VARIANT_LEGACY_INCLUDE_$(PLATFORM_NAME)_$(CURRENT_ARCH))
-VARIANT_LEGACY_INCLUDE_macosx_i386 = $(VARIANT_LEGACY_INCLUDE_compat) $(VARIANT_LEGACY_INCLUDE_gdtoa) $(VARIANT_LEGACY_INCLUDE_gen) $(VARIANT_LEGACY_INCLUDE_locale) $(VARIANT_LEGACY_INCLUDE_net) $(VARIANT_LEGACY_INCLUDE_regex) $(VARIANT_LEGACY_INCLUDE_stdio) $(VARIANT_LEGACY_INCLUDE_stdlib) $(VARIANT_LEGACY_INCLUDE_stdtime) $(VARIANT_LEGACY_INCLUDE_string) $(VARIANT_LEGACY_INCLUDE_sys)
+VARIANT_LEGACY_INCLUDE_macosx_i386 = $(VARIANT_LEGACY_INCLUDE_compat) $(VARIANT_LEGACY_INCLUDE_gdtoa) $(VARIANT_LEGACY_INCLUDE_gen) $(VARIANT_LEGACY_INCLUDE_locale) $(VARIANT_LEGACY_INCLUDE_net) $(VARIANT_LEGACY_INCLUDE_regex) $(VARIANT_LEGACY_INCLUDE_stdio) $(VARIANT_LEGACY_INCLUDE_stdlib) $(VARIANT_LEGACY_INCLUDE_stdtime) $(VARIANT_LEGACY_INCLUDE_sys)
 
 VARIANT_LEGACY_INCLUDE_compat = creat.c setregid.c setreuid.c sigcompat.c killpg.c
 VARIANT_LEGACY_INCLUDE_gdtoa = gdtoa-strtof.c gdtoa-strtod.c gdtoa-strtodg.c
-VARIANT_LEGACY_INCLUDE_gen = clock.c closedir.c confstr.c crypt.c fnmatch.c lockf.c nanosleep.c nftw.c nice.c opendir.c pause.c popen.c rewinddir.c seekdir.c setmode.c sleep.c telldir.c termios.c timezone.c ttyname.c usleep.c wait.c waitpid.c
+VARIANT_LEGACY_INCLUDE_gen = clock.c confstr.c crypt.c fnmatch.c lockf.c nanosleep.c nftw.c nice.c pause.c popen.c setmode.c sleep.c termios.c timezone.c ttyname.c usleep.c wait.c waitpid.c
 VARIANT_LEGACY_INCLUDE_locale = wcsftime.c
 VARIANT_LEGACY_INCLUDE_net = recv.c send.c
 VARIANT_LEGACY_INCLUDE_regex = regcomp.c
 VARIANT_LEGACY_INCLUDE_stdio = fdopen.c fopen.c fputs.c freopen.c fwrite.c tempnam.c
 VARIANT_LEGACY_INCLUDE_stdlib = getopt.c putenv.c realpath.c setenv.c system.c
 VARIANT_LEGACY_INCLUDE_stdtime = localtime.c strftime.c strptime.c
-VARIANT_LEGACY_INCLUDE_string = strerror.c
 VARIANT_LEGACY_INCLUDE_sys = msgctl.c semctl.c shmctl.c
 
 // INODE32 symbols
@@ -85,6 +84,8 @@ VARIANT_DYLD_INCLUDE_sys = _libc_init.c
 VARIANT_DYLD_INCLUDE_x86_64 = x86_64/string/strcpy.s x86_64/string/strlen.s x86_64/string/strncpy.s x86_64/string/strnlen.s            strstr.c
 VARIANT_DYLD_INCLUDE_i386 =     i386/string/strcpy.s   i386/string/strlen.s   i386/string/strncpy.s               strnlen.c            strstr.c
 VARIANT_DYLD_INCLUDE_armv7 =                strcpy.c    arm/string/strlen.s               strncpy.c    arm/string/strnlen.s arm/string/strstr.s
+VARIANT_DYLD_INCLUDE_arm64 =                strcpy.c                                      strncpy.c  arm64/string/strnlen.s            strstr.c
+VARIANT_DYLD_INCLUDE_arm64_32 =             strcpy.c                                      strncpy.c  arm64/string/strnlen.s            strstr.c
 
 VARIANT_DYLD_INCLUDE_armv7s = $(VARIANT_DYLD_INCLUDE_armv7)
 VARIANT_DYLD_INCLUDE_armv7k = $(VARIANT_DYLD_INCLUDE_armv7)