or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-management.mdindex.mdio-filesystem.mdlanguage-execution.mdmonitoring-management.mdproxy-system.mdsecurity-access.mdvalue-interop.md

io-filesystem.mddocs/

0

# I/O and File System Virtualization

1

2

The GraalVM Polyglot API provides comprehensive I/O virtualization capabilities, allowing fine-grained control over file system access, network operations, and byte-level data handling. This enables secure execution environments with custom I/O policies and virtual file systems.

3

4

## I/O Access Control

5

6

IOAccess controls the I/O operations that polyglot contexts can perform, providing security boundaries for file system and network access.

7

8

### Predefined IOAccess Policies

9

10

```java { .api }

11

public final class IOAccess {

12

// Full I/O access - all file system and network operations allowed

13

public static final IOAccess ALL;

14

15

// No I/O access - all I/O operations denied

16

public static final IOAccess NONE;

17

}

18

```

19

20

### Custom IOAccess Configuration

21

22

```java { .api }

23

// Factory method for custom I/O configuration

24

public static IOAccess.Builder newBuilder();

25

```

26

27

The IOAccess.Builder provides granular control over I/O operations:

28

29

```java { .api }

30

public static final class IOAccess.Builder {

31

/**

32

* Controls host socket access for network operations.

33

* @param enabled true to allow socket access

34

* @return this builder

35

*/

36

public IOAccess.Builder allowHostSocketAccess(boolean enabled);

37

38

/**

39

* Controls host file access for file system operations.

40

* @param enabled true to allow file access

41

* @return this builder

42

*/

43

public IOAccess.Builder allowHostFileAccess(boolean enabled);

44

45

/**

46

* Sets a custom file system implementation.

47

* @param fileSystem the custom file system

48

* @return this builder

49

*/

50

public IOAccess.Builder fileSystem(FileSystem fileSystem);

51

52

/**

53

* Builds the IOAccess configuration.

54

* @return the configured IOAccess

55

*/

56

public IOAccess build();

57

}

58

```

59

60

**IOAccess Configuration Examples:**

61

62

```java

63

// Allow file access but deny network access

64

IOAccess fileOnlyAccess = IOAccess.newBuilder()

65

.allowHostFileAccess(true)

66

.allowHostSocketAccess(false)

67

.build();

68

69

Context fileContext = Context.newBuilder("js")

70

.allowIO(fileOnlyAccess)

71

.build();

72

73

// Allow network but deny file system

74

IOAccess networkOnlyAccess = IOAccess.newBuilder()

75

.allowHostFileAccess(false)

76

.allowHostSocketAccess(true)

77

.build();

78

79

Context networkContext = Context.newBuilder("js")

80

.allowIO(networkOnlyAccess)

81

.build();

82

83

// Custom file system with restricted access

84

IOAccess customFSAccess = IOAccess.newBuilder()

85

.fileSystem(new RestrictedFileSystem("/allowed/path"))

86

.allowHostSocketAccess(false)

87

.build();

88

89

Context restrictedContext = Context.newBuilder("js")

90

.allowIO(customFSAccess)

91

.build();

92

```

93

94

## Virtual File System Interface

95

96

The FileSystem interface provides a complete abstraction for file system operations, enabling custom file system implementations.

97

98

### FileSystem Interface

99

100

