Repository navigation
FileHandle Implementation
File handle tracking for open files with position tracking and access mode management.
JNode implements file handles as lightweight wrappers around filesystem entries that track the current file position and access mode. File handles are created when a file is opened and managed through a central FileHandleManager that tracks all open file references. The implementation bridges the standard Java I/O APIs with JNode's virtual filesystem layer.
| Class/File | Location | Purpose |
|---|---|---|
FileHandleImpl |
fs/src/fs/org/jnode/fs/service/def/FileHandleImpl.java |
Concrete file handle implementation |
FileHandleManager |
fs/src/fs/org/jnode/fs/service/def/FileHandleManager.java |
Central registry for open file handles |
FileHandleManager.FileData |
fs/src/fs/org/jnode/fs/service/def/FileHandleManager.java |
Per-file handle tracking, write exclusion, stale-handle reclamation |
VMFileHandle |
core/src/classlib/java/io/VMFileHandle.java |
Interface for file handle operations |
VMOpenMode |
core/src/classlib/java/io/VMOpenMode.java |
Enum for file open modes |
FileSystemAPIImpl |
fs/src/fs/org/jnode/fs/service/def/FileSystemAPIImpl.java |
Uses FileHandleManager for open() |
When a file is opened through the VFS:
-
FileSystemAPIImpl.open(path, mode)delegates toFileHandleManager.open(file, mode) -
FileHandleManagerretrieves or creates aFileDataentry for the underlyingFSFile -
FileData.open(mode)creates a newFileHandleImplinstance - The handle tracks position (
fileOffset), mode (VMOpenMode), the creating thread (owner),canWrite, and references the underlying file
sequenceDiagram
participant App as Application
participant API as FileSystemAPIImpl
participant FHM as FileHandleManager
participant FD as FileData
participant FHI as FileHandleImpl
App->>API: open(path, READ)
API->>FHM: open(fsFile, READ)
FHM->>FD: open(mode)
FD->>FHI: new FileHandleImpl(file, mode, fhm)
FHM-->>API: handle
API-->>App: VMFileHandle
FileHandleImpl maintains a fileOffset field that tracks the current read/write position:
-
getPosition()returns the current offset -
setPosition(long)updates the offset, allowing seeking beyond EOF (extends file) -
read(ByteBuffer)reads fromfileOffsetand advances position -
write(ByteBuffer)writes atfileOffsetand advances position
The constructor processes the VMOpenMode:
- READ: Read-only handle
- WRITE: Write-only, truncates file to length 0
- READ_WRITE: Read and write access
- WRITE mode causes
file.setLength(0)to truncate the file
FileHandleManager.FileData enforces exclusive write access:
- Only one handle can be open for writing per file (
hasWritersflag) - Duplicate handles with write access are rejected with "File is already open for writing"
- Read handles can coexist with write handles (read shares)
The dup() method creates a new handle for the same file:
- Delegates to
FileHandleManager.dup(handle, newMode) - Creates a new
FileHandleImplwith same underlyingFSFile - Allows mode change during duplication
When a handle is closed:
- Underlying file is flushed (
file.flush()) -
closedflag is set -
FileHandleManagerremoves handle fromFileDatatracking -
FileDatais removed from manager when last handle closes
A handle that its owner thread abandons without closing used to pin the FSFile and its write lock forever. FileHandleImpl records owner = Thread.currentThread() at construction, and every FileHandleManager.open() sweeps existing FileData entries first:
openFile.closeStaleHandles();
if (!openFile.hasHandles()) {
files.remove();
}closeStaleHandles() removes each handle whose !isOwnerAlive(), calls closeFromManager() to flush and mark it closed, then clears hasWriters if that handle was writable. closeFromManager() sets closed in a finally block, so a failed flush still releases the handle. The sweep is opportunistic — it runs on open, not on a timer — and it is the reason a dead command thread cannot permanently block the next writer of the same file.
FileHandleManagerTest (in the fs suite) covers this path. See FSEntry-Cache for the related invalid-cache-hit regression tests.
-
Position seeking beyond EOF:
setPosition()extends the file size if seeking past EOF. This behavior exists for compatibility with Classpath's RandomAccessFile. - Write exclusion: Only one write handle per file. Attempting to open a second write handle throws an exception.
-
Single-byte read/write inefficiency:
read()andwrite(int)single-byte methods allocate temporaryByteBufferobjects on every call. -
MappedByteBuffer unimplemented:
mapImpl()returns null — memory-mapped I/O is not implemented. -
Lock unimplemented:
lock()andunlock()methods are stubs returningtrue/no-op. - No synchronized position update: Position updates in read/write are not atomic with the actual I/O operation.
-
Ownership is thread-based, not process-based.
owneris the thread that constructed the handle. A long-lived handle passed to another thread is still reclaimed when the original thread dies, so do not share an open handle across thread lifetimes without an explicit close. -
Stale cleanup runs only on
open(). Idle systems do not reap abandoned handles until the next open sweeps the map; there is no background reaper. -
closeFromManager()flushes but does not callfhm.close(). It runs inside the manager's own sweep and setscloseddirectly, avoiding re-entry into the map it is iterating. -
Write availability is reset when the write handle dies. The sweep clears
hasWritersfor a reclaimed writable handle; without that, a dead writer would block all later writes.
- VFS-Layer — Parent hub for virtual filesystem
- Filesystem-Layer — Related filesystem driver documentation
- Block-Device-Layer — Block device layer that provides underlying I/O
- FSEntry-Cache — Cached entries and invalid-hit regression tests