Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f6bb78d

Browse files
committedAug 1, 2024·
Initial FTS support
Add FTS implementation derived from musl-fts with a few modifications. The compiled fts.o is included in the libc.a archive, and the fts.h header is installed in the sysroot (`include/fts.h`). * fts/musl-fts: Add a copy of the musl-fts sources with modifications. * fts/patches: A set of patches to apply to the musl-fts sources. * fts/update-musl-fts.sh: A script to update the musl-fts sources with the patches applied. * fts/config.h: A configuration header included by the musl-fts sources. * test/smoke: Add a test suite for wasi-libc specific features that libc-test does not cover.
1 parent b9ef79d commit f6bb78d

22 files changed

+1989
-1
lines changed
 

‎LICENSE

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dlmalloc/ - CC0; see the notice in malloc.c for details
1010
emmalloc/ - MIT; see the notice in emmalloc.c for details
1111
libc-bottom-half/cloudlibc/ - BSD-2-Clause; see the LICENSE file for details
1212
libc-top-half/musl/ - MIT; see the COPYRIGHT file for details
13+
fts/musl-fts/ - BSD-3-Clause; see the COPYING file for details
1314

1415
wasi-libc's changes to these files are multi-licensed under the
1516
Apache License v2.0 with LLVM Exceptions, the Apache License v2.0,

‎Makefile

+12
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,10 @@ LIBC_TOP_HALF_ALL_SOURCES = \
376376
$(LIBC_TOP_HALF_MUSL_SOURCES) \
377377
$(sort $(shell find $(LIBC_TOP_HALF_SOURCES) -name \*.[cs]))
378378

379+
FTS_SRC_DIR = fts
380+
MUSL_FTS_SRC_DIR = $(FTS_SRC_DIR)/musl-fts
381+
FTS_SOURCES = $(MUSL_FTS_SRC_DIR)/fts.c
382+
379383
# Add any extra flags
380384
CFLAGS = $(EXTRA_CFLAGS)
381385
# Set the target.
@@ -449,6 +453,7 @@ DLMALLOC_OBJS = $(call objs,$(DLMALLOC_SOURCES))
449453
EMMALLOC_OBJS = $(call objs,$(EMMALLOC_SOURCES))
450454
LIBC_BOTTOM_HALF_ALL_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_ALL_SOURCES))
451455
LIBC_TOP_HALF_ALL_OBJS = $(call asmobjs,$(call objs,$(LIBC_TOP_HALF_ALL_SOURCES)))
456+
FTS_OBJS = $(call objs,$(FTS_SOURCES))
452457
ifeq ($(WASI_SNAPSHOT), p2)
453458
LIBC_OBJS += $(OBJDIR)/wasip2_component_type.o
454459
endif
@@ -467,6 +472,7 @@ ifeq ($(BUILD_LIBC_TOP_HALF),yes)
467472
# libc-top-half is musl.
468473
LIBC_OBJS += $(LIBC_TOP_HALF_ALL_OBJS)
469474
endif
475+
LIBC_OBJS += $(FTS_OBJS)
470476
MUSL_PRINTSCAN_OBJS = $(call objs,$(MUSL_PRINTSCAN_SOURCES))
471477
MUSL_PRINTSCAN_LONG_DOUBLE_OBJS = $(patsubst %.o,%.long-double.o,$(MUSL_PRINTSCAN_OBJS))
472478
MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS = $(patsubst %.o,%.no-floating-point.o,$(MUSL_PRINTSCAN_OBJS))
@@ -736,6 +742,10 @@ $(LIBC_TOP_HALF_ALL_OBJS) $(LIBC_TOP_HALF_ALL_SO_OBJS) $(MUSL_PRINTSCAN_LONG_DOU
736742
-Wno-dangling-else \
737743
-Wno-unknown-pragmas
738744

745+
$(FTS_OBJS): CFLAGS += \
746+
-I$(MUSL_FTS_SRC_DIR) \
747+
-I$(FTS_SRC_DIR) # for config.h
748+
739749
$(LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS) $(LIBWASI_EMULATED_PROCESS_CLOCKS_SO_OBJS): CFLAGS += \
740750
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)
741751

