summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/deno.ts1
-rw-r--r--js/unit_tests.ts1
-rw-r--r--js/util.ts15
-rw-r--r--js/utime.ts52
-rw-r--r--js/utime_test.ts181
5 files changed, 250 insertions, 0 deletions
diff --git a/js/deno.ts b/js/deno.ts
index 46f018afc..0a923ef1d 100644
--- a/js/deno.ts
+++ b/js/deno.ts
@@ -46,6 +46,7 @@ export {
MakeTempDirOptions
} from "./make_temp_dir";
export { chmodSync, chmod } from "./chmod";
+export { utimeSync, utime } from "./utime";
export { removeSync, remove, RemoveOption } from "./remove";
export { renameSync, rename } from "./rename";
export { readFileSync, readFile } from "./read_file";
diff --git a/js/unit_tests.ts b/js/unit_tests.ts
index 4df3ae16e..3cef08e77 100644
--- a/js/unit_tests.ts
+++ b/js/unit_tests.ts
@@ -40,6 +40,7 @@ import "./timers_test.ts";
import "./truncate_test.ts";
import "./url_test.ts";
import "./url_search_params_test.ts";
+import "./utime_test.ts";
import "./write_file_test.ts";
import "./performance_test.ts";
import "./permissions_test.ts";
diff --git a/js/util.ts b/js/util.ts
index 033a2f754..a035d761a 100644
--- a/js/util.ts
+++ b/js/util.ts
@@ -192,3 +192,18 @@ export function hasOwnProperty<T>(obj: T, v: PropertyKey): boolean {
}
return Object.prototype.hasOwnProperty.call(obj, v);
}
+
+/**
+ * Split a number into two parts: lower 32 bit and higher 32 bit
+ * (as if the number is represented as uint64.)
+ *
+ * @param n Number to split.
+ * @internal
+ */
+export function splitNumberToParts(n: number): number[] {
+ // JS bitwise operators (OR, SHIFT) operate as if number is uint32.
+ const lower = n | 0;
+ // This is also faster than Math.floor(n / 0x100000000) in V8.
+ const higher = (n - lower) / 0x100000000;
+ return [lower, higher];
+}
diff --git a/js/utime.ts b/js/utime.ts
new file mode 100644
index 000000000..02c423d24
--- /dev/null
+++ b/js/utime.ts
@@ -0,0 +1,52 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+import * as msg from "gen/cli/msg_generated";
+import * as flatbuffers from "./flatbuffers";
+import * as dispatch from "./dispatch";
+import * as util from "./util";
+
+function req(
+ filename: string,
+ atime: number | Date,
+ mtime: number | Date
+): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
+ const atimeSec = atime instanceof Date ? Math.floor(+atime / 1000) : atime;
+ const mtimeSec = mtime instanceof Date ? Math.floor(+mtime / 1000) : mtime;
+
+ const builder = flatbuffers.createBuilder();
+ const filename_ = builder.createString(filename);
+ const atimeParts = util.splitNumberToParts(atimeSec);
+ const atimeMS_ = builder.createLong(atimeParts[0], atimeParts[1]);
+ const mtimeParts = util.splitNumberToParts(mtimeSec);
+ const mtimeMS_ = builder.createLong(mtimeParts[0], mtimeParts[1]);
+
+ const inner = msg.Utime.createUtime(builder, filename_, atimeMS_, mtimeMS_);
+ return [builder, msg.Any.Utime, inner];
+}
+
+/** Synchronously changes the access and modification times of a file system
+ * object referenced by `filename`. Given times are either in seconds
+ * (Unix epoch time) or as `Date` objects.
+ *
+ * Deno.utimeSync("myfile.txt", 1556495550, new Date());
+ */
+export function utimeSync(
+ filename: string,
+ atime: number | Date,
+ mtime: number | Date
+): void {
+ dispatch.sendSync(...req(filename, atime, mtime));
+}
+
+/** Changes the access and modification times of a file system object
+ * referenced by `filename`. Given times are either in seconds
+ * (Unix epoch time) or as `Date` objects.
+ *
+ * await Deno.utime("myfile.txt", 1556495550, new Date());
+ */
+export async function utime(
+ filename: string,
+ atime: number | Date,
+ mtime: number | Date
+): Promise<void> {
+ await dispatch.sendAsync(...req(filename, atime, mtime));
+}
diff --git a/js/utime_test.ts b/js/utime_test.ts
new file mode 100644
index 000000000..535ee1f40
--- /dev/null
+++ b/js/utime_test.ts
@@ -0,0 +1,181 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+import { testPerm, assert, assertEquals } from "./test_util.ts";
+
+// Allow 10 second difference.
+// Note this might not be enough for FAT (but we are not testing on such fs).
+function assertFuzzyTimestampEquals(t1: number, t2: number): void {
+ assert(Math.abs(t1 - t2) < 10);
+}
+
+testPerm({ read: true, write: true }, function utimeSyncFileSuccess(): void {
+ const testDir = Deno.makeTempDirSync();
+ const filename = testDir + "/file.txt";
+ Deno.writeFileSync(filename, new TextEncoder().encode("hello"), {
+ perm: 0o666
+ });
+
+ const atime = 1000;
+ const mtime = 50000;
+ Deno.utimeSync(filename, atime, mtime);
+
+ const fileInfo = Deno.statSync(filename);
+ assertFuzzyTimestampEquals(fileInfo.accessed, atime);
+ assertFuzzyTimestampEquals(fileInfo.modified, mtime);
+});
+
+testPerm(
+ { read: true, write: true },
+ function utimeSyncDirectorySuccess(): void {
+ const testDir = Deno.makeTempDirSync();
+
+ const atime = 1000;
+ const mtime = 50000;
+ Deno.utimeSync(testDir, atime, mtime);
+
+ const dirInfo = Deno.statSync(testDir);
+ assertFuzzyTimestampEquals(dirInfo.accessed, atime);
+ assertFuzzyTimestampEquals(dirInfo.modified, mtime);
+ }
+);
+
+testPerm({ read: true, write: true }, function utimeSyncDateSuccess(): void {
+ const testDir = Deno.makeTempDirSync();
+
+ const atime = 1000;
+ const mtime = 50000;
+ Deno.utimeSync(testDir, new Date(atime * 1000), new Date(mtime * 1000));
+
+ const dirInfo = Deno.statSync(testDir);
+ assertFuzzyTimestampEquals(dirInfo.accessed, atime);
+ assertFuzzyTimestampEquals(dirInfo.modified, mtime);
+});
+
+testPerm(
+ { read: true, write: true },
+ function utimeSyncLargeNumberSuccess(): void {
+ const testDir = Deno.makeTempDirSync();
+
+ // There are Rust side caps (might be fs relate),
+ // so JUST make them slightly larger than UINT32_MAX.
+ const atime = 0x100000001;
+ const mtime = 0x100000002;
+ Deno.utimeSync(testDir, atime, mtime);
+
+ const dirInfo = Deno.statSync(testDir);
+ assertFuzzyTimestampEquals(dirInfo.accessed, atime);
+ assertFuzzyTimestampEquals(dirInfo.modified, mtime);
+ }
+);
+
+testPerm({ read: true, write: true }, function utimeSyncNotFound(): void {
+ const atime = 1000;
+ const mtime = 50000;
+
+ let caughtError = false;
+ try {
+ Deno.utimeSync("/baddir", atime, mtime);
+ } catch (e) {
+ caughtError = true;
+ assertEquals(e.kind, Deno.ErrorKind.NotFound);
+ assertEquals(e.name, "NotFound");
+ }
+ assert(caughtError);
+});
+
+testPerm({ read: true, write: false }, function utimeSyncPerm(): void {
+ const atime = 1000;
+ const mtime = 50000;
+
+ let caughtError = false;
+ try {
+ Deno.utimeSync("/some_dir", atime, mtime);
+ } catch (e) {
+ caughtError = true;
+ assertEquals(e.kind, Deno.ErrorKind.PermissionDenied);
+ assertEquals(e.name, "PermissionDenied");
+ }
+ assert(caughtError);
+});
+
+testPerm(
+ { read: true, write: true },
+ async function utimeFileSuccess(): Promise<void> {
+ const testDir = Deno.makeTempDirSync();
+ const filename = testDir + "/file.txt";
+ Deno.writeFileSync(filename, new TextEncoder().encode("hello"), {
+ perm: 0o666
+ });
+
+ const atime = 1000;
+ const mtime = 50000;
+ await Deno.utime(filename, atime, mtime);
+
+ const fileInfo = Deno.statSync(filename);
+ assertFuzzyTimestampEquals(fileInfo.accessed, atime);
+ assertFuzzyTimestampEquals(fileInfo.modified, mtime);
+ }
+);
+
+testPerm(
+ { read: true, write: true },
+ async function utimeDirectorySuccess(): Promise<void> {
+ const testDir = Deno.makeTempDirSync();
+
+ const atime = 1000;
+ const mtime = 50000;
+ await Deno.utime(testDir, atime, mtime);
+
+ const dirInfo = Deno.statSync(testDir);
+ assertFuzzyTimestampEquals(dirInfo.accessed, atime);
+ assertFuzzyTimestampEquals(dirInfo.modified, mtime);
+ }
+);
+
+testPerm(
+ { read: true, write: true },
+ async function utimeDateSuccess(): Promise<void> {
+ const testDir = Deno.makeTempDirSync();
+
+ const atime = 1000;
+ const mtime = 50000;
+ await Deno.utime(testDir, new Date(atime * 1000), new Date(mtime * 1000));
+
+ const dirInfo = Deno.statSync(testDir);
+ assertFuzzyTimestampEquals(dirInfo.accessed, atime);
+ assertFuzzyTimestampEquals(dirInfo.modified, mtime);
+ }
+);
+
+testPerm({ read: true, write: true }, async function utimeNotFound(): Promise<
+ void
+> {
+ const atime = 1000;
+ const mtime = 50000;
+
+ let caughtError = false;
+ try {
+ await Deno.utime("/baddir", atime, mtime);
+ } catch (e) {
+ caughtError = true;
+ assertEquals(e.kind, Deno.ErrorKind.NotFound);
+ assertEquals(e.name, "NotFound");
+ }
+ assert(caughtError);
+});
+
+testPerm({ read: true, write: false }, async function utimeSyncPerm(): Promise<
+ void
+> {
+ const atime = 1000;
+ const mtime = 50000;
+
+ let caughtError = false;
+ try {
+ await Deno.utime("/some_dir", atime, mtime);
+ } catch (e) {
+ caughtError = true;
+ assertEquals(e.kind, Deno.ErrorKind.PermissionDenied);
+ assertEquals(e.name, "PermissionDenied");
+ }
+ assert(caughtError);
+});