1use ::std::cell::{Cell, RefCell};
3use ::std::collections::{HashMap, VecDeque};
4use ::std::fs;
5use ::std::path::{Path, PathBuf};
6use ::std::sync::{Arc, Mutex};
7use bao_engine::context::RawValueRootGuard;
8use bun_core::ZBox;
9use bun_sys::fs as bun_fs;
10use mozjs::glue::NewCompileOptions;
13use mozjs::jsapi::*;
14use mozjs::jsval::{DoubleValue, Int32Value, JSVal, StringValue, UndefinedValue};
15use mozjs::rooted;
16use mozjs::rust::wrappers2 as w2;
17
18use crate::require::cache_builtin;
19
20#[allow(dead_code)]
26struct StatfsResult {
27 type_: u64,
28 bsize: u64,
29 #[allow(dead_code)]
30 frsize: u64,
31 blocks: u64,
32 bfree: u64,
33 bavail: u64,
34 files: u64,
35 ffree: u64,
36}
37
38#[allow(dead_code)]
39enum FsAsyncResult {
40 Ok(Vec<u8>),
41 OkStat(bun_sys::PosixStat),
42 OkString(String),
43 OkVoid,
44 OkBool(bool),
45 OkI32(i32),
46 OkOpen(i32),
47 OkRead { bytes_read: i32, buffer: Vec<u8> },
48 OkWrite(i32),
49 OkDirnames(Vec<String>),
50 OkStatfs(StatfsResult),
51 OkDirents(Vec<(String, bool)>),
52}
53
54struct FsAsyncCtx {
55 cx: *mut JSContext,
56 callback: *mut JSObject,
60 cb_root: Option<RawValueRootGuard>,
64 result: Arc<Mutex<Option<::std::result::Result<FsAsyncResult, (String, String)>>>>,
65 encoding: Option<String>,
66 op_name: String,
67 path: String,
68}
69
70unsafe fn schedule_defer(ctx: *mut FsAsyncCtx) {
71 bao_uloop::force_link();
72 let loop_ = bao_uloop::uws_get_loop();
73 if loop_.is_null() {
74 let _ = Box::from_raw(ctx);
75 return;
76 }
77 bao_uloop::uws_loop_defer(
78 loop_,
79 ctx as *mut ::std::ffi::c_void,
80 fs_async_defer_callback,
81 );
82}
83
84unsafe extern "C" fn fs_async_defer_callback(raw_ctx: *mut ::std::ffi::c_void) {
85 let ctx = Box::from_raw(raw_ctx as *mut FsAsyncCtx);
86 let cx = ctx.cx;
87 let cb_value = ctx.cb_root.as_ref().map_or_else(
90 || mozjs::jsval::ObjectValue(ctx.callback),
91 |g| g.get(0),
92 );
93 let encoding = ctx.encoding.as_deref();
94 let _op_name = &ctx.op_name;
95
96 let mut result_guard = ctx.result.lock().unwrap();
97 let result_opt = result_guard.take();
98 ::std::mem::drop(result_guard);
99
100 let mut wrapped_cx =
101 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
102 let cx_ref = &mut wrapped_cx;
103
104 rooted!(&in(cx_ref) let cb_val = cb_value);
105 let global = CurrentGlobalOrNull(cx);
106 if global.is_null() {
107 return;
108 }
109 rooted!(&in(cx_ref) let global_rooted = global);
110
111 match result_opt {
112 Some(Ok(FsAsyncResult::Ok(data))) => {
113 let val = string_or_buffer(cx, &data, encoding);
114 rooted!(&in(cx_ref) let val_rooted = val);
115 let args_arr = [UndefinedValue(), val_rooted.get()];
116 let cb_args = HandleValueArray {
117 length_: 2,
118 elements_: args_arr.as_ptr(),
119 };
120 let mut rval = UndefinedValue();
121 JS_CallFunctionValue(
122 cx,
123 global_rooted.handle().into(),
124 cb_val.handle().into(),
125 &cb_args,
126 MutableHandle::<Value> {
127 _phantom_0: ::std::marker::PhantomData,
128 ptr: &mut rval,
129 },
130 );
131 JS_ClearPendingException(cx);
132 }
133 Some(Ok(FsAsyncResult::OkStat(stat))) => {
134 let stats_obj = create_stats_object(cx, &stat);
135 rooted!(&in(cx_ref) let stats_val = mozjs::jsval::ObjectValue(stats_obj));
136 let args_arr = [UndefinedValue(), stats_val.get()];
137 let cb_args = HandleValueArray {
138 length_: 2,
139 elements_: args_arr.as_ptr(),
140 };
141 let mut rval = UndefinedValue();
142 JS_CallFunctionValue(
143 cx,
144 global_rooted.handle().into(),
145 cb_val.handle().into(),
146 &cb_args,
147 MutableHandle::<Value> {
148 _phantom_0: ::std::marker::PhantomData,
149 ptr: &mut rval,
150 },
151 );
152 JS_ClearPendingException(cx);
153 }
154 Some(Ok(FsAsyncResult::OkString(s))) => {
155 let c_str = ZBox::from_bytes(s.as_bytes());
156 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
157 let val = if js_str.is_null() {
158 UndefinedValue()
159 } else {
160 mozjs::jsval::StringValue(&*js_str)
161 };
162 rooted!(&in(cx_ref) let val_rooted = val);
163 let args_arr = [UndefinedValue(), val_rooted.get()];
164 let cb_args = HandleValueArray {
165 length_: 2,
166 elements_: args_arr.as_ptr(),
167 };
168 let mut rval = UndefinedValue();
169 JS_CallFunctionValue(
170 cx,
171 global_rooted.handle().into(),
172 cb_val.handle().into(),
173 &cb_args,
174 MutableHandle::<Value> {
175 _phantom_0: ::std::marker::PhantomData,
176 ptr: &mut rval,
177 },
178 );
179 JS_ClearPendingException(cx);
180 }
181 Some(Ok(FsAsyncResult::OkVoid)) => {
182 let args_arr = [UndefinedValue()];
183 let cb_args = HandleValueArray {
184 length_: 1,
185 elements_: args_arr.as_ptr(),
186 };
187 let mut rval = UndefinedValue();
188 JS_CallFunctionValue(
189 cx,
190 global_rooted.handle().into(),
191 cb_val.handle().into(),
192 &cb_args,
193 MutableHandle::<Value> {
194 _phantom_0: ::std::marker::PhantomData,
195 ptr: &mut rval,
196 },
197 );
198 JS_ClearPendingException(cx);
199 }
200 Some(Ok(FsAsyncResult::OkBool(b))) => {
201 rooted!(&in(cx_ref) let val = mozjs::jsval::BooleanValue(b));
202 let args_arr = [UndefinedValue(), val.get()];
203 let cb_args = HandleValueArray {
204 length_: 2,
205 elements_: args_arr.as_ptr(),
206 };
207 let mut rval = UndefinedValue();
208 JS_CallFunctionValue(
209 cx,
210 global_rooted.handle().into(),
211 cb_val.handle().into(),
212 &cb_args,
213 MutableHandle::<Value> {
214 _phantom_0: ::std::marker::PhantomData,
215 ptr: &mut rval,
216 },
217 );
218 JS_ClearPendingException(cx);
219 }
220 Some(Ok(FsAsyncResult::OkI32(v))) => {
221 rooted!(&in(cx_ref) let val = mozjs::jsval::Int32Value(v));
222 let args_arr = [UndefinedValue(), val.get()];
223 let cb_args = HandleValueArray {
224 length_: 2,
225 elements_: args_arr.as_ptr(),
226 };
227 let mut rval = UndefinedValue();
228 JS_CallFunctionValue(
229 cx,
230 global_rooted.handle().into(),
231 cb_val.handle().into(),
232 &cb_args,
233 MutableHandle::<Value> {
234 _phantom_0: ::std::marker::PhantomData,
235 ptr: &mut rval,
236 },
237 );
238 JS_ClearPendingException(cx);
239 }
240 Some(Ok(FsAsyncResult::OkOpen(fd))) => {
241 rooted!(&in(cx_ref) let val = mozjs::jsval::Int32Value(fd));
242 let args_arr = [UndefinedValue(), val.get()];
243 let cb_args = HandleValueArray {
244 length_: 2,
245 elements_: args_arr.as_ptr(),
246 };
247 let mut rval = UndefinedValue();
248 JS_CallFunctionValue(
249 cx,
250 global_rooted.handle().into(),
251 cb_val.handle().into(),
252 &cb_args,
253 MutableHandle::<Value> {
254 _phantom_0: ::std::marker::PhantomData,
255 ptr: &mut rval,
256 },
257 );
258 JS_ClearPendingException(cx);
259 }
260 Some(Ok(FsAsyncResult::OkRead { bytes_read, buffer })) => {
261 let buf_obj = crate::globals::create_buffer_object(cx, &buffer);
262 let buf_val = if buf_obj.is_null() {
263 UndefinedValue()
264 } else {
265 mozjs::jsval::ObjectValue(buf_obj)
266 };
267 rooted!(&in(cx_ref) let buf_rooted = buf_val);
268 rooted!(&in(cx_ref) let br_val = mozjs::jsval::Int32Value(bytes_read));
269 let args_arr = [UndefinedValue(), br_val.get(), buf_rooted.get()];
270 let cb_args = HandleValueArray {
271 length_: 3,
272 elements_: args_arr.as_ptr(),
273 };
274 let mut rval = UndefinedValue();
275 JS_CallFunctionValue(
276 cx,
277 global_rooted.handle().into(),
278 cb_val.handle().into(),
279 &cb_args,
280 MutableHandle::<Value> {
281 _phantom_0: ::std::marker::PhantomData,
282 ptr: &mut rval,
283 },
284 );
285 JS_ClearPendingException(cx);
286 }
287 Some(Ok(FsAsyncResult::OkWrite(written))) => {
288 rooted!(&in(cx_ref) let val = mozjs::jsval::Int32Value(written));
289 let args_arr = [UndefinedValue(), val.get()];
290 let cb_args = HandleValueArray {
291 length_: 2,
292 elements_: args_arr.as_ptr(),
293 };
294 let mut rval = UndefinedValue();
295 JS_CallFunctionValue(
296 cx,
297 global_rooted.handle().into(),
298 cb_val.handle().into(),
299 &cb_args,
300 MutableHandle::<Value> {
301 _phantom_0: ::std::marker::PhantomData,
302 ptr: &mut rval,
303 },
304 );
305 JS_ClearPendingException(cx);
306 }
307 Some(Ok(FsAsyncResult::OkDirnames(names))) => {
308 rooted!(&in(cx_ref) let arr = w2::NewArrayObject1(cx_ref, names.len()));
309 if !arr.get().is_null() {
310 for (idx, name) in names.iter().enumerate() {
311 let c_name = ZBox::from_bytes(name.as_bytes());
312 let js_str = JS_NewStringCopyZ(cx, c_name.as_ptr());
313 if !js_str.is_null() {
314 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
315 JS_DefineElement(
316 cx,
317 arr.handle().into(),
318 idx as u32,
319 val.handle().into(),
320 JSPROP_ENUMERATE as u32,
321 );
322 }
323 }
324 }
325 rooted!(&in(cx_ref) let arr_val = mozjs::jsval::ObjectValue(arr.get()));
326 let args_arr = [UndefinedValue(), arr_val.get()];
327 let cb_args = HandleValueArray {
328 length_: 2,
329 elements_: args_arr.as_ptr(),
330 };
331 let mut rval = UndefinedValue();
332 JS_CallFunctionValue(
333 cx,
334 global_rooted.handle().into(),
335 cb_val.handle().into(),
336 &cb_args,
337 MutableHandle::<Value> {
338 _phantom_0: ::std::marker::PhantomData,
339 ptr: &mut rval,
340 },
341 );
342 JS_ClearPendingException(cx);
343 }
344 Some(Ok(FsAsyncResult::OkDirents(entries))) => {
345 rooted!(&in(cx_ref) let arr = w2::NewArrayObject1(cx_ref, entries.len()));
346 if !arr.get().is_null() {
347 for (idx, (name, is_dir)) in entries.iter().enumerate() {
348 let dirent = create_dirent(cx, name, *is_dir);
349 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(dirent));
350 JS_DefineElement(
351 cx,
352 arr.handle().into(),
353 idx as u32,
354 val.handle().into(),
355 JSPROP_ENUMERATE as u32,
356 );
357 }
358 }
359 rooted!(&in(cx_ref) let arr_val = mozjs::jsval::ObjectValue(arr.get()));
360 let args_arr = [UndefinedValue(), arr_val.get()];
361 let cb_args = HandleValueArray {
362 length_: 2,
363 elements_: args_arr.as_ptr(),
364 };
365 let mut rval = UndefinedValue();
366 JS_CallFunctionValue(
367 cx,
368 global_rooted.handle().into(),
369 cb_val.handle().into(),
370 &cb_args,
371 MutableHandle::<Value> {
372 _phantom_0: ::std::marker::PhantomData,
373 ptr: &mut rval,
374 },
375 );
376 JS_ClearPendingException(cx);
377 }
378 Some(Ok(FsAsyncResult::OkStatfs(sf))) => {
379 let stats_obj = create_statfs_object(cx, &sf);
380 rooted!(&in(cx_ref) let stats_val = mozjs::jsval::ObjectValue(stats_obj));
381 let args_arr = [UndefinedValue(), stats_val.get()];
382 let cb_args = HandleValueArray {
383 length_: 2,
384 elements_: args_arr.as_ptr(),
385 };
386 let mut rval = UndefinedValue();
387 JS_CallFunctionValue(
388 cx,
389 global_rooted.handle().into(),
390 cb_val.handle().into(),
391 &cb_args,
392 MutableHandle::<Value> {
393 _phantom_0: ::std::marker::PhantomData,
394 ptr: &mut rval,
395 },
396 );
397 JS_ClearPendingException(cx);
398 }
399 Some(Err((code, msg))) => {
400 rooted!(&in(cx_ref) let err_obj = JS_NewPlainObject(cx));
401 if !err_obj.get().is_null() {
402 let c_msg = ZBox::from_bytes(msg.as_bytes());
403 let js_str = JS_NewStringCopyZ(cx, c_msg.as_ptr());
404 if !js_str.is_null() {
405 rooted!(&in(cx_ref) let msg_val = mozjs::jsval::StringValue(&*js_str));
406 JS_DefineProperty(
407 cx,
408 err_obj.handle().into(),
409 c"message".as_ptr(),
410 msg_val.handle().into(),
411 JSPROP_ENUMERATE as u32,
412 );
413 }
414 let c_code = ZBox::from_bytes(code.as_bytes());
415 let code_str = JS_NewStringCopyZ(cx, c_code.as_ptr());
416 if !code_str.is_null() {
417 rooted!(&in(cx_ref) let code_val = mozjs::jsval::StringValue(&*code_str));
418 JS_DefineProperty(
419 cx,
420 err_obj.handle().into(),
421 c"code".as_ptr(),
422 code_val.handle().into(),
423 JSPROP_ENUMERATE as u32,
424 );
425 }
426 let c_path = ZBox::from_bytes(ctx.path.as_bytes());
427 let path_str = JS_NewStringCopyZ(cx, c_path.as_ptr());
428 if !path_str.is_null() {
429 rooted!(&in(cx_ref) let path_val = mozjs::jsval::StringValue(&*path_str));
430 JS_DefineProperty(
431 cx,
432 err_obj.handle().into(),
433 c"path".as_ptr(),
434 path_val.handle().into(),
435 JSPROP_ENUMERATE as u32,
436 );
437 }
438 }
439 rooted!(&in(cx_ref) let err_val = mozjs::jsval::ObjectValue(err_obj.get()));
440 let args_arr = [err_val.get()];
441 let cb_args = HandleValueArray {
442 length_: 1,
443 elements_: args_arr.as_ptr(),
444 };
445 let mut rval = UndefinedValue();
446 JS_CallFunctionValue(
447 cx,
448 global_rooted.handle().into(),
449 cb_val.handle().into(),
450 &cb_args,
451 MutableHandle::<Value> {
452 _phantom_0: ::std::marker::PhantomData,
453 ptr: &mut rval,
454 },
455 );
456 JS_ClearPendingException(cx);
457 }
458 None => {
459 let null_args = HandleValueArray::empty();
460 let mut rval = UndefinedValue();
461 JS_CallFunctionValue(
462 cx,
463 global_rooted.handle().into(),
464 cb_val.handle().into(),
465 &null_args,
466 MutableHandle::<Value> {
467 _phantom_0: ::std::marker::PhantomData,
468 ptr: &mut rval,
469 },
470 );
471 JS_ClearPendingException(cx);
472 }
473 }
474 }
479
480#[allow(unsafe_op_in_unsafe_fn)]
481unsafe fn extract_callback_and_encoding(
482 cx: *mut JSContext,
483 args: &CallArgs,
484 start_idx: u32,
485) -> Option<(*mut JSObject, Option<String>)> {
486 let mut cb_idx = None;
487 let mut encoding = None;
488 for i in start_idx..args.argc_ {
489 let val = *args.get(i).ptr;
490 if val.is_object() {
491 if cb_idx.is_none() {
492 cb_idx = Some(i);
493 } else if encoding.is_none() {
494 encoding = get_encoding_opt(cx, args, i);
495 }
496 } else if val.is_string() && encoding.is_none() {
497 encoding = Some(crate::jsstr_to_rust_string(cx, val.to_string()));
498 }
499 }
500 cb_idx.map(|idx| ((*args.get(idx).ptr).to_object(), encoding))
501}
502
503fn io_error_code(err: &::std::io::Error) -> &'static str {
504 match err.kind() {
505 ::std::io::ErrorKind::NotFound => "ENOENT",
506 ::std::io::ErrorKind::PermissionDenied => "EACCES",
507 ::std::io::ErrorKind::AlreadyExists => "EEXIST",
508 _ => "ERR",
509 }
510}
511
512#[allow(unsafe_op_in_unsafe_fn)]
513unsafe fn spawn_fs_async<F>(
514 cx: *mut JSContext,
515 op_name: &str,
516 path: String,
517 callback: *mut JSObject,
518 encoding: Option<String>,
519 work: F,
520) where
521 F: FnOnce() -> ::std::result::Result<FsAsyncResult, ::std::io::Error> + Send + 'static,
522{
523 let cb_val = mozjs::jsval::ObjectValue(callback);
527 let cb_root = unsafe {
528 RawValueRootGuard::new(cx, ::std::slice::from_ref(&cb_val), c"fs_async_cb")
529 };
530
531 let result_slot: Arc<Mutex<Option<::std::result::Result<FsAsyncResult, (String, String)>>>> =
532 Arc::new(Mutex::new(None));
533 let result_slot_clone = result_slot.clone();
534
535 let op_name_owned = op_name.to_string();
536 let path_for_err = path.clone();
537
538 let ctx = Box::new(FsAsyncCtx {
539 cx,
540 callback,
541 cb_root,
542 result: result_slot,
543 encoding,
544 op_name: op_name.to_string(),
545 path,
546 });
547 let ctx_ptr = Box::into_raw(ctx) as usize;
548
549 ::std::thread::spawn(move || {
550 let result = work();
551 let stored = match result {
552 Ok(v) => Ok(v),
553 Err(e) => {
554 let code = io_error_code(&e).to_string();
555 let msg = format!("{} '{}': {}", op_name_owned, path_for_err, e);
556 Err((code, msg))
557 }
558 };
559 {
560 let mut slot = result_slot_clone.lock().unwrap();
561 *slot = Some(stored);
562 }
563 schedule_defer(ctx_ptr as *mut FsAsyncCtx);
564 });
565}
566
567const FS_STREAM_JS: &str = r#"
568(function() {
569 var fs = globalThis.__fs_stream_ref;
570 var flush = globalThis.__bao_fs_stream_flush;
571
572 function EE() { this._events = {}; }
573 EE.prototype.on = function(e, fn) {
574 (this._events[e] || (this._events[e] = [])).push(fn);
575 return this;
576 };
577 EE.prototype.emit = function(e) {
578 var a = Array.prototype.slice.call(arguments, 1);
579 var ls = this._events[e];
580 if (ls) for (var i = 0; i < ls.length; i++) ls[i].apply(this, a);
581 return !!ls;
582 };
583
584 function createReadStream(path, opts) {
585 var s = new EE();
586 s.path = path;
587 s.readable = true;
588 s.writable = false;
589 s.bytesRead = 0;
590 var encoding = (opts && opts.encoding) || null;
591 try {
592 var data = fs.readFileSync(path, encoding);
593 s.bytesRead = (typeof data === 'string') ? data.length : 0;
594 setTimeout(function() {
595 s.emit('open', 0);
596 if (data) s.emit('data', data);
597 s.emit('end');
598 s.emit('close');
599 }, 0);
600 } catch(e) {
601 setTimeout(function() { s.emit('error', e); }, 0);
602 }
603 s.pipe = function(dest) {
604 this.on('data', function(c) { dest.write(c); });
605 this.on('end', function() { dest.end(); });
606 return dest;
607 };
608 s.destroy = function() { this.readable = false; this.emit('close'); return this; };
609 return s;
610 }
611
612 function createWriteStream(path, opts) {
613 var s = new EE();
614 s.path = path;
615 s.readable = false;
616 s.writable = true;
617 s.bytesWritten = 0;
618 s._buffer = [];
619 s._ended = false;
620 setTimeout(function() { s.emit('open', 0); }, 0);
621 s.write = function(chunk) {
622 if (this._ended) return false;
623 // Keep chunks RAW: strings stay strings, Buffer/TypedArray chunks stay
624 // binary views (flush extracts their bytes natively). Non-string
625 // non-object primitives keep the legacy String() coercion.
626 if (typeof chunk !== 'string' && typeof chunk !== 'object') chunk = String(chunk);
627 this._buffer.push(chunk);
628 this.bytesWritten += (chunk && chunk.length) || 0;
629 return true;
630 };
631 s.end = function(chunk) {
632 if (chunk) {
633 if (typeof chunk !== 'string' && typeof chunk !== 'object') chunk = String(chunk);
634 this._buffer.push(chunk);
635 this.bytesWritten += (chunk && chunk.length) || 0;
636 }
637 this._ended = true;
638 this.writable = false;
639 try {
640 // Binary-safe flush: string chunks → UTF-8 bytes (byte-identical to
641 // the old join('') + writeFileSync(string)); view chunks → raw bytes.
642 flush(this.path, this._buffer);
643 this.emit('finish');
644 } catch(e) {
645 this.emit('error', e);
646 }
647 this.emit('close');
648 return this;
649 };
650 s.destroy = function() { this.writable = false; this.emit('close'); return this; };
651 return s;
652 }
653
654 return { createReadStream: createReadStream, createWriteStream: createWriteStream };
655})();
656"#;
657
658pub fn install(cx: &mut mozjs::context::JSContext) {
659 rooted!(&in(cx) let fs_obj = unsafe { w2::JS_NewPlainObject(cx) });
660 if fs_obj.get().is_null() {
661 return;
662 }
663
664 unsafe {
665 w2::JS_DefineFunction(
667 cx,
668 fs_obj.handle(),
669 c"readFileSync".as_ptr(),
670 Some(fs_read_file_sync),
671 1,
672 JSPROP_ENUMERATE as u32,
673 );
674 w2::JS_DefineFunction(
675 cx,
676 fs_obj.handle(),
677 c"writeFileSync".as_ptr(),
678 Some(fs_write_file_sync),
679 2,
680 JSPROP_ENUMERATE as u32,
681 );
682 w2::JS_DefineFunction(
683 cx,
684 fs_obj.handle(),
685 c"appendFileSync".as_ptr(),
686 Some(fs_append_file_sync),
687 2,
688 JSPROP_ENUMERATE as u32,
689 );
690 w2::JS_DefineFunction(
691 cx,
692 fs_obj.handle(),
693 c"existsSync".as_ptr(),
694 Some(fs_exists_sync),
695 1,
696 JSPROP_ENUMERATE as u32,
697 );
698 w2::JS_DefineFunction(
699 cx,
700 fs_obj.handle(),
701 c"mkdirSync".as_ptr(),
702 Some(fs_mkdir_sync),
703 1,
704 JSPROP_ENUMERATE as u32,
705 );
706 w2::JS_DefineFunction(
707 cx,
708 fs_obj.handle(),
709 c"readdirSync".as_ptr(),
710 Some(fs_readdir_sync),
711 1,
712 JSPROP_ENUMERATE as u32,
713 );
714 w2::JS_DefineFunction(
715 cx,
716 fs_obj.handle(),
717 c"statSync".as_ptr(),
718 Some(fs_stat_sync),
719 1,
720 JSPROP_ENUMERATE as u32,
721 );
722 w2::JS_DefineFunction(
723 cx,
724 fs_obj.handle(),
725 c"lstatSync".as_ptr(),
726 Some(fs_lstat_sync),
727 1,
728 JSPROP_ENUMERATE as u32,
729 );
730 w2::JS_DefineFunction(
731 cx,
732 fs_obj.handle(),
733 c"unlinkSync".as_ptr(),
734 Some(fs_unlink_sync),
735 1,
736 JSPROP_ENUMERATE as u32,
737 );
738 w2::JS_DefineFunction(
739 cx,
740 fs_obj.handle(),
741 c"rmdirSync".as_ptr(),
742 Some(fs_rmdir_sync),
743 1,
744 JSPROP_ENUMERATE as u32,
745 );
746 w2::JS_DefineFunction(
747 cx,
748 fs_obj.handle(),
749 c"rmSync".as_ptr(),
750 Some(fs_rm_sync),
751 1,
752 JSPROP_ENUMERATE as u32,
753 );
754 w2::JS_DefineFunction(
755 cx,
756 fs_obj.handle(),
757 c"renameSync".as_ptr(),
758 Some(fs_rename_sync),
759 2,
760 JSPROP_ENUMERATE as u32,
761 );
762 w2::JS_DefineFunction(
763 cx,
764 fs_obj.handle(),
765 c"copyFileSync".as_ptr(),
766 Some(fs_copy_file_sync),
767 2,
768 JSPROP_ENUMERATE as u32,
769 );
770 w2::JS_DefineFunction(
771 cx,
772 fs_obj.handle(),
773 c"chmodSync".as_ptr(),
774 Some(fs_chmod_sync),
775 2,
776 JSPROP_ENUMERATE as u32,
777 );
778 w2::JS_DefineFunction(
779 cx,
780 fs_obj.handle(),
781 c"realpathSync".as_ptr(),
782 Some(fs_realpath_sync),
783 1,
784 JSPROP_ENUMERATE as u32,
785 );
786 w2::JS_DefineFunction(
787 cx,
788 fs_obj.handle(),
789 c"readlinkSync".as_ptr(),
790 Some(fs_readlink_sync),
791 1,
792 JSPROP_ENUMERATE as u32,
793 );
794 w2::JS_DefineFunction(
795 cx,
796 fs_obj.handle(),
797 c"symlinkSync".as_ptr(),
798 Some(fs_symlink_sync),
799 2,
800 JSPROP_ENUMERATE as u32,
801 );
802 w2::JS_DefineFunction(
803 cx,
804 fs_obj.handle(),
805 c"linkSync".as_ptr(),
806 Some(fs_link_sync),
807 2,
808 JSPROP_ENUMERATE as u32,
809 );
810 w2::JS_DefineFunction(
811 cx,
812 fs_obj.handle(),
813 c"cpSync".as_ptr(),
814 Some(fs_cp_sync),
815 2,
816 JSPROP_ENUMERATE as u32,
817 );
818 w2::JS_DefineFunction(
819 cx,
820 fs_obj.handle(),
821 c"cp".as_ptr(),
822 Some(fs_cp),
823 3,
824 JSPROP_ENUMERATE as u32,
825 );
826 w2::JS_DefineFunction(
827 cx,
828 fs_obj.handle(),
829 c"watch".as_ptr(),
830 Some(fs_watch),
831 2,
832 JSPROP_ENUMERATE as u32,
833 );
834 w2::JS_DefineFunction(
835 cx,
836 fs_obj.handle(),
837 c"watchFile".as_ptr(),
838 Some(fs_watch_file),
839 2,
840 JSPROP_ENUMERATE as u32,
841 );
842 w2::JS_DefineFunction(
843 cx,
844 fs_obj.handle(),
845 c"unwatchFile".as_ptr(),
846 Some(fs_unwatch_file),
847 2,
848 JSPROP_ENUMERATE as u32,
849 );
850 w2::JS_DefineFunction(
851 cx,
852 fs_obj.handle(),
853 c"statfsSync".as_ptr(),
854 Some(fs_statfs_sync),
855 1,
856 JSPROP_ENUMERATE as u32,
857 );
858 w2::JS_DefineFunction(
859 cx,
860 fs_obj.handle(),
861 c"openSync".as_ptr(),
862 Some(fs_open_sync),
863 2,
864 JSPROP_ENUMERATE as u32,
865 );
866 w2::JS_DefineFunction(
867 cx,
868 fs_obj.handle(),
869 c"closeSync".as_ptr(),
870 Some(fs_close_sync),
871 1,
872 JSPROP_ENUMERATE as u32,
873 );
874 w2::JS_DefineFunction(
875 cx,
876 fs_obj.handle(),
877 c"readSync".as_ptr(),
878 Some(fs_read_sync),
879 4,
880 JSPROP_ENUMERATE as u32,
881 );
882 w2::JS_DefineFunction(
883 cx,
884 fs_obj.handle(),
885 c"writeSync".as_ptr(),
886 Some(fs_write_sync),
887 4,
888 JSPROP_ENUMERATE as u32,
889 );
890 w2::JS_DefineFunction(
891 cx,
892 fs_obj.handle(),
893 c"mkdtempSync".as_ptr(),
894 Some(fs_mkdtemp_sync),
895 1,
896 JSPROP_ENUMERATE as u32,
897 );
898 w2::JS_DefineFunction(
899 cx,
900 fs_obj.handle(),
901 c"fchmodSync".as_ptr(),
902 Some(fs_fchmod_sync),
903 2,
904 JSPROP_ENUMERATE as u32,
905 );
906 w2::JS_DefineFunction(
907 cx,
908 fs_obj.handle(),
909 c"fchownSync".as_ptr(),
910 Some(fs_fchown_sync),
911 3,
912 JSPROP_ENUMERATE as u32,
913 );
914 w2::JS_DefineFunction(
915 cx,
916 fs_obj.handle(),
917 c"fdatasyncSync".as_ptr(),
918 Some(fs_fdatasync_sync),
919 1,
920 JSPROP_ENUMERATE as u32,
921 );
922 w2::JS_DefineFunction(
923 cx,
924 fs_obj.handle(),
925 c"fsyncSync".as_ptr(),
926 Some(fs_fsync_sync),
927 1,
928 JSPROP_ENUMERATE as u32,
929 );
930 w2::JS_DefineFunction(
931 cx,
932 fs_obj.handle(),
933 c"ftruncateSync".as_ptr(),
934 Some(fs_ftruncate_sync),
935 2,
936 JSPROP_ENUMERATE as u32,
937 );
938 w2::JS_DefineFunction(
939 cx,
940 fs_obj.handle(),
941 c"truncateSync".as_ptr(),
942 Some(fs_truncate_sync),
943 2,
944 JSPROP_ENUMERATE as u32,
945 );
946 w2::JS_DefineFunction(
947 cx,
948 fs_obj.handle(),
949 c"opendirSync".as_ptr(),
950 Some(fs_opendir_sync),
951 1,
952 JSPROP_ENUMERATE as u32,
953 );
954 w2::JS_DefineFunction(
955 cx,
956 fs_obj.handle(),
957 c"futimesSync".as_ptr(),
958 Some(fs_futimes_sync),
959 3,
960 JSPROP_ENUMERATE as u32,
961 );
962 w2::JS_DefineFunction(
963 cx,
964 fs_obj.handle(),
965 c"lchmodSync".as_ptr(),
966 Some(fs_lchmod_sync),
967 2,
968 JSPROP_ENUMERATE as u32,
969 );
970 w2::JS_DefineFunction(
971 cx,
972 fs_obj.handle(),
973 c"lchownSync".as_ptr(),
974 Some(fs_lchown_sync),
975 3,
976 JSPROP_ENUMERATE as u32,
977 );
978 w2::JS_DefineFunction(
979 cx,
980 fs_obj.handle(),
981 c"readvSync".as_ptr(),
982 Some(fs_readv_sync),
983 3,
984 JSPROP_ENUMERATE as u32,
985 );
986 w2::JS_DefineFunction(
987 cx,
988 fs_obj.handle(),
989 c"writevSync".as_ptr(),
990 Some(fs_writev_sync),
991 3,
992 JSPROP_ENUMERATE as u32,
993 );
994 w2::JS_DefineFunction(
995 cx,
996 fs_obj.handle(),
997 c"globSync".as_ptr(),
998 Some(fs_glob_sync),
999 2,
1000 JSPROP_ENUMERATE as u32,
1001 );
1002 w2::JS_DefineFunction(
1003 cx,
1004 fs_obj.handle(),
1005 c"openAsBlob".as_ptr(),
1006 Some(fs_open_as_blob),
1007 2,
1008 JSPROP_ENUMERATE as u32,
1009 );
1010
1011 w2::JS_DefineFunction(
1013 cx,
1014 fs_obj.handle(),
1015 c"readFile".as_ptr(),
1016 Some(fs_read_file),
1017 2,
1018 JSPROP_ENUMERATE as u32,
1019 );
1020 w2::JS_DefineFunction(
1021 cx,
1022 fs_obj.handle(),
1023 c"writeFile".as_ptr(),
1024 Some(fs_write_file),
1025 3,
1026 JSPROP_ENUMERATE as u32,
1027 );
1028 w2::JS_DefineFunction(
1029 cx,
1030 fs_obj.handle(),
1031 c"mkdir".as_ptr(),
1032 Some(fs_mkdir),
1033 2,
1034 JSPROP_ENUMERATE as u32,
1035 );
1036 w2::JS_DefineFunction(
1037 cx,
1038 fs_obj.handle(),
1039 c"appendFile".as_ptr(),
1040 Some(fs_append_file),
1041 3,
1042 JSPROP_ENUMERATE as u32,
1043 );
1044 w2::JS_DefineFunction(
1045 cx,
1046 fs_obj.handle(),
1047 c"access".as_ptr(),
1048 Some(fs_access),
1049 2,
1050 JSPROP_ENUMERATE as u32,
1051 );
1052 w2::JS_DefineFunction(
1053 cx,
1054 fs_obj.handle(),
1055 c"chmod".as_ptr(),
1056 Some(fs_chmod),
1057 2,
1058 JSPROP_ENUMERATE as u32,
1059 );
1060 w2::JS_DefineFunction(
1061 cx,
1062 fs_obj.handle(),
1063 c"chown".as_ptr(),
1064 Some(fs_chown),
1065 3,
1066 JSPROP_ENUMERATE as u32,
1067 );
1068 w2::JS_DefineFunction(
1069 cx,
1070 fs_obj.handle(),
1071 c"close".as_ptr(),
1072 Some(fs_close),
1073 1,
1074 JSPROP_ENUMERATE as u32,
1075 );
1076 w2::JS_DefineFunction(
1077 cx,
1078 fs_obj.handle(),
1079 c"copyFile".as_ptr(),
1080 Some(fs_copy_file),
1081 2,
1082 JSPROP_ENUMERATE as u32,
1083 );
1084 w2::JS_DefineFunction(
1085 cx,
1086 fs_obj.handle(),
1087 c"exists".as_ptr(),
1088 Some(fs_exists),
1089 1,
1090 JSPROP_ENUMERATE as u32,
1091 );
1092 w2::JS_DefineFunction(
1093 cx,
1094 fs_obj.handle(),
1095 c"fchmod".as_ptr(),
1096 Some(fs_fchmod),
1097 2,
1098 JSPROP_ENUMERATE as u32,
1099 );
1100 w2::JS_DefineFunction(
1101 cx,
1102 fs_obj.handle(),
1103 c"fchown".as_ptr(),
1104 Some(fs_fchown),
1105 3,
1106 JSPROP_ENUMERATE as u32,
1107 );
1108 w2::JS_DefineFunction(
1109 cx,
1110 fs_obj.handle(),
1111 c"fdatasync".as_ptr(),
1112 Some(fs_fdatasync),
1113 1,
1114 JSPROP_ENUMERATE as u32,
1115 );
1116 w2::JS_DefineFunction(
1117 cx,
1118 fs_obj.handle(),
1119 c"fstat".as_ptr(),
1120 Some(fs_fstat),
1121 1,
1122 JSPROP_ENUMERATE as u32,
1123 );
1124 w2::JS_DefineFunction(
1125 cx,
1126 fs_obj.handle(),
1127 c"fsync".as_ptr(),
1128 Some(fs_fsync),
1129 1,
1130 JSPROP_ENUMERATE as u32,
1131 );
1132 w2::JS_DefineFunction(
1133 cx,
1134 fs_obj.handle(),
1135 c"ftruncate".as_ptr(),
1136 Some(fs_ftruncate),
1137 2,
1138 JSPROP_ENUMERATE as u32,
1139 );
1140 w2::JS_DefineFunction(
1141 cx,
1142 fs_obj.handle(),
1143 c"futimes".as_ptr(),
1144 Some(fs_futimes),
1145 3,
1146 JSPROP_ENUMERATE as u32,
1147 );
1148 w2::JS_DefineFunction(
1149 cx,
1150 fs_obj.handle(),
1151 c"lchown".as_ptr(),
1152 Some(fs_lchown),
1153 3,
1154 JSPROP_ENUMERATE as u32,
1155 );
1156 w2::JS_DefineFunction(
1157 cx,
1158 fs_obj.handle(),
1159 c"link".as_ptr(),
1160 Some(fs_link),
1161 2,
1162 JSPROP_ENUMERATE as u32,
1163 );
1164 w2::JS_DefineFunction(
1165 cx,
1166 fs_obj.handle(),
1167 c"lstat".as_ptr(),
1168 Some(fs_lstat),
1169 1,
1170 JSPROP_ENUMERATE as u32,
1171 );
1172 w2::JS_DefineFunction(
1173 cx,
1174 fs_obj.handle(),
1175 c"lutimes".as_ptr(),
1176 Some(fs_lutimes),
1177 3,
1178 JSPROP_ENUMERATE as u32,
1179 );
1180 w2::JS_DefineFunction(
1181 cx,
1182 fs_obj.handle(),
1183 c"mkdtemp".as_ptr(),
1184 Some(fs_mkdtemp),
1185 1,
1186 JSPROP_ENUMERATE as u32,
1187 );
1188 w2::JS_DefineFunction(
1189 cx,
1190 fs_obj.handle(),
1191 c"open".as_ptr(),
1192 Some(fs_open),
1193 3,
1194 JSPROP_ENUMERATE as u32,
1195 );
1196 w2::JS_DefineFunction(
1197 cx,
1198 fs_obj.handle(),
1199 c"opendir".as_ptr(),
1200 Some(fs_opendir),
1201 1,
1202 JSPROP_ENUMERATE as u32,
1203 );
1204 w2::JS_DefineFunction(
1205 cx,
1206 fs_obj.handle(),
1207 c"read".as_ptr(),
1208 Some(fs_read),
1209 4,
1210 JSPROP_ENUMERATE as u32,
1211 );
1212 w2::JS_DefineFunction(
1213 cx,
1214 fs_obj.handle(),
1215 c"readdir".as_ptr(),
1216 Some(fs_readdir),
1217 2,
1218 JSPROP_ENUMERATE as u32,
1219 );
1220 w2::JS_DefineFunction(
1221 cx,
1222 fs_obj.handle(),
1223 c"readlink".as_ptr(),
1224 Some(fs_readlink),
1225 1,
1226 JSPROP_ENUMERATE as u32,
1227 );
1228 w2::JS_DefineFunction(
1229 cx,
1230 fs_obj.handle(),
1231 c"readv".as_ptr(),
1232 Some(fs_readv),
1233 4,
1234 JSPROP_ENUMERATE as u32,
1235 );
1236 w2::JS_DefineFunction(
1237 cx,
1238 fs_obj.handle(),
1239 c"realpath".as_ptr(),
1240 Some(fs_realpath),
1241 1,
1242 JSPROP_ENUMERATE as u32,
1243 );
1244 w2::JS_DefineFunction(
1245 cx,
1246 fs_obj.handle(),
1247 c"rename".as_ptr(),
1248 Some(fs_rename),
1249 2,
1250 JSPROP_ENUMERATE as u32,
1251 );
1252 w2::JS_DefineFunction(
1253 cx,
1254 fs_obj.handle(),
1255 c"rm".as_ptr(),
1256 Some(fs_rm),
1257 2,
1258 JSPROP_ENUMERATE as u32,
1259 );
1260 w2::JS_DefineFunction(
1261 cx,
1262 fs_obj.handle(),
1263 c"rmdir".as_ptr(),
1264 Some(fs_rmdir),
1265 1,
1266 JSPROP_ENUMERATE as u32,
1267 );
1268 w2::JS_DefineFunction(
1269 cx,
1270 fs_obj.handle(),
1271 c"stat".as_ptr(),
1272 Some(fs_stat),
1273 1,
1274 JSPROP_ENUMERATE as u32,
1275 );
1276 w2::JS_DefineFunction(
1277 cx,
1278 fs_obj.handle(),
1279 c"symlink".as_ptr(),
1280 Some(fs_symlink),
1281 2,
1282 JSPROP_ENUMERATE as u32,
1283 );
1284 w2::JS_DefineFunction(
1285 cx,
1286 fs_obj.handle(),
1287 c"truncate".as_ptr(),
1288 Some(fs_truncate),
1289 2,
1290 JSPROP_ENUMERATE as u32,
1291 );
1292 w2::JS_DefineFunction(
1293 cx,
1294 fs_obj.handle(),
1295 c"unlink".as_ptr(),
1296 Some(fs_unlink),
1297 1,
1298 JSPROP_ENUMERATE as u32,
1299 );
1300 w2::JS_DefineFunction(
1301 cx,
1302 fs_obj.handle(),
1303 c"utimes".as_ptr(),
1304 Some(fs_utimes),
1305 3,
1306 JSPROP_ENUMERATE as u32,
1307 );
1308 w2::JS_DefineFunction(
1309 cx,
1310 fs_obj.handle(),
1311 c"write".as_ptr(),
1312 Some(fs_write),
1313 4,
1314 JSPROP_ENUMERATE as u32,
1315 );
1316 w2::JS_DefineFunction(
1317 cx,
1318 fs_obj.handle(),
1319 c"writev".as_ptr(),
1320 Some(fs_writev),
1321 4,
1322 JSPROP_ENUMERATE as u32,
1323 );
1324 w2::JS_DefineFunction(
1325 cx,
1326 fs_obj.handle(),
1327 c"statfs".as_ptr(),
1328 Some(fs_statfs),
1329 1,
1330 JSPROP_ENUMERATE as u32,
1331 );
1332 w2::JS_DefineFunction(
1333 cx,
1334 fs_obj.handle(),
1335 c"glob".as_ptr(),
1336 Some(fs_glob),
1337 3,
1338 JSPROP_ENUMERATE as u32,
1339 );
1340
1341 let constants: &[(&str, i32)] = &[("F_OK", 0), ("R_OK", 4), ("W_OK", 2), ("X_OK", 1)];
1343 for (name, value) in constants {
1344 let c_name = ZBox::from_bytes(name.as_bytes());
1345 rooted!(&in(cx) let val = mozjs::jsval::Int32Value(*value));
1346 JS_DefineProperty(
1347 cx.raw_cx(),
1348 fs_obj.handle().into(),
1349 c_name.as_ptr(),
1350 val.handle().into(),
1351 JSPROP_ENUMERATE as u32,
1352 );
1353 }
1354
1355 rooted!(&in(cx) let promises_obj = w2::JS_NewPlainObject(cx));
1357 if !promises_obj.get().is_null() {
1358 w2::JS_DefineFunction(
1359 cx,
1360 promises_obj.handle(),
1361 c"readFile".as_ptr(),
1362 Some(fs_promises_read_file),
1363 1,
1364 JSPROP_ENUMERATE as u32,
1365 );
1366 w2::JS_DefineFunction(
1367 cx,
1368 promises_obj.handle(),
1369 c"writeFile".as_ptr(),
1370 Some(fs_promises_write_file),
1371 2,
1372 JSPROP_ENUMERATE as u32,
1373 );
1374 w2::JS_DefineFunction(
1375 cx,
1376 promises_obj.handle(),
1377 c"stat".as_ptr(),
1378 Some(fs_promises_stat),
1379 1,
1380 JSPROP_ENUMERATE as u32,
1381 );
1382 w2::JS_DefineFunction(
1383 cx,
1384 promises_obj.handle(),
1385 c"readdir".as_ptr(),
1386 Some(fs_promises_readdir),
1387 1,
1388 JSPROP_ENUMERATE as u32,
1389 );
1390 w2::JS_DefineFunction(
1391 cx,
1392 promises_obj.handle(),
1393 c"mkdir".as_ptr(),
1394 Some(fs_promises_mkdir),
1395 1,
1396 JSPROP_ENUMERATE as u32,
1397 );
1398 w2::JS_DefineFunction(
1399 cx,
1400 promises_obj.handle(),
1401 c"unlink".as_ptr(),
1402 Some(fs_promises_unlink),
1403 1,
1404 JSPROP_ENUMERATE as u32,
1405 );
1406 w2::JS_DefineFunction(
1407 cx,
1408 promises_obj.handle(),
1409 c"rename".as_ptr(),
1410 Some(fs_promises_rename),
1411 2,
1412 JSPROP_ENUMERATE as u32,
1413 );
1414 w2::JS_DefineFunction(
1415 cx,
1416 promises_obj.handle(),
1417 c"copyFile".as_ptr(),
1418 Some(fs_promises_copy_file),
1419 2,
1420 JSPROP_ENUMERATE as u32,
1421 );
1422 w2::JS_DefineFunction(
1423 cx,
1424 promises_obj.handle(),
1425 c"lstat".as_ptr(),
1426 Some(fs_promises_lstat),
1427 1,
1428 JSPROP_ENUMERATE as u32,
1429 );
1430 w2::JS_DefineFunction(
1431 cx,
1432 promises_obj.handle(),
1433 c"appendFile".as_ptr(),
1434 Some(fs_promises_append_file),
1435 2,
1436 JSPROP_ENUMERATE as u32,
1437 );
1438 w2::JS_DefineFunction(
1439 cx,
1440 promises_obj.handle(),
1441 c"chmod".as_ptr(),
1442 Some(fs_promises_chmod),
1443 2,
1444 JSPROP_ENUMERATE as u32,
1445 );
1446 w2::JS_DefineFunction(
1447 cx,
1448 promises_obj.handle(),
1449 c"chown".as_ptr(),
1450 Some(fs_promises_chown),
1451 3,
1452 JSPROP_ENUMERATE as u32,
1453 );
1454 w2::JS_DefineFunction(
1455 cx,
1456 promises_obj.handle(),
1457 c"access".as_ptr(),
1458 Some(fs_promises_access),
1459 1,
1460 JSPROP_ENUMERATE as u32,
1461 );
1462 w2::JS_DefineFunction(
1463 cx,
1464 promises_obj.handle(),
1465 c"rm".as_ptr(),
1466 Some(fs_promises_rm),
1467 1,
1468 JSPROP_ENUMERATE as u32,
1469 );
1470 w2::JS_DefineFunction(
1471 cx,
1472 promises_obj.handle(),
1473 c"rmdir".as_ptr(),
1474 Some(fs_promises_rmdir),
1475 1,
1476 JSPROP_ENUMERATE as u32,
1477 );
1478 w2::JS_DefineFunction(
1479 cx,
1480 promises_obj.handle(),
1481 c"realpath".as_ptr(),
1482 Some(fs_promises_realpath),
1483 1,
1484 JSPROP_ENUMERATE as u32,
1485 );
1486 w2::JS_DefineFunction(
1487 cx,
1488 promises_obj.handle(),
1489 c"readlink".as_ptr(),
1490 Some(fs_promises_readlink),
1491 1,
1492 JSPROP_ENUMERATE as u32,
1493 );
1494 w2::JS_DefineFunction(
1495 cx,
1496 promises_obj.handle(),
1497 c"symlink".as_ptr(),
1498 Some(fs_promises_symlink),
1499 2,
1500 JSPROP_ENUMERATE as u32,
1501 );
1502 w2::JS_DefineFunction(
1503 cx,
1504 promises_obj.handle(),
1505 c"link".as_ptr(),
1506 Some(fs_promises_link),
1507 2,
1508 JSPROP_ENUMERATE as u32,
1509 );
1510 w2::JS_DefineFunction(
1511 cx,
1512 promises_obj.handle(),
1513 c"truncate".as_ptr(),
1514 Some(fs_promises_truncate),
1515 2,
1516 JSPROP_ENUMERATE as u32,
1517 );
1518 w2::JS_DefineFunction(
1519 cx,
1520 promises_obj.handle(),
1521 c"utimes".as_ptr(),
1522 Some(fs_promises_utimes),
1523 3,
1524 JSPROP_ENUMERATE as u32,
1525 );
1526 w2::JS_DefineFunction(
1527 cx,
1528 promises_obj.handle(),
1529 c"mkdtemp".as_ptr(),
1530 Some(fs_promises_mkdtemp),
1531 1,
1532 JSPROP_ENUMERATE as u32,
1533 );
1534 w2::JS_DefineFunction(
1535 cx,
1536 promises_obj.handle(),
1537 c"open".as_ptr(),
1538 Some(fs_promises_open),
1539 2,
1540 JSPROP_ENUMERATE as u32,
1541 );
1542 w2::JS_DefineFunction(
1543 cx,
1544 promises_obj.handle(),
1545 c"read".as_ptr(),
1546 Some(fs_promises_read),
1547 4,
1548 JSPROP_ENUMERATE as u32,
1549 );
1550 w2::JS_DefineFunction(
1551 cx,
1552 promises_obj.handle(),
1553 c"write".as_ptr(),
1554 Some(fs_promises_write),
1555 4,
1556 JSPROP_ENUMERATE as u32,
1557 );
1558 w2::JS_DefineFunction(
1559 cx,
1560 promises_obj.handle(),
1561 c"statfs".as_ptr(),
1562 Some(fs_promises_statfs),
1563 1,
1564 JSPROP_ENUMERATE as u32,
1565 );
1566
1567 rooted!(&in(cx) let prom_val = mozjs::jsval::ObjectValue(promises_obj.get()));
1568 JS_DefineProperty(
1569 cx.raw_cx(),
1570 fs_obj.handle().into(),
1571 c"promises".as_ptr(),
1572 prom_val.handle().into(),
1573 JSPROP_ENUMERATE as u32,
1574 );
1575 }
1576 }
1577
1578 unsafe {
1580 let global = JS::CurrentGlobalOrNull(cx.raw_cx());
1581 if !global.is_null() {
1582 rooted!(&in(cx) let global_rooted = global);
1583 rooted!(&in(cx) let fs_val = mozjs::jsval::ObjectValue(fs_obj.get()));
1584 JS_DefineProperty(
1585 cx.raw_cx(),
1586 global_rooted.handle().into(),
1587 c"__fs_stream_ref".as_ptr(),
1588 fs_val.handle().into(),
1589 JSPROP_ENUMERATE as u32,
1590 );
1591 w2::JS_DefineFunction(
1595 cx,
1596 global_rooted.handle(),
1597 c"__bao_fs_stream_flush".as_ptr(),
1598 Some(fs_write_stream_flush),
1599 2,
1600 0,
1601 );
1602
1603 let c_filename = ZBox::from_bytes("node:fs:streams".as_bytes());
1604 let opts = NewCompileOptions(cx.raw_cx(), c_filename.as_ptr(), 1);
1605 if !opts.is_null() {
1606 let mut src = mozjs::rust::transform_str_to_source_text(FS_STREAM_JS);
1607 let mut rval = UndefinedValue();
1608 let rval_handle = MutableHandle::<Value> {
1609 _phantom_0: ::std::marker::PhantomData,
1610 ptr: &mut rval,
1611 };
1612 let ok = mozjs_sys::jsapi::JS::Evaluate2(cx.raw_cx(), opts, &mut src, rval_handle);
1613 libc::free(opts as *mut _);
1614
1615 if ok && rval.is_object() {
1616 let exports = rval.to_object();
1617 rooted!(&in(cx) let exports_rooted = exports);
1618
1619 for name in &["createReadStream", "createWriteStream"] {
1620 let cname = ZBox::from_bytes(name.as_bytes());
1621 let mut val = UndefinedValue();
1622 JS_GetProperty(
1623 cx.raw_cx(),
1624 exports_rooted.handle().into(),
1625 cname.as_ptr(),
1626 MutableHandle::<Value> {
1627 _phantom_0: ::std::marker::PhantomData,
1628 ptr: &mut val,
1629 },
1630 );
1631 if !val.is_undefined() {
1632 rooted!(&in(cx) let val_root = val);
1633 JS_DefineProperty(
1634 cx.raw_cx(),
1635 fs_obj.handle().into(),
1636 cname.as_ptr(),
1637 val_root.handle().into(),
1638 JSPROP_ENUMERATE as u32,
1639 );
1640 }
1641 }
1642 }
1643 }
1644
1645 JS_DeleteProperty1(
1646 cx.raw_cx(),
1647 global_rooted.handle().into(),
1648 c"__fs_stream_ref".as_ptr(),
1649 );
1650 JS_DeleteProperty1(
1651 cx.raw_cx(),
1652 global_rooted.handle().into(),
1653 c"__bao_fs_stream_flush".as_ptr(),
1654 );
1655 }
1656 }
1657
1658 cache_builtin(cx, "fs", fs_obj.get());
1659
1660 unsafe {
1664 rooted!(&in(cx) let fsp_obj = w2::JS_NewPlainObject(cx));
1665 if !fsp_obj.get().is_null() {
1666 w2::JS_DefineFunction(
1667 cx,
1668 fsp_obj.handle(),
1669 c"readFile".as_ptr(),
1670 Some(fs_promises_read_file),
1671 1,
1672 JSPROP_ENUMERATE as u32,
1673 );
1674 w2::JS_DefineFunction(
1675 cx,
1676 fsp_obj.handle(),
1677 c"writeFile".as_ptr(),
1678 Some(fs_promises_write_file),
1679 2,
1680 JSPROP_ENUMERATE as u32,
1681 );
1682 w2::JS_DefineFunction(
1683 cx,
1684 fsp_obj.handle(),
1685 c"stat".as_ptr(),
1686 Some(fs_promises_stat),
1687 1,
1688 JSPROP_ENUMERATE as u32,
1689 );
1690 w2::JS_DefineFunction(
1691 cx,
1692 fsp_obj.handle(),
1693 c"readdir".as_ptr(),
1694 Some(fs_promises_readdir),
1695 1,
1696 JSPROP_ENUMERATE as u32,
1697 );
1698 w2::JS_DefineFunction(
1699 cx,
1700 fsp_obj.handle(),
1701 c"mkdir".as_ptr(),
1702 Some(fs_promises_mkdir),
1703 1,
1704 JSPROP_ENUMERATE as u32,
1705 );
1706 w2::JS_DefineFunction(
1707 cx,
1708 fsp_obj.handle(),
1709 c"unlink".as_ptr(),
1710 Some(fs_promises_unlink),
1711 1,
1712 JSPROP_ENUMERATE as u32,
1713 );
1714 w2::JS_DefineFunction(
1715 cx,
1716 fsp_obj.handle(),
1717 c"rename".as_ptr(),
1718 Some(fs_promises_rename),
1719 2,
1720 JSPROP_ENUMERATE as u32,
1721 );
1722 w2::JS_DefineFunction(
1723 cx,
1724 fsp_obj.handle(),
1725 c"copyFile".as_ptr(),
1726 Some(fs_promises_copy_file),
1727 2,
1728 JSPROP_ENUMERATE as u32,
1729 );
1730 w2::JS_DefineFunction(
1731 cx,
1732 fsp_obj.handle(),
1733 c"lstat".as_ptr(),
1734 Some(fs_promises_lstat),
1735 1,
1736 JSPROP_ENUMERATE as u32,
1737 );
1738 w2::JS_DefineFunction(
1739 cx,
1740 fsp_obj.handle(),
1741 c"appendFile".as_ptr(),
1742 Some(fs_promises_append_file),
1743 2,
1744 JSPROP_ENUMERATE as u32,
1745 );
1746 w2::JS_DefineFunction(
1747 cx,
1748 fsp_obj.handle(),
1749 c"chmod".as_ptr(),
1750 Some(fs_promises_chmod),
1751 2,
1752 JSPROP_ENUMERATE as u32,
1753 );
1754 w2::JS_DefineFunction(
1755 cx,
1756 fsp_obj.handle(),
1757 c"chown".as_ptr(),
1758 Some(fs_promises_chown),
1759 3,
1760 JSPROP_ENUMERATE as u32,
1761 );
1762 w2::JS_DefineFunction(
1763 cx,
1764 fsp_obj.handle(),
1765 c"access".as_ptr(),
1766 Some(fs_promises_access),
1767 1,
1768 JSPROP_ENUMERATE as u32,
1769 );
1770 w2::JS_DefineFunction(
1771 cx,
1772 fsp_obj.handle(),
1773 c"rm".as_ptr(),
1774 Some(fs_promises_rm),
1775 1,
1776 JSPROP_ENUMERATE as u32,
1777 );
1778 w2::JS_DefineFunction(
1779 cx,
1780 fsp_obj.handle(),
1781 c"rmdir".as_ptr(),
1782 Some(fs_promises_rmdir),
1783 1,
1784 JSPROP_ENUMERATE as u32,
1785 );
1786 w2::JS_DefineFunction(
1787 cx,
1788 fsp_obj.handle(),
1789 c"realpath".as_ptr(),
1790 Some(fs_promises_realpath),
1791 1,
1792 JSPROP_ENUMERATE as u32,
1793 );
1794 w2::JS_DefineFunction(
1795 cx,
1796 fsp_obj.handle(),
1797 c"readlink".as_ptr(),
1798 Some(fs_promises_readlink),
1799 1,
1800 JSPROP_ENUMERATE as u32,
1801 );
1802 w2::JS_DefineFunction(
1803 cx,
1804 fsp_obj.handle(),
1805 c"symlink".as_ptr(),
1806 Some(fs_promises_symlink),
1807 2,
1808 JSPROP_ENUMERATE as u32,
1809 );
1810 w2::JS_DefineFunction(
1811 cx,
1812 fsp_obj.handle(),
1813 c"link".as_ptr(),
1814 Some(fs_promises_link),
1815 2,
1816 JSPROP_ENUMERATE as u32,
1817 );
1818 w2::JS_DefineFunction(
1819 cx,
1820 fsp_obj.handle(),
1821 c"truncate".as_ptr(),
1822 Some(fs_promises_truncate),
1823 2,
1824 JSPROP_ENUMERATE as u32,
1825 );
1826 w2::JS_DefineFunction(
1827 cx,
1828 fsp_obj.handle(),
1829 c"utimes".as_ptr(),
1830 Some(fs_promises_utimes),
1831 3,
1832 JSPROP_ENUMERATE as u32,
1833 );
1834 w2::JS_DefineFunction(
1835 cx,
1836 fsp_obj.handle(),
1837 c"mkdtemp".as_ptr(),
1838 Some(fs_promises_mkdtemp),
1839 1,
1840 JSPROP_ENUMERATE as u32,
1841 );
1842 w2::JS_DefineFunction(
1843 cx,
1844 fsp_obj.handle(),
1845 c"open".as_ptr(),
1846 Some(fs_promises_open),
1847 2,
1848 JSPROP_ENUMERATE as u32,
1849 );
1850 w2::JS_DefineFunction(
1851 cx,
1852 fsp_obj.handle(),
1853 c"read".as_ptr(),
1854 Some(fs_promises_read),
1855 4,
1856 JSPROP_ENUMERATE as u32,
1857 );
1858 w2::JS_DefineFunction(
1859 cx,
1860 fsp_obj.handle(),
1861 c"write".as_ptr(),
1862 Some(fs_promises_write),
1863 4,
1864 JSPROP_ENUMERATE as u32,
1865 );
1866 w2::JS_DefineFunction(
1867 cx,
1868 fsp_obj.handle(),
1869 c"statfs".as_ptr(),
1870 Some(fs_promises_statfs),
1871 1,
1872 JSPROP_ENUMERATE as u32,
1873 );
1874
1875 w2::JS_DefineFunction(
1878 cx,
1879 fsp_obj.handle(),
1880 c"FileHandle".as_ptr(),
1881 Some(fs_promises_filehandle_ctor),
1882 1,
1883 JSPROP_ENUMERATE as u32,
1884 );
1885 cache_builtin(cx, "fs/promises", fsp_obj.get());
1886 }
1887 }
1888}
1889
1890#[allow(unsafe_op_in_unsafe_fn)]
1893unsafe fn get_path_arg(
1894 cx: *mut JSContext,
1895 args: &CallArgs,
1896 index: u32,
1897) -> ::std::result::Result<::std::string::String, bool> {
1898 if args.argc_ <= index {
1899 JS_ReportErrorUTF8(cx, c"Missing path argument".as_ptr());
1900 return ::std::result::Result::Err(false);
1901 }
1902 let val = *args.get(index).ptr;
1903 if val.is_string() {
1904 let s = val.to_string();
1905 if !s.is_null() {
1906 return ::std::result::Result::Ok(crate::jsstr_to_rust_string(cx, s));
1907 }
1908 }
1909 JS_ReportErrorUTF8(cx, c"The \"path\" argument must be of type string".as_ptr());
1910 ::std::result::Result::Err(false)
1911}
1912
1913#[allow(unsafe_op_in_unsafe_fn)]
1914unsafe fn get_encoding_opt(
1915 cx: *mut JSContext,
1916 args: &CallArgs,
1917 index: u32,
1918) -> ::std::option::Option<::std::string::String> {
1919 if args.argc_ <= index {
1920 return ::std::option::Option::None;
1921 }
1922 let val = *args.get(index).ptr;
1923 if val.is_string() {
1924 let s = val.to_string();
1925 if !s.is_null() {
1926 return ::std::option::Option::Some(crate::jsstr_to_rust_string(cx, s));
1927 }
1928 }
1929 if val.is_object() {
1930 let mut wrapped_cx_enc =
1931 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
1932 let cx_ref_enc = &mut wrapped_cx_enc;
1933 rooted!(&in(cx_ref_enc) let obj = val.to_object());
1934 let mut enc_val = UndefinedValue();
1935 let enc_h = MutableHandle::<Value> {
1936 _phantom_0: ::std::marker::PhantomData,
1937 ptr: &mut enc_val,
1938 };
1939 JS_GetProperty(cx, obj.handle().into(), c"encoding".as_ptr(), enc_h);
1940 if enc_val.is_string() {
1941 let s = enc_val.to_string();
1942 if !s.is_null() {
1943 return ::std::option::Option::Some(crate::jsstr_to_rust_string(cx, s));
1944 }
1945 }
1946 }
1947 ::std::option::Option::None
1948}
1949
1950#[allow(unsafe_op_in_unsafe_fn)]
1956unsafe fn js_string_from_utf8(cx: *mut JSContext, text: &str) -> *mut JSString {
1957 let chars = mozjs::conversions::Utf8Chars::from(text);
1958 mozjs_sys::jsapi::JS_NewStringCopyUTF8N(
1959 cx,
1960 &*chars as *const _ as *const mozjs_sys::jsapi::JS::UTF8Chars,
1961 )
1962}
1963
1964#[allow(unsafe_op_in_unsafe_fn)]
1965unsafe fn return_string_content(
1966 cx: *mut JSContext,
1967 args: &CallArgs,
1968 data: &[u8],
1969 encoding: ::std::option::Option<&str>,
1970) -> bool {
1971 match encoding {
1972 None => {
1978 let buf_obj = crate::globals::create_buffer_object(cx, data);
1979 if buf_obj.is_null() {
1980 args.rval().set(UndefinedValue());
1981 } else {
1982 args.rval().set(mozjs::jsval::ObjectValue(buf_obj));
1983 }
1984 }
1985 Some("utf-8" | "utf8" | "text") => {
1986 let s = ::std::string::String::from_utf8_lossy(data);
1990 let js_str = js_string_from_utf8(cx, &s);
1991 if js_str.is_null() {
1992 args.rval().set(UndefinedValue());
1993 } else {
1994 args.rval().set(mozjs::jsval::StringValue(&*js_str));
1995 }
1996 }
1997 Some("hex") => {
1998 let hex: ::std::string::String = bun_core::fmt::bytes_to_hex_lower_string(data);
1999 let c_str = ZBox::from_bytes(hex.as_bytes());
2000 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
2001 if js_str.is_null() {
2002 args.rval().set(UndefinedValue());
2003 } else {
2004 args.rval().set(mozjs::jsval::StringValue(&*js_str));
2005 }
2006 }
2007 Some("base64") => {
2008 let encoded_bytes = bun_base64::encode_alloc(data);
2011 let encoded = ::std::str::from_utf8(&encoded_bytes).unwrap_or("");
2012 let c_str = ZBox::from_bytes(encoded.as_bytes());
2013 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
2014 if js_str.is_null() {
2015 args.rval().set(UndefinedValue());
2016 } else {
2017 args.rval().set(mozjs::jsval::StringValue(&*js_str));
2018 }
2019 }
2020 Some("latin1" | "binary") => {
2021 let s: ::std::string::String = data.iter().map(|&b| b as char).collect();
2027 let js_str = js_string_from_utf8(cx, &s);
2028 if js_str.is_null() {
2029 args.rval().set(UndefinedValue());
2030 } else {
2031 args.rval().set(mozjs::jsval::StringValue(&*js_str));
2032 }
2033 }
2034 Some(_) => {
2035 let s = ::std::string::String::from_utf8_lossy(data);
2036 let js_str = js_string_from_utf8(cx, &s);
2037 if js_str.is_null() {
2038 args.rval().set(UndefinedValue());
2039 } else {
2040 args.rval().set(mozjs::jsval::StringValue(&*js_str));
2041 }
2042 }
2043 }
2044 true
2045}
2046
2047#[allow(unsafe_op_in_unsafe_fn)]
2048unsafe fn throw_fs_error(cx: *mut JSContext, op: &str, path: &str, err: &::std::io::Error) -> bool {
2049 let code = if err.raw_os_error() == Some(libc::EINVAL) {
2050 "EINVAL"
2053 } else {
2054 match err.kind() {
2055 ::std::io::ErrorKind::NotFound => "ENOENT",
2056 ::std::io::ErrorKind::PermissionDenied => "EACCES",
2057 ::std::io::ErrorKind::AlreadyExists => "EEXIST",
2058 ::std::io::ErrorKind::IsADirectory => "EISDIR",
2059 ::std::io::ErrorKind::NotADirectory => "ENOTDIR",
2060 _ => "ERR",
2061 }
2062 };
2063 let msg = format!("{} '{}': {}", op, path, err);
2064 let c_msg = ZBox::from_bytes(msg.as_bytes());
2065 let code_str = JS_NewStringCopyZ(cx, ZBox::from_bytes(code.as_bytes()).as_ptr());
2066 if !code_str.is_null() {
2067 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2068 if JS_IsExceptionPending(cx) {
2069 rooted!(in(cx) let mut exn = UndefinedValue());
2070 JS_GetPendingException(cx, exn.handle_mut().into());
2071 let exn_val = exn.get();
2072 if !exn_val.is_undefined() && exn_val.is_object() {
2073 rooted!(in(cx) let exn_obj = exn_val.to_object());
2074 rooted!(in(cx) let code_val = StringValue(&*code_str));
2075 JS_DefineProperty(
2076 cx,
2077 exn_obj.handle().into(),
2078 c"code".as_ptr(),
2079 code_val.handle().into(),
2080 JSPROP_ENUMERATE as u32,
2081 );
2082 let path_val = ZBox::from_bytes(path.as_bytes());
2083 let path_str = JS_NewStringCopyZ(cx, path_val.as_ptr());
2084 if !path_str.is_null() {
2085 rooted!(in(cx) let path_v = StringValue(&*path_str));
2086 JS_DefineProperty(
2087 cx,
2088 exn_obj.handle().into(),
2089 c"path".as_ptr(),
2090 path_v.handle().into(),
2091 JSPROP_ENUMERATE as u32,
2092 );
2093 }
2094 JS_SetPendingException(
2095 cx,
2096 exn.handle().into(),
2097 ExceptionStackBehavior::DoNotCapture,
2098 );
2099 }
2100 }
2101 } else {
2102 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2103 }
2104 false
2105}
2106
2107#[allow(unsafe_op_in_unsafe_fn)]
2110unsafe extern "C" fn fs_read_file_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2111 let args = CallArgs::from_vp(vp, argc);
2112 let path = match get_path_arg(cx, &args, 0) {
2113 ::std::result::Result::Ok(p) => p,
2114 ::std::result::Result::Err(b) => return b,
2115 };
2116 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_read(&path) {
2117 let c_msg = ZBox::from_bytes(e.as_bytes());
2118 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2119 return false;
2120 }
2121 let encoding = get_encoding_opt(cx, &args, 1);
2122 match bun_fs::read(&path) {
2123 ::std::result::Result::Ok(data) => {
2124 return_string_content(cx, &args, &data, encoding.as_deref())
2125 }
2126 ::std::result::Result::Err(e) => throw_fs_error(cx, "readFileSync", &path, &e),
2127 }
2128}
2129
2130#[allow(unsafe_op_in_unsafe_fn)]
2131unsafe extern "C" fn fs_write_file_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2132 let args = CallArgs::from_vp(vp, argc);
2133 let path = match get_path_arg(cx, &args, 0) {
2134 ::std::result::Result::Ok(p) => p,
2135 ::std::result::Result::Err(b) => return b,
2136 };
2137 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
2138 let c_msg = ZBox::from_bytes(e.as_bytes());
2139 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2140 return false;
2141 }
2142 let data_val = if argc > 1 {
2143 *args.get(1).ptr
2144 } else {
2145 UndefinedValue()
2146 };
2147
2148 let result = if data_val.is_string() {
2149 let s = data_val.to_string();
2150 if !s.is_null() {
2151 let rust_str = crate::jsstr_to_rust_string(cx, s);
2152 bun_fs::write(&path, rust_str.as_bytes())
2153 } else {
2154 bun_fs::write(&path, &[] as &[u8])
2155 }
2156 } else if data_val.is_object() {
2157 let bytes = crate::node_crypto::extract_buffer_bytes(cx, data_val);
2158 bun_fs::write(&path, &bytes)
2159 } else {
2160 bun_fs::write(&path, &[] as &[u8])
2161 };
2162
2163 match result {
2164 ::std::result::Result::Ok(()) => {
2165 args.rval().set(UndefinedValue());
2166 true
2167 }
2168 ::std::result::Result::Err(e) => throw_fs_error(cx, "writeFileSync", &path, &e),
2169 }
2170}
2171
2172#[allow(unsafe_op_in_unsafe_fn)]
2184unsafe extern "C" fn fs_write_stream_flush(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2185 let args = CallArgs::from_vp(vp, argc);
2186 let path = match get_path_arg(cx, &args, 0) {
2187 ::std::result::Result::Ok(p) => p,
2188 ::std::result::Result::Err(b) => return b,
2189 };
2190 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
2191 let c_msg = ZBox::from_bytes(e.as_bytes());
2192 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2193 return false;
2194 }
2195
2196 let mut total: Vec<u8> = Vec::new();
2197 let chunks_val = if argc > 1 {
2198 *args.get(1).ptr
2199 } else {
2200 UndefinedValue()
2201 };
2202 if chunks_val.is_object() {
2203 let mut wrapped_cx =
2204 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
2205 let cx_ref = &mut wrapped_cx;
2206 rooted!(&in(cx_ref) let arr_root = chunks_val.to_object());
2207 let mut len_val = UndefinedValue();
2208 JS_GetProperty(
2209 cx,
2210 arr_root.handle().into(),
2211 c"length".as_ptr(),
2212 MutableHandle::<Value> {
2213 _phantom_0: ::std::marker::PhantomData,
2214 ptr: &mut len_val,
2215 },
2216 );
2217 let len = if len_val.is_int32() && len_val.to_int32() > 0 {
2218 len_val.to_int32() as u32
2219 } else {
2220 0
2221 };
2222 for i in 0..len {
2223 let mut elem = UndefinedValue();
2224 JS_GetElement(
2225 cx,
2226 arr_root.handle().into(),
2227 i,
2228 MutableHandle::<Value> {
2229 _phantom_0: ::std::marker::PhantomData,
2230 ptr: &mut elem,
2231 },
2232 );
2233 rooted!(&in(cx_ref) let el_root = elem);
2234 let v = el_root.get();
2235 if v.is_string() {
2236 let s = v.to_string();
2237 if !s.is_null() {
2238 total.extend_from_slice(crate::jsstr_to_rust_string(cx, s).as_bytes());
2239 }
2240 } else if v.is_object() {
2241 match crate::node_buffer::collect_byte_view(cx, v) {
2242 ::std::option::Option::Some(bytes) => total.extend_from_slice(&bytes),
2243 ::std::option::Option::None => {
2246 JS_ReportErrorUTF8(
2247 cx,
2248 c"The \"chunk\" argument must be a string or a binary view".as_ptr(),
2249 );
2250 return false;
2251 }
2252 }
2253 } else {
2254 JS_ReportErrorUTF8(
2255 cx,
2256 c"The \"chunk\" argument must be a string or a binary view".as_ptr(),
2257 );
2258 return false;
2259 }
2260 }
2261 }
2262
2263 match bun_fs::write(&path, &total) {
2264 ::std::result::Result::Ok(()) => {
2265 args.rval().set(UndefinedValue());
2266 true
2267 }
2268 ::std::result::Result::Err(e) => throw_fs_error(cx, "createWriteStream", &path, &e),
2269 }
2270}
2271
2272#[allow(unsafe_op_in_unsafe_fn)]
2273unsafe extern "C" fn fs_append_file_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2274 let args = CallArgs::from_vp(vp, argc);
2275 let path = match get_path_arg(cx, &args, 0) {
2276 ::std::result::Result::Ok(p) => p,
2277 ::std::result::Result::Err(b) => return b,
2278 };
2279 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
2280 let c_msg = ZBox::from_bytes(e.as_bytes());
2281 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2282 return false;
2283 }
2284 let data_val = if argc > 1 {
2285 *args.get(1).ptr
2286 } else {
2287 UndefinedValue()
2288 };
2289 let data = if data_val.is_string() {
2290 let s = data_val.to_string();
2291 if !s.is_null() {
2292 crate::jsstr_to_rust_string(cx, s).into_bytes()
2293 } else {
2294 Vec::new()
2295 }
2296 } else if data_val.is_object() {
2297 crate::node_crypto::extract_buffer_bytes(cx, data_val)
2298 } else {
2299 Vec::new()
2300 };
2301
2302 match bun_fs::OpenOptions::new()
2303 .create(true)
2304 .append(true)
2305 .open(&path)
2306 {
2307 ::std::result::Result::Ok(file) => match file.write_all(&data) {
2308 ::std::result::Result::Ok(()) => {
2309 args.rval().set(UndefinedValue());
2310 true
2311 }
2312 ::std::result::Result::Err(e) => throw_fs_error(
2313 cx,
2314 "appendFileSync",
2315 &path,
2316 &::std::io::Error::from_raw_os_error(e.errno as i32),
2317 ),
2318 },
2319 ::std::result::Result::Err(e) => throw_fs_error(cx, "appendFileSync", &path, &e),
2320 }
2321}
2322
2323#[allow(unsafe_op_in_unsafe_fn)]
2324unsafe extern "C" fn fs_exists_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2325 let args = CallArgs::from_vp(vp, argc);
2326 let path = match get_path_arg(cx, &args, 0) {
2327 ::std::result::Result::Ok(p) => p,
2328 ::std::result::Result::Err(b) => return b,
2329 };
2330 args.rval()
2331 .set(mozjs::jsval::BooleanValue(Path::new(&path).exists()));
2332 true
2333}
2334
2335#[allow(unsafe_op_in_unsafe_fn)]
2336unsafe extern "C" fn fs_mkdir_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2337 let args = CallArgs::from_vp(vp, argc);
2338 let path = match get_path_arg(cx, &args, 0) {
2339 ::std::result::Result::Ok(p) => p,
2340 ::std::result::Result::Err(b) => return b,
2341 };
2342 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
2343 let c_msg = ZBox::from_bytes(e.as_bytes());
2344 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2345 return false;
2346 }
2347 let recursive = get_bool_option(cx, &args, 1, "recursive");
2348 let result = if recursive {
2349 fs::create_dir_all(&path)
2350 } else {
2351 fs::create_dir(&path)
2352 };
2353 match result {
2354 ::std::result::Result::Ok(()) => {
2355 args.rval().set(UndefinedValue());
2356 true
2357 }
2358 ::std::result::Result::Err(e) => throw_fs_error(cx, "mkdirSync", &path, &e),
2359 }
2360}
2361
2362#[allow(unsafe_op_in_unsafe_fn)]
2363unsafe extern "C" fn fs_readdir_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2364 let args = CallArgs::from_vp(vp, argc);
2365 let path = match get_path_arg(cx, &args, 0) {
2366 ::std::result::Result::Ok(p) => p,
2367 ::std::result::Result::Err(b) => return b,
2368 };
2369 let with_file_types = get_bool_option(cx, &args, 1, "withFileTypes");
2370
2371 match fs::read_dir(&path) {
2372 ::std::result::Result::Ok(entries) => {
2373 let mut names: Vec<::std::string::String> = Vec::new();
2374 let mut is_dirs: Vec<bool> = Vec::new();
2375 for entry in entries.flatten() {
2376 names.push(entry.file_name().to_string_lossy().into_owned());
2377 is_dirs.push(entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false));
2378 }
2379 let mut wrapped_cx = unsafe {
2381 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx))
2382 };
2383 let cx_ref = &mut wrapped_cx;
2384 rooted!(&in(cx_ref) let arr = unsafe { w2::NewArrayObject1(cx_ref, names.len()) });
2385 if arr.get().is_null() {
2386 args.rval().set(UndefinedValue());
2387 return true;
2388 }
2389 for (i, name) in names.iter().enumerate() {
2390 if with_file_types {
2391 let dirent = create_dirent(cx, name, is_dirs[i]);
2392 if !dirent.is_null() {
2393 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(dirent));
2394 unsafe {
2395 JS_DefineElement(
2396 cx,
2397 arr.handle().into(),
2398 i as u32,
2399 val.handle().into(),
2400 JSPROP_ENUMERATE as u32,
2401 );
2402 }
2403 }
2404 } else {
2405 let c_name = ZBox::from_bytes(name.as_bytes());
2406 let js_str = unsafe { JS_NewStringCopyZ(cx, c_name.as_ptr()) };
2407 if !js_str.is_null() {
2408 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
2409 unsafe {
2410 JS_DefineElement(
2411 cx,
2412 arr.handle().into(),
2413 i as u32,
2414 val.handle().into(),
2415 JSPROP_ENUMERATE as u32,
2416 );
2417 }
2418 }
2419 }
2420 }
2421 args.rval().set(mozjs::jsval::ObjectValue(arr.get()));
2422 true
2423 }
2424 ::std::result::Result::Err(e) => throw_fs_error(cx, "readdirSync", &path, &e),
2425 }
2426}
2427
2428#[allow(unsafe_op_in_unsafe_fn)]
2429unsafe extern "C" fn fs_stat_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2430 let args = CallArgs::from_vp(vp, argc);
2431 let path = match get_path_arg(cx, &args, 0) {
2432 ::std::result::Result::Ok(p) => p,
2433 ::std::result::Result::Err(b) => return b,
2434 };
2435 match bun_fs::metadata(&path) {
2436 ::std::result::Result::Ok(meta) => {
2437 let stats = create_stats_object(cx, &meta);
2438 args.rval().set(mozjs::jsval::ObjectValue(stats));
2439 true
2440 }
2441 ::std::result::Result::Err(e) => throw_fs_error(cx, "statSync", &path, &e),
2442 }
2443}
2444
2445#[allow(unsafe_op_in_unsafe_fn)]
2446unsafe extern "C" fn fs_lstat_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2447 let args = CallArgs::from_vp(vp, argc);
2448 let path = match get_path_arg(cx, &args, 0) {
2449 ::std::result::Result::Ok(p) => p,
2450 ::std::result::Result::Err(b) => return b,
2451 };
2452 match fs::symlink_metadata(&path) {
2453 ::std::result::Result::Ok(meta) => {
2454 let posix = metadata_to_posix_stat(&meta);
2455 let stats = create_stats_object(cx, &posix);
2456 args.rval().set(mozjs::jsval::ObjectValue(stats));
2457 true
2458 }
2459 ::std::result::Result::Err(e) => throw_fs_error(cx, "lstatSync", &path, &e),
2460 }
2461}
2462
2463#[allow(unsafe_op_in_unsafe_fn)]
2464unsafe extern "C" fn fs_unlink_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2465 let args = CallArgs::from_vp(vp, argc);
2466 let path = match get_path_arg(cx, &args, 0) {
2467 ::std::result::Result::Ok(p) => p,
2468 ::std::result::Result::Err(b) => return b,
2469 };
2470 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
2471 let c_msg = ZBox::from_bytes(e.as_bytes());
2472 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2473 return false;
2474 }
2475 match fs::remove_file(&path) {
2476 ::std::result::Result::Ok(()) => {
2477 args.rval().set(UndefinedValue());
2478 true
2479 }
2480 ::std::result::Result::Err(e) => throw_fs_error(cx, "unlinkSync", &path, &e),
2481 }
2482}
2483
2484#[allow(unsafe_op_in_unsafe_fn)]
2485unsafe extern "C" fn fs_rmdir_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2486 let args = CallArgs::from_vp(vp, argc);
2487 let path = match get_path_arg(cx, &args, 0) {
2488 ::std::result::Result::Ok(p) => p,
2489 ::std::result::Result::Err(b) => return b,
2490 };
2491 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
2492 let c_msg = ZBox::from_bytes(e.as_bytes());
2493 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2494 return false;
2495 }
2496 match fs::remove_dir(&path) {
2497 ::std::result::Result::Ok(()) => {
2498 args.rval().set(UndefinedValue());
2499 true
2500 }
2501 ::std::result::Result::Err(e) => throw_fs_error(cx, "rmdirSync", &path, &e),
2502 }
2503}
2504
2505#[allow(unsafe_op_in_unsafe_fn)]
2506unsafe extern "C" fn fs_rm_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2507 let args = CallArgs::from_vp(vp, argc);
2508 let path = match get_path_arg(cx, &args, 0) {
2509 ::std::result::Result::Ok(p) => p,
2510 ::std::result::Result::Err(b) => return b,
2511 };
2512 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
2513 let c_msg = ZBox::from_bytes(e.as_bytes());
2514 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2515 return false;
2516 }
2517 let recursive = get_bool_option(cx, &args, 1, "recursive");
2518 let result = if recursive {
2519 fs::remove_dir_all(&path)
2520 } else {
2521 fs::remove_file(&path)
2522 };
2523 match result {
2524 ::std::result::Result::Ok(()) => {
2525 args.rval().set(UndefinedValue());
2526 true
2527 }
2528 ::std::result::Result::Err(e) => throw_fs_error(cx, "rmSync", &path, &e),
2529 }
2530}
2531
2532#[allow(unsafe_op_in_unsafe_fn)]
2533unsafe extern "C" fn fs_rename_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2534 let args = CallArgs::from_vp(vp, argc);
2535 let from = match get_path_arg(cx, &args, 0) {
2536 ::std::result::Result::Ok(p) => p,
2537 ::std::result::Result::Err(b) => return b,
2538 };
2539 let to = match get_path_arg(cx, &args, 1) {
2540 ::std::result::Result::Ok(p) => p,
2541 ::std::result::Result::Err(b) => return b,
2542 };
2543 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_read(&from) {
2544 let c_msg = ZBox::from_bytes(e.as_bytes());
2545 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2546 return false;
2547 }
2548 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&to) {
2549 let c_msg = ZBox::from_bytes(e.as_bytes());
2550 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2551 return false;
2552 }
2553 match fs::rename(&from, &to) {
2554 ::std::result::Result::Ok(()) => {
2555 args.rval().set(UndefinedValue());
2556 true
2557 }
2558 ::std::result::Result::Err(e) => throw_fs_error(cx, "renameSync", &from, &e),
2559 }
2560}
2561
2562#[allow(unsafe_op_in_unsafe_fn)]
2563unsafe extern "C" fn fs_copy_file_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2564 let args = CallArgs::from_vp(vp, argc);
2565 let from = match get_path_arg(cx, &args, 0) {
2566 ::std::result::Result::Ok(p) => p,
2567 ::std::result::Result::Err(b) => return b,
2568 };
2569 let to = match get_path_arg(cx, &args, 1) {
2570 ::std::result::Result::Ok(p) => p,
2571 ::std::result::Result::Err(b) => return b,
2572 };
2573 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_read(&from) {
2574 let c_msg = ZBox::from_bytes(e.as_bytes());
2575 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2576 return false;
2577 }
2578 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&to) {
2579 let c_msg = ZBox::from_bytes(e.as_bytes());
2580 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2581 return false;
2582 }
2583 match fs::copy(&from, &to) {
2584 ::std::result::Result::Ok(_) => {
2585 args.rval().set(UndefinedValue());
2586 true
2587 }
2588 ::std::result::Result::Err(e) => throw_fs_error(cx, "copyFileSync", &from, &e),
2589 }
2590}
2591
2592#[allow(unsafe_op_in_unsafe_fn)]
2593unsafe extern "C" fn fs_chmod_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2594 let args = CallArgs::from_vp(vp, argc);
2595 let path = match get_path_arg(cx, &args, 0) {
2596 ::std::result::Result::Ok(p) => p,
2597 ::std::result::Result::Err(b) => return b,
2598 };
2599 let mode_val = if argc > 1 {
2600 *args.get(1).ptr
2601 } else {
2602 UndefinedValue()
2603 };
2604 let mode = if mode_val.is_int32() {
2605 mode_val.to_int32() as u32
2606 } else if mode_val.is_double() {
2607 mode_val.to_double() as u32
2608 } else {
2609 0o644
2610 };
2611 #[cfg(unix)]
2612 let result = {
2613 use ::std::os::unix::fs::PermissionsExt;
2614 fs::set_permissions(&path, fs::Permissions::from_mode(mode))
2615 };
2616 #[cfg(not(unix))]
2617 let result = fs::set_permissions(&path, fs::Permissions::new());
2618 match result {
2619 ::std::result::Result::Ok(()) => {
2620 args.rval().set(UndefinedValue());
2621 true
2622 }
2623 ::std::result::Result::Err(e) => throw_fs_error(cx, "chmodSync", &path, &e),
2624 }
2625}
2626
2627#[allow(unsafe_op_in_unsafe_fn)]
2628unsafe extern "C" fn fs_realpath_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2629 let args = CallArgs::from_vp(vp, argc);
2630 let path = match get_path_arg(cx, &args, 0) {
2631 ::std::result::Result::Ok(p) => p,
2632 ::std::result::Result::Err(b) => return b,
2633 };
2634 match fs::canonicalize(&path) {
2635 ::std::result::Result::Ok(resolved) => {
2636 let s = resolved.to_string_lossy();
2637 let c_str = ZBox::from_bytes(s.as_bytes());
2638 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
2639 if js_str.is_null() {
2640 args.rval().set(UndefinedValue());
2641 } else {
2642 args.rval().set(mozjs::jsval::StringValue(&*js_str));
2643 }
2644 true
2645 }
2646 ::std::result::Result::Err(e) => throw_fs_error(cx, "realpathSync", &path, &e),
2647 }
2648}
2649
2650#[allow(unsafe_op_in_unsafe_fn)]
2651unsafe extern "C" fn fs_readlink_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2652 let args = CallArgs::from_vp(vp, argc);
2653 let path = match get_path_arg(cx, &args, 0) {
2654 ::std::result::Result::Ok(p) => p,
2655 ::std::result::Result::Err(b) => return b,
2656 };
2657 match fs::read_link(&path) {
2658 ::std::result::Result::Ok(target) => {
2659 let s = target.to_string_lossy();
2660 let c_str = ZBox::from_bytes(s.as_bytes());
2661 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
2662 if js_str.is_null() {
2663 args.rval().set(UndefinedValue());
2664 } else {
2665 args.rval().set(mozjs::jsval::StringValue(&*js_str));
2666 }
2667 true
2668 }
2669 ::std::result::Result::Err(e) => throw_fs_error(cx, "readlinkSync", &path, &e),
2670 }
2671}
2672
2673#[allow(unsafe_op_in_unsafe_fn)]
2674unsafe extern "C" fn fs_symlink_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2675 let args = CallArgs::from_vp(vp, argc);
2676 let target = match get_path_arg(cx, &args, 0) {
2677 ::std::result::Result::Ok(p) => p,
2678 ::std::result::Result::Err(b) => return b,
2679 };
2680 let path = match get_path_arg(cx, &args, 1) {
2681 ::std::result::Result::Ok(p) => p,
2682 ::std::result::Result::Err(b) => return b,
2683 };
2684 #[cfg(unix)]
2685 let result = ::std::os::unix::fs::symlink(&target, &path);
2686 #[cfg(not(unix))]
2687 let result = fs::hard_link(&target, &path);
2688 match result {
2689 ::std::result::Result::Ok(()) => {
2690 args.rval().set(UndefinedValue());
2691 true
2692 }
2693 ::std::result::Result::Err(e) => throw_fs_error(cx, "symlinkSync", &target, &e),
2694 }
2695}
2696
2697#[allow(unsafe_op_in_unsafe_fn)]
2698unsafe extern "C" fn fs_link_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2699 let args = CallArgs::from_vp(vp, argc);
2700 let from = match get_path_arg(cx, &args, 0) {
2701 ::std::result::Result::Ok(p) => p,
2702 ::std::result::Result::Err(b) => return b,
2703 };
2704 let to = match get_path_arg(cx, &args, 1) {
2705 ::std::result::Result::Ok(p) => p,
2706 ::std::result::Result::Err(b) => return b,
2707 };
2708 match fs::hard_link(&from, &to) {
2709 ::std::result::Result::Ok(()) => {
2710 args.rval().set(UndefinedValue());
2711 true
2712 }
2713 ::std::result::Result::Err(e) => throw_fs_error(cx, "linkSync", &from, &e),
2714 }
2715}
2716
2717#[allow(unsafe_op_in_unsafe_fn)]
2721fn cp_recursive(src: &Path, dst: &Path, error_on_exist: bool) -> ::std::io::Result<()> {
2722 if fs::metadata(src)?.is_dir() {
2723 if error_on_exist && dst.exists() && !dst.is_dir() {
2724 return Err(::std::io::Error::new(
2725 ::std::io::ErrorKind::AlreadyExists,
2726 "destination already exists",
2727 ));
2728 }
2729 fs::create_dir_all(dst)?;
2730 for entry in fs::read_dir(src)? {
2731 let entry = entry?;
2732 let from = entry.path();
2733 let to = dst.join(entry.file_name());
2734 cp_recursive(&from, &to, error_on_exist)?;
2735 }
2736 } else {
2737 fs::copy(src, dst)?;
2738 }
2739 ::std::result::Result::Ok(())
2740}
2741
2742#[allow(unsafe_op_in_unsafe_fn)]
2743unsafe extern "C" fn fs_cp_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2744 let args = CallArgs::from_vp(vp, argc);
2745 let from = match get_path_arg(cx, &args, 0) {
2746 ::std::result::Result::Ok(p) => p,
2747 ::std::result::Result::Err(b) => return b,
2748 };
2749 let to = match get_path_arg(cx, &args, 1) {
2750 ::std::result::Result::Ok(p) => p,
2751 ::std::result::Result::Err(b) => return b,
2752 };
2753 let error_on_exist = get_bool_option(cx, &args, 2, "errorOnExist");
2754 match cp_recursive(Path::new(&from), Path::new(&to), error_on_exist) {
2755 ::std::result::Result::Ok(()) => {
2756 args.rval().set(UndefinedValue());
2757 true
2758 }
2759 ::std::result::Result::Err(e) => {
2760 let msg = format!("cpSync: {}", e);
2761 let c_msg = ZBox::from_bytes(msg.as_bytes());
2762 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2763 false
2764 }
2765 }
2766}
2767
2768#[allow(unsafe_op_in_unsafe_fn)]
2769unsafe extern "C" fn fs_cp(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
2770 let args = CallArgs::from_vp(vp, argc);
2772 let from = match get_path_arg(cx, &args, 0) {
2773 ::std::result::Result::Ok(p) => p,
2774 ::std::result::Result::Err(b) => return b,
2775 };
2776 let to = match get_path_arg(cx, &args, 1) {
2777 ::std::result::Result::Ok(p) => p,
2778 ::std::result::Result::Err(b) => return b,
2779 };
2780 let error_on_exist = get_bool_option(cx, &args, 2, "errorOnExist");
2781 let res = cp_recursive(Path::new(&from), Path::new(&to), error_on_exist);
2782 if let ::std::result::Result::Err(e) = res {
2783 let msg = format!("cp: {}", e);
2784 let c_msg = ZBox::from_bytes(msg.as_bytes());
2785 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
2786 return false;
2787 }
2788 args.rval().set(UndefinedValue());
2789 true
2790}
2791
2792#[allow(unsafe_op_in_unsafe_fn)]
2793unsafe extern "C" fn fs_watch(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
2794 let args = CallArgs::from_vp(vp, _argc);
2795 let path = match get_path_arg(cx, &args, 0) {
2796 ::std::result::Result::Ok(p) => p,
2797 ::std::result::Result::Err(b) => return b,
2798 };
2799
2800 let mut persistent = true;
2803 let mut listener_val = UndefinedValue();
2804 if _argc > 1 {
2805 let opt_val = *args.get(1).ptr;
2806 let opt_is_fn = opt_val.is_object()
2809 && unsafe { mozjs_sys::jsapi::js::IsFunctionObject(opt_val.to_object()) };
2810 if opt_val.is_object() && !opt_is_fn {
2811 let mut wrapped_opt =
2812 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
2813 let cx_opt = &mut wrapped_opt;
2814 rooted!(&in(cx_opt) let opt_obj = opt_val.to_object());
2815 let mut recursive_v = UndefinedValue();
2818 JS_GetProperty(
2819 cx,
2820 opt_obj.handle().into(),
2821 c"recursive".as_ptr(),
2822 MutableHandle::<Value> {
2823 _phantom_0: ::std::marker::PhantomData,
2824 ptr: &mut recursive_v,
2825 },
2826 );
2827 if recursive_v.is_boolean() && recursive_v.to_boolean() {
2828 JS_ReportErrorUTF8(
2829 cx,
2830 c"The value of \"options.recursive\" is not supported on this platform: watch recursive is unavailable (inotify backend covers the watched path only)".as_ptr(),
2831 );
2832 return false;
2833 }
2834 let mut persistent_v = UndefinedValue();
2835 JS_GetProperty(
2836 cx,
2837 opt_obj.handle().into(),
2838 c"persistent".as_ptr(),
2839 MutableHandle::<Value> {
2840 _phantom_0: ::std::marker::PhantomData,
2841 ptr: &mut persistent_v,
2842 },
2843 );
2844 if persistent_v.is_boolean() {
2845 persistent = persistent_v.to_boolean();
2846 }
2847 if _argc > 2 {
2848 listener_val = *args.get(2).ptr;
2849 }
2850 } else {
2851 listener_val = opt_val;
2852 }
2853 }
2854
2855 let is_dir = Path::new(&path).metadata().map(|m| m.is_dir()).unwrap_or(false);
2856
2857 let id = fsw_next_id();
2859 let wd = fsw_add_inotify_watch(&path);
2860 match wd {
2861 ::std::result::Result::Ok(wd) => {
2862 fsw_register_watch(id, wd, path.clone(), is_dir, persistent);
2863 let watcher = fsw_make_watcher_object(cx, id, is_dir);
2864 if watcher.is_null() {
2865 args.rval().set(UndefinedValue());
2866 return true;
2867 }
2868 let mut wrapped_cx =
2869 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
2870 let cx_ref = &mut wrapped_cx;
2871 rooted!(&in(cx_ref) let watcher_r = watcher);
2872 if listener_val.is_object() {
2873 let c_ev = ZBox::from_bytes("change".as_bytes());
2875 let c_name = ZBox::from_bytes("on".as_bytes());
2876 rooted!(&in(cx_ref) let lv = listener_val);
2877 let ev_str = JS_NewStringCopyZ(cx, c_ev.as_ptr());
2878 if !ev_str.is_null() {
2879 let argv = [mozjs::jsval::StringValue(&*ev_str), lv.get()];
2880 let call_args = HandleValueArray {
2881 length_: argv.len(),
2882 elements_: argv.as_ptr(),
2883 };
2884 let mut rval = UndefinedValue();
2885 JS_CallFunctionName(
2886 cx,
2887 watcher_r.handle().into(),
2888 c_name.as_ptr(),
2889 &call_args,
2890 MutableHandle::<Value> {
2891 _phantom_0: ::std::marker::PhantomData,
2892 ptr: &mut rval,
2893 },
2894 );
2895 }
2896 }
2897 args.rval().set(mozjs::jsval::ObjectValue(watcher_r.get()));
2898 true
2899 }
2900 ::std::result::Result::Err(e) => {
2901 let _ = fsw_maybe_shutdown_if_idle();
2902 throw_fs_error(cx, "watch", &path, &e)
2903 }
2904 }
2905}
2906
2907#[allow(unsafe_op_in_unsafe_fn)]
2908unsafe extern "C" fn fs_watch_file(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
2909 let args = CallArgs::from_vp(vp, _argc);
2910 let path = match get_path_arg(cx, &args, 0) {
2911 ::std::result::Result::Ok(p) => p,
2912 ::std::result::Result::Err(b) => return b,
2913 };
2914
2915 let mut interval_ms: u64 = 5007; let mut persistent = true;
2918 let mut listener_val = UndefinedValue();
2919 if _argc > 1 {
2920 let opt_val = *args.get(1).ptr;
2921 let opt_is_fn = opt_val.is_object()
2924 && unsafe { mozjs_sys::jsapi::js::IsFunctionObject(opt_val.to_object()) };
2925 if opt_val.is_object() && !opt_is_fn {
2926 let mut wrapped_opt =
2927 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
2928 let cx_opt = &mut wrapped_opt;
2929 rooted!(&in(cx_opt) let opt_obj = opt_val.to_object());
2930 let mut interval_v = UndefinedValue();
2931 JS_GetProperty(
2932 cx,
2933 opt_obj.handle().into(),
2934 c"interval".as_ptr(),
2935 MutableHandle::<Value> {
2936 _phantom_0: ::std::marker::PhantomData,
2937 ptr: &mut interval_v,
2938 },
2939 );
2940 if interval_v.is_number() {
2941 interval_ms = if interval_v.is_int32() {
2944 interval_v.to_int32().max(1) as u64
2945 } else {
2946 interval_v.to_double().max(1.0) as u64
2947 };
2948 }
2949 let mut persistent_v = UndefinedValue();
2950 JS_GetProperty(
2951 cx,
2952 opt_obj.handle().into(),
2953 c"persistent".as_ptr(),
2954 MutableHandle::<Value> {
2955 _phantom_0: ::std::marker::PhantomData,
2956 ptr: &mut persistent_v,
2957 },
2958 );
2959 if persistent_v.is_boolean() {
2960 persistent = persistent_v.to_boolean();
2961 }
2962 if _argc > 2 {
2963 listener_val = *args.get(2).ptr;
2964 }
2965 } else {
2966 listener_val = opt_val;
2967 }
2968 }
2969
2970 let id = fsw_next_id();
2971 let baseline = fsw_stat_path(&path).unwrap_or_else(fsw_zero_stat);
2974 fsw_register_poll(id, path.clone(), interval_ms, baseline, persistent);
2975
2976 let watcher = fsw_make_watcher_object(cx, id, false);
2977 if watcher.is_null() {
2978 args.rval().set(UndefinedValue());
2979 return true;
2980 }
2981 let mut wrapped_cx =
2982 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
2983 let cx_ref = &mut wrapped_cx;
2984 rooted!(&in(cx_ref) let watcher_r = watcher);
2985 if listener_val.is_object() {
2986 let c_ev = ZBox::from_bytes("change".as_bytes());
2987 let c_name = ZBox::from_bytes("on".as_bytes());
2988 rooted!(&in(cx_ref) let lv = listener_val);
2989 let ev_str = JS_NewStringCopyZ(cx, c_ev.as_ptr());
2990 if !ev_str.is_null() {
2991 let argv = [mozjs::jsval::StringValue(&*ev_str), lv.get()];
2992 let call_args = HandleValueArray {
2993 length_: argv.len(),
2994 elements_: argv.as_ptr(),
2995 };
2996 let mut rval = UndefinedValue();
2997 JS_CallFunctionName(
2998 cx,
2999 watcher_r.handle().into(),
3000 c_name.as_ptr(),
3001 &call_args,
3002 MutableHandle::<Value> {
3003 _phantom_0: ::std::marker::PhantomData,
3004 ptr: &mut rval,
3005 },
3006 );
3007 }
3008 }
3009 args.rval().set(mozjs::jsval::ObjectValue(watcher_r.get()));
3010 true
3011}
3012
3013#[allow(unsafe_op_in_unsafe_fn)]
3018unsafe extern "C" fn fs_unwatch_file(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
3019 let args = CallArgs::from_vp(vp, _argc);
3020 let path = match get_path_arg(cx, &args, 0) {
3021 ::std::result::Result::Ok(p) => p,
3022 ::std::result::Result::Err(b) => return b,
3023 };
3024 let listener_val = if _argc > 1 { *args.get(1).ptr } else { UndefinedValue() };
3025 let canonical = fsw_canonicalize(&path);
3026 let ids: Vec<u64> = FSW_POLLERS.with(|p| {
3027 p.borrow()
3028 .iter()
3029 .filter(|e| e.path == canonical)
3030 .map(|e| e.id)
3031 .collect()
3032 });
3033 for id in ids {
3034 if listener_val.is_object() {
3035 if let Some(obj) = crate::gc_store::gc_store_get_ns(cx, "fswatch", &format!("w{}", id))
3037 {
3038 let mut wrapped_cx =
3039 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
3040 let cx_ref = &mut wrapped_cx;
3041 rooted!(&in(cx_ref) let obj_r = obj);
3042 let c_rm = ZBox::from_bytes("removeListener".as_bytes());
3043 let c_ev = ZBox::from_bytes("change".as_bytes());
3044 rooted!(&in(cx_ref) let lv = listener_val);
3045 let ev_str = JS_NewStringCopyZ(cx, c_ev.as_ptr());
3046 if !ev_str.is_null() {
3047 let argv = [mozjs::jsval::StringValue(&*ev_str), lv.get()];
3048 let call_args = HandleValueArray {
3049 length_: argv.len(),
3050 elements_: argv.as_ptr(),
3051 };
3052 let mut rval = UndefinedValue();
3053 JS_CallFunctionName(
3054 cx,
3055 obj_r.handle().into(),
3056 c_rm.as_ptr(),
3057 &call_args,
3058 MutableHandle::<Value> {
3059 _phantom_0: ::std::marker::PhantomData,
3060 ptr: &mut rval,
3061 },
3062 );
3063 }
3064 if let Some(events_mod) = crate::require::get_builtin(cx, "events") {
3068 if !events_mod.is_null() {
3069 rooted!(&in(cx_ref) let em_r = events_mod);
3070 let c_cnt = ZBox::from_bytes("listenerCount".as_bytes());
3071 let ev2_str = JS_NewStringCopyZ(cx, c_ev.as_ptr());
3072 if !ev2_str.is_null() {
3073 let argv = [mozjs::jsval::ObjectValue(obj_r.get()), mozjs::jsval::StringValue(&*ev2_str)];
3074 let call_args = HandleValueArray {
3075 length_: argv.len(),
3076 elements_: argv.as_ptr(),
3077 };
3078 let mut cnt = UndefinedValue();
3079 let ok = JS_CallFunctionName(
3080 cx,
3081 em_r.handle().into(),
3082 c_cnt.as_ptr(),
3083 &call_args,
3084 MutableHandle::<Value> {
3085 _phantom_0: ::std::marker::PhantomData,
3086 ptr: &mut cnt,
3087 },
3088 );
3089 if ok && cnt.is_int32() && cnt.to_int32() > 0 {
3090 continue;
3091 }
3092 }
3093 }
3094 }
3095 }
3096 }
3097 fsw_close_entry(cx, id);
3098 }
3099 args.rval().set(UndefinedValue());
3100 true
3101}
3102
3103#[allow(unsafe_op_in_unsafe_fn)]
3104unsafe extern "C" fn fs_noop_native(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
3105 let args = CallArgs::from_vp(vp, _argc);
3106 args.rval().set(UndefinedValue());
3107 true
3108}
3109
3110enum PendingFsEvent {
3132 Inotify {
3134 id: u64,
3135 event_type: &'static str,
3137 filename: Option<String>,
3140 },
3141 StatChange {
3143 id: u64,
3144 prev: libc::stat,
3145 curr: libc::stat,
3146 },
3147 WatchError { id: u64, message: String },
3149}
3150
3151enum FswCommand {
3152 AddPoll {
3153 id: u64,
3154 path: PathBuf,
3155 interval_ms: u64,
3156 baseline: libc::stat,
3157 },
3158 RemovePoll { id: u64 },
3159 Shutdown,
3160}
3161
3162struct FswShared {
3163 queue: VecDeque<PendingFsEvent>,
3164 commands: VecDeque<FswCommand>,
3165 wd_map: HashMap<i32, Vec<u64>>,
3172}
3173
3174impl FswShared {
3175 fn new() -> Self {
3176 Self {
3177 queue: VecDeque::new(),
3178 commands: VecDeque::new(),
3179 wd_map: HashMap::new(),
3180 }
3181 }
3182}
3183
3184struct FswWatchEntry {
3186 id: u64,
3187 wd: i32,
3188 path: PathBuf,
3189 is_dir: bool,
3190 persistent: bool,
3191}
3192
3193struct FswPollEntry {
3195 id: u64,
3196 path: PathBuf,
3197 persistent: bool,
3198}
3199
3200thread_local! {
3201 static FSW_NEXT_ID: Cell<u64> = const { Cell::new(1) };
3202 static FSW_WATCHERS: RefCell<Vec<FswWatchEntry>> = const { RefCell::new(Vec::new()) };
3203 static FSW_POLLERS: RefCell<Vec<FswPollEntry>> = const { RefCell::new(Vec::new()) };
3204 static FSW_HUB: RefCell<Option<FswHub>> = const { RefCell::new(None) };
3207}
3208
3209struct FswHub {
3210 shared: Arc<Mutex<FswShared>>,
3211 inotify_fd: i32,
3212 wake_w: i32,
3213 handle: Option<::std::thread::JoinHandle<()>>,
3214}
3215
3216impl Drop for FswHub {
3217 fn drop(&mut self) {
3218 if let Ok(mut shared) = self.shared.lock() {
3221 shared.commands.push_back(FswCommand::Shutdown);
3222 }
3223 fsw_write_wake(self.wake_w);
3224 if let Some(handle) = self.handle.take() {
3225 let _ = handle.join();
3226 }
3227 if self.inotify_fd >= 0 {
3228 unsafe { libc::close(self.inotify_fd) };
3229 }
3230 if self.wake_w >= 0 {
3231 unsafe { libc::close(self.wake_w) };
3232 }
3233 }
3234}
3235
3236fn fsw_write_wake(fd: i32) {
3237 if fd < 0 {
3238 return;
3239 }
3240 let byte = [b'p'];
3241 unsafe {
3244 let _ = libc::write(fd, byte.as_ptr() as *const ::std::ffi::c_void, 1);
3245 }
3246}
3247
3248fn fsw_next_id() -> u64 {
3249 FSW_NEXT_ID.with(|c| {
3250 let v = c.get();
3251 c.set(v + 1);
3252 v
3253 })
3254}
3255
3256fn fsw_zero_stat() -> libc::stat {
3257 unsafe { ::std::mem::zeroed() }
3260}
3261
3262fn fsw_stat_path(path: &str) -> ::std::option::Option<libc::stat> {
3263 let c_path = bun_core::ZBox::from_bytes(path.as_bytes());
3264 let mut st: libc::stat = fsw_zero_stat();
3265 let rc = unsafe { libc::stat(c_path.as_ptr() as *const ::std::ffi::c_char, &mut st) };
3267 if rc == 0 {
3268 Some(st)
3269 } else {
3270 None
3271 }
3272}
3273
3274fn fsw_stat_changed(a: &libc::stat, b: &libc::stat) -> bool {
3275 a.st_size != b.st_size
3277 || a.st_mtime != b.st_mtime
3278 || a.st_mtime_nsec != b.st_mtime_nsec
3279 || a.st_ino != b.st_ino
3280 || a.st_mode != b.st_mode
3281}
3282
3283fn fsw_canonicalize(path: &str) -> PathBuf {
3284 PathBuf::from(path).canonicalize().unwrap_or_else(|_| PathBuf::from(path))
3285}
3286
3287fn fsw_ensure_hub() -> bool {
3289 FSW_HUB.with(|h| {
3290 if h.borrow().is_some() {
3291 return true;
3292 }
3293 unsafe {
3295 let inotify_fd = libc::inotify_init1(libc::IN_CLOEXEC | libc::IN_NONBLOCK);
3296 if inotify_fd < 0 {
3297 return false;
3298 }
3299 let mut pipe_fds = [-1i32, -1];
3300 if libc::pipe2(pipe_fds.as_mut_ptr(), libc::O_CLOEXEC | libc::O_NONBLOCK) != 0 {
3301 libc::close(inotify_fd);
3302 return false;
3303 }
3304 let (wake_r, wake_w) = (pipe_fds[0], pipe_fds[1]);
3305 let shared = Arc::new(Mutex::new(FswShared::new()));
3306 let worker_shared = Arc::clone(&shared);
3307 let spawned = ::std::thread::Builder::new()
3308 .name("bao-fswatch".to_string())
3309 .stack_size(128 * 1024)
3310 .spawn(move || fsw_worker_main(worker_shared, inotify_fd, wake_r));
3311 match spawned {
3312 Ok(handle) => {
3313 *h.borrow_mut() = Some(FswHub {
3315 shared,
3316 inotify_fd,
3317 wake_w,
3318 handle: Some(handle),
3319 });
3320 true
3321 }
3322 Err(_) => {
3323 libc::close(inotify_fd);
3324 libc::close(wake_r);
3325 libc::close(wake_w);
3326 false
3327 }
3328 }
3329 }
3330 })
3331}
3332
3333fn fsw_worker_main(shared: Arc<Mutex<FswShared>>, inotify_fd: i32, wake_r: i32) {
3335 struct PollSpec {
3336 id: u64,
3337 path: PathBuf,
3338 interval_ms: u64,
3339 last: libc::stat,
3340 next_due_ms: u128,
3341 }
3342 let mut polls: Vec<PollSpec> = Vec::new();
3343 let mut inotify_buf = [0u8; 64 * 1024];
3344
3345 loop {
3346 {
3348 let mut commands: VecDeque<FswCommand> = VecDeque::new();
3349 let mut shutdown = false;
3350 if let Ok(mut guard) = shared.lock() {
3351 ::std::mem::swap(&mut commands, &mut guard.commands);
3352 shutdown = commands.iter().any(|c| matches!(c, FswCommand::Shutdown));
3353 if shutdown {
3354 guard.commands.clear();
3355 }
3356 }
3357 if shutdown {
3358 break;
3359 }
3360 for cmd in commands {
3361 match cmd {
3362 FswCommand::AddPoll { id, path, interval_ms, baseline } => {
3363 polls.retain(|p| p.id != id);
3364 polls.push(PollSpec {
3365 id,
3366 path,
3367 interval_ms,
3368 last: baseline,
3369 next_due_ms: monotonic_ms().saturating_add(interval_ms as u128),
3370 });
3371 }
3372 FswCommand::RemovePoll { id } => polls.retain(|p| p.id != id),
3373 FswCommand::Shutdown => unreachable!("handled above"),
3374 }
3375 }
3376 }
3377
3378 let now = monotonic_ms();
3380 let timeout_ms: i64 = polls
3381 .iter()
3382 .map(|p| p.next_due_ms.saturating_sub(now) as i64)
3383 .min()
3384 .unwrap_or(-1);
3385 let timeout_i32: i32 = if timeout_ms < 0 {
3386 -1
3387 } else {
3388 timeout_ms.min(i32::MAX as i64) as i32
3389 };
3390
3391 let mut poll_fds = [
3392 libc::pollfd { fd: inotify_fd, events: libc::POLLIN as i16, revents: 0 },
3393 libc::pollfd { fd: wake_r, events: libc::POLLIN as i16, revents: 0 },
3394 ];
3395 let rc = unsafe { libc::poll(poll_fds.as_mut_ptr(), 2, timeout_i32) };
3398 if rc < 0 {
3399 let errno = unsafe { *libc::__errno_location() };
3400 if errno == libc::EINTR {
3401 continue;
3402 }
3403 break;
3404 }
3405
3406 if poll_fds[1].revents & (libc::POLLIN as i16) != 0 {
3408 let mut scratch = [0u8; 64];
3409 loop {
3410 let n = unsafe {
3412 libc::read(wake_r, scratch.as_mut_ptr() as *mut ::std::ffi::c_void, 64)
3413 };
3414 if n <= 0 {
3415 break;
3416 }
3417 }
3418 }
3419
3420 if poll_fds[0].revents & (libc::POLLIN as i16 | libc::POLLHUP as i16) != 0 {
3422 loop {
3423 let n = unsafe {
3425 libc::read(inotify_fd, inotify_buf.as_mut_ptr() as *mut ::std::ffi::c_void, inotify_buf.len())
3426 };
3427 if n <= 0 {
3428 break;
3429 }
3430 let buf = &inotify_buf[..n as usize];
3431 let mut off = 0usize;
3432 while off + ::std::mem::size_of::<libc::inotify_event>() <= buf.len() {
3433 let ev = unsafe {
3436 &*(buf[off..].as_ptr() as *const libc::inotify_event)
3437 };
3438 let name: Option<String> = if ev.len > 0 {
3439 let name_start = off + ::std::mem::size_of::<libc::inotify_event>();
3440 let name_end = (name_start + ev.len as usize).min(buf.len());
3441 let name_bytes: Vec<u8> = buf[name_start..name_end]
3442 .iter()
3443 .take_while(|&&b| b != 0)
3444 .cloned()
3445 .collect::<Vec<u8>>();
3446 String::from_utf8(name_bytes).ok() } else {
3448 None
3449 };
3450 let ids: Vec<u64> = shared
3453 .lock()
3454 .ok()
3455 .and_then(|g| g.wd_map.get(&ev.wd).cloned())
3456 .unwrap_or_default();
3457 for id in ids {
3458 let event_type = if ev.mask & (libc::IN_MODIFY | libc::IN_ATTRIB) != 0 {
3459 "change"
3460 } else {
3461 "rename"
3464 };
3465 if let Ok(mut guard) = shared.lock() {
3466 guard.queue.push_back(PendingFsEvent::Inotify {
3467 id,
3468 event_type,
3469 filename: name.clone(),
3470 });
3471 }
3472 }
3473 off += ::std::mem::size_of::<libc::inotify_event>() + ev.len as usize;
3474 }
3475 }
3476 }
3477
3478 let now = monotonic_ms();
3480 let mut due: Vec<usize> = Vec::new();
3481 for (i, p) in polls.iter().enumerate() {
3482 if p.next_due_ms <= now {
3483 due.push(i);
3484 }
3485 }
3486 for i in due {
3487 let Some(spec) = polls.get_mut(i) else { continue };
3488 spec.next_due_ms = now + spec.interval_ms as u128;
3489 let curr = match fsw_stat_path(&spec.path.to_string_lossy()) {
3490 Some(st) => st,
3491 None => fsw_zero_stat(),
3492 };
3493 if fsw_stat_changed(&spec.last, &curr) {
3494 let prev = spec.last;
3495 spec.last = curr;
3496 if let Ok(mut guard) = shared.lock() {
3497 guard.queue.push_back(PendingFsEvent::StatChange {
3498 id: spec.id,
3499 prev,
3500 curr,
3501 });
3502 }
3503 } else {
3504 spec.last = curr;
3505 }
3506 }
3507 }
3508 unsafe { libc::close(wake_r) };
3510}
3511
3512fn monotonic_ms() -> u128 {
3513 ::std::time::SystemTime::now()
3514 .duration_since(::std::time::UNIX_EPOCH)
3515 .map(|d| d.as_millis())
3516 .unwrap_or(0)
3517}
3518
3519fn fsw_add_inotify_watch(path: &str) -> ::std::result::Result<i32, ::std::io::Error> {
3520 if !fsw_ensure_hub() {
3521 return ::std::result::Result::Err(::std::io::Error::other(
3522 "fs.watch: failed to start the watcher thread",
3523 ));
3524 }
3525 let c_path = bun_core::ZBox::from_bytes(path.as_bytes());
3526 let mask = libc::IN_ATTRIB
3528 | libc::IN_CREATE
3529 | libc::IN_MODIFY
3530 | libc::IN_MOVED_FROM
3531 | libc::IN_MOVED_TO
3532 | libc::IN_DELETE
3533 | libc::IN_DELETE_SELF
3534 | libc::IN_MOVE_SELF;
3535 let wd = unsafe {
3537 libc::inotify_add_watch(
3538 FSW_HUB.with(|h| h.borrow().as_ref().map(|hub| hub.inotify_fd).unwrap_or(-1)),
3539 c_path.as_ptr() as *const ::std::ffi::c_char,
3540 mask,
3541 )
3542 };
3543 if wd < 0 {
3544 return ::std::result::Result::Err(::std::io::Error::last_os_error());
3545 }
3546 ::std::result::Result::Ok(wd)
3547}
3548
3549fn fsw_register_watch(id: u64, wd: i32, path: String, is_dir: bool, persistent: bool) {
3550 FSW_HUB.with(|h| {
3551 if let Some(hub) = h.borrow().as_ref() {
3552 if let Ok(mut guard) = hub.shared.lock() {
3553 guard.wd_map.entry(wd).or_default().push(id);
3556 }
3557 }
3558 });
3559 FSW_WATCHERS.with(|w| {
3560 w.borrow_mut().push(FswWatchEntry {
3561 id,
3562 wd,
3563 path: PathBuf::from(path),
3564 is_dir,
3565 persistent,
3566 });
3567 });
3568}
3569
3570fn fsw_register_poll(id: u64, path: String, interval_ms: u64, baseline: libc::stat, persistent: bool) {
3571 if !fsw_ensure_hub() {
3572 return;
3573 }
3574 FSW_POLLERS.with(|p| {
3575 p.borrow_mut().push(FswPollEntry {
3576 id,
3577 path: fsw_canonicalize(&path),
3578 persistent,
3579 });
3580 });
3581 FSW_HUB.with(|h| {
3582 if let Some(hub) = h.borrow().as_ref() {
3583 if let Ok(mut guard) = hub.shared.lock() {
3584 guard.commands.push_back(FswCommand::AddPoll {
3585 id,
3586 path: PathBuf::from(path),
3587 interval_ms,
3588 baseline,
3589 });
3590 }
3591 }
3592 });
3593 fsw_wake_worker();
3594}
3595
3596fn fsw_wake_worker() {
3597 FSW_HUB.with(|h| {
3598 if let Some(hub) = h.borrow().as_ref() {
3599 fsw_write_wake(hub.wake_w);
3600 }
3601 });
3602}
3603
3604unsafe fn fsw_close_entry(cx: *mut JSContext, id: u64) {
3607 let watch = FSW_WATCHERS.with(|w| w.borrow_mut().iter().position(|e| e.id == id));
3608 let poll = FSW_POLLERS.with(|p| p.borrow_mut().iter().position(|e| e.id == id));
3609 let key = format!("w{}", id);
3610
3611 if let Some(idx) = watch {
3612 let entry = FSW_WATCHERS.with(|w| w.borrow_mut().remove(idx));
3613 FSW_HUB.with(|h| {
3618 if let Some(hub) = h.borrow().as_ref() {
3619 let mut last_on_wd = false;
3620 if let Ok(mut guard) = hub.shared.lock() {
3621 if let Some(ids) = guard.wd_map.get_mut(&entry.wd) {
3622 ids.retain(|&i| i != id);
3623 last_on_wd = ids.is_empty();
3624 }
3625 if last_on_wd {
3626 guard.wd_map.remove(&entry.wd);
3627 }
3628 }
3629 if last_on_wd {
3630 unsafe { libc::inotify_rm_watch(hub.inotify_fd, entry.wd) };
3631 }
3632 }
3633 });
3634 }
3635 if let Some(idx) = poll {
3636 FSW_POLLERS.with(|p| p.borrow_mut().remove(idx));
3637 FSW_HUB.with(|h| {
3638 if let Some(hub) = h.borrow().as_ref() {
3639 if let Ok(mut guard) = hub.shared.lock() {
3640 guard.commands.push_back(FswCommand::RemovePoll { id });
3641 }
3642 }
3643 });
3644 fsw_wake_worker();
3645 }
3646
3647 if let Some(obj) = crate::gc_store::gc_store_get_ns(cx, "fswatch", &key) {
3650 let cx_ref = &mut mozjs::context::JSContext::from_ptr(
3651 ::std::ptr::NonNull::new_unchecked(cx),
3652 );
3653 rooted!(&in(cx_ref) let obj_r = obj);
3654 let c_emit = ZBox::from_bytes("emit".as_bytes());
3655 let c_ev = ZBox::from_bytes("close".as_bytes());
3656 let ev_str = JS_NewStringCopyZ(cx, c_ev.as_ptr());
3657 if !ev_str.is_null() {
3658 let argv = [mozjs::jsval::StringValue(&*ev_str)];
3659 let call_args = HandleValueArray {
3660 length_: argv.len(),
3661 elements_: argv.as_ptr(),
3662 };
3663 let mut rval = UndefinedValue();
3664 JS_CallFunctionName(
3665 cx,
3666 obj_r.handle().into(),
3667 c_emit.as_ptr(),
3668 &call_args,
3669 MutableHandle::<Value> {
3670 _phantom_0: ::std::marker::PhantomData,
3671 ptr: &mut rval,
3672 },
3673 );
3674 JS_ClearPendingException(cx);
3675 }
3676 }
3677 crate::gc_store::gc_store_remove_ns(cx, "fswatch", &key);
3678 let _ = fsw_maybe_shutdown_if_idle();
3679}
3680
3681fn fsw_maybe_shutdown_if_idle() -> bool {
3684 let watchers_empty = FSW_WATCHERS.with(|w| w.borrow().is_empty());
3685 let pollers_empty = FSW_POLLERS.with(|p| p.borrow().is_empty());
3686 if watchers_empty && pollers_empty {
3687 FSW_HUB.with(|h| {
3688 *h.borrow_mut() = None; });
3690 true
3691 } else {
3692 false
3693 }
3694}
3695
3696unsafe fn fsw_make_watcher_object(cx: *mut JSContext, id: u64, _is_dir: bool) -> *mut JSObject {
3699 let cx_ref = &mut mozjs::context::JSContext::from_ptr(
3700 ::std::ptr::NonNull::new_unchecked(cx),
3701 );
3702 rooted!(&in(cx_ref) let watcher = w2::JS_NewPlainObject(cx_ref));
3703 if watcher.get().is_null() {
3704 return ::std::ptr::null_mut();
3705 }
3706 let on_op: JSNative = Some(crate::node_events::ee_on);
3707 let off_op: JSNative = Some(crate::node_events::ee_off);
3708 let once_op: JSNative = Some(crate::node_events::ee_once);
3709 let emit_op: JSNative = Some(crate::node_events::ee_emit);
3710 let close_op: JSNative = Some(fsw_close_native);
3711 for (name, op, nargs) in [
3712 ("on", on_op, 2u32),
3713 ("addListener", on_op, 2),
3714 ("off", off_op, 2),
3715 ("removeListener", off_op, 2),
3716 ("once", once_op, 2),
3717 ("emit", emit_op, 2),
3718 ("close", close_op, 0),
3719 ] {
3720 let c_name = ZBox::from_bytes(name.as_bytes());
3721 mozjs_sys::jsapi::JS_DefineFunction(
3722 cx,
3723 watcher.handle().into(),
3724 c_name.as_ptr(),
3725 op,
3726 nargs,
3727 JSPROP_ENUMERATE as u32,
3728 );
3729 }
3730 rooted!(&in(cx_ref) let id_v = Int32Value(id as i32));
3733 JS_DefineProperty(
3734 cx,
3735 watcher.handle().into(),
3736 c"_fswId".as_ptr(),
3737 id_v.handle().into(),
3738 0,
3739 );
3740 crate::gc_store::gc_store_insert_ns(cx, "fswatch", &format!("w{}", id), watcher.get());
3741 watcher.get()
3742}
3743
3744#[allow(unsafe_op_in_unsafe_fn)]
3745unsafe extern "C" fn fsw_close_native(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
3746 let args = CallArgs::from_vp(vp, _argc);
3747 let this_v = *args.thisv().ptr;
3748 if this_v.is_object() {
3749 let obj = this_v.to_object();
3750 let cx_ref = &mut mozjs::context::JSContext::from_ptr(
3751 ::std::ptr::NonNull::new_unchecked(cx),
3752 );
3753 rooted!(&in(cx_ref) let obj_r = obj);
3754 let mut id_v = UndefinedValue();
3755 JS_GetProperty(
3756 cx,
3757 obj_r.handle().into(),
3758 c"_fswId".as_ptr(),
3759 MutableHandle::<Value> {
3760 _phantom_0: ::std::marker::PhantomData,
3761 ptr: &mut id_v,
3762 },
3763 );
3764 if id_v.is_int32() {
3765 fsw_close_entry(cx, id_v.to_int32() as u64);
3766 }
3767 }
3768 args.rval().set(UndefinedValue());
3769 true
3770}
3771
3772pub fn fs_watch_loop_alive() -> bool {
3775 let w = FSW_WATCHERS.with(|w| w.borrow().iter().any(|e| e.persistent));
3776 let p = FSW_POLLERS.with(|p| p.borrow().iter().any(|e| e.persistent));
3777 w || p
3778}
3779
3780pub fn fs_watch_pump_all(raw_cx: *mut JSContext) {
3784 let events: Vec<PendingFsEvent> = match FSW_HUB.with(|h| h.borrow().as_ref().map(|hub| Arc::clone(&hub.shared))) {
3786 Some(shared) => match shared.lock() {
3787 Ok(mut guard) => ::std::mem::take(&mut guard.queue).into_iter().collect(),
3788 Err(_) => return,
3789 },
3790 None => return,
3791 };
3792 if events.is_empty() {
3793 return;
3794 }
3795 for ev in events {
3796 unsafe { fsw_dispatch_event(raw_cx, ev) };
3799 }
3800}
3801
3802unsafe fn fsw_dispatch_event(raw_cx: *mut JSContext, ev: PendingFsEvent) {
3805 let (id, event_name, argv): (u64, &str, Vec<mozjs::jsval::JSVal>) = match ev {
3806 PendingFsEvent::Inotify { id, event_type, filename } => {
3807 let mut argv = Vec::with_capacity(2);
3808 let c_type = ZBox::from_bytes(event_type.as_bytes());
3809 let type_str = JS_NewStringCopyZ(raw_cx, c_type.as_ptr());
3810 if !type_str.is_null() {
3811 argv.push(mozjs::jsval::StringValue(&*type_str));
3812 }
3813 let resolved_name: Option<String> = match filename {
3817 Some(name) => Some(name),
3818 None => FSW_WATCHERS.with(|w| {
3819 w.borrow().iter().find(|e| e.id == id).and_then(|e| {
3820 if e.is_dir {
3821 None
3822 } else {
3823 e.path
3824 .file_name()
3825 .map(|n| n.to_string_lossy().into_owned())
3826 }
3827 })
3828 }),
3829 };
3830 match resolved_name {
3831 Some(name) => {
3832 let c_name = ZBox::from_bytes(name.as_bytes());
3833 let name_str = JS_NewStringCopyZ(raw_cx, c_name.as_ptr());
3834 if !name_str.is_null() {
3835 argv.push(mozjs::jsval::StringValue(&*name_str));
3836 }
3837 }
3838 None => argv.push(mozjs::jsval::NullValue()),
3839 }
3840 (id, "change", argv)
3841 }
3842 PendingFsEvent::StatChange { id, prev, curr } => {
3843 let curr_obj = build_stats_object(raw_cx, &curr);
3844 let prev_obj = build_stats_object(raw_cx, &prev);
3845 let mut argv = Vec::with_capacity(2);
3846 if !curr_obj.is_null() {
3847 argv.push(mozjs::jsval::ObjectValue(curr_obj));
3848 }
3849 if !prev_obj.is_null() {
3850 argv.push(mozjs::jsval::ObjectValue(prev_obj));
3851 }
3852 (id, "change", argv)
3853 }
3854 PendingFsEvent::WatchError { id, message } => {
3855 let c_msg = ZBox::from_bytes(message.as_bytes());
3859 let err_obj = JS_NewPlainObject(raw_cx);
3860 if !err_obj.is_null() {
3861 let cx_ref = &mut mozjs::context::JSContext::from_ptr(
3862 ::std::ptr::NonNull::new_unchecked(raw_cx),
3863 );
3864 rooted!(&in(cx_ref) let err_r = err_obj);
3865 let msg_str = JS_NewStringCopyZ(raw_cx, c_msg.as_ptr());
3866 if !msg_str.is_null() {
3867 rooted!(&in(cx_ref) let mv = mozjs::jsval::StringValue(&*msg_str));
3868 JS_DefineProperty(
3869 raw_cx,
3870 err_r.handle().into(),
3871 c"message".as_ptr(),
3872 mv.handle().into(),
3873 JSPROP_ENUMERATE as u32,
3874 );
3875 let argv = vec![mozjs::jsval::ObjectValue(err_r.get())];
3876 return fsw_emit_on_entry(raw_cx, id, "error", argv);
3877 }
3878 }
3879 return;
3880 }
3881 };
3882 fsw_emit_on_entry(raw_cx, id, event_name, argv);
3883}
3884
3885unsafe fn fsw_emit_on_entry(raw_cx: *mut JSContext, id: u64, event: &str, argv: Vec<mozjs::jsval::JSVal>) {
3886 let key = format!("w{}", id);
3887 let Some(obj) = crate::gc_store::gc_store_get_ns(raw_cx, "fswatch", &key) else {
3888 return; };
3890 let cx_ref = &mut mozjs::context::JSContext::from_ptr(
3891 ::std::ptr::NonNull::new_unchecked(raw_cx),
3892 );
3893 rooted!(&in(cx_ref) let obj_r = obj);
3894 let c_emit = ZBox::from_bytes("emit".as_bytes());
3895 let c_ev = ZBox::from_bytes(event.as_bytes());
3896 let ev_str = JS_NewStringCopyZ(raw_cx, c_ev.as_ptr());
3897 if ev_str.is_null() {
3898 return;
3899 }
3900 rooted!(&in(cx_ref) let ev_root = mozjs::jsval::StringValue(&*ev_str));
3901 let mut all_argv: Vec<mozjs::jsval::JSVal> = Vec::with_capacity(argv.len() + 1);
3902 all_argv.push(ev_root.get());
3903 all_argv.extend(argv);
3904 let call_args = HandleValueArray {
3905 length_: all_argv.len(),
3906 elements_: all_argv.as_ptr(),
3907 };
3908 let mut rval = UndefinedValue();
3909 let ok = JS_CallFunctionName(
3910 raw_cx,
3911 obj_r.handle().into(),
3912 c_emit.as_ptr(),
3913 &call_args,
3914 MutableHandle::<Value> {
3915 _phantom_0: ::std::marker::PhantomData,
3916 ptr: &mut rval,
3917 },
3918 );
3919 if !ok {
3920 let mut exn = UndefinedValue();
3923 JS_GetPendingException(
3924 raw_cx,
3925 MutableHandle::<Value> {
3926 _phantom_0: ::std::marker::PhantomData,
3927 ptr: &mut exn,
3928 },
3929 );
3930 JS_ClearPendingException(raw_cx);
3931 if !exn.is_undefined() {
3932 rooted!(&in(cx_ref) let reason_root = exn);
3933 crate::uncaught::route_uncaught_exception(raw_cx, exn);
3934 }
3935 }
3936}
3937
3938#[allow(unsafe_op_in_unsafe_fn)]
3941unsafe extern "C" fn fs_read_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
3942 let args = CallArgs::from_vp(vp, argc);
3943 let path = match get_path_arg(cx, &args, 0) {
3944 ::std::result::Result::Ok(p) => p,
3945 ::std::result::Result::Err(b) => return b,
3946 };
3947 let encoding = get_encoding_opt(cx, &args, 1);
3948
3949 match bun_fs::read(&path) {
3950 ::std::result::Result::Ok(data) => {
3951 return_string_content(cx, &args, &data, encoding.as_deref())
3952 }
3953 ::std::result::Result::Err(e) => throw_fs_error(cx, "readFile", &path, &e),
3954 }
3955}
3956
3957#[allow(unsafe_op_in_unsafe_fn)]
3958unsafe extern "C" fn fs_write_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
3959 let args = CallArgs::from_vp(vp, argc);
3960 let path = match get_path_arg(cx, &args, 0) {
3961 ::std::result::Result::Ok(p) => p,
3962 ::std::result::Result::Err(b) => return b,
3963 };
3964 let data_val = if argc > 1 {
3965 *args.get(1).ptr
3966 } else {
3967 UndefinedValue()
3968 };
3969 let bytes = if data_val.is_string() {
3970 let s = data_val.to_string();
3971 if !s.is_null() {
3972 crate::jsstr_to_rust_string(cx, s).into_bytes()
3973 } else {
3974 Vec::new()
3975 }
3976 } else {
3977 Vec::new()
3978 };
3979
3980 match bun_fs::write(&path, &bytes) {
3981 ::std::result::Result::Ok(()) => {
3982 args.rval().set(UndefinedValue());
3983 true
3984 }
3985 ::std::result::Result::Err(e) => throw_fs_error(cx, "writeFile", &path, &e),
3986 }
3987}
3988
3989#[allow(unsafe_op_in_unsafe_fn)]
3990unsafe extern "C" fn fs_mkdir(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
3991 let args = CallArgs::from_vp(vp, argc);
3992 let path = match get_path_arg(cx, &args, 0) {
3993 ::std::result::Result::Ok(p) => p,
3994 ::std::result::Result::Err(b) => return b,
3995 };
3996 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
3997 let c_msg = ZBox::from_bytes(e.as_bytes());
3998 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
3999 return false;
4000 }
4001 let recursive = get_bool_option(cx, &args, 1, "recursive");
4002 let result = if recursive {
4003 fs::create_dir_all(&path)
4004 } else {
4005 fs::create_dir(&path)
4006 };
4007 match result {
4008 ::std::result::Result::Ok(()) => {
4009 if argc > 1 && (*args.get(argc - 1).ptr).is_object() {
4010 let mut wrapped_cx_cb =
4011 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
4012 let cx_ref_cb = &mut wrapped_cx_cb;
4013 rooted!(&in(cx_ref_cb) let cb = (*args.get(argc - 1).ptr).to_object());
4014 rooted!(&in(cx_ref_cb) let cb_val = mozjs::jsval::ObjectValue(cb.get()));
4015 let null_args = HandleValueArray::empty();
4016 let global = CurrentGlobalOrNull(cx);
4017 if !global.is_null() {
4018 rooted!(&in(cx_ref_cb) let global_rooted = global);
4019 let mut rval = UndefinedValue();
4020 JS_CallFunctionValue(
4021 cx,
4022 global_rooted.handle().into(),
4023 cb_val.handle().into(),
4024 &null_args,
4025 MutableHandle::<Value> {
4026 _phantom_0: ::std::marker::PhantomData,
4027 ptr: &mut rval,
4028 },
4029 );
4030 JS_ClearPendingException(cx);
4031 }
4032 }
4033 args.rval().set(UndefinedValue());
4034 true
4035 }
4036 ::std::result::Result::Err(e) => {
4037 if argc > 1 && (*args.get(argc - 1).ptr).is_object() {
4038 let mut wrapped_cx_err =
4039 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
4040 let cx_ref_err = &mut wrapped_cx_err;
4041 rooted!(&in(cx_ref_err) let cb = (*args.get(argc - 1).ptr).to_object());
4042 rooted!(&in(cx_ref_err) let cb_val = mozjs::jsval::ObjectValue(cb.get()));
4043 let err_msg = format!("EACCES: mkdir '{}': {}", path, e);
4044 let c_err = ZBox::from_bytes(err_msg.as_bytes());
4045 rooted!(&in(cx_ref_err) let err_obj = JS_NewPlainObject(cx));
4046 if !err_obj.get().is_null() {
4047 let msg_str = JS_NewStringCopyZ(cx, c_err.as_ptr());
4048 if !msg_str.is_null() {
4049 rooted!(&in(cx_ref_err) let msg_val = mozjs::jsval::StringValue(&*msg_str));
4050 JS_DefineProperty(
4051 cx,
4052 err_obj.handle().into(),
4053 c"message".as_ptr(),
4054 msg_val.handle().into(),
4055 JSPROP_ENUMERATE as u32,
4056 );
4057 }
4058 let code_str = JS_NewStringCopyZ(cx, c"EACCES".as_ptr());
4059 if !code_str.is_null() {
4060 rooted!(&in(cx_ref_err) let code_val = mozjs::jsval::StringValue(&*code_str));
4061 JS_DefineProperty(
4062 cx,
4063 err_obj.handle().into(),
4064 c"code".as_ptr(),
4065 code_val.handle().into(),
4066 JSPROP_ENUMERATE as u32,
4067 );
4068 }
4069 rooted!(&in(cx_ref_err) let err_val = mozjs::jsval::ObjectValue(err_obj.get()));
4070 let err_args = HandleValueArray {
4071 length_: 1,
4072 elements_: &err_val.get() as *const JSVal,
4073 };
4074 let global = CurrentGlobalOrNull(cx);
4075 if !global.is_null() {
4076 rooted!(&in(cx_ref_err) let global_rooted = global);
4077 let mut rval = UndefinedValue();
4078 JS_CallFunctionValue(
4079 cx,
4080 global_rooted.handle().into(),
4081 cb_val.handle().into(),
4082 &err_args,
4083 MutableHandle::<Value> {
4084 _phantom_0: ::std::marker::PhantomData,
4085 ptr: &mut rval,
4086 },
4087 );
4088 JS_ClearPendingException(cx);
4089 }
4090 }
4091 args.rval().set(UndefinedValue());
4092 true
4093 } else {
4094 throw_fs_error(cx, "mkdir", &path, &e)
4095 }
4096 }
4097 }
4098}
4099
4100#[allow(unsafe_op_in_unsafe_fn)]
4101unsafe extern "C" fn fs_append_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4102 let args = CallArgs::from_vp(vp, argc);
4103 let path = match get_path_arg(cx, &args, 0) {
4104 ::std::result::Result::Ok(p) => p,
4105 ::std::result::Result::Err(b) => return b,
4106 };
4107 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
4108 let c_msg = ZBox::from_bytes(e.as_bytes());
4109 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
4110 return false;
4111 }
4112 let data_val = if argc > 1 {
4113 *args.get(1).ptr
4114 } else {
4115 UndefinedValue()
4116 };
4117 let data = if data_val.is_string() {
4118 let s = data_val.to_string();
4119 if !s.is_null() {
4120 crate::jsstr_to_rust_string(cx, s).into_bytes()
4121 } else {
4122 Vec::new()
4123 }
4124 } else if data_val.is_object() {
4125 crate::node_crypto::extract_buffer_bytes(cx, data_val)
4126 } else {
4127 Vec::new()
4128 };
4129
4130 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
4131 spawn_fs_async(cx, "appendFile", path.clone(), callback, None, move || {
4132 ::std::fs::OpenOptions::new()
4133 .create(true)
4134 .append(true)
4135 .open(&path)
4136 .and_then(|mut f| ::std::io::Write::write_all(&mut f, &data))
4137 .map(|_| FsAsyncResult::OkVoid)
4138 });
4139 args.rval().set(UndefinedValue());
4140 return true;
4141 }
4142
4143 match ::std::fs::OpenOptions::new()
4144 .create(true)
4145 .append(true)
4146 .open(&path)
4147 {
4148 ::std::result::Result::Ok(mut file) => {
4149 match ::std::io::Write::write_all(&mut file, &data) {
4150 ::std::result::Result::Ok(()) => {
4151 args.rval().set(UndefinedValue());
4152 true
4153 }
4154 ::std::result::Result::Err(e) => throw_fs_error(cx, "appendFile", &path, &e),
4155 }
4156 }
4157 ::std::result::Result::Err(e) => throw_fs_error(cx, "appendFile", &path, &e),
4158 }
4159}
4160
4161#[allow(unsafe_op_in_unsafe_fn)]
4162unsafe extern "C" fn fs_access(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4163 let args = CallArgs::from_vp(vp, argc);
4164 let path = match get_path_arg(cx, &args, 0) {
4165 ::std::result::Result::Ok(p) => p,
4166 ::std::result::Result::Err(b) => return b,
4167 };
4168
4169 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
4170 spawn_fs_async(cx, "access", path.clone(), callback, None, move || {
4171 fs::metadata(&path).map(|_| FsAsyncResult::OkVoid)
4172 });
4173 args.rval().set(UndefinedValue());
4174 return true;
4175 }
4176
4177 match fs::metadata(&path) {
4178 ::std::result::Result::Ok(_) => {
4179 args.rval().set(UndefinedValue());
4180 true
4181 }
4182 ::std::result::Result::Err(e) => throw_fs_error(cx, "access", &path, &e),
4183 }
4184}
4185
4186#[allow(unsafe_op_in_unsafe_fn)]
4187unsafe extern "C" fn fs_chmod(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4188 let args = CallArgs::from_vp(vp, argc);
4189 let path = match get_path_arg(cx, &args, 0) {
4190 ::std::result::Result::Ok(p) => p,
4191 ::std::result::Result::Err(b) => return b,
4192 };
4193 let mode_val = if argc > 1 {
4194 *args.get(1).ptr
4195 } else {
4196 UndefinedValue()
4197 };
4198 let mode = if mode_val.is_int32() {
4199 mode_val.to_int32() as u32
4200 } else if mode_val.is_double() {
4201 mode_val.to_double() as u32
4202 } else {
4203 0o644
4204 };
4205
4206 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
4207 spawn_fs_async(cx, "chmod", path.clone(), callback, None, move || {
4208 #[cfg(unix)]
4209 {
4210 use ::std::os::unix::fs::PermissionsExt;
4211 fs::set_permissions(&path, fs::Permissions::from_mode(mode))
4212 .map(|_| FsAsyncResult::OkVoid)
4213 }
4214 #[cfg(not(unix))]
4215 {
4216 fs::set_permissions(&path, fs::Permissions::new()).map(|_| FsAsyncResult::OkVoid)
4217 }
4218 });
4219 args.rval().set(UndefinedValue());
4220 return true;
4221 }
4222
4223 #[cfg(unix)]
4224 let result = {
4225 use ::std::os::unix::fs::PermissionsExt;
4226 fs::set_permissions(&path, fs::Permissions::from_mode(mode))
4227 };
4228 #[cfg(not(unix))]
4229 let result = { fs::set_permissions(&path, fs::Permissions::new()) };
4230 match result {
4231 ::std::result::Result::Ok(()) => {
4232 args.rval().set(UndefinedValue());
4233 true
4234 }
4235 ::std::result::Result::Err(e) => throw_fs_error(cx, "chmod", &path, &e),
4236 }
4237}
4238
4239#[allow(unsafe_op_in_unsafe_fn)]
4240unsafe extern "C" fn fs_chown(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4241 let args = CallArgs::from_vp(vp, argc);
4242 let path = match get_path_arg(cx, &args, 0) {
4243 ::std::result::Result::Ok(p) => p,
4244 ::std::result::Result::Err(b) => return b,
4245 };
4246 let uid = if argc > 1 {
4247 let v = *args.get(1).ptr;
4248 if v.is_int32() {
4249 v.to_int32() as u32
4250 } else if v.is_double() {
4251 v.to_double() as u32
4252 } else {
4253 0
4254 }
4255 } else {
4256 0
4257 };
4258 let gid = if argc > 2 {
4259 let v = *args.get(2).ptr;
4260 if v.is_int32() {
4261 v.to_int32() as u32
4262 } else if v.is_double() {
4263 v.to_double() as u32
4264 } else {
4265 0
4266 }
4267 } else {
4268 0
4269 };
4270
4271 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 3) {
4272 spawn_fs_async(cx, "chown", path.clone(), callback, None, move || {
4273 #[cfg(unix)]
4274 {
4275 ::std::os::unix::fs::chown(&path, Some(uid), Some(gid))
4276 .map(|_| FsAsyncResult::OkVoid)
4277 }
4278 #[cfg(not(unix))]
4279 {
4280 Ok(FsAsyncResult::OkVoid)
4281 }
4282 });
4283 args.rval().set(UndefinedValue());
4284 return true;
4285 }
4286
4287 #[cfg(unix)]
4288 match ::std::os::unix::fs::chown(&path, Some(uid), Some(gid)) {
4289 ::std::result::Result::Ok(()) => {
4290 args.rval().set(UndefinedValue());
4291 true
4292 }
4293 ::std::result::Result::Err(e) => throw_fs_error(cx, "chown", &path, &e),
4294 }
4295 #[cfg(not(unix))]
4296 {
4297 args.rval().set(UndefinedValue());
4298 true
4299 }
4300}
4301
4302#[allow(unsafe_op_in_unsafe_fn)]
4303unsafe extern "C" fn fs_close(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4304 let args = CallArgs::from_vp(vp, argc);
4305 let fd_val = if argc > 0 {
4306 *args.get(0).ptr
4307 } else {
4308 UndefinedValue()
4309 };
4310 let fd = if fd_val.is_int32() {
4311 fd_val.to_int32()
4312 } else {
4313 -1
4314 };
4315
4316 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
4317 spawn_fs_async(
4318 cx,
4319 "close",
4320 format!("fd:{}", fd),
4321 callback,
4322 None,
4323 move || {
4324 #[cfg(unix)]
4325 {
4326 let rv = unsafe { libc::close(fd) };
4327 if rv == 0 {
4328 Ok(FsAsyncResult::OkVoid)
4329 } else {
4330 Err(::std::io::Error::last_os_error())
4331 }
4332 }
4333 #[cfg(not(unix))]
4334 {
4335 Ok(FsAsyncResult::OkVoid)
4336 }
4337 },
4338 );
4339 args.rval().set(UndefinedValue());
4340 return true;
4341 }
4342
4343 #[cfg(unix)]
4344 {
4345 let rv = unsafe { libc::close(fd) };
4346 if rv == 0 {
4347 args.rval().set(UndefinedValue());
4348 true
4349 } else {
4350 throw_fs_error(
4351 cx,
4352 "close",
4353 &format!("fd:{}", fd),
4354 &::std::io::Error::last_os_error(),
4355 )
4356 }
4357 }
4358 #[cfg(not(unix))]
4359 {
4360 args.rval().set(UndefinedValue());
4361 true
4362 }
4363}
4364
4365#[allow(unsafe_op_in_unsafe_fn)]
4366unsafe extern "C" fn fs_copy_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4367 let args = CallArgs::from_vp(vp, argc);
4368 let from = match get_path_arg(cx, &args, 0) {
4369 ::std::result::Result::Ok(p) => p,
4370 ::std::result::Result::Err(b) => return b,
4371 };
4372 let to = match get_path_arg(cx, &args, 1) {
4373 ::std::result::Result::Ok(p) => p,
4374 ::std::result::Result::Err(b) => return b,
4375 };
4376
4377 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
4378 spawn_fs_async(cx, "copyFile", from.clone(), callback, None, move || {
4379 fs::copy(&from, &to).map(|_| FsAsyncResult::OkVoid)
4380 });
4381 args.rval().set(UndefinedValue());
4382 return true;
4383 }
4384
4385 match fs::copy(&from, &to) {
4386 ::std::result::Result::Ok(_) => {
4387 args.rval().set(UndefinedValue());
4388 true
4389 }
4390 ::std::result::Result::Err(e) => throw_fs_error(cx, "copyFile", &from, &e),
4391 }
4392}
4393
4394#[allow(unsafe_op_in_unsafe_fn)]
4395unsafe extern "C" fn fs_exists(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4396 let args = CallArgs::from_vp(vp, argc);
4397 let path = match get_path_arg(cx, &args, 0) {
4398 ::std::result::Result::Ok(p) => p,
4399 ::std::result::Result::Err(b) => return b,
4400 };
4401
4402 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
4403 spawn_fs_async(cx, "exists", path.clone(), callback, None, move || {
4404 Ok(FsAsyncResult::OkBool(Path::new(&path).exists()))
4405 });
4406 args.rval().set(UndefinedValue());
4407 return true;
4408 }
4409
4410 args.rval()
4411 .set(mozjs::jsval::BooleanValue(Path::new(&path).exists()));
4412 true
4413}
4414
4415#[allow(unsafe_op_in_unsafe_fn)]
4416unsafe extern "C" fn fs_fchmod(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4417 let args = CallArgs::from_vp(vp, argc);
4418 let fd_val = if argc > 0 {
4419 *args.get(0).ptr
4420 } else {
4421 UndefinedValue()
4422 };
4423 let fd = if fd_val.is_int32() {
4424 fd_val.to_int32()
4425 } else {
4426 -1
4427 };
4428 let mode_val = if argc > 1 {
4429 *args.get(1).ptr
4430 } else {
4431 UndefinedValue()
4432 };
4433 let mode = if mode_val.is_int32() {
4434 mode_val.to_int32() as u32
4435 } else {
4436 0o644
4437 };
4438
4439 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
4440 spawn_fs_async(
4441 cx,
4442 "fchmod",
4443 format!("fd:{}", fd),
4444 callback,
4445 None,
4446 move || {
4447 #[cfg(unix)]
4448 {
4449 let rv = unsafe { libc::fchmod(fd, mode) };
4450 if rv == 0 {
4451 Ok(FsAsyncResult::OkVoid)
4452 } else {
4453 Err(::std::io::Error::last_os_error())
4454 }
4455 }
4456 #[cfg(not(unix))]
4457 {
4458 Ok(FsAsyncResult::OkVoid)
4459 }
4460 },
4461 );
4462 args.rval().set(UndefinedValue());
4463 return true;
4464 }
4465
4466 #[cfg(unix)]
4467 {
4468 let rv = unsafe { libc::fchmod(fd, mode) };
4469 if rv == 0 {
4470 args.rval().set(UndefinedValue());
4471 true
4472 } else {
4473 throw_fs_error(
4474 cx,
4475 "fchmod",
4476 &format!("fd:{}", fd),
4477 &::std::io::Error::last_os_error(),
4478 )
4479 }
4480 }
4481 #[cfg(not(unix))]
4482 {
4483 args.rval().set(UndefinedValue());
4484 true
4485 }
4486}
4487
4488#[allow(unsafe_op_in_unsafe_fn)]
4489unsafe extern "C" fn fs_fchown(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4490 let args = CallArgs::from_vp(vp, argc);
4491 let fd_val = if argc > 0 {
4492 *args.get(0).ptr
4493 } else {
4494 UndefinedValue()
4495 };
4496 let fd = if fd_val.is_int32() {
4497 fd_val.to_int32()
4498 } else {
4499 -1
4500 };
4501 let uid = if argc > 1 {
4502 let v = *args.get(1).ptr;
4503 if v.is_int32() { v.to_int32() as u32 } else { 0 }
4504 } else {
4505 0
4506 };
4507 let gid = if argc > 2 {
4508 let v = *args.get(2).ptr;
4509 if v.is_int32() { v.to_int32() as u32 } else { 0 }
4510 } else {
4511 0
4512 };
4513
4514 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 3) {
4515 spawn_fs_async(
4516 cx,
4517 "fchown",
4518 format!("fd:{}", fd),
4519 callback,
4520 None,
4521 move || {
4522 #[cfg(unix)]
4523 {
4524 let rv = unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) };
4525 if rv == 0 {
4526 Ok(FsAsyncResult::OkVoid)
4527 } else {
4528 Err(::std::io::Error::last_os_error())
4529 }
4530 }
4531 #[cfg(not(unix))]
4532 {
4533 Ok(FsAsyncResult::OkVoid)
4534 }
4535 },
4536 );
4537 args.rval().set(UndefinedValue());
4538 return true;
4539 }
4540
4541 #[cfg(unix)]
4542 {
4543 let rv = unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) };
4544 if rv == 0 {
4545 args.rval().set(UndefinedValue());
4546 true
4547 } else {
4548 throw_fs_error(
4549 cx,
4550 "fchown",
4551 &format!("fd:{}", fd),
4552 &::std::io::Error::last_os_error(),
4553 )
4554 }
4555 }
4556 #[cfg(not(unix))]
4557 {
4558 args.rval().set(UndefinedValue());
4559 true
4560 }
4561}
4562
4563#[allow(unsafe_op_in_unsafe_fn)]
4564unsafe extern "C" fn fs_fdatasync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4565 let args = CallArgs::from_vp(vp, argc);
4566 let fd_val = if argc > 0 {
4567 *args.get(0).ptr
4568 } else {
4569 UndefinedValue()
4570 };
4571 let fd = if fd_val.is_int32() {
4572 fd_val.to_int32()
4573 } else {
4574 -1
4575 };
4576
4577 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
4578 spawn_fs_async(
4579 cx,
4580 "fdatasync",
4581 format!("fd:{}", fd),
4582 callback,
4583 None,
4584 move || {
4585 #[cfg(unix)]
4586 {
4587 let rv = unsafe { libc::fdatasync(fd) };
4588 if rv == 0 {
4589 Ok(FsAsyncResult::OkVoid)
4590 } else {
4591 Err(::std::io::Error::last_os_error())
4592 }
4593 }
4594 #[cfg(not(unix))]
4595 {
4596 Ok(FsAsyncResult::OkVoid)
4597 }
4598 },
4599 );
4600 args.rval().set(UndefinedValue());
4601 return true;
4602 }
4603
4604 #[cfg(unix)]
4605 {
4606 let rv = unsafe { libc::fdatasync(fd) };
4607 if rv == 0 {
4608 args.rval().set(UndefinedValue());
4609 true
4610 } else {
4611 throw_fs_error(
4612 cx,
4613 "fdatasync",
4614 &format!("fd:{}", fd),
4615 &::std::io::Error::last_os_error(),
4616 )
4617 }
4618 }
4619 #[cfg(not(unix))]
4620 {
4621 args.rval().set(UndefinedValue());
4622 true
4623 }
4624}
4625
4626#[allow(unsafe_op_in_unsafe_fn)]
4627unsafe extern "C" fn fs_fstat(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4628 let args = CallArgs::from_vp(vp, argc);
4629 let fd_val = if argc > 0 {
4630 *args.get(0).ptr
4631 } else {
4632 UndefinedValue()
4633 };
4634 let fd = if fd_val.is_int32() {
4635 fd_val.to_int32()
4636 } else {
4637 -1
4638 };
4639
4640 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
4641 spawn_fs_async(
4642 cx,
4643 "fstat",
4644 format!("fd:{}", fd),
4645 callback,
4646 None,
4647 move || {
4648 #[cfg(unix)]
4649 {
4650 let mut stat_buf: libc::stat = ::std::mem::zeroed();
4651 let rv = unsafe { libc::fstat(fd, &mut stat_buf) };
4652 if rv == 0 {
4653 Ok(FsAsyncResult::OkStat(posix_stat_from_libc(&stat_buf)))
4654 } else {
4655 Err(::std::io::Error::last_os_error())
4656 }
4657 }
4658 #[cfg(not(unix))]
4659 {
4660 Ok(FsAsyncResult::OkVoid)
4661 }
4662 },
4663 );
4664 args.rval().set(UndefinedValue());
4665 return true;
4666 }
4667
4668 #[cfg(unix)]
4669 {
4670 let mut stat_buf: libc::stat = ::std::mem::zeroed();
4671 let rv = unsafe { libc::fstat(fd, &mut stat_buf) };
4672 if rv == 0 {
4673 let posix = posix_stat_from_libc(&stat_buf);
4674 let stats = create_stats_object(cx, &posix);
4675 args.rval().set(mozjs::jsval::ObjectValue(stats));
4676 true
4677 } else {
4678 throw_fs_error(
4679 cx,
4680 "fstat",
4681 &format!("fd:{}", fd),
4682 &::std::io::Error::last_os_error(),
4683 )
4684 }
4685 }
4686 #[cfg(not(unix))]
4687 {
4688 args.rval().set(UndefinedValue());
4689 true
4690 }
4691}
4692
4693#[allow(unsafe_op_in_unsafe_fn)]
4694unsafe extern "C" fn fs_fsync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4695 let args = CallArgs::from_vp(vp, argc);
4696 let fd_val = if argc > 0 {
4697 *args.get(0).ptr
4698 } else {
4699 UndefinedValue()
4700 };
4701 let fd = if fd_val.is_int32() {
4702 fd_val.to_int32()
4703 } else {
4704 -1
4705 };
4706
4707 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
4708 spawn_fs_async(
4709 cx,
4710 "fsync",
4711 format!("fd:{}", fd),
4712 callback,
4713 None,
4714 move || {
4715 #[cfg(unix)]
4716 {
4717 let rv = unsafe { libc::fsync(fd) };
4718 if rv == 0 {
4719 Ok(FsAsyncResult::OkVoid)
4720 } else {
4721 Err(::std::io::Error::last_os_error())
4722 }
4723 }
4724 #[cfg(not(unix))]
4725 {
4726 Ok(FsAsyncResult::OkVoid)
4727 }
4728 },
4729 );
4730 args.rval().set(UndefinedValue());
4731 return true;
4732 }
4733
4734 #[cfg(unix)]
4735 {
4736 let rv = unsafe { libc::fsync(fd) };
4737 if rv == 0 {
4738 args.rval().set(UndefinedValue());
4739 true
4740 } else {
4741 throw_fs_error(
4742 cx,
4743 "fsync",
4744 &format!("fd:{}", fd),
4745 &::std::io::Error::last_os_error(),
4746 )
4747 }
4748 }
4749 #[cfg(not(unix))]
4750 {
4751 args.rval().set(UndefinedValue());
4752 true
4753 }
4754}
4755
4756#[allow(unsafe_op_in_unsafe_fn)]
4757unsafe extern "C" fn fs_ftruncate(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4758 let args = CallArgs::from_vp(vp, argc);
4759 let fd_val = if argc > 0 {
4760 *args.get(0).ptr
4761 } else {
4762 UndefinedValue()
4763 };
4764 let fd = if fd_val.is_int32() {
4765 fd_val.to_int32()
4766 } else {
4767 -1
4768 };
4769 let len_val = if argc > 1 {
4770 *args.get(1).ptr
4771 } else {
4772 UndefinedValue()
4773 };
4774 let len = if len_val.is_int32() {
4775 len_val.to_int32() as i64
4776 } else if len_val.is_double() {
4777 len_val.to_double() as i64
4778 } else {
4779 0
4780 };
4781
4782 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
4783 spawn_fs_async(
4784 cx,
4785 "ftruncate",
4786 format!("fd:{}", fd),
4787 callback,
4788 None,
4789 move || {
4790 #[cfg(unix)]
4791 {
4792 let rv = unsafe { libc::ftruncate(fd, len) };
4793 if rv == 0 {
4794 Ok(FsAsyncResult::OkVoid)
4795 } else {
4796 Err(::std::io::Error::last_os_error())
4797 }
4798 }
4799 #[cfg(not(unix))]
4800 {
4801 Ok(FsAsyncResult::OkVoid)
4802 }
4803 },
4804 );
4805 args.rval().set(UndefinedValue());
4806 return true;
4807 }
4808
4809 #[cfg(unix)]
4810 {
4811 let rv = unsafe { libc::ftruncate(fd, len) };
4812 if rv == 0 {
4813 args.rval().set(UndefinedValue());
4814 true
4815 } else {
4816 throw_fs_error(
4817 cx,
4818 "ftruncate",
4819 &format!("fd:{}", fd),
4820 &::std::io::Error::last_os_error(),
4821 )
4822 }
4823 }
4824 #[cfg(not(unix))]
4825 {
4826 args.rval().set(UndefinedValue());
4827 true
4828 }
4829}
4830
4831#[allow(unsafe_op_in_unsafe_fn)]
4832unsafe extern "C" fn fs_futimes(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4833 let args = CallArgs::from_vp(vp, argc);
4834 let fd_val = if argc > 0 {
4835 *args.get(0).ptr
4836 } else {
4837 UndefinedValue()
4838 };
4839 let fd = if fd_val.is_int32() {
4840 fd_val.to_int32()
4841 } else {
4842 -1
4843 };
4844 let atime_val = if argc > 1 {
4845 *args.get(1).ptr
4846 } else {
4847 UndefinedValue()
4848 };
4849 let mtime_val = if argc > 2 {
4850 *args.get(2).ptr
4851 } else {
4852 UndefinedValue()
4853 };
4854 let atime = if atime_val.is_double() {
4855 atime_val.to_double()
4856 } else if atime_val.is_int32() {
4857 atime_val.to_int32() as f64
4858 } else {
4859 0.0
4860 };
4861 let mtime = if mtime_val.is_double() {
4862 mtime_val.to_double()
4863 } else if mtime_val.is_int32() {
4864 mtime_val.to_int32() as f64
4865 } else {
4866 0.0
4867 };
4868
4869 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 3) {
4870 spawn_fs_async(
4871 cx,
4872 "futimes",
4873 format!("fd:{}", fd),
4874 callback,
4875 None,
4876 move || {
4877 #[cfg(unix)]
4878 {
4879 let tv = [
4880 libc::timeval {
4881 tv_sec: atime as i64,
4882 tv_usec: ((atime % 1.0) * 1_000_000.0) as i64,
4883 },
4884 libc::timeval {
4885 tv_sec: mtime as i64,
4886 tv_usec: ((mtime % 1.0) * 1_000_000.0) as i64,
4887 },
4888 ];
4889 let rv = unsafe { libc::futimes(fd, tv.as_ptr()) };
4890 if rv == 0 {
4891 Ok(FsAsyncResult::OkVoid)
4892 } else {
4893 Err(::std::io::Error::last_os_error())
4894 }
4895 }
4896 #[cfg(not(unix))]
4897 {
4898 Ok(FsAsyncResult::OkVoid)
4899 }
4900 },
4901 );
4902 args.rval().set(UndefinedValue());
4903 return true;
4904 }
4905
4906 #[cfg(unix)]
4907 {
4908 let tv = [
4909 libc::timeval {
4910 tv_sec: atime as i64,
4911 tv_usec: ((atime % 1.0) * 1_000_000.0) as i64,
4912 },
4913 libc::timeval {
4914 tv_sec: mtime as i64,
4915 tv_usec: ((mtime % 1.0) * 1_000_000.0) as i64,
4916 },
4917 ];
4918 let rv = unsafe { libc::futimes(fd, tv.as_ptr()) };
4919 if rv == 0 {
4920 args.rval().set(UndefinedValue());
4921 true
4922 } else {
4923 throw_fs_error(
4924 cx,
4925 "futimes",
4926 &format!("fd:{}", fd),
4927 &::std::io::Error::last_os_error(),
4928 )
4929 }
4930 }
4931 #[cfg(not(unix))]
4932 {
4933 args.rval().set(UndefinedValue());
4934 true
4935 }
4936}
4937
4938#[allow(unsafe_op_in_unsafe_fn)]
4939unsafe extern "C" fn fs_lchown(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4940 let args = CallArgs::from_vp(vp, argc);
4941 let path = match get_path_arg(cx, &args, 0) {
4942 ::std::result::Result::Ok(p) => p,
4943 ::std::result::Result::Err(b) => return b,
4944 };
4945 let uid = if argc > 1 {
4946 let v = *args.get(1).ptr;
4947 if v.is_int32() { v.to_int32() as u32 } else { 0 }
4948 } else {
4949 0
4950 };
4951 let gid = if argc > 2 {
4952 let v = *args.get(2).ptr;
4953 if v.is_int32() { v.to_int32() as u32 } else { 0 }
4954 } else {
4955 0
4956 };
4957
4958 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 3) {
4959 spawn_fs_async(cx, "lchown", path.clone(), callback, None, move || {
4960 #[cfg(unix)]
4961 {
4962 let c_p = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
4963 let rv = unsafe { libc::lchown(c_p.as_ptr(), uid, gid) };
4964 if rv == 0 {
4965 Ok(FsAsyncResult::OkVoid)
4966 } else {
4967 Err(::std::io::Error::last_os_error())
4968 }
4969 }
4970 #[cfg(not(unix))]
4971 {
4972 Ok(FsAsyncResult::OkVoid)
4973 }
4974 });
4975 args.rval().set(UndefinedValue());
4976 return true;
4977 }
4978
4979 #[cfg(unix)]
4980 {
4981 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
4982 let rv = unsafe { libc::lchown(c_path.as_ptr(), uid, gid) };
4983 if rv == 0 {
4984 args.rval().set(UndefinedValue());
4985 true
4986 } else {
4987 throw_fs_error(cx, "lchown", &path, &::std::io::Error::last_os_error())
4988 }
4989 }
4990 #[cfg(not(unix))]
4991 {
4992 args.rval().set(UndefinedValue());
4993 true
4994 }
4995}
4996
4997#[allow(unsafe_op_in_unsafe_fn)]
4998unsafe extern "C" fn fs_link(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
4999 let args = CallArgs::from_vp(vp, argc);
5000 let from = match get_path_arg(cx, &args, 0) {
5001 ::std::result::Result::Ok(p) => p,
5002 ::std::result::Result::Err(b) => return b,
5003 };
5004 let to = match get_path_arg(cx, &args, 1) {
5005 ::std::result::Result::Ok(p) => p,
5006 ::std::result::Result::Err(b) => return b,
5007 };
5008
5009 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
5010 spawn_fs_async(cx, "link", from.clone(), callback, None, move || {
5011 fs::hard_link(&from, &to).map(|_| FsAsyncResult::OkVoid)
5012 });
5013 args.rval().set(UndefinedValue());
5014 return true;
5015 }
5016
5017 match fs::hard_link(&from, &to) {
5018 ::std::result::Result::Ok(()) => {
5019 args.rval().set(UndefinedValue());
5020 true
5021 }
5022 ::std::result::Result::Err(e) => throw_fs_error(cx, "link", &from, &e),
5023 }
5024}
5025
5026#[allow(unsafe_op_in_unsafe_fn)]
5027unsafe extern "C" fn fs_lstat(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5028 let args = CallArgs::from_vp(vp, argc);
5029 let path = match get_path_arg(cx, &args, 0) {
5030 ::std::result::Result::Ok(p) => p,
5031 ::std::result::Result::Err(b) => return b,
5032 };
5033
5034 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
5035 spawn_fs_async(cx, "lstat", path.clone(), callback, None, move || {
5036 fs::symlink_metadata(&path).map(|m| FsAsyncResult::OkStat(metadata_to_posix_stat(&m)))
5037 });
5038 args.rval().set(UndefinedValue());
5039 return true;
5040 }
5041
5042 match fs::symlink_metadata(&path) {
5043 ::std::result::Result::Ok(meta) => {
5044 let posix = metadata_to_posix_stat(&meta);
5045 let stats = create_stats_object(cx, &posix);
5046 args.rval().set(mozjs::jsval::ObjectValue(stats));
5047 true
5048 }
5049 ::std::result::Result::Err(e) => throw_fs_error(cx, "lstat", &path, &e),
5050 }
5051}
5052
5053#[allow(unsafe_op_in_unsafe_fn)]
5054unsafe extern "C" fn fs_lutimes(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5055 let args = CallArgs::from_vp(vp, argc);
5056 let path = match get_path_arg(cx, &args, 0) {
5057 ::std::result::Result::Ok(p) => p,
5058 ::std::result::Result::Err(b) => return b,
5059 };
5060 let atime_val = if argc > 1 {
5061 *args.get(1).ptr
5062 } else {
5063 UndefinedValue()
5064 };
5065 let mtime_val = if argc > 2 {
5066 *args.get(2).ptr
5067 } else {
5068 UndefinedValue()
5069 };
5070 let atime = if atime_val.is_double() {
5071 atime_val.to_double()
5072 } else if atime_val.is_int32() {
5073 atime_val.to_int32() as f64
5074 } else {
5075 0.0
5076 };
5077 let mtime = if mtime_val.is_double() {
5078 mtime_val.to_double()
5079 } else if mtime_val.is_int32() {
5080 mtime_val.to_int32() as f64
5081 } else {
5082 0.0
5083 };
5084
5085 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 3) {
5086 spawn_fs_async(cx, "lutimes", path.clone(), callback, None, move || {
5087 #[cfg(unix)]
5088 {
5089 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
5090 let tv = [
5091 libc::timeval {
5092 tv_sec: atime as i64,
5093 tv_usec: ((atime % 1.0) * 1_000_000.0) as i64,
5094 },
5095 libc::timeval {
5096 tv_sec: mtime as i64,
5097 tv_usec: ((mtime % 1.0) * 1_000_000.0) as i64,
5098 },
5099 ];
5100 let rv = unsafe { libc::lutimes(c_path.as_ptr(), tv.as_ptr()) };
5101 if rv == 0 {
5102 Ok(FsAsyncResult::OkVoid)
5103 } else {
5104 Err(::std::io::Error::last_os_error())
5105 }
5106 }
5107 #[cfg(not(unix))]
5108 {
5109 Ok(FsAsyncResult::OkVoid)
5110 }
5111 });
5112 args.rval().set(UndefinedValue());
5113 return true;
5114 }
5115
5116 #[cfg(unix)]
5117 {
5118 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
5119 let tv = [
5120 libc::timeval {
5121 tv_sec: atime as i64,
5122 tv_usec: ((atime % 1.0) * 1_000_000.0) as i64,
5123 },
5124 libc::timeval {
5125 tv_sec: mtime as i64,
5126 tv_usec: ((mtime % 1.0) * 1_000_000.0) as i64,
5127 },
5128 ];
5129 let rv = unsafe { libc::lutimes(c_path.as_ptr(), tv.as_ptr()) };
5130 if rv == 0 {
5131 args.rval().set(UndefinedValue());
5132 true
5133 } else {
5134 throw_fs_error(cx, "lutimes", &path, &::std::io::Error::last_os_error())
5135 }
5136 }
5137 #[cfg(not(unix))]
5138 {
5139 args.rval().set(UndefinedValue());
5140 true
5141 }
5142}
5143
5144#[allow(unsafe_op_in_unsafe_fn)]
5145unsafe extern "C" fn fs_mkdtemp(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5146 let args = CallArgs::from_vp(vp, argc);
5147 let prefix = match get_path_arg(cx, &args, 0) {
5148 ::std::result::Result::Ok(p) => p,
5149 ::std::result::Result::Err(b) => return b,
5150 };
5151 let _encoding = get_encoding_opt(cx, &args, 1);
5152
5153 if let Some((callback, cb_encoding)) = extract_callback_and_encoding(cx, &args, 1) {
5154 spawn_fs_async(
5155 cx,
5156 "mkdtemp",
5157 prefix.clone(),
5158 callback,
5159 cb_encoding,
5160 move || mkdtemp_inner(&prefix).map(FsAsyncResult::OkString),
5161 );
5162 args.rval().set(UndefinedValue());
5163 return true;
5164 }
5165
5166 match mkdtemp_inner(&prefix) {
5167 ::std::result::Result::Ok(dir) => {
5168 let c_str = ZBox::from_bytes(dir.as_bytes());
5169 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
5170 if js_str.is_null() {
5171 args.rval().set(UndefinedValue());
5172 } else {
5173 args.rval().set(mozjs::jsval::StringValue(&*js_str));
5174 }
5175 true
5176 }
5177 ::std::result::Result::Err(e) => throw_fs_error(cx, "mkdtemp", &prefix, &e),
5178 }
5179}
5180
5181fn mkdtemp_inner(prefix: &str) -> ::std::io::Result<String> {
5182 if prefix.is_empty() {
5186 return Err(::std::io::Error::from_raw_os_error(libc::EINVAL));
5187 }
5188 let mut template = prefix.to_string();
5189 template.push_str("XXXXXX");
5190 let c_template = ::std::ffi::CString::new(template).map_err(|_| {
5191 ::std::io::Error::new(
5192 ::std::io::ErrorKind::InvalidInput,
5193 "prefix contains null byte",
5194 )
5195 })?;
5196 let c_ptr = c_template.into_raw();
5197 let result = unsafe { libc::mkdtemp(c_ptr) };
5198 if result.is_null() {
5199 let e = ::std::io::Error::last_os_error();
5200 unsafe {
5201 let _ = ::std::ffi::CString::from_raw(c_ptr);
5202 }
5203 return Err(e);
5204 }
5205 let result_cstr = unsafe { ::std::ffi::CString::from_raw(result) };
5206 result_cstr
5207 .into_string()
5208 .map_err(|e| ::std::io::Error::new(::std::io::ErrorKind::InvalidData, e))
5209}
5210
5211#[allow(unsafe_op_in_unsafe_fn)]
5212unsafe extern "C" fn fs_open(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5213 let args = CallArgs::from_vp(vp, argc);
5214 let path = match get_path_arg(cx, &args, 0) {
5215 ::std::result::Result::Ok(p) => p,
5216 ::std::result::Result::Err(b) => return b,
5217 };
5218 let flags_val = if argc > 1 {
5219 *args.get(1).ptr
5220 } else {
5221 UndefinedValue()
5222 };
5223 let flags = if flags_val.is_int32() {
5224 flags_val.to_int32()
5225 } else if flags_val.is_string() {
5226 let s = flags_val.to_string();
5227 if !s.is_null() {
5228 let rust_str = crate::jsstr_to_rust_string(cx, s);
5229 parse_open_flags(&rust_str)
5230 } else {
5231 0
5232 }
5233 } else {
5234 0
5235 };
5236 let mode_val = if argc > 2 {
5237 *args.get(2).ptr
5238 } else {
5239 UndefinedValue()
5240 };
5241 let mode = if mode_val.is_int32() {
5242 mode_val.to_int32() as u32
5243 } else {
5244 0o644
5245 };
5246
5247 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 3) {
5248 spawn_fs_async(cx, "open", path.clone(), callback, None, move || {
5249 #[cfg(unix)]
5250 {
5251 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
5252 let fd = unsafe { libc::open(c_path.as_ptr(), flags, mode) };
5253 if fd >= 0 {
5254 Ok(FsAsyncResult::OkOpen(fd))
5255 } else {
5256 Err(::std::io::Error::last_os_error())
5257 }
5258 }
5259 #[cfg(not(unix))]
5260 {
5261 Ok(FsAsyncResult::OkOpen(0))
5262 }
5263 });
5264 args.rval().set(UndefinedValue());
5265 return true;
5266 }
5267
5268 #[cfg(unix)]
5269 {
5270 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
5271 let fd = unsafe { libc::open(c_path.as_ptr(), flags, mode) };
5272 if fd >= 0 {
5273 args.rval().set(mozjs::jsval::Int32Value(fd));
5274 true
5275 } else {
5276 throw_fs_error(cx, "open", &path, &::std::io::Error::last_os_error())
5277 }
5278 }
5279 #[cfg(not(unix))]
5280 {
5281 args.rval().set(mozjs::jsval::Int32Value(0));
5282 true
5283 }
5284}
5285
5286fn parse_open_flags(s: &str) -> i32 {
5287 let mut flags = 0;
5288 if s.contains('w') {
5289 flags |= libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC;
5290 }
5291 if s.contains('a') {
5292 flags |= libc::O_WRONLY | libc::O_CREAT | libc::O_APPEND;
5293 }
5294 if s.contains('+') {
5295 flags = (flags & !(libc::O_WRONLY | libc::O_RDONLY)) | libc::O_RDWR;
5296 }
5297 flags
5298}
5299
5300#[allow(unsafe_op_in_unsafe_fn)]
5301unsafe extern "C" fn fs_opendir(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5302 let args = CallArgs::from_vp(vp, argc);
5303 let path = match get_path_arg(cx, &args, 0) {
5304 ::std::result::Result::Ok(p) => p,
5305 ::std::result::Result::Err(b) => return b,
5306 };
5307
5308 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
5309 let dir_obj = create_dir_object(cx, &path);
5311 let mut wrapped_cx_od =
5312 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
5313 let cx_ref_od = &mut wrapped_cx_od;
5314 rooted!(&in(cx_ref_od) let cb = callback);
5315 rooted!(&in(cx_ref_od) let cb_val = mozjs::jsval::ObjectValue(cb.get()));
5316 rooted!(&in(cx_ref_od) let dir_val = mozjs::jsval::ObjectValue(dir_obj));
5317 let args_arr = [UndefinedValue(), dir_val.get()];
5318 let cb_args = HandleValueArray {
5319 length_: 2,
5320 elements_: args_arr.as_ptr(),
5321 };
5322 let global = CurrentGlobalOrNull(cx);
5323 if !global.is_null() {
5324 rooted!(&in(cx_ref_od) let global_rooted = global);
5325 let mut rval = UndefinedValue();
5326 JS_CallFunctionValue(
5327 cx,
5328 global_rooted.handle().into(),
5329 cb_val.handle().into(),
5330 &cb_args,
5331 MutableHandle::<Value> {
5332 _phantom_0: ::std::marker::PhantomData,
5333 ptr: &mut rval,
5334 },
5335 );
5336 JS_ClearPendingException(cx);
5337 }
5338 args.rval().set(UndefinedValue());
5339 return true;
5340 }
5341
5342 match fs::metadata(&path) {
5344 ::std::result::Result::Ok(meta) if meta.is_dir() => {
5345 let dir_obj = create_dir_object(cx, &path);
5346 args.rval().set(mozjs::jsval::ObjectValue(dir_obj));
5347 true
5348 }
5349 ::std::result::Result::Ok(_) => {
5350 JS_ReportErrorUTF8(cx, c"opendir: path is not a directory".as_ptr());
5351 false
5352 }
5353 ::std::result::Result::Err(e) => throw_fs_error(cx, "opendir", &path, &e),
5354 }
5355}
5356
5357#[allow(unsafe_op_in_unsafe_fn)]
5358unsafe extern "C" fn fs_read(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5359 let args = CallArgs::from_vp(vp, argc);
5360 let fd_val = if argc > 0 {
5361 *args.get(0).ptr
5362 } else {
5363 UndefinedValue()
5364 };
5365 let fd = if fd_val.is_int32() {
5366 fd_val.to_int32()
5367 } else {
5368 -1
5369 };
5370 let length = if argc > 3 {
5371 let v = *args.get(3).ptr;
5372 if v.is_int32() {
5373 v.to_int32() as usize
5374 } else {
5375 65536
5376 }
5377 } else {
5378 65536
5379 };
5380
5381 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 5) {
5382 spawn_fs_async(
5383 cx,
5384 "read",
5385 format!("fd:{}", fd),
5386 callback,
5387 None,
5388 move || {
5389 let mut buf = vec![0u8; length];
5390 #[cfg(unix)]
5391 {
5392 let bytes_read = unsafe {
5393 libc::read(fd, buf.as_mut_ptr() as *mut ::std::ffi::c_void, length)
5394 };
5395 if bytes_read >= 0 {
5396 buf.truncate(bytes_read as usize);
5397 Ok(FsAsyncResult::OkRead {
5398 bytes_read: bytes_read as i32,
5399 buffer: buf,
5400 })
5401 } else {
5402 Err(::std::io::Error::last_os_error())
5403 }
5404 }
5405 #[cfg(not(unix))]
5406 {
5407 Ok(FsAsyncResult::OkRead {
5408 bytes_read: 0,
5409 buffer: buf,
5410 })
5411 }
5412 },
5413 );
5414 args.rval().set(UndefinedValue());
5415 return true;
5416 }
5417
5418 let mut buf = vec![0u8; length];
5419 #[cfg(unix)]
5420 {
5421 let bytes_read =
5422 unsafe { libc::read(fd, buf.as_mut_ptr() as *mut ::std::ffi::c_void, length) };
5423 if bytes_read >= 0 {
5424 buf.truncate(bytes_read as usize);
5425 let buf_obj = crate::globals::create_buffer_object(cx, &buf);
5426 if buf_obj.is_null() {
5427 args.rval().set(UndefinedValue());
5428 } else {
5429 args.rval()
5430 .set(mozjs::jsval::DoubleValue(bytes_read as f64));
5431 }
5432 true
5433 } else {
5434 throw_fs_error(
5435 cx,
5436 "read",
5437 &format!("fd:{}", fd),
5438 &::std::io::Error::last_os_error(),
5439 )
5440 }
5441 }
5442 #[cfg(not(unix))]
5443 {
5444 args.rval().set(UndefinedValue());
5445 true
5446 }
5447}
5448
5449#[allow(unsafe_op_in_unsafe_fn)]
5450unsafe extern "C" fn fs_readdir(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5451 let args = CallArgs::from_vp(vp, argc);
5452 let path = match get_path_arg(cx, &args, 0) {
5453 ::std::result::Result::Ok(p) => p,
5454 ::std::result::Result::Err(b) => return b,
5455 };
5456 let with_file_types = get_bool_option(cx, &args, 1, "withFileTypes");
5457
5458 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
5459 spawn_fs_async(cx, "readdir", path.clone(), callback, None, move || {
5460 fs::read_dir(&path).map(|entries| {
5461 let items: Vec<_> = entries.flatten().collect();
5462 if with_file_types {
5463 let dirents: Vec<(String, bool)> = items
5464 .iter()
5465 .map(|e| {
5466 (
5467 e.file_name().to_string_lossy().into_owned(),
5468 e.file_type().map(|ft| ft.is_dir()).unwrap_or(false),
5469 )
5470 })
5471 .collect();
5472 FsAsyncResult::OkDirents(dirents)
5473 } else {
5474 let names: Vec<String> = items
5475 .iter()
5476 .map(|e| e.file_name().to_string_lossy().into_owned())
5477 .collect();
5478 FsAsyncResult::OkDirnames(names)
5479 }
5480 })
5481 });
5482 args.rval().set(UndefinedValue());
5483 return true;
5484 }
5485
5486 match fs::read_dir(&path) {
5487 ::std::result::Result::Ok(entries) => {
5488 let mut names: Vec<String> = Vec::new();
5489 let mut is_dirs: Vec<bool> = Vec::new();
5490 for entry in entries.flatten() {
5491 names.push(entry.file_name().to_string_lossy().into_owned());
5492 is_dirs.push(entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false));
5493 }
5494 let mut wrapped_cx = unsafe {
5495 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx))
5496 };
5497 let cx_ref = &mut wrapped_cx;
5498 rooted!(&in(cx_ref) let arr = unsafe { w2::NewArrayObject1(cx_ref, names.len()) });
5499 if arr.get().is_null() {
5500 args.rval().set(UndefinedValue());
5501 return true;
5502 }
5503 for (i, name) in names.iter().enumerate() {
5504 if with_file_types {
5505 let dirent = create_dirent(cx, name, is_dirs[i]);
5506 if !dirent.is_null() {
5507 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(dirent));
5508 unsafe {
5509 JS_DefineElement(
5510 cx,
5511 arr.handle().into(),
5512 i as u32,
5513 val.handle().into(),
5514 JSPROP_ENUMERATE as u32,
5515 );
5516 }
5517 }
5518 } else {
5519 let c_name = ZBox::from_bytes(name.as_bytes());
5520 let js_str = unsafe { JS_NewStringCopyZ(cx, c_name.as_ptr()) };
5521 if !js_str.is_null() {
5522 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
5523 unsafe {
5524 JS_DefineElement(
5525 cx,
5526 arr.handle().into(),
5527 i as u32,
5528 val.handle().into(),
5529 JSPROP_ENUMERATE as u32,
5530 );
5531 }
5532 }
5533 }
5534 }
5535 args.rval().set(mozjs::jsval::ObjectValue(arr.get()));
5536 true
5537 }
5538 ::std::result::Result::Err(e) => throw_fs_error(cx, "readdir", &path, &e),
5539 }
5540}
5541
5542#[allow(unsafe_op_in_unsafe_fn)]
5543unsafe extern "C" fn fs_readlink(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5544 let args = CallArgs::from_vp(vp, argc);
5545 let path = match get_path_arg(cx, &args, 0) {
5546 ::std::result::Result::Ok(p) => p,
5547 ::std::result::Result::Err(b) => return b,
5548 };
5549 let _encoding = get_encoding_opt(cx, &args, 1);
5550
5551 if let Some((callback, cb_encoding)) = extract_callback_and_encoding(cx, &args, 1) {
5552 spawn_fs_async(
5553 cx,
5554 "readlink",
5555 path.clone(),
5556 callback,
5557 cb_encoding,
5558 move || {
5559 fs::read_link(&path)
5560 .map(|t| FsAsyncResult::OkString(t.to_string_lossy().into_owned()))
5561 },
5562 );
5563 args.rval().set(UndefinedValue());
5564 return true;
5565 }
5566
5567 match fs::read_link(&path) {
5568 ::std::result::Result::Ok(target) => {
5569 let s = target.to_string_lossy();
5570 let c_str = ZBox::from_bytes(s.as_bytes());
5571 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
5572 if js_str.is_null() {
5573 args.rval().set(UndefinedValue());
5574 } else {
5575 args.rval().set(mozjs::jsval::StringValue(&*js_str));
5576 }
5577 true
5578 }
5579 ::std::result::Result::Err(e) => throw_fs_error(cx, "readlink", &path, &e),
5580 }
5581}
5582
5583#[allow(unsafe_op_in_unsafe_fn)]
5584unsafe extern "C" fn fs_readv(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5585 fs_read(cx, argc, vp)
5586}
5587
5588#[allow(unsafe_op_in_unsafe_fn)]
5589unsafe extern "C" fn fs_realpath(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5590 let args = CallArgs::from_vp(vp, argc);
5591 let path = match get_path_arg(cx, &args, 0) {
5592 ::std::result::Result::Ok(p) => p,
5593 ::std::result::Result::Err(b) => return b,
5594 };
5595 let _encoding = get_encoding_opt(cx, &args, 1);
5596
5597 if let Some((callback, cb_encoding)) = extract_callback_and_encoding(cx, &args, 1) {
5598 spawn_fs_async(
5599 cx,
5600 "realpath",
5601 path.clone(),
5602 callback,
5603 cb_encoding,
5604 move || {
5605 fs::canonicalize(&path)
5606 .map(|p| FsAsyncResult::OkString(p.to_string_lossy().into_owned()))
5607 },
5608 );
5609 args.rval().set(UndefinedValue());
5610 return true;
5611 }
5612
5613 match fs::canonicalize(&path) {
5614 ::std::result::Result::Ok(resolved) => {
5615 let s = resolved.to_string_lossy();
5616 let c_str = ZBox::from_bytes(s.as_bytes());
5617 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
5618 if js_str.is_null() {
5619 args.rval().set(UndefinedValue());
5620 } else {
5621 args.rval().set(mozjs::jsval::StringValue(&*js_str));
5622 }
5623 true
5624 }
5625 ::std::result::Result::Err(e) => throw_fs_error(cx, "realpath", &path, &e),
5626 }
5627}
5628
5629#[allow(unsafe_op_in_unsafe_fn)]
5630unsafe extern "C" fn fs_rename(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5631 let args = CallArgs::from_vp(vp, argc);
5632 let from = match get_path_arg(cx, &args, 0) {
5633 ::std::result::Result::Ok(p) => p,
5634 ::std::result::Result::Err(b) => return b,
5635 };
5636 let to = match get_path_arg(cx, &args, 1) {
5637 ::std::result::Result::Ok(p) => p,
5638 ::std::result::Result::Err(b) => return b,
5639 };
5640
5641 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
5642 spawn_fs_async(cx, "rename", from.clone(), callback, None, move || {
5643 fs::rename(&from, &to).map(|_| FsAsyncResult::OkVoid)
5644 });
5645 args.rval().set(UndefinedValue());
5646 return true;
5647 }
5648
5649 match fs::rename(&from, &to) {
5650 ::std::result::Result::Ok(()) => {
5651 args.rval().set(UndefinedValue());
5652 true
5653 }
5654 ::std::result::Result::Err(e) => throw_fs_error(cx, "rename", &from, &e),
5655 }
5656}
5657
5658#[allow(unsafe_op_in_unsafe_fn)]
5659unsafe extern "C" fn fs_rm(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5660 let args = CallArgs::from_vp(vp, argc);
5661 let path = match get_path_arg(cx, &args, 0) {
5662 ::std::result::Result::Ok(p) => p,
5663 ::std::result::Result::Err(b) => return b,
5664 };
5665 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
5666 let c_msg = ZBox::from_bytes(e.as_bytes());
5667 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
5668 return false;
5669 }
5670 let recursive = get_bool_option(cx, &args, 1, "recursive");
5671
5672 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
5673 spawn_fs_async(cx, "rm", path.clone(), callback, None, move || {
5674 if recursive {
5675 fs::remove_dir_all(&path)
5676 } else {
5677 fs::remove_file(&path)
5678 }
5679 .map(|_| FsAsyncResult::OkVoid)
5680 });
5681 args.rval().set(UndefinedValue());
5682 return true;
5683 }
5684
5685 let result = if recursive {
5686 fs::remove_dir_all(&path)
5687 } else {
5688 fs::remove_file(&path)
5689 };
5690 match result {
5691 ::std::result::Result::Ok(()) => {
5692 args.rval().set(UndefinedValue());
5693 true
5694 }
5695 ::std::result::Result::Err(e) => throw_fs_error(cx, "rm", &path, &e),
5696 }
5697}
5698
5699#[allow(unsafe_op_in_unsafe_fn)]
5700unsafe extern "C" fn fs_rmdir(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5701 let args = CallArgs::from_vp(vp, argc);
5702 let path = match get_path_arg(cx, &args, 0) {
5703 ::std::result::Result::Ok(p) => p,
5704 ::std::result::Result::Err(b) => return b,
5705 };
5706 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
5707 let c_msg = ZBox::from_bytes(e.as_bytes());
5708 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
5709 return false;
5710 }
5711
5712 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
5713 spawn_fs_async(cx, "rmdir", path.clone(), callback, None, move || {
5714 fs::remove_dir(&path).map(|_| FsAsyncResult::OkVoid)
5715 });
5716 args.rval().set(UndefinedValue());
5717 return true;
5718 }
5719
5720 match fs::remove_dir(&path) {
5721 ::std::result::Result::Ok(()) => {
5722 args.rval().set(UndefinedValue());
5723 true
5724 }
5725 ::std::result::Result::Err(e) => throw_fs_error(cx, "rmdir", &path, &e),
5726 }
5727}
5728
5729#[allow(unsafe_op_in_unsafe_fn)]
5730unsafe extern "C" fn fs_stat(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5731 let args = CallArgs::from_vp(vp, argc);
5732 let path = match get_path_arg(cx, &args, 0) {
5733 ::std::result::Result::Ok(p) => p,
5734 ::std::result::Result::Err(b) => return b,
5735 };
5736
5737 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
5738 spawn_fs_async(cx, "stat", path.clone(), callback, None, move || {
5739 bun_fs::metadata(&path).map(FsAsyncResult::OkStat)
5740 });
5741 args.rval().set(UndefinedValue());
5742 return true;
5743 }
5744
5745 match bun_fs::metadata(&path) {
5746 ::std::result::Result::Ok(meta) => {
5747 let stats = create_stats_object(cx, &meta);
5748 args.rval().set(mozjs::jsval::ObjectValue(stats));
5749 true
5750 }
5751 ::std::result::Result::Err(e) => throw_fs_error(cx, "stat", &path, &e),
5752 }
5753}
5754
5755#[allow(unsafe_op_in_unsafe_fn)]
5756unsafe extern "C" fn fs_symlink(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5757 let args = CallArgs::from_vp(vp, argc);
5758 let target = match get_path_arg(cx, &args, 0) {
5759 ::std::result::Result::Ok(p) => p,
5760 ::std::result::Result::Err(b) => return b,
5761 };
5762 let path = match get_path_arg(cx, &args, 1) {
5763 ::std::result::Result::Ok(p) => p,
5764 ::std::result::Result::Err(b) => return b,
5765 };
5766
5767 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
5768 spawn_fs_async(cx, "symlink", target.clone(), callback, None, move || {
5769 #[cfg(unix)]
5770 {
5771 ::std::os::unix::fs::symlink(&target, &path).map(|_| FsAsyncResult::OkVoid)
5772 }
5773 #[cfg(not(unix))]
5774 {
5775 fs::hard_link(&target, &path).map(|_| FsAsyncResult::OkVoid)
5776 }
5777 });
5778 args.rval().set(UndefinedValue());
5779 return true;
5780 }
5781
5782 #[cfg(unix)]
5783 let result = ::std::os::unix::fs::symlink(&target, &path);
5784 #[cfg(not(unix))]
5785 let result = fs::hard_link(&target, &path);
5786 match result {
5787 ::std::result::Result::Ok(()) => {
5788 args.rval().set(UndefinedValue());
5789 true
5790 }
5791 ::std::result::Result::Err(e) => throw_fs_error(cx, "symlink", &target, &e),
5792 }
5793}
5794
5795#[allow(unsafe_op_in_unsafe_fn)]
5796unsafe extern "C" fn fs_truncate(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5797 let args = CallArgs::from_vp(vp, argc);
5798 let path = match get_path_arg(cx, &args, 0) {
5799 ::std::result::Result::Ok(p) => p,
5800 ::std::result::Result::Err(b) => return b,
5801 };
5802 let len_val = if argc > 1 {
5803 *args.get(1).ptr
5804 } else {
5805 UndefinedValue()
5806 };
5807 let len = if len_val.is_int32() {
5808 len_val.to_int32() as i64
5809 } else if len_val.is_double() {
5810 len_val.to_double() as i64
5811 } else {
5812 0
5813 };
5814
5815 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
5816 spawn_fs_async(cx, "truncate", path.clone(), callback, None, move || {
5817 fs::OpenOptions::new()
5819 .write(true)
5820 .open(&path)
5821 .and_then(|f| f.set_len(len.max(0) as u64))
5822 .map(|_| FsAsyncResult::OkVoid)
5823 });
5824 args.rval().set(UndefinedValue());
5825 return true;
5826 }
5827
5828 match fs::OpenOptions::new()
5829 .write(true)
5830 .open(&path)
5831 .and_then(|f| f.set_len(len.max(0) as u64))
5832 {
5833 ::std::result::Result::Ok(()) => {
5834 args.rval().set(UndefinedValue());
5835 true
5836 }
5837 ::std::result::Result::Err(e) => throw_fs_error(cx, "truncate", &path, &e),
5838 }
5839}
5840
5841#[allow(unsafe_op_in_unsafe_fn)]
5842unsafe extern "C" fn fs_unlink(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5843 let args = CallArgs::from_vp(vp, argc);
5844 let path = match get_path_arg(cx, &args, 0) {
5845 ::std::result::Result::Ok(p) => p,
5846 ::std::result::Result::Err(b) => return b,
5847 };
5848 if let ::std::result::Result::Err(e) = crate::permission_bridge::check_fs_write(&path) {
5849 let c_msg = ZBox::from_bytes(e.as_bytes());
5850 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
5851 return false;
5852 }
5853
5854 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
5855 spawn_fs_async(cx, "unlink", path.clone(), callback, None, move || {
5856 fs::remove_file(&path).map(|_| FsAsyncResult::OkVoid)
5857 });
5858 args.rval().set(UndefinedValue());
5859 return true;
5860 }
5861
5862 match fs::remove_file(&path) {
5863 ::std::result::Result::Ok(()) => {
5864 args.rval().set(UndefinedValue());
5865 true
5866 }
5867 ::std::result::Result::Err(e) => throw_fs_error(cx, "unlink", &path, &e),
5868 }
5869}
5870
5871#[allow(unsafe_op_in_unsafe_fn)]
5872unsafe extern "C" fn fs_utimes(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5873 let args = CallArgs::from_vp(vp, argc);
5874 let path = match get_path_arg(cx, &args, 0) {
5875 ::std::result::Result::Ok(p) => p,
5876 ::std::result::Result::Err(b) => return b,
5877 };
5878 let atime_val = if argc > 1 {
5879 *args.get(1).ptr
5880 } else {
5881 UndefinedValue()
5882 };
5883 let mtime_val = if argc > 2 {
5884 *args.get(2).ptr
5885 } else {
5886 UndefinedValue()
5887 };
5888 let atime = if atime_val.is_double() {
5889 atime_val.to_double()
5890 } else if atime_val.is_int32() {
5891 atime_val.to_int32() as f64
5892 } else {
5893 0.0
5894 };
5895 let mtime = if mtime_val.is_double() {
5896 mtime_val.to_double()
5897 } else if mtime_val.is_int32() {
5898 mtime_val.to_int32() as f64
5899 } else {
5900 0.0
5901 };
5902
5903 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 3) {
5904 spawn_fs_async(cx, "utimes", path.clone(), callback, None, move || {
5905 #[cfg(unix)]
5906 {
5907 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
5908 let tv = [
5909 libc::timeval {
5910 tv_sec: atime as i64,
5911 tv_usec: ((atime % 1.0) * 1_000_000.0) as i64,
5912 },
5913 libc::timeval {
5914 tv_sec: mtime as i64,
5915 tv_usec: ((mtime % 1.0) * 1_000_000.0) as i64,
5916 },
5917 ];
5918 let rv = unsafe { libc::utimes(c_path.as_ptr(), tv.as_ptr()) };
5919 if rv == 0 {
5920 Ok(FsAsyncResult::OkVoid)
5921 } else {
5922 Err(::std::io::Error::last_os_error())
5923 }
5924 }
5925 #[cfg(not(unix))]
5926 {
5927 Ok(FsAsyncResult::OkVoid)
5928 }
5929 });
5930 args.rval().set(UndefinedValue());
5931 return true;
5932 }
5933
5934 #[cfg(unix)]
5935 {
5936 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
5937 let tv = [
5938 libc::timeval {
5939 tv_sec: atime as i64,
5940 tv_usec: ((atime % 1.0) * 1_000_000.0) as i64,
5941 },
5942 libc::timeval {
5943 tv_sec: mtime as i64,
5944 tv_usec: ((mtime % 1.0) * 1_000_000.0) as i64,
5945 },
5946 ];
5947 let rv = unsafe { libc::utimes(c_path.as_ptr(), tv.as_ptr()) };
5948 if rv == 0 {
5949 args.rval().set(UndefinedValue());
5950 true
5951 } else {
5952 throw_fs_error(cx, "utimes", &path, &::std::io::Error::last_os_error())
5953 }
5954 }
5955 #[cfg(not(unix))]
5956 {
5957 args.rval().set(UndefinedValue());
5958 true
5959 }
5960}
5961
5962#[allow(unsafe_op_in_unsafe_fn)]
5963unsafe extern "C" fn fs_write(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
5964 let args = CallArgs::from_vp(vp, argc);
5965 let fd_val = if argc > 0 {
5966 *args.get(0).ptr
5967 } else {
5968 UndefinedValue()
5969 };
5970 let fd = if fd_val.is_int32() {
5971 fd_val.to_int32()
5972 } else {
5973 -1
5974 };
5975 let data_val = if argc > 1 {
5976 *args.get(1).ptr
5977 } else {
5978 UndefinedValue()
5979 };
5980 let bytes = if data_val.is_string() {
5981 let s = data_val.to_string();
5982 if !s.is_null() {
5983 crate::jsstr_to_rust_string(cx, s).into_bytes()
5984 } else {
5985 Vec::new()
5986 }
5987 } else if data_val.is_object() {
5988 crate::node_crypto::extract_buffer_bytes(cx, data_val)
5989 } else {
5990 Vec::new()
5991 };
5992
5993 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 5) {
5994 spawn_fs_async(
5995 cx,
5996 "write",
5997 format!("fd:{}", fd),
5998 callback,
5999 None,
6000 move || {
6001 #[cfg(unix)]
6002 {
6003 let written = unsafe {
6004 libc::write(fd, bytes.as_ptr() as *const ::std::ffi::c_void, bytes.len())
6005 };
6006 if written >= 0 {
6007 Ok(FsAsyncResult::OkWrite(written as i32))
6008 } else {
6009 Err(::std::io::Error::last_os_error())
6010 }
6011 }
6012 #[cfg(not(unix))]
6013 {
6014 Ok(FsAsyncResult::OkWrite(0))
6015 }
6016 },
6017 );
6018 args.rval().set(UndefinedValue());
6019 return true;
6020 }
6021
6022 #[cfg(unix)]
6023 {
6024 let written =
6025 unsafe { libc::write(fd, bytes.as_ptr() as *const ::std::ffi::c_void, bytes.len()) };
6026 if written >= 0 {
6027 args.rval().set(mozjs::jsval::DoubleValue(written as f64));
6028 true
6029 } else {
6030 throw_fs_error(
6031 cx,
6032 "write",
6033 &format!("fd:{}", fd),
6034 &::std::io::Error::last_os_error(),
6035 )
6036 }
6037 }
6038 #[cfg(not(unix))]
6039 {
6040 args.rval().set(UndefinedValue());
6041 true
6042 }
6043}
6044
6045#[allow(unsafe_op_in_unsafe_fn)]
6046unsafe extern "C" fn fs_writev(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6047 fs_write(cx, argc, vp)
6048}
6049
6050macro_rules! promise_simple_op {
6053 ($fn_name:ident, $op:expr, $op_name:expr) => {
6054 #[allow(unsafe_op_in_unsafe_fn)]
6055 unsafe extern "C" fn $fn_name(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6056 let args = CallArgs::from_vp(vp, argc);
6057 let path = match get_path_arg(cx, &args, 0) { ::std::result::Result::Ok(p) => p, ::std::result::Result::Err(b) => return b };
6058 let mut wrapped_cx = mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6059 let cx_ref = &mut wrapped_cx;
6060 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6061 if promise.get().is_null() { args.rval().set(UndefinedValue()); return false; }
6062 match $op(&path) {
6063 ::std::result::Result::Ok(()) => {
6064 resolve_undefined(cx, promise.get());
6065 }
6066 ::std::result::Result::Err(e) => {
6067 reject_with_error(cx, promise.get(), &format!("{} '{}': {}", $op_name, path, e));
6068 }
6069 }
6070 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6071 true
6072 }
6073 };
6074}
6075
6076promise_simple_op!(fs_promises_mkdir, |p: &str| fs::create_dir_all(p), "mkdir");
6077promise_simple_op!(fs_promises_unlink, |p: &str| fs::remove_file(p), "unlink");
6078
6079#[allow(unsafe_op_in_unsafe_fn)]
6080unsafe extern "C" fn fs_promises_rename(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6081 let args = CallArgs::from_vp(vp, argc);
6082 let from = match get_path_arg(cx, &args, 0) {
6083 ::std::result::Result::Ok(p) => p,
6084 ::std::result::Result::Err(b) => return b,
6085 };
6086 let to = match get_path_arg(cx, &args, 1) {
6087 ::std::result::Result::Ok(p) => p,
6088 ::std::result::Result::Err(b) => return b,
6089 };
6090 let mut wrapped_cx =
6091 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6092 let cx_ref = &mut wrapped_cx;
6093 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6094 if promise.get().is_null() {
6095 args.rval().set(UndefinedValue());
6096 return false;
6097 }
6098 match fs::rename(&from, &to) {
6099 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6100 ::std::result::Result::Err(e) => {
6101 reject_with_error(cx, promise.get(), &format!("rename '{}': {}", from, e))
6102 }
6103 }
6104 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6105 true
6106}
6107
6108#[allow(unsafe_op_in_unsafe_fn)]
6109unsafe extern "C" fn fs_promises_copy_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6110 let args = CallArgs::from_vp(vp, argc);
6111 let from = match get_path_arg(cx, &args, 0) {
6112 ::std::result::Result::Ok(p) => p,
6113 ::std::result::Result::Err(b) => return b,
6114 };
6115 let to = match get_path_arg(cx, &args, 1) {
6116 ::std::result::Result::Ok(p) => p,
6117 ::std::result::Result::Err(b) => return b,
6118 };
6119 let mut wrapped_cx =
6120 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6121 let cx_ref = &mut wrapped_cx;
6122 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6123 if promise.get().is_null() {
6124 args.rval().set(UndefinedValue());
6125 return false;
6126 }
6127 match fs::copy(&from, &to) {
6128 ::std::result::Result::Ok(_) => resolve_undefined(cx, promise.get()),
6129 ::std::result::Result::Err(e) => {
6130 reject_with_error(cx, promise.get(), &format!("copyFile '{}': {}", from, e))
6131 }
6132 }
6133 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6134 true
6135}
6136
6137#[allow(unsafe_op_in_unsafe_fn)]
6138unsafe extern "C" fn fs_promises_read_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6139 let args = CallArgs::from_vp(vp, argc);
6140 let path = match get_path_arg(cx, &args, 0) {
6141 ::std::result::Result::Ok(p) => p,
6142 ::std::result::Result::Err(b) => return b,
6143 };
6144 let encoding = get_encoding_opt(cx, &args, 1);
6145 let mut wrapped_cx =
6146 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6147 let cx_ref = &mut wrapped_cx;
6148 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6149 if promise.get().is_null() {
6150 args.rval().set(UndefinedValue());
6151 return false;
6152 }
6153
6154 match bun_fs::read(&path) {
6155 ::std::result::Result::Ok(data) => {
6156 let val = string_or_buffer(cx, &data, encoding.as_deref());
6157 rooted!(&in(cx_ref) let val_rooted = val);
6158 unsafe {
6159 mozjs_sys::jsapi::JS::ResolvePromise(
6160 cx,
6161 promise.handle().into(),
6162 val_rooted.handle().into(),
6163 );
6164 }
6165 }
6166 ::std::result::Result::Err(e) => {
6167 reject_with_error(cx, promise.get(), &format!("readFile '{}': {}", path, e))
6168 }
6169 }
6170 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6171 true
6172}
6173
6174#[allow(unsafe_op_in_unsafe_fn)]
6175unsafe extern "C" fn fs_promises_write_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6176 let args = CallArgs::from_vp(vp, argc);
6177 let path = match get_path_arg(cx, &args, 0) {
6178 ::std::result::Result::Ok(p) => p,
6179 ::std::result::Result::Err(b) => return b,
6180 };
6181 let data_val = if argc > 1 {
6182 *args.get(1).ptr
6183 } else {
6184 UndefinedValue()
6185 };
6186 let bytes = if data_val.is_string() {
6187 let s = data_val.to_string();
6188 if !s.is_null() {
6189 crate::jsstr_to_rust_string(cx, s).into_bytes()
6190 } else {
6191 Vec::new()
6192 }
6193 } else {
6194 Vec::new()
6195 };
6196 let mut wrapped_cx =
6197 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6198 let cx_ref = &mut wrapped_cx;
6199 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6200 if promise.get().is_null() {
6201 args.rval().set(UndefinedValue());
6202 return false;
6203 }
6204 match bun_fs::write(&path, &bytes) {
6205 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6206 ::std::result::Result::Err(e) => {
6207 reject_with_error(cx, promise.get(), &format!("writeFile '{}': {}", path, e))
6208 }
6209 }
6210 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6211 true
6212}
6213
6214#[allow(unsafe_op_in_unsafe_fn)]
6215unsafe extern "C" fn fs_promises_stat(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6216 let args = CallArgs::from_vp(vp, argc);
6217 let path = match get_path_arg(cx, &args, 0) {
6218 ::std::result::Result::Ok(p) => p,
6219 ::std::result::Result::Err(b) => return b,
6220 };
6221 let mut wrapped_cx =
6222 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6223 let cx_ref = &mut wrapped_cx;
6224 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6225 if promise.get().is_null() {
6226 args.rval().set(UndefinedValue());
6227 return false;
6228 }
6229 match bun_fs::metadata(&path) {
6230 ::std::result::Result::Ok(meta) => {
6231 let stats = create_stats_object(cx, &meta);
6232 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(stats));
6233 unsafe {
6234 mozjs_sys::jsapi::JS::ResolvePromise(
6235 cx,
6236 promise.handle().into(),
6237 val.handle().into(),
6238 );
6239 }
6240 }
6241 ::std::result::Result::Err(e) => {
6242 reject_with_error(cx, promise.get(), &format!("stat '{}': {}", path, e))
6243 }
6244 }
6245 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6246 true
6247}
6248
6249#[allow(unsafe_op_in_unsafe_fn)]
6250unsafe extern "C" fn fs_promises_readdir(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6251 let args = CallArgs::from_vp(vp, argc);
6252 let path = match get_path_arg(cx, &args, 0) {
6253 ::std::result::Result::Ok(p) => p,
6254 ::std::result::Result::Err(b) => return b,
6255 };
6256
6257 let mut wrapped_cx =
6258 unsafe { mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx)) };
6259 let cx_ref = &mut wrapped_cx;
6260
6261 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6262 if promise.get().is_null() {
6263 args.rval().set(UndefinedValue());
6264 return false;
6265 }
6266
6267 match fs::read_dir(&path) {
6268 ::std::result::Result::Ok(entries) => {
6269 let names: Vec<::std::string::String> = entries
6270 .flatten()
6271 .map(|e| e.file_name().to_string_lossy().into_owned())
6272 .collect();
6273 rooted!(&in(cx_ref) let arr = unsafe { w2::NewArrayObject1(cx_ref, names.len()) });
6274 if arr.get().is_null() {
6275 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6276 return true;
6277 }
6278 for (idx, name) in names.iter().enumerate() {
6279 let c_name = ZBox::from_bytes(name.as_bytes());
6280 let js_str = unsafe { JS_NewStringCopyZ(cx, c_name.as_ptr()) };
6281 if !js_str.is_null() {
6282 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
6283 unsafe {
6284 JS_DefineElement(
6285 cx,
6286 arr.handle().into(),
6287 idx as u32,
6288 val.handle().into(),
6289 JSPROP_ENUMERATE as u32,
6290 );
6291 }
6292 }
6293 }
6294 rooted!(&in(cx_ref) let arr_val = mozjs::jsval::ObjectValue(arr.get()));
6295 unsafe {
6296 mozjs_sys::jsapi::JS::ResolvePromise(
6297 cx,
6298 promise.handle().into(),
6299 arr_val.handle().into(),
6300 );
6301 }
6302 }
6303 ::std::result::Result::Err(e) => {
6304 reject_with_error(cx, promise.get(), &format!("readdir '{}': {}", path, e))
6305 }
6306 }
6307 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6308 true
6309}
6310
6311#[allow(unsafe_op_in_unsafe_fn)]
6312unsafe extern "C" fn fs_promises_lstat(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6313 let args = CallArgs::from_vp(vp, argc);
6314 let path = match get_path_arg(cx, &args, 0) {
6315 ::std::result::Result::Ok(p) => p,
6316 ::std::result::Result::Err(b) => return b,
6317 };
6318 let mut wrapped_cx =
6319 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6320 let cx_ref = &mut wrapped_cx;
6321 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6322 if promise.get().is_null() {
6323 args.rval().set(UndefinedValue());
6324 return false;
6325 }
6326 match fs::symlink_metadata(&path) {
6327 ::std::result::Result::Ok(meta) => {
6328 let posix = metadata_to_posix_stat(&meta);
6329 let stats = create_stats_object(cx, &posix);
6330 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(stats));
6331 unsafe {
6332 mozjs_sys::jsapi::JS::ResolvePromise(
6333 cx,
6334 promise.handle().into(),
6335 val.handle().into(),
6336 );
6337 }
6338 }
6339 ::std::result::Result::Err(e) => {
6340 reject_with_error(cx, promise.get(), &format!("lstat '{}': {}", path, e))
6341 }
6342 }
6343 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6344 true
6345}
6346
6347#[allow(unsafe_op_in_unsafe_fn)]
6348unsafe extern "C" fn fs_promises_append_file(
6349 cx: *mut JSContext,
6350 argc: u32,
6351 vp: *mut JSVal,
6352) -> bool {
6353 let args = CallArgs::from_vp(vp, argc);
6354 let path = match get_path_arg(cx, &args, 0) {
6355 ::std::result::Result::Ok(p) => p,
6356 ::std::result::Result::Err(b) => return b,
6357 };
6358 let data_val = if argc > 1 {
6359 *args.get(1).ptr
6360 } else {
6361 UndefinedValue()
6362 };
6363 let data = if data_val.is_string() {
6364 let s = data_val.to_string();
6365 if !s.is_null() {
6366 crate::jsstr_to_rust_string(cx, s).into_bytes()
6367 } else {
6368 Vec::new()
6369 }
6370 } else if data_val.is_object() {
6371 crate::node_crypto::extract_buffer_bytes(cx, data_val)
6372 } else {
6373 Vec::new()
6374 };
6375 let mut wrapped_cx =
6376 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6377 let cx_ref = &mut wrapped_cx;
6378 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6379 if promise.get().is_null() {
6380 args.rval().set(UndefinedValue());
6381 return false;
6382 }
6383 match ::std::fs::OpenOptions::new()
6384 .create(true)
6385 .append(true)
6386 .open(&path)
6387 .and_then(|mut f| ::std::io::Write::write_all(&mut f, &data))
6388 {
6389 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6390 ::std::result::Result::Err(e) => {
6391 reject_with_error(cx, promise.get(), &format!("appendFile '{}': {}", path, e))
6392 }
6393 }
6394 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6395 true
6396}
6397
6398#[allow(unsafe_op_in_unsafe_fn)]
6399unsafe extern "C" fn fs_promises_chmod(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6400 let args = CallArgs::from_vp(vp, argc);
6401 let path = match get_path_arg(cx, &args, 0) {
6402 ::std::result::Result::Ok(p) => p,
6403 ::std::result::Result::Err(b) => return b,
6404 };
6405 let mode_val = if argc > 1 {
6406 *args.get(1).ptr
6407 } else {
6408 UndefinedValue()
6409 };
6410 let mode = if mode_val.is_int32() {
6411 mode_val.to_int32() as u32
6412 } else if mode_val.is_double() {
6413 mode_val.to_double() as u32
6414 } else {
6415 0o644
6416 };
6417 let mut wrapped_cx =
6418 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6419 let cx_ref = &mut wrapped_cx;
6420 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6421 if promise.get().is_null() {
6422 args.rval().set(UndefinedValue());
6423 return false;
6424 }
6425 #[cfg(unix)]
6426 let result = {
6427 use ::std::os::unix::fs::PermissionsExt;
6428 fs::set_permissions(&path, fs::Permissions::from_mode(mode))
6429 };
6430 #[cfg(not(unix))]
6431 let result = fs::set_permissions(&path, fs::Permissions::new());
6432 match result {
6433 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6434 ::std::result::Result::Err(e) => {
6435 reject_with_error(cx, promise.get(), &format!("chmod '{}': {}", path, e))
6436 }
6437 }
6438 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6439 true
6440}
6441
6442#[allow(unsafe_op_in_unsafe_fn)]
6443unsafe extern "C" fn fs_promises_chown(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6444 let args = CallArgs::from_vp(vp, argc);
6445 let path = match get_path_arg(cx, &args, 0) {
6446 ::std::result::Result::Ok(p) => p,
6447 ::std::result::Result::Err(b) => return b,
6448 };
6449 let uid = if argc > 1 {
6450 let v = *args.get(1).ptr;
6451 if v.is_int32() { v.to_int32() as u32 } else { 0 }
6452 } else {
6453 0
6454 };
6455 let gid = if argc > 2 {
6456 let v = *args.get(2).ptr;
6457 if v.is_int32() { v.to_int32() as u32 } else { 0 }
6458 } else {
6459 0
6460 };
6461 let mut wrapped_cx =
6462 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6463 let cx_ref = &mut wrapped_cx;
6464 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6465 if promise.get().is_null() {
6466 args.rval().set(UndefinedValue());
6467 return false;
6468 }
6469 #[cfg(unix)]
6470 let result = ::std::os::unix::fs::chown(&path, Some(uid), Some(gid));
6471 #[cfg(not(unix))]
6472 let result: ::std::io::Result<()> = Ok(());
6473 match result {
6474 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6475 ::std::result::Result::Err(e) => {
6476 reject_with_error(cx, promise.get(), &format!("chown '{}': {}", path, e))
6477 }
6478 }
6479 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6480 true
6481}
6482
6483#[allow(unsafe_op_in_unsafe_fn)]
6484unsafe extern "C" fn fs_promises_access(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6485 let args = CallArgs::from_vp(vp, argc);
6486 let path = match get_path_arg(cx, &args, 0) {
6487 ::std::result::Result::Ok(p) => p,
6488 ::std::result::Result::Err(b) => return b,
6489 };
6490 let mut wrapped_cx =
6491 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6492 let cx_ref = &mut wrapped_cx;
6493 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6494 if promise.get().is_null() {
6495 args.rval().set(UndefinedValue());
6496 return false;
6497 }
6498 match fs::metadata(&path) {
6499 ::std::result::Result::Ok(_) => resolve_undefined(cx, promise.get()),
6500 ::std::result::Result::Err(e) => {
6501 reject_with_error(cx, promise.get(), &format!("access '{}': {}", path, e))
6502 }
6503 }
6504 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6505 true
6506}
6507
6508#[allow(unsafe_op_in_unsafe_fn)]
6509unsafe extern "C" fn fs_promises_rm(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6510 let args = CallArgs::from_vp(vp, argc);
6511 let path = match get_path_arg(cx, &args, 0) {
6512 ::std::result::Result::Ok(p) => p,
6513 ::std::result::Result::Err(b) => return b,
6514 };
6515 let recursive = get_bool_option(cx, &args, 1, "recursive");
6516 let mut wrapped_cx =
6517 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6518 let cx_ref = &mut wrapped_cx;
6519 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6520 if promise.get().is_null() {
6521 args.rval().set(UndefinedValue());
6522 return false;
6523 }
6524 let result = if recursive {
6525 fs::remove_dir_all(&path)
6526 } else {
6527 fs::remove_file(&path)
6528 };
6529 match result {
6530 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6531 ::std::result::Result::Err(e) => {
6532 reject_with_error(cx, promise.get(), &format!("rm '{}': {}", path, e))
6533 }
6534 }
6535 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6536 true
6537}
6538
6539#[allow(unsafe_op_in_unsafe_fn)]
6540unsafe extern "C" fn fs_promises_rmdir(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6541 let args = CallArgs::from_vp(vp, argc);
6542 let path = match get_path_arg(cx, &args, 0) {
6543 ::std::result::Result::Ok(p) => p,
6544 ::std::result::Result::Err(b) => return b,
6545 };
6546 let mut wrapped_cx =
6547 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6548 let cx_ref = &mut wrapped_cx;
6549 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6550 if promise.get().is_null() {
6551 args.rval().set(UndefinedValue());
6552 return false;
6553 }
6554 match fs::remove_dir(&path) {
6555 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6556 ::std::result::Result::Err(e) => {
6557 reject_with_error(cx, promise.get(), &format!("rmdir '{}': {}", path, e))
6558 }
6559 }
6560 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6561 true
6562}
6563
6564#[allow(unsafe_op_in_unsafe_fn)]
6565unsafe extern "C" fn fs_promises_realpath(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6566 let args = CallArgs::from_vp(vp, argc);
6567 let path = match get_path_arg(cx, &args, 0) {
6568 ::std::result::Result::Ok(p) => p,
6569 ::std::result::Result::Err(b) => return b,
6570 };
6571 let mut wrapped_cx =
6572 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6573 let cx_ref = &mut wrapped_cx;
6574 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6575 if promise.get().is_null() {
6576 args.rval().set(UndefinedValue());
6577 return false;
6578 }
6579 match fs::canonicalize(&path) {
6580 ::std::result::Result::Ok(resolved) => {
6581 let s = resolved.to_string_lossy();
6582 let c_str = ZBox::from_bytes(s.as_bytes());
6583 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
6584 if !js_str.is_null() {
6585 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
6586 unsafe {
6587 mozjs_sys::jsapi::JS::ResolvePromise(
6588 cx,
6589 promise.handle().into(),
6590 val.handle().into(),
6591 );
6592 }
6593 } else {
6594 resolve_undefined(cx, promise.get());
6595 }
6596 }
6597 ::std::result::Result::Err(e) => {
6598 reject_with_error(cx, promise.get(), &format!("realpath '{}': {}", path, e))
6599 }
6600 }
6601 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6602 true
6603}
6604
6605#[allow(unsafe_op_in_unsafe_fn)]
6606unsafe extern "C" fn fs_promises_readlink(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6607 let args = CallArgs::from_vp(vp, argc);
6608 let path = match get_path_arg(cx, &args, 0) {
6609 ::std::result::Result::Ok(p) => p,
6610 ::std::result::Result::Err(b) => return b,
6611 };
6612 let mut wrapped_cx =
6613 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6614 let cx_ref = &mut wrapped_cx;
6615 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6616 if promise.get().is_null() {
6617 args.rval().set(UndefinedValue());
6618 return false;
6619 }
6620 match fs::read_link(&path) {
6621 ::std::result::Result::Ok(target) => {
6622 let s = target.to_string_lossy();
6623 let c_str = ZBox::from_bytes(s.as_bytes());
6624 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
6625 if !js_str.is_null() {
6626 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
6627 unsafe {
6628 mozjs_sys::jsapi::JS::ResolvePromise(
6629 cx,
6630 promise.handle().into(),
6631 val.handle().into(),
6632 );
6633 }
6634 } else {
6635 resolve_undefined(cx, promise.get());
6636 }
6637 }
6638 ::std::result::Result::Err(e) => {
6639 reject_with_error(cx, promise.get(), &format!("readlink '{}': {}", path, e))
6640 }
6641 }
6642 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6643 true
6644}
6645
6646#[allow(unsafe_op_in_unsafe_fn)]
6647unsafe extern "C" fn fs_promises_symlink(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6648 let args = CallArgs::from_vp(vp, argc);
6649 let target = match get_path_arg(cx, &args, 0) {
6650 ::std::result::Result::Ok(p) => p,
6651 ::std::result::Result::Err(b) => return b,
6652 };
6653 let path = match get_path_arg(cx, &args, 1) {
6654 ::std::result::Result::Ok(p) => p,
6655 ::std::result::Result::Err(b) => return b,
6656 };
6657 let mut wrapped_cx =
6658 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6659 let cx_ref = &mut wrapped_cx;
6660 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6661 if promise.get().is_null() {
6662 args.rval().set(UndefinedValue());
6663 return false;
6664 }
6665 #[cfg(unix)]
6666 let result = ::std::os::unix::fs::symlink(&target, &path);
6667 #[cfg(not(unix))]
6668 let result = fs::hard_link(&target, &path);
6669 match result {
6670 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6671 ::std::result::Result::Err(e) => {
6672 reject_with_error(cx, promise.get(), &format!("symlink '{}': {}", target, e))
6673 }
6674 }
6675 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6676 true
6677}
6678
6679#[allow(unsafe_op_in_unsafe_fn)]
6680unsafe extern "C" fn fs_promises_link(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6681 let args = CallArgs::from_vp(vp, argc);
6682 let from = match get_path_arg(cx, &args, 0) {
6683 ::std::result::Result::Ok(p) => p,
6684 ::std::result::Result::Err(b) => return b,
6685 };
6686 let to = match get_path_arg(cx, &args, 1) {
6687 ::std::result::Result::Ok(p) => p,
6688 ::std::result::Result::Err(b) => return b,
6689 };
6690 let mut wrapped_cx =
6691 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6692 let cx_ref = &mut wrapped_cx;
6693 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6694 if promise.get().is_null() {
6695 args.rval().set(UndefinedValue());
6696 return false;
6697 }
6698 match fs::hard_link(&from, &to) {
6699 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6700 ::std::result::Result::Err(e) => {
6701 reject_with_error(cx, promise.get(), &format!("link '{}': {}", from, e))
6702 }
6703 }
6704 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6705 true
6706}
6707
6708#[allow(unsafe_op_in_unsafe_fn)]
6709unsafe extern "C" fn fs_promises_truncate(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6710 let args = CallArgs::from_vp(vp, argc);
6711 let path = match get_path_arg(cx, &args, 0) {
6712 ::std::result::Result::Ok(p) => p,
6713 ::std::result::Result::Err(b) => return b,
6714 };
6715 let len_val = if argc > 1 {
6716 *args.get(1).ptr
6717 } else {
6718 UndefinedValue()
6719 };
6720 let len = if len_val.is_int32() {
6721 len_val.to_int32() as u64
6722 } else if len_val.is_double() {
6723 len_val.to_double() as u64
6724 } else {
6725 0
6726 };
6727 let mut wrapped_cx =
6728 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6729 let cx_ref = &mut wrapped_cx;
6730 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6731 if promise.get().is_null() {
6732 args.rval().set(UndefinedValue());
6733 return false;
6734 }
6735 match fs::OpenOptions::new().write(true).open(&path).and_then(|f| f.set_len(len)) {
6737 ::std::result::Result::Ok(()) => resolve_undefined(cx, promise.get()),
6738 ::std::result::Result::Err(e) => {
6739 reject_with_error(cx, promise.get(), &format!("truncate '{}': {}", path, e))
6740 }
6741 }
6742 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6743 true
6744}
6745
6746#[allow(unsafe_op_in_unsafe_fn)]
6747unsafe extern "C" fn fs_promises_utimes(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6748 let args = CallArgs::from_vp(vp, argc);
6749 let path = match get_path_arg(cx, &args, 0) {
6750 ::std::result::Result::Ok(p) => p,
6751 ::std::result::Result::Err(b) => return b,
6752 };
6753 let atime_val = if argc > 1 {
6754 *args.get(1).ptr
6755 } else {
6756 UndefinedValue()
6757 };
6758 let mtime_val = if argc > 2 {
6759 *args.get(2).ptr
6760 } else {
6761 UndefinedValue()
6762 };
6763 let atime = if atime_val.is_double() {
6764 atime_val.to_double()
6765 } else if atime_val.is_int32() {
6766 atime_val.to_int32() as f64
6767 } else {
6768 0.0
6769 };
6770 let mtime = if mtime_val.is_double() {
6771 mtime_val.to_double()
6772 } else if mtime_val.is_int32() {
6773 mtime_val.to_int32() as f64
6774 } else {
6775 0.0
6776 };
6777 let mut wrapped_cx =
6778 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6779 let cx_ref = &mut wrapped_cx;
6780 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6781 if promise.get().is_null() {
6782 args.rval().set(UndefinedValue());
6783 return false;
6784 }
6785 #[cfg(unix)]
6786 {
6787 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
6788 let tv = [
6789 libc::timeval {
6790 tv_sec: atime as i64,
6791 tv_usec: ((atime % 1.0) * 1_000_000.0) as i64,
6792 },
6793 libc::timeval {
6794 tv_sec: mtime as i64,
6795 tv_usec: ((mtime % 1.0) * 1_000_000.0) as i64,
6796 },
6797 ];
6798 let rv = unsafe { libc::utimes(c_path.as_ptr(), tv.as_ptr()) };
6799 if rv == 0 {
6800 resolve_undefined(cx, promise.get());
6801 } else {
6802 reject_with_error(
6803 cx,
6804 promise.get(),
6805 &format!("utimes '{}': {}", path, ::std::io::Error::last_os_error()),
6806 );
6807 }
6808 }
6809 #[cfg(not(unix))]
6810 {
6811 resolve_undefined(cx, promise.get());
6812 }
6813 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6814 true
6815}
6816
6817#[allow(unsafe_op_in_unsafe_fn)]
6818unsafe extern "C" fn fs_promises_mkdtemp(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6819 let args = CallArgs::from_vp(vp, argc);
6820 let prefix = match get_path_arg(cx, &args, 0) {
6821 ::std::result::Result::Ok(p) => p,
6822 ::std::result::Result::Err(b) => return b,
6823 };
6824 let mut wrapped_cx =
6825 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6826 let cx_ref = &mut wrapped_cx;
6827 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6828 if promise.get().is_null() {
6829 args.rval().set(UndefinedValue());
6830 return false;
6831 }
6832 match mkdtemp_inner(&prefix) {
6833 ::std::result::Result::Ok(dir) => {
6834 let c_str = ZBox::from_bytes(dir.as_bytes());
6835 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
6836 if !js_str.is_null() {
6837 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
6838 unsafe {
6839 mozjs_sys::jsapi::JS::ResolvePromise(
6840 cx,
6841 promise.handle().into(),
6842 val.handle().into(),
6843 );
6844 }
6845 } else {
6846 resolve_undefined(cx, promise.get());
6847 }
6848 }
6849 ::std::result::Result::Err(e) => {
6850 reject_with_error(cx, promise.get(), &format!("mkdtemp '{}': {}", prefix, e))
6851 }
6852 }
6853 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6854 true
6855}
6856
6857#[allow(unsafe_op_in_unsafe_fn)]
6858unsafe extern "C" fn fs_promises_open(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6859 let args = CallArgs::from_vp(vp, argc);
6860 let path = match get_path_arg(cx, &args, 0) {
6861 ::std::result::Result::Ok(p) => p,
6862 ::std::result::Result::Err(b) => return b,
6863 };
6864 let flags_val = if argc > 1 {
6865 *args.get(1).ptr
6866 } else {
6867 UndefinedValue()
6868 };
6869 let flags = if flags_val.is_int32() {
6870 flags_val.to_int32()
6871 } else if flags_val.is_string() {
6872 let s = flags_val.to_string();
6873 if !s.is_null() {
6874 parse_open_flags(&crate::jsstr_to_rust_string(cx, s))
6875 } else {
6876 0
6877 }
6878 } else {
6879 0
6880 };
6881 let mode_val = if argc > 2 {
6882 *args.get(2).ptr
6883 } else {
6884 UndefinedValue()
6885 };
6886 let mode = if mode_val.is_int32() {
6887 mode_val.to_int32() as u32
6888 } else {
6889 0o644
6890 };
6891 let mut wrapped_cx =
6892 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6893 let cx_ref = &mut wrapped_cx;
6894 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6895 if promise.get().is_null() {
6896 args.rval().set(UndefinedValue());
6897 return false;
6898 }
6899 #[cfg(unix)]
6900 {
6901 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
6902 let fd = unsafe { libc::open(c_path.as_ptr(), flags, mode) };
6903 if fd >= 0 {
6904 let fh = create_filehandle_object(cx, fd);
6906 if !fh.is_null() {
6907 rooted!(&in(cx_ref) let fh_val = mozjs::jsval::ObjectValue(fh));
6908 unsafe {
6909 mozjs_sys::jsapi::JS::ResolvePromise(
6910 cx,
6911 promise.handle().into(),
6912 fh_val.handle().into(),
6913 );
6914 }
6915 } else {
6916 rooted!(&in(cx_ref) let val = mozjs::jsval::Int32Value(fd));
6918 unsafe {
6919 mozjs_sys::jsapi::JS::ResolvePromise(
6920 cx,
6921 promise.handle().into(),
6922 val.handle().into(),
6923 );
6924 }
6925 }
6926 } else {
6927 reject_with_error(
6928 cx,
6929 promise.get(),
6930 &format!("open '{}': {}", path, ::std::io::Error::last_os_error()),
6931 );
6932 }
6933 }
6934 #[cfg(not(unix))]
6935 {
6936 resolve_undefined(cx, promise.get());
6937 }
6938 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
6939 true
6940}
6941
6942#[allow(unsafe_op_in_unsafe_fn)]
6943unsafe extern "C" fn fs_promises_read(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
6944 let args = CallArgs::from_vp(vp, argc);
6945 let fd_val = if argc > 0 {
6946 *args.get(0).ptr
6947 } else {
6948 UndefinedValue()
6949 };
6950 let fd = if fd_val.is_int32() {
6951 fd_val.to_int32()
6952 } else {
6953 -1
6954 };
6955 let length = if argc > 3 {
6956 let v = *args.get(3).ptr;
6957 if v.is_int32() {
6958 v.to_int32() as usize
6959 } else {
6960 65536
6961 }
6962 } else {
6963 65536
6964 };
6965 let mut wrapped_cx =
6966 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
6967 let cx_ref = &mut wrapped_cx;
6968 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
6969 if promise.get().is_null() {
6970 args.rval().set(UndefinedValue());
6971 return false;
6972 }
6973 let mut buf = vec![0u8; length];
6974 #[cfg(unix)]
6975 {
6976 let bytes_read =
6977 unsafe { libc::read(fd, buf.as_mut_ptr() as *mut ::std::ffi::c_void, length) };
6978 if bytes_read >= 0 {
6979 buf.truncate(bytes_read as usize);
6980 let buf_obj = crate::globals::create_buffer_object(cx, &buf);
6981 if !buf_obj.is_null() {
6982 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(buf_obj));
6983 unsafe {
6984 mozjs_sys::jsapi::JS::ResolvePromise(
6985 cx,
6986 promise.handle().into(),
6987 val.handle().into(),
6988 );
6989 }
6990 } else {
6991 resolve_undefined(cx, promise.get());
6992 }
6993 } else {
6994 reject_with_error(
6995 cx,
6996 promise.get(),
6997 &format!("read fd:{}: {}", fd, ::std::io::Error::last_os_error()),
6998 );
6999 }
7000 }
7001 #[cfg(not(unix))]
7002 {
7003 resolve_undefined(cx, promise.get());
7004 }
7005 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
7006 true
7007}
7008
7009#[allow(unsafe_op_in_unsafe_fn)]
7010unsafe extern "C" fn fs_promises_write(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7011 let args = CallArgs::from_vp(vp, argc);
7012 let fd_val = if argc > 0 {
7013 *args.get(0).ptr
7014 } else {
7015 UndefinedValue()
7016 };
7017 let fd = if fd_val.is_int32() {
7018 fd_val.to_int32()
7019 } else {
7020 -1
7021 };
7022 let data_val = if argc > 1 {
7023 *args.get(1).ptr
7024 } else {
7025 UndefinedValue()
7026 };
7027 let bytes = if data_val.is_string() {
7028 let s = data_val.to_string();
7029 if !s.is_null() {
7030 crate::jsstr_to_rust_string(cx, s).into_bytes()
7031 } else {
7032 Vec::new()
7033 }
7034 } else if data_val.is_object() {
7035 crate::node_crypto::extract_buffer_bytes(cx, data_val)
7036 } else {
7037 Vec::new()
7038 };
7039 let mut wrapped_cx =
7040 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
7041 let cx_ref = &mut wrapped_cx;
7042 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
7043 if promise.get().is_null() {
7044 args.rval().set(UndefinedValue());
7045 return false;
7046 }
7047 #[cfg(unix)]
7048 {
7049 let written =
7050 unsafe { libc::write(fd, bytes.as_ptr() as *const ::std::ffi::c_void, bytes.len()) };
7051 if written >= 0 {
7052 rooted!(&in(cx_ref) let val = mozjs::jsval::DoubleValue(written as f64));
7053 unsafe {
7054 mozjs_sys::jsapi::JS::ResolvePromise(
7055 cx,
7056 promise.handle().into(),
7057 val.handle().into(),
7058 );
7059 }
7060 } else {
7061 reject_with_error(
7062 cx,
7063 promise.get(),
7064 &format!("write fd:{}: {}", fd, ::std::io::Error::last_os_error()),
7065 );
7066 }
7067 }
7068 #[cfg(not(unix))]
7069 {
7070 resolve_undefined(cx, promise.get());
7071 }
7072 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
7073 true
7074}
7075
7076#[allow(unsafe_op_in_unsafe_fn)]
7079unsafe extern "C" fn fs_statfs_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7080 let args = CallArgs::from_vp(vp, argc);
7081 let path = match get_path_arg(cx, &args, 0) {
7082 ::std::result::Result::Ok(p) => p,
7083 ::std::result::Result::Err(b) => return b,
7084 };
7085 #[cfg(unix)]
7086 {
7087 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
7088 let mut buf: libc::statfs = ::std::mem::zeroed();
7089 let rv = unsafe { libc::statfs(c_path.as_ptr(), &mut buf) };
7090 if rv == 0 {
7091 let sf = StatfsResult {
7092 type_: buf.f_type as u64,
7093 bsize: buf.f_bsize as u64,
7094 frsize: buf.f_frsize as u64,
7095 blocks: buf.f_blocks as u64,
7096 bfree: buf.f_bfree as u64,
7097 bavail: buf.f_bavail as u64,
7098 files: buf.f_files as u64,
7099 ffree: buf.f_ffree as u64,
7100 };
7101 let obj = create_statfs_object(cx, &sf);
7102 args.rval().set(mozjs::jsval::ObjectValue(obj));
7103 true
7104 } else {
7105 throw_fs_error(cx, "statfsSync", &path, &::std::io::Error::last_os_error())
7106 }
7107 }
7108 #[cfg(not(unix))]
7109 {
7110 let _ = path;
7111 args.rval().set(UndefinedValue());
7112 true
7113 }
7114}
7115
7116#[allow(unsafe_op_in_unsafe_fn)]
7117unsafe extern "C" fn fs_statfs(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7118 let args = CallArgs::from_vp(vp, argc);
7119 let path = match get_path_arg(cx, &args, 0) {
7120 ::std::result::Result::Ok(p) => p,
7121 ::std::result::Result::Err(b) => return b,
7122 };
7123
7124 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 1) {
7125 spawn_fs_async(cx, "statfs", path.clone(), callback, None, move || {
7126 #[cfg(unix)]
7127 {
7128 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
7129 let mut buf: libc::statfs = ::std::mem::zeroed();
7130 let rv = unsafe { libc::statfs(c_path.as_ptr(), &mut buf) };
7131 if rv == 0 {
7132 Ok(FsAsyncResult::OkStatfs(StatfsResult {
7133 type_: buf.f_type as u64,
7134 bsize: buf.f_bsize as u64,
7135 frsize: buf.f_frsize as u64,
7136 blocks: buf.f_blocks as u64,
7137 bfree: buf.f_bfree as u64,
7138 bavail: buf.f_bavail as u64,
7139 files: buf.f_files as u64,
7140 ffree: buf.f_ffree as u64,
7141 }))
7142 } else {
7143 Err(::std::io::Error::last_os_error())
7144 }
7145 }
7146 #[cfg(not(unix))]
7147 {
7148 Ok(FsAsyncResult::OkStatfs(StatfsResult {
7149 type_: 0,
7150 bsize: 0,
7151 frsize: 0,
7152 blocks: 0,
7153 bfree: 0,
7154 bavail: 0,
7155 files: 0,
7156 ffree: 0,
7157 }))
7158 }
7159 });
7160 args.rval().set(UndefinedValue());
7161 return true;
7162 }
7163
7164 #[cfg(unix)]
7165 {
7166 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
7167 let mut buf: libc::statfs = ::std::mem::zeroed();
7168 let rv = unsafe { libc::statfs(c_path.as_ptr(), &mut buf) };
7169 if rv == 0 {
7170 let sf = StatfsResult {
7171 type_: buf.f_type as u64,
7172 bsize: buf.f_bsize as u64,
7173 frsize: buf.f_frsize as u64,
7174 blocks: buf.f_blocks as u64,
7175 bfree: buf.f_bfree as u64,
7176 bavail: buf.f_bavail as u64,
7177 files: buf.f_files as u64,
7178 ffree: buf.f_ffree as u64,
7179 };
7180 let obj = create_statfs_object(cx, &sf);
7181 args.rval().set(mozjs::jsval::ObjectValue(obj));
7182 true
7183 } else {
7184 throw_fs_error(cx, "statfs", &path, &::std::io::Error::last_os_error())
7185 }
7186 }
7187 #[cfg(not(unix))]
7188 {
7189 args.rval().set(UndefinedValue());
7190 true
7191 }
7192}
7193
7194#[allow(unsafe_op_in_unsafe_fn)]
7195unsafe extern "C" fn fs_promises_statfs(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7196 let args = CallArgs::from_vp(vp, argc);
7197 let path = match get_path_arg(cx, &args, 0) {
7198 ::std::result::Result::Ok(p) => p,
7199 ::std::result::Result::Err(b) => return b,
7200 };
7201 let mut wrapped_cx =
7202 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
7203 let cx_ref = &mut wrapped_cx;
7204 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
7205 if promise.get().is_null() {
7206 args.rval().set(UndefinedValue());
7207 return false;
7208 }
7209
7210 #[cfg(unix)]
7211 {
7212 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
7213 let mut buf: libc::statfs = ::std::mem::zeroed();
7214 let rv = unsafe { libc::statfs(c_path.as_ptr(), &mut buf) };
7215 if rv == 0 {
7216 let sf = StatfsResult {
7217 type_: buf.f_type as u64,
7218 bsize: buf.f_bsize as u64,
7219 frsize: buf.f_bsize as u64,
7220 blocks: buf.f_blocks as u64,
7221 bfree: buf.f_bfree as u64,
7222 bavail: buf.f_bavail as u64,
7223 files: buf.f_files as u64,
7224 ffree: buf.f_ffree as u64,
7225 };
7226 let obj = create_statfs_object(cx, &sf);
7227 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(obj));
7228 unsafe {
7229 mozjs_sys::jsapi::JS::ResolvePromise(
7230 cx,
7231 promise.handle().into(),
7232 val.handle().into(),
7233 );
7234 }
7235 } else {
7236 reject_with_error(
7237 cx,
7238 promise.get(),
7239 &format!("statfs '{}': {}", path, ::std::io::Error::last_os_error()),
7240 );
7241 }
7242 }
7243 #[cfg(not(unix))]
7244 {
7245 resolve_undefined(cx, promise.get());
7246 }
7247 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
7248 true
7249}
7250
7251#[allow(unsafe_op_in_unsafe_fn)]
7254unsafe extern "C" fn fs_open_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7255 let args = CallArgs::from_vp(vp, argc);
7256 let path = match get_path_arg(cx, &args, 0) {
7257 ::std::result::Result::Ok(p) => p,
7258 ::std::result::Result::Err(b) => return b,
7259 };
7260 let flags_val = if argc > 1 {
7261 *args.get(1).ptr
7262 } else {
7263 UndefinedValue()
7264 };
7265 let flags = if flags_val.is_int32() {
7266 flags_val.to_int32()
7267 } else if flags_val.is_string() {
7268 let s = flags_val.to_string();
7269 if !s.is_null() {
7270 parse_open_flags(&crate::jsstr_to_rust_string(cx, s))
7271 } else {
7272 0
7273 }
7274 } else {
7275 0
7276 };
7277 let mode_val = if argc > 2 {
7278 *args.get(2).ptr
7279 } else {
7280 UndefinedValue()
7281 };
7282 let mode = if mode_val.is_int32() {
7283 mode_val.to_int32() as u32
7284 } else {
7285 0o644
7286 };
7287 #[cfg(unix)]
7288 {
7289 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
7290 let fd = unsafe { libc::open(c_path.as_ptr(), flags, mode) };
7291 if fd >= 0 {
7292 args.rval().set(mozjs::jsval::Int32Value(fd));
7293 true
7294 } else {
7295 throw_fs_error(cx, "openSync", &path, &::std::io::Error::last_os_error())
7296 }
7297 }
7298 #[cfg(not(unix))]
7299 {
7300 args.rval().set(mozjs::jsval::Int32Value(0));
7301 true
7302 }
7303}
7304
7305#[allow(unsafe_op_in_unsafe_fn)]
7306unsafe extern "C" fn fs_close_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7307 let args = CallArgs::from_vp(vp, argc);
7308 let fd_val = if argc > 0 {
7309 *args.get(0).ptr
7310 } else {
7311 UndefinedValue()
7312 };
7313 let fd = if fd_val.is_int32() {
7314 fd_val.to_int32()
7315 } else {
7316 -1
7317 };
7318 #[cfg(unix)]
7319 {
7320 let rv = unsafe { libc::close(fd) };
7321 if rv == 0 {
7322 args.rval().set(UndefinedValue());
7323 true
7324 } else {
7325 throw_fs_error(
7326 cx,
7327 "closeSync",
7328 &format!("fd:{}", fd),
7329 &::std::io::Error::last_os_error(),
7330 )
7331 }
7332 }
7333 #[cfg(not(unix))]
7334 {
7335 args.rval().set(UndefinedValue());
7336 true
7337 }
7338}
7339
7340#[allow(unsafe_op_in_unsafe_fn)]
7355unsafe extern "C" fn fs_truncate_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7356 let args = CallArgs::from_vp(vp, argc);
7357 let path = match get_path_arg(cx, &args, 0) {
7358 ::std::result::Result::Ok(p) => p,
7359 ::std::result::Result::Err(b) => return b,
7360 };
7361 let len_val = if argc > 1 {
7362 *args.get(1).ptr
7363 } else {
7364 UndefinedValue()
7365 };
7366 let len = if len_val.is_int32() {
7367 len_val.to_int32() as i64
7368 } else if len_val.is_double() {
7369 len_val.to_double() as i64
7370 } else {
7371 0
7372 };
7373 match fs::OpenOptions::new().write(true).open(&path).and_then(|f| f.set_len(len.max(0) as u64)) {
7374 ::std::result::Result::Ok(()) => {
7375 args.rval().set(UndefinedValue());
7376 true
7377 }
7378 ::std::result::Result::Err(e) => throw_fs_error(cx, "truncateSync", &path, &e),
7379 }
7380}
7381
7382#[allow(unsafe_op_in_unsafe_fn)]
7385unsafe extern "C" fn fs_opendir_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7386 let args = CallArgs::from_vp(vp, argc);
7387 let path = match get_path_arg(cx, &args, 0) {
7388 ::std::result::Result::Ok(p) => p,
7389 ::std::result::Result::Err(b) => return b,
7390 };
7391 match fs::metadata(&path) {
7392 ::std::result::Result::Ok(meta) if meta.is_dir() => {
7393 let dir_obj = create_dir_object(cx, &path);
7394 args.rval().set(mozjs::jsval::ObjectValue(dir_obj));
7395 true
7396 }
7397 ::std::result::Result::Ok(_) => {
7398 JS_ReportErrorUTF8(cx, c"opendirSync: path is not a directory".as_ptr());
7399 false
7400 }
7401 ::std::result::Result::Err(e) => throw_fs_error(cx, "opendirSync", &path, &e),
7402 }
7403}
7404
7405#[allow(unsafe_op_in_unsafe_fn)]
7406unsafe extern "C" fn fs_read_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7407 let args = CallArgs::from_vp(vp, argc);
7408 let fd_val = if argc > 0 {
7409 *args.get(0).ptr
7410 } else {
7411 UndefinedValue()
7412 };
7413 let fd = if fd_val.is_int32() {
7414 fd_val.to_int32()
7415 } else {
7416 -1
7417 };
7418
7419 let buf_val = if argc > 1 { *args.get(1).ptr } else { UndefinedValue() };
7421 if !buf_val.is_object() {
7422 JS_ReportErrorUTF8(
7423 cx,
7424 c"readSync: buffer argument must be a Buffer or Uint8Array".as_ptr(),
7425 );
7426 return false;
7427 }
7428 let wrapped_cx = mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
7429 rooted!(&in(wrapped_cx) let buf_obj = buf_val.to_object());
7430 if !mozjs_sys::jsapi::JS_IsArrayBufferViewObject(buf_obj.get()) {
7431 JS_ReportErrorUTF8(
7432 cx,
7433 c"readSync: buffer argument must be a Buffer or Uint8Array".as_ptr(),
7434 );
7435 return false;
7436 }
7437
7438 let byte_len = mozjs_sys::jsapi::JS_GetTypedArrayByteLength(buf_obj.get()) as usize;
7439
7440 let to_num = |v: JSVal| -> Option<f64> {
7441 if v.is_number() {
7442 Some(v.to_number())
7443 } else if v.is_int32() {
7444 Some(v.to_int32() as f64)
7445 } else {
7446 None
7447 }
7448 };
7449 let offset = if argc > 2 {
7450 to_num(*args.get(2).ptr).unwrap_or(0.0)
7451 } else {
7452 0.0
7453 };
7454 let length = if argc > 3 {
7455 to_num(*args.get(3).ptr)
7456 .filter(|n| *n >= 0.0)
7457 .map(|n| n as usize)
7458 .unwrap_or(byte_len)
7459 } else {
7460 byte_len
7461 };
7462 let position_arg = if argc > 4 { *args.get(4).ptr } else { UndefinedValue() };
7463 let use_pread = position_arg.is_number() || position_arg.is_int32();
7464 let position: i64 = if use_pread {
7465 to_num(position_arg).unwrap_or(0.0) as i64
7466 } else {
7467 -1
7468 };
7469
7470 if offset < 0.0 || offset as usize > byte_len {
7471 JS_ReportErrorUTF8(
7472 cx,
7473 c"readSync: offset is out of bounds".as_ptr(),
7474 );
7475 return false;
7476 }
7477 let offset = offset as usize;
7478 if length > byte_len - offset {
7479 JS_ReportErrorUTF8(
7480 cx,
7481 c"readSync: length extends beyond buffer".as_ptr(),
7482 );
7483 return false;
7484 }
7485 if length == 0 {
7486 args.rval().set(mozjs::jsval::Int32Value(0));
7487 return true;
7488 }
7489
7490 #[cfg(unix)]
7491 {
7492 let mut is_shared = false;
7494 let data_ptr = mozjs_sys::jsapi::JS_GetUint8ArrayData(
7495 buf_obj.get(),
7496 &mut is_shared,
7497 ::std::ptr::null(),
7498 );
7499 if data_ptr.is_null() {
7500 JS_ReportErrorUTF8(
7501 cx,
7502 c"readSync: cannot access buffer storage".as_ptr(),
7503 );
7504 return false;
7505 }
7506 let dst = unsafe { data_ptr.add(offset) };
7507 let bytes_read = if use_pread {
7508 unsafe {
7509 libc::pread(
7510 fd,
7511 dst as *mut ::std::ffi::c_void,
7512 length,
7513 position,
7514 )
7515 }
7516 } else {
7517 unsafe { libc::read(fd, dst as *mut ::std::ffi::c_void, length) }
7518 };
7519 if bytes_read >= 0 {
7520 args.rval().set(mozjs::jsval::Int32Value(bytes_read as i32));
7521 true
7522 } else {
7523 throw_fs_error(
7524 cx,
7525 "readSync",
7526 &format!("fd:{}", fd),
7527 &::std::io::Error::last_os_error(),
7528 )
7529 }
7530 }
7531 #[cfg(not(unix))]
7532 {
7533 args.rval().set(mozjs::jsval::Int32Value(0));
7534 true
7535 }
7536}
7537
7538#[allow(unsafe_op_in_unsafe_fn)]
7539unsafe extern "C" fn fs_write_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7540 let args = CallArgs::from_vp(vp, argc);
7541 let fd_val = if argc > 0 {
7542 *args.get(0).ptr
7543 } else {
7544 UndefinedValue()
7545 };
7546 let fd = if fd_val.is_int32() {
7547 fd_val.to_int32()
7548 } else {
7549 -1
7550 };
7551 let data_val = if argc > 1 {
7552 *args.get(1).ptr
7553 } else {
7554 UndefinedValue()
7555 };
7556 let bytes = if data_val.is_string() {
7557 let s = data_val.to_string();
7558 if !s.is_null() {
7559 crate::jsstr_to_rust_string(cx, s).into_bytes()
7560 } else {
7561 Vec::new()
7562 }
7563 } else if data_val.is_object() {
7564 crate::node_crypto::extract_buffer_bytes(cx, data_val)
7565 } else {
7566 Vec::new()
7567 };
7568 #[cfg(unix)]
7569 {
7570 let written =
7571 unsafe { libc::write(fd, bytes.as_ptr() as *const ::std::ffi::c_void, bytes.len()) };
7572 if written >= 0 {
7573 args.rval().set(mozjs::jsval::DoubleValue(written as f64));
7574 true
7575 } else {
7576 throw_fs_error(
7577 cx,
7578 "writeSync",
7579 &format!("fd:{}", fd),
7580 &::std::io::Error::last_os_error(),
7581 )
7582 }
7583 }
7584 #[cfg(not(unix))]
7585 {
7586 args.rval().set(UndefinedValue());
7587 true
7588 }
7589}
7590
7591#[allow(unsafe_op_in_unsafe_fn)]
7592unsafe extern "C" fn fs_mkdtemp_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7593 let args = CallArgs::from_vp(vp, argc);
7594 let prefix = match get_path_arg(cx, &args, 0) {
7595 ::std::result::Result::Ok(p) => p,
7596 ::std::result::Result::Err(b) => return b,
7597 };
7598 match mkdtemp_inner(&prefix) {
7599 ::std::result::Result::Ok(dir) => {
7600 let c_str = ZBox::from_bytes(dir.as_bytes());
7601 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
7602 if js_str.is_null() {
7603 args.rval().set(UndefinedValue());
7604 } else {
7605 args.rval().set(mozjs::jsval::StringValue(&*js_str));
7606 }
7607 true
7608 }
7609 ::std::result::Result::Err(e) => throw_fs_error(cx, "mkdtempSync", &prefix, &e),
7610 }
7611}
7612
7613#[allow(unsafe_op_in_unsafe_fn)]
7614unsafe extern "C" fn fs_fchmod_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7615 let args = CallArgs::from_vp(vp, argc);
7616 let fd_val = if argc > 0 {
7617 *args.get(0).ptr
7618 } else {
7619 UndefinedValue()
7620 };
7621 let fd = if fd_val.is_int32() {
7622 fd_val.to_int32()
7623 } else {
7624 -1
7625 };
7626 let mode_val = if argc > 1 {
7627 *args.get(1).ptr
7628 } else {
7629 UndefinedValue()
7630 };
7631 let mode = if mode_val.is_int32() {
7632 mode_val.to_int32() as u32
7633 } else {
7634 0o644
7635 };
7636 #[cfg(unix)]
7637 {
7638 let rv = unsafe { libc::fchmod(fd, mode) };
7639 if rv == 0 {
7640 args.rval().set(UndefinedValue());
7641 true
7642 } else {
7643 throw_fs_error(
7644 cx,
7645 "fchmodSync",
7646 &format!("fd:{}", fd),
7647 &::std::io::Error::last_os_error(),
7648 )
7649 }
7650 }
7651 #[cfg(not(unix))]
7652 {
7653 args.rval().set(UndefinedValue());
7654 true
7655 }
7656}
7657
7658#[allow(unsafe_op_in_unsafe_fn)]
7659unsafe extern "C" fn fs_fchown_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7660 let args = CallArgs::from_vp(vp, argc);
7661 let fd_val = if argc > 0 {
7662 *args.get(0).ptr
7663 } else {
7664 UndefinedValue()
7665 };
7666 let fd = if fd_val.is_int32() {
7667 fd_val.to_int32()
7668 } else {
7669 -1
7670 };
7671 let uid = if argc > 1 {
7672 let v = *args.get(1).ptr;
7673 if v.is_int32() { v.to_int32() as u32 } else { 0 }
7674 } else {
7675 0
7676 };
7677 let gid = if argc > 2 {
7678 let v = *args.get(2).ptr;
7679 if v.is_int32() { v.to_int32() as u32 } else { 0 }
7680 } else {
7681 0
7682 };
7683 #[cfg(unix)]
7684 {
7685 let rv = unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) };
7686 if rv == 0 {
7687 args.rval().set(UndefinedValue());
7688 true
7689 } else {
7690 throw_fs_error(
7691 cx,
7692 "fchownSync",
7693 &format!("fd:{}", fd),
7694 &::std::io::Error::last_os_error(),
7695 )
7696 }
7697 }
7698 #[cfg(not(unix))]
7699 {
7700 args.rval().set(UndefinedValue());
7701 true
7702 }
7703}
7704
7705#[allow(unsafe_op_in_unsafe_fn)]
7706unsafe extern "C" fn fs_fdatasync_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7707 let args = CallArgs::from_vp(vp, argc);
7708 let fd_val = if argc > 0 {
7709 *args.get(0).ptr
7710 } else {
7711 UndefinedValue()
7712 };
7713 let fd = if fd_val.is_int32() {
7714 fd_val.to_int32()
7715 } else {
7716 -1
7717 };
7718 #[cfg(unix)]
7719 {
7720 let rv = unsafe { libc::fdatasync(fd) };
7721 if rv == 0 {
7722 args.rval().set(UndefinedValue());
7723 true
7724 } else {
7725 throw_fs_error(
7726 cx,
7727 "fdatasyncSync",
7728 &format!("fd:{}", fd),
7729 &::std::io::Error::last_os_error(),
7730 )
7731 }
7732 }
7733 #[cfg(not(unix))]
7734 {
7735 args.rval().set(UndefinedValue());
7736 true
7737 }
7738}
7739
7740#[allow(unsafe_op_in_unsafe_fn)]
7741unsafe extern "C" fn fs_fsync_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7742 let args = CallArgs::from_vp(vp, argc);
7743 let fd_val = if argc > 0 {
7744 *args.get(0).ptr
7745 } else {
7746 UndefinedValue()
7747 };
7748 let fd = if fd_val.is_int32() {
7749 fd_val.to_int32()
7750 } else {
7751 -1
7752 };
7753 #[cfg(unix)]
7754 {
7755 let rv = unsafe { libc::fsync(fd) };
7756 if rv == 0 {
7757 args.rval().set(UndefinedValue());
7758 true
7759 } else {
7760 throw_fs_error(
7761 cx,
7762 "fsyncSync",
7763 &format!("fd:{}", fd),
7764 &::std::io::Error::last_os_error(),
7765 )
7766 }
7767 }
7768 #[cfg(not(unix))]
7769 {
7770 args.rval().set(UndefinedValue());
7771 true
7772 }
7773}
7774
7775#[allow(unsafe_op_in_unsafe_fn)]
7776unsafe extern "C" fn fs_ftruncate_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7777 let args = CallArgs::from_vp(vp, argc);
7778 let fd_val = if argc > 0 {
7779 *args.get(0).ptr
7780 } else {
7781 UndefinedValue()
7782 };
7783 let fd = if fd_val.is_int32() {
7784 fd_val.to_int32()
7785 } else {
7786 -1
7787 };
7788 let len_val = if argc > 1 {
7789 *args.get(1).ptr
7790 } else {
7791 UndefinedValue()
7792 };
7793 let len = if len_val.is_int32() {
7794 len_val.to_int32() as i64
7795 } else if len_val.is_double() {
7796 len_val.to_double() as i64
7797 } else {
7798 0
7799 };
7800 #[cfg(unix)]
7801 {
7802 let rv = unsafe { libc::ftruncate(fd, len) };
7803 if rv == 0 {
7804 args.rval().set(UndefinedValue());
7805 true
7806 } else {
7807 throw_fs_error(
7808 cx,
7809 "ftruncateSync",
7810 &format!("fd:{}", fd),
7811 &::std::io::Error::last_os_error(),
7812 )
7813 }
7814 }
7815 #[cfg(not(unix))]
7816 {
7817 args.rval().set(UndefinedValue());
7818 true
7819 }
7820}
7821
7822#[allow(unsafe_op_in_unsafe_fn)]
7823unsafe extern "C" fn fs_futimes_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7824 let args = CallArgs::from_vp(vp, argc);
7825 let fd_val = if argc > 0 {
7826 *args.get(0).ptr
7827 } else {
7828 UndefinedValue()
7829 };
7830 let fd = if fd_val.is_int32() {
7831 fd_val.to_int32()
7832 } else {
7833 -1
7834 };
7835 let atime_val = if argc > 1 {
7836 *args.get(1).ptr
7837 } else {
7838 UndefinedValue()
7839 };
7840 let mtime_val = if argc > 2 {
7841 *args.get(2).ptr
7842 } else {
7843 UndefinedValue()
7844 };
7845 let atime = if atime_val.is_double() {
7846 atime_val.to_double()
7847 } else if atime_val.is_int32() {
7848 atime_val.to_int32() as f64
7849 } else {
7850 0.0
7851 };
7852 let mtime = if mtime_val.is_double() {
7853 mtime_val.to_double()
7854 } else if mtime_val.is_int32() {
7855 mtime_val.to_int32() as f64
7856 } else {
7857 0.0
7858 };
7859 #[cfg(unix)]
7860 {
7861 let tv = [
7862 libc::timeval {
7863 tv_sec: atime as i64,
7864 tv_usec: ((atime % 1.0) * 1_000_000.0) as i64,
7865 },
7866 libc::timeval {
7867 tv_sec: mtime as i64,
7868 tv_usec: ((mtime % 1.0) * 1_000_000.0) as i64,
7869 },
7870 ];
7871 let rv = unsafe { libc::futimes(fd, tv.as_ptr()) };
7872 if rv == 0 {
7873 args.rval().set(UndefinedValue());
7874 true
7875 } else {
7876 throw_fs_error(
7877 cx,
7878 "futimesSync",
7879 &format!("fd:{}", fd),
7880 &::std::io::Error::last_os_error(),
7881 )
7882 }
7883 }
7884 #[cfg(not(unix))]
7885 {
7886 args.rval().set(UndefinedValue());
7887 true
7888 }
7889}
7890
7891#[allow(unsafe_op_in_unsafe_fn)]
7892unsafe extern "C" fn fs_lchmod_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7893 let args = CallArgs::from_vp(vp, argc);
7894 let path = match get_path_arg(cx, &args, 0) {
7895 ::std::result::Result::Ok(p) => p,
7896 ::std::result::Result::Err(b) => return b,
7897 };
7898 let mode_val = if argc > 1 {
7899 *args.get(1).ptr
7900 } else {
7901 UndefinedValue()
7902 };
7903 let mode = if mode_val.is_int32() {
7904 mode_val.to_int32() as u32
7905 } else {
7906 0o644
7907 };
7908 #[cfg(unix)]
7910 {
7911 use ::std::os::unix::fs::PermissionsExt;
7912 match fs::set_permissions(&path, fs::Permissions::from_mode(mode)) {
7913 ::std::result::Result::Ok(()) => {
7914 args.rval().set(UndefinedValue());
7915 true
7916 }
7917 ::std::result::Result::Err(e) => throw_fs_error(cx, "lchmodSync", &path, &e),
7918 }
7919 }
7920 #[cfg(not(unix))]
7921 {
7922 let _ = mode;
7923 let _ = path;
7924 args.rval().set(UndefinedValue());
7925 true
7926 }
7927}
7928
7929#[allow(unsafe_op_in_unsafe_fn)]
7930unsafe extern "C" fn fs_lchown_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7931 let args = CallArgs::from_vp(vp, argc);
7932 let path = match get_path_arg(cx, &args, 0) {
7933 ::std::result::Result::Ok(p) => p,
7934 ::std::result::Result::Err(b) => return b,
7935 };
7936 let uid = if argc > 1 {
7937 let v = *args.get(1).ptr;
7938 if v.is_int32() { v.to_int32() as u32 } else { 0 }
7939 } else {
7940 0
7941 };
7942 let gid = if argc > 2 {
7943 let v = *args.get(2).ptr;
7944 if v.is_int32() { v.to_int32() as u32 } else { 0 }
7945 } else {
7946 0
7947 };
7948 #[cfg(unix)]
7949 {
7950 let c_path = ::std::ffi::CString::new(path.as_str()).unwrap_or_default();
7951 let rv = unsafe { libc::lchown(c_path.as_ptr(), uid, gid) };
7952 if rv == 0 {
7953 args.rval().set(UndefinedValue());
7954 true
7955 } else {
7956 throw_fs_error(cx, "lchownSync", &path, &::std::io::Error::last_os_error())
7957 }
7958 }
7959 #[cfg(not(unix))]
7960 {
7961 args.rval().set(UndefinedValue());
7962 true
7963 }
7964}
7965
7966#[allow(unsafe_op_in_unsafe_fn)]
7967unsafe extern "C" fn fs_readv_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
7968 let args = CallArgs::from_vp(vp, argc);
7969 let fd_val = if argc > 0 {
7970 *args.get(0).ptr
7971 } else {
7972 UndefinedValue()
7973 };
7974 let fd = if fd_val.is_int32() {
7975 fd_val.to_int32()
7976 } else {
7977 -1
7978 };
7979 let buffers_val = if argc > 1 {
7980 *args.get(1).ptr
7981 } else {
7982 UndefinedValue()
7983 };
7984 if !buffers_val.is_object() {
7985 JS_ReportErrorUTF8(cx, c"readvSync: buffers must be an array".as_ptr());
7986 return false;
7987 }
7988 let mut wrapped_cx =
7989 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
7990 let cx_ref = &mut wrapped_cx;
7991 rooted!(&in(cx_ref) let buffers_obj = buffers_val.to_object());
7992 let mut total_read: i32 = 0;
7993 let mut buf_idx: u32 = 0;
7994 loop {
7995 let mut elem = UndefinedValue();
7996 JS_GetElement(
7997 cx,
7998 buffers_obj.handle().into(),
7999 buf_idx,
8000 MutableHandle::<Value> {
8001 _phantom_0: ::std::marker::PhantomData,
8002 ptr: &mut elem,
8003 },
8004 );
8005 if elem.is_undefined() {
8006 break;
8007 }
8008 if elem.is_object() {
8009 let buf_bytes = crate::node_crypto::extract_buffer_bytes(cx, elem);
8010 if !buf_bytes.is_empty() {
8011 let mut write_buf = buf_bytes;
8012 #[cfg(unix)]
8013 {
8014 let n = unsafe {
8015 libc::read(
8016 fd,
8017 write_buf.as_mut_ptr() as *mut ::std::ffi::c_void,
8018 write_buf.len(),
8019 )
8020 };
8021 if n < 0 {
8022 return throw_fs_error(
8023 cx,
8024 "readvSync",
8025 &format!("fd:{}", fd),
8026 &::std::io::Error::last_os_error(),
8027 );
8028 }
8029 total_read += n as i32;
8030 }
8031 }
8032 }
8033 buf_idx += 1;
8034 }
8035 args.rval().set(mozjs::jsval::Int32Value(total_read));
8036 true
8037}
8038
8039#[allow(unsafe_op_in_unsafe_fn)]
8040unsafe extern "C" fn fs_writev_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
8041 let args = CallArgs::from_vp(vp, argc);
8042 let fd_val = if argc > 0 {
8043 *args.get(0).ptr
8044 } else {
8045 UndefinedValue()
8046 };
8047 let fd = if fd_val.is_int32() {
8048 fd_val.to_int32()
8049 } else {
8050 -1
8051 };
8052 let buffers_val = if argc > 1 {
8053 *args.get(1).ptr
8054 } else {
8055 UndefinedValue()
8056 };
8057 if !buffers_val.is_object() {
8058 JS_ReportErrorUTF8(cx, c"writevSync: buffers must be an array".as_ptr());
8059 return false;
8060 }
8061 let mut wrapped_cx =
8062 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8063 let cx_ref = &mut wrapped_cx;
8064 rooted!(&in(cx_ref) let buffers_obj = buffers_val.to_object());
8065 let mut total_written: i32 = 0;
8066 let mut buf_idx: u32 = 0;
8067 loop {
8068 let mut elem = UndefinedValue();
8069 JS_GetElement(
8070 cx,
8071 buffers_obj.handle().into(),
8072 buf_idx,
8073 MutableHandle::<Value> {
8074 _phantom_0: ::std::marker::PhantomData,
8075 ptr: &mut elem,
8076 },
8077 );
8078 if elem.is_undefined() {
8079 break;
8080 }
8081 let bytes = if elem.is_string() {
8082 let s = elem.to_string();
8083 if !s.is_null() {
8084 crate::jsstr_to_rust_string(cx, s).into_bytes()
8085 } else {
8086 Vec::new()
8087 }
8088 } else if elem.is_object() {
8089 crate::node_crypto::extract_buffer_bytes(cx, elem)
8090 } else {
8091 Vec::new()
8092 };
8093 if !bytes.is_empty() {
8094 #[cfg(unix)]
8095 {
8096 let n = unsafe {
8097 libc::write(fd, bytes.as_ptr() as *const ::std::ffi::c_void, bytes.len())
8098 };
8099 if n < 0 {
8100 return throw_fs_error(
8101 cx,
8102 "writevSync",
8103 &format!("fd:{}", fd),
8104 &::std::io::Error::last_os_error(),
8105 );
8106 }
8107 total_written += n as i32;
8108 }
8109 }
8110 buf_idx += 1;
8111 }
8112 args.rval().set(mozjs::jsval::Int32Value(total_written));
8113 true
8114}
8115
8116struct GlobOptions {
8134 start_dir: String,
8135 dot: bool,
8136 exclude_fn: Option<*mut JSObject>,
8139 exclude_globs: Vec<String>,
8140}
8141
8142#[allow(unsafe_op_in_unsafe_fn)]
8145unsafe fn glob_collect(
8146 cx: *mut JSContext,
8147 pattern: &str,
8148 opts: &GlobOptions,
8149 results: &mut Vec<String>,
8150) {
8151 type Walker = bun_glob::GlobWalker<bun_glob::walk::SyscallAccessor, false>;
8152 let absolute = pattern.starts_with('/');
8153 let mut walker = match Walker::init_with_cwd(
8154 pattern.as_bytes(),
8155 opts.start_dir.as_bytes(),
8156 opts.dot,
8157 absolute,
8158 true,
8160 false,
8161 false,
8163 None,
8164 ) {
8165 Ok(Ok(w)) => w,
8166 _ => return,
8168 };
8169 let mut iter = bun_glob::walk::Iterator::new(&mut walker);
8170 if iter.init().is_err() {
8171 return;
8172 }
8173 let prefix = format!("{}/", opts.start_dir.trim_end_matches('/'));
8174 loop {
8175 match iter.next() {
8176 Ok(Ok(Some(path))) => {
8177 let full = String::from_utf8_lossy(&path).into_owned();
8178 let shown = if !absolute && full.starts_with(&prefix) {
8179 full[prefix.len()..].to_string()
8180 } else {
8181 full
8182 };
8183 if glob_excluded(cx, &shown, opts) {
8184 continue;
8185 }
8186 results.push(shown);
8187 }
8188 _ => break,
8189 }
8190 }
8191}
8192
8193#[allow(unsafe_op_in_unsafe_fn)]
8196unsafe fn glob_excluded(cx: *mut JSContext, path: &str, opts: &GlobOptions) -> bool {
8197 if let Some(cb) = opts.exclude_fn {
8198 if !cb.is_null() {
8199 let wrapped_cx = mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8200 rooted!(&in(wrapped_cx) let cb_root = cb);
8201 let path_c = ZBox::from_bytes(path.as_bytes());
8202 let path_js = JS_NewStringCopyZ(cx, path_c.as_ptr());
8203 if path_js.is_null() {
8204 return false;
8205 }
8206 let arg = mozjs::jsval::StringValue(&*path_js);
8207 let args_arr = [arg];
8208 let call_args = HandleValueArray {
8209 length_: 1,
8210 elements_: args_arr.as_ptr(),
8211 };
8212 let global = CurrentGlobalOrNull(cx);
8213 if global.is_null() {
8214 return false;
8215 }
8216 rooted!(&in(wrapped_cx) let global_root = global);
8217 rooted!(&in(wrapped_cx) let cb_val = mozjs::jsval::ObjectValue(cb_root.get()));
8218 let mut rval = UndefinedValue();
8219 let ok = JS_CallFunctionValue(
8220 cx,
8221 global_root.handle().into(),
8222 cb_val.handle().into(),
8223 &call_args,
8224 MutableHandle::<Value> {
8225 _phantom_0: ::std::marker::PhantomData,
8226 ptr: &mut rval,
8227 },
8228 );
8229 return ok && rval.is_boolean() && rval.to_boolean();
8230 }
8231 }
8232 for pat in &opts.exclude_globs {
8233 if let bun_glob::MatchResult::Match = bun_glob::r#match(pat.as_bytes(), path.as_bytes()) {
8234 return true;
8235 }
8236 }
8237 false
8238}
8239
8240#[allow(unsafe_op_in_unsafe_fn)]
8242unsafe fn glob_opt_string(cx: *mut JSContext, obj: *mut JSObject, name: &[u8]) -> Option<String> {
8243 let name_z = ZBox::from_bytes(name);
8244 let wrapped_cx = mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8245 rooted!(&in(wrapped_cx) let obj_root = obj);
8246 let mut val = UndefinedValue();
8247 JS_GetProperty(
8248 cx,
8249 obj_root.handle().into(),
8250 name_z.as_ptr(),
8251 MutableHandle::<Value> {
8252 _phantom_0: ::std::marker::PhantomData,
8253 ptr: &mut val,
8254 },
8255 );
8256 if val.is_string() {
8257 let s = crate::jsstr_to_rust_string(cx, val.to_string());
8258 if !s.is_empty() {
8259 return Some(s);
8260 }
8261 }
8262 None
8263}
8264
8265#[allow(unsafe_op_in_unsafe_fn)]
8267unsafe fn glob_opt_bool(cx: *mut JSContext, obj: *mut JSObject, name: &[u8]) -> bool {
8268 let name_z = ZBox::from_bytes(name);
8269 let wrapped_cx = mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8270 rooted!(&in(wrapped_cx) let obj_root = obj);
8271 let mut val = UndefinedValue();
8272 JS_GetProperty(
8273 cx,
8274 obj_root.handle().into(),
8275 name_z.as_ptr(),
8276 MutableHandle::<Value> {
8277 _phantom_0: ::std::marker::PhantomData,
8278 ptr: &mut val,
8279 },
8280 );
8281 val.is_boolean() && val.to_boolean()
8282}
8283
8284#[allow(unsafe_op_in_unsafe_fn)]
8288unsafe fn glob_parse_options(cx: *mut JSContext, args: &CallArgs, arg_index: u32) -> GlobOptions {
8289 let mut opts = GlobOptions {
8290 start_dir: ::std::env::current_dir()
8291 .map(|p| p.to_string_lossy().into_owned())
8292 .unwrap_or_default(),
8293 dot: false,
8294 exclude_fn: None,
8295 exclude_globs: Vec::new(),
8296 };
8297 let val = *args.get(arg_index).ptr;
8298 if !val.is_object() {
8299 return opts;
8300 }
8301 let obj = val.to_object();
8302 if let Some(cwd) = glob_opt_string(cx, obj, b"cwd") {
8304 opts.start_dir = cwd;
8305 } else if let Some(root) = glob_opt_string(cx, obj, b"root") {
8306 opts.start_dir = root;
8307 }
8308 opts.dot = glob_opt_bool(cx, obj, b"dot");
8309
8310 let excl_z = ZBox::from_bytes(b"exclude");
8311 let wrapped_cx = mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8312 rooted!(&in(wrapped_cx) let obj_root = obj);
8313 let mut excl = UndefinedValue();
8314 JS_GetProperty(
8315 cx,
8316 obj_root.handle().into(),
8317 excl_z.as_ptr(),
8318 MutableHandle::<Value> {
8319 _phantom_0: ::std::marker::PhantomData,
8320 ptr: &mut excl,
8321 },
8322 );
8323 if excl.is_object() {
8324 let excl_obj = excl.to_object();
8325 if mozjs_sys::jsapi::JS::IsCallable(excl_obj) {
8326 opts.exclude_fn = Some(excl_obj);
8327 } else {
8328 let mut len_val = UndefinedValue();
8330 JS_GetProperty(
8331 cx,
8332 obj_root.handle().into(),
8333 c"length".as_ptr(),
8334 MutableHandle::<Value> {
8335 _phantom_0: ::std::marker::PhantomData,
8336 ptr: &mut len_val,
8337 },
8338 );
8339 if len_val.is_int32() {
8340 for i in 0..len_val.to_int32().max(0) as u32 {
8341 let mut elem = UndefinedValue();
8342 if JS_GetElement(
8343 cx,
8344 obj_root.handle().into(),
8345 i,
8346 MutableHandle::<Value> {
8347 _phantom_0: ::std::marker::PhantomData,
8348 ptr: &mut elem,
8349 },
8350 ) && elem.is_string()
8351 {
8352 opts.exclude_globs.push(crate::jsstr_to_rust_string(cx, elem.to_string()));
8353 }
8354 }
8355 }
8356 }
8357 }
8358 opts
8359}
8360
8361#[allow(unsafe_op_in_unsafe_fn)]
8363unsafe fn glob_patterns(cx: *mut JSContext, args: &CallArgs) -> Vec<String> {
8364 let val = *args.get(0).ptr;
8365 let mut patterns = Vec::new();
8366 if val.is_string() {
8367 patterns.push(crate::jsstr_to_rust_string(cx, val.to_string()));
8368 } else if val.is_object() {
8369 let wrapped_cx = mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8370 rooted!(&in(wrapped_cx) let arr = val.to_object());
8371 let mut len_val = UndefinedValue();
8372 JS_GetProperty(
8373 cx,
8374 arr.handle().into(),
8375 c"length".as_ptr(),
8376 MutableHandle::<Value> {
8377 _phantom_0: ::std::marker::PhantomData,
8378 ptr: &mut len_val,
8379 },
8380 );
8381 if len_val.is_int32() {
8382 for i in 0..len_val.to_int32().max(0) as u32 {
8383 let mut elem = UndefinedValue();
8384 if JS_GetElement(
8385 cx,
8386 arr.handle().into(),
8387 i,
8388 MutableHandle::<Value> {
8389 _phantom_0: ::std::marker::PhantomData,
8390 ptr: &mut elem,
8391 },
8392 ) && elem.is_string()
8393 {
8394 patterns.push(crate::jsstr_to_rust_string(cx, elem.to_string()));
8395 }
8396 }
8397 }
8398 }
8399 patterns
8400}
8401
8402#[allow(unsafe_op_in_unsafe_fn)]
8403unsafe extern "C" fn fs_glob_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
8404 let args = CallArgs::from_vp(vp, argc);
8405 let patterns = glob_patterns(cx, &args);
8406 let opts = glob_parse_options(cx, &args, 1);
8407 let mut results: Vec<String> = Vec::new();
8408 for pat in &patterns {
8409 glob_collect(cx, pat, &opts, &mut results);
8410 }
8411 let mut wrapped_cx =
8412 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8413 let cx_ref = &mut wrapped_cx;
8414 rooted!(&in(cx_ref) let arr = w2::NewArrayObject1(cx_ref, results.len()));
8415 if arr.get().is_null() {
8416 args.rval().set(UndefinedValue());
8417 return true;
8418 }
8419 for (idx, path) in results.iter().enumerate() {
8420 let c_path = ZBox::from_bytes(path.as_bytes());
8421 let js_str = JS_NewStringCopyZ(cx, c_path.as_ptr());
8422 if !js_str.is_null() {
8423 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
8424 JS_DefineElement(
8425 cx,
8426 arr.handle().into(),
8427 idx as u32,
8428 val.handle().into(),
8429 JSPROP_ENUMERATE as u32,
8430 );
8431 }
8432 }
8433 args.rval().set(mozjs::jsval::ObjectValue(arr.get()));
8434 true
8435}
8436
8437#[allow(unsafe_op_in_unsafe_fn)]
8438unsafe extern "C" fn fs_glob(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
8439 let args = CallArgs::from_vp(vp, argc);
8440 let patterns = glob_patterns(cx, &args);
8441
8442 let opts_idx = if argc >= 3 { 1 } else { 1 };
8445 let opts = glob_parse_options(cx, &args, opts_idx);
8446
8447 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 2) {
8448 let mut prefiltered: Vec<String> = Vec::new();
8451 for pat in &patterns {
8452 glob_collect(cx, pat, &opts, &mut prefiltered);
8453 }
8454 spawn_fs_async(cx, "glob", patterns.join(","), callback, None, move || {
8455 Ok(FsAsyncResult::OkDirnames(prefiltered))
8456 });
8457 args.rval().set(UndefinedValue());
8458 return true;
8459 }
8460
8461 let mut results: Vec<String> = Vec::new();
8463 for pat in &patterns {
8464 glob_collect(cx, pat, &opts, &mut results);
8465 }
8466 let mut wrapped_cx =
8467 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8468 let cx_ref = &mut wrapped_cx;
8469 rooted!(&in(cx_ref) let arr = w2::NewArrayObject1(cx_ref, results.len()));
8470 if arr.get().is_null() {
8471 args.rval().set(UndefinedValue());
8472 return true;
8473 }
8474 for (idx, path) in results.iter().enumerate() {
8475 let c_path = ZBox::from_bytes(path.as_bytes());
8476 let js_str = JS_NewStringCopyZ(cx, c_path.as_ptr());
8477 if !js_str.is_null() {
8478 rooted!(&in(cx_ref) let val = mozjs::jsval::StringValue(&*js_str));
8479 JS_DefineElement(
8480 cx,
8481 arr.handle().into(),
8482 idx as u32,
8483 val.handle().into(),
8484 JSPROP_ENUMERATE as u32,
8485 );
8486 }
8487 }
8488 args.rval().set(mozjs::jsval::ObjectValue(arr.get()));
8489 true
8490}
8491
8492#[allow(unsafe_op_in_unsafe_fn)]
8493unsafe extern "C" fn fs_open_as_blob(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
8494 let args = CallArgs::from_vp(vp, argc);
8495 let path = match get_path_arg(cx, &args, 0) {
8496 ::std::result::Result::Ok(p) => p,
8497 ::std::result::Result::Err(b) => return b,
8498 };
8499 let mut wrapped_cx =
8500 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8501 let cx_ref = &mut wrapped_cx;
8502 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
8503 if promise.get().is_null() {
8504 args.rval().set(UndefinedValue());
8505 return false;
8506 }
8507
8508 match bun_fs::read(&path) {
8509 ::std::result::Result::Ok(data) => {
8510 let buf_obj = crate::globals::create_buffer_object(cx, &data);
8511 if !buf_obj.is_null() {
8512 rooted!(&in(cx_ref) let blob_obj = JS_NewPlainObject(cx));
8514 if !blob_obj.get().is_null() {
8515 define_num_prop(cx, blob_obj.get(), "size", data.len() as f64);
8516 rooted!(&in(cx_ref) let buf_val = mozjs::jsval::ObjectValue(buf_obj));
8517 JS_DefineProperty(
8518 cx,
8519 blob_obj.handle().into(),
8520 c"_buffer".as_ptr(),
8521 buf_val.handle().into(),
8522 0,
8523 );
8524 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(blob_obj.get()));
8525 unsafe {
8526 mozjs_sys::jsapi::JS::ResolvePromise(
8527 cx,
8528 promise.handle().into(),
8529 val.handle().into(),
8530 );
8531 }
8532 } else {
8533 resolve_undefined(cx, promise.get());
8534 }
8535 } else {
8536 resolve_undefined(cx, promise.get());
8537 }
8538 }
8539 ::std::result::Result::Err(e) => {
8540 reject_with_error(cx, promise.get(), &format!("openAsBlob '{}': {}", path, e))
8541 }
8542 }
8543 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
8544 true
8545}
8546
8547#[allow(unsafe_op_in_unsafe_fn)]
8550unsafe fn get_bool_option(cx: *mut JSContext, args: &CallArgs, opt_index: u32, key: &str) -> bool {
8551 if args.argc_ <= opt_index {
8552 return false;
8553 }
8554 let opt_val = *args.get(opt_index).ptr;
8555 if !opt_val.is_object() {
8556 return false;
8557 }
8558 let mut wrapped_cx_opt =
8559 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8560 let cx_ref_opt = &mut wrapped_cx_opt;
8561 rooted!(&in(cx_ref_opt) let obj = opt_val.to_object());
8562 let c_key = ZBox::from_bytes(key.as_bytes());
8563 let mut val = UndefinedValue();
8564 JS_GetProperty(
8565 cx,
8566 obj.handle().into(),
8567 c_key.as_ptr(),
8568 MutableHandle::<Value> {
8569 _phantom_0: ::std::marker::PhantomData,
8570 ptr: &mut val,
8571 },
8572 );
8573 val.is_boolean() && val.to_boolean()
8574}
8575
8576#[allow(unsafe_op_in_unsafe_fn)]
8577unsafe fn string_or_buffer(
8578 cx: *mut JSContext,
8579 data: &[u8],
8580 encoding: ::std::option::Option<&str>,
8581) -> JSVal {
8582 match encoding {
8583 Some("utf-8" | "utf8" | "text") | None => {
8584 let s = ::std::string::String::from_utf8_lossy(data);
8587 let js_str = js_string_from_utf8(cx, &s);
8588 if js_str.is_null() {
8589 UndefinedValue()
8590 } else {
8591 mozjs::jsval::StringValue(&*js_str)
8592 }
8593 }
8594 Some("hex") => {
8595 let hex: ::std::string::String = bun_core::fmt::bytes_to_hex_lower_string(data);
8596 let c_str = ZBox::from_bytes(hex.as_bytes());
8597 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
8598 if js_str.is_null() {
8599 UndefinedValue()
8600 } else {
8601 mozjs::jsval::StringValue(&*js_str)
8602 }
8603 }
8604 Some("base64") => {
8605 let encoded_bytes = bun_base64::encode_alloc(data);
8608 let encoded = ::std::str::from_utf8(&encoded_bytes).unwrap_or("");
8609 let c_str = ZBox::from_bytes(encoded.as_bytes());
8610 let js_str = JS_NewStringCopyZ(cx, c_str.as_ptr());
8611 if js_str.is_null() {
8612 UndefinedValue()
8613 } else {
8614 mozjs::jsval::StringValue(&*js_str)
8615 }
8616 }
8617 _ => UndefinedValue(),
8618 }
8619}
8620
8621#[allow(unsafe_op_in_unsafe_fn)]
8622#[cfg(unix)]
8625fn metadata_to_posix_stat(meta: &fs::Metadata) -> bun_sys::PosixStat {
8626 use ::std::os::unix::fs::MetadataExt;
8627 bun_sys::PosixStat {
8628 dev: meta.dev() as u64,
8629 ino: meta.ino() as u64,
8630 mode: meta.mode() as u64,
8631 nlink: meta.nlink() as u64,
8632 uid: meta.uid() as u64,
8633 gid: meta.gid() as u64,
8634 rdev: meta.rdev() as u64,
8635 size: meta.size(),
8636 blksize: meta.blksize() as u64,
8637 blocks: meta.blocks() as u64,
8638 atim: bun_sys::Timespec {
8639 sec: meta.atime(),
8640 nsec: meta.atime_nsec() as i64,
8641 },
8642 mtim: bun_sys::Timespec {
8643 sec: meta.mtime(),
8644 nsec: meta.mtime_nsec() as i64,
8645 },
8646 ctim: bun_sys::Timespec {
8647 sec: meta.ctime(),
8648 nsec: meta.ctime_nsec() as i64,
8649 },
8650 birthtim: bun_sys::Timespec { sec: 0, nsec: 0 },
8651 }
8652}
8653
8654#[cfg(not(unix))]
8655fn metadata_to_posix_stat(meta: &fs::Metadata) -> bun_sys::PosixStat {
8656 bun_sys::PosixStat {
8657 dev: 0,
8658 ino: 0,
8659 mode: 0,
8660 nlink: 0,
8661 uid: 0,
8662 gid: 0,
8663 rdev: 0,
8664 size: meta.len(),
8665 blksize: 0,
8666 blocks: 0,
8667 atim: bun_sys::Timespec { sec: 0, nsec: 0 },
8668 mtim: bun_sys::Timespec { sec: 0, nsec: 0 },
8669 ctim: bun_sys::Timespec { sec: 0, nsec: 0 },
8670 birthtim: bun_sys::Timespec { sec: 0, nsec: 0 },
8671 }
8672}
8673
8674#[cfg(unix)]
8678fn posix_stat_from_libc(s: &libc::stat) -> bun_sys::PosixStat {
8679 bun_sys::PosixStat {
8680 dev: s.st_dev as u64,
8681 ino: s.st_ino as u64,
8682 mode: s.st_mode as u64,
8683 nlink: s.st_nlink as u64,
8684 uid: s.st_uid as u64,
8685 gid: s.st_gid as u64,
8686 rdev: s.st_rdev as u64,
8687 size: s.st_size as u64,
8688 blksize: s.st_blksize as u64,
8689 blocks: s.st_blocks as u64,
8690 atim: bun_sys::Timespec {
8691 sec: s.st_atime,
8692 nsec: s.st_atime_nsec as i64,
8693 },
8694 mtim: bun_sys::Timespec {
8695 sec: s.st_mtime,
8696 nsec: s.st_mtime_nsec as i64,
8697 },
8698 ctim: bun_sys::Timespec {
8699 sec: s.st_ctime,
8700 nsec: s.st_ctime_nsec as i64,
8701 },
8702 birthtim: bun_sys::Timespec { sec: 0, nsec: 0 },
8703 }
8704}
8705
8706#[cfg(not(unix))]
8707fn posix_stat_from_libc(_s: &libc::stat) -> bun_sys::PosixStat {
8708 bun_sys::PosixStat {
8709 dev: 0,
8710 ino: 0,
8711 mode: 0,
8712 nlink: 0,
8713 uid: 0,
8714 gid: 0,
8715 rdev: 0,
8716 size: 0,
8717 blksize: 0,
8718 blocks: 0,
8719 atim: bun_sys::Timespec { sec: 0, nsec: 0 },
8720 mtim: bun_sys::Timespec { sec: 0, nsec: 0 },
8721 ctim: bun_sys::Timespec { sec: 0, nsec: 0 },
8722 birthtim: bun_sys::Timespec { sec: 0, nsec: 0 },
8723 }
8724}
8725
8726#[allow(unsafe_op_in_unsafe_fn)]
8727unsafe fn create_stats_object(cx: *mut JSContext, meta: &bun_fs::PosixStat) -> *mut JSObject {
8728 let mut wrapped_cx =
8729 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8730 let cx_ref = &mut wrapped_cx;
8731 rooted!(&in(cx_ref) let stats = JS_NewPlainObject(cx));
8732 if stats.get().is_null() {
8733 return stats.get();
8734 }
8735
8736 let mode_type = (meta.mode as u32) & libc::S_IFMT;
8738 let is_file = mode_type == libc::S_IFREG;
8739 let is_dir = mode_type == libc::S_IFDIR;
8740 let is_symlink = mode_type == libc::S_IFLNK;
8741 let is_block_device = mode_type == libc::S_IFBLK;
8742 let is_character_device = mode_type == libc::S_IFCHR;
8743 let is_fifo = mode_type == libc::S_IFIFO;
8744 let is_socket = mode_type == libc::S_IFSOCK;
8745
8746 let atime_ms = meta.atim.sec as f64 * 1000.0 + meta.atim.nsec as f64 / 1_000_000.0;
8747 let mtime_ms = meta.mtim.sec as f64 * 1000.0 + meta.mtim.nsec as f64 / 1_000_000.0;
8748 let ctime_ms = meta.ctim.sec as f64 * 1000.0 + meta.ctim.nsec as f64 / 1_000_000.0;
8749 let birthtime_ms = if meta.birthtim.sec == 0 && meta.birthtim.nsec == 0 {
8751 ctime_ms
8752 } else {
8753 meta.birthtim.sec as f64 * 1000.0 + meta.birthtim.nsec as f64 / 1_000_000.0
8754 };
8755
8756 define_num_prop(cx, stats.get(), "size", meta.size as f64);
8757 define_num_prop(cx, stats.get(), "dev", meta.dev as f64);
8758 define_num_prop(cx, stats.get(), "ino", meta.ino as f64);
8759 define_num_prop(cx, stats.get(), "mode", meta.mode as f64);
8760 define_num_prop(cx, stats.get(), "nlink", meta.nlink as f64);
8761 define_num_prop(cx, stats.get(), "uid", meta.uid as f64);
8762 define_num_prop(cx, stats.get(), "gid", meta.gid as f64);
8763 define_num_prop(cx, stats.get(), "rdev", meta.rdev as f64);
8764 define_num_prop(cx, stats.get(), "blksize", meta.blksize as f64);
8765 define_num_prop(cx, stats.get(), "blocks", meta.blocks as f64);
8766 define_num_prop(cx, stats.get(), "atimeMs", atime_ms);
8767 define_num_prop(cx, stats.get(), "mtimeMs", mtime_ms);
8768 define_num_prop(cx, stats.get(), "ctimeMs", ctime_ms);
8769 define_num_prop(cx, stats.get(), "birthtimeMs", birthtime_ms);
8770
8771 let date_props: [(&str, f64); 4] = [
8773 ("atime", atime_ms),
8774 ("mtime", mtime_ms),
8775 ("ctime", ctime_ms),
8776 ("birthtime", birthtime_ms),
8777 ];
8778 for (prop, ms) in &date_props {
8779 let date_obj = w2::NewDateObject(cx_ref, mozjs::jsapi::ClippedTime { t: *ms });
8780 if !date_obj.is_null() {
8781 rooted!(&in(cx_ref) let date_val = mozjs::jsval::ObjectValue(date_obj));
8782 let c_prop = ZBox::from_bytes(prop.as_bytes());
8783 JS_DefineProperty(
8784 cx,
8785 stats.handle().into(),
8786 c_prop.as_ptr(),
8787 date_val.handle().into(),
8788 JSPROP_ENUMERATE as u32,
8789 );
8790 }
8791 }
8792
8793 define_bool_prop(cx, stats.get(), "_isFile", is_file);
8795 define_bool_prop(cx, stats.get(), "_isDirectory", is_dir);
8796 define_bool_prop(cx, stats.get(), "_isSymbolicLink", is_symlink);
8797 define_bool_prop(cx, stats.get(), "_isBlockDevice", is_block_device);
8798 define_bool_prop(cx, stats.get(), "_isCharacterDevice", is_character_device);
8799 define_bool_prop(cx, stats.get(), "_isFIFO", is_fifo);
8800 define_bool_prop(cx, stats.get(), "_isSocket", is_socket);
8801
8802 w2::JS_DefineFunction(
8804 cx_ref,
8805 stats.handle().into(),
8806 c"isFile".as_ptr(),
8807 Some(stats_is_file),
8808 0,
8809 JSPROP_ENUMERATE as u32,
8810 );
8811 w2::JS_DefineFunction(
8812 cx_ref,
8813 stats.handle().into(),
8814 c"isDirectory".as_ptr(),
8815 Some(stats_is_directory),
8816 0,
8817 JSPROP_ENUMERATE as u32,
8818 );
8819 w2::JS_DefineFunction(
8820 cx_ref,
8821 stats.handle().into(),
8822 c"isSymbolicLink".as_ptr(),
8823 Some(stats_is_symlink),
8824 0,
8825 JSPROP_ENUMERATE as u32,
8826 );
8827 w2::JS_DefineFunction(
8828 cx_ref,
8829 stats.handle().into(),
8830 c"isBlockDevice".as_ptr(),
8831 Some(stats_is_block_device),
8832 0,
8833 JSPROP_ENUMERATE as u32,
8834 );
8835 w2::JS_DefineFunction(
8836 cx_ref,
8837 stats.handle().into(),
8838 c"isCharacterDevice".as_ptr(),
8839 Some(stats_is_character_device),
8840 0,
8841 JSPROP_ENUMERATE as u32,
8842 );
8843 w2::JS_DefineFunction(
8844 cx_ref,
8845 stats.handle().into(),
8846 c"isFIFO".as_ptr(),
8847 Some(stats_is_fifo),
8848 0,
8849 JSPROP_ENUMERATE as u32,
8850 );
8851 w2::JS_DefineFunction(
8852 cx_ref,
8853 stats.handle().into(),
8854 c"isSocket".as_ptr(),
8855 Some(stats_is_socket),
8856 0,
8857 JSPROP_ENUMERATE as u32,
8858 );
8859
8860 stats.get()
8861}
8862
8863#[allow(unsafe_op_in_unsafe_fn)]
8864unsafe fn create_dirent(cx: *mut JSContext, name: &str, is_dir: bool) -> *mut JSObject {
8865 let mut wrapped_cx =
8866 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8867 let cx_ref = &mut wrapped_cx;
8868 rooted!(&in(cx_ref) let dirent = JS_NewPlainObject(cx));
8869 if dirent.get().is_null() {
8870 return dirent.get();
8871 }
8872 let c_name = ZBox::from_bytes(name.as_bytes());
8873 let js_str = JS_NewStringCopyZ(cx, c_name.as_ptr());
8874 if !js_str.is_null() {
8875 rooted!(&in(cx_ref) let name_val = mozjs::jsval::StringValue(&*js_str));
8876 JS_DefineProperty(
8877 cx,
8878 dirent.handle().into(),
8879 c"name".as_ptr(),
8880 name_val.handle().into(),
8881 JSPROP_ENUMERATE as u32,
8882 );
8883 }
8884 let type_code: i32 = if is_dir { 1 } else { 0 };
8886 set_hidden_int(cx, dirent.get(), "_typeCode", type_code);
8887 define_bool_prop(cx, dirent.get(), "isFile", !is_dir);
8888 define_bool_prop(cx, dirent.get(), "isDirectory", is_dir);
8889
8890 w2::JS_DefineFunction(
8891 cx_ref,
8892 dirent.handle().into(),
8893 c"isFile".as_ptr(),
8894 Some(dirent_is_file),
8895 0,
8896 JSPROP_ENUMERATE as u32,
8897 );
8898 w2::JS_DefineFunction(
8899 cx_ref,
8900 dirent.handle().into(),
8901 c"isDirectory".as_ptr(),
8902 Some(dirent_is_directory),
8903 0,
8904 JSPROP_ENUMERATE as u32,
8905 );
8906 w2::JS_DefineFunction(
8907 cx_ref,
8908 dirent.handle().into(),
8909 c"isSymbolicLink".as_ptr(),
8910 Some(dirent_is_symbolic_link),
8911 0,
8912 JSPROP_ENUMERATE as u32,
8913 );
8914 w2::JS_DefineFunction(
8915 cx_ref,
8916 dirent.handle().into(),
8917 c"isBlockDevice".as_ptr(),
8918 Some(dirent_is_block_device),
8919 0,
8920 JSPROP_ENUMERATE as u32,
8921 );
8922 w2::JS_DefineFunction(
8923 cx_ref,
8924 dirent.handle().into(),
8925 c"isCharacterDevice".as_ptr(),
8926 Some(dirent_is_character_device),
8927 0,
8928 JSPROP_ENUMERATE as u32,
8929 );
8930 w2::JS_DefineFunction(
8931 cx_ref,
8932 dirent.handle().into(),
8933 c"isFIFO".as_ptr(),
8934 Some(dirent_is_fifo),
8935 0,
8936 JSPROP_ENUMERATE as u32,
8937 );
8938 w2::JS_DefineFunction(
8939 cx_ref,
8940 dirent.handle().into(),
8941 c"isSocket".as_ptr(),
8942 Some(dirent_is_socket),
8943 0,
8944 JSPROP_ENUMERATE as u32,
8945 );
8946
8947 dirent.get()
8948}
8949
8950#[allow(unsafe_op_in_unsafe_fn)]
8951unsafe fn resolve_undefined(cx: *mut JSContext, promise: *mut JSObject) {
8952 let mut wrapped_cx =
8953 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8954 let cx_ref = &mut wrapped_cx;
8955 rooted!(&in(cx_ref) let val = UndefinedValue());
8956 rooted!(&in(cx_ref) let promise_rooted = promise);
8957 mozjs_sys::jsapi::JS::ResolvePromise(cx, promise_rooted.handle().into(), val.handle().into());
8958}
8959
8960#[allow(unsafe_op_in_unsafe_fn)]
8961unsafe fn reject_with_error(cx: *mut JSContext, promise: *mut JSObject, msg: &str) {
8962 let mut wrapped_cx =
8963 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8964 let cx_ref = &mut wrapped_cx;
8965 rooted!(&in(cx_ref) let err_obj = JS_NewPlainObject(cx));
8966 if !err_obj.get().is_null() {
8967 let c_msg = ZBox::from_bytes(msg.as_bytes());
8968 let js_str = JS_NewStringCopyZ(cx, c_msg.as_ptr());
8969 if !js_str.is_null() {
8970 rooted!(&in(cx_ref) let msg_val = mozjs::jsval::StringValue(&*js_str));
8971 JS_DefineProperty(
8972 cx,
8973 err_obj.handle().into(),
8974 c"message".as_ptr(),
8975 msg_val.handle().into(),
8976 JSPROP_ENUMERATE as u32,
8977 );
8978 }
8979 }
8980 rooted!(&in(cx_ref) let err_val = mozjs::jsval::ObjectValue(err_obj.get()));
8981 rooted!(&in(cx_ref) let promise_rooted = promise);
8982 mozjs_sys::jsapi::JS::RejectPromise(
8983 cx,
8984 promise_rooted.handle().into(),
8985 err_val.handle().into(),
8986 );
8987}
8988
8989#[allow(unsafe_op_in_unsafe_fn)]
8990unsafe fn define_num_prop(cx: *mut JSContext, obj_ptr: *mut JSObject, name: &str, val: f64) {
8991 let c_name = ZBox::from_bytes(name.as_bytes());
8992 let mut wrapped_cx =
8993 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
8994 let cx_ref = &mut wrapped_cx;
8995 rooted!(&in(cx_ref) let obj = obj_ptr);
8996 let js_val = if val == (val as i32) as f64 && val.abs() < i32::MAX as f64 {
8997 mozjs::jsval::Int32Value(val as i32)
8998 } else {
8999 mozjs::jsval::DoubleValue(val)
9000 };
9001 rooted!(&in(cx_ref) let v = js_val);
9002 JS_DefineProperty(
9003 cx,
9004 obj.handle().into(),
9005 c_name.as_ptr(),
9006 v.handle().into(),
9007 JSPROP_ENUMERATE as u32,
9008 );
9009}
9010
9011#[allow(unsafe_op_in_unsafe_fn)]
9012unsafe fn define_bool_prop(cx: *mut JSContext, obj_ptr: *mut JSObject, name: &str, val: bool) {
9013 let c_name = ZBox::from_bytes(name.as_bytes());
9014 let mut wrapped_cx =
9015 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9016 let cx_ref = &mut wrapped_cx;
9017 rooted!(&in(cx_ref) let obj = obj_ptr);
9018 rooted!(&in(cx_ref) let v = mozjs::jsval::BooleanValue(val));
9019 JS_DefineProperty(
9020 cx,
9021 obj.handle().into(),
9022 c_name.as_ptr(),
9023 v.handle().into(),
9024 JSPROP_ENUMERATE as u32,
9025 );
9026}
9027
9028#[allow(unsafe_op_in_unsafe_fn)]
9029unsafe fn set_hidden_int(cx: *mut JSContext, obj: *mut JSObject, prop: &str, val: i32) {
9030 let c_name = ZBox::from_bytes(prop.as_bytes());
9031 let mut wrapped_cx =
9032 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9033 let cx_ref = &mut wrapped_cx;
9034 rooted!(&in(cx_ref) let obj_rooted = obj);
9035 rooted!(&in(cx_ref) let v = mozjs::jsval::Int32Value(val));
9036 JS_DefineProperty(
9037 cx,
9038 obj_rooted.handle().into(),
9039 c_name.as_ptr(),
9040 v.handle().into(),
9041 (JSPROP_ENUMERATE | JSPROP_PERMANENT) as u32,
9042 );
9043}
9044
9045#[allow(unsafe_op_in_unsafe_fn)]
9046unsafe fn set_hidden_bool(cx: *mut JSContext, obj: *mut JSObject, prop: &str, val: bool) {
9047 let c_name = ZBox::from_bytes(prop.as_bytes());
9048 let mut wrapped_cx =
9049 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9050 let cx_ref = &mut wrapped_cx;
9051 rooted!(&in(cx_ref) let obj_rooted = obj);
9052 rooted!(&in(cx_ref) let v = mozjs::jsval::BooleanValue(val));
9053 JS_DefineProperty(
9054 cx,
9055 obj_rooted.handle().into(),
9056 c_name.as_ptr(),
9057 v.handle().into(),
9058 (JSPROP_ENUMERATE | JSPROP_PERMANENT) as u32,
9059 );
9060}
9061
9062#[allow(unsafe_op_in_unsafe_fn)]
9063unsafe fn get_hidden_int(cx: *mut JSContext, obj: *mut JSObject, prop: &str) -> i32 {
9064 let c_name = ZBox::from_bytes(prop.as_bytes());
9065 let mut wrapped_cx =
9066 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9067 let cx_ref = &mut wrapped_cx;
9068 rooted!(&in(cx_ref) let obj_rooted = obj);
9069 let mut val = UndefinedValue();
9070 JS_GetProperty(
9071 cx,
9072 obj_rooted.handle().into(),
9073 c_name.as_ptr(),
9074 MutableHandle::<Value> {
9075 _phantom_0: ::std::marker::PhantomData,
9076 ptr: &mut val,
9077 },
9078 );
9079 if val.is_int32() { val.to_int32() } else { -1 }
9080}
9081
9082unsafe fn build_stats_object(cx: *mut JSContext, st: &libc::stat) -> *mut JSObject {
9084 let mut wrapped_cx =
9085 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9086 let cx_ref = &mut wrapped_cx;
9087 rooted!(&in(cx_ref) let stats = JS_NewPlainObject(cx));
9088 if stats.get().is_null() {
9089 return stats.get();
9090 }
9091
9092 let mode_type = st.st_mode & libc::S_IFMT;
9093 let is_file = mode_type == libc::S_IFREG;
9094 let is_dir = mode_type == libc::S_IFDIR;
9095 let is_symlink = mode_type == libc::S_IFLNK;
9096 let is_block_device = mode_type == libc::S_IFBLK;
9097 let is_character_device = mode_type == libc::S_IFCHR;
9098 let is_fifo = mode_type == libc::S_IFIFO;
9099 let is_socket = mode_type == libc::S_IFSOCK;
9100
9101 let atime_ms = st.st_atime as f64 * 1000.0 + st.st_atime_nsec as f64 / 1_000_000.0;
9102 let mtime_ms = st.st_mtime as f64 * 1000.0 + st.st_mtime_nsec as f64 / 1_000_000.0;
9103 let ctime_ms = st.st_ctime as f64 * 1000.0 + st.st_ctime_nsec as f64 / 1_000_000.0;
9104 let birthtime_ms = ctime_ms; define_num_prop(cx, stats.get(), "size", st.st_size as f64);
9107 define_num_prop(cx, stats.get(), "dev", st.st_dev as f64);
9108 define_num_prop(cx, stats.get(), "ino", st.st_ino as f64);
9109 define_num_prop(cx, stats.get(), "mode", st.st_mode as f64);
9110 define_num_prop(cx, stats.get(), "nlink", st.st_nlink as f64);
9111 define_num_prop(cx, stats.get(), "uid", st.st_uid as f64);
9112 define_num_prop(cx, stats.get(), "gid", st.st_gid as f64);
9113 define_num_prop(cx, stats.get(), "rdev", st.st_rdev as f64);
9114 define_num_prop(cx, stats.get(), "blksize", st.st_blksize as f64);
9115 define_num_prop(cx, stats.get(), "blocks", st.st_blocks as f64);
9116 define_num_prop(cx, stats.get(), "atimeMs", atime_ms);
9117 define_num_prop(cx, stats.get(), "mtimeMs", mtime_ms);
9118 define_num_prop(cx, stats.get(), "ctimeMs", ctime_ms);
9119 define_num_prop(cx, stats.get(), "birthtimeMs", birthtime_ms);
9120
9121 let date_props: [(&str, f64); 4] = [
9123 ("atime", atime_ms),
9124 ("mtime", mtime_ms),
9125 ("ctime", ctime_ms),
9126 ("birthtime", birthtime_ms),
9127 ];
9128 for (prop, ms) in &date_props {
9129 let date_obj = w2::NewDateObject(cx_ref, mozjs::jsapi::ClippedTime { t: *ms });
9130 if !date_obj.is_null() {
9131 rooted!(&in(cx_ref) let date_val = mozjs::jsval::ObjectValue(date_obj));
9132 let c_prop = ZBox::from_bytes(prop.as_bytes());
9133 JS_DefineProperty(
9134 cx,
9135 stats.handle().into(),
9136 c_prop.as_ptr(),
9137 date_val.handle().into(),
9138 JSPROP_ENUMERATE as u32,
9139 );
9140 }
9141 }
9142
9143 define_bool_prop(cx, stats.get(), "_isFile", is_file);
9144 define_bool_prop(cx, stats.get(), "_isDirectory", is_dir);
9145 define_bool_prop(cx, stats.get(), "_isSymbolicLink", is_symlink);
9146 define_bool_prop(cx, stats.get(), "_isBlockDevice", is_block_device);
9147 define_bool_prop(cx, stats.get(), "_isCharacterDevice", is_character_device);
9148 define_bool_prop(cx, stats.get(), "_isFIFO", is_fifo);
9149 define_bool_prop(cx, stats.get(), "_isSocket", is_socket);
9150
9151 w2::JS_DefineFunction(
9152 cx_ref,
9153 stats.handle().into(),
9154 c"isFile".as_ptr(),
9155 Some(stats_is_file),
9156 0,
9157 JSPROP_ENUMERATE as u32,
9158 );
9159 w2::JS_DefineFunction(
9160 cx_ref,
9161 stats.handle().into(),
9162 c"isDirectory".as_ptr(),
9163 Some(stats_is_directory),
9164 0,
9165 JSPROP_ENUMERATE as u32,
9166 );
9167 w2::JS_DefineFunction(
9168 cx_ref,
9169 stats.handle().into(),
9170 c"isSymbolicLink".as_ptr(),
9171 Some(stats_is_symlink),
9172 0,
9173 JSPROP_ENUMERATE as u32,
9174 );
9175 w2::JS_DefineFunction(
9176 cx_ref,
9177 stats.handle().into(),
9178 c"isBlockDevice".as_ptr(),
9179 Some(stats_is_block_device),
9180 0,
9181 JSPROP_ENUMERATE as u32,
9182 );
9183 w2::JS_DefineFunction(
9184 cx_ref,
9185 stats.handle().into(),
9186 c"isCharacterDevice".as_ptr(),
9187 Some(stats_is_character_device),
9188 0,
9189 JSPROP_ENUMERATE as u32,
9190 );
9191 w2::JS_DefineFunction(
9192 cx_ref,
9193 stats.handle().into(),
9194 c"isFIFO".as_ptr(),
9195 Some(stats_is_fifo),
9196 0,
9197 JSPROP_ENUMERATE as u32,
9198 );
9199 w2::JS_DefineFunction(
9200 cx_ref,
9201 stats.handle().into(),
9202 c"isSocket".as_ptr(),
9203 Some(stats_is_socket),
9204 0,
9205 JSPROP_ENUMERATE as u32,
9206 );
9207
9208 stats.get()
9209}
9210
9211#[allow(unsafe_op_in_unsafe_fn)]
9212unsafe fn get_hidden_bool(cx: *mut JSContext, obj: *mut JSObject, prop: &str) -> bool {
9213 let c_name = ZBox::from_bytes(prop.as_bytes());
9214 let mut wrapped_cx =
9215 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9216 let cx_ref = &mut wrapped_cx;
9217 rooted!(&in(cx_ref) let obj_rooted = obj);
9218 let mut val = UndefinedValue();
9219 JS_GetProperty(
9220 cx,
9221 obj_rooted.handle().into(),
9222 c_name.as_ptr(),
9223 MutableHandle::<Value> {
9224 _phantom_0: ::std::marker::PhantomData,
9225 ptr: &mut val,
9226 },
9227 );
9228 val.to_boolean()
9229}
9230
9231#[allow(unsafe_op_in_unsafe_fn)]
9232unsafe extern "C" fn stats_is_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
9233 let args = CallArgs::from_vp(vp, argc);
9234 let mut wrapped_cx =
9235 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9236 let cx_ref = &mut wrapped_cx;
9237 rooted!(&in(cx_ref) let this = args.thisv().to_object());
9238 args.rval().set(mozjs::jsval::BooleanValue(get_hidden_bool(
9239 cx,
9240 this.get(),
9241 "_isFile",
9242 )));
9243 true
9244}
9245
9246#[allow(unsafe_op_in_unsafe_fn)]
9247unsafe extern "C" fn stats_is_directory(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
9248 let args = CallArgs::from_vp(vp, argc);
9249 let mut wrapped_cx =
9250 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9251 let cx_ref = &mut wrapped_cx;
9252 rooted!(&in(cx_ref) let this = args.thisv().to_object());
9253 args.rval().set(mozjs::jsval::BooleanValue(get_hidden_bool(
9254 cx,
9255 this.get(),
9256 "_isDirectory",
9257 )));
9258 true
9259}
9260unsafe fn create_filehandle_object(cx: *mut JSContext, fd: i32) -> *mut JSObject {
9270 let mut wrapped_cx =
9271 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9272 let cx_ref = &mut wrapped_cx;
9273 rooted!(&in(cx_ref) let fh = mozjs_sys::jsapi::JS_NewPlainObject(cx));
9274 if fh.get().is_null() {
9275 return ::std::ptr::null_mut();
9276 }
9277
9278 set_hidden_int(cx, fh.get(), "_fd", fd);
9279 set_hidden_int(cx, fh.get(), "_refs", 1);
9280 set_hidden_bool(cx, fh.get(), "_closed", false);
9281
9282 rooted!(&in(cx_ref) let fd_val = mozjs::jsval::Int32Value(fd));
9283 JS_DefineProperty(
9284 cx,
9285 fh.handle().into(),
9286 c"fd".as_ptr(),
9287 fd_val.handle().into(),
9288 (JSPROP_ENUMERATE | JSPROP_READONLY) as u32,
9289 );
9290 JS_DefineFunction(
9291 cx,
9292 fh.handle().into(),
9293 c"read".as_ptr(),
9294 Some(fh_read),
9295 4,
9296 JSPROP_ENUMERATE as u32,
9297 );
9298 JS_DefineFunction(
9299 cx,
9300 fh.handle().into(),
9301 c"write".as_ptr(),
9302 Some(fh_write),
9303 4,
9304 JSPROP_ENUMERATE as u32,
9305 );
9306 JS_DefineFunction(
9307 cx,
9308 fh.handle().into(),
9309 c"close".as_ptr(),
9310 Some(fh_close),
9311 0,
9312 JSPROP_ENUMERATE as u32,
9313 );
9314 JS_DefineFunction(
9315 cx,
9316 fh.handle().into(),
9317 c"stat".as_ptr(),
9318 Some(fh_stat),
9319 0,
9320 JSPROP_ENUMERATE as u32,
9321 );
9322 JS_DefineFunction(
9323 cx,
9324 fh.handle().into(),
9325 c"chmod".as_ptr(),
9326 Some(fh_chmod),
9327 1,
9328 JSPROP_ENUMERATE as u32,
9329 );
9330 JS_DefineFunction(
9331 cx,
9332 fh.handle().into(),
9333 c"chown".as_ptr(),
9334 Some(fh_chown),
9335 2,
9336 JSPROP_ENUMERATE as u32,
9337 );
9338 JS_DefineFunction(
9339 cx,
9340 fh.handle().into(),
9341 c"datasync".as_ptr(),
9342 Some(fh_datasync),
9343 0,
9344 JSPROP_ENUMERATE as u32,
9345 );
9346 JS_DefineFunction(
9347 cx,
9348 fh.handle().into(),
9349 c"sync".as_ptr(),
9350 Some(fh_sync),
9351 0,
9352 JSPROP_ENUMERATE as u32,
9353 );
9354 JS_DefineFunction(
9355 cx,
9356 fh.handle().into(),
9357 c"truncate".as_ptr(),
9358 Some(fh_truncate),
9359 1,
9360 JSPROP_ENUMERATE as u32,
9361 );
9362 JS_DefineFunction(
9363 cx,
9364 fh.handle().into(),
9365 c"utimes".as_ptr(),
9366 Some(fh_utimes),
9367 2,
9368 JSPROP_ENUMERATE as u32,
9369 );
9370 JS_DefineFunction(
9371 cx,
9372 fh.handle().into(),
9373 c"appendFile".as_ptr(),
9374 Some(fh_append_file),
9375 1,
9376 JSPROP_ENUMERATE as u32,
9377 );
9378 JS_DefineFunction(
9379 cx,
9380 fh.handle().into(),
9381 c"readFile".as_ptr(),
9382 Some(fh_read_file),
9383 0,
9384 JSPROP_ENUMERATE as u32,
9385 );
9386 JS_DefineFunction(
9387 cx,
9388 fh.handle().into(),
9389 c"writeFile".as_ptr(),
9390 Some(fh_write_file),
9391 1,
9392 JSPROP_ENUMERATE as u32,
9393 );
9394
9395 fh.get()
9396}
9397
9398#[allow(unsafe_op_in_unsafe_fn)]
9400unsafe extern "C" fn fs_promises_filehandle_ctor(
9401 cx: *mut JSContext,
9402 argc: u32,
9403 vp: *mut JSVal,
9404) -> bool {
9405 let args = CallArgs::from_vp(vp, argc);
9406 let fd_val = if argc > 0 {
9407 *args.get(0).ptr
9408 } else {
9409 UndefinedValue()
9410 };
9411 let fd = if fd_val.is_int32() {
9412 fd_val.to_int32()
9413 } else {
9414 -1
9415 };
9416 if fd < 0 {
9417 JS_ReportErrorUTF8(cx, c"FileHandle requires a valid file descriptor".as_ptr());
9418 args.rval().set(UndefinedValue());
9419 return false;
9420 }
9421 let fh = create_filehandle_object(cx, fd);
9422 if fh.is_null() {
9423 args.rval().set(UndefinedValue());
9424 return false;
9425 }
9426 args.rval().set(mozjs::jsval::ObjectValue(fh));
9427 true
9428}
9429
9430#[allow(unsafe_op_in_unsafe_fn)]
9431unsafe extern "C" fn fh_read(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
9432 let args = CallArgs::from_vp(vp, argc);
9433 let this = args.thisv();
9434 if !this.is_object() {
9435 JS_ReportErrorUTF8(
9436 cx,
9437 c"FileHandle.read() must be called on a FileHandle instance".as_ptr(),
9438 );
9439 args.rval().set(UndefinedValue());
9440 return false;
9441 }
9442 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9443 let mut wrapped_cx =
9444 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9445 let cx_ref = &mut wrapped_cx;
9446 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9447 if promise.get().is_null() {
9448 args.rval().set(UndefinedValue());
9449 return false;
9450 }
9451
9452 if fd < 0 {
9453 reject_with_error(
9454 cx,
9455 promise.get(),
9456 "FileHandle: fd is invalid (already closed)",
9457 );
9458 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9459 return true;
9460 }
9461
9462 let length = if argc > 2 {
9463 let v = *args.get(2).ptr;
9464 if v.is_int32() {
9465 v.to_int32() as usize
9466 } else {
9467 65536
9468 }
9469 } else {
9470 65536
9471 };
9472 let position = if argc > 3 {
9473 let v = *args.get(3).ptr;
9474 if v.is_int32() {
9475 v.to_int32() as i64
9476 } else if v.is_double() {
9477 v.to_double() as i64
9478 } else {
9479 -1
9480 }
9481 } else {
9482 -1
9483 };
9484
9485 let mut buf = vec![0u8; length];
9486 #[cfg(unix)]
9487 {
9488 let bytes_read = if position >= 0 {
9489 unsafe {
9490 libc::lseek(fd, position, libc::SEEK_SET);
9491 }
9492 unsafe { libc::read(fd, buf.as_mut_ptr() as *mut ::std::ffi::c_void, length) }
9493 } else {
9494 unsafe { libc::read(fd, buf.as_mut_ptr() as *mut ::std::ffi::c_void, length) }
9495 };
9496 if bytes_read >= 0 {
9497 buf.truncate(bytes_read as usize);
9498 let buf_obj = crate::globals::create_buffer_object(cx, &buf);
9499 if !buf_obj.is_null() {
9500 rooted!(&in(cx_ref) let result_obj = mozjs_sys::jsapi::JS_NewPlainObject(cx));
9501 if !result_obj.get().is_null() {
9502 rooted!(&in(cx_ref) let br_val = mozjs::jsval::DoubleValue(bytes_read as f64));
9503 JS_DefineProperty(
9504 cx,
9505 result_obj.handle().into(),
9506 c"bytesRead".as_ptr(),
9507 br_val.handle().into(),
9508 JSPROP_ENUMERATE as u32,
9509 );
9510 rooted!(&in(cx_ref) let buf_val = mozjs::jsval::ObjectValue(buf_obj));
9511 JS_DefineProperty(
9512 cx,
9513 result_obj.handle().into(),
9514 c"buffer".as_ptr(),
9515 buf_val.handle().into(),
9516 JSPROP_ENUMERATE as u32,
9517 );
9518 rooted!(&in(cx_ref) let result_val = mozjs::jsval::ObjectValue(result_obj.get()));
9519 unsafe {
9520 mozjs_sys::jsapi::JS::ResolvePromise(
9521 cx,
9522 promise.handle().into(),
9523 result_val.handle().into(),
9524 );
9525 }
9526 } else {
9527 resolve_undefined(cx, promise.get());
9528 }
9529 } else {
9530 resolve_undefined(cx, promise.get());
9531 }
9532 } else {
9533 reject_with_error(
9534 cx,
9535 promise.get(),
9536 &format!("FileHandle.read: {}", ::std::io::Error::last_os_error()),
9537 );
9538 }
9539 }
9540 #[cfg(not(unix))]
9541 {
9542 resolve_undefined(cx, promise.get());
9543 }
9544 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9545 true
9546}
9547
9548#[allow(unsafe_op_in_unsafe_fn)]
9549unsafe extern "C" fn fh_write(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
9550 let args = CallArgs::from_vp(vp, argc);
9551 let this = args.thisv();
9552 if !this.is_object() {
9553 JS_ReportErrorUTF8(
9554 cx,
9555 c"FileHandle.write() must be called on a FileHandle instance".as_ptr(),
9556 );
9557 args.rval().set(UndefinedValue());
9558 return false;
9559 }
9560 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9561 let mut wrapped_cx =
9562 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9563 let cx_ref = &mut wrapped_cx;
9564 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9565 if promise.get().is_null() {
9566 args.rval().set(UndefinedValue());
9567 return false;
9568 }
9569
9570 if fd < 0 {
9571 reject_with_error(
9572 cx,
9573 promise.get(),
9574 "FileHandle: fd is invalid (already closed)",
9575 );
9576 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9577 return true;
9578 }
9579
9580 let data = if argc > 0 && (*args.get(0).ptr).is_object() {
9581 crate::node_crypto::extract_buffer_bytes(cx, *args.get(0).ptr)
9582 } else if argc > 0 && (*args.get(0).ptr).is_string() {
9583 let s = (*args.get(0).ptr).to_string();
9584 if !s.is_null() {
9585 crate::jsstr_to_rust_string(cx, s).into_bytes()
9586 } else {
9587 Vec::new()
9588 }
9589 } else {
9590 Vec::new()
9591 };
9592
9593 let position = if argc > 3 {
9594 let v = *args.get(3).ptr;
9595 if v.is_int32() {
9596 v.to_int32() as i64
9597 } else if v.is_double() {
9598 v.to_double() as i64
9599 } else {
9600 -1
9601 }
9602 } else {
9603 -1
9604 };
9605
9606 #[cfg(unix)]
9607 {
9608 let bytes_written = if position >= 0 {
9609 unsafe {
9610 libc::lseek(fd, position, libc::SEEK_SET);
9611 }
9612 unsafe { libc::write(fd, data.as_ptr() as *const ::std::ffi::c_void, data.len()) }
9613 } else {
9614 unsafe { libc::write(fd, data.as_ptr() as *const ::std::ffi::c_void, data.len()) }
9615 };
9616 if bytes_written >= 0 {
9617 rooted!(&in(cx_ref) let result_obj = mozjs_sys::jsapi::JS_NewPlainObject(cx));
9618 if !result_obj.get().is_null() {
9619 rooted!(&in(cx_ref) let bw_val = mozjs::jsval::DoubleValue(bytes_written as f64));
9620 JS_DefineProperty(
9621 cx,
9622 result_obj.handle().into(),
9623 c"bytesWritten".as_ptr(),
9624 bw_val.handle().into(),
9625 JSPROP_ENUMERATE as u32,
9626 );
9627 let buf_obj = crate::globals::create_buffer_object(cx, &data);
9628 if !buf_obj.is_null() {
9629 rooted!(&in(cx_ref) let buf_val = mozjs::jsval::ObjectValue(buf_obj));
9630 JS_DefineProperty(
9631 cx,
9632 result_obj.handle().into(),
9633 c"buffer".as_ptr(),
9634 buf_val.handle().into(),
9635 JSPROP_ENUMERATE as u32,
9636 );
9637 }
9638 unsafe {
9639 rooted!(&in(cx_ref) let result_val = mozjs::jsval::ObjectValue(result_obj.get()));
9640 mozjs_sys::jsapi::JS::ResolvePromise(
9641 cx,
9642 promise.handle().into(),
9643 result_val.handle().into(),
9644 );
9645 }
9646 } else {
9647 resolve_undefined(cx, promise.get());
9648 }
9649 } else {
9650 reject_with_error(
9651 cx,
9652 promise.get(),
9653 &format!("FileHandle.write: {}", ::std::io::Error::last_os_error()),
9654 );
9655 }
9656 }
9657 #[cfg(not(unix))]
9658 {
9659 resolve_undefined(cx, promise.get());
9660 }
9661 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9662 true
9663}
9664
9665#[allow(unsafe_op_in_unsafe_fn)]
9666unsafe extern "C" fn fh_close(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
9667 let args = CallArgs::from_vp(vp, _argc);
9668 let this = args.thisv();
9669 if !this.is_object() {
9670 args.rval().set(UndefinedValue());
9671 return false;
9672 }
9673 let fh_obj = this.to_object();
9674 let fd = get_hidden_int(cx, fh_obj, "_fd");
9675 let closed = get_hidden_bool(cx, fh_obj, "_closed");
9676 let mut wrapped_cx =
9677 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9678 let cx_ref = &mut wrapped_cx;
9679 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9680 if promise.get().is_null() {
9681 args.rval().set(UndefinedValue());
9682 return false;
9683 }
9684 if closed || fd < 0 {
9685 resolve_undefined(cx, promise.get());
9686 } else {
9687 #[cfg(unix)]
9688 {
9689 let ret = unsafe { libc::close(fd) };
9690 if ret == 0 {
9691 set_hidden_bool(cx, fh_obj, "_closed", true);
9692 set_hidden_int(cx, fh_obj, "_fd", -1);
9693 resolve_undefined(cx, promise.get());
9694 } else {
9695 reject_with_error(
9696 cx,
9697 promise.get(),
9698 &format!("FileHandle.close: {}", ::std::io::Error::last_os_error()),
9699 );
9700 }
9701 }
9702 #[cfg(not(unix))]
9703 {
9704 set_hidden_bool(cx, fh_obj, "_closed", true);
9705 set_hidden_int(cx, fh_obj, "_fd", -1);
9706 resolve_undefined(cx, promise.get());
9707 }
9708 }
9709 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9710 true
9711}
9712
9713#[allow(unsafe_op_in_unsafe_fn)]
9714unsafe extern "C" fn fh_stat(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
9715 let args = CallArgs::from_vp(vp, _argc);
9716 let this = args.thisv();
9717 if !this.is_object() {
9718 args.rval().set(UndefinedValue());
9719 return false;
9720 }
9721 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9722 let mut wrapped_cx =
9723 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9724 let cx_ref = &mut wrapped_cx;
9725 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9726 if promise.get().is_null() {
9727 args.rval().set(UndefinedValue());
9728 return false;
9729 }
9730 #[cfg(unix)]
9731 {
9732 let mut st: libc::stat = unsafe { ::std::mem::zeroed() };
9733 let ret = unsafe { libc::fstat(fd, &mut st) };
9734 if ret == 0 {
9735 let stats_obj = build_stats_object(cx, &st);
9736 if !stats_obj.is_null() {
9737 rooted!(&in(cx_ref) let stats_val = mozjs::jsval::ObjectValue(stats_obj));
9738 unsafe {
9739 mozjs_sys::jsapi::JS::ResolvePromise(
9740 cx,
9741 promise.handle().into(),
9742 stats_val.handle().into(),
9743 );
9744 }
9745 } else {
9746 resolve_undefined(cx, promise.get());
9747 }
9748 } else {
9749 reject_with_error(
9750 cx,
9751 promise.get(),
9752 &format!("FileHandle.stat: {}", ::std::io::Error::last_os_error()),
9753 );
9754 }
9755 }
9756 #[cfg(not(unix))]
9757 {
9758 resolve_undefined(cx, promise.get());
9759 }
9760 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9761 true
9762}
9763
9764#[allow(unsafe_op_in_unsafe_fn)]
9765unsafe extern "C" fn fh_chmod(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
9766 let args = CallArgs::from_vp(vp, argc);
9767 let this = args.thisv();
9768 if !this.is_object() {
9769 args.rval().set(UndefinedValue());
9770 return false;
9771 }
9772 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9773 let mode = if argc > 0 {
9774 let v = *args.get(0).ptr;
9775 if v.is_int32() {
9776 v.to_int32() as u32
9777 } else if v.is_double() {
9778 v.to_double() as u32
9779 } else {
9780 0o644
9781 }
9782 } else {
9783 0o644
9784 };
9785 let mut wrapped_cx =
9786 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9787 let cx_ref = &mut wrapped_cx;
9788 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9789 if promise.get().is_null() {
9790 args.rval().set(UndefinedValue());
9791 return false;
9792 }
9793 #[cfg(unix)]
9794 {
9795 let ret = unsafe { libc::fchmod(fd, mode) };
9796 if ret == 0 {
9797 resolve_undefined(cx, promise.get());
9798 } else {
9799 reject_with_error(
9800 cx,
9801 promise.get(),
9802 &format!("FileHandle.chmod: {}", ::std::io::Error::last_os_error()),
9803 );
9804 }
9805 }
9806 #[cfg(not(unix))]
9807 {
9808 resolve_undefined(cx, promise.get());
9809 }
9810 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9811 true
9812}
9813
9814#[allow(unsafe_op_in_unsafe_fn)]
9815unsafe extern "C" fn fh_chown(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
9816 let args = CallArgs::from_vp(vp, argc);
9817 let this = args.thisv();
9818 if !this.is_object() {
9819 args.rval().set(UndefinedValue());
9820 return false;
9821 }
9822 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9823 let uid = if argc > 0 {
9824 let v = *args.get(0).ptr;
9825 if v.is_int32() { v.to_int32() } else { -1 }
9826 } else {
9827 -1
9828 };
9829 let gid = if argc > 1 {
9830 let v = *args.get(1).ptr;
9831 if v.is_int32() { v.to_int32() } else { -1 }
9832 } else {
9833 -1
9834 };
9835 let mut wrapped_cx =
9836 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9837 let cx_ref = &mut wrapped_cx;
9838 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9839 if promise.get().is_null() {
9840 args.rval().set(UndefinedValue());
9841 return false;
9842 }
9843 #[cfg(unix)]
9844 {
9845 let ret = unsafe { libc::fchown(fd, uid as u32, gid as u32) };
9846 if ret == 0 {
9847 resolve_undefined(cx, promise.get());
9848 } else {
9849 reject_with_error(
9850 cx,
9851 promise.get(),
9852 &format!("FileHandle.chown: {}", ::std::io::Error::last_os_error()),
9853 );
9854 }
9855 }
9856 #[cfg(not(unix))]
9857 {
9858 resolve_undefined(cx, promise.get());
9859 }
9860 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9861 true
9862}
9863
9864#[allow(unsafe_op_in_unsafe_fn)]
9865unsafe extern "C" fn fh_datasync(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
9866 let args = CallArgs::from_vp(vp, _argc);
9867 let this = args.thisv();
9868 if !this.is_object() {
9869 args.rval().set(UndefinedValue());
9870 return false;
9871 }
9872 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9873 let mut wrapped_cx =
9874 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9875 let cx_ref = &mut wrapped_cx;
9876 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9877 if promise.get().is_null() {
9878 args.rval().set(UndefinedValue());
9879 return false;
9880 }
9881 #[cfg(unix)]
9882 {
9883 let ret = unsafe { libc::fdatasync(fd) };
9884 if ret == 0 {
9885 resolve_undefined(cx, promise.get());
9886 } else {
9887 reject_with_error(
9888 cx,
9889 promise.get(),
9890 &format!("FileHandle.datasync: {}", ::std::io::Error::last_os_error()),
9891 );
9892 }
9893 }
9894 #[cfg(not(unix))]
9895 {
9896 resolve_undefined(cx, promise.get());
9897 }
9898 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9899 true
9900}
9901
9902#[allow(unsafe_op_in_unsafe_fn)]
9903unsafe extern "C" fn fh_sync(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
9904 let args = CallArgs::from_vp(vp, _argc);
9905 let this = args.thisv();
9906 if !this.is_object() {
9907 args.rval().set(UndefinedValue());
9908 return false;
9909 }
9910 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9911 let mut wrapped_cx =
9912 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9913 let cx_ref = &mut wrapped_cx;
9914 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9915 if promise.get().is_null() {
9916 args.rval().set(UndefinedValue());
9917 return false;
9918 }
9919 #[cfg(unix)]
9920 {
9921 let ret = unsafe { libc::fsync(fd) };
9922 if ret == 0 {
9923 resolve_undefined(cx, promise.get());
9924 } else {
9925 reject_with_error(
9926 cx,
9927 promise.get(),
9928 &format!("FileHandle.sync: {}", ::std::io::Error::last_os_error()),
9929 );
9930 }
9931 }
9932 #[cfg(not(unix))]
9933 {
9934 resolve_undefined(cx, promise.get());
9935 }
9936 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9937 true
9938}
9939
9940#[allow(unsafe_op_in_unsafe_fn)]
9941unsafe extern "C" fn fh_truncate(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
9942 let args = CallArgs::from_vp(vp, argc);
9943 let this = args.thisv();
9944 if !this.is_object() {
9945 args.rval().set(UndefinedValue());
9946 return false;
9947 }
9948 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9949 let len = if argc > 0 {
9950 let v = *args.get(0).ptr;
9951 if v.is_int32() {
9952 v.to_int32() as i64
9953 } else if v.is_double() {
9954 v.to_double() as i64
9955 } else {
9956 0
9957 }
9958 } else {
9959 0
9960 };
9961 let mut wrapped_cx =
9962 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
9963 let cx_ref = &mut wrapped_cx;
9964 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
9965 if promise.get().is_null() {
9966 args.rval().set(UndefinedValue());
9967 return false;
9968 }
9969 #[cfg(unix)]
9970 {
9971 let ret = unsafe { libc::ftruncate(fd, len) };
9972 if ret == 0 {
9973 resolve_undefined(cx, promise.get());
9974 } else {
9975 reject_with_error(
9976 cx,
9977 promise.get(),
9978 &format!("FileHandle.truncate: {}", ::std::io::Error::last_os_error()),
9979 );
9980 }
9981 }
9982 #[cfg(not(unix))]
9983 {
9984 resolve_undefined(cx, promise.get());
9985 }
9986 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
9987 true
9988}
9989
9990#[allow(unsafe_op_in_unsafe_fn)]
9991unsafe extern "C" fn fh_utimes(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
9992 let args = CallArgs::from_vp(vp, argc);
9993 let this = args.thisv();
9994 if !this.is_object() {
9995 args.rval().set(UndefinedValue());
9996 return false;
9997 }
9998 let fd = get_hidden_int(cx, this.to_object(), "_fd");
9999 let atime = if argc > 0 {
10000 let v = *args.get(0).ptr;
10001 if v.is_double() {
10002 v.to_double()
10003 } else if v.is_int32() {
10004 v.to_int32() as f64
10005 } else {
10006 0.0
10007 }
10008 } else {
10009 0.0
10010 };
10011 let mtime = if argc > 1 {
10012 let v = *args.get(1).ptr;
10013 if v.is_double() {
10014 v.to_double()
10015 } else if v.is_int32() {
10016 v.to_int32() as f64
10017 } else {
10018 0.0
10019 }
10020 } else {
10021 0.0
10022 };
10023 let mut wrapped_cx =
10024 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10025 let cx_ref = &mut wrapped_cx;
10026 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
10027 if promise.get().is_null() {
10028 args.rval().set(UndefinedValue());
10029 return false;
10030 }
10031 #[cfg(unix)]
10032 {
10033 let tv = [
10034 libc::timeval {
10035 tv_sec: atime as i64,
10036 tv_usec: 0,
10037 },
10038 libc::timeval {
10039 tv_sec: mtime as i64,
10040 tv_usec: 0,
10041 },
10042 ];
10043 let ret = unsafe { libc::futimes(fd, tv.as_ptr()) };
10044 if ret == 0 {
10045 resolve_undefined(cx, promise.get());
10046 } else {
10047 reject_with_error(
10048 cx,
10049 promise.get(),
10050 &format!("FileHandle.utimes: {}", ::std::io::Error::last_os_error()),
10051 );
10052 }
10053 }
10054 #[cfg(not(unix))]
10055 {
10056 resolve_undefined(cx, promise.get());
10057 }
10058 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
10059 true
10060}
10061
10062#[allow(unsafe_op_in_unsafe_fn)]
10063unsafe extern "C" fn fh_append_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10064 let args = CallArgs::from_vp(vp, argc);
10065 let this = args.thisv();
10066 if !this.is_object() {
10067 args.rval().set(UndefinedValue());
10068 return false;
10069 }
10070 let fd = get_hidden_int(cx, this.to_object(), "_fd");
10071 let data = if argc > 0 && (*args.get(0).ptr).is_object() {
10072 crate::node_crypto::extract_buffer_bytes(cx, *args.get(0).ptr)
10073 } else if argc > 0 && (*args.get(0).ptr).is_string() {
10074 let s = (*args.get(0).ptr).to_string();
10075 if !s.is_null() {
10076 crate::jsstr_to_rust_string(cx, s).into_bytes()
10077 } else {
10078 Vec::new()
10079 }
10080 } else {
10081 Vec::new()
10082 };
10083 let mut wrapped_cx =
10084 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10085 let cx_ref = &mut wrapped_cx;
10086 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
10087 if promise.get().is_null() {
10088 args.rval().set(UndefinedValue());
10089 return false;
10090 }
10091 #[cfg(unix)]
10092 {
10093 let ret =
10094 unsafe { libc::write(fd, data.as_ptr() as *const ::std::ffi::c_void, data.len()) };
10095 if ret >= 0 {
10096 resolve_undefined(cx, promise.get());
10097 } else {
10098 reject_with_error(
10099 cx,
10100 promise.get(),
10101 &format!(
10102 "FileHandle.appendFile: {}",
10103 ::std::io::Error::last_os_error()
10104 ),
10105 );
10106 }
10107 }
10108 #[cfg(not(unix))]
10109 {
10110 resolve_undefined(cx, promise.get());
10111 }
10112 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
10113 true
10114}
10115
10116#[allow(unsafe_op_in_unsafe_fn)]
10117unsafe extern "C" fn fh_read_file(cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
10118 let args = CallArgs::from_vp(vp, _argc);
10119 let this = args.thisv();
10120 if !this.is_object() {
10121 args.rval().set(UndefinedValue());
10122 return false;
10123 }
10124 let fd = get_hidden_int(cx, this.to_object(), "_fd");
10125 let mut wrapped_cx =
10126 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10127 let cx_ref = &mut wrapped_cx;
10128 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
10129 if promise.get().is_null() {
10130 args.rval().set(UndefinedValue());
10131 return false;
10132 }
10133 #[cfg(unix)]
10134 {
10135 let file_size = unsafe { libc::lseek(fd, 0, libc::SEEK_END) };
10136 if file_size < 0 {
10137 reject_with_error(
10138 cx,
10139 promise.get(),
10140 &format!("FileHandle.readFile: {}", ::std::io::Error::last_os_error()),
10141 );
10142 } else {
10143 unsafe {
10144 libc::lseek(fd, 0, libc::SEEK_SET);
10145 }
10146 let mut buf = vec![0u8; file_size as usize];
10147 let bytes_read = unsafe {
10148 libc::read(
10149 fd,
10150 buf.as_mut_ptr() as *mut ::std::ffi::c_void,
10151 file_size as usize,
10152 )
10153 };
10154 if bytes_read >= 0 {
10155 buf.truncate(bytes_read as usize);
10156 let buf_obj = crate::globals::create_buffer_object(cx, &buf);
10157 if !buf_obj.is_null() {
10158 rooted!(&in(cx_ref) let buf_val = mozjs::jsval::ObjectValue(buf_obj));
10159 unsafe {
10160 mozjs_sys::jsapi::JS::ResolvePromise(
10161 cx,
10162 promise.handle().into(),
10163 buf_val.handle().into(),
10164 );
10165 }
10166 } else {
10167 resolve_undefined(cx, promise.get());
10168 }
10169 } else {
10170 reject_with_error(
10171 cx,
10172 promise.get(),
10173 &format!("FileHandle.readFile: {}", ::std::io::Error::last_os_error()),
10174 );
10175 }
10176 }
10177 }
10178 #[cfg(not(unix))]
10179 {
10180 resolve_undefined(cx, promise.get());
10181 }
10182 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
10183 true
10184}
10185
10186#[allow(unsafe_op_in_unsafe_fn)]
10187unsafe extern "C" fn fh_write_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10188 let args = CallArgs::from_vp(vp, argc);
10189 let this = args.thisv();
10190 if !this.is_object() {
10191 args.rval().set(UndefinedValue());
10192 return false;
10193 }
10194 let fd = get_hidden_int(cx, this.to_object(), "_fd");
10195 let data = if argc > 0 && (*args.get(0).ptr).is_object() {
10196 crate::node_crypto::extract_buffer_bytes(cx, *args.get(0).ptr)
10197 } else if argc > 0 && (*args.get(0).ptr).is_string() {
10198 let s = (*args.get(0).ptr).to_string();
10199 if !s.is_null() {
10200 crate::jsstr_to_rust_string(cx, s).into_bytes()
10201 } else {
10202 Vec::new()
10203 }
10204 } else {
10205 Vec::new()
10206 };
10207 let mut wrapped_cx =
10208 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10209 let cx_ref = &mut wrapped_cx;
10210 rooted!(&in(cx_ref) let promise = mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()));
10211 if promise.get().is_null() {
10212 args.rval().set(UndefinedValue());
10213 return false;
10214 }
10215 #[cfg(unix)]
10216 {
10217 let ret =
10218 unsafe { libc::write(fd, data.as_ptr() as *const ::std::ffi::c_void, data.len()) };
10219 if ret >= 0 {
10220 resolve_undefined(cx, promise.get());
10221 } else {
10222 reject_with_error(
10223 cx,
10224 promise.get(),
10225 &format!(
10226 "FileHandle.writeFile: {}",
10227 ::std::io::Error::last_os_error()
10228 ),
10229 );
10230 }
10231 }
10232 #[cfg(not(unix))]
10233 {
10234 resolve_undefined(cx, promise.get());
10235 }
10236 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
10237 true
10238}
10239
10240#[allow(unsafe_op_in_unsafe_fn)]
10243unsafe extern "C" fn stats_is_block_device(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10244 let args = CallArgs::from_vp(vp, argc);
10245 let mut wrapped_cx =
10246 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10247 let cx_ref = &mut wrapped_cx;
10248 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10249 args.rval().set(mozjs::jsval::BooleanValue(get_hidden_bool(
10250 cx,
10251 this.get(),
10252 "_isBlockDevice",
10253 )));
10254 true
10255}
10256
10257#[allow(unsafe_op_in_unsafe_fn)]
10258unsafe extern "C" fn stats_is_character_device(
10259 cx: *mut JSContext,
10260 argc: u32,
10261 vp: *mut JSVal,
10262) -> bool {
10263 let args = CallArgs::from_vp(vp, argc);
10264 let mut wrapped_cx =
10265 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10266 let cx_ref = &mut wrapped_cx;
10267 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10268 args.rval().set(mozjs::jsval::BooleanValue(get_hidden_bool(
10269 cx,
10270 this.get(),
10271 "_isCharacterDevice",
10272 )));
10273 true
10274}
10275
10276#[allow(unsafe_op_in_unsafe_fn)]
10277unsafe extern "C" fn stats_is_fifo(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10278 let args = CallArgs::from_vp(vp, argc);
10279 let mut wrapped_cx =
10280 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10281 let cx_ref = &mut wrapped_cx;
10282 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10283 args.rval().set(mozjs::jsval::BooleanValue(get_hidden_bool(
10284 cx,
10285 this.get(),
10286 "_isFIFO",
10287 )));
10288 true
10289}
10290
10291#[allow(unsafe_op_in_unsafe_fn)]
10292unsafe extern "C" fn stats_is_socket(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10293 let args = CallArgs::from_vp(vp, argc);
10294 let mut wrapped_cx =
10295 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10296 let cx_ref = &mut wrapped_cx;
10297 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10298 args.rval().set(mozjs::jsval::BooleanValue(get_hidden_bool(
10299 cx,
10300 this.get(),
10301 "_isSocket",
10302 )));
10303 true
10304}
10305
10306#[allow(unsafe_op_in_unsafe_fn)]
10307unsafe extern "C" fn stats_is_symlink(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10308 let args = CallArgs::from_vp(vp, argc);
10309 let mut wrapped_cx =
10310 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10311 let cx_ref = &mut wrapped_cx;
10312 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10313 args.rval().set(mozjs::jsval::BooleanValue(get_hidden_bool(
10314 cx,
10315 this.get(),
10316 "_isSymbolicLink",
10317 )));
10318 true
10319}
10320
10321#[allow(unsafe_op_in_unsafe_fn)]
10324unsafe extern "C" fn dirent_is_file(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10325 let args = CallArgs::from_vp(vp, argc);
10326 let mut wrapped_cx =
10327 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10328 let cx_ref = &mut wrapped_cx;
10329 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10330 let type_code = get_hidden_int(cx, this.get(), "_typeCode");
10331 args.rval().set(mozjs::jsval::BooleanValue(type_code == 0));
10332 true
10333}
10334
10335#[allow(unsafe_op_in_unsafe_fn)]
10336unsafe extern "C" fn dirent_is_directory(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10337 let args = CallArgs::from_vp(vp, argc);
10338 let mut wrapped_cx =
10339 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10340 let cx_ref = &mut wrapped_cx;
10341 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10342 let type_code = get_hidden_int(cx, this.get(), "_typeCode");
10343 args.rval().set(mozjs::jsval::BooleanValue(type_code == 1));
10344 true
10345}
10346
10347#[allow(unsafe_op_in_unsafe_fn)]
10348unsafe extern "C" fn dirent_is_symbolic_link(
10349 cx: *mut JSContext,
10350 argc: u32,
10351 vp: *mut JSVal,
10352) -> bool {
10353 let args = CallArgs::from_vp(vp, argc);
10354 let mut wrapped_cx =
10355 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10356 let cx_ref = &mut wrapped_cx;
10357 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10358 let type_code = get_hidden_int(cx, this.get(), "_typeCode");
10359 args.rval().set(mozjs::jsval::BooleanValue(type_code == 2));
10360 true
10361}
10362
10363macro_rules! dirent_type_method {
10364 ($fn_name:ident) => {
10365 #[allow(unsafe_op_in_unsafe_fn)]
10366 unsafe extern "C" fn $fn_name(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
10367 let args = CallArgs::from_vp(vp, _argc);
10368 args.rval().set(mozjs::jsval::BooleanValue(false));
10369 true
10370 }
10371 };
10372}
10373dirent_type_method!(dirent_is_block_device);
10374dirent_type_method!(dirent_is_character_device);
10375dirent_type_method!(dirent_is_fifo);
10376dirent_type_method!(dirent_is_socket);
10377
10378#[allow(unsafe_op_in_unsafe_fn)]
10381unsafe fn create_statfs_object(cx: *mut JSContext, sf: &StatfsResult) -> *mut JSObject {
10382 let mut wrapped_cx =
10383 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10384 let cx_ref = &mut wrapped_cx;
10385 rooted!(&in(cx_ref) let obj = JS_NewPlainObject(cx));
10386 if obj.get().is_null() {
10387 return obj.get();
10388 }
10389 define_num_prop(cx, obj.get(), "type", sf.type_ as f64);
10390 define_num_prop(cx, obj.get(), "bsize", sf.bsize as f64);
10391 define_num_prop(cx, obj.get(), "blocks", sf.blocks as f64);
10392 define_num_prop(cx, obj.get(), "bfree", sf.bfree as f64);
10393 define_num_prop(cx, obj.get(), "bavail", sf.bavail as f64);
10394 define_num_prop(cx, obj.get(), "files", sf.files as f64);
10395 define_num_prop(cx, obj.get(), "ffree", sf.ffree as f64);
10396 obj.get()
10397}
10398
10399#[allow(unsafe_op_in_unsafe_fn)]
10412unsafe fn create_dir_object(cx: *mut JSContext, dir_path: &str) -> *mut JSObject {
10413 let mut wrapped_cx =
10414 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10415 let cx_ref = &mut wrapped_cx;
10416 rooted!(&in(cx_ref) let dir = JS_NewPlainObject(cx));
10417 if dir.get().is_null() {
10418 return dir.get();
10419 }
10420
10421 let c_path = ZBox::from_bytes(dir_path.as_bytes());
10423 let path_str = JS_NewStringCopyZ(cx, c_path.as_ptr());
10424 if !path_str.is_null() {
10425 rooted!(&in(cx_ref) let path_val = mozjs::jsval::StringValue(&*path_str));
10426 JS_DefineProperty(
10427 cx,
10428 dir.handle().into(),
10429 c"path".as_ptr(),
10430 path_val.handle().into(),
10431 JSPROP_ENUMERATE as u32,
10432 );
10433 }
10434
10435 let c_dp = ZBox::from_bytes(dir_path.as_bytes());
10437 let dp_str = JS_NewStringCopyZ(cx, c_dp.as_ptr());
10438 if !dp_str.is_null() {
10439 rooted!(&in(cx_ref) let dp_val = mozjs::jsval::StringValue(&*dp_str));
10440 JS_DefineProperty(
10441 cx,
10442 dir.handle().into(),
10443 c"_dirPath".as_ptr(),
10444 dp_val.handle().into(),
10445 0,
10446 );
10447 }
10448
10449 set_hidden_int(cx, dir.get(), "_entriesIndex", 0);
10451 set_hidden_bool(cx, dir.get(), "_closed", false);
10453
10454 JS_DefineFunction(
10456 cx,
10457 dir.handle().into(),
10458 c"readSync".as_ptr(),
10459 Some(dir_read_sync),
10460 0,
10461 JSPROP_ENUMERATE as u32,
10462 );
10463 JS_DefineFunction(
10464 cx,
10465 dir.handle().into(),
10466 c"read".as_ptr(),
10467 Some(dir_read),
10468 1,
10469 JSPROP_ENUMERATE as u32,
10470 );
10471 JS_DefineFunction(
10472 cx,
10473 dir.handle().into(),
10474 c"closeSync".as_ptr(),
10475 Some(dir_close_sync),
10476 0,
10477 JSPROP_ENUMERATE as u32,
10478 );
10479 JS_DefineFunction(
10480 cx,
10481 dir.handle().into(),
10482 c"close".as_ptr(),
10483 Some(dir_close),
10484 1,
10485 JSPROP_ENUMERATE as u32,
10486 );
10487 JS_DefineFunction(
10488 cx,
10489 dir.handle().into(),
10490 c"\x5B\x5D".as_ptr(),
10491 Some(dir_symbol_iterator),
10492 0,
10493 0,
10494 );
10495
10496 dir.get()
10497}
10498
10499#[allow(unsafe_op_in_unsafe_fn)]
10500unsafe fn dir_ensure_entries(cx: *mut JSContext, dir_obj: *mut JSObject) {
10501 let mut wrapped_cx =
10503 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10504 let cx_ref = &mut wrapped_cx;
10505 rooted!(&in(cx_ref) let dir_rooted = dir_obj);
10506 let mut entries_val = UndefinedValue();
10507 JS_GetProperty(
10508 cx,
10509 dir_rooted.handle().into(),
10510 c"_entries".as_ptr(),
10511 MutableHandle::<Value> {
10512 _phantom_0: ::std::marker::PhantomData,
10513 ptr: &mut entries_val,
10514 },
10515 );
10516 if !entries_val.is_undefined() {
10517 return;
10518 }
10519
10520 let dir_path = {
10522 let mut dp_val = UndefinedValue();
10523 JS_GetProperty(
10524 cx,
10525 dir_rooted.handle().into(),
10526 c"_dirPath".as_ptr(),
10527 MutableHandle::<Value> {
10528 _phantom_0: ::std::marker::PhantomData,
10529 ptr: &mut dp_val,
10530 },
10531 );
10532 if dp_val.is_string() {
10533 crate::jsstr_to_rust_string(cx, dp_val.to_string())
10534 } else {
10535 return;
10536 }
10537 };
10538
10539 match fs::read_dir(&dir_path) {
10540 Ok(raw_entries) => {
10541 let entries: Vec<(String, bool)> = raw_entries
10542 .flatten()
10543 .map(|e| {
10544 let name = e.file_name().to_string_lossy().into_owned();
10545 let is_dir = e.file_type().map(|ft| ft.is_dir()).unwrap_or(false);
10546 (name, is_dir)
10547 })
10548 .collect();
10549
10550 rooted!(&in(cx_ref) let arr = w2::NewArrayObject1(cx_ref, entries.len()));
10551 if !arr.get().is_null() {
10552 for (idx, (name, is_dir)) in entries.iter().enumerate() {
10553 let dirent = create_dirent(cx, name, *is_dir);
10554 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(dirent));
10555 JS_DefineElement(
10556 cx,
10557 arr.handle().into(),
10558 idx as u32,
10559 val.handle().into(),
10560 JSPROP_ENUMERATE as u32,
10561 );
10562 }
10563 }
10564 rooted!(&in(cx_ref) let arr_val = mozjs::jsval::ObjectValue(arr.get()));
10565 JS_DefineProperty(
10566 cx,
10567 dir_rooted.handle().into(),
10568 c"_entries".as_ptr(),
10569 arr_val.handle().into(),
10570 0,
10571 );
10572 }
10573 Err(_) => {
10574 rooted!(&in(cx_ref) let arr = w2::NewArrayObject1(cx_ref, 0));
10576 rooted!(&in(cx_ref) let arr_val = mozjs::jsval::ObjectValue(arr.get()));
10577 JS_DefineProperty(
10578 cx,
10579 dir_rooted.handle().into(),
10580 c"_entries".as_ptr(),
10581 arr_val.handle().into(),
10582 0,
10583 );
10584 }
10585 }
10586}
10587
10588#[allow(unsafe_op_in_unsafe_fn)]
10589unsafe extern "C" fn dir_read_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10590 let args = CallArgs::from_vp(vp, argc);
10591 let mut wrapped_cx =
10592 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10593 let cx_ref = &mut wrapped_cx;
10594 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10595
10596 let closed = get_hidden_bool(cx, this.get(), "_closed");
10597 if closed {
10598 let c_msg = ZBox::from_bytes("Dir is already closed".as_bytes());
10599 JS_ReportErrorUTF8(cx, c"%s".as_ptr(), c_msg.as_ptr());
10600 return false;
10601 }
10602
10603 dir_ensure_entries(cx, this.get());
10604
10605 let idx = get_hidden_int(cx, this.get(), "_entriesIndex") as u32;
10606
10607 let mut entries_val = UndefinedValue();
10608 JS_GetProperty(
10609 cx,
10610 this.handle().into(),
10611 c"_entries".as_ptr(),
10612 MutableHandle::<Value> {
10613 _phantom_0: ::std::marker::PhantomData,
10614 ptr: &mut entries_val,
10615 },
10616 );
10617 if entries_val.is_object() {
10618 let entries_obj = entries_val.to_object();
10619 rooted!(&in(cx_ref) let eo = entries_obj);
10620 let mut len_val = UndefinedValue();
10621 JS_GetProperty(
10622 cx,
10623 eo.handle().into(),
10624 c"length".as_ptr(),
10625 MutableHandle::<Value> {
10626 _phantom_0: ::std::marker::PhantomData,
10627 ptr: &mut len_val,
10628 },
10629 );
10630 let len = if len_val.is_int32() {
10631 len_val.to_int32() as u32
10632 } else {
10633 0
10634 };
10635
10636 if idx < len {
10637 let mut elem = UndefinedValue();
10638 JS_GetElement(
10639 cx,
10640 eo.handle().into(),
10641 idx,
10642 MutableHandle::<Value> {
10643 _phantom_0: ::std::marker::PhantomData,
10644 ptr: &mut elem,
10645 },
10646 );
10647 args.rval().set(elem);
10648 set_hidden_int(cx, this.get(), "_entriesIndex", (idx + 1) as i32);
10649 } else {
10650 args.rval().set(mozjs::jsval::NullValue());
10651 }
10652 } else {
10653 args.rval().set(mozjs::jsval::NullValue());
10654 }
10655 true
10656}
10657
10658#[allow(unsafe_op_in_unsafe_fn)]
10659unsafe extern "C" fn dir_read(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10660 let args = CallArgs::from_vp(vp, argc);
10661 let mut wrapped_cx =
10662 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10663 let cx_ref = &mut wrapped_cx;
10664
10665 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10666
10667 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 0) {
10668 let closed = get_hidden_bool(cx, this.get(), "_closed");
10670 if closed {
10671 rooted!(&in(cx_ref) let err_obj = JS_NewPlainObject(cx));
10672 if !err_obj.get().is_null() {
10673 let c_msg = ZBox::from_bytes("Dir is already closed".as_bytes());
10674 let msg_str = JS_NewStringCopyZ(cx, c_msg.as_ptr());
10675 if !msg_str.is_null() {
10676 rooted!(&in(cx_ref) let msg_val = mozjs::jsval::StringValue(&*msg_str));
10677 JS_DefineProperty(
10678 cx,
10679 err_obj.handle().into(),
10680 c"message".as_ptr(),
10681 msg_val.handle().into(),
10682 JSPROP_ENUMERATE as u32,
10683 );
10684 }
10685 }
10686 rooted!(&in(cx_ref) let err_val = mozjs::jsval::ObjectValue(err_obj.get()));
10687 let err_args = HandleValueArray {
10688 length_: 1,
10689 elements_: &err_val.get() as *const JSVal,
10690 };
10691 let global = CurrentGlobalOrNull(cx);
10692 if !global.is_null() {
10693 rooted!(&in(cx_ref) let global_rooted = global);
10694 rooted!(&in(cx_ref) let cb = callback);
10695 rooted!(&in(cx_ref) let cb_val = mozjs::jsval::ObjectValue(cb.get()));
10696 let mut rval = UndefinedValue();
10697 JS_CallFunctionValue(
10698 cx,
10699 global_rooted.handle().into(),
10700 cb_val.handle().into(),
10701 &err_args,
10702 MutableHandle::<Value> {
10703 _phantom_0: ::std::marker::PhantomData,
10704 ptr: &mut rval,
10705 },
10706 );
10707 JS_ClearPendingException(cx);
10708 }
10709 args.rval().set(UndefinedValue());
10710 return true;
10711 }
10712
10713 dir_ensure_entries(cx, this.get());
10714 let idx = get_hidden_int(cx, this.get(), "_entriesIndex") as u32;
10715 let mut entries_val = UndefinedValue();
10716 JS_GetProperty(
10717 cx,
10718 this.handle().into(),
10719 c"_entries".as_ptr(),
10720 MutableHandle::<Value> {
10721 _phantom_0: ::std::marker::PhantomData,
10722 ptr: &mut entries_val,
10723 },
10724 );
10725
10726 let next_val = if entries_val.is_object() {
10727 let entries_obj = entries_val.to_object();
10728 rooted!(&in(cx_ref) let eo = entries_obj);
10729 let mut len_val = UndefinedValue();
10730 JS_GetProperty(
10731 cx,
10732 eo.handle().into(),
10733 c"length".as_ptr(),
10734 MutableHandle::<Value> {
10735 _phantom_0: ::std::marker::PhantomData,
10736 ptr: &mut len_val,
10737 },
10738 );
10739 let len = if len_val.is_int32() {
10740 len_val.to_int32() as u32
10741 } else {
10742 0
10743 };
10744 if idx < len {
10745 let mut elem = UndefinedValue();
10746 JS_GetElement(
10747 cx,
10748 eo.handle().into(),
10749 idx,
10750 MutableHandle::<Value> {
10751 _phantom_0: ::std::marker::PhantomData,
10752 ptr: &mut elem,
10753 },
10754 );
10755 set_hidden_int(cx, this.get(), "_entriesIndex", (idx + 1) as i32);
10756 elem
10757 } else {
10758 mozjs::jsval::NullValue()
10759 }
10760 } else {
10761 mozjs::jsval::NullValue()
10762 };
10763
10764 rooted!(&in(cx_ref) let next_rooted = next_val);
10765 rooted!(&in(cx_ref) let cb = callback);
10766 rooted!(&in(cx_ref) let cb_val = mozjs::jsval::ObjectValue(cb.get()));
10767 let args_arr = [UndefinedValue(), next_rooted.get()];
10768 let cb_args = HandleValueArray {
10769 length_: 2,
10770 elements_: args_arr.as_ptr(),
10771 };
10772 let global = CurrentGlobalOrNull(cx);
10773 if !global.is_null() {
10774 rooted!(&in(cx_ref) let global_rooted = global);
10775 let mut rval = UndefinedValue();
10776 JS_CallFunctionValue(
10777 cx,
10778 global_rooted.handle().into(),
10779 cb_val.handle().into(),
10780 &cb_args,
10781 MutableHandle::<Value> {
10782 _phantom_0: ::std::marker::PhantomData,
10783 ptr: &mut rval,
10784 },
10785 );
10786 JS_ClearPendingException(cx);
10787 }
10788 args.rval().set(UndefinedValue());
10789 return true;
10790 }
10791
10792 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
10794 if promise.get().is_null() {
10795 args.rval().set(UndefinedValue());
10796 return false;
10797 }
10798
10799 let closed = get_hidden_bool(cx, this.get(), "_closed");
10800 if closed {
10801 reject_with_error(cx, promise.get(), "Dir is already closed");
10802 } else {
10803 dir_ensure_entries(cx, this.get());
10804 let idx = get_hidden_int(cx, this.get(), "_entriesIndex") as u32;
10805 let mut entries_val = UndefinedValue();
10806 JS_GetProperty(
10807 cx,
10808 this.handle().into(),
10809 c"_entries".as_ptr(),
10810 MutableHandle::<Value> {
10811 _phantom_0: ::std::marker::PhantomData,
10812 ptr: &mut entries_val,
10813 },
10814 );
10815
10816 let next_val = if entries_val.is_object() {
10817 let entries_obj = entries_val.to_object();
10818 rooted!(&in(cx_ref) let eo = entries_obj);
10819 let mut len_val = UndefinedValue();
10820 JS_GetProperty(
10821 cx,
10822 eo.handle().into(),
10823 c"length".as_ptr(),
10824 MutableHandle::<Value> {
10825 _phantom_0: ::std::marker::PhantomData,
10826 ptr: &mut len_val,
10827 },
10828 );
10829 let len = if len_val.is_int32() {
10830 len_val.to_int32() as u32
10831 } else {
10832 0
10833 };
10834 if idx < len {
10835 let mut elem = UndefinedValue();
10836 JS_GetElement(
10837 cx,
10838 eo.handle().into(),
10839 idx,
10840 MutableHandle::<Value> {
10841 _phantom_0: ::std::marker::PhantomData,
10842 ptr: &mut elem,
10843 },
10844 );
10845 set_hidden_int(cx, this.get(), "_entriesIndex", (idx + 1) as i32);
10846 elem
10847 } else {
10848 mozjs::jsval::NullValue()
10849 }
10850 } else {
10851 mozjs::jsval::NullValue()
10852 };
10853
10854 rooted!(&in(cx_ref) let val = next_val);
10855 unsafe {
10856 mozjs_sys::jsapi::JS::ResolvePromise(cx, promise.handle().into(), val.handle().into());
10857 }
10858 }
10859 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
10860 true
10861}
10862
10863#[allow(unsafe_op_in_unsafe_fn)]
10864unsafe extern "C" fn dir_close_sync(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10865 let args = CallArgs::from_vp(vp, argc);
10866 let mut wrapped_cx =
10867 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10868 let cx_ref = &mut wrapped_cx;
10869 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10870 set_hidden_bool(cx, this.get(), "_closed", true);
10871 args.rval().set(UndefinedValue());
10872 true
10873}
10874
10875#[allow(unsafe_op_in_unsafe_fn)]
10876unsafe extern "C" fn dir_close(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10877 let args = CallArgs::from_vp(vp, argc);
10878 let mut wrapped_cx =
10879 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10880 let cx_ref = &mut wrapped_cx;
10881 rooted!(&in(cx_ref) let this = args.thisv().to_object());
10882 set_hidden_bool(cx, this.get(), "_closed", true);
10883
10884 if let Some((callback, _)) = extract_callback_and_encoding(cx, &args, 0) {
10885 rooted!(&in(cx_ref) let cb = callback);
10886 rooted!(&in(cx_ref) let cb_val = mozjs::jsval::ObjectValue(cb.get()));
10887 let null_args = HandleValueArray::empty();
10888 let global = CurrentGlobalOrNull(cx);
10889 if !global.is_null() {
10890 rooted!(&in(cx_ref) let global_rooted = global);
10891 let mut rval = UndefinedValue();
10892 JS_CallFunctionValue(
10893 cx,
10894 global_rooted.handle().into(),
10895 cb_val.handle().into(),
10896 &null_args,
10897 MutableHandle::<Value> {
10898 _phantom_0: ::std::marker::PhantomData,
10899 ptr: &mut rval,
10900 },
10901 );
10902 JS_ClearPendingException(cx);
10903 }
10904 args.rval().set(UndefinedValue());
10905 return true;
10906 }
10907
10908 args.rval().set(UndefinedValue());
10909 true
10910}
10911
10912#[allow(unsafe_op_in_unsafe_fn)]
10913unsafe extern "C" fn dir_symbol_iterator(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10914 let args = CallArgs::from_vp(vp, argc);
10916 let mut wrapped_cx =
10917 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10918 let cx_ref = &mut wrapped_cx;
10919 rooted!(&in(cx_ref) let iter = JS_NewPlainObject(cx));
10920 if iter.get().is_null() {
10921 args.rval().set(UndefinedValue());
10922 return true;
10923 }
10924
10925 let this_val = args.thisv();
10927 if this_val.is_object() {
10928 rooted!(&in(cx_ref) let dir_ref = this_val.to_object());
10929 rooted!(&in(cx_ref) let dir_ref_val = mozjs::jsval::ObjectValue(dir_ref.get()));
10930 JS_DefineProperty(
10931 cx,
10932 iter.handle().into(),
10933 c"_dirRef".as_ptr(),
10934 dir_ref_val.handle().into(),
10935 0,
10936 );
10937 }
10938
10939 JS_DefineFunction(
10940 cx,
10941 iter.handle().into(),
10942 c"next".as_ptr(),
10943 Some(dir_iterator_next),
10944 0,
10945 JSPROP_ENUMERATE as u32,
10946 );
10947 args.rval().set(mozjs::jsval::ObjectValue(iter.get()));
10948 true
10949}
10950
10951#[allow(unsafe_op_in_unsafe_fn)]
10952unsafe extern "C" fn dir_iterator_next(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
10953 let args = CallArgs::from_vp(vp, argc);
10954 let mut wrapped_cx =
10955 mozjs::context::JSContext::from_ptr(::std::ptr::NonNull::new_unchecked(cx));
10956 let cx_ref = &mut wrapped_cx;
10957
10958 rooted!(&in(cx_ref) let promise = unsafe { mozjs_sys::jsapi::JS::NewPromiseObject(cx, HandleObject::null()) });
10959 if promise.get().is_null() {
10960 args.rval().set(UndefinedValue());
10961 return false;
10962 }
10963
10964 let this_val = args.thisv();
10966 if !this_val.is_object() {
10967 reject_with_error(
10968 cx,
10969 promise.get(),
10970 "Dir iterator next() called on wrong object",
10971 );
10972 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
10973 return true;
10974 }
10975 let iter_obj = this_val.to_object();
10976 rooted!(&in(cx_ref) let iter_rooted = iter_obj);
10977 let mut dir_ref_val = UndefinedValue();
10978 JS_GetProperty(
10979 cx,
10980 iter_rooted.handle().into(),
10981 c"_dirRef".as_ptr(),
10982 MutableHandle::<Value> {
10983 _phantom_0: ::std::marker::PhantomData,
10984 ptr: &mut dir_ref_val,
10985 },
10986 );
10987
10988 if !dir_ref_val.is_object() {
10989 rooted!(&in(cx_ref) let result_obj = JS_NewPlainObject(cx));
10991 if !result_obj.get().is_null() {
10992 define_bool_prop(cx, result_obj.get(), "done", true);
10993 }
10994 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(result_obj.get()));
10995 unsafe {
10996 mozjs_sys::jsapi::JS::ResolvePromise(cx, promise.handle().into(), val.handle().into());
10997 }
10998 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
10999 return true;
11000 }
11001
11002 let dir_obj = dir_ref_val.to_object();
11003 let closed = get_hidden_bool(cx, dir_obj, "_closed");
11004 if closed {
11005 rooted!(&in(cx_ref) let result_obj = JS_NewPlainObject(cx));
11006 if !result_obj.get().is_null() {
11007 define_bool_prop(cx, result_obj.get(), "done", true);
11008 }
11009 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(result_obj.get()));
11010 unsafe {
11011 mozjs_sys::jsapi::JS::ResolvePromise(cx, promise.handle().into(), val.handle().into());
11012 }
11013 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
11014 return true;
11015 }
11016
11017 dir_ensure_entries(cx, dir_obj);
11018 let idx = get_hidden_int(cx, dir_obj, "_entriesIndex") as u32;
11019
11020 rooted!(&in(cx_ref) let dir_rooted = dir_obj);
11021 let mut entries_val = UndefinedValue();
11022 JS_GetProperty(
11023 cx,
11024 dir_rooted.handle().into(),
11025 c"_entries".as_ptr(),
11026 MutableHandle::<Value> {
11027 _phantom_0: ::std::marker::PhantomData,
11028 ptr: &mut entries_val,
11029 },
11030 );
11031
11032 let next_dirent = if entries_val.is_object() {
11033 let entries_arr = entries_val.to_object();
11034 rooted!(&in(cx_ref) let ea = entries_arr);
11035 let mut len_val = UndefinedValue();
11036 JS_GetProperty(
11037 cx,
11038 ea.handle().into(),
11039 c"length".as_ptr(),
11040 MutableHandle::<Value> {
11041 _phantom_0: ::std::marker::PhantomData,
11042 ptr: &mut len_val,
11043 },
11044 );
11045 let len = if len_val.is_int32() {
11046 len_val.to_int32() as u32
11047 } else {
11048 0
11049 };
11050 if idx < len {
11051 let mut elem = UndefinedValue();
11052 JS_GetElement(
11053 cx,
11054 ea.handle().into(),
11055 idx,
11056 MutableHandle::<Value> {
11057 _phantom_0: ::std::marker::PhantomData,
11058 ptr: &mut elem,
11059 },
11060 );
11061 set_hidden_int(cx, dir_obj, "_entriesIndex", (idx + 1) as i32);
11062 elem
11063 } else {
11064 mozjs::jsval::NullValue()
11065 }
11066 } else {
11067 mozjs::jsval::NullValue()
11068 };
11069
11070 rooted!(&in(cx_ref) let result_obj = JS_NewPlainObject(cx));
11071 if !result_obj.get().is_null() {
11072 if next_dirent.is_null() {
11073 define_bool_prop(cx, result_obj.get(), "done", true);
11074 } else {
11075 define_bool_prop(cx, result_obj.get(), "done", false);
11076 rooted!(&in(cx_ref) let dv = next_dirent);
11077 JS_DefineProperty(
11078 cx,
11079 result_obj.handle().into(),
11080 c"value".as_ptr(),
11081 dv.handle().into(),
11082 JSPROP_ENUMERATE as u32,
11083 );
11084 }
11085 }
11086 rooted!(&in(cx_ref) let val = mozjs::jsval::ObjectValue(result_obj.get()));
11087 unsafe {
11088 mozjs_sys::jsapi::JS::ResolvePromise(cx, promise.handle().into(), val.handle().into());
11089 }
11090 args.rval().set(mozjs::jsval::ObjectValue(promise.get()));
11091 true
11092}
11093
11094#[cfg(test)]
11095mod tests {
11096 use super::mkdtemp_inner;
11097
11098 #[test]
11101 fn mkdtemp_empty_prefix_returns_einval() {
11102 let err = mkdtemp_inner("").expect_err("empty prefix must be rejected");
11103 assert_eq!(err.raw_os_error(), Some(libc::EINVAL));
11104 }
11105}