@@ -764,6 +774,8 @@ include_dirs:
764774
cp -r "$(LIBC_TOP_HALF_MUSL_DIR)"/arch/generic/bits/* "$(SYSROOT_INC)/bits"
765775
cp -r "$(LIBC_TOP_HALF_MUSL_DIR)"/arch/wasm32/bits/* "$(SYSROOT_INC)/bits"
766776

777+
cp "$(MUSL_FTS_SRC_DIR)/fts.h" "$(SYSROOT_INC)/fts.h"
778+
767779
# Remove selected header files.
768780
$(RM) $(patsubst %,$(SYSROOT_INC)/%,$(MUSL_OMIT_HEADERS))
769781
ifeq ($(WASI_SNAPSHOT), p2)

‎expected/wasm32-wasip1-threads/defined-symbols.txt

+5
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,11 @@ ftello64
714714
ftime
715715
ftruncate
716716
ftrylockfile
717+
fts_children
718+
fts_close
719+
fts_open
720+
fts_read
721+
fts_set
717722
funlockfile
718723
futimens
719724
futimesat

‎expected/wasm32-wasip1-threads/include-all.c

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
#include <float.h>
8787
#include <fmtmsg.h>
8888
#include <fnmatch.h>
89+
#include <fts.h>
8990
#include <ftw.h>
9091
#include <getopt.h>
9192
#include <glob.h>

‎expected/wasm32-wasip1-threads/predefined-macros.txt

+42
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,40 @@
384384
#define FSETLOCKING_BYCALLER 2
385385
#define FSETLOCKING_INTERNAL 1
386386
#define FSETLOCKING_QUERY 0
387+
#define FTS_AGAIN 1
388+
#define FTS_COMFOLLOW 0x001
389+
#define FTS_D 1
390+
#define FTS_DC 2
391+
#define FTS_DEFAULT 3
392+
#define FTS_DNR 4
393+
#define FTS_DONTCHDIR 0x01
394+
#define FTS_DOT 5
395+
#define FTS_DP 6
396+
#define FTS_ERR 7
397+
#define FTS_F 8
398+
#define FTS_FOLLOW 2
399+
#define FTS_INIT 9
400+
#define FTS_ISW 0x04
401+
#define FTS_LOGICAL 0x002
402+
#define FTS_NAMEONLY 0x100
403+
#define FTS_NOCHDIR 0x004
404+
#define FTS_NOINSTR 3
405+
#define FTS_NOSTAT 0x008
406+
#define FTS_NS 10
407+
#define FTS_NSOK 11
408+
#define FTS_OPTIONMASK 0x0ff
409+
#define FTS_PHYSICAL 0x010
410+
#define FTS_ROOTLEVEL 0
411+
#define FTS_ROOTPARENTLEVEL -1
412+
#define FTS_SEEDOT 0x020
413+
#define FTS_SKIP 4
414+
#define FTS_SL 12
415+
#define FTS_SLNONE 13
416+
#define FTS_STOP 0x200
417+
#define FTS_SYMFOLLOW 0x02
418+
#define FTS_W 14
419+
#define FTS_WHITEOUT 0x080
420+
#define FTS_XDEV 0x040
387421
#define FTW_CHDIR 4
388422
#define FTW_D 2
389423
#define FTW_DEPTH 8
@@ -2075,6 +2109,7 @@
20752109
#define _FLOAT_H
20762110
#define _FMTMSG_H
20772111
#define _FNMATCH_H
2112+
#define _FTS_H_
20782113
#define _FTW_H
20792114
#define _GETOPT_H
20802115
#define _GLOB_H
@@ -3031,6 +3066,13 @@
30313066
#define __alignof_is_defined 1
30323067
#define __bitop(x,i,o) ((x)[(i)/8] o (1<<(i)%8))
30333068
#define __bool_true_false_are_defined 1
3069+
#define __fts_dev_t dev_t
3070+
#define __fts_ino_t ino_t
3071+
#define __fts_length_t unsigned int
3072+
#define __fts_level_t int
3073+
#define __fts_nlink_t nlink_t
3074+
#define __fts_number_t int64_t
3075+
#define __fts_stat_t struct stat
30343076
#define __inline inline
30353077
#define __restrict restrict
30363078
#define __tg_complex(fun,x) (__RETCAST_CX(x)( __FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : __LDBLCX((x)+I) ? fun ## l (x) : fun(x) ))

‎expected/wasm32-wasip1/defined-symbols.txt

+5
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,11 @@ ftello
648648
ftello64
649649
ftime
650650
ftruncate
651+
fts_children
652+
fts_close
653+
fts_open
654+
fts_read
655+
fts_set
651656
futimens
652657
futimesat
653658
fwide

‎expected/wasm32-wasip1/include-all.c

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
#include <float.h>
8787
#include <fmtmsg.h>
8888
#include <fnmatch.h>
89+
#include <fts.h>
8990
#include <ftw.h>
9091
#include <getopt.h>
9192
#include <glob.h>

‎expected/wasm32-wasip1/predefined-macros.txt

+42
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,40 @@
384384
#define FSETLOCKING_BYCALLER 2
385385
#define FSETLOCKING_INTERNAL 1
386386
#define FSETLOCKING_QUERY 0
387+
#define FTS_AGAIN 1
388+
#define FTS_COMFOLLOW 0x001
389+
#define FTS_D 1
390+
#define FTS_DC 2
391+
#define FTS_DEFAULT 3
392+
#define FTS_DNR 4
393+
#define FTS_DONTCHDIR 0x01
394+
#define FTS_DOT 5
395+
#define FTS_DP 6
396+
#define FTS_ERR 7
397+
#define FTS_F 8
398+
#define FTS_FOLLOW 2
399+
#define FTS_INIT 9
400+
#define FTS_ISW 0x04
401+
#define FTS_LOGICAL 0x002
402+
#define FTS_NAMEONLY 0x100
403+
#define FTS_NOCHDIR 0x004
404+
#define FTS_NOINSTR 3
405+
#define FTS_NOSTAT 0x008
406+
#define FTS_NS 10
407+
#define FTS_NSOK 11
408+
#define FTS_OPTIONMASK 0x0ff
409+
#define FTS_PHYSICAL 0x010
410+
#define FTS_ROOTLEVEL 0
411+
#define FTS_ROOTPARENTLEVEL -1
412+
#define FTS_SEEDOT 0x020
413+
#define FTS_SKIP 4
414+
#define FTS_SL 12
415+
#define FTS_SLNONE 13
416+
#define FTS_STOP 0x200
417+
#define FTS_SYMFOLLOW 0x02
418+
#define FTS_W 14
419+
#define FTS_WHITEOUT 0x080
420+
#define FTS_XDEV 0x040
387421
#define FTW_CHDIR 4
388422
#define FTW_D 2
389423
#define FTW_DEPTH 8
@@ -2070,6 +2104,7 @@
20702104
#define _FLOAT_H
20712105
#define _FMTMSG_H
20722106
#define _FNMATCH_H
2107+
#define _FTS_H_
20732108
#define _FTW_H
20742109
#define _GETOPT_H
20752110
#define _GLOB_H
@@ -3021,6 +3056,13 @@
30213056
#define __alignof_is_defined 1
30223057
#define __bitop(x,i,o) ((x)[(i)/8] o (1<<(i)%8))
30233058
#define __bool_true_false_are_defined 1
3059+
#define __fts_dev_t dev_t
3060+
#define __fts_ino_t ino_t
3061+
#define __fts_length_t unsigned int
3062+
#define __fts_level_t int
3063+
#define __fts_nlink_t nlink_t
3064+
#define __fts_number_t int64_t
3065+
#define __fts_stat_t struct stat
30243066
#define __inline inline
30253067
#define __restrict restrict
30263068
#define __tg_complex(fun,x) (__RETCAST_CX(x)( __FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : __LDBLCX((x)+I) ? fun ## l (x) : fun(x) ))

‎expected/wasm32-wasip2/defined-symbols.txt

+5
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,11 @@ ftello
735735
ftello64
736736
ftime
737737
ftruncate
738+
fts_children
739+
fts_close
740+
fts_open
741+
fts_read
742+
fts_set
738743
futimens
739744
futimesat
740745
fwide

‎expected/wasm32-wasip2/include-all.c

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
#include <float.h>
8787
#include <fmtmsg.h>
8888
#include <fnmatch.h>
89+
#include <fts.h>
8990
#include <ftw.h>
9091
#include <getopt.h>
9192
#include <glob.h>

‎expected/wasm32-wasip2/predefined-macros.txt

+42
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,40 @@
474474
#define FSETLOCKING_BYCALLER 2
475475
#define FSETLOCKING_INTERNAL 1
476476
#define FSETLOCKING_QUERY 0
477+
#define FTS_AGAIN 1
478+
#define FTS_COMFOLLOW 0x001
479+
#define FTS_D 1
480+
#define FTS_DC 2
481+
#define FTS_DEFAULT 3
482+
#define FTS_DNR 4
483+
#define FTS_DONTCHDIR 0x01
484+
#define FTS_DOT 5
485+
#define FTS_DP 6
486+
#define FTS_ERR 7
487+
#define FTS_F 8
488+
#define FTS_FOLLOW 2
489+
#define FTS_INIT 9
490+
#define FTS_ISW 0x04
491+
#define FTS_LOGICAL 0x002
492+
#define FTS_NAMEONLY 0x100
493+
#define FTS_NOCHDIR 0x004
494+
#define FTS_NOINSTR 3
495+
#define FTS_NOSTAT 0x008
496+
#define FTS_NS 10
497+
#define FTS_NSOK 11
498+
#define FTS_OPTIONMASK 0x0ff
499+
#define FTS_PHYSICAL 0x010
500+
#define FTS_ROOTLEVEL 0
501+
#define FTS_ROOTPARENTLEVEL -1
502+
#define FTS_SEEDOT 0x020
503+
#define FTS_SKIP 4
504+
#define FTS_SL 12
505+
#define FTS_SLNONE 13
506+
#define FTS_STOP 0x200
507+
#define FTS_SYMFOLLOW 0x02
508+
#define FTS_W 14
509+
#define FTS_WHITEOUT 0x080
510+
#define FTS_XDEV 0x040
477511
#define FTW_CHDIR 4
478512
#define FTW_D 2
479513
#define FTW_DEPTH 8
@@ -2220,6 +2254,7 @@
22202254
#define _FLOAT_H
22212255
#define _FMTMSG_H
22222256
#define _FNMATCH_H
2257+
#define _FTS_H_
22232258
#define _FTW_H
22242259
#define _GETOPT_H
22252260
#define _GLOB_H
@@ -3173,6 +3208,13 @@
31733208
#define __alignof_is_defined 1
31743209
#define __bitop(x,i,o) ((x)[(i)/8] o (1<<(i)%8))
31753210
#define __bool_true_false_are_defined 1
3211+
#define __fts_dev_t dev_t
3212+
#define __fts_ino_t ino_t
3213+
#define __fts_length_t unsigned int
3214+
#define __fts_level_t int
3215+
#define __fts_nlink_t nlink_t
3216+
#define __fts_number_t int64_t
3217+
#define __fts_stat_t struct stat
31763218
#define __inline inline
31773219
#define __restrict restrict
31783220
#define __tg_complex(fun,x) (__RETCAST_CX(x)( __FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : __LDBLCX((x)+I) ? fun ## l (x) : fun(x) ))

‎fts/config.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#define HAVE_DECL_MAX 1
2+
3+
#define HAVE_DECL_UINTMAX_MAX 0
4+
5+
#define HAVE_DIRFD 1
6+
7+
#define HAVE_FCHDIR 0

‎fts/musl-fts/COPYING

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Copyright (c) 1989, 1993
2+
The Regents of the University of California. All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions
6+
are met:
7+
1. Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
2. Redistributions in binary form must reproduce the above copyright
10+
notice, this list of conditions and the following disclaimer in the
11+
documentation and/or other materials provided with the distribution.
12+
3. Neither the name of the University nor the names of its contributors
13+
may be used to endorse or promote products derived from this software
14+
without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26+
SUCH DAMAGE.

‎fts/musl-fts/NOTICE.wasi-libc.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
This directory contains a copy of the musl-fts library licensed under
2+
BSD-3-Clause with wasi-libc modifications. See COPYING for the full license text.
3+
4+
The original source code can be found at https://github.com/void-linux/musl-fts/archive/refs/tags/v1.2.7.tar.gz
5+
6+
## How to update musl-fts sources
7+
8+
1. Update the `MUSL_FTS_VERSION` variable in `./fts/update-musl-fts.sh`
9+
2. Run `./fts/update-musl-fts.sh`

‎fts/musl-fts/fts.c

+1,279
Large diffs are not rendered by default.

‎fts/musl-fts/fts.h

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/* $NetBSD: fts.h,v 1.19 2009/08/16 19:33:38 christos Exp $ */
2+
3+
/*
4+
* Copyright (c) 1989, 1993
5+
* The Regents of the University of California. All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions
9+
* are met:
10+
* 1. Redistributions of source code must retain the above copyright
11+
* notice, this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright
13+
* notice, this list of conditions and the following disclaimer in the
14+
* documentation and/or other materials provided with the distribution.
15+
* 3. Neither the name of the University nor the names of its contributors
16+
* may be used to endorse or promote products derived from this software
17+
* without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29+
* SUCH DAMAGE.
30+
*
31+
* @(#)fts.h 8.3 (Berkeley) 8/14/94
32+
*/
33+
34+
#ifndef _FTS_H_
35+
#define _FTS_H_
36+
37+
#include <stdint.h>
38+
#include <sys/types.h>
39+
40+
#ifndef __fts_stat_t
41+
#define __fts_stat_t struct stat
42+
#endif
43+
#ifndef __fts_nlink_t
44+
#define __fts_nlink_t nlink_t
45+
#endif
46+
#ifndef __fts_ino_t
47+
#define __fts_ino_t ino_t
48+
#endif
49+
#ifndef __fts_length_t
50+
#define __fts_length_t unsigned int
51+
#endif
52+
#ifndef __fts_number_t
53+
#define __fts_number_t int64_t
54+
#endif
55+
#ifndef __fts_dev_t
56+
#define __fts_dev_t dev_t
57+
#endif
58+
#ifndef __fts_level_t
59+
#define __fts_level_t int
60+
#endif
61+
62+
typedef struct {
63+
struct _ftsent *fts_cur; /* current node */
64+
struct _ftsent *fts_child; /* linked list of children */
65+
struct _ftsent **fts_array; /* sort array */
66+
dev_t fts_dev; /* starting device # */
67+
char *fts_path; /* path for this descent */
68+
int fts_rfd; /* fd for root */
69+
unsigned int fts_pathlen; /* sizeof(path) */
70+
unsigned int fts_nitems; /* elements in the sort array */
71+
int (*fts_compar) /* compare function */
72+
(const struct _ftsent **, const struct _ftsent **);
73+
74+
#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
75+
#define FTS_LOGICAL 0x002 /* logical walk */
76+
#define FTS_NOCHDIR 0x004 /* don't change directories */
77+
#define FTS_NOSTAT 0x008 /* don't get stat info */
78+
#define FTS_PHYSICAL 0x010 /* physical walk */
79+
#define FTS_SEEDOT 0x020 /* return dot and dot-dot */
80+
#define FTS_XDEV 0x040 /* don't cross devices */
81+
#define FTS_WHITEOUT 0x080 /* return whiteout information */
82+
#define FTS_OPTIONMASK 0x0ff /* valid user option mask */
83+
84+
#define FTS_NAMEONLY 0x100 /* (private) child names only */
85+
#define FTS_STOP 0x200 /* (private) unrecoverable error */
86+
int fts_options; /* fts_open options, global flags */
87+
} FTS;
88+
89+
typedef struct _ftsent {
90+
struct _ftsent *fts_cycle; /* cycle node */
91+
struct _ftsent *fts_parent; /* parent directory */
92+
struct _ftsent *fts_link; /* next file in directory */
93+
__fts_number_t fts_number; /* local numeric value */
94+
void *fts_pointer; /* local address value */
95+
char *fts_accpath; /* access path */
96+
char *fts_path; /* root path */
97+
int fts_errno; /* errno for this node */
98+
int fts_symfd; /* fd for symlink */
99+
__fts_length_t fts_pathlen; /* strlen(fts_path) */
100+
__fts_length_t fts_namelen; /* strlen(fts_name) */
101+
102+
__fts_ino_t fts_ino; /* inode */
103+
__fts_dev_t fts_dev; /* device */
104+
__fts_nlink_t fts_nlink; /* link count */
105+
106+
#define FTS_ROOTPARENTLEVEL -1
107+
#define FTS_ROOTLEVEL 0
108+
__fts_level_t fts_level; /* depth (-1 to N) */
109+
110+
#define FTS_D 1 /* preorder directory */
111+
#define FTS_DC 2 /* directory that causes cycles */
112+
#define FTS_DEFAULT 3 /* none of the above */
113+
#define FTS_DNR 4 /* unreadable directory */
114+
#define FTS_DOT 5 /* dot or dot-dot */
115+
#define FTS_DP 6 /* postorder directory */
116+
#define FTS_ERR 7 /* error; errno is set */
117+
#define FTS_F 8 /* regular file */
118+
#define FTS_INIT 9 /* initialized only */
119+
#define FTS_NS 10 /* stat(2) failed */
120+
#define FTS_NSOK 11 /* no stat(2) requested */
121+
#define FTS_SL 12 /* symbolic link */
122+
#define FTS_SLNONE 13 /* symbolic link without target */
123+
#define FTS_W 14 /* whiteout object */
124+
unsigned short fts_info; /* user flags for FTSENT structure */
125+
126+
#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
127+
#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
128+
#define FTS_ISW 0x04 /* this is a whiteout object */
129+
unsigned short fts_flags; /* private flags for FTSENT structure */
130+
131+
#define FTS_AGAIN 1 /* read node again */
132+
#define FTS_FOLLOW 2 /* follow symbolic link */
133+
#define FTS_NOINSTR 3 /* no instructions */
134+
#define FTS_SKIP 4 /* discard node */
135+
unsigned short fts_instr; /* fts_set() instructions */
136+
137+
__fts_stat_t *fts_statp; /* stat(2) information */
138+
char fts_name[1]; /* file name */
139+
} FTSENT;
140+
141+
#ifdef __cplusplus
142+
extern "C" {
143+
#endif
144+
FTSENT *fts_children(FTS *, int);
145+
int fts_close(FTS *);
146+
FTS *fts_open(char * const *, int,
147+
int (*)(const FTSENT **, const FTSENT **));
148+
FTSENT *fts_read(FTS *);
149+
int fts_set(FTS *, FTSENT *, int);
150+
#ifdef __cplusplus
151+
}
152+
#endif
153+
154+
155+
#endif /* !_FTS_H_ */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
From 878675b2299c23593a9adee25d5c828fb760819e Mon Sep 17 00:00:00 2001
2+
From: Yuta Saito <kateinoigakukun@gmail.com>
3+
Date: Thu, 1 Aug 2024 01:50:49 +0000
4+
Subject: [PATCH] Add conditional handling for fchdir and chdir functions
5+
6+
Define preprocessor conditions for `HAVE_FCHDIR` to handle platforms without
7+
fchdir. On these platforms, pretend that `FTS_NOCHDIR` is always set.
8+
9+
This change is necessary to build the `fts` module on the top of the WASI and
10+
wasi-libc, which doesn't provide the `fchdir`.
11+
12+
Upstream pull request: https://github.com/void-linux/musl-fts/pull/14
13+
---
14+
fts.c | 24 ++++++++++++++++++++++++
15+
1 file changed, 24 insertions(+)
16+
17+
diff --git a/fts.c b/fts.c
18+
index 0f8d05b..da4bc08 100644
19+
--- a/fts.c
20+
+++ b/fts.c
21+
@@ -112,8 +112,15 @@ static int fts_safe_changedir(const FTS *, const FTSENT *, int,
22+
#define ISSET(opt) (sp->fts_options & (opt))
23+
#define SET(opt) (sp->fts_options |= (opt))
24+
25+
+#if HAVE_FCHDIR
26+
#define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path))
27+
#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
28+
+#else
29+
+/* If we don't have fchdir, pretend that !ISSET(FTS_NOCHDIR) is always false in
30+
+ * the above macros, and do not reference chdir or fchdir. */
31+
+#define CHDIR(sp, path) 0
32+
+#define FCHDIR(sp, fd) 0
33+
+#endif
34+
35+
/* fts_build flags */
36+
#define BCHILD 1 /* fts_children */
37+
@@ -136,6 +143,11 @@ fts_open(char * const *argv, int options,
38+
39+
_DIAGASSERT(argv != NULL);
40+
41+
+#if !HAVE_FCHDIR
42+
+ /* If we don't have fchdir, pretend that FTS_NOCHDIR is always set. */
43+
+ options |= FTS_NOCHDIR;
44+
+#endif
45+
+
46+
/* Options check. */
47+
if (options & ~FTS_OPTIONMASK) {
48+
errno = EINVAL;
49+
@@ -299,12 +311,14 @@ fts_close(FTS *sp)
50+
free(sp->fts_array);
51+
free(sp->fts_path);
52+
53+
+ #if HAVE_FCHDIR
54+
/* Return to original directory, save errno if necessary. */
55+
if (!ISSET(FTS_NOCHDIR)) {
56+
if (fchdir(sp->fts_rfd) == -1)
57+
saved_errno = errno;
58+
(void)close(sp->fts_rfd);
59+
}
60+
+ #endif
61+
62+
/* Free up the stream pointer. */
63+
free(sp);
64+
@@ -611,6 +625,7 @@ fts_children(FTS *sp, int instr)
65+
} else
66+
instr = BCHILD;
67+
68+
+ #if HAVE_FCHDIR
69+
/*
70+
* If using chdir on a relative path and called BEFORE fts_read does
71+
* its chdir to the root of a traversal, we can lose -- we need to
72+
@@ -631,6 +646,10 @@ fts_children(FTS *sp, int instr)
73+
}
74+
(void)close(fd);
75+
return (sp->fts_child);
76+
+ #else
77+
+ /* If not using chdir, just build the list. */
78+
+ return (sp->fts_child = fts_build(sp, instr));
79+
+ #endif
80+
}
81+
82+
/*
83+
@@ -1226,6 +1245,7 @@ fts_maxarglen(char * const *argv)
84+
static int
85+
fts_safe_changedir(const FTS *sp, const FTSENT *p, int fd, const char *path)
86+
{
87+
+#if HAVE_FCHDIR
88+
int oldfd = fd, ret = -1;
89+
__fts_stat_t sb;
90+
91+
@@ -1252,4 +1272,8 @@ bail:
92+
errno = save_errno;
93+
}
94+
return ret;
95+
+#else
96+
+ /* If we can't do fchdir, pretend as if ISSET(FTS_NOCHDIR) is set. */
97+
+ return 0;
98+
+#endif
99+
}
100+
--
101+
2.43.2
102+

‎fts/update-musl-fts.sh

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/sh
2+
3+
FTS_DIR="$(dirname "$(realpath "$0")")"
4+
MUSL_FTS_VERSION=1.2.7
5+
MUSL_FTS_TARBALL_URL="https://github.com/void-linux/musl-fts/archive/refs/tags/v$MUSL_FTS_VERSION.tar.gz"
6+
MUSL_FTS_SRC_DIR="$FTS_DIR/musl-fts"
7+
8+
mkdir -p "$MUSL_FTS_SRC_DIR"
9+
10+
# Download and extract the musl-fts tarball
11+
echo "Downloading musl-fts $MUSL_FTS_VERSION"
12+
curl -L "$MUSL_FTS_TARBALL_URL" | tar xzf - --strip-component=1 -C "$MUSL_FTS_SRC_DIR" \
13+
musl-fts-$MUSL_FTS_VERSION/fts.c \
14+
musl-fts-$MUSL_FTS_VERSION/fts.h \
15+
musl-fts-$MUSL_FTS_VERSION/COPYING
16+
17+
for patch in "$FTS_DIR/patches/"*.patch; do
18+
echo "Applying patch $patch"
19+
patch -p1 -d "$MUSL_FTS_SRC_DIR" < "$patch"
20+
done
21+
22+
cat <<EOF > "$MUSL_FTS_SRC_DIR/NOTICE.wasi-libc.md"
23+
This directory contains a copy of the musl-fts library licensed under
24+
BSD-3-Clause with wasi-libc modifications. See COPYING for the full license text.
25+
26+
The original source code can be found at $MUSL_FTS_TARBALL_URL
27+
28+
## How to update musl-fts sources
29+
30+
1. Update the \`MUSL_FTS_VERSION\` variable in \`$0\`
31+
2. Run \`$0\`
32+
EOF

‎test/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
build
22
download
33
run
4+
5+
smoke/*.dir

‎test/Makefile

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# - `run`: execute the benchmarks with a Wasm `$(ENGINE)` of choice (e.g.,
1010
# Wasmtime)
1111

12-
test: run
12+
test: run run_smoke
1313

1414
# Unlike the `libc-test` directory, we will output all artifacts to the `build`
1515
# directory (keeping with the `wasi-libc` conventions).
@@ -190,6 +190,10 @@ endif
190190
clean::
191191
rm -rf $(OBJDIR)/*/*.err
192192

193+
##### SMOKE TEST SUITE #########################################################
194+
195+
include smoke/smoke.mk
196+
193197
##### MISC #####################################################################
194198

195199
# Note: the `clean` target has been built up by all of the previous sections.

‎test/smoke/smoke.mk

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Smoke test suite specific to wasi-libc
2+
#
3+
# This Makefile is included by the parent Makefile
4+
5+
SMOKE_TESTS_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
6+
SMOKE_TESTS := $(wildcard $(SMOKE_TESTS_DIR)/*.c)
7+
SMOKE_OBJDIR := $(OBJDIR)/smoke
8+
SMOKE_WASMS := $(SMOKE_TESTS:$(SMOKE_TESTS_DIR)/%.c=$(SMOKE_OBJDIR)/%.core.wasm)
9+
SMOKE_ERRS := $(SMOKE_WASMS:%.core.wasm=%.wasm.err)
10+
11+
$(SMOKE_OBJDIR):
12+
mkdir -p $@
13+
14+
$(SMOKE_OBJDIR)/%.core.wasm: $(SMOKE_TESTS_DIR)/%.c | $(SMOKE_OBJDIR)
15+
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
16+
17+
ifeq ($(TARGET_TRIPLE), wasm32-wasip2)
18+
$(SMOKE_OBJDIR)/%.wasm: $(SMOKE_OBJDIR)/%.core.wasm
19+
$(WASM_TOOLS) component new --adapt $(ADAPTER) $< -o $@
20+
endif
21+
22+
ifeq ($(TARGET_TRIPLE), wasm32-wasip2)
23+
$(SMOKE_OBJDIR)/%.wasm.err: $(SMOKE_OBJDIR)/%.wasm
24+
rm -rf $(SMOKE_TESTS_DIR)/$*.dir
25+
mkdir -p $(SMOKE_TESTS_DIR)/$*.dir
26+
$(ENGINE) --dir $(SMOKE_TESTS_DIR)/$*.dir::/ --wasm component-model $< >$@
27+
else
28+
$(SMOKE_OBJDIR)/%.wasm.err: $(SMOKE_OBJDIR)/%.core.wasm
29+
rm -rf $(SMOKE_TESTS_DIR)/$*.dir
30+
mkdir -p $(SMOKE_TESTS_DIR)/$*.dir
31+
$(ENGINE) --dir $(SMOKE_TESTS_DIR)/$*.dir::/ $< >$@
32+
endif
33+
34+
run_smoke: $(SMOKE_ERRS)
35+
@echo "Smoke tests passed"

‎test/smoke/test_fts.c

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/*
2+
* We modified musl-fts not to use fchdir() and we made FTS_NOCHDIR
3+
* the default behavior. This test is to make sure that the modified
4+
* musl-fts works as expected.
5+
*/
6+
7+
#include <fts.h>
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
#include <string.h>
11+
#include <unistd.h>
12+
#include <sys/stat.h>
13+
#include <errno.h>
14+
15+
void __expect_next_ftsent(FTSENT *p, const char *path, short level, int info, const char *file, int line) {
16+
if (p == NULL) {
17+
printf("Error: fts_read() returned NULL at %s:%d\n", file, line);
18+
exit(1);
19+
}
20+
21+
if (strcmp(p->fts_path, path) != 0) {
22+
printf("Error: expected path \"%s\", got \"%s\" at %s:%d\n", path, p->fts_path, file, line);
23+
exit(1);
24+
}
25+
26+
if (p->fts_level != level) {
27+
printf("Error: expected level %d, got %d at %s:%d\n", level, p->fts_level, file, line);
28+
exit(1);
29+
}
30+
31+
if (p->fts_info != info) {
32+
printf("Error: expected info %d, got %d at %s:%d\n", info, p->fts_info, file, line);
33+
exit(1);
34+
}
35+
}
36+
37+
#define expect_next_ftsent(p, path, level, info) __expect_next_ftsent(p, path, level, info, __FILE__, __LINE__)
38+
39+
static int compare_ents (const FTSENT **a, const FTSENT **b) {
40+
return strcmp((*a)->fts_name, (*b)->fts_name);
41+
}
42+
43+
void touch(const char *path) {
44+
FILE *f = fopen(path, "w");
45+
if (f == NULL) {
46+
printf("Error: fopen(%s) failed: %s\n", path, strerror(errno));
47+
exit(1);
48+
}
49+
fclose(f);
50+
}
51+
52+
void test_fts_info(int base_options) {
53+
FTS *ftsp;
54+
55+
mkdir("t1", 0755);
56+
touch("t1/file1");
57+
mkdir("t1/dir1", 0755);
58+
touch("t1/dir1/file2");
59+
mkdir("t1/dir1/dir2", 0755);
60+
touch("t1/dir1/file3");
61+
62+
char *paths[] = {"./t1", NULL};
63+
ftsp = fts_open(paths, base_options, compare_ents);
64+
if (ftsp == NULL) {
65+
printf("Error: fts_open(%s, %d) failed: %s\n", paths[0], base_options, strerror(errno));
66+
exit(1);
67+
}
68+
69+
expect_next_ftsent(fts_read(ftsp), "./t1", 0, FTS_D);
70+
expect_next_ftsent(fts_read(ftsp), "./t1/dir1", 1, FTS_D);
71+
expect_next_ftsent(fts_read(ftsp), "./t1/dir1/dir2", 2, FTS_D);
72+
expect_next_ftsent(fts_read(ftsp), "./t1/dir1/dir2", 2, FTS_DP);
73+
expect_next_ftsent(fts_read(ftsp), "./t1/dir1/file2", 2, FTS_F);
74+
expect_next_ftsent(fts_read(ftsp), "./t1/dir1/file3", 2, FTS_F);
75+
expect_next_ftsent(fts_read(ftsp), "./t1/dir1", 1, FTS_DP);
76+
expect_next_ftsent(fts_read(ftsp), "./t1/file1", 1, FTS_F);
77+
expect_next_ftsent(fts_read(ftsp), "./t1", 0, FTS_DP);
78+
79+
fts_close(ftsp);
80+
}
81+
82+
void test_symlink_fts_info(int base_options) {
83+
FTS *ftsp;
84+
85+
mkdir("t2", 0755);
86+
touch("t2/file1");
87+
symlink("file1", "t2/symlink1");
88+
symlink("nonexistent", "t2/broken_symlink1");
89+
90+
char *paths[] = {"./t2", NULL};
91+
ftsp = fts_open(paths, base_options, compare_ents);
92+
if (ftsp == NULL) {
93+
printf("Error: fts_open(%s, %d) failed: %s\n", paths[0], base_options, strerror(errno));
94+
exit(1);
95+
}
96+
97+
expect_next_ftsent(fts_read(ftsp), "./t2", 0, FTS_D);
98+
expect_next_ftsent(fts_read(ftsp), "./t2/broken_symlink1", 1, FTS_SL);
99+
expect_next_ftsent(fts_read(ftsp), "./t2/file1", 1, FTS_F);
100+
expect_next_ftsent(fts_read(ftsp), "./t2/symlink1", 1, FTS_SL);
101+
expect_next_ftsent(fts_read(ftsp), "./t2", 0, FTS_DP);
102+
103+
fts_close(ftsp);
104+
105+
ftsp = fts_open(paths, base_options | FTS_LOGICAL, compare_ents);
106+
if (ftsp == NULL) {
107+
printf("Error: fts_open(%s, %d | FTS_LOGICAL) failed: %s\n", paths[0], base_options, strerror(errno));
108+
exit(1);
109+
}
110+
111+
expect_next_ftsent(fts_read(ftsp), "./t2", 0, FTS_D);
112+
// FTS_SLNONE should be returned for broken symlinks in FTS_LOGICAL mode
113+
expect_next_ftsent(fts_read(ftsp), "./t2/broken_symlink1", 1, FTS_SLNONE);
114+
expect_next_ftsent(fts_read(ftsp), "./t2/file1", 1, FTS_F);
115+
expect_next_ftsent(fts_read(ftsp), "./t2/symlink1", 1, FTS_F);
116+
expect_next_ftsent(fts_read(ftsp), "./t2", 0, FTS_DP);
117+
}
118+
119+
void __expect_child_ftsent(FTSENT *p, const char *name, short level, int info, const char *file, int line) {
120+
if (p == NULL) {
121+
printf("Error: fts_children() returned NULL at %s:%d\n", file, line);
122+
exit(1);
123+
}
124+
125+
// Check fts_name instead of fts_path because fts_children() doesn't set fts_path
126+
if (strcmp(p->fts_name, name) != 0) {
127+
printf("Error: expected name \"%s\", got \"%s\" at %s:%d\n", name, p->fts_name, file, line);
128+
exit(1);
129+
}
130+
131+
if (p->fts_level != level) {
132+
printf("Error: expected level %d, got %d at %s:%d\n", level, p->fts_level, file, line);
133+
exit(1);
134+
}
135+
136+
if (p->fts_info != info) {
137+
printf("Error: expected info %d, got %d at %s:%d\n", info, p->fts_info, file, line);
138+
exit(1);
139+
}
140+
}
141+
142+
#define expect_child_ftsent(p, name, level, info) __expect_child_ftsent(p, name, level, info, __FILE__, __LINE__)
143+
144+
void test_fts_children(int base_options) {
145+
FTS *ftsp;
146+
FTSENT *p;
147+
148+
mkdir("t3", 0755);
149+
touch("t3/file1");
150+
mkdir("t3/dir1", 0755);
151+
touch("t3/dir1/file2");
152+
mkdir("t3/dir1/dir2", 0755);
153+
touch("t3/dir1/file3");
154+
155+
char *paths[] = {"./t3", NULL};
156+
ftsp = fts_open(paths, base_options, compare_ents);
157+
if (ftsp == NULL) {
158+
printf("Error: fts_open(%s, %d) failed: %s\n", paths[0], base_options, strerror(errno));
159+
exit(1);
160+
}
161+
162+
FTSENT *t3 = fts_read(ftsp);
163+
expect_next_ftsent(t3, "./t3", 0, FTS_D);
164+
165+
FTSENT *ents = fts_children(ftsp, 0);
166+
expect_child_ftsent(ents, "dir1", 1, FTS_D);
167+
expect_child_ftsent(ents->fts_link, "file1", 1, FTS_F);
168+
169+
fts_close(ftsp);
170+
}
171+
172+
int main(void) {
173+
int base_options_set[] = {FTS_PHYSICAL, FTS_NOCHDIR};
174+
for (int i = 0; i < sizeof(base_options_set) / sizeof(base_options_set[0]); i++) {
175+
test_fts_info(base_options_set[i]);
176+
test_symlink_fts_info(base_options_set[i]);
177+
test_fts_children(base_options_set[i]);
178+
}
179+
return 0;
180+
}

0 commit comments

Comments
 (0)
Please sign in to comment.