```java { .api }

101

public interface FileSystem {

102

/**

103

* Parses a URI to a Path.

104

* @param uri the URI to parse

105

* @return the path

106

*/

107

Path parsePath(URI uri);

108

109

/**

110

* Parses a string to a Path.

111

* @param path the path string

112

* @return the path

113

*/

114

Path parsePath(String path);

115

116

/**

117

* Checks access permissions for a path.

118

* @param path the path to check

119

* @param modes the access modes to check

120

* @param linkOptions link handling options

121

* @throws IOException if access check fails

122

*/

123

void checkAccess(Path path, Set<? extends AccessMode> modes, LinkOption... linkOptions) throws IOException;

124

125

/**

126

* Creates a directory.

127

* @param dir the directory to create

128

* @param attrs file attributes

129

* @throws IOException if creation fails

130

*/

131

void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException;

132

133

/**

134

* Deletes a file or directory.

135

* @param path the path to delete

136

* @throws IOException if deletion fails

137

*/

138

void delete(Path path) throws IOException;

139

140

/**

141

* Opens a byte channel for reading/writing.

142

* @param path the file path

143

* @param options open options

144

* @param attrs file attributes

145

* @return the byte channel

146

* @throws IOException if opening fails

147

*/

148

SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException;

149

150

/**

151

* Creates a directory stream for listing directory contents.

152

* @param dir the directory

153

* @param filter optional filter for entries

154

* @return directory stream

155

* @throws IOException if listing fails

156

*/

157

DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException;

158

159

/**

160

* Reads file attributes.

161

* @param path the file path

162

* @param attributes attribute pattern to read

163

* @param options link handling options

164

* @return map of attributes

165

* @throws IOException if reading fails

166

*/

167

Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException;

168

169

/**

170

* Sets a file attribute.

171

* @param path the file path

172

* @param attribute the attribute name

173

* @param value the attribute value

174

* @param options link handling options

175

* @throws IOException if setting fails

176

*/

177

void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException;

178

179

/**

180

* Copies a file.

181

* @param source source path

182

* @param target target path

183

* @param options copy options

184

* @throws IOException if copying fails

185

*/

186

void copy(Path source, Path target, CopyOption... options) throws IOException;

187

188

/**

189

* Moves a file.

190

* @param source source path

191

* @param target target path

192

* @param options move options

193

* @throws IOException if moving fails

194

*/

195

void move(Path source, Path target, CopyOption... options) throws IOException;

196

197

/**

198

* Converts to absolute path.

199

* @param path the path to convert

200

* @return absolute path

201

*/

202

Path toAbsolutePath(Path path);

203

204

/**

205

* Resolves to real path (following links).

206

* @param path the path to resolve

207

* @param linkOptions link handling options

208

* @return real path

209

* @throws IOException if resolution fails

210

*/

211

Path toRealPath(Path path, LinkOption... linkOptions) throws IOException;

212

213

/**

214

* Gets the path separator.

215

* @return path separator string

216

*/

217

String getSeparator();

218

219

/**

220

* Gets the path separator for PATH-style variables.

221

* @return path separator string

222

*/

223

String getPathSeparator();

224

225

/**

226

* Detects MIME type of a file.

227

* @param path the file path

228

* @return MIME type or null

229

*/

230

String getMimeType(Path path);

231

232

/**

233

* Detects text encoding of a file.

234

* @param path the file path

235

* @return encoding name or null

236

*/

237

String getEncoding(Path path);

238

239

/**

240

* Gets the temporary directory.

241

* @return temp directory path

242

*/

243

Path getTempDirectory();

244

245

/**

246

* Checks if two paths refer to the same file.

247

* @param path1 first path

248

* @param path2 second path

249

* @param options link handling options

250

* @return true if same file

251

* @throws IOException if comparison fails

252

*/

253

boolean isSameFile(Path path1, Path path2, LinkOption... options) throws IOException;

254

}

255

```

256

257

### Custom FileSystem Implementation Example

258

259

```java

260

import org.graalvm.polyglot.io.FileSystem;

261

import java.nio.file.*;

262

import java.io.IOException;

263

import java.util.*;

264

265

public class RestrictedFileSystem implements FileSystem {

266

private final Path allowedRoot;

267

private final Set<String> allowedExtensions;

268

private final FileSystem delegate;

269

270

public RestrictedFileSystem(String allowedPath) {

271

this.allowedRoot = Paths.get(allowedPath).toAbsolutePath();

272

this.allowedExtensions = Set.of(".txt", ".json", ".csv", ".log");

273

this.delegate = FileSystems.getDefault();

274

}

275

276

@Override

277

public Path parsePath(String path) {

278

Path parsed = delegate.getPath(path);

279

return validatePath(parsed);

280

}

281

282

@Override

283

public Path parsePath(URI uri) {

284

Path parsed = Paths.get(uri);

285

return validatePath(parsed);

286

}

287

288

private Path validatePath(Path path) {

289

Path absolute = path.toAbsolutePath();

290

291

// Ensure path is within allowed root

292

if (!absolute.startsWith(allowedRoot)) {

293

throw new SecurityException("Access denied: path outside allowed directory");

294

}

295

296

// Check file extension

297

String filename = absolute.getFileName().toString();

298

if (filename.contains(".") && allowedExtensions.stream()

299

.noneMatch(filename.toLowerCase()::endsWith)) {

300

throw new SecurityException("Access denied: file type not allowed");

301

}

302

303

return absolute;

304

}

305

306

@Override

307

public void checkAccess(Path path, Set<? extends AccessMode> modes, LinkOption... linkOptions) throws IOException {

308

Path validatedPath = validatePath(path);

309

Files.checkAccess(validatedPath, modes.toArray(new AccessMode[0]));

310

}

311

312

@Override

313

public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {

314

Path validatedPath = validatePath(path);

315

316

// Log file access

317

System.out.println("File access: " + validatedPath);

318

319

return Files.newByteChannel(validatedPath, options, attrs);

320

}

321

322

@Override

323

public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException {

324

Path validatedDir = validatePath(dir);

325

326

return Files.newDirectoryStream(validatedDir, entry -> {

327

try {

328

Path validated = validatePath(entry);

329

return filter == null || filter.accept(validated);

330

} catch (SecurityException e) {

331

return false; // Skip inaccessible files

332

} catch (IOException e) {

333

return false;

334

}

335

});

336

}

337

338

@Override

339

public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {

340

Path validatedDir = validatePath(dir);

341

Files.createDirectory(validatedDir, attrs);

342

}

343

344

@Override

345

public void delete(Path path) throws IOException {

346

Path validatedPath = validatePath(path);

347

Files.delete(validatedPath);

348

}

349

350

// Additional methods implementation...

351

@Override

352

public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException {

353

Path validatedPath = validatePath(path);

354

return Files.readAttributes(validatedPath, attributes, options);

355

}

356

357

@Override

358

public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {

359

Path validatedPath = validatePath(path);

360

Files.setAttribute(validatedPath, attribute, value, options);

361

}

362

363

@Override

364

public void copy(Path source, Path target, CopyOption... options) throws IOException {

365

Path validatedSource = validatePath(source);

366

Path validatedTarget = validatePath(target);

367

Files.copy(validatedSource, validatedTarget, options);

368

}

369

370

@Override

371

public void move(Path source, Path target, CopyOption... options) throws IOException {

372

Path validatedSource = validatePath(source);

373

Path validatedTarget = validatePath(target);

374

Files.move(validatedSource, validatedTarget, options);

375

}

376

377

@Override

378

public Path toAbsolutePath(Path path) {

379

return validatePath(path);

380

}

381

382

@Override

383

public Path toRealPath(Path path, LinkOption... linkOptions) throws IOException {

384

Path validatedPath = validatePath(path);

385

return validatedPath.toRealPath(linkOptions);

386

}

387

388

@Override

389

public String getSeparator() {

390

return delegate.getSeparator();

391

}

392

393

@Override

394

public String getPathSeparator() {

395

return File.pathSeparator;

396

}

397

398

@Override

399

public String getMimeType(Path path) {

400

try {

401

Path validatedPath = validatePath(path);

402

return Files.probeContentType(validatedPath);

403

} catch (Exception e) {

404

return null;

405

}

406

}

407

408

@Override

409

public String getEncoding(Path path) {

410

// Simple encoding detection based on file extension

411

String filename = path.getFileName().toString().toLowerCase();

412

if (filename.endsWith(".json") || filename.endsWith(".js")) {

413

return "UTF-8";

414

}

415

return null;

416

}

417

418

@Override

419

public Path getTempDirectory() {

420

// Return temp directory within allowed root

421

return allowedRoot.resolve("temp");

422

}

423

424

@Override

425

public boolean isSameFile(Path path1, Path path2, LinkOption... options) throws IOException {

426

Path validatedPath1 = validatePath(path1);

427

Path validatedPath2 = validatePath(path2);

428

return Files.isSameFile(validatedPath1, validatedPath2);

429

}

430

}

431

432

// Usage

433

RestrictedFileSystem restrictedFS = new RestrictedFileSystem("/safe/sandbox");

434

Context context = Context.newBuilder("js")

435

.allowIO(IOAccess.newBuilder()

436

.fileSystem(restrictedFS)

437

.allowHostSocketAccess(false)

438

.build())

439

.build();

440

```

441

442

## ByteSequence Interface

443

444

ByteSequence provides an abstraction for byte data that can be used across polyglot boundaries.

445

446

### ByteSequence Interface

447

448

```java { .api }

449

public interface ByteSequence {

450

/**

451

* Returns the length of the byte sequence.

452

* @return the length

453

*/

454

int length();

455

456

/**

457

* Returns the byte at the specified index.

458

* @param index the index

459

* @return the byte value

460

*/

461

byte byteAt(int index);

462

463

/**

464

* Creates a subsequence.

465

* @param startIndex start index (inclusive)

466

* @param endIndex end index (exclusive)

467

* @return the subsequence

468

*/

469

ByteSequence subSequence(int startIndex, int endIndex);

470

471

/**

472

* Converts to byte array.

473

* @return byte array copy

474

*/

475

byte[] toByteArray();

476

}

477

```

478

479

### ByteSequence Implementations

480

481

The polyglot API provides implementations for common use cases:

482

483

**Creating ByteSequence from various sources:**

484

485

```java

486

import org.graalvm.polyglot.io.ByteSequence;

487

488

// From byte array

489

byte[] data = {0x48, 0x65, 0x6C, 0x6C, 0x6F}; // "Hello" in ASCII

490

ByteSequence fromArray = ByteSequence.create(data);

491

492

// From string with encoding

493

ByteSequence fromString = ByteSequence.create("Hello World", StandardCharsets.UTF_8);

494

495

// From InputStream

496

try (InputStream input = new FileInputStream("data.bin")) {

497

ByteSequence fromStream = ByteSequence.create(input);

498

}

499

500

// Usage with Source

501

Source binarySource = Source.newBuilder("js", fromArray, "binary-data.js").build();

502

503

Context context = Context.create("js");

504

context.getBindings("js").putMember("binaryData", fromArray);

505

506

context.eval("js", """

507

console.log('Length:', binaryData.length);

508

console.log('First byte:', binaryData.byteAt(0));

509

510

// Convert to string (if text data)

511

let text = '';

512

for (let i = 0; i < binaryData.length; i++) {

513

text += String.fromCharCode(binaryData.byteAt(i));

514

}

515

console.log('Text:', text); // "Hello"

516

""");

517

```

518

519

### Custom ByteSequence Implementation

520

521

```java

522

public class MemoryMappedByteSequence implements ByteSequence {

523

private final MappedByteBuffer buffer;

524

private final int offset;

525

private final int length;

526

527

public MemoryMappedByteSequence(Path file) throws IOException {

528

try (RandomAccessFile randomAccessFile = new RandomAccessFile(file.toFile(), "r");

529

FileChannel channel = randomAccessFile.getChannel()) {

530

531

this.buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());

532

this.offset = 0;

533

this.length = (int) channel.size();

534

}

535

}

536

537

private MemoryMappedByteSequence(MappedByteBuffer buffer, int offset, int length) {

538

this.buffer = buffer;

539

this.offset = offset;

540

this.length = length;

541

}

542

543

@Override

544

public int length() {

545

return length;

546

}

547

548

@Override

549

public byte byteAt(int index) {

550

if (index < 0 || index >= length) {

551

throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);

552

}

553

return buffer.get(offset + index);

554

}

555

556

@Override

557

public ByteSequence subSequence(int startIndex, int endIndex) {

558

if (startIndex < 0 || endIndex > length || startIndex > endIndex) {

559

throw new IndexOutOfBoundsException();

560

}

561

return new MemoryMappedByteSequence(buffer, offset + startIndex, endIndex - startIndex);

562

}

563

564

@Override

565

public byte[] toByteArray() {

566

byte[] result = new byte[length];

567

for (int i = 0; i < length; i++) {

568

result[i] = byteAt(i);

569

}

570

return result;

571

}

572

}

573

```

574

575

## Message Transport and Communication

576

577

The polyglot API provides interfaces for message-based communication, useful for implementing client-server protocols or inter-process communication.

578

579

### MessageTransport Interface

580

581

```java { .api }

582

public interface MessageTransport {

583

/**

584

* Opens a message endpoint for communication.

585

* @param uri the endpoint URI

586

* @param peerEndpoint the peer endpoint for bidirectional communication

587

* @return the opened message endpoint

588

* @throws IOException if opening fails

589

*/

590

MessageEndpoint open(URI uri, MessageEndpoint peerEndpoint) throws IOException;

591

}

592

```

593

594

### MessageEndpoint Interface

595

596

```java { .api }

597

public interface MessageEndpoint extends AutoCloseable {

598

/**

599

* Sends a text message.

600

* @param text the text message

601

* @throws IOException if sending fails

602

*/

603

void sendText(String text) throws IOException;

604

605

/**

606

* Sends binary data.

607

* @param data the binary data

608

* @throws IOException if sending fails

609

*/

610

void sendBinary(ByteBuffer data) throws IOException;

611

612

/**

613

* Sends a ping message.

614

* @param data optional ping data

615

* @throws IOException if sending fails

616

*/

617

void sendPing(ByteBuffer data) throws IOException;

618

619

/**

620

* Sends a pong response.

621

* @param data optional pong data

622

* @throws IOException if sending fails

623

*/

624

void sendPong(ByteBuffer data) throws IOException;

625

626

/**

627

* Sends close message and closes the endpoint.

628

* @throws IOException if closing fails

629

*/

630

void sendClose() throws IOException;

631

632

/**

633

* Closes the endpoint.

634

*/

635

@Override

636

void close() throws IOException;

637

}

638

```

639

640

**Message Transport Example:**

641

642

```java

643

public class WebSocketTransport implements MessageTransport {

644

645

@Override

646

public MessageEndpoint open(URI uri, MessageEndpoint peerEndpoint) throws IOException {

647

return new WebSocketEndpoint(uri, peerEndpoint);

648

}

649

650

private static class WebSocketEndpoint implements MessageEndpoint {

651

private final URI uri;

652

private final MessageEndpoint peer;

653

private volatile boolean closed = false;

654

655

public WebSocketEndpoint(URI uri, MessageEndpoint peer) {

656

this.uri = uri;

657

this.peer = peer;

658

}

659

660

@Override

661

public void sendText(String text) throws IOException {

662

if (closed) throw new IOException("Endpoint is closed");

663

664

// Log message

665

System.out.printf("Sending text to %s: %s%n", uri, text);

666

667

// Simulate sending to peer

668

if (peer != null) {

669

// In real implementation, this would go through network

670

// peer.receiveText(text);

671

}

672

}

673

674

@Override

675

public void sendBinary(ByteBuffer data) throws IOException {

676

if (closed) throw new IOException("Endpoint is closed");

677

678

System.out.printf("Sending %d bytes to %s%n", data.remaining(), uri);

679

680

if (peer != null) {

681

// peer.receiveBinary(data);

682

}

683

}

684

685

@Override

686

public void sendPing(ByteBuffer data) throws IOException {

687

if (closed) throw new IOException("Endpoint is closed");

688

689

System.out.printf("Sending ping to %s%n", uri);

690

691

// Automatic pong response

692

if (peer != null) {

693

peer.sendPong(data);

694

}

695

}

696

697

@Override

698

public void sendPong(ByteBuffer data) throws IOException {

699

if (closed) throw new IOException("Endpoint is closed");

700

701

System.out.printf("Sending pong to %s%n", uri);

702

}

703

704

@Override

705

public void sendClose() throws IOException {

706

close();

707

}

708

709

@Override

710

public void close() throws IOException {

711

if (!closed) {

712

closed = true;

713

System.out.printf("Closed connection to %s%n", uri);

714

}

715

}

716

}

717

}

718

719

// Usage in Context configuration

720

Context context = Context.newBuilder("js")

721

.allowIO(IOAccess.newBuilder()

722

.allowHostSocketAccess(true)

723

.build())

724

.option("js.webSocket", "true") // Example: enable WebSocket support

725

.build();

726

```

727

728

## Process Handler Interface

729

730

ProcessHandler provides an abstraction for creating and managing external processes.

731

732

### ProcessHandler Interface

733

734

```java { .api }

735

public interface ProcessHandler {

736

/**

737

* Starts an external process.

738

* @param command the process command configuration

739

* @return the started process

740

* @throws IOException if process creation fails

741

*/

742

Process start(ProcessCommand command) throws IOException;

743

}

744

```

745

746

### ProcessCommand Configuration

747

748

```java { .api }

749

public final class ProcessCommand {

750

// Process command builder methods

751

public static ProcessCommand.Builder create(String... command);

752

public static ProcessCommand.Builder create(List<String> command);

753

754

public static final class Builder {

755

public Builder arguments(String... args);

756

public Builder arguments(List<String> args);

757

public Builder environment(Map<String, String> env);

758

public Builder directory(Path workingDirectory);

759

public Builder redirectInput(ProcessHandler.Redirect redirect);

760

public Builder redirectOutput(ProcessHandler.Redirect redirect);

761

public Builder redirectError(ProcessHandler.Redirect redirect);

762

public ProcessCommand build();

763

}

764

}

765

```

766

767

**Process Handler Example:**

768

769

```java

770

public class RestrictedProcessHandler implements ProcessHandler {

771

private final Set<String> allowedCommands;

772

private final Path allowedDirectory;

773

774

public RestrictedProcessHandler(Set<String> allowedCommands, Path allowedDirectory) {

775

this.allowedCommands = allowedCommands;

776

this.allowedDirectory = allowedDirectory;

777

}

778

779

@Override

780

public Process start(ProcessCommand command) throws IOException {

781

List<String> commandList = command.getCommand();

782

if (commandList.isEmpty()) {

783

throw new IOException("Empty command");

784

}

785

786

String executable = commandList.get(0);

787

if (!allowedCommands.contains(executable)) {

788

throw new SecurityException("Command not allowed: " + executable);

789

}

790

791

Path workingDir = command.getDirectory();

792

if (workingDir != null && !workingDir.startsWith(allowedDirectory)) {

793

throw new SecurityException("Working directory not allowed: " + workingDir);

794

}

795

796

// Log process creation

797

System.out.printf("Starting process: %s in %s%n", commandList, workingDir);

798

799

ProcessBuilder builder = new ProcessBuilder(commandList);

800

if (workingDir != null) {

801

builder.directory(workingDir.toFile());

802

}

803

804

// Restrict environment

805

builder.environment().clear();

806

builder.environment().put("PATH", "/usr/bin:/bin");

807

808

return builder.start();

809

}

810

}

811

812

// Usage

813

Set<String> allowedCommands = Set.of("echo", "cat", "ls", "grep");

814

Path sandboxDir = Paths.get("/safe/sandbox");

815

ProcessHandler processHandler = new RestrictedProcessHandler(allowedCommands, sandboxDir);

816

817

Context context = Context.newBuilder("js")

818

.allowIO(IOAccess.newBuilder()

819

.allowHostFileAccess(true)

820

.build())

821

.allowCreateProcess(true)

822

.option("js.processHandler", processHandler) // Example configuration

823

.build();

824

```

825

826

## I/O Security Best Practices

827

828

### 1. Path Traversal Prevention

829

830

```java

831

public class SecureFileSystem implements FileSystem {

832

private final Path rootPath;

833

834

private Path securePath(Path path) {

835

Path normalized = rootPath.resolve(path).normalize();

836

if (!normalized.startsWith(rootPath)) {

837

throw new SecurityException("Path traversal attempt: " + path);

838

}

839

return normalized;

840

}

841

842

@Override

843

public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {

844

Path securePath = securePath(path);

845

846

// Audit file access

847

AuditLogger.logFileAccess(securePath, options);

848

849

return Files.newByteChannel(securePath, options, attrs);

850

}

851

}

852

```

853

854

### 2. Resource Quotas

855

856

```java

857

public class QuotaFileSystem implements FileSystem {

858

private final AtomicLong bytesRead = new AtomicLong(0);

859

private final AtomicLong bytesWritten = new AtomicLong(0);

860

private final long maxBytesRead;

861

private final long maxBytesWritten;

862

863

public QuotaFileSystem(long maxBytesRead, long maxBytesWritten) {

864

this.maxBytesRead = maxBytesRead;

865

this.maxBytesWritten = maxBytesWritten;

866

}

867

868

@Override

869

public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {

870

SeekableByteChannel channel = Files.newByteChannel(path, options, attrs);

871

872

return new QuotaByteChannel(channel, bytesRead, bytesWritten, maxBytesRead, maxBytesWritten);

873

}

874

}

875

876

class QuotaByteChannel implements SeekableByteChannel {

877

private final SeekableByteChannel delegate;

878

private final AtomicLong totalBytesRead;

879

private final AtomicLong totalBytesWritten;

880

private final long maxRead;

881

private final long maxWrite;

882

883

// Implementation that tracks and limits I/O operations...

884

}

885

```

886

887

### 3. I/O Monitoring and Logging

888

889

```java

890

public class MonitoringFileSystem implements FileSystem {

891

private final FileSystem delegate;

892

private final IOMonitor monitor;

893

894

public MonitoringFileSystem(FileSystem delegate, IOMonitor monitor) {

895

this.delegate = delegate;

896

this.monitor = monitor;

897

}

898

899

@Override

900

public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {

901

monitor.onFileAccess(path, options);

902

903

long startTime = System.nanoTime();

904

try {

905

SeekableByteChannel channel = delegate.newByteChannel(path, options, attrs);

906

monitor.onFileOpenSuccess(path, System.nanoTime() - startTime);

907

return channel;

908

} catch (IOException e) {

909

monitor.onFileOpenFailure(path, e, System.nanoTime() - startTime);

910

throw e;

911

}

912

}

913

}

914

915

interface IOMonitor {

916

void onFileAccess(Path path, Set<? extends OpenOption> options);

917

void onFileOpenSuccess(Path path, long durationNanos);

918

void onFileOpenFailure(Path path, IOException error, long durationNanos);

919

}

920

```