summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/js/file_info.ts68
-rw-r--r--cli/js/lib.deno_runtime.d.ts31
-rw-r--r--cli/js/stat.ts12
-rw-r--r--cli/js/stat_test.ts50
-rw-r--r--cli/ops/fs.rs87
5 files changed, 204 insertions, 44 deletions
diff --git a/cli/js/file_info.ts b/cli/js/file_info.ts
index 2f08658c7..f0ab5bf6c 100644
--- a/cli/js/file_info.ts
+++ b/cli/js/file_info.ts
@@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { StatResponse } from "./stat.ts";
+import { build } from "./build.ts";
/** A FileInfo describes a file and is returned by `stat`, `lstat`,
* `statSync`, `lstatSync`.
@@ -22,13 +23,38 @@ export interface FileInfo {
* be available on all platforms.
*/
created: number | null;
+
+ /** The file or directory name. */
+ name: string | null;
+
+ /** ID of the device containing the file. Unix only. */
+ dev: number | null;
+
+ /** Inode number. Unix only. */
+ ino: number | null;
+
/** The underlying raw st_mode bits that contain the standard Unix permissions
* for this file/directory. TODO Match behavior with Go on windows for mode.
*/
mode: number | null;
- /** The file or directory name. */
- name: string | null;
+ /** Number of hard links pointing to this file. Unix only. */
+ nlink: number | null;
+
+ /** User ID of the owner of this file. Unix only. */
+ uid: number | null;
+
+ /** User ID of the owner of this file. Unix only. */
+ gid: number | null;
+
+ /** Device ID of this file. Unix only. */
+ rdev: number | null;
+
+ /** Blocksize for filesystem I/O. Unix only. */
+ blksize: number | null;
+
+ /** Number of blocks allocated to the file, in 512-byte units. Unix only. */
+ blocks: number | null;
/** Returns whether this is info for a regular file. This result is mutually
* exclusive to `FileInfo.isDirectory` and `FileInfo.isSymlink`.
@@ -54,17 +80,37 @@ export class FileInfoImpl implements FileInfo {
modified: number | null;
accessed: number | null;
created: number | null;
- mode: number | null;
name: string | null;
+ dev: number | null;
+ ino: number | null;
+ mode: number | null;
+ nlink: number | null;
+ uid: number | null;
+ gid: number | null;
+ rdev: number | null;
+ blksize: number | null;
+ blocks: number | null;
+
/* @internal */
constructor(private _res: StatResponse) {
+ const isUnix = build.os === "mac" || build.os === "linux";
const modified = this._res.modified;
const accessed = this._res.accessed;
const created = this._res.created;
- const hasMode = this._res.hasMode;
- const mode = this._res.mode; // negative for invalid mode (Windows)
const name = this._res.name;
+ // Unix only
+ const {
+ dev,
+ ino,
+ mode,
+ nlink,
+ uid,
+ gid,
+ rdev,
+ blksize,
+ blocks
+ } = this._res;
this._isFile = this._res.isFile;
this._isSymlink = this._res.isSymlink;
@@ -72,9 +118,17 @@ export class FileInfoImpl implements FileInfo {
this.modified = modified ? modified : null;
this.accessed = accessed ? accessed : null;
this.created = created ? created : null;
- // null on Windows
- this.mode = hasMode ? mode : null;
this.name = name ? name : null;
+ // Only non-null if on Unix
+ this.dev = isUnix ? dev : null;
+ this.ino = isUnix ? ino : null;
+ this.mode = isUnix ? mode : null;
+ this.nlink = isUnix ? nlink : null;
+ this.uid = isUnix ? uid : null;
+ this.gid = isUnix ? gid : null;
+ this.rdev = isUnix ? rdev : null;
+ this.blksize = isUnix ? blksize : null;
+ this.blocks = isUnix ? blocks : null;
}
isFile(): boolean {
diff --git a/cli/js/lib.deno_runtime.d.ts b/cli/js/lib.deno_runtime.d.ts
index f65c9650d..f95236af7 100644
--- a/cli/js/lib.deno_runtime.d.ts
+++ b/cli/js/lib.deno_runtime.d.ts
@@ -732,12 +732,28 @@ declare namespace Deno {
* be available on all platforms.
*/
created: number | null;
+ /** The file or directory name. */
+ name: string | null;
+ /** ID of the device containing the file. Unix only. */
+ dev: number | null;
+ /** Inode number. Unix only. */
+ ino: number | null;
/** The underlying raw st_mode bits that contain the standard Unix permissions
* for this file/directory. TODO Match behavior with Go on windows for mode.
*/
mode: number | null;
- /** The file or directory name. */
- name: string | null;
+ /** Number of hard links pointing to this file. Unix only. */
+ nlink: number | null;
+ /** User ID of the owner of this file. Unix only. */
+ uid: number | null;
+ /** User ID of the owner of this file. Unix only. */
+ gid: number | null;
+ /** Device ID of this file. Unix only. */
+ rdev: number | null;
+ /** Blocksize for filesystem I/O. Unix only. */
+ blksize: number | null;
+ /** Number of blocks allocated to the file, in 512-byte units. Unix only. */
+ blocks: number | null;
/** Returns whether this is info for a regular file. This result is mutually
* exclusive to `FileInfo.isDirectory` and `FileInfo.isSymlink`.
*/
@@ -827,9 +843,16 @@ declare namespace Deno {
modified: number;
accessed: number;
created: number;
- mode: number;
- hasMode: boolean;
name: string | null;
+ dev: number;
+ ino: number;
+ mode: number;
+ nlink: number;
+ uid: number;
+ gid: number;
+ rdev: number;
+ blksize: number;
+ blocks: number;
}
/** Queries the file system for information on the path provided. If the given
* path is a symlink information about the symlink will be returned.
diff --git a/cli/js/stat.ts b/cli/js/stat.ts
index 4a07eca21..b27170263 100644
--- a/cli/js/stat.ts
+++ b/cli/js/stat.ts
@@ -10,9 +10,17 @@ export interface StatResponse {
modified: number;
accessed: number;
created: number;
- mode: number;
- hasMode: boolean; // false on windows
name: string | null;
+ // Unix only members
+ dev: number;
+ ino: number;
+ mode: number;
+ nlink: number;
+ uid: number;
+ gid: number;
+ rdev: number;
+ blksize: number;
+ blocks: number;
}
/** Queries the file system for information on the path provided. If the given
diff --git a/cli/js/stat_test.ts b/cli/js/stat_test.ts
index 9e78888a3..7b4f06114 100644
--- a/cli/js/stat_test.ts
+++ b/cli/js/stat_test.ts
@@ -170,3 +170,53 @@ testPerm({ read: true }, async function lstatNotFound(): Promise<void> {
assert(caughtError);
assertEquals(badInfo, undefined);
});
+
+const isWindows = Deno.build.os === "win";
+
+// OS dependent tests
+if (isWindows) {
+ testPerm(
+ { read: true, write: true },
+ async function statNoUnixFields(): Promise<void> {
+ const enc = new TextEncoder();
+ const data = enc.encode("Hello");
+ const tempDir = Deno.makeTempDirSync();
+ const filename = tempDir + "/test.txt";
+ Deno.writeFileSync(filename, data, { perm: 0o666 });
+ const s = Deno.statSync(filename);
+ assert(s.dev === null);
+ assert(s.ino === null);
+ assert(s.mode === null);
+ assert(s.nlink === null);
+ assert(s.uid === null);
+ assert(s.gid === null);
+ assert(s.rdev === null);
+ assert(s.blksize === null);
+ assert(s.blocks === null);
+ }
+ );
+} else {
+ testPerm(
+ { read: true, write: true },
+ async function statUnixFields(): Promise<void> {
+ const enc = new TextEncoder();
+ const data = enc.encode("Hello");
+ const tempDir = Deno.makeTempDirSync();
+ const filename = tempDir + "/test.txt";
+ const filename2 = tempDir + "/test2.txt";
+ Deno.writeFileSync(filename, data, { perm: 0o666 });
+ // Create a link
+ Deno.linkSync(filename, filename2);
+ const s = Deno.statSync(filename);
+ assert(s.dev !== null);
+ assert(s.ino !== null);
+ assertEquals(s.mode & 0o666, 0o666);
+ assertEquals(s.nlink, 2);
+ assert(s.uid !== null);
+ assert(s.gid !== null);
+ assert(s.rdev !== null);
+ assert(s.blksize !== null);
+ assert(s.blocks !== null);
+ }
+ );
+}
diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs
index df15e2c88..c6830ddd2 100644
--- a/cli/ops/fs.rs
+++ b/cli/ops/fs.rs
@@ -14,6 +14,8 @@ use std::path::PathBuf;
use std::time::UNIX_EPOCH;
#[cfg(unix)]
+use std::os::unix::fs::MetadataExt;
+#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
pub fn init(i: &mut Isolate, s: &ThreadSafeState) {
@@ -226,14 +228,55 @@ macro_rules! to_seconds {
}};
}
-#[cfg(any(unix))]
-fn get_mode(perm: &fs::Permissions) -> u32 {
- perm.mode()
-}
+#[inline(always)]
+fn get_stat_json(
+ metadata: fs::Metadata,
+ maybe_name: Option<String>,
+) -> Result<Value, ErrBox> {
+ // Unix stat member (number types only). 0 if not on unix.
+ macro_rules! usm {
+ ($member: ident) => {{
+ #[cfg(unix)]
+ {
+ metadata.$member()
+ }
+ #[cfg(not(unix))]
+ {
+ 0
+ }
+ }};
+ }
-#[cfg(not(any(unix)))]
-fn get_mode(_perm: &fs::Permissions) -> u32 {
- 0
+ let mut json_val = json!({
+ "isFile": metadata.is_file(),
+ "isSymlink": metadata.file_type().is_symlink(),
+ "len": metadata.len(),
+ // In seconds. Available on both Unix or Windows.
+ "modified":to_seconds!(metadata.modified()),
+ "accessed":to_seconds!(metadata.accessed()),
+ "created":to_seconds!(metadata.created()),
+ // Following are only valid under Unix.
+ "dev": usm!(dev),
+ "ino": usm!(ino),
+ "mode": usm!(mode),
+ "nlink": usm!(nlink),
+ "uid": usm!(uid),
+ "gid": usm!(gid),
+ "rdev": usm!(rdev),
+ // TODO(kevinkassimo): *time_nsec requires BigInt.
+ // Probably should be treated as String if we need to add them.
+ "blksize": usm!(blksize),
+ "blocks": usm!(blocks),
+ });
+
+ // "name" is an optional field by our design.
+ if let Some(name) = maybe_name {
+ if let serde_json::Value::Object(ref mut m) = json_val {
+ m.insert("name".to_owned(), json!(name));
+ }
+ }
+
+ Ok(json_val)
}
#[derive(Deserialize)]
@@ -265,17 +308,7 @@ fn op_stat(
} else {
fs::metadata(&filename)?
};
-
- Ok(json!({
- "isFile": metadata.is_file(),
- "isSymlink": metadata.file_type().is_symlink(),
- "len": metadata.len(),
- "modified":to_seconds!(metadata.modified()),
- "accessed":to_seconds!(metadata.accessed()),
- "created":to_seconds!(metadata.created()),
- "mode": get_mode(&metadata.permissions()),
- "hasMode": cfg!(target_family = "unix"), // false on windows,
- }))
+ get_stat_json(metadata, None)
})
}
@@ -335,19 +368,11 @@ fn op_read_dir(
.map(|entry| {
let entry = entry.unwrap();
let metadata = entry.metadata().unwrap();
- let file_type = metadata.file_type();
-
- json!({
- "isFile": file_type.is_file(),
- "isSymlink": file_type.is_symlink(),
- "len": metadata.len(),
- "modified": to_seconds!(metadata.modified()),
- "accessed": to_seconds!(metadata.accessed()),
- "created": to_seconds!(metadata.created()),
- "mode": get_mode(&metadata.permissions()),
- "name": entry.file_name().to_str().unwrap(),
- "hasMode": cfg!(target_family = "unix"), // false on windows,
- })
+ get_stat_json(
+ metadata,
+ Some(entry.file_name().to_str().unwrap().to_owned()),
+ )
+ .unwrap()
})
.collect();