Interface struct ‣ Directory ᴾᴴᴾ - chung-leong/zigar GitHub Wiki

JavaScript | PHP


The std.fs.Dir struct provides an interface to a directory in Zig. When used as an argument to function exported to PHP, it accepts a PHP stream resource. During the conversion process a virtual file descriptor is created. This file descriptor is closed automatically when the resource is freed.

The following example lists the contents of a virtual directory:

const std = @import("std");

pub fn scan(dir: std.fs.Dir) !void {
    var iter = dir.iterate();
    while (try iter.next()) |entry| {
        const entry_type = switch (entry.kind) {
            .file => "file",
            .directory => "dir",
            else => "unknown",
        };
        std.debug.print("{s} ({s})\n", .{ entry.name, entry_type });
    }
}
<?php

require_once __DIR__ . '/VirtualFSStream.php';

$m = zigar_use(__DIR__ . '/dir-example-1.zig');

$dir = new VirtualDir([
    'harry-truman.txt' => new VirtualFile,
    'doris-day.txt' => new VirtualFile,
    'red-china.txt' => new VirtualFile,
    'johnnie-ray.txt' => new VirtualFile,
    'south-pacific.txt' => new VirtualFile,
    'walter-winchell.txt' => new VirtualFile,
    'joe-dimaggio.txt' => new VirtualFile,
    'wiki' => new VirtualDir(),
]);
VirtualFSStream::add_root_node('we-didnt-start-the-fire', $dir);
$strm = opendir('vfs://we-didnt-start-the-fire');
$m->scan($strm);
closedir($strm);
harry-truman.txt (file)
doris-day.txt (file)
red-china.txt (file)
johnnie-ray.txt (file)
south-pacific.txt (file)
walter-winchell.txt (file)
joe-dimaggio.txt (file)
wiki (dir)

As is the case with File, closing the directory resource releases the file descriptor created during the conversion process. You can also choose to close the directory on the Zig side with the help of @constCast():

    defer @constCast(&dir).close()

Virtual FS wrapper

VirtualFSStream provides a relatively spartan stream wrapper that lets you to use strings as files. A key requirement for a stream wrapper is that it has a public "path" property. This is necessary because opendir does not save the path within the stream. Without the path, Zigar has no way of handling calls to openat and the likes.

This requirement means that you currently cannot pass a stream of a real directory in the file system:

<?php

require_once __DIR__ . '/VirtualFSStream.php';

$m = zigar_use(__DIR__ . '/dir-example-1.zig');

$strm = opendir(__DIR__);
$m->scan($strm);
closedir($strm);
PHP Fatal error:  Uncaught Exception: args[0]: stream wrapper does not have the property 'path' (zig) in /home/rwiggum/examples/dir-example-1b.php:8

A workaround will be implemented in the next release of Zigar. Getting the path from a file descriptor is non-trivial so it's deferred for now.

Opening a file

As VirtualFSStream::dir_opendir() does save the path to $this, we're able to use std.fs.Dir.openFile to open a file using just its name:

const std = @import("std");

pub fn print(dir: std.fs.Dir, name: []const u8) !void {
    var file = try dir.openFile(name, .{});
    defer file.close();
    const stdout = std.io.getStdOut();
    var buffer: [1024]u8 = undefined;
    while (true) {
        const len = try file.read(&buffer);
        if (len == 0) break;
        _ = try stdout.write(buffer[0..len]);
    }
    _ = try stdout.write("\n");
}
<?php

require_once __DIR__ . '/VirtualFSStream.php';

$m = zigar_use(__DIR__ . '/dir-example-2.zig');

$dir = new VirtualDir([
    'harry-truman.txt' => new VirtualFile('The 33rd president of the United States'),
    'doris-day.txt' => new VirtualFile('A shining star of the movie musicals of the 1950s'),
    'red-china.txt' => new VirtualFile('Communist victory in China’s 1945-49 civil war led to the establishment of the People’s Republic of China'),
    'johnnie-ray.txt' => new VirtualFile('The Elvis of the early 1950s'),
    'south-pacific.txt' => new VirtualFile('Rodgers and Hammerstein musical'),
    'walter-winchell.txt' => new VirtualFile('A journalist and radio host whose mix of news and gossip attracted the attention of Americans from the 1930s through the 1950s'),
    'joe-dimaggio.txt' => new VirtualFile('Baseball star with the New York Yankees'),
    'wiki' => new VirtualDir(),
]);
VirtualFSStream::add_root_node('we-didnt-start-the-fire', $dir);
$strm = opendir('vfs://we-didnt-start-the-fire');
$m->print($strm, 'harry-truman.txt');
$m->print($strm, 'joe-dimaggio.txt');
closedir($strm);
The 33rd president of the United States
Baseball star with the New York Yankees

Note:

Calling std.fs.Dir.iterate() with a virtual directory will crash on Linux on non-x86 platforms due to the use of direct syscalls.


Interface structs | Directory interface