diff --git a/js/deno.ts b/js/deno.ts index 21766401b6..d121b3183a 100644 --- a/js/deno.ts +++ b/js/deno.ts @@ -6,6 +6,7 @@ export { exit, FileInfo, makeTempDirSync, + mkdirSync, readFileSync, statSync, lStatSync, diff --git a/js/os.ts b/js/os.ts index e669aea9d0..cca1218740 100644 --- a/js/os.ts +++ b/js/os.ts @@ -104,6 +104,25 @@ export function makeTempDirSync({ return path!; } +// mkdir creates a new directory with the specified name +// and permission bits (before umask). +export function mkdirSync(path: string, mode = 0o777): void { + /* Ideally we could write: + const res = send({ + command: fbs.Command.MKDIR_SYNC, + mkdirSyncPath: path, + mkdirSyncMode: mode, + }); + */ + const builder = new flatbuffers.Builder(); + const path_ = builder.createString(path); + fbs.MkdirSync.startMkdirSync(builder); + fbs.MkdirSync.addPath(builder, path_); + fbs.MkdirSync.addMode(builder, mode); + const msg = fbs.MkdirSync.endMkdirSync(builder); + send(builder, fbs.Any.MkdirSync, msg); +} + export function readFileSync(filename: string): Uint8Array { /* Ideally we could write const res = send({ diff --git a/js/os_test.ts b/js/os_test.ts index cd5ede221d..8142956ebd 100644 --- a/js/os_test.ts +++ b/js/os_test.ts @@ -183,3 +183,24 @@ test(function makeTempDirSyncPerm() { assert(err); assertEqual(err.name, "deno.PermissionDenied"); }); + +testPerm({ write: true }, function mkdirSync() { + const path = deno.makeTempDirSync() + "/dir/subdir"; + deno.mkdirSync(path); + const pathInfo = deno.statSync(path); + assert(pathInfo.isDirectory()); +}); + +testPerm({ write: false }, function mkdDirSyncPerm() { + let err; + try { + const path = "/baddir"; + deno.mkdirSync(path); + } catch (err_) { + err = err_; + } + // TODO assert(err instanceof deno.PermissionDenied). + assert(err); + assertEqual(err.name, "deno.PermissionDenied"); +}); + diff --git a/src/handlers.rs b/src/handlers.rs index f583f24000..df77df26a3 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -38,6 +38,7 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) { msg::Any::TimerStart => handle_timer_start, msg::Any::TimerClear => handle_timer_clear, msg::Any::MakeTempDir => handle_make_temp_dir, + msg::Any::MkdirSync => handle_mkdir_sync, msg::Any::ReadFileSync => handle_read_file_sync, msg::Any::SetEnv => handle_set_env, msg::Any::StatSync => handle_stat_sync, @@ -488,6 +489,30 @@ fn handle_make_temp_dir( )) } +fn handle_mkdir_sync( + d: *const DenoC, + base: msg::Base, + _builder: &mut FlatBufferBuilder, +) -> HandlerResult { + let msg = base.msg_as_mkdir_sync().unwrap(); + let path = msg.path().unwrap(); + // TODO let mode = msg.mode(); + let deno = from_c(d); + + debug!("handle_mkdir_sync {}", path); + if deno.flags.allow_write { + // TODO(ry) Use mode. + deno_fs::mkdir(Path::new(path))?; + Ok(null_buf()) + } else { + let err = std::io::Error::new( + std::io::ErrorKind::PermissionDenied, + "allow_write is off.", + ); + Err(err.into()) + } +} + // Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184 fn handle_read_file_sync( _d: *const DenoC, diff --git a/src/msg.fbs b/src/msg.fbs index ca2e16af7a..ebb4077f7a 100644 --- a/src/msg.fbs +++ b/src/msg.fbs @@ -16,6 +16,7 @@ union Any { FetchRes, MakeTempDir, MakeTempDirRes, + MkdirSync, ReadFileSync, ReadFileSyncRes, StatSync, @@ -166,6 +167,12 @@ table MakeTempDirRes { path: string; } +table MkdirSync { + path: string; + mode: uint; + // mode specified by https://godoc.org/os#FileMode +} + table ReadFileSync { filename: string; }