Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better error message for ensureSymlink if the current existing link is broken #925

Open
aviladev opened this issue Oct 15, 2021 · 2 comments

Comments

@aviladev
Copy link

aviladev commented Oct 15, 2021

  • Operating System: Pop!_OS 20.04 LTS
  • Node.js version: v16.11.0
  • fs-extra version: 10.0.0

I'm not sure if this is the expected behavior.

Here's what I'm trying to do... basically I want to replicate what ln -sfn does. I would like to create a link to a file in my home bin folder. If I move the target file to another directory, then as expected, that link will now be broken. That's why I want to recreate that link, updating the target path. The problem is when I do this (calling createSymlink) node throws an error (because the link is broken):

node:internal/process/promises:246
          triggerUncaughtException(err, true /* fromPromise */);
          ^

[Error: ENOENT: no such file or directory, stat '/home/myusername/bin/rgb-toggle'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'stat',
  path: '/home/myusername/bin/rgb-toggle'
}

The error is thrown by Node when calling fs.stat or fs.statSync, here's what happens when I call it in Node REPL:

> fs.statSync(`${os.homedir()}/bin/rgb-toggle`)
Uncaught Error: ENOENT: no such file or directory, stat '/home/myusername/bin/rgb-toggle'
    at Object.statSync (node:fs:1536:3) {
  errno: -2,
  syscall: 'stat',
  code: 'ENOENT',
  path: '/home/myusername/bin/rgb-toggle'
}

The link exists, only it's broken. Looks like that is expected behavior for Node because it will call POSIX stat, and as the description:

stat() retrieve information about the file pointed to by pathname.

However for that purpose we can use fs.lstat or fs.lstatSync which will call POSIX lstat, which as described:

lstat() is identical to stat(), except that if pathname is a symbolic link, then it returns information about the link itself, not the file that the link refers to.

Calling fs.lstatSync succeeds:

> fs.lstatSync(`${os.homedir()}/bin/rgb-toggle`)
Stats {
  dev: 66307,
  mode: 41471,
  nlink: 1,
  uid: 1000,
  gid: 1000,
  rdev: 0,
  blksize: 4096,
  ino: 5396104,
  size: 60,
  blocks: 8,
  atimeMs: 1634260915813.8984,
  mtimeMs: 1634260915813.8984,
  ctimeMs: 1634260915813.8984,
  birthtimeMs: 1634260915813.8984,
  atime: 2021-10-15T01:21:55.814Z,
  mtime: 2021-10-15T01:21:55.814Z,
  ctime: 2021-10-15T01:21:55.814Z,
  birthtime: 2021-10-15T01:21:55.814Z
}

Shouldn't fs.ensureSymlink check for broken symlink and update it (given the new target path exists)?

@RyanZim
Copy link
Collaborator

RyanZim commented Oct 15, 2021

ping @manidlou

@RyanZim
Copy link
Collaborator

RyanZim commented Oct 20, 2022

If you call ensureSymlink on an existing symlink, with a different target, it fails with Error: EEXIST: file already exists. It'd be weird for this to succeed if the symlink was broken. I'll admit, ENOENT is an odd error to throw here. If possible, we should try to change this to throw EEXIST even when the symlink is broken.

@RyanZim RyanZim changed the title ensureSymlink fails if the current existing link is broken Better error message for ensureSymlink if the current existing link is broken Oct 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants