Skip to content

Openfox does not follow symbolic links when opening projects #243

Description

@ColasNahaboo

Symptom: I have git projects on various places, so I tried to make symlinks to them from the directory Openfox find projects. But it does not see them.

The bug: Openfox checks that projects are real directories, but do not check if they are symlinks to directories

The fix: Just ask Deepseek flash under openfox to fix the bug.
It seems to work OK with the prompt I used:

openfox (we are in a local copy of its repo) seem to not see existing projects that are not real directories but symlinks to existing one.
Review the code to see if this bug is real, and propose a fix.
The fix should be portable on all the OS openfox runs in (Linux, MacOS, Windows, ...)

I am a bit wary of submitting a PR for this, as my Deepseek/Openfox setup (first time I use OpenFox, but I am impressed) made some refactoring decisions that may not be seen as desirable by Conrad. I guess it is simpler for him to just tell his system to fix the bug :-) ... just tell me

Anyways, here are some useful insights:

It created a new directory-checking function:

export async function isDirectoryEntry(parent: string, entry: Dirent): Promise<boolean> {
  if (entry.isDirectory()) return true
  if (!entry.isSymbolicLink()) return false
  try { return (await stat(join(parent, entry.name))).isDirectory() }
  catch { return false } // broken symlink
}

And there is a subtility in Windows for writing the tests:

Junction points on Windows: Windows also has junction points (directory junctions), which are like directory symlinks but don't require privileges (junctions can be created without admin via cmd /c mklink /J... actually junctions require no special privileges since Windows Vista? Let me recall: junctions can be created without admin rights. fs.symlink on Windows with type 'junction' doesn't require privileges). But how does Node report junctions in readdir? Junctions are reparse points. Dirent.isSymbolicLink() for a junction... Actually on Windows, junctions are reported as isSymbolicLink() returning... hmm. Let me recall Node behavior:

    On Windows, fs.stat follows symlinks and junctions.
    Dirent for a junction: Node classifies junctions as symlinks? Actually, in Node.js, for junction points, Dirent.isSymbolicLink() returns true? Let me think. The libuv uv_fs_scandir sets the type. For reparse points, libuv checks... Actually on Windows, junctions are reparse points (IO_REPARSE_TAG_MOUNT_POINT), symlinks are IO_REPARSE_TAG_SYMLINK. libuv's uv_dirent is set to UV_DIRENT_LINK for both? I believe libuv reports both as UV_DIRENT_LINK, so Dirent.isSymbolicLink() returns true for junctions too. And fs.stat follows both. So the fix handles junctions too.

Actually, I should be careful: there's a subtlety that on Windows, Dirent.isDirectory() for a junction might return... Let me recall: In Node, for a junction, Dirent.isSymbolicLink() returns true (they're reported as links). And fs.stat() on a junction resolves to the target's type. So our helper works.

Additional notes:

  • Leave unchanged: tools/read.ts still excludes symlinks deliberately — that's a symlink-loop guard, not a bug.
  • Optional follow-up (separate PR): projects.workdir is a UNIQUE exact-string key, so the same physical dir can be registered via both symlink path and realpath; normalize via realpath at creation/getProjectByWorkdir.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions