Skip to content

Commit

Permalink
fix permission errors are swallowed by fs.copy() (#3504)
Browse files Browse the repository at this point in the history
  • Loading branch information
axetroy authored and ry committed Dec 18, 2019
1 parent 1c09cc6 commit ef30d37
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 63 deletions.
52 changes: 29 additions & 23 deletions std/fs/copy.ts
Expand Up @@ -23,21 +23,25 @@ async function ensureValidCopy(
options: CopyOptions,
isCopyFolder = false
): Promise<Deno.FileInfo> {
const destStat: Deno.FileInfo | null = await Deno.lstat(dest).catch(
(): Promise<null> => Promise.resolve(null)
);

if (destStat) {
if (isCopyFolder && !destStat.isDirectory()) {
throw new Error(
`Cannot overwrite non-directory '${dest}' with directory '${src}'.`
);
}
if (!options.overwrite) {
throw new Error(`'${dest}' already exists.`);
let destStat: Deno.FileInfo | null;

try {
destStat = await Deno.lstat(dest);
} catch (err) {
if (err instanceof Deno.DenoError && err.kind == Deno.ErrorKind.NotFound) {
return;
}
}

if (isCopyFolder && !destStat.isDirectory()) {
throw new Error(
`Cannot overwrite non-directory '${dest}' with directory '${src}'.`
);
}
if (!options.overwrite) {
throw new Error(`'${dest}' already exists.`);
}

return destStat!;
}

Expand All @@ -51,19 +55,19 @@ function ensureValidCopySync(

try {
destStat = Deno.lstatSync(dest);
} catch {
// ignore error
} catch (err) {
if (err instanceof Deno.DenoError && err.kind == Deno.ErrorKind.NotFound) {
return;
}
}

if (destStat!) {
if (isCopyFolder && !destStat!.isDirectory()) {
throw new Error(
`Cannot overwrite non-directory '${dest}' with directory '${src}'.`
);
}
if (!options.overwrite) {
throw new Error(`'${dest}' already exists.`);
}
if (isCopyFolder && !destStat!.isDirectory()) {
throw new Error(
`Cannot overwrite non-directory '${dest}' with directory '${src}'.`
);
}
if (!options.overwrite) {
throw new Error(`'${dest}' already exists.`);
}

return destStat!;
Expand Down Expand Up @@ -186,6 +190,7 @@ function copyDirSync(src: string, dest: string, options: CopyOptions): void {

/**
* Copy a file or directory. The directory can have contents. Like `cp -r`.
* Requires the `--allow-read` and `--alow-write` flag.
* @param src the file/directory path.
* Note that if `src` is a directory it will copy everything inside
* of this directory, not the entire directory itself
Expand Down Expand Up @@ -224,6 +229,7 @@ export async function copy(

/**
* Copy a file or directory. The directory can have contents. Like `cp -r`.
* Requires the `--allow-read` and `--alow-write` flag.
* @param src the file/directory path.
* Note that if `src` is a directory it will copy everything inside
* of this directory, not the entire directory itself
Expand Down
40 changes: 20 additions & 20 deletions std/fs/ensure_dir.ts
@@ -1,49 +1,49 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { getFileInfoType } from "./utils.ts";
const { lstat, lstatSync, mkdir, mkdirSync, ErrorKind } = Deno;

/**
* Ensures that the directory exists.
* If the directory structure does not exist, it is created. Like mkdir -p.
* Requires the `--allow-read` and `--alow-write` flag.
*/
export async function ensureDir(dir: string): Promise<void> {
let pathExists = false;
try {
// if dir exists
const stat = await Deno.stat(dir);
pathExists = true;
if (!stat.isDirectory()) {
const fileInfo = await lstat(dir);
if (!fileInfo.isDirectory()) {
throw new Error(
`Ensure path exists, expected 'dir', got '${getFileInfoType(stat)}'`
`Ensure path exists, expected 'dir', got '${getFileInfoType(fileInfo)}'`
);
}
} catch (err) {
if (pathExists) {
throw err;
if (err instanceof Deno.DenoError && err.kind === ErrorKind.NotFound) {
// if dir not exists. then create it.
await mkdir(dir, true);
return;
}
// if dir not exists. then create it.
await Deno.mkdir(dir, true);
throw err;
}
}

/**
* Ensures that the directory exists.
* If the directory structure does not exist, it is created. Like mkdir -p.
* Requires the `--allow-read` and `--alow-write` flag.
*/
export function ensureDirSync(dir: string): void {
let pathExists = false;
try {
// if dir exists
const stat = Deno.statSync(dir);
pathExists = true;
if (!stat.isDirectory()) {
const fileInfo = lstatSync(dir);
if (!fileInfo.isDirectory()) {
throw new Error(
`Ensure path exists, expected 'dir', got '${getFileInfoType(stat)}'`
`Ensure path exists, expected 'dir', got '${getFileInfoType(fileInfo)}'`
);
}
} catch (err) {
if (pathExists) {
throw err;
if (err instanceof Deno.DenoError && err.kind == ErrorKind.NotFound) {
// if dir not exists. then create it.
mkdirSync(dir, true);
return;
}
// if dir not exists. then create it.
Deno.mkdirSync(dir, true);
throw err;
}
}
42 changes: 22 additions & 20 deletions std/fs/ensure_file.ts
Expand Up @@ -2,34 +2,36 @@
import * as path from "../path/mod.ts";
import { ensureDir, ensureDirSync } from "./ensure_dir.ts";
import { getFileInfoType } from "./utils.ts";
const { lstat, lstatSync, writeFile, writeFileSync, ErrorKind } = Deno;

/**
* Ensures that the file exists.
* If the file that is requested to be created is in directories that do not
* exist.
* these directories are created. If the file already exists,
* it is NOTMODIFIED.
* Requires the `--allow-read` and `--alow-write` flag.
*/
export async function ensureFile(filePath: string): Promise<void> {
let pathExists = false;
try {
// if file exists
const stat = await Deno.lstat(filePath);
pathExists = true;
const stat = await lstat(filePath);
if (!stat.isFile()) {
throw new Error(
`Ensure path exists, expected 'file', got '${getFileInfoType(stat)}'`
);
}
} catch (err) {
if (pathExists) {
throw err;
}
// if file not exists
// ensure dir exists
await ensureDir(path.dirname(filePath));
// create file
await Deno.writeFile(filePath, new Uint8Array());
if (err instanceof Deno.DenoError && err.kind === ErrorKind.NotFound) {
// ensure dir exists
await ensureDir(path.dirname(filePath));
// create file
await writeFile(filePath, new Uint8Array());
return;
}

throw err;
}
}

Expand All @@ -39,26 +41,26 @@ export async function ensureFile(filePath: string): Promise<void> {
* exist,
* these directories are created. If the file already exists,
* it is NOT MODIFIED.
* Requires the `--allow-read` and `--alow-write` flag.
*/
export function ensureFileSync(filePath: string): void {
let pathExists = false;
try {
// if file exists
const stat = Deno.statSync(filePath);
pathExists = true;
const stat = lstatSync(filePath);
if (!stat.isFile()) {
throw new Error(
`Ensure path exists, expected 'file', got '${getFileInfoType(stat)}'`
);
}
} catch (err) {
if (pathExists) {
throw err;
}
// if file not exists
// ensure dir exists
ensureDirSync(path.dirname(filePath));
// create file
Deno.writeFileSync(filePath, new Uint8Array());
if (err instanceof Deno.DenoError && err.kind === ErrorKind.NotFound) {
// ensure dir exists
ensureDirSync(path.dirname(filePath));
// create file
writeFileSync(filePath, new Uint8Array());
return;
}
throw err;
}
}

0 comments on commit ef30d37

Please sign in to comment.