Coverage Report

Created: 2026-05-30 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/njs/external/njs_fs_module.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Dmitry Volyntsev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
8
#include <njs.h>
9
#include <njs_utils.h>
10
#include <njs_buffer.h>
11
#include <dirent.h>
12
#include <njs_unix.h>
13
14
#if (NJS_SOLARIS)
15
16
#define DT_DIR         0
17
#define DT_REG         1
18
#define DT_CHR         2
19
#define DT_LNK         3
20
#define DT_BLK         4
21
#define DT_FIFO        5
22
#define DT_SOCK        6
23
#define NJS_DT_INVALID 0xffffffff
24
25
#define njs_dentry_type(_dentry)                                             \
26
    (NJS_DT_INVALID)
27
28
#else
29
30
#define NJS_DT_INVALID 0xffffffff
31
32
#define njs_dentry_type(_dentry)                                             \
33
0
    ((_dentry)->d_type)
34
35
#endif
36
37
38
#define njs_fs_magic(calltype, mode)                                         \
39
    (((mode) << 2) | calltype)
40
41
#define njs_fs_magic2(field, type)                                           \
42
    (((type) << 4) | field)
43
44
45
typedef enum {
46
    NJS_FS_DIRECT,
47
    NJS_FS_PROMISE,
48
    NJS_FS_CALLBACK,
49
} njs_fs_calltype_t;
50
51
52
typedef enum {
53
    NJS_FS_TRUNC,
54
    NJS_FS_APPEND,
55
} njs_fs_writemode_t;
56
57
58
typedef enum {
59
    NJS_FS_STAT,
60
    NJS_FS_LSTAT,
61
    NJS_FS_FSTAT,
62
} njs_fs_statmode_t;
63
64
65
typedef struct {
66
    njs_str_t       name;
67
    int             value;
68
} njs_fs_entry_t;
69
70
71
typedef enum {
72
    NJS_FTW_PHYS = 1,
73
    NJS_FTW_MOUNT = 2,
74
    NJS_FTW_DEPTH = 8,
75
} njs_ftw_flags_t;
76
77
78
typedef enum {
79
    NJS_FTW_F,
80
    NJS_FTW_D,
81
    NJS_FTW_DNR,
82
    NJS_FTW_NS,
83
    NJS_FTW_SL,
84
    NJS_FTW_DP,
85
    NJS_FTW_SLN,
86
} njs_ftw_type_t;
87
88
89
typedef struct {
90
    long tv_sec;
91
    long tv_nsec;
92
} njs_timespec_t;
93
94
95
typedef struct {
96
    uint64_t        st_dev;
97
    uint64_t        st_mode;
98
    uint64_t        st_nlink;
99
    uint64_t        st_uid;
100
    uint64_t        st_gid;
101
    uint64_t        st_rdev;
102
    uint64_t        st_ino;
103
    uint64_t        st_size;
104
    uint64_t        st_blksize;
105
    uint64_t        st_blocks;
106
    njs_timespec_t  st_atim;
107
    njs_timespec_t  st_mtim;
108
    njs_timespec_t  st_ctim;
109
    njs_timespec_t  st_birthtim;
110
} njs_stat_t;
111
112
113
typedef enum {
114
    NJS_FS_STAT_DEV,
115
    NJS_FS_STAT_INO,
116
    NJS_FS_STAT_MODE,
117
    NJS_FS_STAT_NLINK,
118
    NJS_FS_STAT_UID,
119
    NJS_FS_STAT_GID,
120
    NJS_FS_STAT_RDEV,
121
    NJS_FS_STAT_SIZE,
122
    NJS_FS_STAT_BLKSIZE,
123
    NJS_FS_STAT_BLOCKS,
124
    NJS_FS_STAT_ATIME,
125
    NJS_FS_STAT_BIRTHTIME,
126
    NJS_FS_STAT_CTIME,
127
    NJS_FS_STAT_MTIME,
128
} njs_stat_prop_t;
129
130
131
typedef struct {
132
    njs_int_t       fd;
133
    njs_vm_t        *vm;
134
} njs_filehandle_t;
135
136
137
typedef struct {
138
    njs_int_t           bytes;
139
    njs_opaque_value_t  buffer;
140
} njs_bytes_struct_t;
141
142
143
typedef njs_int_t (*njs_file_tree_walk_cb_t)(const char *, const struct stat *,
144
     njs_ftw_type_t);
