File Coverage

Restrict.xs
Criterion Covered Total %
statement 185 197 93.9
branch 284 644 44.1
condition n/a
subroutine n/a
pod n/a
total 469 841 55.7


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "easyxs/easyxs.h"
3              
4             // Cribbed from Socket.xs:
5             /* STRUCT_OFFSET should have come from from perl.h, but if not,
6             * roll our own (not using offsetof() since that is C99). */
7             #ifndef STRUCT_OFFSET
8             # define STRUCT_OFFSET(s,m) (Size_t)(&(((s *)0)->m))
9             #endif
10              
11             #define STRUCT_MEMBER_SIZE(s,m) sizeof(((s *)0)->m)
12              
13             #define SA_FAMILY_END_OFFSET ( \
14             STRUCT_OFFSET(struct sockaddr, sa_family) \
15             + STRUCT_MEMBER_SIZE(struct sockaddr, sa_family) \
16             )
17              
18             // Modern Win32 releases do support UNIX sockets via afunix.h,
19             // but that header file isn’t available on MinGW. Socket.xs defines
20             // the necessary structs and constants directly; if needed we could
21             // take that approach, but for now let’s just forgo UNIX socket support
22             // unless there’s sys/un.h.
23             #ifdef I_SYS_UN // cf. perl5 Porting/Glossary
24              
25             #define HAS_UNIX_SOCKETS 1
26             #include
27              
28             #define SUN_PATH_LEN STRUCT_MEMBER_SIZE(struct sockaddr_un, sun_path)
29              
30             #else
31             #define HAS_UNIX_SOCKETS 0
32             #endif
33              
34             #include
35             #include
36              
37             #include "ppport.h"
38              
39             #define DEBUG 0
40              
41             /* A duplicate of PL_ppaddr as we find it at BOOT time.
42             We can thus overwrite PL_ppaddr with our own wrapper functions.
43             This interacts better with wrap_op_checker(), which doesn’t provide
44             a good way to call the op’s (now-overwritten) op_ppaddr callback.
45             */
46             static Perl_ppaddr_t ORIG_PL_ppaddr[OP_max];
47              
48             #define MYPKG "Filesys::Restrict"
49              
50             /* An idempotent variant of dMARK that allows us to inspect the
51             mark stack without changing it: */
52             #ifndef dMARK_TOPMARK
53             #define dMARK_TOPMARK SV **mark = PL_stack_base + TOPMARK
54             #endif
55              
56 161           static inline SV* _get_callback(pTHX) {
57 161           SV* callback = get_sv(MYPKG "::_AUTHORIZE", 0);
58              
59 161 50         if (callback && !SvOK(callback)) {
    100          
    50          
    50          
60 5           callback = NULL;
61             }
62              
63 161           return callback;
64             }
65              
66             #define _IS_FILEHANDLE(expr) ( \
67             (SvTYPE(expr) == SVt_PVGV) || \
68             (SvROK(expr) && SvTYPE(SvRV(expr)) == SVt_PVGV) || \
69             (SvTYPE(expr) == SVt_PVIO) || \
70             (SvROK(expr) && SvTYPE(SvRV(expr)) == SVt_PVIO) \
71             )
72              
73 25           bool _is_pipe_open(pTHX_ const char* str, STRLEN len) {
74 25 100         if (len >= 2) {
75 17 50         if (memEQ("|-", str, 2)) return true;
76 17 50         if (memEQ("-|", str, 2)) return true;
77             }
78              
79 25           return false;
80             }
81              
82             #define _IS_SCALAR_REF(sv) (SvROK(sv) && (SvTYPE(SvRV(sv)) < SVt_PVGV))
83              
84             // Returns NULL to indicate no path.
85 13           static SV* _get_path_from_3arg_open(pTHX_ SV* mode, SV* expr) {
86              
87             // 3-arg open with undef 3rd arg opens an anonymous tempfile.
88 13 100         if (!SvOK(expr)) return NULL;
    50          
    50          
89              
90             // Ignore scalar-reference paths, which indicate an “open”
91             // of a Perl scalar.
92 12 100         if (_IS_SCALAR_REF(expr)) return NULL;
    50          
93              
94 12 50         if (!SvPOK(mode)) croak("mode isn’t a string?!?");
95              
96             STRLEN modelen;
97 12 50         const char* modestr = SvPVbyte(mode, modelen);
98              
99 12 50         if (_is_pipe_open(aTHX_ modestr, modelen)) return NULL;
100              
101             // If the last character of the mode is '=' then expr is a
102             // file descriptor or filehandle, so we shouldn’t care.
103 12 100         if (NULL != strchr(modestr, '&')) return NULL;
104              
105 13           return expr;
106             }
107              
108 13           static SV* _get_path_from_2arg_open(pTHX_ SV* expr) {
109             STRLEN len;
110 13 50         const char* str = SvPVbyte(expr, len);
111              
112 13 50         if (_is_pipe_open(aTHX_ str, len)) return NULL;
113              
114 13 50         if (len < 1) return NULL;
115              
116             // Special cases:
117 13 50         if (len == 2) {
118 0 0         if (memEQ(str, ">-", 2)) return NULL; // opens STDOUT
119 0 0         if (memEQ(str, "<-", 2)) return NULL; // opens STDIN
120             }
121              
122 13           STRLEN idx = 0;
123              
124 13 100         if (str[idx] == '+') idx++;
125              
126 13 100         if (str[idx] == '<') {
127 5           idx++;
128             }
129 8 50         else if (str[idx] == '>') {
130 8           idx++;
131              
132 8 100         if (str[idx] == '>') idx++;
133             }
134             else {
135              
136             // For now ignore anything that isn’t +>, +>>, +<, >, >>, or <.
137 0           return NULL;
138             }
139              
140             // Duplicating a filehandle or file descriptor is always OK.
141 13 50         if (str[idx] == '&') return NULL;
142              
143 13           return newSVpvn_flags(
144             str + idx,
145             len - idx,
146             SVs_TEMP
147             );
148             }
149              
150 195           static inline void _prep_stack(pTHX_ SV** args, unsigned argscount) {
151 195           dSP;
152              
153 195           ENTER;
154 195           SAVETMPS;
155              
156 195 50         PUSHMARK(SP);
157 195 50         EXTEND(SP, argscount);
158              
159             unsigned a;
160              
161 585 100         for (a=0; a < argscount; a++) PUSHs(args[a]);
162              
163 195           PUTBACK;
164 195           }
165              
166 138           static inline void _authorize(pTHX_ int OPID, SV* path_sv, SV* callback_sv) {
167 138           const char* opname = PL_op_desc[OPID];
168              
169 138           dSP;
170              
171 138           SV* args[] = {
172 138           newSVpvn_flags(opname, strlen(opname), SVs_TEMP),
173             path_sv,
174             };
175              
176 138           _prep_stack(aTHX_ args, 2);
177              
178 138           I32 returns = call_sv( callback_sv, G_SCALAR );
179              
180 138           SPAGAIN;
181              
182             bool authorized;
183              
184 138 50         if (returns) {
185 138           SV* got = POPs;
186 138 50         authorized = SvTRUE(got);
    50          
    0          
    50          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    100          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
187             }
188             else {
189 0           authorized = false;
190             }
191              
192 138           PUTBACK;
193 138 50         FREETMPS;
194 138           LEAVE;
195              
196 138 100         if (!authorized) {
197 57           _prep_stack(aTHX_ args, 2);
198              
199 57           call_pv( MYPKG "::_CROAK", G_VOID | G_DISCARD );
200              
201             // We should never get here:
202             assert(0);
203             }
204 81           }
205              
206             // open() is such a funny beast that it gets its own wrapper.
207 26           static OP* _wrapped_pp_OP_OPEN(pTHX) {
208 26           SV* callback = _get_callback(aTHX);
209 26 50         if (callback) {
210 26           dSP;
211 26           dMARK_TOPMARK;
212              
213 26           int numargs = SP - MARK;
214              
215             SV* path;
216              
217 26           switch (numargs) {
218             case 1:
219 0           path = NULL;
220 0           break;
221              
222             case 2:
223 13           path = _get_path_from_2arg_open(aTHX_ MARK[2]);
224 13           break;
225              
226             case 3:
227 13           path = _get_path_from_3arg_open(aTHX_ MARK[2], MARK[3]);
228              
229 13           break;
230              
231             default:
232              
233             // Shouldn’t happen, but just in case …
234 0           croak("Bad # of args: %d", numargs);
235             }
236              
237 26 100         if (path) {
238 21           _authorize(aTHX_ OP_OPEN, path, callback);
239             }
240             }
241              
242 17           return ORIG_PL_ppaddr[OP_OPEN](aTHX);
243             }
244              
245             # if 0
246             // require() also gets its own wrapper since it depends on @INC.
247             static OP* _wrapped_pp_OP_REQUIRE(pTHX) {
248             SV* callback = _get_callback(aTHX);
249             if (callback) {
250             dSP;
251              
252             SV* required = *SP;
253              
254             STRLEN reqlen;
255             const char* required_str = SvPVbyte(required, reqlen);
256              
257             if (reqlen && NULL != strchr("./", required_str[0])) {
258             _authorize(aTHX_ OP_REQUIRE, required, callback);
259             }
260             }
261              
262             return ORIG_PL_ppaddr[OP_REQUIRE](aTHX);
263             }
264             #endif
265              
266             #define MAKE_LAST_ARG_WRAPPER(OPID, CHECK_FH) \
267             static OP* _wrapped_pp_##OPID(pTHX) { \
268             SV* callback = _get_callback(aTHX); \
269             if (callback) { \
270             dSP; \
271             if (!CHECK_FH || !_IS_FILEHANDLE(*SP)) { \
272             _authorize(aTHX_ OPID, *SP, callback); \
273             } \
274             } \
275             \
276             return ORIG_PL_ppaddr[OPID](aTHX); \
277             }
278              
279             #define MAKE_LAST_ARG_WRAPPER_CHECK_FH(OPID) \
280             MAKE_LAST_ARG_WRAPPER(OPID, 1)
281              
282             #define MAKE_LAST_ARG_WRAPPER_NO_CHECK_FH(OPID) \
283             MAKE_LAST_ARG_WRAPPER(OPID, 0)
284              
285             #define MAKE_2ARG_WRAPPER(OPID) \
286             static OP* _wrapped_pp_##OPID(pTHX) { \
287             SV* callback = _get_callback(aTHX); \
288             if (callback) { \
289             dSP; \
290             _authorize(aTHX_ OPID, *SP, callback); \
291             _authorize(aTHX_ OPID, *(SP - 1), callback); \
292             } \
293             \
294             return ORIG_PL_ppaddr[OPID](aTHX); \
295             }
296              
297             // ----------------------------------------------------------------------
298              
299             #define _MY_SET_SP_AND_MARK(OP_MAXARG) \
300             dSP; \
301             dMARK_TOPMARK; \
302             \
303             /* The compiler will optimize this away \
304             for MAKE_FIRST_ARG_OPEN_LIST_WRAPPER: \
305             */ \
306             if (OP_MAXARG) \
307             if (SP < MARK || (SP - MARK) > OP_MAXARG) { \
308             unsigned numargs = MAXARG; \
309             MARK = SP; \
310             while (numargs--) MARK--; \
311             }
312              
313             /* For ops that take an indefinite number of args. */
314             #define MAKE_FIRST_ARG_OPEN_LIST_WRAPPER(OPID) \
315             MAKE_SINGLE_ARG_LIST_WRAPPER(OPID, 0, 0)
316              
317             /* For ops whose number of string args is a fixed range.
318              
319             NB: In some perls, some list opts don’t set MARK. In those cases we
320             fall back to MAXARG. As of now mkdir is the known “offender”, and
321             only on Alpine Linux 3.11 & 3.12 (not 3.13).
322             */
323             #define MAKE_SINGLE_ARG_LIST_WRAPPER(OPID, ARG_INDEX, OP_MAXARG) \
324             static OP* _wrapped_pp_##OPID(pTHX) { \
325             SV* callback = _get_callback(aTHX); \
326             if (callback) { \
327             _MY_SET_SP_AND_MARK(OP_MAXARG) \
328             \
329             _authorize(aTHX_ OPID, MARK[1 + ARG_INDEX], callback); \
330             } \
331             \
332             return ORIG_PL_ppaddr[OPID](aTHX); \
333             }
334              
335 3           static OP* _wrapped_pp_OP_TRUNCATE(pTHX) {
336 3           SV* callback = _get_callback(aTHX);
337 3 50         if (callback) {
338 3           dSP;
339 3           SV* first_arg = *(SP - 1);
340              
341 3 50         if (!_IS_FILEHANDLE(first_arg)) {
    100          
    50          
    50          
    50          
    0          
342 2           _authorize(aTHX_ OP_TRUNCATE, first_arg, callback);
343             }
344             }
345              
346 2           return ORIG_PL_ppaddr[OP_TRUNCATE](aTHX);
347             }
348              
349             #define MAKE_ALL_ARGS_LIST_WRAPPER_CHECK_FH(OPID, ARG_INDEX) \
350             static OP* _wrapped_pp_##OPID(pTHX) { \
351             SV* callback = _get_callback(aTHX); \
352             if (callback) { \
353             _MY_SET_SP_AND_MARK(0) \
354             \
355             MARK += ARG_INDEX; \
356             while (++MARK <= SP) { \
357             if (!_IS_FILEHANDLE(*MARK)) { \
358             _authorize(aTHX_ OPID, *MARK, callback); \
359             } \
360             } \
361             } \
362             \
363             return ORIG_PL_ppaddr[OPID](aTHX); \
364             }
365              
366             /* For ops where only the last arg is a string. */
367             #define MAKE_SOCKET_OP_WRAPPER(OPID) \
368             static OP* _wrapped_pp_##OPID(pTHX) { \
369             SV* callback = _get_callback(aTHX); \
370             if (callback) { \
371             dSP; \
372             STRLEN pathlen; \
373             const char* path = _get_local_socket_path(aTHX_ SP[0], &pathlen); \
374             if (path) { \
375             SV* path_sv = newSVpvn_flags(path, pathlen, SVs_TEMP); \
376             _authorize(aTHX_ OPID, path_sv, callback); \
377             } \
378             } \
379             \
380             return ORIG_PL_ppaddr[OPID](aTHX); \
381             }
382              
383 6           static const char* _get_local_socket_path(pTHX_ SV* sockname_sv, STRLEN *pathlen) {
384 6           char* path = NULL;
385              
386             #if HAS_UNIX_SOCKETS
387              
388             STRLEN sockname_len;
389 6 50         const char* sockname_str = SvPVbyte(sockname_sv, sockname_len);
390              
391             // Let Perl handle the failure state:
392 6 50         if (sockname_len >= SA_FAMILY_END_OFFSET) {
393 6           sa_family_t family = ( (struct sockaddr*) sockname_str )->sa_family;
394              
395 6 50         if (family == AF_UNIX) {
396 6           path = ( (struct sockaddr_un*) sockname_str )->sun_path;
397              
398             // We could compute pathlen via strlen(), but that would break
399             // Linux abstract-namespace sockets. We could start at the end
400             // of sun_path and find the first non-NUL, but that breaks in
401             // macOS (at least), which doesn’t zero out the rest of
402             // sun_path.
403             //
404             // So, we make a special exception for leading-NUL. :(
405             //
406 6 100         if (path[0] == '\0') {
407 1           *pathlen = 1 + strnlen(1 + path, SUN_PATH_LEN - 1);
408             }
409             else {
410 5           *pathlen = strnlen(path, SUN_PATH_LEN);
411             }
412             }
413             }
414             #endif
415              
416 6           return path;
417             }
418              
419 7 50         MAKE_SOCKET_OP_WRAPPER(OP_BIND);
    50          
420 3 50         MAKE_SOCKET_OP_WRAPPER(OP_CONNECT);
    50          
421              
422 6 50         MAKE_SINGLE_ARG_LIST_WRAPPER(OP_SYSOPEN, 1, 4);
    50          
    50          
    0          
423              
424 0 0         MAKE_FIRST_ARG_OPEN_LIST_WRAPPER(OP_EXEC);
425 6 50         MAKE_FIRST_ARG_OPEN_LIST_WRAPPER(OP_SYSTEM);
426              
427 0 0         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_LSTAT);
    0          
    0          
    0          
    0          
    0          
    0          
428 2 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_STAT);
    50          
    50          
    0          
    50          
    50          
    0          
429 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTRREAD);
    100          
    50          
    0          
    50          
    50          
    0          
430 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTRWRITE);
    100          
    50          
    0          
    50          
    50          
    0          
431 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTREXEC);
    100          
    50          
    0          
    50          
    50          
    0          
432 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTEREAD);
    100          
    50          
    0          
    50          
    50          
    0          
433 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTEWRITE);
    100          
    50          
    0          
    50          
    50          
    0          
434 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTEEXEC);
    100          
    50          
    0          
    50          
    50          
    0          
435 7 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTIS);
    100          
    50          
    0          
    50          
    50          
    0          
436 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTSIZE);
    100          
    50          
    0          
    50          
    50          
    0          
437 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTMTIME);
    100          
    50          
    0          
    50          
    50          
    0          
438 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTATIME);
    100          
    50          
    0          
    50          
    50          
    0          
439 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTCTIME);
    100          
    50          
    0          
    50          
    50          
    0          
440 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTROWNED);
    100          
    50          
    0          
    50          
    50          
    0          
441 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTEOWNED);
    100          
    50          
    0          
    50          
    50          
    0          
442 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTZERO);
    100          
    50          
    0          
    50          
    50          
    0          
443 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTSOCK);
    100          
    50          
    0          
    50          
    50          
    0          
444 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTCHR);
    100          
    50          
    0          
    50          
    50          
    0          
445 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTBLK);
    100          
    50          
    0          
    50          
    50          
    0          
446 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTFILE);
    100          
    50          
    0          
    50          
    50          
    0          
447 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTDIR);
    100          
    50          
    0          
    50          
    50          
    0          
448 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTPIPE);
    100          
    50          
    0          
    50          
    50          
    0          
449 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTSUID);
    100          
    50          
    0          
    50          
    50          
    0          
450 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTSGID);
    100          
    50          
    0          
    50          
    50          
    0          
451 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTSVTX);
    100          
    50          
    0          
    50          
    50          
    0          
452 3 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTLINK);
    50          
    50          
    0          
    50          
    50          
    0          
453 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTTEXT);
    100          
    50          
    0          
    50          
    50          
    0          
454 5 50         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_FTBINARY);
    100          
    50          
    0          
    50          
    50          
    0          
455 0 0         MAKE_LAST_ARG_WRAPPER_CHECK_FH(OP_CHDIR);
    0          
    0          
    0          
    0          
    0          
    0          
456 13 50         MAKE_ALL_ARGS_LIST_WRAPPER_CHECK_FH(OP_CHOWN, 2);
    50          
    100          
    50          
    50          
    50          
    0          
    100          
457 0 0         MAKE_LAST_ARG_WRAPPER_NO_CHECK_FH(OP_CHROOT);
458 10 50         MAKE_ALL_ARGS_LIST_WRAPPER_CHECK_FH(OP_UNLINK, 0);
    50          
    50          
    0          
    50          
    50          
    0          
    100          
459 16 50         MAKE_ALL_ARGS_LIST_WRAPPER_CHECK_FH(OP_CHMOD, 1);
    50          
    100          
    50          
    50          
    50          
    0          
    100          
460 13 50         MAKE_ALL_ARGS_LIST_WRAPPER_CHECK_FH(OP_UTIME, 2);
    50          
    100          
    50          
    50          
    50          
    0          
    100          
461 5 50         MAKE_2ARG_WRAPPER(OP_RENAME);
462 5 50         MAKE_2ARG_WRAPPER(OP_LINK);
463              
464             // symlink() is special: its “target” (the first arg) and doesn’t
465             // need to refer to a valid filesystem node.
466 0 0         MAKE_LAST_ARG_WRAPPER_NO_CHECK_FH(OP_SYMLINK);
467              
468 3 50         MAKE_LAST_ARG_WRAPPER_NO_CHECK_FH(OP_READLINK);
469 16 100         MAKE_SINGLE_ARG_LIST_WRAPPER(OP_MKDIR, 0, 2);
    50          
    50          
    0          
470 3 50         MAKE_LAST_ARG_WRAPPER_NO_CHECK_FH(OP_RMDIR);
471 3 50         MAKE_LAST_ARG_WRAPPER_NO_CHECK_FH(OP_OPEN_DIR);
472              
473             // MAKE_LAST_ARG_WRAPPER_NO_CHECK_FH(OP_DOFILE);
474              
475             /* ---------------------------------------------------------------------- */
476              
477             #define MAKE_BOOT_WRAPPER(OPID) \
478             ORIG_PL_ppaddr[OPID] = PL_ppaddr[OPID]; \
479             PL_ppaddr[OPID] = _wrapped_pp_##OPID;
480              
481             //----------------------------------------------------------------------
482              
483             bool initialized = false;
484              
485             MODULE = Filesys::Restrict PACKAGE = Filesys::Restrict
486              
487             PROTOTYPES: DISABLE
488              
489             BOOT:
490             /* In theory this is for PL_check rather than PL_ppaddr, but per
491             Paul Evans in practice this mutex gets used for other stuff, too.
492             Paul says a race here should be exceptionally rare, so for pre-5.16
493             perls (which lack this mutex) let’s just skip it.
494             */
495             #ifdef OP_CHECK_MUTEX_LOCK
496             OP_CHECK_MUTEX_LOCK;
497             #endif
498 6 50         if (!initialized) {
499 6           initialized = true;
500              
501 6           MAKE_BOOT_WRAPPER(OP_OPEN);
502 6           MAKE_BOOT_WRAPPER(OP_SYSOPEN);
503 6           MAKE_BOOT_WRAPPER(OP_TRUNCATE);
504 6           MAKE_BOOT_WRAPPER(OP_EXEC);
505 6           MAKE_BOOT_WRAPPER(OP_SYSTEM);
506              
507             if (HAS_UNIX_SOCKETS) {
508 6           MAKE_BOOT_WRAPPER(OP_BIND);
509 6           MAKE_BOOT_WRAPPER(OP_CONNECT);
510             }
511              
512 6           HV *stash = gv_stashpv(MYPKG, FALSE);
513 6           newCONSTSUB(stash, "_HAS_UNIX_SOCKETS", boolSV(HAS_UNIX_SOCKETS));
514              
515 6           MAKE_BOOT_WRAPPER(OP_LSTAT);
516 6           MAKE_BOOT_WRAPPER(OP_STAT);
517 6           MAKE_BOOT_WRAPPER(OP_FTRREAD);
518 6           MAKE_BOOT_WRAPPER(OP_FTRWRITE);
519 6           MAKE_BOOT_WRAPPER(OP_FTREXEC);
520 6           MAKE_BOOT_WRAPPER(OP_FTEREAD);
521 6           MAKE_BOOT_WRAPPER(OP_FTEWRITE);
522 6           MAKE_BOOT_WRAPPER(OP_FTEEXEC);
523 6           MAKE_BOOT_WRAPPER(OP_FTIS);
524 6           MAKE_BOOT_WRAPPER(OP_FTSIZE);
525 6           MAKE_BOOT_WRAPPER(OP_FTMTIME);
526 6           MAKE_BOOT_WRAPPER(OP_FTATIME);
527 6           MAKE_BOOT_WRAPPER(OP_FTCTIME);
528 6           MAKE_BOOT_WRAPPER(OP_FTROWNED);
529 6           MAKE_BOOT_WRAPPER(OP_FTEOWNED);
530 6           MAKE_BOOT_WRAPPER(OP_FTZERO);
531 6           MAKE_BOOT_WRAPPER(OP_FTSOCK);
532 6           MAKE_BOOT_WRAPPER(OP_FTCHR);
533 6           MAKE_BOOT_WRAPPER(OP_FTBLK);
534 6           MAKE_BOOT_WRAPPER(OP_FTFILE);
535 6           MAKE_BOOT_WRAPPER(OP_FTDIR);
536 6           MAKE_BOOT_WRAPPER(OP_FTPIPE);
537 6           MAKE_BOOT_WRAPPER(OP_FTSUID);
538 6           MAKE_BOOT_WRAPPER(OP_FTSGID);
539 6           MAKE_BOOT_WRAPPER(OP_FTSVTX);
540 6           MAKE_BOOT_WRAPPER(OP_FTLINK);
541 6           MAKE_BOOT_WRAPPER(OP_FTTEXT);
542 6           MAKE_BOOT_WRAPPER(OP_FTBINARY);
543 6           MAKE_BOOT_WRAPPER(OP_CHDIR);
544 6           MAKE_BOOT_WRAPPER(OP_CHOWN);
545 6           MAKE_BOOT_WRAPPER(OP_CHROOT);
546 6           MAKE_BOOT_WRAPPER(OP_UNLINK);
547 6           MAKE_BOOT_WRAPPER(OP_CHMOD);
548 6           MAKE_BOOT_WRAPPER(OP_UTIME);
549 6           MAKE_BOOT_WRAPPER(OP_RENAME);
550 6           MAKE_BOOT_WRAPPER(OP_LINK);
551 6           MAKE_BOOT_WRAPPER(OP_SYMLINK);
552 6           MAKE_BOOT_WRAPPER(OP_READLINK);
553 6           MAKE_BOOT_WRAPPER(OP_MKDIR);
554 6           MAKE_BOOT_WRAPPER(OP_RMDIR);
555 6           MAKE_BOOT_WRAPPER(OP_OPEN_DIR);
556              
557             // MAKE_BOOT_WRAPPER(OP_REQUIRE);
558             // MAKE_BOOT_WRAPPER(OP_DOFILE);
559             }
560             #ifdef OP_CHECK_MUTEX_UNLOCK
561             OP_CHECK_MUTEX_UNLOCK;
562             #endif