9P-FILE(3)
π 9P-FILE(3) β the Library Functions Manual moment π
okay so this is a page from the Library Functions Manual, bestie, and it's all about the in-memory file hierarchy crew in <9p.h>. Buckle up, we're going in π
β¨ NAME β¨
Tree, alloctree, freetree, File, createfile, closefile, removefile, walkfile, opendirfile, readdirfile, closedirfile, hasperm β literally the whole in-memory file hierarchy. that's the vibe. π¦
πΈ SYNOPSIS πΈ
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
typedef struct File
{
Ref;
Dir;
void*aux;
...
} File;
typedef struct Tree
{
File *root;
...
} Tree;
Tree* alloctree(char *uid, char *gid, ulong mode,
void (*destroy)(File*))
void freetree(Tree *tree)
File* createfile(File *dir, char *name, char *uid,
ulong mode, void *aux)
int removefile(File *file)
void closefile(File *file)
File* walkfile(File *dir, char *path)
Readdir* opendirfile(File *dir)
long readdirfile(Readdir *rdir, char *buf, long n)
void closedirfile(Readdir *rdir)
int hasperm(File *file, char *uid, int p)
like, look at that signature block. she's giving structure. she's giving ... at the end of both structs because there's more and we're not gonna spell it out. iconic π₯
π DESCRIPTION π
Files and Trees give you an in-memory file hierarchy, and the whole point of them is to be used inside 9P file servers. no cap. π«Ά
π the tree itself
alloctreeβ creates a brand-new tree of files. the root of the tree (which is also therootelement in the structure) gets modemode, and it's owned by useruidand groupgid. thedestroyfunction pointer gets used wheneverFilestructures are freed β more on that in a sec, bestie.freetreeβ destroys the whole tree. bye bestie π
π making files
Files (directories included!) other than the root get made with createfile. it attempts to create a file named name inside the directory dir. if it actually gets created, the file will have owner uid and inherit its group from the directory. the mode and the permissions of dir get used to calculate the permission bits for the new file, exactly the way it's described in open(9p). and yes β it is permissible for name to be a slash-separated path rather than a single element. go off π¦
π§ removing + walking
removefileβ takes a file out of the file tree. important: the file does not get freed until the last reference to it has been removed. directories may only be removed when they're empty (respect the boundaries, queen π). returns zero on success,-1on error. and honestly it's correct to think ofremovefileasclosefilewith the extra side effect of removing the file when possible.walkfileβ evaluatespathrelative to the directorydirand returns the resulting file, or zero if the named file (or any intermediate element) doesn't exist. no file, no problem, just zero.
π aux + reference counting (pay attention here)
the File structure's aux pointer is free real estate β the client can use it for per-File storage.
files are reference-counted: if it's not zero, destroy (the one you specified in the call to alloctree) will be called for each file when its last reference is removed, or when the tree is freed. destroy should take care of any cleanup related to aux. π§Ή
when you create new file references by copying pointers, callincref(seelock(3)) to update the reference count. when you're noting the removal of a reference to a file, callclosefile.
createfile and walkfile return new references. meanwhile removefile, closefile, and walkfile (but not createfile) consume the reference you pass in. yeah. the asymmetry is real. that's the whole game π
π reading directories
directories can be read, and reading one yields a directory entry structure (see stat(9p)) for every file in that directory. π
because concurrent directory reading is a thing, clients have to grab a Readdir structure by calling opendirfile on the directory. after that, each call to readdirfile yields an integral number of machine-independent stat buffers, and keeps going until end of directory. when you're done, call closedirfile to free the Readdir. clean up after yourself, bestie π
β permissions with hasperm
hasperm does permission checking, but keep it real β it's simplistic. it assumes only one-user groups, named by uid. it returns non-zero if uid has permission p according to file->mode, where p is a bitwise-or of AREAD, AWRITE and AEXEC. πΈ
9P servers written using File trees do the standard permission checks automatically, so you'd only call hasperm explicitly when you want additional checks. and a 9P server is free to link against a different hasperm implementation if it wants more complex groups. flexible. we love to see it. β¨
π₯ EXAMPLE π₯
the following code correctly handles references when elementwise walking a path and creating a file. study her. she's the blueprint. π
f = tree->root;
incref(f);
for(i=0; i<n && f!=nil; i++)
f = walkfile(f, elem[i]);
if(f == nil)
return nil;
nf = createfile(f, "foo", "nls", 0666, nil);
closefile(f);
return nf;
see how walkfile eats the reference and hands back a new one each loop? and then closefile(f) right before returning nf? that's the reference discipline, fr fr π«Ά
π¦ SOURCE π¦
/src/lib9p/file.c
π SEE ALSO π
π BUGS π
the reference counting is cumbersome. that's it. that's the bug note. we said what we said. π
okay that's the whole page, bestie β signing off from the 9P-FILE(3) page of the Library Functions Manual, version 9P-FILE(3), as the footer says. love u, go count some references ππβ¨
π¦ where this page comes from
- alpine 3.24: plan9port-doc 0_git20260208-r0 Β· LPL-1.02
- arch rolling: plan9port 20261021-2 Β· custom
- nixos 26.05: plan9port 0-unstable-2025-11-10
- nixos 26.05: plan9port-wayland 0-unstable-2025-11-26
- nixpkgs unstable: plan9port 0-unstable-2025-11-10
- nixpkgs unstable: plan9port-wayland 0-unstable-2025-11-26
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms