fs.copy() semantics differ from cp -- no symlink/metadata preservation #40

Closed
opened 2026-07-26 19:04:56 +02:00 by michael · 0 comments
Owner

fs.copy(src, dst) is implemented as read_file() + write_file() (full content read into memory, rewritten as a new regular file). This differs from shell 'cp' in several ways:

  • Symlinks: 'cp' by default follows a symlink and copies the target's content into a new regular file too (same outcome as fs.copy here) -- but 'cp -a'/'cp -P' behavior (preserving the symlink itself) cannot be replicated with fs.copy().
  • Metadata: permissions, timestamps, ownership are not preserved -- the new file gets whatever the process's own umask/defaults produce.
  • Large files: full read-into-memory instead of streaming -- could matter for big files.

Found while migrating DAW/daw-module-manager (index.lua) from 'os.execute(cp ...)' to fs.copy() for registry-index.json / .minisig files, where this is harmless. Unclear whether other consumers (e.g. daw-modul-storage-* backups, package installs) rely on symlink or metadata preservation via fs.copy() or a similar path.

Needs: audit which callers actually need cp-equivalent semantics, then decide whether fs.copy() should be documented as 'content-only copy, not a cp replacement', or whether a separate fs function (e.g. fs.copy_preserve() shelling out to 'cp -a' via sys) is needed for those cases.

fs.copy(src, dst) is implemented as read_file() + write_file() (full content read into memory, rewritten as a new regular file). This differs from shell 'cp' in several ways: - Symlinks: 'cp' by default follows a symlink and copies the target's content into a new regular file too (same outcome as fs.copy here) -- but 'cp -a'/'cp -P' behavior (preserving the symlink itself) cannot be replicated with fs.copy(). - Metadata: permissions, timestamps, ownership are not preserved -- the new file gets whatever the process's own umask/defaults produce. - Large files: full read-into-memory instead of streaming -- could matter for big files. Found while migrating DAW/daw-module-manager (index.lua) from 'os.execute(cp ...)' to fs.copy() for registry-index.json / .minisig files, where this is harmless. Unclear whether other consumers (e.g. daw-modul-storage-* backups, package installs) rely on symlink or metadata preservation via fs.copy() or a similar path. Needs: audit which callers actually need cp-equivalent semantics, then decide whether fs.copy() should be documented as 'content-only copy, not a cp replacement', or whether a separate fs function (e.g. fs.copy_preserve() shelling out to 'cp -a' via sys) is needed for those cases.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
DAW/daw-lua-common#40
No description provided.