Skip to content

Inconsistency in fs.cp operation #58947

Description

@jasnell

In the fs.cp... API, we have options such as errorOnExist and force that are intended to control what happens when the destination already exists. There is, however, a discrepancy in how the options are implemented depending on whether the src/dest are files or directories.

For instance, let's suppose we have the following directory layout:

~/tmp
    | -- ~/tmp/a (file)
    | -- ~/tmp/b (file)
    | -- ~/tmp/c (directory)
    |            | -- /tmp/c/1 (file)
    | -- ~/tmp/d (directory)
                 | -- /tmp/d/2 (file)

Then, in the fs.cp operation, let's first try copying a to b, with options errorOnExist: true and force: false we get the appropriate error indicating that the destination exists and we're not going to overwrite it:

> fs.cp('a', 'b', { errorOnExist: true, force: false }, console.log)
undefined
> SystemError [ERR_FS_CP_EEXIST]: Target already exists: cp returned EEXIST (b already exists) b
    at mayCopyFile (node:internal/fs/cp/cp:250:11)
    at onFile (node:internal/fs/cp/cp:242:10)
    at getStatsForCopy (node:internal/fs/cp/cp:211:12) {
  code: 'ERR_FS_CP_EEXIST',
  info: {
    message: 'b already exists',
    path: 'b',
    syscall: 'cp',
    errno: 17,
    code: 'EEXIST'
  },
  errno: [Getter/Setter: 17],
  syscall: [Getter/Setter: 'cp'],
  path: [Getter/Setter: 'b']
}

However, if we try copying c to d, with options errorOnExist: true and force: false, we happily go ahead and copy contents of 'c' over to 'd', erroring only if one of the individual files in d overlaps with a file in c

> fs.cp('c', 'd', { recursive: true, errorOnExist: true, force: false }, console.log)
undefined
> null undefined

This just feels wrong. d already exists and we're being told not to force. I would expect the behavior to be the same as copying the files. If d exists, this operation should fail.

I don't think we can change this behavior now without it being semver-major and potentially breaking a lot of things but we really ought to have an option of enforcing that no copy is performed if d exists.

@nodejs/fs @anonrig @dario-piotrowicz

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    fsIssues and PRs related to file-system APIs and the fs module.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions