Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
116 lines
3.2 KiB
C
116 lines
3.2 KiB
C
// schattr -- attach metadata to files, and ask the filesystem about it.
|
|
//
|
|
// schattr set <file> <name> <value> attach a value
|
|
// schattr get <file> <name> read it back
|
|
// schattr rm <file> <name> remove it
|
|
// schattr index <name> start indexing that attribute
|
|
// schattr find <name> <value> every object carrying that value
|
|
//
|
|
// `find` is the point of the rest. Without an index it is refused rather than
|
|
// answered by walking every file, because a query that silently degrades into a
|
|
// full scan is worse than one that says it cannot help: the first teaches you to
|
|
// use it on a filesystem where it will not scale.
|
|
//
|
|
// Indexing covers values written *after* the index is declared. There is no
|
|
// reindexing pass, so declare the index first.
|
|
|
|
#include "core/types.h"
|
|
#include "uapi/user.h"
|
|
|
|
static void
|
|
puts_(const char *s)
|
|
{
|
|
int n = 0;
|
|
while (s[n]) n++;
|
|
write(1, (void *)s, n);
|
|
}
|
|
|
|
static void
|
|
putn_(unsigned long long v)
|
|
{
|
|
char buf[24];
|
|
int i = 0;
|
|
if (v == 0) { write(1, "0", 1); return; }
|
|
while (v > 0 && i < (int)sizeof(buf)) { buf[i++] = '0' + (int)(v % 10); v /= 10; }
|
|
while (i--) write(1, &buf[i], 1);
|
|
}
|
|
|
|
static int
|
|
streq(const char *a, const char *b)
|
|
{
|
|
while (*a && *a == *b) { a++; b++; }
|
|
return *a == *b;
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
if (argc < 2) {
|
|
puts_("usage: schattr set|get|rm <file> <name> [value]\n");
|
|
puts_(" schattr index <name>\n");
|
|
puts_(" schattr find <name> <value>\n");
|
|
exit();
|
|
}
|
|
|
|
if (streq(argv[1], "set") && argc == 5) {
|
|
int len = 0;
|
|
while (argv[4][len]) len++;
|
|
if (setxattr(argv[2], argv[3], argv[4], len, 0) < 0) {
|
|
puts_("schattr: set failed\n");
|
|
exit();
|
|
}
|
|
exit();
|
|
}
|
|
|
|
if (streq(argv[1], "get") && argc == 4) {
|
|
char val[256];
|
|
int n = getxattr(argv[2], argv[3], val, sizeof(val) - 1);
|
|
if (n < 0) {
|
|
puts_("schattr: no such attribute\n");
|
|
exit();
|
|
}
|
|
val[n] = '\0';
|
|
puts_(val);
|
|
puts_("\n");
|
|
exit();
|
|
}
|
|
|
|
if (streq(argv[1], "rm") && argc == 4) {
|
|
if (removexattr(argv[2], argv[3]) < 0) {
|
|
puts_("schattr: remove failed\n");
|
|
exit();
|
|
}
|
|
exit();
|
|
}
|
|
|
|
if (streq(argv[1], "index") && argc == 3) {
|
|
if (schfs_index(argv[2]) < 0) {
|
|
puts_("schattr: could not create the index\n");
|
|
exit();
|
|
}
|
|
puts_("schattr: indexing "); puts_(argv[2]);
|
|
puts_(" from now on\n");
|
|
exit();
|
|
}
|
|
|
|
if (streq(argv[1], "find") && argc == 4) {
|
|
unsigned long long ids[64];
|
|
int n = schfs_query(argv[2], argv[3], ids, 64);
|
|
if (n < 0) {
|
|
puts_("schattr: no index on "); puts_(argv[2]);
|
|
puts_(" -- declare one with `schattr index` first\n");
|
|
exit();
|
|
}
|
|
putn_((unsigned long long)n);
|
|
puts_(n == 1 ? " object:\n" : " objects:\n");
|
|
for (int i = 0; i < n; i++) {
|
|
puts_(" #");
|
|
putn_(ids[i]);
|
|
puts_("\n");
|
|
}
|
|
exit();
|
|
}
|
|
|
|
puts_("schattr: bad usage\n");
|
|
exit();
|
|
}
|