NOFOLLOW_LINKS makes a metadata read describe a symbolic link itself rather than the target it names. That observation is useful for an intake policy but does not lock the path against replacement.
Java symbolic links: inspect attributes without claiming race safety
Operational contract
A manifest intake may reject symbolic links because they can point outside the owned staging tree. readAttributes with NOFOLLOW_LINKS distinguishes a regular file from a link at the moment of inspection. A later open can still follow a path that has been replaced in between. For an adversarial writable directory, move ownership to a trusted staging area or use a supported handle-relative API such as SecureDirectoryStream, with a fallback policy when it is unavailable. The sample is an inspection gate, not a race-free opener.
Failure case
A contractor uploads a candidate named shipment-47.manifest. The metadata gate accepts a regular file and rejects a symbolic link. If another writer can rename entries after the check, the application must not claim that the next path-based read is protected. The job keeps the folder write permissions narrow and validates the opened content before it makes any state change.
Java code
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
public class ManifestAttributeGate {
public static void requireRegularEntry(Path candidate) throws IOException {
BasicFileAttributes observed = Files.readAttributes(
candidate, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
if (!observed.isRegularFile()) {
throw new IOException("Manifest entry is not a regular file");
}
}
}Performance and ownership cost
One metadata read is O(1) API work but may involve remote or slow filesystem I/O. Secure open-and-verify designs cost more coordination than a lexical check, yet they are needed when untrusted users can mutate the directory. The observed attributes should never be sold as a permanent property of a path name.
Common Mistakes
- Do not equate Path.normalize with filesystem containment.
- Do not assume NOFOLLOW_LINKS prevents a later replacement race.
- Do not accept a symbolic link because its current target appears regular.
Connected lessons
- Java Path.normalize: reject lexical escapes without promising symlink safety
- Java Files.move: atomic publication is a filesystem contract
- Java file I/O: UTF-8, streaming reads, and path ownership
- Java walkFileTree: visit failures without hiding incomplete scans
- Java WatchService: register, consume, and reset each key
- Java WatchService OVERFLOW: reconcile against directory state
- Java DirectoryStream: close iteration and reject silent truncation
- Java file, JDBC, and subprocess boundaries quiz
- Advanced Java