145
146
147
static njs_int_t njs_fs_access(njs_vm_t *vm, njs_value_t *args,
148
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
149
static njs_int_t njs_fs_exists_sync(njs_vm_t *vm, njs_value_t *args,
150
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
151
static njs_int_t njs_fs_mkdir(njs_vm_t *vm, njs_value_t *args,
152
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
153
static njs_int_t njs_fs_open(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
154
    njs_index_t calltype, njs_value_t *retval);
155
static njs_int_t njs_fs_close(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
156
    njs_index_t calltype, njs_value_t *retval);
157
static njs_int_t njs_fs_read(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
158
    njs_index_t calltype, njs_value_t *retval);
159
static njs_int_t njs_fs_read_file(njs_vm_t *vm, njs_value_t *args,
160
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
161
static njs_int_t njs_fs_readdir(njs_vm_t *vm, njs_value_t *args,
162
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
163
static njs_int_t njs_fs_readlink(njs_vm_t *vm, njs_value_t *args,
164
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
165
static njs_int_t njs_fs_realpath(njs_vm_t *vm, njs_value_t *args,
166
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
167
static njs_int_t njs_fs_rename(njs_vm_t *vm, njs_value_t *args,
168
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
169
static njs_int_t njs_fs_rmdir(njs_vm_t *vm, njs_value_t *args,
170
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
171
static njs_int_t njs_fs_stat(njs_vm_t *vm, njs_value_t *args,
172
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
173
static njs_int_t njs_fs_symlink(njs_vm_t *vm, njs_value_t *args,
174
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
175
static njs_int_t njs_fs_unlink(njs_vm_t *vm, njs_value_t *args,
176
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
177
static njs_int_t njs_fs_write(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
178
    njs_index_t calltype, njs_value_t *retval);
179
static njs_int_t njs_fs_write_file(njs_vm_t *vm, njs_value_t *args,
180
    njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
181
182
static njs_int_t njs_fs_constant(njs_vm_t *vm, njs_object_prop_t *prop,
183
    uint32_t unused, njs_value_t *value, njs_value_t *setval,
184
    njs_value_t *retval);
185
186
static njs_int_t njs_fs_dirent_constructor(njs_vm_t *vm, njs_value_t *args,
187
    njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
188
static njs_int_t njs_fs_dirent_test(njs_vm_t *vm, njs_value_t *args,
189
    njs_uint_t nargs, njs_index_t testtype, njs_value_t *retval);
190
191
static njs_int_t njs_fs_stats_test(njs_vm_t *vm, njs_value_t *args,
192
    njs_uint_t nargs, njs_index_t testtype, njs_value_t *retval);
193
static njs_int_t njs_fs_stats_prop(njs_vm_t *vm, njs_object_prop_t *prop,
194
    uint32_t unused, njs_value_t *value, njs_value_t *setval,
195
    njs_value_t *retval);
196
static njs_int_t njs_fs_stats_create(njs_vm_t *vm, struct stat *st,
197
    njs_value_t *retval);
198
199
static njs_int_t njs_fs_filehandle_close(njs_vm_t *vm, njs_value_t *args,
200
    njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
201
static njs_int_t njs_fs_filehandle_value_of(njs_vm_t *vm, njs_value_t *args,
202
    njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
203
static njs_int_t njs_fs_filehandle_create(njs_vm_t *vm, int fd,
204
    njs_bool_t shadow, njs_opaque_value_t *retval);
205
206
static njs_int_t njs_fs_bytes_read_create(njs_vm_t *vm, int bytes,
207
    njs_value_t *buffer, njs_opaque_value_t *retval);
208
static njs_int_t njs_fs_bytes_written_create(njs_vm_t *vm, int bytes,
209
    njs_value_t *buffer, njs_opaque_value_t *retval);
210
211
static njs_int_t njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data);
212
213
static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall,
214
    const char *desc, const char *path, int errn, njs_opaque_value_t *result);
215
static njs_int_t njs_fs_result(njs_vm_t *vm, njs_opaque_value_t *result,
216
    njs_index_t calltype, const njs_value_t* callback, njs_uint_t nargs,
217
    njs_value_t *retval);
218
219
static njs_int_t njs_file_tree_walk(const char *path,
220
    njs_file_tree_walk_cb_t cb, int fd_limit, njs_ftw_flags_t flags);
221
222
static njs_int_t njs_fs_make_path(njs_vm_t *vm, char *path, mode_t md,
223
    njs_bool_t recursive, njs_opaque_value_t *retval);
224
static njs_int_t njs_fs_rmtree(njs_vm_t *vm, const char *path,
225
    njs_bool_t recursive, njs_opaque_value_t *retval);
226
227
static const char *njs_fs_path(njs_vm_t *vm, char storage[NJS_MAX_PATH + 1],
228
    njs_value_t *src, const char *prop_name);
229
static int njs_fs_flags(njs_vm_t *vm, njs_value_t *value, int default_flags);
230
static mode_t njs_fs_mode(njs_vm_t *vm, njs_value_t *value,
231
    mode_t default_mode);
232
233
static njs_int_t njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name,
234
    njs_value_t *type, njs_value_t *retval);
235
236
237
static njs_int_t njs_fs_init(njs_vm_t *vm);
238
239
240
static const njs_str_t  string_flag = njs_str("flag");
241
static const njs_str_t  string_mode = njs_str("mode");
242
static const njs_str_t  string_buffer = njs_str("buffer");
243
static const njs_str_t  string_encoding = njs_str("encoding");
244
static const njs_str_t  string_recursive = njs_str("recursive");
245
246
247
static njs_fs_entry_t njs_flags_table[] = {
248
    { njs_str("a"),   O_APPEND | O_CREAT | O_WRONLY },
249
    { njs_str("a+"),  O_APPEND | O_CREAT | O_RDWR },
250
    { njs_str("as"),  O_APPEND | O_CREAT | O_SYNC | O_WRONLY },
251
    { njs_str("as+"), O_APPEND | O_CREAT | O_RDWR | O_SYNC },
252
    { njs_str("ax"),  O_APPEND | O_CREAT | O_EXCL | O_WRONLY },
253
    { njs_str("ax+"), O_APPEND | O_CREAT | O_EXCL | O_RDWR },
254
    { njs_str("r"),   O_RDONLY },
255
    { njs_str("r+"),  O_RDWR },
256
    { njs_str("rs+"), O_RDWR   | O_SYNC },
257
    { njs_str("w"),   O_CREAT  | O_TRUNC | O_WRONLY },
258
    { njs_str("w+"),  O_CREAT  | O_TRUNC | O_RDWR },
259
    { njs_str("wx"),  O_CREAT  | O_TRUNC | O_EXCL | O_WRONLY },
260
    { njs_str("wx+"), O_CREAT  | O_TRUNC | O_EXCL | O_RDWR },
261
    { njs_null_str, 0 }
262
};
263
264
265
static njs_external_t  njs_ext_fs_constants[] = {
266
267
    {
268
        .flags = NJS_EXTERN_PROPERTY,
269
        .name.string = njs_str("F_OK"),
270
        .enumerable = 1,
271
        .u.property = {
272
            .handler = njs_fs_constant,
273
            .magic32 = F_OK,
274
        }
275
    },
276
277
    {
278
        .flags = NJS_EXTERN_PROPERTY,
279
        .name.string = njs_str("R_OK"),
280
        .enumerable = 1,
281
        .u.property = {
282
            .handler = njs_fs_constant,
283
            .magic32 = R_OK,
284
        }
285
    },
286
287
    {
288
        .flags = NJS_EXTERN_PROPERTY,
289
        .name.string = njs_str("W_OK"),
290
        .enumerable = 1,
291
        .u.property = {
292
            .handler = njs_fs_constant,
293
            .magic32 = W_OK,
294
        }
295
    },
296
297
    {
298
        .flags = NJS_EXTERN_PROPERTY,
299
        .name.string = njs_str("X_OK"),
300
        .enumerable = 1,
301
        .u.property = {
302
            .handler = njs_fs_constant,
303
            .magic32 = X_OK,
304
        }
305
    },
306
307
};
308
309
310
static njs_external_t  njs_ext_fs_promises[] = {
311
312
    {
313
        .flags = NJS_EXTERN_METHOD,
314
        .name.string = njs_str("access"),
315
        .writable = 1,
316
        .configurable = 1,
317
        .u.method = {
318
            .native = njs_fs_access,
319
            .magic8 = NJS_FS_PROMISE,
320
        }
321
    },
322
323
    {
324
        .flags = NJS_EXTERN_METHOD,
325
        .name.string = njs_str("appendFile"),
326
        .writable = 1,
327
        .configurable = 1,
328
        .u.method = {
329
            .native = njs_fs_write_file,
330
            .magic8 = njs_fs_magic(NJS_FS_PROMISE, NJS_FS_APPEND),
331
        }
332
    },
333
334
    {
335
        .flags = NJS_EXTERN_METHOD,
336
        .name.string = njs_str("close"),
337
        .writable = 1,
338
        .configurable = 1,
339
        .u.method = {
340
            .native = njs_fs_close,
341
            .magic8 = NJS_FS_PROMISE,
342
        }
343
    },
344
345
    {
346
        .flags = NJS_EXTERN_METHOD,
347
        .name.string = njs_str("fstat"),
348
        .writable = 1,
349
        .configurable = 1,
350
        .u.method = {
351
            .native = njs_fs_stat,
352
            .magic8 = njs_fs_magic(NJS_FS_PROMISE, NJS_FS_FSTAT),
353
        }
354
    },
355
356
    {
357
        .flags = NJS_EXTERN_METHOD,
358
        .name.string = njs_str("mkdir"),
359
        .writable = 1,
360
        .configurable = 1,
361
        .u.method = {
362
            .native = njs_fs_mkdir,
363
            .magic8 = NJS_FS_PROMISE,
364
        }
365
    },
366
367
    {
368
        .flags = NJS_EXTERN_METHOD,
369
        .name.string = njs_str("lstat"),
370
        .writable = 1,
371
        .configurable = 1,
372
        .u.method = {
373
            .native = njs_fs_stat,
374
            .magic8 = njs_fs_magic(NJS_FS_PROMISE, NJS_FS_LSTAT),
375
        }
376
    },
377
378
    {
379
        .flags = NJS_EXTERN_METHOD,
380
        .name.string = njs_str("open"),
381
        .writable = 1,
382
        .configurable = 1,
383
        .u.method = {
384
            .native = njs_fs_open,
385
            .magic8 = NJS_FS_PROMISE,
386
        }
387
    },
388
389
    {
390
        .flags = NJS_EXTERN_METHOD,
391
        .name.string = njs_str("readFile"),
392
        .writable = 1,
393
        .configurable = 1,
394
        .u.method = {
395
            .native = njs_fs_read_file,
396
            .magic8 = NJS_FS_PROMISE,
397
        }
398
    },
399
400
    {
401
        .flags = NJS_EXTERN_METHOD,
402
        .name.string = njs_str("readdir"),
403
        .writable = 1,
404
        .configurable = 1,
405
        .u.method = {
406
            .native = njs_fs_readdir,
407
            .magic8 = NJS_FS_PROMISE,
408
        }
409
    },
410
411
    {
412
        .flags = NJS_EXTERN_METHOD,
413
        .name.string = njs_str("readlink"),
414
        .writable = 1,
415
        .configurable = 1,
416
        .u.method = {
417
            .native = njs_fs_readlink,
418
            .magic8 = NJS_FS_PROMISE,
419
        }
420
    },
421
422
    {
423
        .flags = NJS_EXTERN_METHOD,
424
        .name.string = njs_str("realpath"),
425
        .writable = 1,
426
        .configurable = 1,
427
        .u.method = {
428
            .native = njs_fs_realpath,
429
            .magic8 = NJS_FS_PROMISE,
430
        }
431
    },
432
433
    {
434
        .flags = NJS_EXTERN_METHOD,
435
        .name.string = njs_str("rename"),
436
        .writable = 1,
437
        .configurable = 1,
438
        .u.method = {
439
            .native = njs_fs_rename,
440
            .magic8 = NJS_FS_PROMISE,
441
        }
442
    },
443
444
    {
445
        .flags = NJS_EXTERN_METHOD,
446
        .name.string = njs_str("rmdir"),
447
        .writable = 1,
448
        .configurable = 1,
449
        .u.method = {
450
            .native = njs_fs_rmdir,
451
            .magic8 = NJS_FS_PROMISE,
452
        }
453
    },
454
455
    {
456
        .flags = NJS_EXTERN_METHOD,
457
        .name.string = njs_str("stat"),
458
        .writable = 1,
459
        .configurable = 1,
460
        .u.method = {
461
            .native = njs_fs_stat,
462
            .magic8 = njs_fs_magic(NJS_FS_PROMISE, NJS_FS_STAT),
463
        }
464
    },
465
466
    {
467
        .flags = NJS_EXTERN_METHOD,
468
        .name.string = njs_str("symlink"),
469
        .writable = 1,
470
        .configurable = 1,
471
        .u.method = {
472
            .native = njs_fs_symlink,
473
            .magic8 = NJS_FS_PROMISE,
474
        }
475
    },
476
477
    {
478
        .flags = NJS_EXTERN_METHOD,
479
        .name.string = njs_str("unlink"),
480
        .writable = 1,
481
        .configurable = 1,
482
        .u.method = {
483
            .native = njs_fs_unlink,
484
            .magic8 = NJS_FS_PROMISE,
485
        }
486
    },
487
488
    {
489
        .flags = NJS_EXTERN_METHOD,
490
        .name.string = njs_str("writeFile"),
491
        .writable = 1,
492
        .configurable = 1,
493
        .u.method = {
494
            .native = njs_fs_write_file,
495
            .magic8 = njs_fs_magic(NJS_FS_PROMISE, NJS_FS_TRUNC),
496
        }
497
    },
498
499
};
500
501
502
static njs_external_t  njs_ext_fs[] = {
503
504
    {
505
        .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
506
        .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
507
        .u.property = {
508
            .value = "fs",
509
        }
510
    },
511
512
    {
513
        .flags = NJS_EXTERN_METHOD,
514
        .name.string = njs_str("access"),
515
        .writable = 1,
516
        .configurable = 1,
517
        .u.method = {
518
            .native = njs_fs_access,
519
            .magic8 = NJS_FS_CALLBACK,
520
        }
521
    },
522
523
    {
524
        .flags = NJS_EXTERN_METHOD,
525
        .name.string = njs_str("accessSync"),
526
        .writable = 1,
527
        .configurable = 1,
528
        .u.method = {
529
            .native = njs_fs_access,
530
            .magic8 = NJS_FS_DIRECT,
531
        }
532
    },
533
534
    {
535
        .flags = NJS_EXTERN_METHOD,
536
        .name.string = njs_str("appendFile"),
537
        .writable = 1,
538
        .configurable = 1,
539
        .u.method = {
540
            .native = njs_fs_write_file,
541
            .magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_APPEND),
542
        }
543
    },
544
545
    {
546
        .flags = NJS_EXTERN_METHOD,
547
        .name.string = njs_str("appendFileSync"),
548
        .writable = 1,
549
        .configurable = 1,
550
        .u.method = {
551
            .native = njs_fs_write_file,
552
            .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_APPEND),
553
        }
554
    },
555
556
    {
557
        .flags = NJS_EXTERN_METHOD,
558
        .name.string = njs_str("closeSync"),
559
        .writable = 1,
560
        .configurable = 1,
561
        .u.method = {
562
            .native = njs_fs_close,
563
            .magic8 = NJS_FS_DIRECT,
564
        }
565
    },
566
567
    {
568
        .flags = NJS_EXTERN_OBJECT,
569
        .name.string = njs_str("constants"),
570
        .writable = 1,
571
        .enumerable = 1,
572
        .configurable = 1,
573
        .u.object = {
574
            .properties = njs_ext_fs_constants,
575
            .nproperties = njs_nitems(njs_ext_fs_constants),
576
        }
577
    },
578
579
    {
580
        .flags = NJS_EXTERN_METHOD,
581
        .name.string = njs_str("Dirent"),
582
        .writable = 1,
583
        .configurable = 1,
584
        .u.method = {
585
            .native = njs_fs_dirent_constructor,
586
            .ctor = 1,
587
        }
588
    },
589
590
    {
591
        .flags = NJS_EXTERN_METHOD,
592
        .name.string = njs_str("existsSync"),
593
        .writable = 1,
594
        .configurable = 1,
595
        .u.method = {
596
            .native = njs_fs_exists_sync,
597
        }
598
    },
599
600
    {
601
        .flags = NJS_EXTERN_METHOD,
602
        .name.string = njs_str("fstatSync"),
603
        .writable = 1,
604
        .configurable = 1,
605
        .u.method = {
606
            .native = njs_fs_stat,
607
            .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_FSTAT),
608
        }
609
    },
610
611
    {
612
        .flags = NJS_EXTERN_METHOD,
613
        .name.string = njs_str("lstat"),
614
        .writable = 1,
615
        .configurable = 1,
616
        .u.method = {
617
            .native = njs_fs_stat,
618
            .magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_LSTAT),
619
        }
620
    },
621
622
    {
623
        .flags = NJS_EXTERN_METHOD,
624
        .name.string = njs_str("lstatSync"),
625
        .writable = 1,
626
        .configurable = 1,
627
        .u.method = {
628
            .native = njs_fs_stat,
629
            .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_LSTAT),
630
        }
631
    },
632
633
    {
634
        .flags = NJS_EXTERN_METHOD,
635
        .name.string = njs_str("mkdir"),
636
        .writable = 1,
637
        .configurable = 1,
638
        .u.method = {
639
            .native = njs_fs_mkdir,
640
            .magic8 = NJS_FS_CALLBACK,
641
        }
642
    },
643
644
    {
645
        .flags = NJS_EXTERN_METHOD,
646
        .name.string = njs_str("mkdirSync"),
647
        .writable = 1,
648
        .configurable = 1,
649
        .u.method = {
650
            .native = njs_fs_mkdir,
651
            .magic8 = NJS_FS_DIRECT,
652
        }
653
    },
654
655
    {
656
        .flags = NJS_EXTERN_METHOD,
657
        .name.string = njs_str("openSync"),
658
        .writable = 1,
659
        .configurable = 1,
660
        .u.method = {
661
            .native = njs_fs_open,
662
            .magic8 = NJS_FS_DIRECT,
663
        }
664
    },
665
666
    {
667
        .flags = NJS_EXTERN_OBJECT,
668
        .name.string = njs_str("promises"),
669
        .writable = 1,
670
        .enumerable = 1,
671
        .configurable = 1,
672
        .u.object = {
673
            .properties = njs_ext_fs_promises,
674
            .nproperties = njs_nitems(njs_ext_fs_promises),
675
        }
676
    },
677
678
    {
679
        .flags = NJS_EXTERN_METHOD,
680
        .name.string = njs_str("readdir"),
681
        .writable = 1,
682
        .configurable = 1,
683
        .u.method = {
684
            .native = njs_fs_readdir,
685
            .magic8 = NJS_FS_CALLBACK,
686
        }
687
    },
688
689
    {
690
        .flags = NJS_EXTERN_METHOD,
691
        .name.string = njs_str("readdirSync"),
692
        .writable = 1,
693
        .configurable = 1,
694
        .u.method = {
695
            .native = njs_fs_readdir,
696
            .magic8 = NJS_FS_DIRECT,
697
        }
698
    },
699
700
    {
701
        .flags = NJS_EXTERN_METHOD,
702
        .name.string = njs_str("readFile"),
703
        .writable = 1,
704
        .configurable = 1,
705
        .u.method = {
706
            .native = njs_fs_read_file,
707
            .magic8 = NJS_FS_CALLBACK,
708
        }
709
    },
710
711
    {
712
        .flags = NJS_EXTERN_METHOD,
713
        .name.string = njs_str("readFileSync"),
714
        .writable = 1,
715
        .configurable = 1,
716
        .u.method = {
717
            .native = njs_fs_read_file,
718
            .magic8 = NJS_FS_DIRECT,
719
        }
720
    },
721
722
    {
723
        .flags = NJS_EXTERN_METHOD,
724
        .name.string = njs_str("readSync"),
725
        .writable = 1,
726
        .configurable = 1,
727
        .u.method = {
728
            .native = njs_fs_read,
729
            .magic8 = NJS_FS_DIRECT,
730
        }
731
    },
732
733
    {
734
        .flags = NJS_EXTERN_METHOD,
735
        .name.string = njs_str("readlink"),
736
        .writable = 1,
737
        .configurable = 1,
738
        .u.method = {
739
            .native = njs_fs_readlink,
740
            .magic8 = NJS_FS_CALLBACK,
741
        }
742
    },
743
744
    {
745
        .flags = NJS_EXTERN_METHOD,
746
        .name.string = njs_str("readlinkSync"),
747
        .writable = 1,
748
        .configurable = 1,
749
        .u.method = {
750
            .native = njs_fs_readlink,
751
            .magic8 = NJS_FS_DIRECT,
752
        }
753
    },
754
755
    {
756
        .flags = NJS_EXTERN_METHOD,
757
        .name.string = njs_str("realpath"),
758
        .writable = 1,
759
        .configurable = 1,
760
        .u.method = {
761
            .native = njs_fs_realpath,
762
            .magic8 = NJS_FS_CALLBACK,
763
        }
764
    },
765
766
    {
767
        .flags = NJS_EXTERN_METHOD,
768
        .name.string = njs_str("realpathSync"),
769
        .writable = 1,
770
        .configurable = 1,
771
        .u.method = {
772
            .native = njs_fs_realpath,
773
            .magic8 = NJS_FS_DIRECT,
774
        }
775
    },
776
777
    {
778
        .flags = NJS_EXTERN_METHOD,
779
        .name.string = njs_str("rename"),
780
        .writable = 1,
781
        .configurable = 1,
782
        .u.method = {
783
            .native = njs_fs_rename,
784
            .magic8 = NJS_FS_CALLBACK,
785
        }
786
    },
787
788
    {
789
        .flags = NJS_EXTERN_METHOD,
790
        .name.string = njs_str("renameSync"),
791
        .writable = 1,
792
        .configurable = 1,
793
        .u.method = {
794
            .native = njs_fs_rename,
795
            .magic8 = NJS_FS_DIRECT,
796
        }
797
    },
798
799
    {
800
        .flags = NJS_EXTERN_METHOD,
801
        .name.string = njs_str("rmdir"),
802
        .writable = 1,
803
        .configurable = 1,
804
        .u.method = {
805
            .native = njs_fs_rmdir,
806
            .magic8 = NJS_FS_CALLBACK,
807
        }
808
    },
809
810
    {
811
        .flags = NJS_EXTERN_METHOD,
812
        .name.string = njs_str("rmdirSync"),
813
        .writable = 1,
814
        .configurable = 1,
815
        .u.method = {
816
            .native = njs_fs_rmdir,
817
            .magic8 = NJS_FS_DIRECT,
818
        }
819
    },
820
821
    {
822
        .flags = NJS_EXTERN_METHOD,
823
        .name.string = njs_str("stat"),
824
        .writable = 1,
825
        .configurable = 1,
826
        .u.method = {
827
            .native = njs_fs_stat,
828
            .magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_STAT),
829
        }
830
    },
831
832
    {
833
        .flags = NJS_EXTERN_METHOD,
834
        .name.string = njs_str("statSync"),
835
        .writable = 1,
836
        .configurable = 1,
837
        .u.method = {
838
            .native = njs_fs_stat,
839
            .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_STAT),
840
        }
841
    },
842
843
    {
844
        .flags = NJS_EXTERN_METHOD,
845
        .name.string = njs_str("symlink"),
846
        .writable = 1,
847
        .configurable = 1,
848
        .u.method = {
849
            .native = njs_fs_symlink,
850
            .magic8 = NJS_FS_CALLBACK,
851
        }
852
    },
853
854
    {
855
        .flags = NJS_EXTERN_METHOD,
856
        .name.string = njs_str("symlinkSync"),
857
        .writable = 1,
858
        .configurable = 1,
859
        .u.method = {
860
            .native = njs_fs_symlink,
861
            .magic8 = NJS_FS_DIRECT,
862
        }
863
    },
864
865
    {
866
        .flags = NJS_EXTERN_METHOD,
867
        .name.string = njs_str("unlink"),
868
        .writable = 1,
869
        .configurable = 1,
870
        .u.method = {
871
            .native = njs_fs_unlink,
872
            .magic8 = NJS_FS_CALLBACK,
873
        }
874
    },
875
876
    {
877
        .flags = NJS_EXTERN_METHOD,
878
        .name.string = njs_str("unlinkSync"),
879
        .writable = 1,
880
        .configurable = 1,
881
        .u.method = {
882
            .native = njs_fs_unlink,
883
            .magic8 = NJS_FS_DIRECT,
884
        }
885
    },
886
887
    {
888
        .flags = NJS_EXTERN_METHOD,
889
        .name.string = njs_str("writeFile"),
890
        .writable = 1,
891
        .configurable = 1,
892
        .u.method = {
893
            .native = njs_fs_write_file,
894
            .magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_TRUNC),
895
        }
896
    },
897
898
    {
899
        .flags = NJS_EXTERN_METHOD,
900
        .name.string = njs_str("writeFileSync"),
901
        .writable = 1,
902
        .configurable = 1,
903
        .u.method = {
904
            .native = njs_fs_write_file,
905
            .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_TRUNC),
906
        }
907
    },
908
909
    {
910
        .flags = NJS_EXTERN_METHOD,
911
        .name.string = njs_str("writeSync"),
912
        .writable = 1,
913
        .configurable = 1,
914
        .u.method = {
915
            .native = njs_fs_write,
916
            .magic8 = NJS_FS_DIRECT,
917
        }
918
    },
919
920
};
921
922
923
static njs_external_t  njs_ext_dirent[] = {
924
925
    {
926
        .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
927
        .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
928
        .u.property = {
929
            .value = "Dirent",
930
        }
931
    },
932
933
    {
934
        .flags = NJS_EXTERN_METHOD,
935
        .name.string = njs_str("constructor"),
936
        .writable = 1,
937
        .configurable = 1,
938
        .u.method = {
939
            .native = njs_fs_dirent_constructor,
940
        }
941
    },
942
943
    {
944
        .flags = NJS_EXTERN_METHOD,
945
        .name.string = njs_str("isBlockDevice"),
946
        .writable = 1,
947
        .configurable = 1,
948
        .u.method = {
949
            .native = njs_fs_dirent_test,
950
            .magic8 = DT_BLK,
951
        }
952
    },
953
954
    {
955
        .flags = NJS_EXTERN_METHOD,
956
        .name.string = njs_str("isCharacterDevice"),
957
        .writable = 1,
958
        .configurable = 1,
959
        .u.method = {
960
            .native = njs_fs_dirent_test,
961
            .magic8 = DT_CHR,
962
        }
963
    },
964
965
    {
966
        .flags = NJS_EXTERN_METHOD,
967
        .name.string = njs_str("isDirectory"),
968
        .writable = 1,
969
        .configurable = 1,
970
        .u.method = {
971
            .native = njs_fs_dirent_test,
972
            .magic8 = DT_DIR,
973
        }
974
    },
975
976
    {
977
        .flags = NJS_EXTERN_METHOD,
978
        .name.string = njs_str("isFIFO"),
979
        .writable = 1,
980
        .configurable = 1,
981
        .u.method = {
982
            .native = njs_fs_dirent_test,
983
            .magic8 = DT_FIFO,
984
        }
985
    },
986
987
    {
988
        .flags = NJS_EXTERN_METHOD,
989
        .name.string = njs_str("isFile"),
990
        .writable = 1,
991
        .configurable = 1,
992
        .u.method = {
993
            .native = njs_fs_dirent_test,
994
            .magic8 = DT_REG,
995
        }
996
    },
997
998
    {
999
        .flags = NJS_EXTERN_METHOD,
1000
        .name.string = njs_str("isSocket"),
1001
        .writable = 1,
1002
        .configurable = 1,
1003
        .u.method = {
1004
            .native = njs_fs_dirent_test,
1005
            .magic8 = DT_SOCK,
1006
        }
1007
    },
1008
1009
    {
1010
        .flags = NJS_EXTERN_METHOD,
1011
        .name.string = njs_str("isSymbolicLink"),
1012
        .writable = 1,
1013
        .configurable = 1,
1014
        .u.method = {
1015
            .native = njs_fs_dirent_test,
1016
            .magic8 = DT_LNK,
1017
        }
1018
    },
1019
};
1020
1021
1022
static njs_external_t  njs_ext_stats[] = {
1023
1024
    {
1025
        .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
1026
        .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
1027
        .u.property = {
1028
            .value = "Stats",
1029
        }
1030
    },
1031
1032
    {
1033
        .flags = NJS_EXTERN_PROPERTY,
1034
        .name.string = njs_str("atime"),
1035
        .enumerable = 1,
1036
        .u.property = {
1037
            .handler = njs_fs_stats_prop,
1038
            .magic32 = njs_fs_magic2(NJS_FS_STAT_ATIME, 1),
1039
        }
1040
    },
1041
1042
    {
1043
        .flags = NJS_EXTERN_PROPERTY,
1044
        .name.string = njs_str("atimeMs"),
1045
        .enumerable = 1,
1046
        .u.property = {
1047
            .handler = njs_fs_stats_prop,
1048
            .magic32 = njs_fs_magic2(NJS_FS_STAT_ATIME, 0),
1049
        }
1050
    },
1051
1052
    {
1053
        .flags = NJS_EXTERN_PROPERTY,
1054
        .name.string = njs_str("birthtime"),
1055
        .enumerable = 1,
1056
        .u.property = {
1057
            .handler = njs_fs_stats_prop,
1058
            .magic32 = njs_fs_magic2(NJS_FS_STAT_BIRTHTIME, 1),
1059
        }
1060
    },
1061
1062
    {
1063
        .flags = NJS_EXTERN_PROPERTY,
1064
        .name.string = njs_str("birthtimeMs"),
1065
        .enumerable = 1,
1066
        .u.property = {
1067
            .handler = njs_fs_stats_prop,
1068
            .magic32 = njs_fs_magic2(NJS_FS_STAT_BIRTHTIME, 0),
1069
        }
1070
    },
1071
1072
    {
1073
        .flags = NJS_EXTERN_PROPERTY,
1074
        .name.string = njs_str("ctime"),
1075
        .enumerable = 1,
1076
        .u.property = {
1077
            .handler = njs_fs_stats_prop,
1078
            .magic32 = njs_fs_magic2(NJS_FS_STAT_CTIME, 1),
1079
        }
1080
    },
1081
1082
    {
1083
        .flags = NJS_EXTERN_PROPERTY,
1084
        .name.string = njs_str("ctimeMs"),
1085
        .enumerable = 1,
1086
        .u.property = {
1087
            .handler = njs_fs_stats_prop,
1088
            .magic32 = njs_fs_magic2(NJS_FS_STAT_CTIME, 0),
1089
        }
1090
    },
1091
1092
    {
1093
        .flags = NJS_EXTERN_PROPERTY,
1094
        .name.string = njs_str("blksize"),
1095
        .enumerable = 1,
1096
        .u.property = {
1097
            .handler = njs_fs_stats_prop,
1098
            .magic32 = njs_fs_magic2(NJS_FS_STAT_BLKSIZE, 0),
1099
        }
1100
    },
1101
1102
    {
1103
        .flags = NJS_EXTERN_PROPERTY,
1104
        .name.string = njs_str("blocks"),
1105
        .enumerable = 1,
1106
        .u.property = {
1107
            .handler = njs_fs_stats_prop,
1108
            .magic32 = njs_fs_magic2(NJS_FS_STAT_BLOCKS, 0),
1109
        }
1110
    },
1111
1112
    {
1113
        .flags = NJS_EXTERN_PROPERTY,
1114
        .name.string = njs_str("dev"),
1115
        .enumerable = 1,
1116
        .u.property = {
1117
            .handler = njs_fs_stats_prop,
1118
            .magic32 = njs_fs_magic2(NJS_FS_STAT_DEV, 0),
1119
        }
1120
    },
1121
1122
    {
1123
        .flags = NJS_EXTERN_PROPERTY,
1124
        .name.string = njs_str("gid"),
1125
        .enumerable = 1,
1126
        .u.property = {
1127
            .handler = njs_fs_stats_prop,
1128
            .magic32 = njs_fs_magic2(NJS_FS_STAT_GID, 0),
1129
        }
1130
    },
1131
1132
    {
1133
        .flags = NJS_EXTERN_PROPERTY,
1134
        .name.string = njs_str("ino"),
1135
        .enumerable = 1,
1136
        .u.property = {
1137
            .handler = njs_fs_stats_prop,
1138
            .magic32 = njs_fs_magic2(NJS_FS_STAT_INO, 0),
1139
        }
1140
    },
1141
1142
    {
1143
        .flags = NJS_EXTERN_PROPERTY,
1144
        .name.string = njs_str("mode"),
1145
        .enumerable = 1,
1146
        .u.property = {
1147
            .handler = njs_fs_stats_prop,
1148
            .magic32 = njs_fs_magic2(NJS_FS_STAT_MODE, 0),
1149
        }
1150
    },
1151
1152
    {
1153
        .flags = NJS_EXTERN_PROPERTY,
1154
        .name.string = njs_str("mtime"),
1155
        .enumerable = 1,
1156
        .u.property = {
1157
            .handler = njs_fs_stats_prop,
1158
            .magic32 = njs_fs_magic2(NJS_FS_STAT_MTIME, 1),
1159
        }
1160
    },
1161
1162
    {
1163
        .flags = NJS_EXTERN_PROPERTY,
1164
        .name.string = njs_str("mtimeMs"),
1165
        .enumerable = 1,
1166
        .u.property = {
1167
            .handler = njs_fs_stats_prop,
1168
            .magic32 = njs_fs_magic2(NJS_FS_STAT_MTIME, 0),
1169
        }
1170
    },
1171
1172
    {
1173
        .flags = NJS_EXTERN_PROPERTY,
1174
        .name.string = njs_str("nlink"),
1175
        .enumerable = 1,
1176
        .u.property = {
1177
            .handler = njs_fs_stats_prop,
1178
            .magic32 = njs_fs_magic2(NJS_FS_STAT_NLINK, 0),
1179
        }
1180
    },
1181
1182
    {
1183
        .flags = NJS_EXTERN_PROPERTY,
1184
        .name.string = njs_str("rdev"),
1185
        .enumerable = 1,
1186
        .u.property = {
1187
            .handler = njs_fs_stats_prop,
1188
            .magic32 = njs_fs_magic2(NJS_FS_STAT_RDEV, 0),
1189
        }
1190
    },
1191
1192
    {
1193
        .flags = NJS_EXTERN_PROPERTY,
1194
        .name.string = njs_str("size"),
1195
        .enumerable = 1,
1196
        .u.property = {
1197
            .handler = njs_fs_stats_prop,
1198
            .magic32 = njs_fs_magic2(NJS_FS_STAT_SIZE, 0),
1199
        }
1200
    },
1201
1202
    {
1203
        .flags = NJS_EXTERN_PROPERTY,
1204
        .name.string = njs_str("uid"),
1205
        .enumerable = 1,
1206
        .u.property = {
1207
            .handler = njs_fs_stats_prop,
1208
            .magic32 = njs_fs_magic2(NJS_FS_STAT_UID, 0),
1209
        }
1210
    },
1211
1212
    {
1213
        .flags = NJS_EXTERN_METHOD,
1214
        .name.string = njs_str("isBlockDevice"),
1215
        .writable = 1,
1216
        .configurable = 1,
1217
        .u.method = {
1218
            .native = njs_fs_stats_test,
1219
            .magic8 = DT_BLK,
1220
        }
1221
    },
1222
1223
    {
1224
        .flags = NJS_EXTERN_METHOD,
1225
        .name.string = njs_str("isCharacterDevice"),
1226
        .writable = 1,
1227
        .configurable = 1,
1228
        .u.method = {
1229
            .native = njs_fs_stats_test,
1230
            .magic8 = DT_CHR,
1231
        }
1232
    },
1233
1234
    {
1235
        .flags = NJS_EXTERN_METHOD,
1236
        .name.string = njs_str("isDirectory"),
1237
        .writable = 1,
1238
        .configurable = 1,
1239
        .u.method = {
1240
            .native = njs_fs_stats_test,
1241
            .magic8 = DT_DIR,
1242
        }
1243
    },
1244
1245
    {
1246
        .flags = NJS_EXTERN_METHOD,
1247
        .name.string = njs_str("isFIFO"),
1248
        .writable = 1,
1249
        .configurable = 1,
1250
        .u.method = {
1251
            .native = njs_fs_stats_test,
1252
            .magic8 = DT_FIFO,
1253
        }
1254
    },
1255
1256
    {
1257
        .flags = NJS_EXTERN_METHOD,
1258
        .name.string = njs_str("isFile"),
1259
        .writable = 1,
1260
        .configurable = 1,
1261
        .u.method = {
1262
            .native = njs_fs_stats_test,
1263
            .magic8 = DT_REG,
1264
        }
1265
    },
1266
1267
    {
1268
        .flags = NJS_EXTERN_METHOD,
1269
        .name.string = njs_str("isSocket"),
1270
        .writable = 1,
1271
        .configurable = 1,
1272
        .u.method = {
1273
            .native = njs_fs_stats_test,
1274
            .magic8 = DT_SOCK,
1275
        }
1276
    },
1277
1278
    {
1279
        .flags = NJS_EXTERN_METHOD,
1280
        .name.string = njs_str("isSymbolicLink"),
1281
        .writable = 1,
1282
        .configurable = 1,
1283
        .u.method = {
1284
            .native = njs_fs_stats_test,
1285
            .magic8 = DT_LNK,
1286
        }
1287
    },
1288
1289
};
1290
1291
1292
static njs_external_t  njs_ext_filehandle[] = {
1293
1294
    {
1295
        .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
1296
        .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
1297
        .u.property = {
1298
            .value = "FileHandle",
1299
        }
1300
    },
1301
1302
    {
1303
        .flags = NJS_EXTERN_METHOD,
1304
        .name.string = njs_str("close"),
1305
        .writable = 1,
1306
        .configurable = 1,
1307
        .u.method = {
1308
            .native = njs_fs_filehandle_close,
1309
        }
1310
    },
1311
1312
    {
1313
        .flags = NJS_EXTERN_PROPERTY,
1314
        .name.string = njs_str("fd"),
1315
        .enumerable = 1,
1316
        .u.property = {
1317
            .handler = njs_external_property,
1318
            .magic32 = offsetof(njs_filehandle_t, fd),
1319
            .magic16 = NJS_EXTERN_TYPE_INT,
1320
        }
1321
    },
1322
1323
    {
1324
        .flags = NJS_EXTERN_METHOD,
1325
        .name.string = njs_str("read"),
1326
        .writable = 1,
1327
        .configurable = 1,
1328
        .u.method = {
1329
            .native = njs_fs_read,
1330
            .magic8 = NJS_FS_PROMISE,
1331
        }
1332
    },
1333
1334
    {
1335
        .flags = NJS_EXTERN_METHOD,
1336
        .name.string = njs_str("stat"),
1337
        .writable = 1,
1338
        .configurable = 1,
1339
        .u.method = {
1340
            .native = njs_fs_stat,
1341
            .magic8 = njs_fs_magic(NJS_FS_PROMISE, NJS_FS_FSTAT),
1342
        }
1343
    },
1344
1345
    {
1346
        .flags = NJS_EXTERN_METHOD,
1347
        .name.string = njs_str("valueOf"),
1348
        .writable = 1,
1349
        .configurable = 1,
1350
        .u.method = {
1351
            .native = njs_fs_filehandle_value_of,
1352
        }
1353
    },
1354
1355
    {
1356
        .flags = NJS_EXTERN_METHOD,
1357
        .name.string = njs_str("write"),
1358
        .writable = 1,
1359
        .configurable = 1,
1360
        .u.method = {
1361
            .native = njs_fs_write,
1362
            .magic8 = NJS_FS_PROMISE,
1363
        }
1364
    },
1365
1366
};
1367
1368
1369
static njs_external_t  njs_ext_bytes_read[] = {
1370
1371
    {
1372
        .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
1373
        .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
1374
        .u.property = {
1375
            .value = "BytesRead",
1376
        }
1377
    },
1378
1379
    {
1380
        .flags = NJS_EXTERN_PROPERTY,
1381
        .name.string = njs_str("buffer"),
1382
        .enumerable = 1,
1383
        .u.property = {
1384
            .handler = njs_external_property,
1385
            .magic32 = offsetof(njs_bytes_struct_t, buffer),
1386
            .magic16 = NJS_EXTERN_TYPE_VALUE,
1387
        }
1388
    },
1389
1390
    {
1391
        .flags = NJS_EXTERN_PROPERTY,
1392
        .name.string = njs_str("bytesRead"),
1393
        .enumerable = 1,
1394
        .u.property = {
1395
            .handler = njs_external_property,
1396
            .magic32 = offsetof(njs_bytes_struct_t, bytes),
1397
            .magic16 = NJS_EXTERN_TYPE_INT,
1398
        }
1399
    },
1400
1401
};
1402
1403
1404
static njs_external_t  njs_ext_bytes_written[] = {
1405
1406
    {
1407
        .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
1408
        .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
1409
        .u.property = {
1410
            .value = "BytesWritten",
1411
        }
1412
    },
1413
1414
    {
1415
        .flags = NJS_EXTERN_PROPERTY,
1416
        .name.string = njs_str("buffer"),
1417
        .enumerable = 1,
1418
        .u.property = {
1419
            .handler = njs_external_property,
1420
            .magic32 = offsetof(njs_bytes_struct_t, buffer),
1421
            .magic16 = NJS_EXTERN_TYPE_VALUE,
1422
        }
1423
    },
1424
1425
    {
1426
        .flags = NJS_EXTERN_PROPERTY,
1427
        .name.string = njs_str("bytesWritten"),
1428
        .enumerable = 1,
1429
        .u.property = {
1430
            .handler = njs_external_property,
1431
            .magic32 = offsetof(njs_bytes_struct_t, bytes),
1432
            .magic16 = NJS_EXTERN_TYPE_INT,
1433
        }
1434
    },
1435
1436
};
1437
1438
1439
static njs_int_t    njs_fs_stats_proto_id;
1440
static njs_int_t    njs_fs_dirent_proto_id;
1441
static njs_int_t    njs_fs_filehandle_proto_id;
1442
static njs_int_t    njs_fs_bytes_read_proto_id;
1443
static njs_int_t    njs_fs_bytes_written_proto_id;
1444
1445
1446
njs_module_t  njs_fs_module = {
1447
    .name = njs_str("fs"),
1448
    .preinit = NULL,
1449
    .init = njs_fs_init,
1450
};
1451
1452
1453
static njs_int_t
1454
njs_fs_access(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
1455
    njs_index_t calltype, njs_value_t *retval)
1456
0
{
1457
0
    int                 md;
1458
0
    njs_int_t           ret;
1459
0
    const char          *path;
1460
0
    njs_value_t         *callback, *mode;
1461
0
    njs_opaque_value_t  result;
1462
0
    char                path_buf[NJS_MAX_PATH + 1];
1463
1464
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
1465
0
    if (njs_slow_path(path == NULL)) {
1466
0
        return NJS_ERROR;
1467
0
    }
1468
1469
0
    callback = NULL;
1470
0
    mode = njs_arg(args, nargs, 2);
1471
1472
0
    if (calltype == NJS_FS_CALLBACK) {
1473
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
1474
0
        if (!njs_value_is_function(callback)) {
1475
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
1476
0
            return NJS_ERROR;
1477
0
        }
1478
1479
0
        if (mode == callback) {
1480
0
            mode = njs_value_arg(&njs_value_undefined);
1481
0
        }
1482
0
    }
1483
1484
0
    if (njs_value_is_number(mode)) {
1485
0
        md = njs_value_number(mode);
1486
1487
0
    } else if (njs_value_is_undefined(mode)) {
1488
0
        md = F_OK;
1489
1490
0
    } else {
1491
0
        njs_vm_type_error(vm, "\"mode\" must be a number");
1492
0
        return NJS_ERROR;
1493
0
    }
1494
1495
0
    njs_value_undefined_set(njs_value_arg(&result));
1496
1497
0
    ret = access(path, md);
1498
0
    if (njs_slow_path(ret != 0)) {
1499
0
        ret = njs_fs_error(vm, "access", strerror(errno), path, errno, &result);
1500
0
    }
1501
1502
0
    if (ret == NJS_OK) {
1503
0
        return njs_fs_result(vm, &result, calltype, callback, 1, retval);
1504
0
    }
1505
1506
0
    return NJS_ERROR;
1507
0
}
1508
1509
1510
static njs_int_t
1511
njs_fs_exists_sync(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
1512
    njs_index_t calltype, njs_value_t *retval)
1513
0
{
1514
0
    const char  *path;
1515
0
    char        path_buf[NJS_MAX_PATH + 1];
1516
1517
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
1518
0
    if (njs_slow_path(path == NULL)) {
1519
0
        return NJS_ERROR;
1520
0
    }
1521
1522
0
    njs_value_boolean_set(retval, access(path, F_OK) == 0);
1523
1524
0
    return NJS_OK;
1525
0
}
1526
1527
1528
static njs_int_t
1529
njs_fs_open(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
1530
    njs_index_t calltype, njs_value_t *retval)
1531
0
{
1532
0
    int                 fd, flags;
1533
0
    mode_t              md;
1534
0
    njs_int_t           ret;
1535
0
    const char          *path;
1536
0
    njs_value_t         *value;
1537
0
    njs_opaque_value_t  result;
1538
0
    char                path_buf[NJS_MAX_PATH + 1];
1539
1540
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
1541
0
    if (njs_slow_path(path == NULL)) {
1542
0
        return NJS_ERROR;
1543
0
    }
1544
1545
0
    value = njs_arg(args, nargs, 2);
1546
0
    if (njs_value_is_function(value)) {
1547
0
        value = njs_value_arg(&njs_value_undefined);
1548
0
    }
1549
1550
0
    flags = njs_fs_flags(vm, value, O_RDONLY);
1551
0
    if (njs_slow_path(flags == -1)) {
1552
0
        return NJS_ERROR;
1553
0
    }
1554
1555
0
    value = njs_arg(args, nargs, 3);
1556
0
    if (njs_value_is_function(value)) {
1557
0
        value = njs_value_arg(&njs_value_undefined);
1558
0
    }
1559
1560
0
    md = njs_fs_mode(vm, value, 0666);
1561
0
    if (njs_slow_path(md == (mode_t) -1)) {
1562
0
        return NJS_ERROR;
1563
0
    }
1564
1565
0
    fd = open(path, flags, md);
1566
0
    if (njs_slow_path(fd < 0)) {
1567
0
        ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &result);
1568
0
        goto done;
1569
0
    }
1570
1571
0
    ret = njs_fs_filehandle_create(vm, fd, calltype == NJS_FS_DIRECT, &result);
1572
0
    if (njs_slow_path(ret != NJS_OK)) {
1573
0
        goto done;
1574
0
    }
1575
1576
0
    if (calltype == NJS_FS_DIRECT) {
1577
0
        njs_value_number_set(njs_value_arg(&result), fd);
1578
0
    }
1579
1580
0
done:
1581
1582
0
    if (ret == NJS_OK) {
1583
0
        return njs_fs_result(vm, &result, calltype, NULL, 2, retval);
1584
0
    }
1585
1586
0
    if (fd != -1) {
1587
0
        (void) close(fd);
1588
0
    }
1589
1590
0
    return NJS_ERROR;
1591
0
}
1592
1593
1594
static njs_int_t
1595
njs_fs_close(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
1596
    njs_index_t calltype, njs_value_t *retval)
1597
0
{
1598
0
    int64_t             fd;
1599
0
    njs_int_t           ret;
1600
0
    njs_value_t         *fh;
1601
0
    njs_opaque_value_t  result;
1602
1603
0
    fh = njs_arg(args, nargs, 1);
1604
1605
0
    ret = njs_value_to_integer(vm, fh, &fd);
1606
0
    if (njs_slow_path(ret != NJS_OK)) {
1607
0
        return ret;
1608
0
    }
1609
1610
0
    njs_value_undefined_set(njs_value_arg(&result));
1611
1612
0
    ret = close((int) fd);
1613
0
    if (njs_slow_path(ret != 0)) {
1614
0
        ret = njs_fs_error(vm, "close", strerror(errno), NULL, errno, &result);
1615
0
    }
1616
1617
0
    if (ret == NJS_OK) {
1618
0
        return njs_fs_result(vm, &result, calltype, NULL, 1, retval);
1619
0
    }
1620
1621
0
    return NJS_ERROR;
1622
0
}
1623
1624
1625
static njs_int_t
1626
njs_fs_mkdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
1627
    njs_index_t calltype, njs_value_t *retval)
1628
0
{
1629
0
    char                *path;
1630
0
    mode_t              md;
1631
0
    njs_int_t           ret;
1632
0
    njs_value_t         *callback, *options;
1633
0
    njs_opaque_value_t  mode, recursive, result;
1634
0
    char                path_buf[NJS_MAX_PATH + 1];
1635
1636
0
    path = (char *) njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
1637
0
    if (njs_slow_path(path == NULL)) {
1638
0
        return NJS_ERROR;
1639
0
    }
1640
1641
0
    callback = NULL;
1642
0
    options = njs_arg(args, nargs, 2);
1643
1644
0
    if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
1645
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
1646
0
        if (!njs_value_is_function(callback)) {
1647
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
1648
0
            return NJS_ERROR;
1649
0
        }
1650
1651
0
        if (options == callback) {
1652
0
            options = njs_value_arg(&njs_value_undefined);
1653
0
        }
1654
0
    }
1655
1656
0
    njs_value_undefined_set(njs_value_arg(&mode));
1657
0
    njs_value_boolean_set(njs_value_arg(&recursive), 0);
1658
1659
0
    if (njs_value_is_number(options)) {
1660
0
        njs_value_assign(&mode, options);
1661
1662
0
    } else if (!njs_value_is_undefined(options)) {
1663
0
        if (!njs_value_is_object(options)) {
1664
0
            njs_vm_type_error(vm, "Unknown options type"
1665
0
                             "(a number or object required)");
1666
0
            return NJS_ERROR;
1667
0
        }
1668
1669
0
        (void) njs_vm_object_prop(vm, options, &string_recursive, &recursive);
1670
1671
0
        (void) njs_vm_object_prop(vm, options, &string_mode, &mode);
1672
0
    }
1673
1674
0
    md = njs_fs_mode(vm, njs_value_arg(&mode), 0777);
1675
0
    if (njs_slow_path(md == (mode_t) -1)) {
1676
0
        return NJS_ERROR;
1677
0
    }
1678
1679
0
    ret = njs_fs_make_path(vm, path, md,
1680
0
                           njs_value_bool(njs_value_arg(&recursive)), &result);
1681
1682
0
    if (ret == NJS_OK) {
1683
0
        return njs_fs_result(vm, &result, calltype, callback, 1, retval);
1684
0
    }
1685
1686
0
    return NJS_ERROR;
1687
0
}
1688
1689
1690
static njs_int_t
1691
njs_fs_read(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
1692
    njs_index_t calltype, njs_value_t *retval)
1693
0
{
1694
0
    int64_t             fd, length, pos, offset;
1695
0
    ssize_t             n;
1696
0
    njs_int_t           ret;
1697
0
    njs_str_t           data;
1698
0
    njs_uint_t          fd_offset;
1699
0
    njs_value_t         *buffer, *value;
1700
0
    njs_opaque_value_t  result;
1701
1702
0
    fd_offset = !!(calltype == NJS_FS_DIRECT);
1703
1704
0
    ret = njs_value_to_integer(vm, njs_arg(args, nargs, fd_offset), &fd);
1705
0
    if (njs_slow_path(ret != NJS_OK)) {
1706
0
        return ret;
1707
0
    }
1708
1709
0
    pos = -1;
1710
1711
    /*
1712
     * fh.read(buffer, offset[, length[, position]])
1713
     * fs.readSync(fd, buffer, offset[, length[, position]])
1714
     */
1715
1716
0
    buffer = njs_arg(args, nargs, fd_offset + 1);
1717
0
    ret = njs_value_buffer_get(vm, buffer, &data);
1718
0
    if (njs_slow_path(ret != NJS_OK)) {
1719
0
        return NJS_ERROR;
1720
0
    }
1721
1722
0
    ret = njs_value_to_integer(vm, njs_arg(args, nargs, fd_offset + 2),
1723
0
                               &offset);
1724
0
    if (njs_slow_path(ret != NJS_OK)) {
1725
0
        return ret;
1726
0
    }
1727
1728
0
    if (njs_slow_path(offset < 0 || (size_t) offset > data.length)) {
1729
0
        njs_vm_range_error(vm, "offset is out of range (must be <= %z)",
1730
0
                           data.length);
1731
0
        return NJS_ERROR;
1732
0
    }
1733
1734
0
    data.length -= offset;
1735
0
    data.start += offset;
1736
1737
0
    value = njs_arg(args, nargs, fd_offset + 3);
1738
1739
0
    if (!njs_value_is_undefined(value)) {
1740
0
        ret = njs_value_to_integer(vm, value, &length);
1741
0
        if (njs_slow_path(ret != NJS_OK)) {
1742
0
            return ret;
1743
0
        }
1744
1745
0
        if (njs_slow_path(length < 0 || (size_t) length > data.length)) {
1746
0
            njs_vm_range_error(vm, "length is out of range (must be <= %z)",
1747
0
                               data.length);
1748
0
            return NJS_ERROR;
1749
0
        }
1750
1751
0
        data.length = length;
1752
0
    }
1753
1754
0
    value = njs_arg(args, nargs, fd_offset + 4);
1755
1756
0
    if (!njs_value_is_null_or_undefined(value)) {
1757
0
        ret = njs_value_to_integer(vm, value, &pos);
1758
0
        if (njs_slow_path(ret != NJS_OK)) {
1759
0
            return ret;
1760
0
        }
1761
0
    }
1762
1763
0
    if (pos == -1) {
1764
0
        n = read(fd, data.start, data.length);
1765
1766
0
    } else {
1767
0
        n = pread(fd, data.start, data.length, pos);
1768
0
    }
1769
1770
0
    if (njs_slow_path(n == -1)) {
1771
0
        ret = njs_fs_error(vm, "read", strerror(errno), NULL, errno, &result);
1772
0
        goto done;
1773
0
    }
1774
1775
0
    if (calltype == NJS_FS_PROMISE) {
1776
0
        ret = njs_fs_bytes_read_create(vm, n, buffer, &result);
1777
0
        if (njs_slow_path(ret != NJS_OK)) {
1778
0
            goto done;
1779
0
        }
1780
1781
0
    } else {
1782
0
        njs_value_number_set(njs_value_arg(&result), n);
1783
0
    }
1784
1785
0
done:
1786
1787
0
    if (ret == NJS_OK) {
1788
0
        return njs_fs_result(vm, &result, calltype, NULL, 1, retval);
1789
0
    }
1790
1791
0
    return NJS_ERROR;
1792
0
}
1793
1794
1795
static njs_int_t
1796
njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
1797
    njs_index_t calltype, njs_value_t *retval)
1798
0
{
1799
0
    int                          fd, flags;
1800
0
    njs_str_t                    data;
1801
0
    njs_int_t                    ret;
1802
0
    const char                   *path;
1803
0
    njs_value_t                  *callback, *options;
1804
0
    struct stat                  sb;
1805
0
    njs_opaque_value_t           flag, result, encode;
1806
0
    const njs_buffer_encoding_t  *encoding;
1807
0
    char                         path_buf[NJS_MAX_PATH + 1];
1808
1809
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
1810
0
    if (njs_slow_path(path == NULL)) {
1811
0
        return NJS_ERROR;
1812
0
    }
1813
1814
0
    callback = NULL;
1815
1816
0
    options = njs_arg(args, nargs, 2);
1817
1818
0
    if (calltype == NJS_FS_CALLBACK) {
1819
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
1820
0
        if (!njs_value_is_function(callback)) {
1821
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
1822
0
            return NJS_ERROR;
1823
0
        }
1824
1825
0
        if (options == callback) {
1826
0
            options = njs_value_arg(&njs_value_undefined);
1827
0
        }
1828
0
    }
1829
1830
0
    njs_value_undefined_set(njs_value_arg(&flag));
1831
0
    njs_value_undefined_set(njs_value_arg(&encode));
1832
1833
0
    if (njs_value_is_string(options)) {
1834
0
        njs_value_assign(&encode, options);
1835
1836
0
    } else if (!njs_value_is_undefined(options)) {
1837
0
        if (!njs_value_is_object(options)) {
1838
0
            njs_vm_type_error(vm, "Unknown options type "
1839
0
                              "(a string or object required)");
1840
0
            return NJS_ERROR;
1841
0
        }
1842
1843
0
        (void) njs_vm_object_prop(vm, options, &string_flag, &flag);
1844
1845
0
        (void) njs_vm_object_prop(vm, options, &string_encoding, &encode);
1846
0
    }
1847
1848
0
    flags = njs_fs_flags(vm, njs_value_arg(&flag), O_RDONLY);
1849
0
    if (njs_slow_path(flags == -1)) {
1850
0
        return NJS_ERROR;
1851
0
    }
1852
1853
0
    encoding = NULL;
1854
0
    if (!njs_value_is_undefined(njs_value_arg(&encode))) {
1855
0
        encoding = njs_buffer_encoding(vm, njs_value_arg(&encode), 1);
1856
0
        if (njs_slow_path(encoding == NULL)) {
1857
0
            return NJS_ERROR;
1858
0
        }
1859
0
    }
1860
1861
0
    fd = open(path, flags);
1862
0
    if (njs_slow_path(fd < 0)) {
1863
0
        ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &result);
1864
0
        goto done;
1865
0
    }
1866
1867
0
    ret = fstat(fd, &sb);
1868
0
    if (njs_slow_path(ret == -1)) {
1869
0
        ret = njs_fs_error(vm, "stat", strerror(errno), path, errno, &result);
1870
0
        goto done;
1871
0
    }
1872
1873
0
    if (njs_slow_path(!S_ISREG(sb.st_mode))) {
1874
0
        ret = njs_fs_error(vm, "stat", "File is not regular", path, 0, &result);
1875
0
        goto done;
1876
0
    }
1877
1878
0
    data.start = NULL;
1879
0
    data.length = sb.st_size;
1880
1881
0
    ret = njs_fs_fd_read(vm, fd, &data);
1882
0
    if (njs_slow_path(ret != NJS_OK)) {
1883
0
        if (ret == NJS_DECLINED) {
1884
0
            ret = njs_fs_error(vm, "read", strerror(errno), path, errno,
1885
0
                               &result);
1886
0
        }
1887
1888
0
        goto done;
1889
0
    }
1890
1891
0
    if (encoding == NULL) {
1892
0
        ret = njs_buffer_set(vm, njs_value_arg(&result), data.start,
1893
0
                             data.length);
1894
1895
0
    } else {
1896
0
        ret = encoding->encode(vm, njs_value_arg(&result), &data);
1897
0
        njs_mp_free(njs_vm_memory_pool(vm), data.start);
1898
0
    }
1899
1900
0
done:
1901
1902
0
    if (fd != -1) {
1903
0
        (void) close(fd);
1904
0
    }
1905
1906
0
    if (ret == NJS_OK) {
1907
0
        return njs_fs_result(vm, &result, calltype, callback, 2, retval);
1908
0
    }
1909
1910
0
    return NJS_ERROR;
1911
0
}
1912
1913
1914
static njs_int_t
1915
njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
1916
    njs_index_t calltype, njs_value_t *retval)
1917
0
{
1918
0
    DIR                          *dir;
1919
0
    njs_str_t                    s;
1920
0
    njs_int_t                    ret;
1921
0
    const char                   *path;
1922
0
    njs_value_t                  *callback, *options, *value;
1923
0
    struct dirent                *entry;
1924
0
    njs_opaque_value_t           encode, types, ename, etype, result;
1925
0
    const njs_buffer_encoding_t  *encoding;
1926
0
    char                         path_buf[NJS_MAX_PATH + 1];
1927
1928
0
    static const njs_str_t  string_types = njs_str("withFileTypes");
1929
1930
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
1931
0
    if (njs_slow_path(path == NULL)) {
1932
0
        return NJS_ERROR;
1933
0
    }
1934
1935
0
    callback = NULL;
1936
0
    options = njs_arg(args, nargs, 2);
1937
1938
0
    if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
1939
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
1940
0
        if (!njs_value_is_function(callback)) {
1941
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
1942
0
            return NJS_ERROR;
1943
0
        }
1944
0
        if (options == callback) {
1945
0
            options = njs_value_arg(&njs_value_undefined);
1946
0
        }
1947
0
    }
1948
1949
0
    njs_value_boolean_set(njs_value_arg(&types), 0);
1950
0
    njs_value_undefined_set(njs_value_arg(&encode));
1951
1952
0
    if (njs_value_is_string(options)) {
1953
0
        njs_value_assign(&encode, options);
1954
1955
0
    } else if (!njs_value_is_undefined(options)) {
1956
0
        if (!njs_value_is_object(options)) {
1957
0
            njs_vm_type_error(vm, "Unknown options type "
1958
0
                             "(a string or object required)");
1959
0
            return NJS_ERROR;
1960
0
        }
1961
1962
0
        (void) njs_vm_object_prop(vm, options, &string_encoding, &encode);
1963
1964
0
        (void) njs_vm_object_prop(vm, options, &string_types, &types);
1965
0
    }
1966
1967
0
    encoding = NULL;
1968
1969
1970
0
    if (njs_value_is_string(njs_value_arg(&encode))) {
1971
0
        njs_value_string_get(vm, njs_value_arg(&encode), &s);
1972
1973
0
    } else {
1974
0
        s.length = 0;
1975
0
        s.start = NULL;
1976
0
    }
1977
1978
0
    if (!njs_strstr_eq(&s, &string_buffer)) {
1979
0
        encoding = njs_buffer_encoding(vm, njs_value_arg(&encode), 1);
1980
0
        if (njs_slow_path(encoding == NULL)) {
1981
0
            return NJS_ERROR;
1982
0
        }
1983
0
    }
1984
1985
0
    ret = njs_vm_array_alloc(vm, njs_value_arg(&result), 8);
1986
0
    if (njs_slow_path(ret != NJS_OK)) {
1987
0
        return NJS_ERROR;
1988
0
    }
1989
1990
0
    dir = opendir(path);
1991
0
    if (njs_slow_path(dir == NULL)) {
1992
0
        ret = njs_fs_error(vm, "opendir", strerror(errno), path, errno,
1993
0
                           &result);
1994
0
        goto done;
1995
0
    }
1996
1997
0
    ret = NJS_OK;
1998
1999
0
    for ( ;; ) {
2000
0
        errno = 0;
2001
0
        entry = readdir(dir);
2002
0
        if (njs_slow_path(entry == NULL)) {
2003
0
            if (errno != 0) {
2004
0
                ret = njs_fs_error(vm, "readdir", strerror(errno), path, errno,
2005
0
                                   &result);
2006
0
            }
2007
2008
0
            goto done;
2009
0
        }
2010
2011
0
        s.start = (u_char *) entry->d_name;
2012
0
        s.length = njs_strlen(s.start);
2013
2014
0
        if ((s.length == 1 && s.start[0] == '.')
2015
0
            || (s.length == 2 && (s.start[0] == '.' && s.start[1] == '.')))
2016
0
        {
2017
0
            continue;
2018
0
        }
2019
2020
0
        value = njs_vm_array_push(vm, njs_value_arg(&result));
2021
0
        if (njs_slow_path(value == NULL)) {
2022
0
            goto done;
2023
0
        }
2024
2025
0
        if (encoding == NULL) {
2026
0
            ret = njs_buffer_set(vm, njs_value_arg(&ename), s.start, s.length);
2027
2028
0
        } else {
2029
0
            ret = encoding->encode(vm, njs_value_arg(&ename), &s);
2030
0
        }
2031
2032
0
        if (njs_slow_path(ret != NJS_OK)) {
2033
0
            goto done;
2034
0
        }
2035
2036
0
        if (njs_fast_path(!njs_value_bool(njs_value_arg(&types)))) {
2037
0
            njs_value_assign(value, &ename);
2038
0
            continue;
2039
0
        }
2040
2041
0
        njs_value_number_set(njs_value_arg(&etype), njs_dentry_type(entry));
2042
2043
0
        ret = njs_fs_dirent_create(vm, njs_value_arg(&ename),
2044
0
                                   njs_value_arg(&etype), value);
2045
0
        if (njs_slow_path(ret != NJS_OK)) {
2046
0
            goto done;
2047
0
        }
2048
0
    }
2049
2050
0
done:
2051
2052
0
    if (dir != NULL) {
2053
0
        (void) closedir(dir);
2054
0
    }
2055
2056
0
    if (ret == NJS_OK) {
2057
0
        return njs_fs_result(vm, &result, calltype, callback, 2, retval);
2058
0
    }
2059
2060
0
    return NJS_ERROR;
2061
0
}
2062
2063
2064
static njs_int_t
2065
njs_fs_readlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2066
    njs_index_t calltype, njs_value_t *retval)
2067
0
{
2068
0
    ssize_t                      n;
2069
0
    njs_int_t                    ret;
2070
0
    njs_str_t                    s;
2071
0
    const char                   *path;
2072
0
    njs_value_t                  *callback, *options;
2073
0
    njs_opaque_value_t           encode, result;
2074
0
    const njs_buffer_encoding_t  *encoding;
2075
0
    char                         path_buf[NJS_MAX_PATH + 1],
2076
0
                                 dst_buf[NJS_MAX_PATH + 1];
2077
2078
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
2079
0
    if (njs_slow_path(path == NULL)) {
2080
0
        return NJS_ERROR;
2081
0
    }
2082
2083
0
    callback = NULL;
2084
0
    options = njs_arg(args, nargs, 2);
2085
2086
0
    if (calltype == NJS_FS_CALLBACK) {
2087
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
2088
0
        if (!njs_value_is_function(callback)) {
2089
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
2090
0
            return NJS_ERROR;
2091
0
        }
2092
2093
0
        if (options == callback) {
2094
0
            options = njs_value_arg(&njs_value_undefined);
2095
0
        }
2096
0
    }
2097
2098
0
    njs_value_undefined_set(njs_value_arg(&encode));
2099
2100
0
    if (njs_value_is_string(options)) {
2101
0
        njs_value_assign(&encode, options);
2102
2103
0
    } else if (!njs_value_is_undefined(options)) {
2104
0
        if (!njs_value_is_object(options)) {
2105
0
            njs_vm_type_error(vm, "Unknown options type "
2106
0
                              "(a string or object required)");
2107
0
            return NJS_ERROR;
2108
0
        }
2109
2110
0
        (void) njs_vm_object_prop(vm, options, &string_encoding, &encode);
2111
0
    }
2112
2113
0
    encoding = NULL;
2114
2115
0
    if (njs_value_is_string(njs_value_arg(&encode))) {
2116
0
        njs_value_string_get(vm, njs_value_arg(&encode), &s);
2117
2118
0
    } else {
2119
0
        s.length = 0;
2120
0
        s.start = NULL;
2121
0
    }
2122
2123
0
    if (!njs_strstr_eq(&s, &string_buffer)) {
2124
0
        encoding = njs_buffer_encoding(vm, njs_value_arg(&encode), 1);
2125
0
        if (njs_slow_path(encoding == NULL)) {
2126
0
            return NJS_ERROR;
2127
0
        }
2128
0
    }
2129
2130
0
    s.start = (u_char *) dst_buf;
2131
0
    n = readlink(path, dst_buf, sizeof(dst_buf) - 1);
2132
0
    if (njs_slow_path(n < 0)) {
2133
0
        ret = njs_fs_error(vm, "readlink", strerror(errno), path, errno,
2134
0
                           &result);
2135
0
        goto done;
2136
0
    }
2137
2138
0
    s.length = n;
2139
2140
0
    if (encoding == NULL) {
2141
0
        ret = njs_buffer_new(vm, njs_value_arg(&result), s.start, s.length);
2142
2143
0
    } else {
2144
0
        ret = encoding->encode(vm, njs_value_arg(&result), &s);
2145
0
    }
2146
2147
0
done:
2148
2149
0
    if (ret == NJS_OK) {
2150
0
        return njs_fs_result(vm, &result, calltype, callback, 2, retval);
2151
0
    }
2152
2153
0
    return NJS_ERROR;
2154
0
}
2155
2156
2157
static njs_int_t
2158
njs_fs_realpath(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2159
    njs_index_t calltype, njs_value_t *retval)
2160
0
{
2161
0
    njs_int_t                    ret;
2162
0
    njs_str_t                    s;
2163
0
    const char                   *path;
2164
0
    njs_value_t                  *callback, *options;
2165
0
    njs_opaque_value_t           encode, result;
2166
0
    const njs_buffer_encoding_t  *encoding;
2167
0
    char                         path_buf[NJS_MAX_PATH + 1],
2168
0
                                 dst_buf[NJS_MAX_PATH + 1];
2169
2170
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
2171
0
    if (njs_slow_path(path == NULL)) {
2172
0
        return NJS_ERROR;
2173
0
    }
2174
2175
0
    callback = NULL;
2176
0
    options = njs_arg(args, nargs, 2);
2177
2178
0
    if (calltype == NJS_FS_CALLBACK) {
2179
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
2180
0
        if (!njs_value_is_function(callback)) {
2181
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
2182
0
            return NJS_ERROR;
2183
0
        }
2184
2185
0
        if (options == callback) {
2186
0
            options = njs_value_arg(&njs_value_undefined);
2187
0
        }
2188
0
    }
2189
2190
0
    njs_value_undefined_set(njs_value_arg(&encode));
2191
2192
0
    if (njs_value_is_string(options)) {
2193
0
        njs_value_assign(&encode, options);
2194
2195
0
    } else if (!njs_value_is_undefined(options)) {
2196
0
        if (!njs_value_is_object(options)) {
2197
0
            njs_vm_type_error(vm, "Unknown options type "
2198
0
                              "(a string or object required)");
2199
0
            return NJS_ERROR;
2200
0
        }
2201
2202
0
        (void) njs_vm_object_prop(vm, options, &string_encoding, &encode);
2203
0
    }
2204
2205
0
    encoding = NULL;
2206
2207
0
    if (njs_value_is_string(njs_value_arg(&encode))) {
2208
0
        njs_value_string_get(vm, njs_value_arg(&encode), &s);
2209
2210
0
    } else {
2211
0
        s.length = 0;
2212
0
        s.start = NULL;
2213
0
    }
2214
2215
0
    if (!njs_strstr_eq(&s, &string_buffer)) {
2216
0
        encoding = njs_buffer_encoding(vm, njs_value_arg(&encode), 1);
2217
0
        if (njs_slow_path(encoding == NULL)) {
2218
0
            return NJS_ERROR;
2219
0
        }
2220
0
    }
2221
2222
0
    s.start = (u_char *) realpath(path, dst_buf);
2223
0
    if (njs_slow_path(s.start == NULL)) {
2224
0
        ret = njs_fs_error(vm, "realpath", strerror(errno), path, errno,
2225
0
                           &result);
2226
0
        goto done;
2227
0
    }
2228
2229
0
    s.length = njs_strlen(s.start);
2230
2231
0
    if (encoding == NULL) {
2232
0
        ret = njs_buffer_new(vm, njs_value_arg(&result), s.start, s.length);
2233
2234
0
    } else {
2235
0
        ret = encoding->encode(vm, njs_value_arg(&result), &s);
2236
0
    }
2237
2238
0
done:
2239
2240
0
    if (ret == NJS_OK) {
2241
0
        return njs_fs_result(vm, &result, calltype, callback, 2, retval);
2242
0
    }
2243
2244
0
    return NJS_ERROR;
2245
0
}
2246
2247
2248
static njs_int_t
2249
njs_fs_rename(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2250
    njs_index_t calltype, njs_value_t *retval)
2251
0
{
2252
0
    njs_int_t            ret;
2253
0
    const char          *path, *newpath;
2254
0
    njs_value_t         *callback;
2255
0
    njs_opaque_value_t  result;
2256
0
    char                path_buf[NJS_MAX_PATH + 1],
2257
0
                        newpath_buf[NJS_MAX_PATH + 1];
2258
2259
0
    callback = NULL;
2260
2261
0
    if (calltype == NJS_FS_CALLBACK) {
2262
0
        callback = njs_arg(args, nargs, 3);
2263
0
        if (!njs_value_is_function(callback)) {
2264
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
2265
0
            return NJS_ERROR;
2266
0
        }
2267
0
    }
2268
2269
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "oldPath");
2270
0
    if (njs_slow_path(path == NULL)) {
2271
0
        return NJS_ERROR;
2272
0
    }
2273
2274
0
    newpath = njs_fs_path(vm, newpath_buf, njs_arg(args, nargs, 2), "newPath");
2275
0
    if (njs_slow_path(newpath == NULL)) {
2276
0
        return NJS_ERROR;
2277
0
    }
2278
2279
0
    njs_value_undefined_set(njs_value_arg(&result));
2280
2281
0
    ret = rename(path, newpath);
2282
0
    if (njs_slow_path(ret != 0)) {
2283
0
        ret = njs_fs_error(vm, "rename", strerror(errno), NULL, errno, &result);
2284
0
    }
2285
2286
0
    if (ret == NJS_OK) {
2287
0
        return njs_fs_result(vm, &result, calltype, callback, 1, retval);
2288
0
    }
2289
2290
0
    return NJS_ERROR;
2291
0
}
2292
2293
2294
static njs_int_t
2295
njs_fs_rmdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2296
    njs_index_t calltype, njs_value_t *retval)
2297
0
{
2298
0
    njs_int_t           ret;
2299
0
    const char          *path;
2300
0
    njs_value_t         *callback, *options;
2301
0
    njs_opaque_value_t  recursive, result;
2302
0
    char                path_buf[NJS_MAX_PATH + 1];
2303
2304
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
2305
0
    if (njs_slow_path(path == NULL)) {
2306
0
        return NJS_ERROR;
2307
0
    }
2308
2309
0
    callback = NULL;
2310
0
    options = njs_arg(args, nargs, 2);
2311
2312
0
    if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
2313
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
2314
0
        if (!njs_value_is_function(callback)) {
2315
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
2316
0
            return NJS_ERROR;
2317
0
        }
2318
0
        if (options == callback) {
2319
0
            options = njs_value_arg(&njs_value_undefined);
2320
0
        }
2321
0
    }
2322
2323
0
    njs_value_boolean_set(njs_value_arg(&recursive), 0);
2324
2325
0
    if (njs_slow_path(!njs_value_is_undefined(options))) {
2326
0
        if (!njs_value_is_object(options)) {
2327
0
            njs_vm_type_error(vm, "Unknown options type "
2328
0
                              "(an object required)");
2329
0
            return NJS_ERROR;
2330
0
        }
2331
2332
0
        (void) njs_vm_object_prop(vm, options, &string_recursive, &recursive);
2333
0
    }
2334
2335
2336
0
    ret = njs_fs_rmtree(vm, path, njs_value_bool(njs_value_arg(&recursive)),
2337
0
                        &result);
2338
2339
0
    if (ret == NJS_OK) {
2340
0
        return njs_fs_result(vm, &result, calltype, callback, 1, retval);
2341
0
    }
2342
2343
0
    return NJS_ERROR;
2344
0
}
2345
2346
2347
static njs_int_t
2348
njs_fs_stat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2349
    njs_index_t magic, njs_value_t *retval)
2350
0
{
2351
0
    int64_t             fd;
2352
0
    njs_int_t           ret;
2353
0
    njs_uint_t          fd_offset;
2354
0
    njs_bool_t          throw;
2355
0
    struct stat         sb;
2356
0
    const char          *path;
2357
0
    njs_value_t         *callback, *options, *value;
2358
0
    njs_opaque_value_t  result;
2359
0
    njs_fs_calltype_t   calltype;
2360
0
    char                path_buf[NJS_MAX_PATH + 1];
2361
2362
0
    static const njs_str_t  string_bigint = njs_str("bigint");
2363
0
    static const njs_str_t  string_throw = njs_str("throwIfNoEntry");
2364
2365
0
    fd = -1;
2366
0
    path = NULL;
2367
0
    calltype = magic & 3;
2368
2369
0
    if ((magic >> 2) != NJS_FS_FSTAT) {
2370
0
        path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
2371
0
        if (njs_slow_path(path == NULL)) {
2372
0
            return NJS_ERROR;
2373
0
        }
2374
2375
0
        options = njs_arg(args, nargs, 2);
2376
2377
0
    } else {
2378
0
        fd_offset = !!(calltype == NJS_FS_DIRECT);
2379
0
        ret = njs_value_to_integer(vm, njs_argument(args, fd_offset), &fd);
2380
0
        if (njs_slow_path(ret != NJS_OK)) {
2381
0
            return ret;
2382
0
        }
2383
2384
0
        options = njs_arg(args, nargs, fd_offset + 1);
2385
0
    }
2386
2387
0
    callback = NULL;
2388
2389
0
    if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
2390
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
2391
0
        if (!njs_value_is_function(callback)) {
2392
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
2393
0
            return NJS_ERROR;
2394
0
        }
2395
2396
0
        if (options == callback) {
2397
0
            options = njs_value_arg(&njs_value_undefined);
2398
0
        }
2399
0
    }
2400
2401
0
    throw = 1;
2402
2403
0
    if (!njs_value_is_undefined(options)) {
2404
0
        if (!njs_value_is_object(options)) {
2405
0
            njs_vm_type_error(vm, "Unknown options type "
2406
0
                              "(an object required)");
2407
0
            return NJS_ERROR;
2408
0
        }
2409
2410
0
        value = njs_vm_object_prop(vm, options, &string_bigint, &result);
2411
0
        if (value != NULL && njs_value_bool(value)) {
2412
0
            njs_vm_type_error(vm, "\"bigint\" is not supported");
2413
0
            return NJS_ERROR;
2414
0
        }
2415
2416
0
        if (calltype == NJS_FS_DIRECT) {
2417
0
            value = njs_vm_object_prop(vm, options, &string_throw, &result);
2418
2419
0
            if (value != NULL) {
2420
0
                throw = njs_value_bool(value);
2421
0
            }
2422
0
        }
2423
0
    }
2424
2425
0
    switch (magic >> 2) {
2426
0
    case NJS_FS_STAT:
2427
0
        ret = stat(path, &sb);
2428
0
        break;
2429
2430
0
    case NJS_FS_LSTAT:
2431
0
        ret = lstat(path, &sb);
2432
0
        break;
2433
2434
0
    case NJS_FS_FSTAT:
2435
0
    default:
2436
0
        ret = fstat(fd, &sb);
2437
0
        break;
2438
0
    }
2439
2440
0
    if (njs_slow_path(ret != 0)) {
2441
0
        if (errno != ENOENT || throw) {
2442
0
            ret = njs_fs_error(vm,
2443
0
                               ((magic >> 2) == NJS_FS_STAT) ? "stat" : "lstat",
2444
0
                               strerror(errno), path, errno, &result);
2445
0
            if (njs_slow_path(ret != NJS_OK)) {
2446
0
                return NJS_ERROR;
2447
0
            }
2448
0
        } else {
2449
0
            njs_value_undefined_set(njs_value_arg(&result));
2450
0
        }
2451
2452
0
        return njs_fs_result(vm, &result, calltype, callback, 2, retval);
2453
0
    }
2454
2455
0
    ret = njs_fs_stats_create(vm, &sb, njs_value_arg(&result));
2456
0
    if (njs_slow_path(ret != NJS_OK)) {
2457
0
        return NJS_ERROR;
2458
0
    }
2459
2460
0
    return njs_fs_result(vm, &result, calltype, callback, 2, retval);
2461
0
}
2462
2463
2464
static njs_int_t
2465
njs_fs_symlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2466
    njs_index_t calltype, njs_value_t *retval)
2467
0
{
2468
0
    njs_int_t           ret;
2469
0
    const char          *target, *path;
2470
0
    njs_value_t         *callback, *type;
2471
0
    njs_opaque_value_t  result;
2472
0
    char                target_buf[NJS_MAX_PATH + 1],
2473
0
                        path_buf[NJS_MAX_PATH + 1];
2474
2475
0
    target = njs_fs_path(vm, target_buf, njs_arg(args, nargs, 1), "target");
2476
0
    if (njs_slow_path(target == NULL)) {
2477
0
        return NJS_ERROR;
2478
0
    }
2479
2480
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 2), "path");
2481
0
    if (njs_slow_path(path == NULL)) {
2482
0
        return NJS_ERROR;
2483
0
    }
2484
2485
0
    callback = NULL;
2486
0
    type = njs_arg(args, nargs, 3);
2487
2488
0
    if (calltype == NJS_FS_CALLBACK) {
2489
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 4));
2490
0
        if (!njs_value_is_function(callback)) {
2491
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
2492
0
            return NJS_ERROR;
2493
0
        }
2494
2495
0
        if (type == callback) {
2496
0
            type = njs_value_arg(&njs_value_undefined);
2497
0
        }
2498
0
    }
2499
2500
0
    if (njs_slow_path(!njs_value_is_undefined(type)
2501
0
                      && !njs_value_is_string(type)))
2502
0
    {
2503
0
        njs_vm_type_error(vm, "\"type\" must be a string");
2504
0
        return NJS_ERROR;
2505
0
    }
2506
2507
0
    njs_value_undefined_set(njs_value_arg(&result));
2508
2509
0
    ret = symlink(target, path);
2510
0
    if (njs_slow_path(ret != 0)) {
2511
0
        ret = njs_fs_error(vm, "symlink", strerror(errno), path, errno,
2512
0
                           &result);
2513
0
    }
2514
2515
0
    if (ret == NJS_OK) {
2516
0
        return njs_fs_result(vm, &result, calltype, callback, 1, retval);
2517
0
    }
2518
2519
0
    return NJS_ERROR;
2520
0
}
2521
2522
2523
static njs_int_t
2524
njs_fs_unlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2525
    njs_index_t calltype, njs_value_t *retval)
2526
0
{
2527
0
    njs_int_t           ret;
2528
0
    const char          *path;
2529
0
    njs_value_t         *callback;
2530
0
    njs_opaque_value_t  result;
2531
0
    char                path_buf[NJS_MAX_PATH + 1];
2532
2533
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
2534
0
    if (njs_slow_path(path == NULL)) {
2535
0
        return NJS_ERROR;
2536
0
    }
2537
2538
0
    callback = NULL;
2539
2540
0
    if (calltype == NJS_FS_CALLBACK) {
2541
0
        callback = njs_arg(args, nargs, 2);
2542
0
        if (!njs_value_is_function(callback)) {
2543
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
2544
0
            return NJS_ERROR;
2545
0
        }
2546
0
    }
2547
2548
0
    njs_value_undefined_set(njs_value_arg(&result));
2549
2550
0
    ret = unlink(path);
2551
0
    if (njs_slow_path(ret != 0)) {
2552
0
        ret = njs_fs_error(vm, "unlink", strerror(errno), path, errno, &result);
2553
0
    }
2554
2555
0
    if (ret == NJS_OK) {
2556
0
        return njs_fs_result(vm, &result, calltype, callback, 1, retval);
2557
0
    }
2558
2559
0
    return NJS_ERROR;
2560
0
}
2561
2562
2563
static njs_int_t
2564
njs_fs_write(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2565
    njs_index_t calltype, njs_value_t *retval)
2566
0
{
2567
0
    int64_t                      fd, length, pos, offset;
2568
0
    ssize_t                      n;
2569
0
    njs_int_t                    ret;
2570
0
    njs_str_t                    data;
2571
0
    njs_uint_t                   fd_offset;
2572
0
    njs_value_t                  *buffer, *value;
2573
0
    njs_opaque_value_t           result;
2574
0
    const njs_buffer_encoding_t  *encoding;
2575
2576
0
    fd_offset = !!(calltype == NJS_FS_DIRECT);
2577
2578
0
    ret = njs_value_to_integer(vm, njs_arg(args, nargs, fd_offset), &fd);
2579
0
    if (njs_slow_path(ret != NJS_OK)) {
2580
0
        return ret;
2581
0
    }
2582
2583
0
    buffer = njs_arg(args, nargs, fd_offset + 1);
2584
2585
0
    pos = -1;
2586
0
    encoding = NULL;
2587
2588
    /*
2589
     * fs.writeSync(fd, string[, position[, encoding]])
2590
     * fh.write(string[, position[, encoding]])
2591
     */
2592
2593
0
    if (njs_value_is_string(buffer)) {
2594
0
        value = njs_arg(args, nargs, fd_offset + 2);
2595
2596
0
        if (!njs_value_is_null_or_undefined(value)) {
2597
0
            ret = njs_value_to_integer(vm, value, &pos);
2598
0
            if (njs_slow_path(ret != NJS_OK)) {
2599
0
                return ret;
2600
0
            }
2601
0
        }
2602
2603
0
        encoding = njs_buffer_encoding(vm, njs_arg(args, nargs, fd_offset + 3),
2604
0
                                       1);
2605
0
        if (njs_slow_path(encoding == NULL)) {
2606
0
            return NJS_ERROR;
2607
0
        }
2608
2609
0
        ret = njs_buffer_decode_string(vm, buffer, njs_value_arg(&result),
2610
0
                                       encoding);
2611
0
        if (njs_slow_path(ret != NJS_OK)) {
2612
0
            return NJS_ERROR;
2613
0
        }
2614
2615
0
        njs_value_string_get(vm, njs_value_arg(&result), &data);
2616
2617
0
        goto process;
2618
0
    }
2619
2620
    /*
2621
     * fh.write(buffer, offset[, length[, position]])
2622
     * fs.writeSync(fd, buffer, offset[, length[, position]])
2623
     */
2624
2625
0
    ret = njs_vm_value_to_bytes(vm, &data, buffer);
2626
0
    if (njs_slow_path(ret != NJS_OK)) {
2627
0
        return NJS_ERROR;
2628
0
    }
2629
2630
0
    ret = njs_value_to_integer(vm, njs_arg(args, nargs, fd_offset + 2),
2631
0
                               &offset);
2632
0
    if (njs_slow_path(ret != NJS_OK)) {
2633
0
        return ret;
2634
0
    }
2635
2636
0
    if (njs_slow_path(offset < 0 || (size_t) offset > data.length)) {
2637
0
        njs_vm_range_error(vm, "offset is out of range (must be <= %z)",
2638
0
                           data.length);
2639
0
        return NJS_ERROR;
2640
0
    }
2641
2642
0
    data.length -= offset;
2643
0
    data.start += offset;
2644
2645
0
    value = njs_arg(args, nargs, fd_offset + 3);
2646
2647
0
    if (!njs_value_is_undefined(value)) {
2648
0
        ret = njs_value_to_integer(vm, value, &length);
2649
0
        if (njs_slow_path(ret != NJS_OK)) {
2650
0
            return ret;
2651
0
        }
2652
2653
0
        if (njs_slow_path(length < 0 || (size_t) length > data.length)) {
2654
0
            njs_vm_range_error(vm, "length is out of range (must be <= %z)",
2655
0
                               data.length);
2656
0
            return NJS_ERROR;
2657
0
        }
2658
2659
0
        data.length = length;
2660
0
    }
2661
2662
0
    value = njs_arg(args, nargs, fd_offset + 4);
2663
2664
0
    if (!njs_value_is_null_or_undefined(value)) {
2665
0
        ret = njs_value_to_integer(vm, value, &pos);
2666
0
        if (njs_slow_path(ret != NJS_OK)) {
2667
0
            return ret;
2668
0
        }
2669
0
    }
2670
2671
0
process:
2672
2673
0
    if (pos == -1) {
2674
0
        n = write(fd, data.start, data.length);
2675
2676
0
    } else {
2677
0
        n = pwrite(fd, data.start, data.length, pos);
2678
0
    }
2679
2680
0
    if (njs_slow_path(n == -1)) {
2681
0
        ret = njs_fs_error(vm, "write", strerror(errno), NULL, errno, &result);
2682
0
        goto done;
2683
0
    }
2684
2685
0
    if (njs_slow_path((size_t) n != data.length)) {
2686
0
        ret = njs_fs_error(vm, "write", "failed to write all the data", NULL,
2687
0
                           0, &result);
2688
0
        goto done;
2689
0
    }
2690
2691
0
    if (calltype == NJS_FS_PROMISE) {
2692
0
        ret = njs_fs_bytes_written_create(vm, n, buffer, &result);
2693
0
        if (njs_slow_path(ret != NJS_OK)) {
2694
0
            goto done;
2695
0
        }
2696
2697
0
    } else {
2698
0
        njs_value_number_set(njs_value_arg(&result), n);
2699
0
    }
2700
2701
0
done:
2702
2703
0
    if (ret == NJS_OK) {
2704
0
        return njs_fs_result(vm, &result, calltype, NULL, 1, retval);
2705
0
    }
2706
2707
0
    return NJS_ERROR;
2708
0
}
2709
2710
2711
static njs_int_t
2712
njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
2713
    njs_index_t magic, njs_value_t *retval)
2714
0
{
2715
0
    int                          fd, flags;
2716
0
    u_char                       *p, *end;
2717
0
    mode_t                       md;
2718
0
    ssize_t                      n;
2719
0
    njs_str_t                    content;
2720
0
    njs_int_t                    ret;
2721
0
    const char                   *path;
2722
0
    njs_value_t                  *data, *callback, *options;
2723
0
    njs_opaque_value_t           flag, mode, encode, result;
2724
0
    njs_fs_calltype_t            calltype;
2725
0
    const njs_buffer_encoding_t  *encoding;
2726
0
    char                         path_buf[NJS_MAX_PATH + 1];
2727
2728
0
    path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
2729
0
    if (njs_slow_path(path == NULL)) {
2730
0
        return NJS_ERROR;
2731
0
    }
2732
2733
0
    callback = NULL;
2734
0
    calltype = magic & 3;
2735
0
    options = njs_arg(args, nargs, 3);
2736
2737
0
    if (calltype == NJS_FS_CALLBACK) {
2738
0
        callback = njs_arg(args, nargs, njs_min(nargs - 1, 4));
2739
0
        if (!njs_value_is_function(callback)) {
2740
0
            njs_vm_type_error(vm, "\"callback\" must be a function");
2741
0
            return NJS_ERROR;
2742
0
        }
2743
2744
0
        if (options == callback) {
2745
0
            options = njs_value_arg(&njs_value_undefined);
2746
0
        }
2747
0
    }
2748
2749
0
    njs_value_undefined_set(njs_value_arg(&flag));
2750
0
    njs_value_undefined_set(njs_value_arg(&mode));
2751
0
    njs_value_undefined_set(njs_value_arg(&encode));
2752
2753
0
    if (njs_value_is_string(options)) {
2754
0
        njs_value_assign(&encode, options);
2755
2756
0
    } else if (!njs_value_is_undefined(options)) {
2757
0
        if (!njs_value_is_object(options)) {
2758
0
            njs_vm_type_error(vm, "Unknown options type "
2759
0
                              "(a string or object required)");
2760
0
            return NJS_ERROR;
2761
0
        }
2762
2763
0
        (void) njs_vm_object_prop(vm, options, &string_flag, &flag);
2764
2765
0
        (void) njs_vm_object_prop(vm, options, &string_mode, &mode);
2766
2767
0
        (void) njs_vm_object_prop(vm, options, &string_encoding, &encode);
2768
0
    }
2769
2770
0
    data = njs_arg(args, nargs, 2);
2771
2772
0
    if (njs_value_is_buffer(data) || njs_value_is_data_view(data)) {
2773
0
        ret = njs_value_buffer_get(vm, data, &content);
2774
0
        if (njs_slow_path(ret != NJS_OK)) {
2775
0
            return NJS_ERROR;
2776
0
        }
2777
2778
0
    } else {
2779
0
        encoding = njs_buffer_encoding(vm, njs_value_arg(&encode), 1);
2780
0
        if (njs_slow_path(encoding == NULL)) {
2781
0
            return NJS_ERROR;
2782
0
        }
2783
2784
0
        ret = njs_value_to_string(vm, njs_value_arg(&result), data);
2785
0
        if (njs_slow_path(ret != NJS_OK)) {
2786
0
            return NJS_ERROR;
2787
0
        }
2788
2789
0
        ret = njs_buffer_decode_string(vm, njs_value_arg(&result),
2790
0
                                       njs_value_arg(&result), encoding);
2791
0
        if (njs_slow_path(ret != NJS_OK)) {
2792
0
            return NJS_ERROR;
2793
0
        }
2794
2795
0
        njs_value_string_get(vm, njs_value_arg(&result), &content);
2796
0
    }
2797
2798
0
    flags = njs_fs_flags(vm, njs_value_arg(&flag), O_CREAT | O_WRONLY);
2799
0
    if (njs_slow_path(flags == -1)) {
2800
0
        return NJS_ERROR;
2801
0
    }
2802
2803
0
    flags |= ((magic >> 2) == NJS_FS_APPEND) ? O_APPEND : O_TRUNC;
2804
2805
0
    md = njs_fs_mode(vm, njs_value_arg(&mode), 0666);
2806
0
    if (njs_slow_path(md == (mode_t) -1)) {
2807
0
        return NJS_ERROR;
2808
0
    }
2809
2810
0
    fd = open(path, flags, md);
2811
0
    if (njs_slow_path(fd < 0)) {
2812
0
        ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &result);
2813
0
        goto done;
2814
0
    }
2815
2816
0
    p = content.start;
2817
0
    end = p + content.length;
2818
2819
0
    while (p < end) {
2820
0
        n = write(fd, p, end - p);
2821
0
        if (njs_slow_path(n == -1)) {
2822
0
            if (errno == EINTR) {
2823
0
                continue;
2824
0
            }
2825
2826
0
            ret = njs_fs_error(vm, "write", strerror(errno), path, errno,
2827
0
                               &result);
2828
0
            goto done;
2829
0
        }
2830
2831
0
        p += n;
2832
0
    }
2833
2834
0
    ret = NJS_OK;
2835
0
    njs_value_undefined_set(njs_value_arg(&result));
2836
2837
0
done:
2838
2839
0
    if (fd != -1) {
2840
0
        (void) close(fd);
2841
0
    }
2842
2843
0
    if (ret == NJS_OK) {
2844
0
        return njs_fs_result(vm, &result, calltype, callback, 1, retval);
2845
0
    }
2846
2847
0
    return NJS_ERROR;
2848
0
}
2849
2850
2851
static njs_int_t
2852
njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data)
2853
0
{
2854
0
    u_char   *p, *end, *start;
2855
0
    size_t   size;
2856
0
    ssize_t  n;
2857
2858
0
    size = data->length;
2859
2860
0
    if (size == 0) {
2861
0
        size = 4096;
2862
0
    }
2863
2864
0
    data->start = njs_mp_alloc(njs_vm_memory_pool(vm), size);
2865
0
    if (data->start == NULL) {
2866
0
        njs_vm_memory_error(vm);
2867
0
        return NJS_ERROR;
2868
0
    }
2869
2870
0
    p = data->start;
2871
0
    end = p + size;
2872
2873
0
    for ( ;; ) {
2874
0
        n = read(fd, p, end - p);
2875
2876
0
        if (njs_slow_path(n < 0)) {
2877
0
            return NJS_DECLINED;
2878
0
        }
2879
2880
0
        p += n;
2881
2882
0
        if (n == 0) {
2883
0
            break;
2884
0
        }
2885
2886
0
        if (end - p < 2048) {
2887
0
            size *= 2;
2888
2889
0
            start = njs_mp_alloc(njs_vm_memory_pool(vm), size);
2890
0
            if (start == NULL) {
2891
0
                njs_vm_memory_error(vm);
2892
0
                return NJS_ERROR;
2893
0
            }
2894
2895
0
            memcpy(start, data->start, p - data->start);
2896
2897
0
            njs_mp_free(njs_vm_memory_pool(vm), data->start);
2898
2899
0
            p = start + (p - data->start);
2900
0
            end = start + size;
2901
0
            data->start = start;
2902
0
        }
2903
0
    }
2904
2905
0
    data->length = p - data->start;
2906
2907
0
    return NJS_OK;
2908
0
}
2909
2910
2911
static njs_int_t
2912
njs_fs_make_path(njs_vm_t *vm, char *path, mode_t md, njs_bool_t recursive,
2913
    njs_opaque_value_t *retval)
2914
0
{
2915
0
    int          err;
2916
0
    njs_int_t    ret;
2917
0
    const char   *p, *prev, *end;
2918
0
    struct stat  sb;
2919
2920
0
    njs_value_undefined_set(njs_value_arg(retval));
2921
2922
0
    end = path + njs_strlen(path);
2923
2924
0
    if (!recursive) {
2925
0
        ret = mkdir(path, md);
2926
0
        if (ret != 0) {
2927
0
            err = errno;
2928
0
            goto failed;
2929
0
        }
2930
2931
0
        return NJS_OK;
2932
0
    }
2933
2934
0
    p = path;
2935
0
    prev = p;
2936
2937
0
    for ( ;; ) {
2938
0
        p = strchr(prev + 1, '/');
2939
0
        if (p == NULL) {
2940
0
            p = end;
2941
0
        }
2942
2943
0
        if (njs_slow_path((p - path) > NJS_MAX_PATH)) {
2944
0
            njs_vm_internal_error(vm, "too large path");
2945
0
            return NJS_ERROR;
2946
0
        }
2947
2948
0
        path[p - path] = '\0';
2949
2950
0
        ret = mkdir(path, md);
2951
0
        err = errno;
2952
2953
0
        if (ret != 0) {
2954
0
            switch (err) {
2955
0
            case EACCES:
2956
0
            case ENOTDIR:
2957
0
            case EPERM:
2958
0
                goto failed_restore;
2959
2960
0
            case EEXIST:
2961
0
            default:
2962
0
                ret = stat(path, &sb);
2963
0
                if (ret == 0) {
2964
0
                    if (!S_ISDIR(sb.st_mode)) {
2965
0
                        err = ENOTDIR;
2966
0
                        goto failed_restore;
2967
0
                    }
2968
2969
0
                    break;
2970
0
                }
2971
2972
0
                goto failed_restore;
2973
0
            }
2974
0
        }
2975
2976
0
        if (p == end) {
2977
0
            break;
2978
0
        }
2979
2980
0
        path[p - path] = '/';
2981
0
        prev = p;
2982
0
    }
2983
2984
0
    return NJS_OK;
2985
2986
0
failed_restore:
2987
2988
0
    if (p != end) {
2989
0
        path[p - path] = '/';
2990
0
    }
2991
2992
0
failed:
2993
2994
0
    return njs_fs_error(vm, "mkdir", strerror(err), path, err, retval);
2995
0
}
2996
2997
2998
typedef struct njs_ftw_trace_s  njs_ftw_trace_t;
2999
3000
struct njs_ftw_trace_s {
3001
    struct njs_ftw_trace_s  *chain;
3002
    dev_t                   dev;
3003
    ino_t                   ino;
3004
};
3005
3006
3007
static int
3008
njs_ftw(char *path, njs_file_tree_walk_cb_t cb, int fd_limit,
3009
    njs_ftw_flags_t flags, njs_ftw_trace_t *parent)
3010
0
{
3011
0
    int              type, ret, dfd;
3012
0
    DIR              *d;
3013
0
    size_t           base, len, length;
3014
0
    const char       *d_name;
3015
0
    struct stat      st;
3016
0
    struct dirent    *entry;
3017
0
    njs_ftw_trace_t  trace, *h;
3018
3019
0
    ret = (flags & NJS_FTW_PHYS) ? lstat(path, &st) : stat(path, &st);
3020
3021
0
    if (ret < 0) {
3022
0
        if (!(flags & NJS_FTW_PHYS) && errno == ENOENT && !lstat(path, &st)) {
3023
0
            type = NJS_FTW_SLN;
3024
3025
0
        } else if (errno != EACCES) {
3026
0
            return NJS_ERROR;
3027
3028
0
        } else {
3029
0
            type = NJS_FTW_NS;
3030
0
        }
3031
3032
0
    } else if (S_ISDIR(st.st_mode)) {
3033
0
        type = (flags & NJS_FTW_DEPTH) ? NJS_FTW_DP : NJS_FTW_D;
3034
3035
0
    } else if (S_ISLNK(st.st_mode)) {
3036
0
        type = (flags & NJS_FTW_PHYS) ? NJS_FTW_SL : NJS_FTW_SLN;
3037
3038
0
    } else {
3039
0
        type = NJS_FTW_F;
3040
0
    }
3041
3042
0
    if ((flags & NJS_FTW_MOUNT) && parent != NULL && st.st_dev != parent->dev) {
3043
0
        return NJS_OK;
3044
0
    }
3045
3046
0
    for (h = parent; h != NULL; h = h->chain) {
3047
0
        if (h->dev == st.st_dev && h->ino == st.st_ino) {
3048
0
            return NJS_OK;
3049
0
        }
3050
0
    }
3051
3052
0
    len = njs_strlen(path);
3053
0
    base = len && (path[len - 1] == '/') ? len - 1 : len;
3054
3055
0
    trace.chain = parent;
3056
0
    trace.dev = st.st_dev;
3057
0
    trace.ino = st.st_ino;
3058
3059
0
    d = NULL;
3060
0
    dfd = -1;
3061
3062
0
    if (type == NJS_FTW_D || type == NJS_FTW_DP) {
3063
0
        dfd = open(path, O_RDONLY);
3064
0
        if (dfd < 0) {
3065
0
            if (errno != EACCES) {
3066
0
                return NJS_ERROR;
3067
0
            }
3068
3069
0
            type = NJS_FTW_DNR;
3070
0
        }
3071
0
    }
3072
3073
0
    if (!(flags & NJS_FTW_DEPTH)) {
3074
0
        ret = cb(path, &st, type);
3075
0
        if (njs_slow_path(ret != 0)) {
3076
0
            goto done;
3077
0
        }
3078
0
    }
3079
3080
0
    if (type == NJS_FTW_D || type == NJS_FTW_DP) {
3081
0
        d = fdopendir(dfd);
3082
0
        if (njs_slow_path(d == NULL)) {
3083
0
            ret = NJS_ERROR;
3084
0
            goto done;
3085
0
        }
3086
3087
0
        for ( ;; ) {
3088
0
            entry = readdir(d);
3089
3090
0
            if (entry == NULL) {
3091
0
                break;
3092
0
            }
3093
3094
0
            d_name = entry->d_name;
3095
0
            length = njs_strlen(d_name);
3096
3097
0
            if ((length == 1 && d_name[0] == '.')
3098
0
                || (length == 2 && (d_name[0] == '.' && d_name[1] == '.')))
3099
0
            {
3100
0
                continue;
3101
0
            }
3102
3103
0
            if (njs_slow_path(length >= (NJS_MAX_PATH - len))) {
3104
0
                errno = ENAMETOOLONG;
3105
0
                ret = NJS_ERROR;
3106
0
                goto done;
3107
0
            }
3108
3109
0
            path[base] = '/';
3110
0
            memcpy(&path[base + 1], d_name, length + njs_length("\0"));
3111
3112
0
            if (fd_limit != 0) {
3113
0
                ret = njs_ftw(path, cb, fd_limit - 1, flags, &trace);
3114
0
                if (njs_slow_path(ret != 0)) {
3115
0
                    goto done;
3116
0
                }
3117
0
            }
3118
0
        }
3119
3120
0
        (void) closedir(d);
3121
0
        d = NULL;
3122
0
        dfd = -1;
3123
0
    }
3124
3125
0
    path[len] = '\0';
3126
3127
0
    if (flags & NJS_FTW_DEPTH) {
3128
0
        ret = cb(path, &st, type);
3129
0
        if (njs_slow_path(ret != 0)) {
3130
0
            return ret;
3131
0
        }
3132
0
    }
3133
3134
0
    ret = NJS_OK;
3135
3136
0
done:
3137
3138
0
    if (d != NULL) {
3139
        /* closedir() also closes underlying dfd. */
3140
0
        (void) closedir(d);
3141
3142
0
    } else if (dfd >= 0) {
3143
0
        (void) close(dfd);
3144
0
    }
3145
3146
0
    return ret;
3147
0
}
3148
3149
3150
static njs_int_t
3151
njs_file_tree_walk(const char *path, njs_file_tree_walk_cb_t cb, int fd_limit,
3152
    njs_ftw_flags_t flags)
3153
0
{
3154
0
    size_t  len;
3155
0
    char    pathbuf[NJS_MAX_PATH + 1];
3156
3157
0
    len = njs_strlen(path);
3158
0
    if (njs_slow_path(len > NJS_MAX_PATH)) {
3159
0
        errno = ENAMETOOLONG;
3160
0
        return -1;
3161
0
    }
3162
3163
0
    memcpy(pathbuf, path, len + 1);
3164
3165
0
    return njs_ftw(pathbuf, cb, fd_limit, flags, NULL);
3166
0
}
3167
3168
3169
static njs_int_t
3170
njs_fs_rmtree_cb(const char *path, const struct stat *sb, njs_ftw_type_t type)
3171
0
{
3172
0
    njs_int_t  ret;
3173
3174
0
    ret = remove(path);
3175
0
    if (ret != 0) {
3176
0
        return NJS_ERROR;
3177
0
    }
3178
3179
0
    return NJS_OK;
3180
0
}
3181
3182
3183
static njs_int_t
3184
njs_fs_rmtree(njs_vm_t *vm, const char *path, njs_bool_t recursive,
3185
    njs_opaque_value_t *retval)
3186
0
{
3187
0
    njs_int_t   ret;
3188
0
    const char  *description;
3189
3190
0
    njs_value_undefined_set(njs_value_arg(retval));
3191
3192
0
    ret = rmdir(path);
3193
0
    if (ret == 0) {
3194
0
        return NJS_OK;
3195
0
    }
3196
3197
0
    description = strerror(errno);
3198
3199
0
    if (recursive && (errno == ENOTEMPTY || errno == EEXIST)) {
3200
0
        ret = njs_file_tree_walk(path, njs_fs_rmtree_cb, 16,
3201
0
                                 NJS_FTW_PHYS | NJS_FTW_MOUNT | NJS_FTW_DEPTH);
3202
3203
0
        if (ret == NJS_OK) {
3204
0
            return NJS_OK;
3205
0
        }
3206
3207
0
        description = strerror(errno);
3208
0
    }
3209
3210
0
    return njs_fs_error(vm, "rmdir", description, path, errno, retval);
3211
0
}
3212
3213
3214
static const char *
3215
njs_fs_path(njs_vm_t *vm, char storage[NJS_MAX_PATH + 1], njs_value_t *src,
3216
    const char *prop_name)
3217
0
{
3218
0
    u_char     *p;
3219
0
    njs_str_t  str;
3220
0
    njs_int_t  ret;
3221
3222
0
    if (njs_value_is_string(src)) {
3223
0
        njs_value_string_get(vm, src, &str);
3224
3225
0
    } else if (njs_value_is_buffer(src)) {
3226
0
        ret = njs_value_buffer_get(vm, src, &str);
3227
0
        if (njs_slow_path(ret != NJS_OK)) {
3228
0
            return NULL;
3229
0
        }
3230
3231
0
    } else {
3232
0
        njs_vm_type_error(vm, "\"%s\" must be a string or Buffer", prop_name);
3233
0
        return NULL;
3234
0
    }
3235
3236
0
    if (njs_slow_path(str.length > NJS_MAX_PATH - 1)) {
3237
0
        njs_vm_internal_error(vm, "\"%s\" is too long >= %d", prop_name,
3238
0
                              NJS_MAX_PATH);
3239
0
        return NULL;
3240
0
    }
3241
3242
0
    if (njs_slow_path(memchr(str.start, '\0', str.length) != 0)) {
3243
0
        njs_vm_type_error(vm, "\"%s\" must be a Buffer without null bytes",
3244
0
                          prop_name);
3245
0
        return NULL;
3246
0
    }
3247
3248
0
    p = njs_cpymem(storage, str.start, str.length);
3249
0
    *p++ = '\0';
3250
3251
0
    return storage;
3252
0
}
3253
3254
3255
static int
3256
njs_fs_flags(njs_vm_t *vm, njs_value_t *value, int default_flags)
3257
0
{
3258
0
    njs_str_t       flags;
3259
0
    njs_int_t       ret;
3260
0
    njs_fs_entry_t  *fl;
3261
3262
0
    if (njs_value_is_undefined(value)) {
3263
0
        return default_flags;
3264
0
    }
3265
3266
0
    ret = njs_value_to_string(vm, value, value);
3267
0
    if (njs_slow_path(ret != NJS_OK)) {
3268
0
        return -1;
3269
0
    }
3270
3271
0
    njs_value_string_get(vm, value, &flags);
3272
3273
0
    for (fl = &njs_flags_table[0]; fl->name.length != 0; fl++) {
3274
0
        if (njs_strstr_eq(&flags, &fl->name)) {
3275
0
            return fl->value;
3276
0
        }
3277
0
    }
3278
3279
0
    njs_vm_type_error(vm, "Unknown file open flags: \"%V\"", &flags);
3280
3281
0
    return -1;
3282
0
}
3283
3284
3285
static mode_t
3286
njs_fs_mode(njs_vm_t *vm, njs_value_t *value, mode_t default_mode)
3287
0
{
3288
0
    int64_t    i64;
3289
0
    njs_int_t  ret;
3290
3291
    /* GCC complains about uninitialized i64. */
3292
0
    i64 = 0;
3293
3294
0
    if (njs_value_is_undefined(value)) {
3295
0
        return default_mode;
3296
0
    }
3297
3298
0
    ret = njs_value_to_integer(vm, value, &i64);
3299
0
    if (njs_slow_path(ret != NJS_OK)) {
3300
0
        return (mode_t) -1;
3301
0
    }
3302
3303
0
    return (mode_t) i64;
3304
0
}
3305
3306
3307
static njs_int_t
3308
njs_fs_error(njs_vm_t *vm, const char *syscall, const char *description,
3309
    const char *path, int errn, njs_opaque_value_t *retval)
3310
0
{
3311
0
    size_t              size;
3312
0
    njs_int_t           ret;
3313
0
    const char          *code;
3314
0
    njs_opaque_value_t  value;
3315
3316
0
    static const njs_str_t  string_errno = njs_str("errno");
3317
0
    static const njs_str_t  string_code = njs_str("code");
3318
0
    static const njs_str_t  string_path = njs_str("path");
3319
0
    static const njs_str_t  string_syscall = njs_str("syscall");
3320
3321
0
    size = description != NULL ? njs_strlen(description) : 0;
3322
3323
0
    njs_vm_error(vm, "%*s", size, description);
3324
3325
0
    njs_vm_exception_get(vm, njs_value_arg(retval));
3326
3327
0
    if (errn != 0) {
3328
0
        njs_value_number_set(njs_value_arg(&value), errn);
3329
0
        ret = njs_vm_object_prop_set(vm, njs_value_arg(retval),
3330
0
                                     &string_errno, &value);
3331
0
        if (njs_slow_path(ret != NJS_OK)) {
3332
0
            return NJS_ERROR;
3333
0
        }
3334
3335
0
        code = njs_errno_string(errn);
3336
3337
0
        ret = njs_vm_value_string_create(vm, njs_value_arg(&value),
3338
0
                                         (u_char *) code, njs_strlen(code));
3339
0
        if (njs_slow_path(ret != NJS_OK)) {
3340
0
            return NJS_ERROR;
3341
0
        }
3342
3343
0
        ret = njs_vm_object_prop_set(vm, njs_value_arg(retval), &string_code,
3344
0
                                     &value);
3345
0
        if (njs_slow_path(ret != NJS_OK)) {
3346
0
            return NJS_ERROR;
3347
0
        }
3348
0
    }
3349
3350
0
    if (path != NULL) {
3351
0
        ret = njs_vm_value_string_create(vm, njs_value_arg(&value),
3352
0
                                         (u_char *) path, njs_strlen(path));
3353
0
        if (njs_slow_path(ret != NJS_OK)) {
3354
0
            return NJS_ERROR;
3355
0
        }
3356
3357
0
        ret = njs_vm_object_prop_set(vm, njs_value_arg(retval), &string_path,
3358
0
                                     &value);
3359
0
        if (njs_slow_path(ret != NJS_OK)) {
3360
0
            return NJS_ERROR;
3361
0
        }
3362
0
    }
3363
3364
0
    if (syscall != NULL) {
3365
0
        ret = njs_vm_value_string_create(vm, njs_value_arg(&value),
3366
0
                                         (u_char *) syscall,
3367
0
                                         njs_strlen(syscall));
3368
0
        if (njs_slow_path(ret != NJS_OK)) {
3369
0
            return NJS_ERROR;
3370
0
        }
3371
3372
0
        ret = njs_vm_object_prop_set(vm, njs_value_arg(retval), &string_syscall,
3373
0
                                     &value);
3374
0
        if (njs_slow_path(ret != NJS_OK)) {
3375
0
            return NJS_ERROR;
3376
0
        }
3377
0
    }
3378
3379
0
    return NJS_OK;
3380
0
}
3381
3382
3383
static njs_int_t
3384
ngx_fs_promise_trampoline(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
3385
    njs_index_t unused, njs_value_t *retval)
3386
0
{
3387
0
    njs_function_t  *callback;
3388
3389
0
    callback = njs_value_function(njs_argument(args, 1));
3390
3391
0
    return njs_vm_call(vm, callback, njs_argument(args, 2), 1);
3392
0
}
3393
3394
3395
static njs_int_t
3396
njs_fs_result(njs_vm_t *vm, njs_opaque_value_t *result, njs_index_t calltype,
3397
    const njs_value_t *callback, njs_uint_t nargs, njs_value_t *retval)
3398
0
{
3399
0
    njs_int_t           ret;
3400
0
    njs_function_t      *cb;
3401
0
    njs_opaque_value_t  promise, callbacks[2], arguments[2];
3402
3403
0
    switch (calltype) {
3404
0
    case NJS_FS_DIRECT:
3405
0
        if (njs_value_is_error(njs_value_arg(result))) {
3406
0
            njs_vm_throw(vm, njs_value_arg(result));
3407
0
            return NJS_ERROR;
3408
0
        }
3409
3410
0
        njs_value_assign(retval, result);
3411
0
        return NJS_OK;
3412
3413
0
    case NJS_FS_PROMISE:
3414
0
        ret = njs_vm_promise_create(vm, njs_value_arg(&promise),
3415
0
                                    njs_value_arg(&callbacks[0]));
3416
0
        if (njs_slow_path(ret != NJS_OK)) {
3417
0
            return ret;
3418
0
        }
3419
3420
0
        cb = njs_vm_function_alloc(vm, ngx_fs_promise_trampoline, 0, 0);
3421
0
        if (njs_slow_path(cb == NULL)) {
3422
0
            return NJS_ERROR;
3423
0
        }
3424
3425
0
        njs_value_assign(&arguments[0],
3426
0
                         &callbacks[njs_value_is_error(njs_value_arg(result))]);
3427
0
        njs_value_assign(&arguments[1], result);
3428
3429
0
        ret = njs_vm_enqueue_job(vm, cb, njs_value_arg(&arguments), 2);
3430
0
        if (njs_slow_path(ret == NJS_ERROR)) {
3431
0
            return NJS_ERROR;
3432
0
        }
3433
3434
0
        njs_value_assign(retval, &promise);
3435
3436
0
        return NJS_OK;
3437
3438
0
    case NJS_FS_CALLBACK:
3439
0
        if (njs_value_is_error(njs_value_arg(result))) {
3440
0
            njs_value_assign(&arguments[0], result);
3441
0
            njs_value_undefined_set(njs_value_arg(&arguments[1]));
3442
3443
0
        } else {
3444
0
            njs_value_undefined_set(njs_value_arg(&arguments[0]));
3445
0
            njs_value_assign(&arguments[1], result);
3446
0
        }
3447
3448
0
        ret = njs_vm_enqueue_job(vm, njs_value_function(callback),
3449
0
                                 njs_value_arg(&arguments), 2);
3450
0
        if (njs_slow_path(ret == NJS_ERROR)) {
3451
0
            return NJS_ERROR;
3452
0
        }
3453
3454
0
        njs_value_undefined_set(retval);
3455
3456
0
        return NJS_OK;
3457
3458
0
    default:
3459
0
        njs_vm_internal_error(vm, "invalid calltype");
3460
3461
0
        return NJS_ERROR;
3462
0
    }
3463
0
}
3464
3465
3466
static njs_int_t
3467
njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name, njs_value_t *type,
3468
    njs_value_t *retval)
3469
0
{
3470
0
    njs_int_t  ret;
3471
3472
0
    static const njs_str_t  string_name = njs_str("name");
3473
0
    static const njs_str_t  string_type = njs_str("type");
3474
3475
0
    ret = njs_vm_external_create(vm, retval, njs_fs_dirent_proto_id, NULL, 0);
3476
0
    if (njs_slow_path(ret != NJS_OK)) {
3477
0
        return ret;
3478
0
    }
3479
3480
0
    ret = njs_vm_object_prop_set(vm, retval, &string_name,
3481
0
                                 (njs_opaque_value_t *) name);
3482
0
    if (njs_slow_path(ret != NJS_OK)) {
3483
0
        return ret;
3484
0
    }
3485
3486
    /* TODO: use a private symbol as a key. */
3487
0
    return njs_vm_object_prop_set(vm, retval, &string_type,
3488
0
                                  (njs_opaque_value_t *) type);
3489
0
}
3490
3491
3492
static njs_int_t
3493
njs_fs_dirent_constructor(njs_vm_t *vm, njs_value_t *args,
3494
    njs_uint_t nargs, njs_index_t unused, njs_value_t *retval)
3495
0
{
3496
0
    if (njs_slow_path(!njs_vm_constructor(vm))) {
3497
0
        njs_vm_type_error(vm, "the Dirent constructor must be called with new");
3498
0
        return NJS_ERROR;
3499
0
    }
3500
3501
0
    return njs_fs_dirent_create(vm, njs_arg(args, nargs, 1),
3502
0
                                njs_arg(args, nargs, 2), retval);
3503
0
}
3504
3505
3506
static njs_int_t
3507
njs_fs_dirent_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
3508
    njs_index_t testtype, njs_value_t *retval)
3509
0
{
3510
0
    njs_value_t         *type;
3511
0
    njs_opaque_value_t  lvalue;
3512
3513
0
    static const njs_str_t  string_type = njs_str("type");
3514
3515
0
    type = njs_vm_object_prop(vm, njs_argument(args, 0), &string_type, &lvalue);
3516
0
    if (njs_slow_path(type == NULL)) {
3517
0
        return NJS_ERROR;
3518
0
    }
3519
3520
0
    if (njs_slow_path(njs_value_is_number(type)
3521
0
                      && (njs_value_number(type) == NJS_DT_INVALID)))
3522
0
    {
3523
0
        njs_vm_internal_error(vm, "dentry type is not supported on this "
3524
0
                              "platform");
3525
0
        return NJS_ERROR;
3526
0
    }
3527
3528
0
    njs_value_boolean_set(retval,
3529
0
                          njs_value_is_number(type)
3530
0
                          && testtype == njs_value_number(type));
3531
3532
0
    return NJS_OK;
3533
0
}
3534
3535
3536
static void
3537
njs_fs_to_stat(njs_stat_t *dst, struct stat *st)
3538
0
{
3539
0
    dst->st_dev = st->st_dev;
3540
0
    dst->st_mode = st->st_mode;
3541
0
    dst->st_nlink = st->st_nlink;
3542
0
    dst->st_uid = st->st_uid;
3543
0
    dst->st_gid = st->st_gid;
3544
0
    dst->st_rdev = st->st_rdev;
3545
0
    dst->st_ino = st->st_ino;
3546
0
    dst->st_size = st->st_size;
3547
0
    dst->st_blksize = st->st_blksize;
3548
0
    dst->st_blocks = st->st_blocks;
3549
3550
#if (NJS_HAVE_STAT_ATIMESPEC)
3551
3552
    dst->st_atim.tv_sec = st->st_atimespec.tv_sec;
3553
    dst->st_atim.tv_nsec = st->st_atimespec.tv_nsec;
3554
    dst->st_mtim.tv_sec = st->st_mtimespec.tv_sec;
3555
    dst->st_mtim.tv_nsec = st->st_mtimespec.tv_nsec;
3556
    dst->st_ctim.tv_sec = st->st_ctimespec.tv_sec;
3557
    dst->st_ctim.tv_nsec = st->st_ctimespec.tv_nsec;
3558
3559
#elif (NJS_HAVE_STAT_ATIM)
3560
3561
0
    dst->st_atim.tv_sec = st->st_atim.tv_sec;
3562
0
    dst->st_atim.tv_nsec = st->st_atim.tv_nsec;
3563
0
    dst->st_mtim.tv_sec = st->st_mtim.tv_sec;
3564
0
    dst->st_mtim.tv_nsec = st->st_mtim.tv_nsec;
3565
0
    dst->st_ctim.tv_sec = st->st_ctim.tv_sec;
3566
0
    dst->st_ctim.tv_nsec = st->st_ctim.tv_nsec;
3567
3568
#if (NJS_HAVE_STAT_BIRTHTIM)
3569
    dst->st_birthtim.tv_sec = st->st_birthtim.tv_sec;
3570
    dst->st_birthtim.tv_nsec = st->st_birthtim.tv_nsec;
3571
#elif (NJS_HAVE__STAT_BIRTHTIM)
3572
    dst->st_birthtim.tv_sec = st->__st_birthtim.tv_sec;
3573
    dst->st_birthtim.tv_nsec = st->__st_birthtim.tv_nsec;
3574
#else
3575
0
    dst->st_birthtim.tv_sec = st->st_ctim.tv_sec;
3576
0
    dst->st_birthtim.tv_nsec = st->st_ctim.tv_nsec;
3577
0
#endif
3578
3579
#else
3580
3581
  dst->st_atim.tv_sec = st->st_atime;
3582
  dst->st_atim.tv_nsec = 0;
3583
  dst->st_mtim.tv_sec = st->st_mtime;
3584
  dst->st_mtim.tv_nsec = 0;
3585
  dst->st_ctim.tv_sec = st->st_ctime;
3586
  dst->st_ctim.tv_nsec = 0;
3587
  dst->st_birthtim.tv_sec = st->st_ctime;
3588
  dst->st_birthtim.tv_nsec = 0;
3589
3590
#endif
3591
0
}
3592
3593
3594
static njs_int_t
3595
njs_fs_stats_create(njs_vm_t *vm, struct stat *st, njs_value_t *retval)
3596
0
{
3597
0
    njs_stat_t  *stat;
3598
3599
0
    stat = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(njs_stat_t));
3600
0
    if (njs_slow_path(stat == NULL)) {
3601
0
        njs_vm_memory_error(vm);
3602
0
        return NJS_ERROR;
3603
0
    }
3604
3605
0
    njs_fs_to_stat(stat, st);
3606
3607
0
    return njs_vm_external_create(vm, retval, njs_fs_stats_proto_id,
3608
0
                                  stat, 0);
3609
0
}
3610
3611
3612
static njs_int_t
3613
njs_fs_stats_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
3614
    njs_index_t testtype, njs_value_t *retval)
3615
0
{
3616
0
    unsigned    mask;
3617
0
    njs_stat_t  *st;
3618
3619
0
    st = njs_vm_external(vm, njs_fs_stats_proto_id, njs_argument(args, 0));
3620
0
    if (njs_slow_path(st == NULL)) {
3621
0
        return NJS_DECLINED;
3622
0
    }
3623
3624
0
    switch (testtype) {
3625
0
    case DT_DIR:
3626
0
        mask = S_IFDIR;
3627
0
        break;
3628
3629
0
    case DT_REG:
3630
0
        mask = S_IFREG;
3631
0
        break;
3632
3633
0
    case DT_CHR:
3634
0
        mask = S_IFCHR;
3635
0
        break;
3636
3637
0
    case DT_LNK:
3638
0
        mask = S_IFLNK;
3639
0
        break;
3640
3641
0
    case DT_BLK:
3642
0
        mask = S_IFBLK;
3643
0
        break;
3644
3645
0
    case DT_FIFO:
3646
0
        mask = S_IFIFO;
3647
0
        break;
3648
3649
0
    case DT_SOCK:
3650
0
    default:
3651
0
        mask = S_IFSOCK;
3652
0
    }
3653
3654
0
    njs_value_boolean_set(retval, (st->st_mode & S_IFMT) == mask);
3655
3656
0
    return NJS_OK;
3657
0
}
3658
3659
3660
static njs_int_t
3661
njs_fs_stats_prop(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused,
3662
    njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
3663
0
{
3664
0
    double      v;
3665
0
    njs_int_t   ret;
3666
0
    njs_stat_t  *st;
3667
3668
0
#define njs_fs_time_ms(ts) ((ts)->tv_sec * 1000.0 + (ts)->tv_nsec / 1000000.0)
3669
3670
0
    st = njs_vm_external(vm, njs_fs_stats_proto_id, value);
3671
0
    if (njs_slow_path(st == NULL)) {
3672
0
        return NJS_DECLINED;
3673
0
    }
3674
3675
0
    switch (njs_vm_prop_magic32(prop) & 0xf) {
3676
0
    case NJS_FS_STAT_DEV:
3677
0
        v = st->st_dev;
3678
0
        break;
3679
3680
0
    case NJS_FS_STAT_INO:
3681
0
        v = st->st_ino;
3682
0
        break;
3683
3684
0
    case NJS_FS_STAT_MODE:
3685
0
        v = st->st_mode;
3686
0
        break;
3687
3688
0
    case NJS_FS_STAT_NLINK:
3689
0
        v = st->st_nlink;
3690
0
        break;
3691
3692
0
    case NJS_FS_STAT_UID:
3693
0
        v = st->st_uid;
3694
0
        break;
3695
3696
0
    case NJS_FS_STAT_GID:
3697
0
        v = st->st_gid;
3698
0
        break;
3699
3700
0
    case NJS_FS_STAT_RDEV:
3701
0
        v = st->st_rdev;
3702
0
        break;
3703
3704
0
    case NJS_FS_STAT_SIZE:
3705
0
        v = st->st_size;
3706
0
        break;
3707
3708
0
    case NJS_FS_STAT_BLKSIZE:
3709
0
        v = st->st_blksize;
3710
0
        break;
3711
3712
0
    case NJS_FS_STAT_BLOCKS:
3713
0
        v = st->st_blocks;
3714
0
        break;
3715
3716
0
    case NJS_FS_STAT_ATIME:
3717
0
        v = njs_fs_time_ms(&st->st_atim);
3718
0
        break;
3719
3720
0
    case NJS_FS_STAT_BIRTHTIME:
3721
0
        v = njs_fs_time_ms(&st->st_birthtim);
3722
0
        break;
3723
3724
0
    case NJS_FS_STAT_CTIME:
3725
0
        v = njs_fs_time_ms(&st->st_ctim);
3726
0
        break;
3727
3728
0
    case NJS_FS_STAT_MTIME:
3729
0
    default:
3730
0
        v = njs_fs_time_ms(&st->st_mtim);
3731
0
        break;
3732
0
    }
3733
3734
0
    switch (njs_vm_prop_magic32(prop) >> 4) {
3735
0
    case 0:
3736
0
        njs_value_number_set(retval, v);
3737
0
        break;
3738
3739
0
    case 1:
3740
0
    default:
3741
0
        ret = njs_vm_date_alloc(vm, retval, v);
3742
0
        if (njs_slow_path(ret != NJS_OK)) {
3743
0
            return NJS_ERROR;
3744
0
        }
3745
3746
0
        break;
3747
0
    }
3748
3749
0
    return NJS_OK;
3750
0
}
3751
3752
3753
static njs_int_t
3754
njs_fs_filehandle_close(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
3755
    njs_index_t unused, njs_value_t *retval)
3756
0
{
3757
0
    njs_filehandle_t    *fh;
3758
0
    njs_opaque_value_t  result;
3759
3760
0
    fh = njs_vm_external(vm, njs_fs_filehandle_proto_id, njs_argument(args, 0));
3761
0
    if (njs_slow_path(fh == NULL)) {
3762
0
        njs_vm_type_error(vm, "\"this\" is not a filehandle object");
3763
0
        return NJS_ERROR;
3764
0
    }
3765
3766
0
    if (njs_slow_path(fh->fd == -1)) {
3767
0
        njs_vm_error(vm, "file was already closed");
3768
0
        return NJS_ERROR;
3769
0
    }
3770
3771
0
    (void) close(fh->fd);
3772
0
    fh->fd = -1;
3773
3774
0
    njs_value_undefined_set(njs_value_arg(&result));
3775
3776
0
    return njs_fs_result(vm, &result, NJS_FS_PROMISE, NULL, 1, retval);
3777
0
}
3778
3779
3780
static njs_int_t
3781
njs_fs_filehandle_value_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
3782
    njs_index_t unused, njs_value_t *retval)
3783
0
{
3784
0
    njs_filehandle_t  *fh;
3785
3786
0
    fh = njs_vm_external(vm, njs_fs_filehandle_proto_id, njs_argument(args, 0));
3787
0
    if (njs_slow_path(fh == NULL)) {
3788
0
        njs_vm_type_error(vm, "\"this\" is not a filehandle object");
3789
0
        return NJS_ERROR;
3790
0
    }
3791
3792
0
    njs_value_number_set(retval, fh->fd);
3793
3794
0
    return NJS_OK;
3795
0
}
3796
3797
3798
static void
3799
njs_fs_filehandle_cleanup(void *data)
3800
0
{
3801
0
    njs_filehandle_t  *fh = data;
3802
3803
0
    if (fh->vm != NULL && fh->fd != -1) {
3804
0
        (void) close(fh->fd);
3805
0
    }
3806
0
}
3807
3808
3809
static njs_int_t
3810
njs_fs_filehandle_create(njs_vm_t *vm, int fd, njs_bool_t shadow,
3811
    njs_opaque_value_t *retval)
3812
0
{
3813
0
    njs_filehandle_t  *fh;
3814
0
    njs_mp_cleanup_t  *cln;
3815
3816
0
    fh = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(njs_filehandle_t));
3817
0
    if (njs_slow_path(fh == NULL)) {
3818
0
        njs_vm_memory_error(vm);
3819
0
        return NJS_ERROR;
3820
0
    }
3821
3822
0
    fh->fd = fd;
3823
0
    fh->vm = !shadow ? vm : NULL;
3824
3825
0
    cln = njs_mp_cleanup_add(njs_vm_memory_pool(vm), 0);
3826
0
    if (cln == NULL) {
3827
0
        njs_vm_memory_error(vm);
3828
0
        return NJS_ERROR;
3829
0
    }
3830
3831
0
    cln->handler = njs_fs_filehandle_cleanup;
3832
0
    cln->data = fh;
3833
3834
0
    return njs_vm_external_create(vm, njs_value_arg(retval),
3835
0
                                  njs_fs_filehandle_proto_id, fh, 0);
3836
0
}
3837
3838
3839
static njs_int_t
3840
njs_fs_bytes_read_create(njs_vm_t *vm, int bytes, njs_value_t *buffer,
3841
    njs_opaque_value_t *retval)
3842
0
{
3843
0
    njs_bytes_struct_t  *bs;
3844
3845
0
    bs = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(njs_bytes_struct_t));
3846
0
    if (njs_slow_path(bs == NULL)) {
3847
0
        njs_vm_memory_error(vm);
3848
0
        return NJS_ERROR;
3849
0
    }
3850
3851
0
    bs->bytes = bytes;
3852
0
    njs_value_assign(&bs->buffer, buffer);
3853
3854
0
    return njs_vm_external_create(vm, njs_value_arg(retval),
3855
0
                                  njs_fs_bytes_read_proto_id, bs, 0);
3856
0
}
3857
3858
3859
static njs_int_t
3860
njs_fs_bytes_written_create(njs_vm_t *vm, int bytes, njs_value_t *buffer,
3861
    njs_opaque_value_t *retval)
3862
0
{
3863
0
    njs_bytes_struct_t  *bs;
3864
3865
0
    bs = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(njs_bytes_struct_t));
3866
0
    if (njs_slow_path(bs == NULL)) {
3867
0
        njs_vm_memory_error(vm);
3868
0
        return NJS_ERROR;
3869
0
    }
3870
3871
0
    bs->bytes = bytes;
3872
0
    njs_value_assign(&bs->buffer, buffer);
3873
3874
0
    return njs_vm_external_create(vm, njs_value_arg(retval),
3875
0
                                  njs_fs_bytes_written_proto_id, bs, 0);
3876
0
}
3877
3878
3879
njs_int_t
3880
njs_fs_constant(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused,
3881
    njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
3882
0
{
3883
0
    njs_value_number_set(retval,  njs_vm_prop_magic32(prop));
3884
3885
0
    return NJS_OK;
3886
0
}
3887
3888
3889
static njs_int_t
3890
njs_fs_init(njs_vm_t *vm)
3891
9.30k
{
3892
9.30k
    njs_int_t           ret, proto_id;
3893
9.30k
    njs_mod_t           *module;
3894
9.30k
    njs_opaque_value_t  value;
3895
3896
9.30k
    if (njs_vm_options(vm)->sandbox) {
3897
0
        return NJS_OK;
3898
0
    }
3899
3900
9.30k
    njs_fs_stats_proto_id = njs_vm_external_prototype(vm, njs_ext_stats,
3901
9.30k
                                                    njs_nitems(njs_ext_stats));
3902
9.30k
    if (njs_slow_path(njs_fs_stats_proto_id < 0)) {
3903
0
        return NJS_ERROR;
3904
0
    }
3905
3906
9.30k
    njs_fs_dirent_proto_id = njs_vm_external_prototype(vm, njs_ext_dirent,
3907
9.30k
                                                   njs_nitems(njs_ext_dirent));
3908
9.30k
    if (njs_slow_path(njs_fs_dirent_proto_id < 0)) {
3909
0
        return NJS_ERROR;
3910
0
    }
3911
3912
9.30k
    njs_fs_filehandle_proto_id = njs_vm_external_prototype(vm,
3913
9.30k
                                               njs_ext_filehandle,
3914
9.30k
                                               njs_nitems(njs_ext_filehandle));
3915
9.30k
    if (njs_slow_path(njs_fs_filehandle_proto_id < 0)) {
3916
0
        return NJS_ERROR;
3917
0
    }
3918
3919
9.30k
    njs_fs_bytes_read_proto_id = njs_vm_external_prototype(vm,
3920
9.30k
                                               njs_ext_bytes_read,
3921
9.30k
                                               njs_nitems(njs_ext_bytes_read));
3922
9.30k
    if (njs_slow_path(njs_fs_bytes_written_proto_id < 0)) {
3923
0
        return NJS_ERROR;
3924
0
    }
3925
3926
9.30k
    njs_fs_bytes_written_proto_id = njs_vm_external_prototype(vm,
3927
9.30k
                                             njs_ext_bytes_written,
3928
9.30k
                                             njs_nitems(njs_ext_bytes_written));
3929
9.30k
    if (njs_slow_path(njs_fs_bytes_written_proto_id < 0)) {
3930
0
        return NJS_ERROR;
3931
0
    }
3932
3933
9.30k
    proto_id = njs_vm_external_prototype(vm, njs_ext_fs,
3934
9.30k
                                         njs_nitems(njs_ext_fs));
3935
9.30k
    if (njs_slow_path(proto_id < 0)) {
3936
0
        return NJS_ERROR;
3937
0
    }
3938
3939
9.30k
    ret = njs_vm_external_create(vm, njs_value_arg(&value), proto_id, NULL, 1);
3940
9.30k
    if (njs_slow_path(ret != NJS_OK)) {
3941
0
        return NJS_ERROR;
3942
0
    }
3943
3944
9.30k
    module = njs_vm_add_module(vm, &njs_str_value("fs"), njs_value_arg(&value));
3945
9.30k
    if (njs_slow_path(module == NULL)) {
3946
0
        return NJS_ERROR;
3947
0
    }
3948
3949
9.30k
    return NJS_OK;
3950
9.30k
}