From b061a43bf32824cb214e9e3a29a974341de443d4 Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 26 Sep 2017 16:52:03 +0000 Subject: [PATCH] Libc-1244.1.7.tar.gz --- .gitattributes | 1 + .upstream_base_commits | 42 +- Libc.xcodeproj/project.pbxproj | 350 ++++-- Platforms/appletvos/Makefile.inc | 11 - Platforms/bridgeos/Makefile.inc | 8 +- Platforms/iphoneos/Makefile.inc | 11 - Platforms/macosx/Makefile.inc | 6 - Platforms/watchos/Makefile.inc | 11 - emulated/statvfs.c | 12 +- fbsdcompat/_fbsd_compat_.h | 6 + fbsdcompat/_fpmath.h | 2 +- fbsdcompat/spinlock.h | 10 +- gdtoa/FreeBSD/_ldtoa.c | 2 +- gdtoa/FreeBSD/gdtoa-hexnan.c | 2 +- gdtoa/arith.h | 7 + gdtoa/gd_qnan.h | 2 +- gen/FreeBSD/arc4random.3 | 4 +- gen/FreeBSD/arc4random.c | 2 +- gen/FreeBSD/closedir.c | 19 +- gen/FreeBSD/err.c | 9 + gen/FreeBSD/getcwd.3 | 20 +- gen/FreeBSD/getlogin.c | 1 - gen/FreeBSD/getmntinfo.3 | 57 +- gen/FreeBSD/getmntinfo.c | 75 +- gen/FreeBSD/getpeereid.c | 6 +- gen/FreeBSD/glob.3 | 60 +- gen/FreeBSD/glob.c | 745 +++++++----- gen/FreeBSD/opendir.c | 376 +++--- gen/FreeBSD/readdir.c | 28 +- gen/FreeBSD/rewinddir.c | 29 +- gen/FreeBSD/scandir.c | 54 +- gen/FreeBSD/scandir_b.c | 111 +- gen/FreeBSD/seekdir.c | 6 +- gen/FreeBSD/telldir.c | 127 ++- gen/FreeBSD/telldir.h | 5 + gen/FreeBSD/ttyname.3 | 117 +- gen/FreeBSD/ttyslot.c | 22 +- gen/FreeBSD/vis.c | 2 +- gen/NetBSD/rb.c | 2 +- gen/NetBSD/rbtree.3 | 109 +- gen/__dirent.h | 1 - gen/clock_gettime.c | 6 +- gen/crypt.c | 2 +- gen/disklabel.c | 12 +- gen/fts.c | 46 +- gen/getttyent.c | 4 +- gen/nanosleep.c | 2 +- gen/nlist.c | 6 +- gen/strtofflags.c | 2 +- gen/sync_volume_np.c | 2 +- gen/thread_stack_pcs.c | 6 +- gen/utmpx-darwin.c | 158 +-- include/_types.h | 1 + include/_types/_nl_item.h | 1 + include/_types/_wctrans_t.h | 1 + include/_types/_wctype_t.h | 1 + include/assert.h | 2 +- include/dirent.h | 4 +- include/fsproperties.h | 2 + include/glob.h | 6 +- include/limits.h | 2 +- include/secure/_string.h | 78 +- include/secure/_strings.h | 59 + include/stdint.h | 25 +- include/stdio.h | 2 + include/stdlib.h | 20 +- include/string.h | 2 - include/strings.h | 5 + include/sys/cdefs.h | 2 +- include/sys/rbtree.h | 7 + include/time.h | 2 +- include/unistd.h | 17 +- include/wchar.h | 1 + libdarwin/AppleInternalVariant.plist | 8 + libdarwin/dirstat.c | 365 ++++++ libdarwin/dirstat.h | 54 + libdarwin/dirstat_collection.c | 216 ++++ libdarwin/dirstat_collection.h | 37 + .../init.c | 21 +- libdarwin/variant.c | 494 ++++++++ locale/FreeBSD/collate.c | 8 +- locale/FreeBSD/gb18030.c | 2 +- locale/FreeBSD/gb2312.c | 2 +- locale/FreeBSD/setrunelocale.c | 12 +- locale/FreeBSD/wcstod.c | 1 + locale/xlocale.c | 6 +- locale/xlocale_private.h | 8 +- man/manpages.lst | 12 +- net/FreeBSD/inet.3 | 11 - os/assumes.c | 57 +- os/assumes.h | 265 +++-- os/variant_private.h | 145 +++ secure/chk_fail.c | 109 ++ stdio/FreeBSD/_flock_stub.c | 13 +- stdio/FreeBSD/fgetwc.c | 2 +- stdio/FreeBSD/findfp.c | 20 +- stdio/FreeBSD/fmemopen.c | 262 +++++ stdio/FreeBSD/fopen.3 | 227 ++-- stdio/FreeBSD/fputs.c | 2 +- stdio/FreeBSD/getdelim.c | 4 +- stdio/FreeBSD/mktemp.3 | 42 +- stdio/FreeBSD/mktemp.c | 75 +- stdio/FreeBSD/open_memstream.3 | 155 +++ stdio/FreeBSD/open_memstream.c | 210 ++++ stdio/FreeBSD/open_wmemstream.c | 274 +++++ stdio/FreeBSD/printf.3 | 20 + stdio/FreeBSD/vfprintf.c | 74 +- stdio/FreeBSD/vfwprintf.c | 39 +- stdio/FreeBSD/vswprintf.c | 2 +- stdio/FreeBSD/xprintf_float.c | 1 + stdio/FreeBSD/xprintf_int.c | 4 +- stdlib/FreeBSD/atexit.3 | 31 +- stdlib/FreeBSD/exit.c | 8 + stdlib/FreeBSD/getenv.c | 10 +- stdlib/FreeBSD/psort.c | 13 +- stdlib/FreeBSD/psort_b.c | 13 +- stdlib/FreeBSD/psort_r.c | 13 +- stdlib/FreeBSD/qsort.c | 247 ++-- stdlib/FreeBSD/realpath.3 | 2 +- stdlib/FreeBSD/realpath.c | 51 +- stdlib/FreeBSD/setenv.c | 14 +- stdlib/FreeBSD/system.c | 2 + stdlib/qsort_b-fbsd.c | 8 - stdlib/qsort_b.c | 11 + stdtime/FreeBSD/ctime.3 | 15 +- stdtime/FreeBSD/ftime.c | 2 +- stdtime/FreeBSD/localtime.c | 996 ++++++++++------ stdtime/FreeBSD/private.h | 13 +- stdtime/FreeBSD/strftime.c | 8 +- stdtime/FreeBSD/strptime.c | 78 +- stdtime/FreeBSD/tzfile.5 | 24 +- stdtime/FreeBSD/tzfile.h | 92 +- stdtime/timegm.3 | 86 -- string/FreeBSD/strerror.c | 24 +- string/FreeBSD/strlcpy.3 | 138 ++- string/NetBSD/memset_s.3 | 2 +- sys/crt_externs.c | 2 +- sys/gettimeofday.c | 6 +- sys/settimeofday.c | 8 + tests/Makefile | 24 +- tests/assumes.c | 40 + tests/assumes_legacy.c | 23 + tests/dir.c | 258 +++++ tests/dirstat.c | 120 ++ tests/err.c | 25 + tests/flockfile.c | 26 + tests/freebsd_fmemopen.c | 268 +++++ tests/freebsd_glob.c | 109 ++ tests/freebsd_open_memstream.c | 185 +++ tests/freebsd_open_wmemstream.c | 185 +++ tests/freebsd_qsort.c | 90 ++ tests/freebsd_qsort.h | 312 +++++ tests/fts_find.c | 38 +- tests/locale.c | 10 +- tests/mktemp.c | 8 +- tests/net.c | 70 +- tests/netbsd_fmemopen.c | 1010 +++++++++++++++++ tests/netbsd_getenv_thread.c | 3 +- tests/netbsd_glob.c | 249 ++++ tests/netbsd_open_memstream.c | 83 ++ tests/netbsd_printf.c | 102 ++ tests/netbsd_stat.c | 64 +- tests/netbsd_strerror.c | 105 ++ tests/netbsd_vis.c | 2 +- tests/os_variant.c | 155 +++ tests/printf.c | 66 ++ tests/psort.c | 19 +- tests/qsort.c | 54 + tests/qsort_perf.c | 256 +++++ tests/realpath.c | 135 +++ tests/realpath_edge.c | 59 + tests/stdio.c | 32 +- tests/strerror.c | 134 +++ tests/strlcpy.c | 11 + tests/strptime.c | 28 +- tests/wchar.c | 4 +- util/login.c | 5 + x86_64/string/strncpy.s | 4 +- xcodescripts/eos.xcconfig | 2 + xcodescripts/generate_features.pl | 27 +- xcodescripts/headers.sh | 3 +- xcodescripts/legacy_alias.list | 19 + xcodescripts/libc.xcconfig | 25 +- xcodescripts/manpages.sh | 1 + xcodescripts/patch_headers_variants.pl | 3 + xcodescripts/variants.xcconfig | 7 +- 186 files changed, 10187 insertions(+), 2403 deletions(-) create mode 100644 .gitattributes create mode 100644 include/secure/_strings.h create mode 100644 libdarwin/AppleInternalVariant.plist create mode 100644 libdarwin/dirstat.c create mode 100644 libdarwin/dirstat.h create mode 100644 libdarwin/dirstat_collection.c create mode 100644 libdarwin/dirstat_collection.h rename darwin/init_cpu_capabilities.c => libdarwin/init.c (71%) create mode 100644 libdarwin/variant.c create mode 100644 os/variant_private.h create mode 100644 stdio/FreeBSD/fmemopen.c create mode 100644 stdio/FreeBSD/open_memstream.3 create mode 100644 stdio/FreeBSD/open_memstream.c create mode 100644 stdio/FreeBSD/open_wmemstream.c delete mode 100644 stdlib/qsort_b-fbsd.c create mode 100644 stdlib/qsort_b.c delete mode 100644 stdtime/timegm.3 create mode 100644 tests/assumes.c create mode 100644 tests/assumes_legacy.c create mode 100644 tests/dir.c create mode 100644 tests/dirstat.c create mode 100644 tests/err.c create mode 100644 tests/flockfile.c create mode 100644 tests/freebsd_fmemopen.c create mode 100644 tests/freebsd_glob.c create mode 100644 tests/freebsd_open_memstream.c create mode 100644 tests/freebsd_open_wmemstream.c create mode 100644 tests/freebsd_qsort.c create mode 100644 tests/freebsd_qsort.h create mode 100644 tests/netbsd_fmemopen.c create mode 100644 tests/netbsd_glob.c create mode 100644 tests/netbsd_open_memstream.c create mode 100644 tests/netbsd_printf.c create mode 100644 tests/netbsd_strerror.c create mode 100644 tests/os_variant.c create mode 100644 tests/printf.c create mode 100644 tests/qsort.c create mode 100644 tests/qsort_perf.c create mode 100644 tests/realpath.c create mode 100644 tests/realpath_edge.c create mode 100644 tests/strerror.c create mode 100644 tests/strlcpy.c create mode 100644 xcodescripts/legacy_alias.list diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5012327 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.upstream_base_commits merge=union diff --git a/.upstream_base_commits b/.upstream_base_commits index e512103..efee8b9 100644 --- a/.upstream_base_commits +++ b/.upstream_base_commits @@ -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 diff --git a/Libc.xcodeproj/project.pbxproj b/Libc.xcodeproj/project.pbxproj index adda4b8..6802ba6 100644 --- a/Libc.xcodeproj/project.pbxproj +++ b/Libc.xcodeproj/project.pbxproj @@ -18,6 +18,17 @@ 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 */ @@ -111,6 +122,13 @@ 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 */; }; @@ -121,6 +139,7 @@ 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 */; }; @@ -609,7 +628,7 @@ 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 */; }; @@ -715,12 +734,6 @@ 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 */; }; @@ -741,12 +754,6 @@ 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 */; }; @@ -1543,7 +1550,7 @@ 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 */; }; @@ -2081,7 +2088,7 @@ 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 */; }; @@ -2604,7 +2611,7 @@ 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 */; }; @@ -3127,7 +3134,7 @@ 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 */; }; @@ -3650,7 +3657,7 @@ 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 */; }; @@ -4201,7 +4208,7 @@ 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 */; }; @@ -4307,12 +4314,6 @@ 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 */; }; @@ -4325,12 +4326,6 @@ 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 */; }; @@ -4836,7 +4831,7 @@ 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 */; }; @@ -5359,7 +5354,7 @@ 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 */; }; @@ -5535,7 +5530,7 @@ 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 */; }; @@ -5565,6 +5560,13 @@ 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 */; @@ -5774,10 +5776,23 @@ 63D4060C13DDF26A0094DD56 /* strcat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = strcat.c; sourceTree = ""; }; 63D4060F13DDF4340094DD56 /* strncat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = strncat.c; sourceTree = ""; }; 63D4061213DDF6A20094DD56 /* strlcat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = strlcat.c; sourceTree = ""; }; + 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 = ""; }; + 926F73991E03E8D6001E049D /* variant_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = variant_private.h; path = os/variant_private.h; sourceTree = ""; }; + 92767C821E0A7E2100AB9C76 /* init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = init.c; sourceTree = ""; }; + 9280EA171E59BC8A007A6F58 /* AppleInternalVariant.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AppleInternalVariant.plist; sourceTree = ""; }; + 928841341EA7554D001064D1 /* dirstat_collection.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dirstat_collection.c; sourceTree = ""; }; + 92888B0F1EA5BE6D00BA923E /* fmemopen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmemopen.c; sourceTree = ""; }; + 92888B101EA5BE6D00BA923E /* open_memstream.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = open_memstream.3; sourceTree = ""; }; + 92888B111EA5BE6D00BA923E /* open_memstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = open_memstream.c; sourceTree = ""; }; + 92888B121EA5BE6D00BA923E /* open_wmemstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = open_wmemstream.c; sourceTree = ""; }; 928BD0FD1D7606EA00EC01FC /* timingsafe_bcmp.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = timingsafe_bcmp.3; sourceTree = ""; }; 928BD0FE1D7606EA00EC01FC /* timingsafe_bcmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = timingsafe_bcmp.c; sourceTree = ""; }; 928BD1091D7608A400EC01FC /* environ.7 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = environ.7; sourceTree = ""; }; 92ABC7E81D375FC2000DF880 /* compatibility_hacks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compatibility_hacks.c; sourceTree = ""; }; + 92D763DC1EA6D9FB001467FC /* dirstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dirstat.c; sourceTree = ""; }; + 92D763E41EA6F887001467FC /* dirstat_collection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirstat_collection.h; sourceTree = ""; }; + 92D763E51EA6F887001467FC /* dirstat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirstat.h; sourceTree = ""; }; 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 = ""; }; B122F2B11432B95B00AF95D0 /* regcomp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = regcomp.c; sourceTree = ""; }; @@ -5819,17 +5834,12 @@ B1795372158B0E35008990E8 /* xprintf_exec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xprintf_exec.c; sourceTree = ""; }; B19C64591450F8B900032373 /* sync_volume_np.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sync_volume_np.3; sourceTree = ""; }; B19C645B1450F90200032373 /* sync_volume_np.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sync_volume_np.c; sourceTree = ""; }; + C00AC1181E04B7E000286B61 /* legacy_opendir_alias.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = legacy_opendir_alias.list; sourceTree = ""; }; C06E02D11CA0C9CA00B07322 /* tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = tests; sourceTree = ""; }; C0E343811C58299D00E749C2 /* skip_installhdrs.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = skip_installhdrs.sh; sourceTree = ""; }; 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 = ""; }; C9194B4C140E3BC700BE0C3A /* build_linklists.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build_linklists.sh; sourceTree = ""; }; - C921D3831395B7DD001CE070 /* init_cpu_capabilities.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = init_cpu_capabilities.c; sourceTree = ""; }; - C921D3841395B7DD001CE070 /* pthread_getspecific.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pthread_getspecific.s; sourceTree = ""; }; - C921D3851395B7DD001CE070 /* pthread_self.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pthread_self.s; sourceTree = ""; }; - C921D3861395B7DD001CE070 /* pthread_set_self.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pthread_set_self.s; sourceTree = ""; }; - C921D3871395B7DD001CE070 /* start_wqthread.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = start_wqthread.s; sourceTree = ""; }; - C921D3881395B7DD001CE070 /* thread_start.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = thread_start.s; sourceTree = ""; }; 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 = ""; }; @@ -6756,7 +6766,7 @@ C9B53CB5138D9E9A0028D27C /* ecvt.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = ecvt.3; sourceTree = ""; }; C9B53CB7138D9E9A0028D27C /* ecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ecvt.c; sourceTree = ""; }; C9B53CB9138D9E9A0028D27C /* gcvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gcvt.c; sourceTree = ""; }; - C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "qsort_b-fbsd.c"; sourceTree = ""; }; + C9B53CBD138D9E9A0028D27C /* qsort_b.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = qsort_b.c; sourceTree = ""; }; C9B53CBE138D9E9A0028D27C /* strtod_l.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = strtod_l.3; sourceTree = ""; }; C9B53CBF138D9E9A0028D27C /* strtol_l.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = strtol_l.3; sourceTree = ""; }; C9B53CC2138D9E9A0028D27C /* asctime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = asctime.c; sourceTree = ""; }; @@ -6948,6 +6958,7 @@ C9ECE2761950E384008E8672 /* atexit_receipt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atexit_receipt.c; sourceTree = ""; }; C9FA32F8138E4A5C0089A94B /* utf2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utf2.c; sourceTree = ""; }; 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 = ""; }; E41BEA97178E72E100E348BB /* Libc.order */ = {isa = PBXFileReference; lastKnownFileType = text; path = Libc.order; sourceTree = ""; }; E4A877A6174D82FB000DBB55 /* alias.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = alias.list; sourceTree = ""; }; FC2ED60E157D4BE70098EC69 /* inet_ntop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet_ntop.c; sourceTree = ""; }; @@ -6973,6 +6984,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 926F738F1E03E2A3001E049D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; B122F2A91432B8E600AF95D0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -7101,6 +7119,7 @@ 4B2C64A015519B0500342BFA /* os */ = { isa = PBXGroup; children = ( + 926F73991E03E8D6001E049D /* variant_private.h */, 2DF67CE7184F9CD000B83A3D /* debug_private.h */, 2DF67CDD184F9CBE00B83A3D /* debug_private.c */, 4B2C64AB15519C3400342BFA /* assumes.h */, @@ -7109,6 +7128,20 @@ name = os; sourceTree = ""; }; + 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 = ""; + }; B122F2AE1432B95B00AF95D0 /* TRE */ = { isa = PBXGroup; children = ( @@ -7167,9 +7200,10 @@ C9B53595138D9A690028D27C = { isa = PBXGroup; children = ( + 926F73961E03E8C4001E049D /* libdarwin */, C9B535AE138D9E980028D27C /* APPLE_LICENSE */, C9B535AF138D9E980028D27C /* arm */, - C9B535E2138D9E980028D27C /* arm */, + C9B535E2138D9E980028D27C /* arm64 */, C9B535F5138D9E980028D27C /* compat-43 */, C9B53612138D9E980028D27C /* darwin */, C9B5361D138D9E980028D27C /* db */, @@ -7226,6 +7260,7 @@ C97A721C1517AF53005E1998 /* libc_eOS.a */, 3F5120F116C3174300AFB431 /* libFortifySource.a */, C0E345E21C582ECB00E749C2 /* libc.a */, + 926F73921E03E2A3001E049D /* libsystem_darwin.dylib */, ); name = Products; sourceTree = ""; @@ -7257,12 +7292,12 @@ path = string; sourceTree = ""; }; - C9B535E2138D9E980028D27C /* arm */ = { + C9B535E2138D9E980028D27C /* arm64 */ = { isa = PBXGroup; children = ( C9B535EB138D9E980028D27C /* string */, ); - path = arm; + path = arm64; sourceTree = ""; }; C9B535EB138D9E980028D27C /* string */ = { @@ -7980,6 +8015,7 @@ C9B538A9138D9E990028D27C /* _common.h */, C9B538AA138D9E990028D27C /* _stdio.h */, C9B538AB138D9E990028D27C /* _string.h */, + E40EA6C01EAA8F9300B2FA36 /* _strings.h */, ); path = secure; sourceTree = ""; @@ -8434,6 +8470,7 @@ C9B53B55138D9E990028D27C /* flags.c */, C9B53B57138D9E990028D27C /* floatio.h */, C9B53B58138D9E990028D27C /* flockfile.3 */, + 92888B0F1EA5BE6D00BA923E /* fmemopen.c */, C9B53B5A138D9E990028D27C /* fopen.3 */, C9B53B5C138D9E990028D27C /* fopen.c */, C9B53B5E138D9E990028D27C /* fprintf.c */, @@ -8478,6 +8515,9 @@ 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 */, @@ -8564,7 +8604,7 @@ C9B53CAD138D9E9A0028D27C /* l64a.c */, C9B53CAF138D9E9A0028D27C /* NetBSD */, C9B53CB4138D9E9A0028D27C /* OpenBSD */, - C9B53CBD138D9E9A0028D27C /* qsort_b-fbsd.c */, + C9B53CBD138D9E9A0028D27C /* qsort_b.c */, C9B53CBE138D9E9A0028D27C /* strtod_l.3 */, C9B53CBF138D9E9A0028D27C /* strtol_l.3 */, ); @@ -8966,6 +9006,7 @@ isa = PBXGroup; children = ( E4A877A6174D82FB000DBB55 /* alias.list */, + C00AC1181E04B7E000286B61 /* legacy_opendir_alias.list */, C9C2A948138DF7DD00287F00 /* libc.xcconfig */, C9766153138ECF0000741512 /* variants.xcconfig */, C9AE91AE1517CDAC00A2626C /* eos.xcconfig */, @@ -9004,6 +9045,17 @@ }; /* 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; @@ -9039,6 +9091,24 @@ 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" */; @@ -9349,6 +9419,14 @@ 925E7FE619E8945900AC7889 = { CreatedOnToolsVersion = 6.1; }; + 926F73911E03E2A3001E049D = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; + 926F739D1E046E55001E049D = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; 928F25D01BEACED7007B13C7 = { CreatedOnToolsVersion = 7.1; }; @@ -9384,6 +9462,8 @@ 3F51206A16C3174300AFB431 /* FortifySource */, 925E7FE619E8945900AC7889 /* Libc_tests */, 928F25D01BEACED7007B13C7 /* darwintests */, + 926F739D1E046E55001E049D /* Libc_darwin */, + 926F73911E03E2A3001E049D /* libsystem_darwin.dylib */, ); }; /* End PBXProject section */ @@ -9434,6 +9514,21 @@ 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; @@ -9945,6 +10040,17 @@ ); 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; @@ -10422,7 +10528,7 @@ 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 */, @@ -10528,12 +10634,6 @@ 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 */, @@ -10746,6 +10846,7 @@ 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 */, @@ -10857,6 +10958,7 @@ 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 */, @@ -10910,6 +11012,7 @@ 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 */, @@ -10977,7 +11080,7 @@ 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 */, @@ -11462,7 +11565,7 @@ 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 */, @@ -11563,12 +11666,6 @@ 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 */, @@ -12017,7 +12114,7 @@ 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 */, @@ -12556,7 +12653,7 @@ 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 */, @@ -13095,7 +13192,7 @@ 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 */, @@ -13665,7 +13762,7 @@ 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 */, @@ -13771,12 +13868,6 @@ 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 */, @@ -13814,12 +13905,6 @@ 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 */, ); @@ -14370,7 +14455,7 @@ 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 */, @@ -14909,7 +14994,7 @@ 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 */, @@ -15449,7 +15534,7 @@ 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 */, @@ -15567,6 +15652,11 @@ 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 */; @@ -15731,6 +15821,86 @@ }; 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 = { @@ -15834,7 +16004,7 @@ 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; @@ -15848,7 +16018,7 @@ 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; }; @@ -16184,6 +16354,24 @@ 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 = ( diff --git a/Platforms/appletvos/Makefile.inc b/Platforms/appletvos/Makefile.inc index 7b485b2..aacbe5a 100644 --- a/Platforms/appletvos/Makefile.inc +++ b/Platforms/appletvos/Makefile.inc @@ -17,17 +17,6 @@ # 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/Platforms/bridgeos/Makefile.inc b/Platforms/bridgeos/Makefile.inc index dcb0cc6..ba2fd54 100644 --- a/Platforms/bridgeos/Makefile.inc +++ b/Platforms/bridgeos/Makefile.inc @@ -1,5 +1,5 @@ # -# Selectable features for Apple Watch +# Selectable features for bridgeOS # # Legacy *64 APIs @@ -17,12 +17,6 @@ # 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 diff --git a/Platforms/iphoneos/Makefile.inc b/Platforms/iphoneos/Makefile.inc index df32671..3ea7c19 100644 --- a/Platforms/iphoneos/Makefile.inc +++ b/Platforms/iphoneos/Makefile.inc @@ -17,17 +17,6 @@ # 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/Platforms/macosx/Makefile.inc b/Platforms/macosx/Makefile.inc index f48843d..9952af8 100644 --- a/Platforms/macosx/Makefile.inc +++ b/Platforms/macosx/Makefile.inc @@ -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 diff --git a/Platforms/watchos/Makefile.inc b/Platforms/watchos/Makefile.inc index 2253e33..b8c3680 100644 --- a/Platforms/watchos/Makefile.inc +++ b/Platforms/watchos/Makefile.inc @@ -17,17 +17,6 @@ # 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/emulated/statvfs.c b/emulated/statvfs.c index 8056189..5680001 100644 --- a/emulated/statvfs.c +++ b/emulated/statvfs.c @@ -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 */ diff --git a/fbsdcompat/_fbsd_compat_.h b/fbsdcompat/_fbsd_compat_.h index f134d5c..cdda374 100644 --- a/fbsdcompat/_fbsd_compat_.h +++ b/fbsdcompat/_fbsd_compat_.h @@ -172,6 +172,12 @@ #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) diff --git a/fbsdcompat/_fpmath.h b/fbsdcompat/_fpmath.h index fcd5aa3..ed38fc5 100644 --- a/fbsdcompat/_fpmath.h +++ b/fbsdcompat/_fpmath.h @@ -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; diff --git a/fbsdcompat/spinlock.h b/fbsdcompat/spinlock.h index 4fc0901..b3417ce 100644 --- a/fbsdcompat/spinlock.h +++ b/fbsdcompat/spinlock.h @@ -60,20 +60,20 @@ #ifndef _SPINLOCK_H_ #define _SPINLOCK_H_ #ifdef __APPLE__ -#include +#include -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__ */ diff --git a/gdtoa/FreeBSD/_ldtoa.c b/gdtoa/FreeBSD/_ldtoa.c index 903ce10..6367839 100644 --- a/gdtoa/FreeBSD/_ldtoa.c +++ b/gdtoa/FreeBSD/_ldtoa.c @@ -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) diff --git a/gdtoa/FreeBSD/gdtoa-hexnan.c b/gdtoa/FreeBSD/gdtoa-hexnan.c index 0c485b4..4de2605 100644 --- a/gdtoa/FreeBSD/gdtoa-hexnan.c +++ b/gdtoa/FreeBSD/gdtoa-hexnan.c @@ -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 diff --git a/gdtoa/arith.h b/gdtoa/arith.h index f60614a..0f5dd96 100644 --- a/gdtoa/arith.h +++ b/gdtoa/arith.h @@ -42,6 +42,13 @@ #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 diff --git a/gdtoa/gd_qnan.h b/gdtoa/gd_qnan.h index 601fff6..7c570ba 100644 --- a/gdtoa/gd_qnan.h +++ b/gdtoa/gd_qnan.h @@ -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 diff --git a/gen/FreeBSD/arc4random.3 b/gen/FreeBSD/arc4random.3 index d8d5502..a6b7f3d 100644 --- a/gen/FreeBSD/arc4random.3 +++ b/gen/FreeBSD/arc4random.3 @@ -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 diff --git a/gen/FreeBSD/arc4random.c b/gen/FreeBSD/arc4random.c index e49f56b..d2368d7 100644 --- a/gen/FreeBSD/arc4random.c +++ b/gen/FreeBSD/arc4random.c @@ -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; diff --git a/gen/FreeBSD/closedir.c b/gen/FreeBSD/closedir.c index 10bfe5e..e69e0ec 100644 --- a/gen/FreeBSD/closedir.c +++ b/gen/FreeBSD/closedir.c @@ -31,7 +31,7 @@ static char sccsid[] = "@(#)closedir.c 8.1 (Berkeley) 6/10/93"; #endif /* LIBC_SCCS and not lint */ #include -__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 @@ -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))); } diff --git a/gen/FreeBSD/err.c b/gen/FreeBSD/err.c index aec3422..f763764 100644 --- a/gen/FreeBSD/err.c +++ b/gen/FreeBSD/err.c @@ -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); } diff --git a/gen/FreeBSD/getcwd.3 b/gen/FreeBSD/getcwd.3 index 17f039e..707b8b8 100644 --- a/gen/FreeBSD/getcwd.3 +++ b/gen/FreeBSD/getcwd.3 @@ -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 , diff --git a/gen/FreeBSD/getlogin.c b/gen/FreeBSD/getlogin.c index ce4efc2..8f0d988 100644 --- a/gen/FreeBSD/getlogin.c +++ b/gen/FreeBSD/getlogin.c @@ -88,7 +88,6 @@ int getlogin_r(char *logname, size_t namelen) { char *result; - int len; int status; pthread_mutex_lock(&__logname_mutex); diff --git a/gen/FreeBSD/getmntinfo.3 b/gen/FreeBSD/getmntinfo.3 index 0c8283b..9bf03b4 100644 --- a/gen/FreeBSD/getmntinfo.3 +++ b/gen/FreeBSD/getmntinfo.3 @@ -28,11 +28,12 @@ .\" @(#)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 diff --git a/gen/FreeBSD/getmntinfo.c b/gen/FreeBSD/getmntinfo.c index 24b7886..6f4bda7 100644 --- a/gen/FreeBSD/getmntinfo.c +++ b/gen/FreeBSD/getmntinfo.c @@ -36,33 +36,74 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/getmntinfo.c,v 1.5 2007/01/09 00:27:54 imp #include #include #include +#include #include +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); } diff --git a/gen/FreeBSD/getpeereid.c b/gen/FreeBSD/getpeereid.c index 5608c48..482dfd0 100644 --- a/gen/FreeBSD/getpeereid.c +++ b/gen/FreeBSD/getpeereid.c @@ -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); diff --git a/gen/FreeBSD/glob.3 b/gen/FreeBSD/glob.3 index a71c96b..192c70c 100644 --- a/gen/FreeBSD/glob.3 +++ b/gen/FreeBSD/glob.3 @@ -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. .\" @@ -28,40 +28,24 @@ .\" 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 , diff --git a/gen/FreeBSD/glob.c b/gen/FreeBSD/glob.c index e519cc6..8daab13 100644 --- a/gen/FreeBSD/glob.c +++ b/gen/FreeBSD/glob.c @@ -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 -__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 #include #include +#include #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 diff --git a/gen/FreeBSD/opendir.c b/gen/FreeBSD/opendir.c index 05f7f92..4242906 100644 --- a/gen/FreeBSD/opendir.c +++ b/gen/FreeBSD/opendir.c @@ -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); } diff --git a/gen/FreeBSD/readdir.c b/gen/FreeBSD/readdir.c index 3875cef..aa8443b 100644 --- a/gen/FreeBSD/readdir.c +++ b/gen/FreeBSD/readdir.c @@ -31,7 +31,7 @@ static char sccsid[] = "@(#)readdir.c 8.3 (Berkeley) 9/29/94"; #endif /* LIBC_SCCS and not lint */ #include -__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 @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/readdir.c,v 1.15 2008/05/05 14:05:23 kib Ex #include #include #include -#include #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; diff --git a/gen/FreeBSD/rewinddir.c b/gen/FreeBSD/rewinddir.c index bdbb33e..97067d3 100644 --- a/gen/FreeBSD/rewinddir.c +++ b/gen/FreeBSD/rewinddir.c @@ -31,18 +31,37 @@ static char sccsid[] = "@(#)rewinddir.c 8.1 (Berkeley) 6/8/93"; #endif /* LIBC_SCCS and not lint */ #include -__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 #include +#include +#include +#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); } diff --git a/gen/FreeBSD/scandir.c b/gen/FreeBSD/scandir.c index 814f996..b47983e 100644 --- a/gen/FreeBSD/scandir.c +++ b/gen/FreeBSD/scandir.c @@ -31,7 +31,7 @@ static char sccsid[] = "@(#)scandir.c 8.3 (Berkeley) 1/2/94"; #endif /* LIBC_SCCS and not lint */ #include -__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 */ + + /* see */ +#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 + diff --git a/gen/FreeBSD/scandir_b.c b/gen/FreeBSD/scandir_b.c index e13b917..92a7727 100644 --- a/gen/FreeBSD/scandir_b.c +++ b/gen/FreeBSD/scandir_b.c @@ -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 @@ -10,14 +10,11 @@ * 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) @@ -25,97 +22,11 @@ * 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 -__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 -#include -#include -#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 */ - - 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; -} diff --git a/gen/FreeBSD/seekdir.c b/gen/FreeBSD/seekdir.c index cfadd8c..71eb393 100644 --- a/gen/FreeBSD/seekdir.c +++ b/gen/FreeBSD/seekdir.c @@ -31,7 +31,7 @@ static char sccsid[] = "@(#)seekdir.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include -__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 @@ -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); diff --git a/gen/FreeBSD/telldir.c b/gen/FreeBSD/telldir.c index 355ed50..c447a37 100644 --- a/gen/FreeBSD/telldir.c +++ b/gen/FreeBSD/telldir.c @@ -31,7 +31,7 @@ static char sccsid[] = "@(#)telldir.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include -__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 @@ -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 diff --git a/gen/FreeBSD/telldir.h b/gen/FreeBSD/telldir.h index c1f0ad0..271981e 100644 --- a/gen/FreeBSD/telldir.h +++ b/gen/FreeBSD/telldir.h @@ -36,6 +36,7 @@ #define _TELLDIR_H_ #include +#include /* * 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 diff --git a/gen/FreeBSD/ttyname.3 b/gen/FreeBSD/ttyname.3 index 0012549..0d023a8 100644 --- a/gen/FreeBSD/ttyname.3 +++ b/gen/FreeBSD/ttyname.3 @@ -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. @@ -30,53 +26,34 @@ .\" 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 . diff --git a/gen/FreeBSD/ttyslot.c b/gen/FreeBSD/ttyslot.c index a553e16..d437a48 100644 --- a/gen/FreeBSD/ttyslot.c +++ b/gen/FreeBSD/ttyslot.c @@ -31,7 +31,7 @@ static char sccsid[] = "@(#)ttyslot.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include -__FBSDID("$FreeBSD: src/lib/libc/gen/ttyslot.c,v 1.6 2009/02/12 19:00:13 ed Exp $"); +__FBSDID("$FreeBSD$"); #include #include @@ -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); } diff --git a/gen/FreeBSD/vis.c b/gen/FreeBSD/vis.c index f48f173..23e0bbc 100644 --- a/gen/FreeBSD/vis.c +++ b/gen/FreeBSD/vis.c @@ -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) diff --git a/gen/NetBSD/rb.c b/gen/NetBSD/rb.c index 5fa261a..46221c7 100644 --- a/gen/NetBSD/rb.c +++ b/gen/NetBSD/rb.c @@ -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. diff --git a/gen/NetBSD/rbtree.3 b/gen/NetBSD/rbtree.3 index cc7deed..399eeca 100644 --- a/gen/NetBSD/rbtree.3 +++ b/gen/NetBSD/rbtree.3 @@ -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. @@ -29,11 +29,23 @@ .\" 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 @@ -55,6 +67,12 @@ .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. diff --git a/gen/__dirent.h b/gen/__dirent.h index 8c3407c..79d4164 100644 --- a/gen/__dirent.h +++ b/gen/__dirent.h @@ -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 diff --git a/gen/clock_gettime.c b/gen/clock_gettime.c index 7be0ad7..783a251 100644 --- a/gen/clock_gettime.c +++ b/gen/clock_gettime.c @@ -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: diff --git a/gen/crypt.c b/gen/crypt.c index 6743885..606431a 100644 --- a/gen/crypt.c +++ b/gen/crypt.c @@ -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 ==================== */ diff --git a/gen/disklabel.c b/gen/disklabel.c index b88f91d..fe90e21 100644 --- a/gen/disklabel.c +++ b/gen/disklabel.c @@ -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); diff --git a/gen/fts.c b/gen/fts.c index 729ec79..040abcc 100644 --- a/gen/fts.c +++ b/gen/fts.c @@ -54,7 +54,6 @@ #include #include -#include #include #include #include @@ -66,13 +65,14 @@ #include #include #include +#include #ifdef __BLOCKS__ #include #endif /* __BLOCKS__ */ #include -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; diff --git a/gen/getttyent.c b/gen/getttyent.c index d403614..25a1498 100644 --- a/gen/getttyent.c +++ b/gen/getttyent.c @@ -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 diff --git a/gen/nanosleep.c b/gen/nanosleep.c index 71ad76c..934707e 100644 --- a/gen/nanosleep.c +++ b/gen/nanosleep.c @@ -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(); } diff --git a/gen/nlist.c b/gen/nlist.c index a4f7c53..817c043 100644 --- a/gen/nlist.c +++ b/gen/nlist.c @@ -62,6 +62,7 @@ #include #include #include +#include /* Stuff lifted from and 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) { diff --git a/gen/strtofflags.c b/gen/strtofflags.c index e6b98df..0df9996 100644 --- a/gen/strtofflags.c +++ b/gen/strtofflags.c @@ -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])) diff --git a/gen/sync_volume_np.c b/gen/sync_volume_np.c index a87e257..7e2d638 100644 --- a/gen/sync_volume_np.c +++ b/gen/sync_volume_np.c @@ -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; } diff --git a/gen/thread_stack_pcs.c b/gen/thread_stack_pcs.c index 1076065..53a7b5f 100644 --- a/gen/thread_stack_pcs.c +++ b/gen/thread_stack_pcs.c @@ -29,7 +29,7 @@ #include #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 */ diff --git a/gen/utmpx-darwin.c b/gen/utmpx-darwin.c index 485fa5d..d9e555a 100644 --- a/gen/utmpx-darwin.c +++ b/gen/utmpx-darwin.c @@ -55,24 +55,13 @@ #include #endif /* UTMP_COMPAT */ -#if ASL_API_VERSION < 20131108 -#include -#include -#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 diff --git a/include/_types.h b/include/_types.h index 6340283..83cd510 100644 --- a/include/_types.h +++ b/include/_types.h @@ -25,6 +25,7 @@ #define __TYPES_H_ #include +#include /* __uint32_t */ #if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 #define __strfmonlike(fmtarg, firstvararg) \ diff --git a/include/_types/_nl_item.h b/include/_types/_nl_item.h index ca4531e..4339653 100644 --- a/include/_types/_nl_item.h +++ b/include/_types/_nl_item.h @@ -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 diff --git a/include/_types/_wctrans_t.h b/include/_types/_wctrans_t.h index 1d3df0b..2b66435 100644 --- a/include/_types/_wctrans_t.h +++ b/include/_types/_wctrans_t.h @@ -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 diff --git a/include/_types/_wctype_t.h b/include/_types/_wctype_t.h index 650ebc4..8d76a5d 100644 --- a/include/_types/_wctype_t.h +++ b/include/_types/_wctype_t.h @@ -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 diff --git a/include/assert.h b/include/assert.h index 67ae0fd..7c81e75 100644 --- a/include/assert.h +++ b/include/assert.h @@ -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 diff --git a/include/dirent.h b/include/dirent.h index bd84e6d..c105526 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -65,6 +65,7 @@ #include #include #include +#include /* __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 */ diff --git a/include/fsproperties.h b/include/fsproperties.h index 7e90bd9..d0ccc27 100644 --- a/include/fsproperties.h +++ b/include/fsproperties.h @@ -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_ */ diff --git a/include/glob.h b/include/glob.h index 06314af..4f2b684 100644 --- a/include/glob.h +++ b/include/glob.h @@ -13,11 +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. - * 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. * diff --git a/include/limits.h b/include/limits.h index b7d202d..2ed444e 100644 --- a/include/limits.h +++ b/include/limits.h @@ -111,7 +111,7 @@ #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 diff --git a/include/secure/_string.h b/include/secure/_string.h index c1ff94b..08e228d 100644 --- a/include/secure/_string.h +++ b/include/secure/_string.h @@ -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@ * @@ -28,21 +28,16 @@ #ifndef _SECURE__STRING_H_ #define _SECURE__STRING_H_ -#include #include +#include #include #if _USE_FORTIFY_LEVEL > 0 -#ifndef __has_builtin -#define _undef__has_builtin -#define __has_builtin(x) 0 -#endif - /* */ #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 @@ -54,46 +49,53 @@ #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 */ @@ -101,41 +103,41 @@ #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 index 0000000..9069e59 --- /dev/null +++ b/include/secure/_strings.h @@ -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 directly; include instead." +#endif + +#ifndef _SECURE__STRINGS_H_ +#define _SECURE__STRINGS_H_ + +#include +#include +#include + +#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_ */ diff --git a/include/stdint.h b/include/stdint.h index c0e570a..b4f027e 100644 --- a/include/stdint.h +++ b/include/stdint.h @@ -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) diff --git a/include/stdio.h b/include/stdio.h index d0cf7a5..a9b35cd 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -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 */ diff --git a/include/stdlib.h b/include/stdlib.h index c04d3a7..a8e5d8d 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -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 */ diff --git a/include/string.h b/include/string.h index 93d545c..6fe4b8d 100644 --- a/include/string.h +++ b/include/string.h @@ -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 diff --git a/include/strings.h b/include/strings.h index 0c59530..c0e915f 100644 --- a/include/strings.h +++ b/include/strings.h @@ -92,5 +92,10 @@ __END_DECLS #include #endif +#if defined (__GNUC__) && _FORTIFY_SOURCE > 0 && !defined (__cplusplus) +/* Security checking functions. */ +#include +#endif + #endif /* _STRINGS_H_ */ diff --git a/include/sys/cdefs.h b/include/sys/cdefs.h index cf18a94..451bb22 100644 --- a/include/sys/cdefs.h +++ b/include/sys/cdefs.h @@ -34,7 +34,7 @@ */ #include_next #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." diff --git a/include/sys/rbtree.h b/include/sys/rbtree.h index e74b017..b57f32e 100644 --- a/include/sys/rbtree.h +++ b/include/sys/rbtree.h @@ -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: diff --git a/include/time.h b/include/time.h index dedea0b..51442ef 100644 --- a/include/time.h +++ b/include/time.h @@ -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 */ }; diff --git a/include/unistd.h b/include/unistd.h index 4384247..7896f8d 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -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__ */ diff --git a/include/wchar.h b/include/wchar.h index bd16be1..1e514ae 100644 --- a/include/wchar.h +++ b/include/wchar.h @@ -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 index 0000000..554c06f --- /dev/null +++ b/libdarwin/AppleInternalVariant.plist @@ -0,0 +1,8 @@ + + + + + AppleInternal + + + diff --git a/libdarwin/dirstat.c b/libdarwin/dirstat.c new file mode 100644 index 0000000..d0b5edf --- /dev/null +++ b/libdarwin/dirstat.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "dirstat.h" +#include "dirstat_collection.h" + +#if !TARGET_OS_SIMULATOR +#define HAS_APFS +#endif + +#ifdef HAS_APFS +#include +#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) { + // + 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 + // + // 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 index 0000000..d3235de --- /dev/null +++ b/libdarwin/dirstat.h @@ -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 +#include + +__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 index 0000000..890cb45 --- /dev/null +++ b/libdarwin/dirstat_collection.c @@ -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 +#include +#include +#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 index 0000000..18aff57 --- /dev/null +++ b/libdarwin/dirstat_collection.h @@ -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 +#include +#include + +__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/darwin/init_cpu_capabilities.c b/libdarwin/init.c similarity index 71% rename from darwin/init_cpu_capabilities.c rename to libdarwin/init.c index 62d1df2..ba68629 100644 --- a/darwin/init_cpu_capabilities.c +++ b/libdarwin/init.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2012 Apple Computer, Inc. All rights reserved. + * 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, @@ -17,20 +17,11 @@ * 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 -#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 ) +void +__libdarwin_init(void) { } diff --git a/libdarwin/variant.c b/libdarwin/variant.c new file mode 100644 index 0000000..927ac28 --- /dev/null +++ b/libdarwin/variant.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 diff --git a/locale/FreeBSD/collate.c b/locale/FreeBSD/collate.c index d468783..028c182 100644 --- a/locale/FreeBSD/collate.c +++ b/locale/FreeBSD/collate.c @@ -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); } diff --git a/locale/FreeBSD/gb18030.c b/locale/FreeBSD/gb18030.c index 4662465..baeaada 100644 --- a/locale/FreeBSD/gb18030.c +++ b/locale/FreeBSD/gb18030.c @@ -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; diff --git a/locale/FreeBSD/gb2312.c b/locale/FreeBSD/gb2312.c index 559ada4..dea5a92 100644 --- a/locale/FreeBSD/gb2312.c +++ b/locale/FreeBSD/gb2312.c @@ -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; diff --git a/locale/FreeBSD/setrunelocale.c b/locale/FreeBSD/setrunelocale.c index 213a62b..852109c 100644 --- a/locale/FreeBSD/setrunelocale.c +++ b/locale/FreeBSD/setrunelocale.c @@ -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); diff --git a/locale/FreeBSD/wcstod.c b/locale/FreeBSD/wcstod.c index 3ecc75a..0089af0 100644 --- a/locale/FreeBSD/wcstod.c +++ b/locale/FreeBSD/wcstod.c @@ -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 #include #include #include diff --git a/locale/xlocale.c b/locale/xlocale.c index 1e1c443..6efb9a5 100644 --- a/locale/xlocale.c +++ b/locale/xlocale.c @@ -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); diff --git a/locale/xlocale_private.h b/locale/xlocale_private.h index 2301aa0..ba9feb2 100644 --- a/locale/xlocale_private.h +++ b/locale/xlocale_private.h @@ -32,8 +32,8 @@ #include #include #include -#include #include +#include #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; diff --git a/man/manpages.lst b/man/manpages.lst index d2d41a5..4621bef 100644 --- a/man/manpages.lst +++ b/man/manpages.lst @@ -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 diff --git a/net/FreeBSD/inet.3 b/net/FreeBSD/inet.3 index a679b74..de22fa2 100644 --- a/net/FreeBSD/inet.3 +++ b/net/FreeBSD/inet.3 @@ -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 @@ -77,12 +76,6 @@ .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 diff --git a/os/assumes.c b/os/assumes.c index e51d399..455fd47 100644 --- a/os/assumes.c +++ b/os/assumes.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,12 @@ #include #include "os/assumes.h" #include +#include +#include +#include + +#include +#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) { diff --git a/os/assumes.h b/os/assumes.h index c120f4e..b25abbd 100644 --- a/os/assumes.h +++ b/os/assumes.h @@ -24,6 +24,7 @@ #define __OS_ASSUMES_H__ #include +#include __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 + +#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 -#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 index 0000000..f9826cd --- /dev/null +++ b/os/variant_private.h @@ -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 + +#include +#include + +/*! @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__ diff --git a/secure/chk_fail.c b/secure/chk_fail.c index 29401b8..db859a6 100644 --- a/secure/chk_fail.c +++ b/secure/chk_fail.c @@ -28,3 +28,112 @@ #include #include + +#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 +#include +#include +#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(); + } +} diff --git a/stdio/FreeBSD/_flock_stub.c b/stdio/FreeBSD/_flock_stub.c index a556da3..330830f 100644 --- a/stdio/FreeBSD/_flock_stub.c +++ b/stdio/FreeBSD/_flock_stub.c @@ -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 #include #include #include @@ -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) { + // - 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; + // - 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) { + // - preserve errno. + int save_errno = errno; _pthread_mutex_unlock(&fp->_fl_mutex); + errno = save_errno; } diff --git a/stdio/FreeBSD/fgetwc.c b/stdio/FreeBSD/fgetwc.c index ead24c3..709244f 100644 --- a/stdio/FreeBSD/fgetwc.c +++ b/stdio/FreeBSD/fgetwc.c @@ -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) diff --git a/stdio/FreeBSD/findfp.c b/stdio/FreeBSD/findfp.c index 1f515ab..f5a31f5 100644 --- a/stdio/FreeBSD/findfp.c +++ b/stdio/FreeBSD/findfp.c @@ -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 index 0000000..bcf187d --- /dev/null +++ b/stdio/FreeBSD/fmemopen.c @@ -0,0 +1,262 @@ +/*- + * Copyright (C) 2013 Pietro Cerutti + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#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); +} diff --git a/stdio/FreeBSD/fopen.3 b/stdio/FreeBSD/fopen.3 index ab304e9..e057f35 100644 --- a/stdio/FreeBSD/fopen.3 +++ b/stdio/FreeBSD/fopen.3 @@ -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,102 +30,102 @@ .\" 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. diff --git a/stdio/FreeBSD/fputs.c b/stdio/FreeBSD/fputs.c index 163541b..0cd58ef 100644 --- a/stdio/FreeBSD/fputs.c +++ b/stdio/FreeBSD/fputs.c @@ -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. diff --git a/stdio/FreeBSD/getdelim.c b/stdio/FreeBSD/getdelim.c index 02ff26d..705231a 100644 --- a/stdio/FreeBSD/getdelim.c +++ b/stdio/FreeBSD/getdelim.c @@ -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; diff --git a/stdio/FreeBSD/mktemp.3 b/stdio/FreeBSD/mktemp.3 index d4072c6..3a55c7f 100644 --- a/stdio/FreeBSD/mktemp.3 +++ b/stdio/FreeBSD/mktemp.3 @@ -34,9 +34,12 @@ .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 @@ -54,12 +57,23 @@ .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" @@ -70,6 +84,13 @@ .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 diff --git a/stdio/FreeBSD/mktemp.c b/stdio/FreeBSD/mktemp.c index 08b0aec..001cf3e 100644 --- a/stdio/FreeBSD/mktemp.c +++ b/stdio/FreeBSD/mktemp.c @@ -33,6 +33,7 @@ static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; #include #include "namespace.h" +#include #include #include #include @@ -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 index 0000000..8e2c1e9 --- /dev/null +++ b/stdio/FreeBSD/open_memstream.3 @@ -0,0 +1,155 @@ +.\" Copyright (c) 2013 Hudson River Trading LLC +.\" Written by: John H. Baldwin +.\" 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 index 0000000..a2d9bda --- /dev/null +++ b/stdio/FreeBSD/open_memstream.c @@ -0,0 +1,210 @@ +/*- + * Copyright (c) 2013 Hudson River Trading LLC + * Written by: John H. Baldwin + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#ifdef DEBUG +#include +#endif +#include +#include +#include +#include + +/* 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 index 0000000..948a90b --- /dev/null +++ b/stdio/FreeBSD/open_wmemstream.c @@ -0,0 +1,274 @@ +/*- + * Copyright (c) 2013 Hudson River Trading LLC + * Written by: John H. Baldwin + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#ifdef DEBUG +#include +#endif +#include +#include +#include +#include + +#include + +/* 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); +} diff --git a/stdio/FreeBSD/printf.3 b/stdio/FreeBSD/printf.3 index 850fa98..380ffeb 100644 --- a/stdio/FreeBSD/printf.3 +++ b/stdio/FreeBSD/printf.3 @@ -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 diff --git a/stdio/FreeBSD/vfprintf.c b/stdio/FreeBSD/vfprintf.c index 701e2ab..2e707ef 100644 --- a/stdio/FreeBSD/vfprintf.c +++ b/stdio/FreeBSD/vfprintf.c @@ -64,6 +64,10 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das #include #include "un-namespace.h" +#include +#include +#include + #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 */ } diff --git a/stdio/FreeBSD/vfwprintf.c b/stdio/FreeBSD/vfwprintf.c index f623fff..176a11c 100644 --- a/stdio/FreeBSD/vfwprintf.c +++ b/stdio/FreeBSD/vfwprintf.c @@ -64,6 +64,9 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.42 2009/11/25 04:27:55 wo #include #include "un-namespace.h" +#include +#include + #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 */ } diff --git a/stdio/FreeBSD/vswprintf.c b/stdio/FreeBSD/vswprintf.c index 4227e74..9129639 100644 --- a/stdio/FreeBSD/vswprintf.c +++ b/stdio/FreeBSD/vswprintf.c @@ -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(). diff --git a/stdio/FreeBSD/xprintf_float.c b/stdio/FreeBSD/xprintf_float.c index 9f4c60e..217956e 100644 --- a/stdio/FreeBSD/xprintf_float.c +++ b/stdio/FreeBSD/xprintf_float.c @@ -36,6 +36,7 @@ #include #include "xlocale_private.h" #include +#include #include #include #include diff --git a/stdio/FreeBSD/xprintf_int.c b/stdio/FreeBSD/xprintf_int.c index fb64451..ce33d2a 100644 --- a/stdio/FreeBSD/xprintf_int.c +++ b/stdio/FreeBSD/xprintf_int.c @@ -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 */ diff --git a/stdlib/FreeBSD/atexit.3 b/stdlib/FreeBSD/atexit.3 index b3d978b..9d60aa8 100644 --- a/stdlib/FreeBSD/atexit.3 +++ b/stdlib/FreeBSD/atexit.3 @@ -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 @@ -41,23 +41,32 @@ .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 diff --git a/stdlib/FreeBSD/exit.c b/stdlib/FreeBSD/exit.c index e61834e..ba66bc6 100644 --- a/stdlib/FreeBSD/exit.c +++ b/stdlib/FreeBSD/exit.c @@ -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); +} diff --git a/stdlib/FreeBSD/getenv.c b/stdlib/FreeBSD/getenv.c index bde7421..c012578 100644 --- a/stdlib/FreeBSD/getenv.c +++ b/stdlib/FreeBSD/getenv.c @@ -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) diff --git a/stdlib/FreeBSD/psort.c b/stdlib/FreeBSD/psort.c index cb6f707..e9251ab 100644 --- a/stdlib/FreeBSD/psort.c +++ b/stdlib/FreeBSD/psort.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das E #include #include #include +#include #define __APPLE_API_PRIVATE #include @@ -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 diff --git a/stdlib/FreeBSD/psort_b.c b/stdlib/FreeBSD/psort_b.c index cb6f707..e9251ab 100644 --- a/stdlib/FreeBSD/psort_b.c +++ b/stdlib/FreeBSD/psort_b.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das E #include #include #include +#include #define __APPLE_API_PRIVATE #include @@ -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 diff --git a/stdlib/FreeBSD/psort_r.c b/stdlib/FreeBSD/psort_r.c index cb6f707..e9251ab 100644 --- a/stdlib/FreeBSD/psort_r.c +++ b/stdlib/FreeBSD/psort_r.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das E #include #include #include +#include #define __APPLE_API_PRIVATE #include @@ -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 diff --git a/stdlib/FreeBSD/qsort.c b/stdlib/FreeBSD/qsort.c index 1d0e3c5..b1c5257 100644 --- a/stdlib/FreeBSD/qsort.c +++ b/stdlib/FreeBSD/qsort.c @@ -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 -__FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das Exp $"); +__FBSDID("$FreeBSD$"); +#include #include #include @@ -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 diff --git a/stdlib/FreeBSD/realpath.3 b/stdlib/FreeBSD/realpath.3 index bce1dae..740857b 100644 --- a/stdlib/FreeBSD/realpath.3 +++ b/stdlib/FreeBSD/realpath.3 @@ -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 diff --git a/stdlib/FreeBSD/realpath.c b/stdlib/FreeBSD/realpath.c index 13c4e6f..3ce9d8b 100644 --- a/stdlib/FreeBSD/realpath.c +++ b/stdlib/FreeBSD/realpath.c @@ -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; } diff --git a/stdlib/FreeBSD/setenv.c b/stdlib/FreeBSD/setenv.c index 75a5a0d..7f08fca 100644 --- a/stdlib/FreeBSD/setenv.c +++ b/stdlib/FreeBSD/setenv.c @@ -42,15 +42,15 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/setenv.c,v 1.14 2007/05/01 16:02:41 ache #include 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. diff --git a/stdlib/FreeBSD/system.c b/stdlib/FreeBSD/system.c index 61ef03c..b4e96ef 100644 --- a/stdlib/FreeBSD/system.c +++ b/stdlib/FreeBSD/system.c @@ -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 +#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 index 17c0c50..0000000 --- a/stdlib/qsort_b-fbsd.c +++ /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 index 0000000..734070b --- /dev/null +++ b/stdlib/qsort_b.c @@ -0,0 +1,11 @@ +#include +#include + +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); +} diff --git a/stdtime/FreeBSD/ctime.3 b/stdtime/FreeBSD/ctime.3 index 1cd4fcd..65dd91f 100644 --- a/stdtime/FreeBSD/ctime.3 +++ b/stdtime/FreeBSD/ctime.3 @@ -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 diff --git a/stdtime/FreeBSD/ftime.c b/stdtime/FreeBSD/ftime.c index 6bb3f03..7e3195d 100644 --- a/stdtime/FreeBSD/ftime.c +++ b/stdtime/FreeBSD/ftime.c @@ -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 */ diff --git a/stdtime/FreeBSD/localtime.c b/stdtime/FreeBSD/localtime.c index c814a30..6c7bd19 100644 --- a/stdtime/FreeBSD/localtime.c +++ b/stdtime/FreeBSD/localtime.c @@ -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 #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 #include +#include #include #include #include -#include #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. */ diff --git a/stdtime/FreeBSD/private.h b/stdtime/FreeBSD/private.h index d1d821e..3a54608 100644 --- a/stdtime/FreeBSD/private.h +++ b/stdtime/FreeBSD/private.h @@ -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); /* diff --git a/stdtime/FreeBSD/strftime.c b/stdtime/FreeBSD/strftime.c index 8acb0a4..ccf1d07 100644 --- a/stdtime/FreeBSD/strftime.c +++ b/stdtime/FreeBSD/strftime.c @@ -15,15 +15,13 @@ * 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); diff --git a/stdtime/FreeBSD/strptime.c b/stdtime/FreeBSD/strptime.c index 2220c5d..d237bdd 100644 --- a/stdtime/FreeBSD/strptime.c +++ b/stdtime/FreeBSD/strptime.c @@ -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; } } diff --git a/stdtime/FreeBSD/tzfile.5 b/stdtime/FreeBSD/tzfile.5 index 6dcbc27..60187eb 100644 --- a/stdtime/FreeBSD/tzfile.5 +++ b/stdtime/FreeBSD/tzfile.5 @@ -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. diff --git a/stdtime/FreeBSD/tzfile.h b/stdtime/FreeBSD/tzfile.h index aff38e7..1128133 100644 --- a/stdtime/FreeBSD/tzfile.h +++ b/stdtime/FreeBSD/tzfile.h @@ -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 +#include +/* 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 . +** 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 index e5f3fbc..0000000 --- a/stdtime/timegm.3 +++ /dev/null @@ -1,86 +0,0 @@ -.\" Copyright (C) 2001 Andries Brouwer -.\" -.\" 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 -.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 -#include - -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) diff --git a/string/FreeBSD/strerror.c b/string/FreeBSD/strerror.c index 46144e3..9689434 100644 --- a/string/FreeBSD/strerror.c +++ b/string/FreeBSD/strerror.c @@ -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; } diff --git a/string/FreeBSD/strlcpy.3 b/string/FreeBSD/strlcpy.3 index 3cf8bc2..30a7588 100644 --- a/string/FreeBSD/strlcpy.3 +++ b/string/FreeBSD/strlcpy.3 @@ -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 .\" @@ -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 @@ -39,80 +39,89 @@ .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 . diff --git a/string/NetBSD/memset_s.3 b/string/NetBSD/memset_s.3 index 9b1f662..3c25e7e 100644 --- a/string/NetBSD/memset_s.3 +++ b/string/NetBSD/memset_s.3 @@ -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 diff --git a/sys/crt_externs.c b/sys/crt_externs.c index a78524f..982e2db 100644 --- a/sys/crt_externs.c +++ b/sys/crt_externs.c @@ -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 diff --git a/sys/gettimeofday.c b/sys/gettimeofday.c index 56d9312..95a8da3 100644 --- a/sys/gettimeofday.c +++ b/sys/gettimeofday.c @@ -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 */ diff --git a/sys/settimeofday.c b/sys/settimeofday.c index 9ebd7a1..3eb4766 100644 --- a/sys/settimeofday.c +++ b/sys/settimeofday.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#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; } diff --git a/tests/Makefile b/tests/Makefile index 4165350..2b2f5be 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -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 index 0000000..caf3442 --- /dev/null +++ b/tests/assumes.c @@ -0,0 +1,40 @@ +#define OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE 1 +#include + +#include + +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 index 0000000..772d4f9 --- /dev/null +++ b/tests/assumes_legacy.c @@ -0,0 +1,23 @@ +#include + +#include + +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 index 0000000..a359b44 --- /dev/null +++ b/tests/dir.c @@ -0,0 +1,258 @@ +#include +#include +#include +#include + +#include +#include + +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 index 0000000..1a7a09e --- /dev/null +++ b/tests/dirstat.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include + +#include + +#if !TARGET_OS_SIMULATOR +#define HAS_APFS +#endif + +#ifdef HAS_APFS +#include +#endif + +T_DECL(dirstat, "Runs dirstat(3)") +{ + bool fast_only = false; + bool force_fallback = false; + char *path = "/System/Library/Frameworks"; + + // 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 ]"); + } + } + + 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 index 0000000..436e5d1 --- /dev/null +++ b/tests/err.c @@ -0,0 +1,25 @@ +#include +#include +#include + +#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 index 0000000..f150172 --- /dev/null +++ b/tests/flockfile.c @@ -0,0 +1,26 @@ +#include +#include +#include +#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 index 0000000..0e59a37 --- /dev/null +++ b/tests/freebsd_fmemopen.c @@ -0,0 +1,268 @@ +/*- +Copyright (C) 2013 Pietro Cerutti + +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 + +#include +#include +#include +#include + +#include + +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 index 0000000..428213c --- /dev/null +++ b/tests/freebsd_glob.c @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * 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 index 0000000..381c28c --- /dev/null +++ b/tests/freebsd_open_memstream.c @@ -0,0 +1,185 @@ +/*- + * Copyright (c) 2013 Hudson River Trading LLC + * Written by: John H. Baldwin + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 index 0000000..4996cff --- /dev/null +++ b/tests/freebsd_open_wmemstream.c @@ -0,0 +1,185 @@ +/*- + * Copyright (c) 2013 Hudson River Trading LLC + * Written by: John H. Baldwin + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 index 0000000..68954e2 --- /dev/null +++ b/tests/freebsd_qsort.c @@ -0,0 +1,90 @@ +/*- + * Copyright (C) 2004 Maxim Sobolev + * 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 + +#include +#include +#include +#include + +#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 index 0000000..1349995 --- /dev/null +++ b/tests/freebsd_qsort.h @@ -0,0 +1,312 @@ +/*- + * Copyright (C) 2004 Maxim Sobolev + * 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 + +#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 diff --git a/tests/fts_find.c b/tests/fts_find.c index 1c0bc31..4dcb26f 100644 --- a/tests/fts_find.c +++ b/tests/fts_find.c @@ -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 diff --git a/tests/locale.c b/tests/locale.c index 3ec6e89..d3aa4bf 100644 --- a/tests/locale.c +++ b/tests/locale.c @@ -7,7 +7,7 @@ #include -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); +} diff --git a/tests/mktemp.c b/tests/mktemp.c index ff26ddc..96f9beb 100644 --- a/tests/mktemp.c +++ b/tests/mktemp.c @@ -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; diff --git a/tests/net.c b/tests/net.c index b173c25..758ee48 100644 --- a/tests/net.c +++ b/tests/net.c @@ -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); + // 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; + // + 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 index 0000000..4cf79ff --- /dev/null +++ b/tests/netbsd_fmemopen.c @@ -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 +#include +#include +#include +#include +#include + +#include + +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 diff --git a/tests/netbsd_getenv_thread.c b/tests/netbsd_getenv_thread.c index bfab97b..927bdff 100644 --- a/tests/netbsd_getenv_thread.c +++ b/tests/netbsd_getenv_thread.c @@ -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 index 0000000..fcebdb1 --- /dev/null +++ b/tests/netbsd_glob.c @@ -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 +__RCSID("$NetBSD: t_glob.c,v 1.5 2017/01/14 20:47:41 christos Exp $"); + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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 index 0000000..08dc642 --- /dev/null +++ b/tests/netbsd_open_memstream.c @@ -0,0 +1,83 @@ +/* + * Based on the OpenBSD test + * Copyright (c) 2011 Martin Pieuchot + * + * 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 +__RCSID("$NetBSD: t_open_memstream.c,v 1.2 2014/10/19 11:17:43 justin Exp $"); + +#include +#include +#include +#include +#include + +#include + +#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 index 0000000..81c2196 --- /dev/null +++ b/tests/netbsd_printf.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#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 +} diff --git a/tests/netbsd_stat.c b/tests/netbsd_stat.c index a2dc5f9..bc0661d 100644 --- a/tests/netbsd_stat.c +++ b/tests/netbsd_stat.c @@ -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 index 0000000..f9b0815 --- /dev/null +++ b/tests/netbsd_strerror.c @@ -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 +__RCSID("$NetBSD: t_strerror.c,v 1.3 2011/05/10 06:55:27 jruoho Exp $"); + +#include +#include +#include +#include +#include + +#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); +} diff --git a/tests/netbsd_vis.c b/tests/netbsd_vis.c index 0670964..07e0775 100644 --- a/tests/netbsd_vis.c +++ b/tests/netbsd_vis.c @@ -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 index 0000000..3717f6d --- /dev/null +++ b/tests/os_variant.c @@ -0,0 +1,155 @@ +#include + +#include + +/* + * 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 index 0000000..ab7f1b5 --- /dev/null +++ b/tests/printf.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/tests/psort.c b/tests/psort.c index 41986e1..17a9a1b 100644 --- a/tests/psort.c +++ b/tests/psort.c @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -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 index 0000000..d345b68 --- /dev/null +++ b/tests/qsort.c @@ -0,0 +1,54 @@ +/* + * Randomized test for qsort() routine. + */ + +#include + +#include +#include +#include +#include +#include + +#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 index 0000000..5827aee --- /dev/null +++ b/tests/qsort_perf.c @@ -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 + +#include +#include +#include +#include +#include + +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 index 0000000..6a4c153 --- /dev/null +++ b/tests/realpath.c @@ -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 +__RCSID("$NetBSD: t_realpath.c,v 1.2 2012/03/27 07:54:58 njoly Exp $"); + +#include + +#include +#include +#include +#include +#include + +#include +#include + +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 index 0000000..a98c76c --- /dev/null +++ b/tests/realpath_edge.c @@ -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 + +#include +#include +#include +#include +#include +#include +#include + +#include + +// 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); +} + diff --git a/tests/stdio.c b/tests/stdio.c index d0e96b2..dc0f1b5 100644 --- a/tests/stdio.c +++ b/tests/stdio.c @@ -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 index 0000000..dc847c8 --- /dev/null +++ b/tests/strerror.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2001 Wes Peters + * 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 +#include +#include +#include +#include +#include + +#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 index 0000000..c90945a --- /dev/null +++ b/tests/strlcpy.c @@ -0,0 +1,11 @@ +#include + +#include + +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); +} diff --git a/tests/strptime.c b/tests/strptime.c index 804c5ec..7cbca30 100644 --- a/tests/strptime.c +++ b/tests/strptime.c @@ -3,8 +3,34 @@ #include #include -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); +} diff --git a/tests/wchar.c b/tests/wchar.c index 07d9aaa..f76dd14 100644 --- a/tests/wchar.c +++ b/tests/wchar.c @@ -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; diff --git a/util/login.c b/util/login.c index 39fcf07..c1599cd 100644 --- a/util/login.c +++ b/util/login.c @@ -58,6 +58,9 @@ #include #include +#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 diff --git a/x86_64/string/strncpy.s b/x86_64/string/strncpy.s index f18ca34..72e2bf7 100644 --- a/x86_64/string/strncpy.s +++ b/x86_64/string/strncpy.s @@ -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 diff --git a/xcodescripts/eos.xcconfig b/xcodescripts/eos.xcconfig index f2cbedd..d86e479 100644 --- a/xcodescripts/eos.xcconfig +++ b/xcodescripts/eos.xcconfig @@ -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 diff --git a/xcodescripts/generate_features.pl b/xcodescripts/generate_features.pl index e2d689f..0704fcd 100755 --- a/xcodescripts/generate_features.pl +++ b/xcodescripts/generate_features.pl @@ -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 { diff --git a/xcodescripts/headers.sh b/xcodescripts/headers.sh index d447595..64d1da8 100755 --- a/xcodescripts/headers.sh +++ b/xcodescripts/headers.sh @@ -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 index 0000000..fe2ecc4 --- /dev/null +++ b/xcodescripts/legacy_alias.list @@ -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 diff --git a/xcodescripts/libc.xcconfig b/xcodescripts/libc.xcconfig index 3559c34..a7a1081 100644 --- a/xcodescripts/libc.xcconfig +++ b/xcodescripts/libc.xcconfig @@ -1,7 +1,7 @@ #include "/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 , 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) diff --git a/xcodescripts/manpages.sh b/xcodescripts/manpages.sh index 317cf2e..32054df 100644 --- a/xcodescripts/manpages.sh +++ b/xcodescripts/manpages.sh @@ -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" diff --git a/xcodescripts/patch_headers_variants.pl b/xcodescripts/patch_headers_variants.pl index 24da935..a71d758 100644 --- a/xcodescripts/patch_headers_variants.pl +++ b/xcodescripts/patch_headers_variants.pl @@ -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"; diff --git a/xcodescripts/variants.xcconfig b/xcodescripts/variants.xcconfig index 6134dcc..415f81c 100644 --- a/xcodescripts/variants.xcconfig +++ b/xcodescripts/variants.xcconfig @@ -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) -- 2.45.2