wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit b5c72baed6d135d3e70635f469623a11884bc4a2
parent b80f313cbc8a5f3f09fed78e4196bd2e6fe82249
Author: Anselm R. Garbe <garbeam@wmii.de>
Date:   Mon, 19 Jun 2006 10:58:08 +0200

moved fs2.c to fs.c (if you need fs.c for reference, use hg update <changeset before this>


Diffstat:
cmd/wm/Makefile | 2+-
cmd/wm/fs.c | 2202+++++++++++++++++++++++++------------------------------------------------------
cmd/wm/fs2.c | 774-------------------------------------------------------------------------------
3 files changed, 686 insertions(+), 2292 deletions(-)

diff --git a/cmd/wm/Makefile b/cmd/wm/Makefile @@ -9,7 +9,7 @@ LDFLAGS += -L../../liblitz -llitz -L../../libixp -lixp -L../../libcext -lcext - # Solaris # LDFLAGS += -lsocket -SRC = area.c bar.c client.c column.c event.c frame.c fs2.c geom.c \ +SRC = area.c bar.c client.c column.c event.c frame.c fs.c geom.c \ key.c mouse.c rule.c view.c wm.c OBJ = ${SRC:.c=.o} diff --git a/cmd/wm/fs.c b/cmd/wm/fs.c @@ -1,1611 +1,779 @@ /* - * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> + * (C)opyright MMVI Kris Maglione <bsdaemon at comcast dot net> * See LICENSE file for license details. */ -#include <stdarg.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <sys/types.h> #include <time.h> -#include <unistd.h> -#include <X11/Xatom.h> -#include <X11/Xproto.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <sys/socket.h> #include "wm.h" -static char E9pversion[] = "9P version not supported"; -static char Enoperm[] = "permission denied"; -static char Enofile[] = "file not found"; -static char Efidinuse[] = "fid in use"; -static char Enomode[] = "mode not supported"; -static char Enofunc[] = "function not supported"; -static char Enocommand[] = "command not supported"; -static char Ebadvalue[] = "bad value"; - -enum { WMII_IOUNIT = 2048 }; - -/* - * filesystem specification - * / FsDroot - * /def/ FsDdef - * /def/border FsFborder 0..n - * /def/font FsFfont xlib font name - * /def/selcolors FsFselcolors selected colors - * /def/normcolors FsFnormcolors normal colors - * /def/tagrules FsFtagrules tagging rules - * /def/keys FsFkeys keys - * /def/grabmod FsFgrabmod grab modifier - * /def/colrules FsFcolrules column rules - * /bar/ FsDbars - * /bar/lab/ FsDbar - * /bar/lab/data FsFdata <arbitrary data which gets displayed> - * /bar/lab/colors FsFcolors <#RRGGBB> <#RRGGBB> <#RRGGBB> - * /client/ FsDclients - * /client/1/ FsDGclient see /tag/X/X/X/X/ namespace below - * /event FsFevent - * /ctl FsFctl command interface (root) - * /tag FsDtag - * /tag/X/ FsDview - * /tag/X/ctl FsFctl command interface (tag) - * /tag/X/name FsFname current view name - * /tag/X/index FsFindex current view name - * /tag/X/sel/ FsDarea - * /tag/X/1/ FsDarea - * /tag/X/1/ctl FsFctl command interface (area) - * /tag/X/1/mode FsFmode column mode - * /tag/X/1/sel/ FsDclient - * /tag/X/1/1/props FsFprops Class:instance of client - * /tag/X/1/1/index FsFindex index of client in /client - * /tag/X/1/1/name FsFname name of client - * /tag/X/1/1/tags FsFtags tag of client - * /tag/X/1/geom FsFgeom geometry of client - * /tag/X/1/ctl FsFctl command interface (client) - */ -const char *dirnames[] = { +/* Datatypes: */ +typedef struct Dirtab Dirtab; +struct Dirtab { + char *name; + unsigned char qtype; + unsigned int type; + unsigned int perm; }; -/* IXP stuff */ - -PackedQid root_qid; +typedef struct FileId FileId; +struct FileId { + FileId *next; + union { + void *ref; + Bar *bar; + Bar **bar_p; + View *view; + Client *client; + Rules *rule; + BlitzColor *col; + }; + unsigned int id; + unsigned int index; + Dirtab tab; + unsigned short nref; +}; -/* - * Qid->path is calculated related to the index of the associated structure. - * i1 is associated to tag, key, global client, or bar - * i2 is associated to area - * i3 is associated to client - * ie /view/sel/ctl is i1id = sel tag id, i2id = sel area id , i3id = 0 (no id) - */ +/* Function prototypes */ +static void dostat(Stat *s, unsigned int len, FileId *f); + +/* Error messages */ +static char + Enoperm[] = "permission denied", + Enofile[] = "file not found", + Ebadvalue[] = "bad value", + Einterrupted[] = "interrupted", + Enocommand[] = "command not supported"; +/* Old error messages: + Eisdir[] = "file is a directory", + Efidinuse[] = "fid in use", + Enomode[] = "mode not supported", + Enofunc[] = "function not supported", +*/ + +/* Constants */ +enum { /* Dirs */ + FsRoot, FsDClient, FsDClients, FsDBar, + FsDSClient, FsDTag, FsDTags, + /* Files */ + FsFBar, FsFBorder, FsFCNorm, FsFCSel, + FsFCctl, FsFCindex, FsFColRules, FsFCtags, + FsFEvent, FsFFont, FsFKeys, FsFRctl, + FsFTagRules, FsFTctl, FsFTindex, FsFprops, + RsFFont +}; -static unsigned char -dir_of_qid(PackedQid wqid[IXP_MAX_WELEM], unsigned short qsel) -{ - return qsel ? wqid[qsel - 1].ptype : FsDroot; -} +/* QID Macros */ +#define QID(t, i) (((long long)((t)&0xFF)<<32)|((i)&0xFFFFFFFF)) +/* Will I ever need these macros? + * I don't think so. */ +#define TYPE(q) ((q)>>32&0xFF) +#define ID(q) ((q)&0xFFFFFFFF) + +/* Global vars */ +FileId *free_fileid = nil; +Req *pending_event_reads = nil; +P9Srv p9srv = { + .open= fs_open, + .walk= fs_walk, + .read= fs_read, + .stat= fs_stat, + .write= fs_write, + .clunk= fs_clunk, + .flush= fs_flush, + .attach=fs_attach, + .create=fs_create, + .remove=fs_remove, + .freefid=fs_freefid +}; -static Bool -unpack_qpath(PackedQid wqid[IXP_MAX_WELEM], unsigned short qsel, - unsigned char *type, void **i1, void **i2, void **i3) -{ - *i1 = *i2 = *i3 = nil; - *type = wqid[qsel].ptype; +/* ad-hoc file tree. Empty names ("") indicate a dynamic entry to be filled + * in by lookup_file */ +static Dirtab +dirtab_root[]= {{".", QTDIR, FsRoot, 0500|DMDIR }, + {"rbar", QTDIR, FsDBar, 0700|DMDIR }, + {"lbar", QTDIR, FsDBar, 0700|DMDIR }, + {"client", QTDIR, FsDClients, 0500|DMDIR }, + {"tag", QTDIR, FsDTags, 0500|DMDIR }, + {"ctl", QTAPPEND, FsFRctl, 0600|DMAPPEND }, + {"border", QTFILE, FsFBorder, 0600 }, + {"colrules", QTFILE, FsFColRules, 0600 }, + {"event", QTFILE, FsFEvent, 0600 }, + {"font", QTFILE, FsFFont, 0600 }, + {"keys", QTFILE, FsFKeys, 0600 }, + {"normcolors", QTFILE, FsFCNorm, 0600 }, + {"selcolors", QTFILE, FsFCSel, 0600 }, + {"tagrules", QTFILE, FsFTagRules, 0600 }, + {nil}}, +dirtab_clients[]={{".", QTDIR, FsDClients, 0500|DMDIR }, + {"", QTDIR, FsDClient, 0500|DMDIR }, + {nil}}, +dirtab_client[]= {{".", QTDIR, FsDClient, 0500|DMDIR }, + {"ctl", QTAPPEND, FsFCctl, 0200|DMAPPEND }, + {"tags", QTFILE, FsFCtags, 0600 }, + {"props", QTFILE, FsFprops, 0400 }, + {nil}}, +dirtab_sclient[]={{".", QTDIR, FsDSClient, 0500|DMDIR }, + {"ctl", QTAPPEND, FsFCctl, 0200|DMAPPEND }, + {"index", QTFILE, FsFCindex, 0400 }, + {"tags", QTFILE, FsFCtags, 0600 }, + {"props", QTFILE, FsFprops, 0400 }, + {nil}}, +dirtab_bar[]= {{".", QTDIR, FsDBar, 0700|DMDIR }, + {"", QTFILE, FsFBar, 0600 }, + {nil}}, +dirtab_tags[]= {{".", QTDIR, FsDTags, 0500|DMDIR }, + {"", QTDIR, FsDTag, 0500|DMDIR }, + {nil}}, +dirtab_tag[]= {{".", QTDIR, FsDTag, 0500|DMDIR }, + {"ctl", QTAPPEND, FsFTctl, 0200|DMAPPEND }, + {"index", QTFILE, FsFTindex, 0400 }, + {nil}}; +/* Writing the lists separately and using an array of their references + * removes the need for casting and allows for C90 conformance, + * since otherwise we would need to use compound literals */ +static Dirtab *dirtab[] = { + [FsRoot] dirtab_root, + [FsDBar] dirtab_bar, + [FsDClients] dirtab_clients, + [FsDClient] dirtab_client, + [FsDSClient] dirtab_sclient, + [FsDTags] dirtab_tags, + [FsDTag] dirtab_tag +}; - if(wqid[qsel].i1id) { - unsigned char dir_type = dir_of_qid(wqid, qsel); - if((dir_type == FsDGclient) || (dir_type == FsDclients)) - *i1 = (void *)client_of_id(wqid[qsel].i1id); - else { - switch(*type) { - case FsFdata: - case FsFcolors: - case FsDbar: *i1 = (void *)bar_of_id(wqid[qsel].i1id); break; - default: *i1 = (void *)view_of_id(wqid[qsel].i1id); break; - } - } - if(!*i1) - return False; - if(wqid[qsel].i2id) { - if(!(*i2 = (void *)area_of_id(VIEW(*i1), wqid[qsel].i2id))) - return False; - if(wqid[qsel].i3id) - if(!(*i3 = (void *)frame_of_id(AREA(*i2), wqid[qsel].i3id))) - return False; +/* get_file/free_file save and reuse old FileId structs + * since so many of them are needed for so many + * purposes */ +static FileId * +get_file() { + FileId *temp; + if(!free_fileid) { + unsigned int i = 15; + temp = cext_emallocz(sizeof(FileId) * i); + for(; i; i--) { + temp->next = free_fileid; + free_fileid = temp++; } } - return True; + temp = free_fileid; + free_fileid = temp->next; + temp->nref = 1; + temp->next = nil; + return temp; } -static char * -name_of_qid(PackedQid wqid[IXP_MAX_WELEM], unsigned short qsel) -{ - unsigned char dir_type, type; - void *i1, *i2, *i3; - static char buf[256]; - - unpack_qpath(wqid, qsel, &type, &i1, &i2, &i3); - dir_type = dir_of_qid(wqid, qsel); - - switch(type) { - case FsDroot: return "/"; break; - case FsDdef: return "def"; break; - case FsDtag: return "tag"; break; - case FsDclients: return "client"; break; - case FsDbars: return "bar"; break; - case FsDview: - if(dir_type != FsDtag) - return nil; - if(VIEW(i1) == sel) - return "sel"; - return VIEW(i1)->name; - break; - case FsDbar: - if(!i1) - return nil; - return BAR(i1)->name; - break; - case FsDarea: - if(!i1 || !i2) - return nil; - if(VIEW(i1)->sel == AREA(i2)) - return "sel"; - snprintf(buf, sizeof(buf), "%u", idx_of_area(i2)); - return buf; - break; - case FsDGclient: - if(!i1) - return nil; - snprintf(buf, sizeof(buf), "%u", idx_of_client(CLIENT(i1))); - return buf; - break; - case FsDclient: - if(!i2 || !i3) - return nil; - if(AREA(i2)->sel == FRAME(i3)) - return "sel"; - snprintf(buf, sizeof(buf), "%u", idx_of_frame(i3)); - return buf; - break; - case FsFselcolors: return "selcolors"; break; - case FsFnormcolors: return "normcolors"; break; - case FsFfont: return "font"; break; - case FsFcolrules: return "colrules"; break; - case FsFgrabmod: return "grabmod"; break; - case FsFtagrules: return "tagrules"; break; - case FsFkeys: return "keys"; break; - case FsFcolors: return "colors"; break; - case FsFdata: - if(!i1) - return nil; - return "data"; - break; - case FsFctl: return "ctl"; break; - case FsFborder: return "border"; break; - case FsFgeom: - if((dir_type == FsDclient) && (!i1 || !i2 || !i3)) - return nil; - else if(!i1) - return nil; - return "geom"; - break; - case FsFtags: - if((dir_type == FsDclient) && (!i1 || !i2 || !i3)) - return nil; - else if((dir_type == FsDGclient) && !i1) - return nil; - return "tags"; - break; - case FsFprops: - case FsFindex: - case FsFname: - if((dir_type == FsDclient) && (!i1 || !i2 || !i3)) - return nil; - else if(!i1) - return nil; - switch(type) { - case FsFname: - return "name"; - break; - case FsFprops: - return "props"; - break; - case FsFindex: - return "index"; - break; - default: - break; - } - break; - case FsFmode: - if((dir_type == FsDarea) && (!i1 || !i2)) - return nil; - return "mode"; - break; - case FsFevent: return "event"; break; - default: return nil; break; - } - return nil; +/* Convenience func: */ +/* ugly, though... */ +FileId * +push_file(FileId ***last) { + FileId *ret = get_file(); + **last = ret; + *last = &ret->next; + return ret; } -static unsigned char -type_of_name(PackedQid wqid[IXP_MAX_WELEM], unsigned short qsel, char *name) -{ - unsigned char dir_type; - void *i1, *i2, *i3; - unsigned int i; - - unpack_qpath(wqid, qsel, &dir_type, &i1, &i2, &i3); +static void +free_file(FileId *f) { + if(--f->nref) + return; + free(f->tab.name); + f->next = free_fileid; + free_fileid = f; +} - if(!name || !name[0] || !strncmp(name, "/", 2)) - return FsDroot; - if(!strncmp(name, "tag", 4)) - return FsDtag; - if(!strncmp(name, "tags", 5)) - return FsFtags; - if(!strncmp(name, "client", 7)) - return FsDclients; - if(!strncmp(name, "", 5)) - return FsDview; - if(!strncmp(name, "bar", 4)) - return FsDbars; - if(!strncmp(name, "def", 4)) - return FsDdef; - if(!strncmp(name, "ctl", 4)) - return FsFctl; - if(!strncmp(name, "event", 6)) - return FsFevent; - if(!strncmp(name, "props", 6)) - return FsFprops; - if(!strncmp(name, "index", 6)) - return FsFindex; - if(!strncmp(name, "name", 5)) - return FsFname; - if(!strncmp(name, "border", 7)) - return FsFborder; - if(!strncmp(name, "geom", 5)) - return FsFgeom; - if(!strncmp(name, "colors", 7)) - return FsFcolors; - if(!strncmp(name, "selcolors", 10)) - return FsFselcolors; - if(!strncmp(name, "normcolors", 11)) - return FsFnormcolors; - if(!strncmp(name, "font", 5)) - return FsFfont; - if(!strncmp(name, "colrules", 9)) - return FsFcolrules; - if(!strncmp(name, "grabmod", 8)) - return FsFgrabmod; - if(!strncmp(name, "keys", 5)) - return FsFkeys; - if(!strncmp(name, "tagrules", 9)) - return FsFtagrules; - if(!strncmp(name, "data", 5)) - return FsFdata; - if(!strncmp(name, "mode", 5)) - return FsFmode; - if((dir_type == FsDbars) && bar_of_name(name)) - return FsDbar; - if((dir_type == FsDtag) && view_of_name(name)) - return FsDview; - if(!strncmp(name, "sel", 4)) - goto dyndir; - if(sscanf(name, "%d", &i) != 1) - return FsLast; -dyndir: - switch(dir_type) { - case FsDbars: return FsDbar; break; - case FsDtag: return FsDview; break; - case FsDview: return FsDarea; break; - case FsDclients: return FsDGclient; break; - case FsDarea: return FsDclient; break; - } - return FsLast; +/* This function's name belies it's true purpose. It increases + * the reference count of the FileId list */ +static void +clone_files(FileId *f) { + for(; f; f=f->next) + cext_assert(f->nref++); } -static PackedQid * -qid_of_name(PackedQid wqid[IXP_MAX_WELEM], unsigned short qsel, char *name) +/* All lookups and directory organization should be performed through + * lookup_file, mostly through the dirtabs[] tree. */ +static FileId * +lookup_file(FileId *parent, char *name) { - void *i1, *i2, *i3; - int i; - unsigned char dir_type, type; + FileId *ret, *file, **last; + Dirtab *dir; Client *c; - static PackedQid new; - memset(&new, 0, sizeof(PackedQid)); + View *v; + Bar *b; + unsigned int i, id; - unpack_qpath(wqid, qsel, &dir_type, &i1, &i2, &i3); - type = type_of_name(wqid, qsel, name); + if(!(parent->tab.perm & DMDIR)) + return nil; - switch(type) { - case FsDroot: - new = root_qid; - break; - case FsDdef: - case FsDtag: - case FsDclients: - case FsDbars: - if(dir_type != FsDroot) - return nil; - new.type= IXP_QTDIR; - new.ptype= type; - break; - case FsDview: - if((dir_type != FsDtag) || !view) - return nil; - View *v = strncmp(name, "sel", 4) ? view_of_name(name) : sel; - if(!v) - return nil; - new.type= IXP_QTDIR; - new.ptype= FsDview; - new.i1id= v->id; - break; - case FsDarea: - if(!i1 || dir_type != FsDview) - return nil; - { - View *p = VIEW(i1); - new.type= IXP_QTDIR; - new.ptype= FsDarea; - new.i1id= p->id; - if(!strncmp(name, "sel", 4)) { - new.i2id= p->sel->id; - } - else { - Area *a; - if(sscanf(name, "%d", &i) != 1) - return nil; - for(a=p->area; i && a; a=a->next, i--); - if(!a) - return nil; - new.i2id= a->id; - } - } - break; - case FsDclient: - if(!i1 || !i2 || dir_type != FsDarea) - return nil; - { - View *p = VIEW(i1); - Area *a = AREA(i2); - new.type= IXP_QTDIR; - new.ptype= FsDclient; - new.i1id= p->id; - new.i2id= a->id; - if(!strncmp(name, "sel", 4)) { - if(!a->frame) - return nil; - new.i3id= a->sel->id; + dir = dirtab[parent->tab.type]; + last = &ret; + ret = nil; + + for(; dir->name; dir++) { + /* Dynamic dirs */ + if(!*dir->name) { /* strlen(dir->name) == 0 */ + switch(parent->tab.type) { + case FsDClients: + if(!name || !strncmp(name, "sel", 4)) { + if((c = sel_client())) { + file = get_file(); + *last = file; + last = &file->next; + file->ref = c; + file->id = c->id; + file->index = idx_of_client(c); + file->tab = *dirtab[FsDSClient]; + file->tab.name = strdup("sel"); + }if(name) goto LastItem; + } + if(name) { + id = (unsigned int)strtol(name, &name, 10); + if(*name) goto NextItem; + } + + i=0; + for(c=client; c; c=c->next, i++) { + if(!name || i == id) { + file = get_file(); + *last = file; + last = &file->next; + file->ref = c; + file->id = c->id; + file->tab = *dir; + asprintf(&file->tab.name, "%d", i); + if(name) goto LastItem; + } + } + break; + case FsDTags: + if(!name || !strncmp(name, "sel", 4)) { + if(sel) { + file = get_file(); + *last = file; + last = &file->next; + file->ref = sel; + file->id = sel->id; + file->tab = *dir; + file->tab.name = strdup("sel"); + }if(name) goto LastItem; + } + for(v=view; v; v=v->next) { + if(!name || !strcmp(name, v->name)) { + file = get_file(); + *last = file; + last = &file->next; + file->ref = v; + file->id = v->id; + file->tab = *dir; + file->tab.name = strdup(v->name); + if(name) goto LastItem; + } + } + break; + case FsDBar: + for(b=*parent->bar_p; b; b=b->next) { + if(!name || !strcmp(name, b->name)) { + file = get_file(); + *last = file; + last = &file->next; + file->ref = b; + file->id = b->id; + file->tab = *dir; + file->tab.name = strdup(b->name); + if(name) goto LastItem; + } + } + break; } - else { - Frame *f; - if(sscanf(name, "%d", &i) != 1) - return nil; - for(f=a->frame; f && i; f=f->anext, i--); - if(!f) - return nil; - new.i3id= f->id; + }else /* Static dirs */ + if(!name || !strcmp(name, dir->name)) { + file = get_file(); + *last = file; + last = &file->next; + file->id = 0; + file->ref = parent->ref; + file->index = parent->index; + file->tab = *dir; + file->tab.name = strdup(file->tab.name); + + /* Special considerations: */ + switch(file->tab.type) { + case FsDBar: + if(!strncmp(file->tab.name, "lbar", 5)) + file->ref = &lbar; + else + file->ref = &rbar; + break; + case FsFColRules: + file->ref = &def.colrules; + break; + case FsFTagRules: + file->ref = &def.tagrules; + break; + case FsFCSel: + file->ref = &def.selcolor; + break; + case FsFCNorm: + file->ref = &def.normcolor; + break; } + if(name) goto LastItem; } - break; - case FsDGclient: - if(dir_type != FsDclients) - return nil; - if(sscanf(name, "%d", &i) != 1) - return nil; - for(c=client; i && c; c=c->next, i--); - if(!c) - return nil; - new.type= IXP_QTDIR; - new.ptype= FsDGclient; - new.i1id= c->id; - break; - case FsDbar: - if(dir_type != FsDbars) - return nil; - { - Bar *l; - if(!(l = bar_of_name(name))) - return nil; - new.type= IXP_QTDIR; - new.ptype= FsDbar; - new.i1id= l->id; - } - break; - case FsFdata: - case FsFcolors: - if(!i1 || (dir_type != FsDbar)) - return nil; - goto Mkfile; - break; - case FsFmode: - if((dir_type == FsDarea) && (!i1 || !i2)) - return nil; - goto Mkfile; - break; - case FsFgeom: - case FsFindex: - if(dir_type == FsDview) - return nil; - case FsFname: - case FsFprops: - if(dir_type == FsDroot) - return nil; - case FsFtags: - if((dir_type == FsDclient) && ((!i1 || !i2 || !i3))) - return nil; - else if((dir_type == FsDGclient) && !i1) - return nil; - goto Mkfile; - break; - case FsFborder: - case FsFgrabmod: - case FsFfont: - case FsFcolrules: - case FsFtagrules: - case FsFselcolors: - case FsFnormcolors: - case FsFkeys: - if(dir_type != FsDdef) - return nil; - case FsFctl: - case FsFevent: -Mkfile: - new = wqid[qsel]; - new.type = IXP_QTFILE; - new.ptype = type; - break; - default: - return nil; - break; + NextItem: + continue; } - return &new; +LastItem: + *last = nil; + return ret; } -static unsigned int -pack_stat(Stat *stat, PackedQid wqid[IXP_MAX_WELEM], unsigned short qsel, - char *name, unsigned long long length, unsigned int mode) -{ - PackedQid *qid; - stat->mode = mode; - stat->atime = stat->mtime = time(0); - cext_strlcpy(stat->uid, getenv("USER"), sizeof(stat->uid)); - cext_strlcpy(stat->gid, getenv("USER"), sizeof(stat->gid)); - cext_strlcpy(stat->muid, getenv("USER"), sizeof(stat->muid)); - - cext_strlcpy(stat->name, name, sizeof(stat->name)); - stat->length = length; - if((qid = qid_of_name(wqid, qsel ? qsel - 1 : 0, name))) - stat->qid = qid->qid; - - return ixp_sizeof_stat(stat); -} - -static unsigned int -stat_of_name(Stat *stat, char *name, PackedQid wqid[IXP_MAX_WELEM], unsigned short qsel) -{ - unsigned char dir_type, type; - void *i1, *i2, *i3; - char buf[256]; - XRectangle fr; - Frame *f; +void +fs_walk(Req *r) { + FileId *f, *nf; + int i; - if(!unpack_qpath(wqid, qsel, &dir_type, &i1, &i2, &i3)) - return 0; - type = type_of_name(wqid, qsel, name); + f = r->fid->aux; - switch (type) { - case FsDclient: - case FsDGclient: - case FsDarea: - case FsDview: - case FsDdef: - case FsDclients: - case FsDbar: - case FsDroot: - case FsDtag: - return pack_stat(stat, wqid, qsel, name, 0, IXP_DMDIR | IXP_DMREAD | IXP_DMEXEC); - break; - case FsDbars: - return pack_stat(stat, wqid, qsel, name, 0, IXP_DMDIR | IXP_DMREAD | IXP_DMWRITE | IXP_DMEXEC); - break; - case FsFctl: - return pack_stat(stat, wqid, qsel, name, 0, IXP_DMWRITE); - break; - case FsFevent: - return pack_stat(stat, wqid, qsel, name, 0, IXP_DMREAD | IXP_DMWRITE); - break; - case FsFborder: - snprintf(buf, sizeof(buf), "%d", def.border); - return pack_stat(stat, wqid, qsel, name, strlen(buf), IXP_DMREAD | IXP_DMWRITE); - break; - case FsFgeom: - if(dir_type == FsDclient) - fr = FRAME(i3)->rect; - else if(CLIENT(i1)->frame) - fr = CLIENT(i1)->sel->rect; - else - fr = CLIENT(i1)->rect; - snprintf(buf, sizeof(buf), "%d %d %d %d", fr.x, fr.y, fr.width, fr.height); - return pack_stat(stat, wqid, qsel, name, strlen(buf), IXP_DMREAD | IXP_DMWRITE); - break; - case FsFprops: - if(dir_type == FsDclient) { - f = FRAME(i3); - return pack_stat(stat, wqid, qsel, name, strlen(f->client->props), IXP_DMREAD); - } - else - return pack_stat(stat, wqid, qsel, name, strlen(CLIENT(i1)->props), IXP_DMREAD); - break; - case FsFindex: - switch(dir_type) { - case FsDclient: - f = FRAME(i3); - snprintf(buf, sizeof(buf), "%d", idx_of_client(f->client)); - break; - case FsDarea: - snprintf(buf, sizeof(buf), "%d", idx_of_area(i2)); - break; - default: - snprintf(buf, sizeof(buf), "%d", idx_of_client(i1)); - break; - } - return pack_stat(stat, wqid, qsel, name, strlen(buf), IXP_DMREAD); - break; - case FsFname: - if(dir_type == FsDclient) { - f = FRAME(i3); - return pack_stat(stat, wqid, qsel, name, strlen(f->client->name), IXP_DMREAD); + clone_files(f); + for(i=0; i < r->ifcall.nwname; i++) { + if(!strncmp(r->ifcall.wname[i], "..", 3)) { + if(f->next) { + nf=f; + f=f->next; + free_file(nf); + } + }else{ + nf = lookup_file(f, r->ifcall.wname[i]); + if(!nf) + break; + cext_assert(!nf->next); + nf->next = f; + f = nf; } - else if(dir_type == FsDview) - return pack_stat(stat, wqid, qsel, name, - view ? strlen(VIEW(i1)->name) : 0, IXP_DMREAD); - else - return pack_stat(stat, wqid, qsel, name, strlen(CLIENT(i1)->name), IXP_DMREAD); - break; - case FsFtags: - switch(dir_type) { - case FsDclient: - f = FRAME(i3); - return pack_stat(stat, wqid, qsel, name, strlen(f->client->tags), IXP_DMREAD | IXP_DMWRITE); - break; - case FsDGclient: - return pack_stat(stat, wqid, qsel, - name, strlen(CLIENT(i1)->tags), IXP_DMREAD | IXP_DMWRITE); - break; - default: - break; + r->ofcall.wqid[i].type = f->tab.qtype; + r->ofcall.wqid[i].path = QID(f->tab.type, f->id); + } + /* There should be a way to do this on freefid() */ + if(i < r->ifcall.nwname) { + while((nf = f)) { + f=f->next; + free_file(nf); } - break; - case FsFdata: - return pack_stat(stat, wqid, qsel, name, - !BAR(i1)->next ? 0 : strlen(BAR(i1)->data), IXP_DMREAD | IXP_DMWRITE); - break; - case FsFmode: - return pack_stat(stat, wqid, qsel, name, - strlen(str_of_column_mode(AREA(i2)->mode)), - IXP_DMREAD | IXP_DMWRITE); - break; - case FsFcolors: - case FsFselcolors: - case FsFnormcolors: - return pack_stat(stat, wqid, qsel, name, 23, IXP_DMREAD | IXP_DMWRITE); - break; - case FsFkeys: - return pack_stat(stat, wqid, qsel, name, def.keys ? strlen(def.keys) : 0, IXP_DMREAD | IXP_DMWRITE); - break; - case FsFtagrules: - return pack_stat(stat, wqid, qsel, name, def.tagrules ? strlen(def.tagrules) : 0, IXP_DMREAD | IXP_DMWRITE); - break; - case FsFcolrules: - return pack_stat(stat, wqid, qsel, name, def.colrules ? strlen(def.colrules) : 0, IXP_DMREAD | IXP_DMWRITE); - case FsFfont: - return pack_stat(stat, wqid, qsel, name, strlen(def.font), IXP_DMREAD | IXP_DMWRITE); - case FsFgrabmod: - return pack_stat(stat, wqid, qsel, name, strlen(def.grabmod), IXP_DMREAD | IXP_DMWRITE); - break; + return respond(r, Enofile); } - return 0; -} - -static unsigned int -stat_of_names(unsigned char **p, int *iounit, PackedQid wqid[IXP_MAX_WELEM], unsigned short qsel, ...) -{ - va_list ap; - char *str; - unsigned int n = 0; - Stat stat; - va_start(ap, qsel); - - while((str = va_arg(ap, char *))) { - n += stat_of_name(&stat, str, wqid, qsel); - ixp_pack_stat(p, iounit, &stat); + /* Remove refs for r->fid if no new fid */ + /* If Fids were ref counted, this could be + * done in their decref function */ + if(r->ifcall.fid == r->ifcall.newfid) { + nf=r->fid->aux; + r->fid->aux = f; + while((nf = f)) { + f=f->next; + free_file(nf); + } } - va_end(ap); - return n; + r->newfid->aux = f; + r->ofcall.nwqid = i; + respond(r, nil); } -static char * -xversion(IXPConn *c, Fcall *fcall) -{ - if(strncmp(fcall->version, IXP_VERSION, strlen(IXP_VERSION))) - return E9pversion; - else if(fcall->maxmsg > IXP_MAX_MSG) - fcall->maxmsg = IXP_MAX_MSG; - fcall->id = RVERSION; - ixp_server_respond_fcall(c, fcall); - return nil; +void +fs_stat(Req *r) { + Stat s; + int size; + unsigned char *buf; + + dostat(&s, 0, r->fid->aux); + r->ofcall.nstat = size = ixp_sizeof_stat(&s); + buf = cext_emallocz(size); + r->ofcall.stat = buf; + + ixp_pack_stat(&buf, &size, &s); + respond(r, nil); } -static char * -xattach(IXPConn *c, Fcall *fcall) -{ - IXPMap *new = cext_emallocz(sizeof(IXPMap)); - new->next=c->map; - c->map=new; - new->wqid[0] = root_qid.qid; - new->nwqid = 1; - new->fid = fcall->fid; - fcall->id = RATTACH; - fcall->qid = new->wqid[new->sel]; - ixp_server_respond_fcall(c, fcall); - return nil; +/* This should be moved to libixp */ +static void +write_buf(Req *r, void *buf, unsigned int len) { + if(r->ifcall.offset >= len) + return; + + len -= r->ifcall.offset; + if(len > r->ifcall.count) + len = r->ifcall.count; + /* XXX: mallocz is not really needed here */ + r->ofcall.data = cext_emallocz(len); + memcpy(r->ofcall.data, buf + r->ifcall.offset, len); + r->ofcall.count = len; } -static char * -xwalk(IXPConn *c, Fcall *fcall) -{ - IXPMap *m; - char *err; - unsigned int qsel, nwqid; - PackedQid wqid[IXP_MAX_WELEM], *qid; - - if(!(m = ixp_server_fid2map(c, fcall->fid))) { - err = Enofile; - goto Fail; - }if(fcall->fid != fcall->newfid && (ixp_server_fid2map(c, fcall->newfid))) { - err = Efidinuse; - goto Fail; - } - - for(qsel = 0; qsel < m->nwqid; qsel++) - wqid[qsel].qid = m->wqid[qsel]; - if(qsel) - qsel--; - for(nwqid = 0; nwqid < fcall->nwname; nwqid++) { - if(qsel >= IXP_MAX_WELEM) - break; - if(!strncmp(fcall->wname[nwqid], "..", 3)) { - if(qsel) - qsel--; - qid = &wqid[qsel]; - } - else { - qid = qid_of_name(wqid, qsel, fcall->wname[nwqid]); - if(!qid) - break; - qsel++; +/* This should probably be factored out like lookup_file + * so we can use it to get size for stats and not write + * data anywhere. -KM */ +/* This is obviously not a priority, however. -KM */ +void +fs_read(Req *r) { + unsigned char *buf; + FileId *f, *tf; + int n, offset; + int size; + + offset = 0; + f = r->fid->aux; + + if(f->tab.perm & DMDIR) { + Stat s; + offset = 0; + size = r->ifcall.count; + buf = cext_emallocz(size); + r->ofcall.data = buf; + + tf = f = lookup_file(f, nil); + /* Note: f->tab.name == "."; goto next */ + for(f=f->next; f; f=f->next) { + dostat(&s, 0, f); + n = ixp_sizeof_stat(&s); + if(offset >= r->ifcall.offset) { + if(size < n) + break; + ixp_pack_stat(&buf, &size, &s); + } + offset += n; } - fcall->wqid[nwqid] = wqid[qsel].qid = qid->qid; - } - if(fcall->nwname && !nwqid) { - err = Enofile; - goto Fail; - } + while((f = tf)) { + tf=tf->next; + free_file(f); + } - /* a fid will only be valid, if the walk was complete */ - if(nwqid == fcall->nwname) { - unsigned int i; - if(fcall->fid != fcall->newfid) { - m = cext_emallocz(sizeof(IXPMap)); - m->next=c->map; - c->map=m; + r->ofcall.count = r->ifcall.count - size; + respond(r, nil); + }else{ + switch(f->tab.type) { + case FsFprops: + write_buf(r, (void *)f->client->props, strlen(f->client->props)); + return respond(r, nil); + case FsFCSel: + case FsFCNorm: + write_buf(r, (void *)f->col->colstr, strlen(f->col->colstr)); + return respond(r, nil); + case FsFColRules: + case FsFTagRules: + write_buf(r, (void *)f->rule->string, f->rule->size); + return respond(r, nil); + case FsFKeys: + write_buf(r, (void *)def.keys, def.keyssz); + return respond(r, nil); + case FsFFont: + write_buf(r, (void *)def.font.fontstr, strlen(def.font.fontstr)); + return respond(r, nil); + case FsFCtags: + write_buf(r, (void *)f->client->tags, strlen(f->client->tags)); + return respond(r, nil); + case FsFCindex: + if(r->ifcall.offset) + return respond(r, nil); + n = asprintf((char **)&r->ofcall.data, "%d", f->index); + cext_assert(n >= 0); + r->ofcall.count = n; + return respond(r, nil); + case FsFBorder: + if(r->ifcall.offset) + return respond(r, nil); + n = asprintf((char **)&r->ofcall.data, "%d", def.border); + cext_assert(n >= 0); + r->ofcall.count = n; + return respond(r, nil); + case FsFTindex: + buf = view_index(f->view); + n = strlen((char *)buf); + write_buf(r, (void *)buf, n); + return respond(r, nil); + case FsFEvent: + r->aux = pending_event_reads; + pending_event_reads = r; + return; } - for(i = 0; i <= qsel; i++) - m->wqid[i] = wqid[i].qid; - m->nwqid = qsel + 1; - m->sel = qsel; - m->fid = fcall->newfid; + /* XXX: This should be taken care of by open */ + /* should probably be an assertion in the future */ + respond(r, Enoperm); } - free(fcall->wname[0]); - fcall->id = RWALK; - fcall->nwqid = nwqid; - ixp_server_respond_fcall(c, fcall); - return nil; -Fail: - free(fcall->wname[0]); - return err; } -static char * -xcreate(IXPConn *c, Fcall *fcall) -{ - IXPMap *m = ixp_server_fid2map(c, fcall->fid); - PackedQid *qid = (PackedQid *)&m->wqid[m->sel]; - unsigned char type; - - if(!(fcall->mode | IXP_OWRITE)) - return Enomode; - if(!m) - return Enofile; - if(!strncmp(fcall->name, ".", 2) || !strncmp(fcall->name, "..", 3)) - return "illegal file name"; - - type = qid->ptype; - switch(type) { - case FsDbars: - create_bar(fcall->name); - break; - default: - return Enofile; - break; - } - - if(!(qid = qid_of_name((PackedQid *)&m->wqid, m->sel, fcall->name))) - return Enofile; - - m->wqid[m->nwqid++] = fcall->qid = qid->qid; - m->sel++; - fcall->id = RCREATE; - fcall->iounit = WMII_IOUNIT; - ixp_server_respond_fcall(c, fcall); - return nil; +void +fs_attach(Req *r) { + FileId *f = get_file(); + f->tab = dirtab[FsRoot][0]; + f->tab.name = strdup("/"); + r->fid->aux = f; + r->fid->qid.type = f->tab.qtype; + r->fid->qid.path = QID(f->tab.type, 0); + r->ofcall.qid = r->fid->qid; + respond(r, nil); } -static char * -xopen(IXPConn *c, Fcall *fcall) -{ - IXPMap *m = ixp_server_fid2map(c, fcall->fid); - - if(!m) - return Enofile; - if(!(fcall->mode | IXP_OREAD) && !(fcall->mode | IXP_OWRITE)) - return Enomode; - fcall->id = ROPEN; - fcall->qid = m->wqid[m->sel]; - fcall->iounit = WMII_IOUNIT; - ixp_server_respond_fcall(c, fcall); - - return nil; +void +fs_open(Req *r) { + /* XXX */ + r->ofcall.mode = r->ifcall.mode; + respond(r, nil); } -static char * -xremove(IXPConn *c, Fcall *fcall) -{ - IXPMap *t, *m = ixp_server_fid2map(c, fcall->fid); - unsigned char type; - void *i1, *i2, *i3; +void +fs_freefid(Fid *f) { + FileId *id, *tid; - if(!m) - return Enofile; - if(!unpack_qpath((PackedQid *)&m->wqid, m->sel, &type, &i1, &i2, &i3)) - return Enofile; - if(type != FsDbar) - return Enoperm; - /* clunk */ - if(c->map == m) - c->map = m->next; - else { - for(t=c->map; t && t->next != m; t=t->next); - if(t) - t->next = m->next; + for(id=f->aux; id; id = tid) { + tid = id->next; + free_file(id); } - free(m); - switch(type) { - case FsDbar: - { - Bar *b = BAR(i1); - destroy_bar(b); - draw_bar(); - } +} + +void +fs_clunk(Req *r) { + Client *c; + FileId *f = r->fid->aux; + + switch(f->tab.type) { + case FsFTagRules: + update_rules(&f->rule->rule, f->rule->string); + /* no break */ + case FsFColRules: + for(c=client; c; c=c->next) + apply_rules(c); + update_views(); break; - default: + case FsFKeys: + def.keys[def.keyssz] = '\0'; + update_keys(); + break; + case FsFCtags: + apply_tags(f->client, f->client->tags); + update_views(); + draw_client(f->client); break; } - fcall->id = RREMOVE; - ixp_server_respond_fcall(c, fcall); - return nil; + respond(r, nil); } -static char * -xread(IXPConn *c, Fcall *fcall) -{ - Stat stat; - IXPMap *m = ixp_server_fid2map(c, fcall->fid); - PackedQid *pwqid = (PackedQid *)&m->wqid; - View *v; - Frame *f; - Area *a; - Client *cl; - Bar *b; - void *i1, *i2, *i3; - unsigned int i, len; - int iounit; - unsigned char dir_type, type, *p = fcall->data; - char buf[256]; - XRectangle fr; +/* This should be moved to libixp */ +void +write_to_buf(Req *r, void *buf, unsigned int *len, unsigned int max) { + unsigned int offset, count; - if(!m) - return Enofile; - if(!unpack_qpath(pwqid, m->sel, &type, &i1, &i2, &i3)) - return Enofile; - dir_type = dir_of_qid(pwqid, m->sel); + offset = (r->fid->omode&OAPPEND) ? *len : r->ifcall.offset; + if(offset > *len || r->ifcall.count == 0) { + r->ofcall.count = 0; + return; + } - fcall->count = 0; - iounit = fcall->iounit; - if(fcall->offset) { - switch (type) { - case FsDtag: - /* jump to offset */ - len = 0; - if(view) - len += stat_of_name(&stat, "sel", pwqid, m->sel); - for(v=view; v; v=v->next) { - len += stat_of_name(&stat, v->name, pwqid, m->sel); - if(len <= fcall->offset) - continue; - break; - } - /* offset found, proceeding */ - for(; v; v=v->next) { - len = stat_of_name(&stat, v->name, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - break; - case FsDclients: - /* jump to offset */ - len = 0; - for(cl=client, i=0; cl; cl=cl->next, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len += stat_of_name(&stat, buf, pwqid, m->sel); - if(len <= fcall->offset) - continue; - break; - } - /* offset found, proceeding */ - for(; cl; cl=cl->next, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len = stat_of_name(&stat, buf, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - break; - case FsDbars: - /* jump to offset */ - len = 0; - for(b=bar; b; b=b->next) { - len += stat_of_name(&stat, b->name, pwqid, m->sel); - if(len <= fcall->offset) - continue; - break; - } - /* offset found, proceeding */ - for(; b; b=b->next) { - len = stat_of_name(&stat, b->name, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - break; - case FsDview: - /* jump to offset */ - len = 0; - if(view) { - len = stat_of_name(&stat, "name", pwqid, m->sel); - len += stat_of_name(&stat, "ctl", pwqid, m->sel); - if(VIEW(i1)->area) - len += stat_of_name(&stat, "sel", pwqid, m->sel); - for(a=VIEW(i1)->area, i=0; a; a=a->next, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len += stat_of_name(&stat, buf, pwqid, m->sel); - if(len <= fcall->offset) - continue; - break; - } - /* offset found, proceeding */ - for(; a; a=a->next, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len = stat_of_name(&stat, buf, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - } - break; - case FsDarea: - /* jump to offset */ - len = stat_of_name(&stat, "ctl", pwqid, m->sel); - len += stat_of_name(&stat, "index", pwqid, m->sel); - if(i2) - len += stat_of_name(&stat, "mode", pwqid, m->sel); - if(AREA(i2)->frame) - len += stat_of_name(&stat, "sel", pwqid, m->sel); - for(f=AREA(i2)->frame, i=0; f; f=f->anext, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len += stat_of_name(&stat, buf, pwqid, m->sel); - if(len <= fcall->offset) - continue; - break; - } - /* offset found, proceeding */ - for(; f; f=f->anext, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len = stat_of_name(&stat, buf, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - break; - case FsFevent: - memcpy(&c->pending, fcall, sizeof(Fcall)); - c->is_pending = 1; - return nil; - break; - case FsFkeys: - len = def.keys ? strlen(def.keys) : 0; - if(len <= fcall->offset) { - fcall->count = 0; - break; - } - fcall->count = len - fcall->offset; - if(fcall->count > fcall->iounit) { - memcpy(p, def.keys + fcall->offset, fcall->iounit); - fcall->count = fcall->iounit; - } - else if(fcall->count) - memcpy(p, def.keys + fcall->offset, fcall->count); - break; - case FsFtagrules: - len = def.tagrules ? strlen(def.tagrules) : 0; - if(len <= fcall->offset) { - fcall->count = 0; - break; - } - fcall->count = len - fcall->offset; - if(fcall->count > fcall->iounit) { - memcpy(p, def.tagrules + fcall->offset, fcall->iounit); - fcall->count = fcall->iounit; - } - else if(fcall->count) - memcpy(p, def.tagrules + fcall->offset, fcall->count); - break; - case FsFcolrules: - len = def.colrules ? strlen(def.colrules) : 0; - if(len <= fcall->offset) { - fcall->count = 0; - break; - } - fcall->count = len - fcall->offset; - if(fcall->count > fcall->iounit) { - memcpy(p, def.colrules + fcall->offset, fcall->iounit); - fcall->count = fcall->iounit; - } - else if(fcall->count) - memcpy(p, def.colrules + fcall->offset, fcall->count); - break; - default: - break; - } + count = r->ifcall.count; + if(max && (count > max - offset)) + count = max - offset; + + *len = offset + count; + + if(max == 0) { + *(void **)buf = realloc(*(void **)buf, *len + 1); + cext_assert(*(void **)buf); + buf = *(void **)buf; } - else { - switch (type) { - case FsDroot: - fcall->count = stat_of_names(&p, &iounit, pwqid, m->sel, "ctl", "event", "def", "bar", nil); - if(view) { - fcall->count += stat_of_names(&p, &iounit, pwqid, m->sel, "tag", nil); - } - if(client) { - fcall->count += stat_of_names(&p, &iounit, pwqid, m->sel, "client", nil); - } - break; - case FsDtag: - if(view) { - fcall->count += stat_of_names(&p, &iounit, pwqid, m->sel, "sel", nil); - } - for(v=view; v; v=v->next) { - len = stat_of_name(&stat, v->name, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - break; - case FsDclients: - for(cl=client, i=0; cl; cl=cl->next, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len = stat_of_name(&stat, buf, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - break; - case FsDbars: - for(b=bar; b; b=b->next) { - len = stat_of_name(&stat, b->name, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - break; - case FsDbar: - if(!i1) - return Enofile; - fcall->count = stat_of_names(&p, &iounit, pwqid, m->sel, "colors", "data", nil); - break; - case FsDdef: - fcall->count = stat_of_names(&p, &iounit, pwqid, m->sel, "border", "selcolors", - "normcolors", "font", "keys", "tagrules", "grabmod", "colrules", nil); - break; - case FsDview: - if(view) { - fcall->count = stat_of_names(&p, &iounit, pwqid, m->sel, "name", "ctl", nil); - if(VIEW(i1)->area) { - fcall->count += stat_of_names(&p, &iounit, pwqid, m->sel, "sel", nil); - } - for(a=VIEW(i1)->area, i=0; a; a=a->next, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len = stat_of_name(&stat, buf, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - } - break; - case FsDarea: - fcall->count = stat_of_names(&p, &iounit, pwqid, m->sel, "ctl", "index", nil); - if(i2) { - fcall->count += stat_of_names(&p, &iounit, pwqid, m->sel, "mode", nil); - } - if(AREA(i2)->frame) { - fcall->count += stat_of_names(&p, &iounit, pwqid, m->sel, "sel", nil); - } - for(f=AREA(i2)->frame, i=0; f; f=f->anext, i++) { - snprintf(buf, sizeof(buf), "%u", i); - len = stat_of_name(&stat, buf, pwqid, m->sel); - if(fcall->count + len > fcall->iounit) - break; - fcall->count += len; - ixp_pack_stat(&p, &iounit, &stat); - } - break; - case FsDGclient: - case FsDclient: - fcall->count = stat_of_names(&p, &iounit, pwqid, m->sel, "props", "name", - "index", "tags", "geom", "ctl", nil); - break; - case FsFctl: - return Enoperm; - break; - case FsFevent: - memcpy(&c->pending, fcall, sizeof(Fcall)); - c->is_pending = 1; - return nil; - break; - case FsFborder: - snprintf(buf, sizeof(buf), "%u", def.border); - fcall->count = strlen(buf); - memcpy(p, buf, fcall->count); - break; - case FsFgeom: - if(dir_type == FsDclient) - fr = FRAME(i3)->rect; - else if(CLIENT(i1)->frame) - fr = CLIENT(i1)->sel->rect; - else - fr = CLIENT(i1)->rect; - snprintf(buf, sizeof(buf), "%d %d %d %d", fr.x, fr.y, fr.width, fr.height); - fcall->count = strlen(buf); - memcpy(p, buf, fcall->count); - break; - case FsFprops: - if(dir_type == FsDclient) { - if((fcall->count = strlen(FRAME(i3)->client->props))) - memcpy(p, FRAME(i3)->client->props, fcall->count); - } - else { - if((fcall->count = strlen(CLIENT(i1)->props))) - memcpy(p, CLIENT(i1)->props, fcall->count); - } - break; - case FsFindex: - switch(dir_type) { - case FsDclient: - snprintf(buf, sizeof(buf), "%d", - idx_of_client(FRAME(i3)->client)); - break; - case FsDarea: - snprintf(buf, sizeof(buf), "%d", idx_of_area(i2)); - break; - default: - snprintf(buf, sizeof(buf), "%d", idx_of_client(i1)); - break; - } - if((fcall->count = strlen(buf))) - memcpy(p, buf, fcall->count); - break; - case FsFname: - if(dir_type == FsDclient) { - if((fcall->count = strlen(FRAME(i3)->client->name))) - memcpy(p, FRAME(i3)->client->name, fcall->count); - } - else if(dir_type == FsDview) { - if((fcall->count = strlen(VIEW(i1)->name))) - memcpy(p, VIEW(i1)->name, fcall->count); - } - else { - if((fcall->count = strlen(CLIENT(i1)->name))) - memcpy(p, CLIENT(i1)->name, fcall->count); - } - break; - case FsFtags: - switch(dir_type) { - case FsDclient: - { - Client *c = FRAME(i3)->client; - if((fcall->count = strlen(c->tags))) - memcpy(p, c->tags, fcall->count); - } - break; - case FsDGclient: - if((fcall->count = strlen(CLIENT(i1)->tags))) - memcpy(p, CLIENT(i1)->tags, fcall->count); - break; - default: + + memcpy(buf + offset, r->ifcall.data, count); +} + +/* This should be moved to libixp */ +void +data_to_cstring(Req *r) { + unsigned int i; + if(r->ifcall.count) { + for(i=0; i < r->ifcall.count; i++) + if(r->ifcall.data[i] == '\n') break; - } - break; - case FsFdata: - if(!i1) - return Enofile; - if((fcall->count = strlen(BAR(i1)->data))) - memcpy(p, BAR(i1)->data, fcall->count); - break; - case FsFcolors: - if(!i1) - return Enofile; - if((fcall->count = strlen(BAR(i1)->colstr))) - memcpy(p, BAR(i1)->colstr, fcall->count); - break; - case FsFselcolors: - if((fcall->count = strlen(def.selcolor))) - memcpy(p, def.selcolor.string, fcall->count); - break; - case FsFnormcolors: - if((fcall->count = strlen(def.normcolor))) - memcpy(p, def.normcolor.string, fcall->count); - break; - case FsFkeys: - fcall->count = def.keys ? strlen(def.keys) : 0; - if(fcall->count > fcall->iounit) { - memcpy(p, def.keys, fcall->iounit); - fcall->count = fcall->iounit; - } - else if(fcall->count) - memcpy(p, def.keys, fcall->count); - break; - case FsFtagrules: - fcall->count = def.tagrules ? strlen(def.tagrules) : 0; - if(fcall->count > fcall->iounit) { - memcpy(p, def.tagrules, fcall->iounit); - fcall->count = fcall->iounit; - } - else if(fcall->count) - memcpy(p, def.tagrules, fcall->count); - break; - case FsFgrabmod: - if((fcall->count = strlen(def.grabmod))) - memcpy(p, def.grabmod, fcall->count); - break; - case FsFcolrules: - fcall->count = def.colrules ? strlen(def.colrules) : 0; - if(fcall->count > fcall->iounit) { - memcpy(p, def.colrules, fcall->iounit); - fcall->count = fcall->iounit; - } - else if(fcall->count) - memcpy(p, def.colrules, fcall->count); - break; - case FsFfont: - if((fcall->count = strlen(def.font))) - memcpy(p, def.font, fcall->count); - break; - case FsFmode: - snprintf(buf, sizeof(buf), "%s", - str_of_column_mode(AREA(i2)->mode)); - fcall->count = strlen(buf); - memcpy(p, buf, fcall->count); - break; - default: - return Enoperm; - break; - } + if(i == r->ifcall.count) + r->ifcall.data = realloc(r->ifcall.data, i + 1); + cext_assert(r->ifcall.data); + r->ifcall.data[i] = '\0'; } - fcall->id = RREAD; - ixp_server_respond_fcall(c, fcall); - return nil; } -static char * -xstat(IXPConn *c, Fcall *fcall) -{ - IXPMap *m = ixp_server_fid2map(c, fcall->fid); - char *name; - - if(!m) - return Enofile; - if(!(name = name_of_qid((PackedQid *)&m->wqid, m->sel))) - return Enofile; - if(!stat_of_name(&fcall->stat, name, (PackedQid *)&m->wqid, m->sel ? m->sel - 1 : 0)) - return Enofile; - fcall->id = RSTAT; - ixp_server_respond_fcall(c, fcall); - return nil; +/* This should be moved to liblitz */ +int +parse_colors(char **buf, int *buflen, BlitzColor *col) { + unsigned int i; + if(*buflen < 23 || 3 != sscanf(*buf, "#%06x #%06x #%06x", &i,&i,&i)) + return 0; + (*buflen) -= 23; + bcopy(*buf, col->colstr, 23); + blitz_loadcolor(col); + return 1; } -static char * -xwrite(IXPConn *c, Fcall *fcall) -{ - char buf[256], *tmp; - IXPMap *m = ixp_server_fid2map(c, fcall->fid); - void *i1, *i2, *i3; - int i; - unsigned char dir_type, type; - unsigned int len; - Frame *f; - Client *cl; - - if(!m) - return Enofile; - if(!unpack_qpath((PackedQid *)&m->wqid, m->sel, &type, &i1, &i2, &i3)) - return Enofile; - dir_type = dir_of_qid((PackedQid *)&m->wqid, m->sel); +/* This function needs to be seriously cleaned up */ +void +fs_write(Req *r) { + FileId *f; + char *buf, *errstr; + unsigned int i; - switch(type) { - case FsFctl: - if(fcall->count >= sizeof(buf)) - return Enocommand; - memcpy(buf, fcall->data, fcall->count); - buf[fcall->count] = 0; - switch(dir_type) { - case FsDroot: - if(!strncmp(buf, "quit", 5)) - srv.running = 0; - else if(!strncmp(buf, "view ", 5)) - select_view(&buf[5]); - else - return Enocommand; - break; - case FsDview: - if(!strncmp(buf, "select ", 7)) { - if(view) - select_area(VIEW(i1)->sel, &buf[7]); - } - else - return Enocommand; - break; - case FsDarea: - if(!strncmp(buf, "select ", 7)) { - Area *a = AREA(i2); - if(a->frame) - select_client(a->sel->client, &buf[7]); - } - else - return Enocommand; - break; - case FsDclient: - f = FRAME(i3); - if(!strncmp(buf, "kill", 5)) - kill_client(f->client); - else if(!strncmp(buf, "newcol ", 7)) - newcol_client(f->client, &buf[7]); - else if(!strncmp(buf, "send ", 5)) - send_client(f->client, &buf[5]); - else if(!strncmp(buf, "move ", 5)) - move_client(f->client, &buf[5]); - else if(!strncmp(buf, "size ", 5)) - size_client(f->client, &buf[5]); - else - return Enocommand; - break; - case FsDGclient: - if(!strncmp(buf, "kill", 5)) - kill_client(CLIENT(i1)); - else - return Enocommand; - break; - default: - break; - } - break; - case FsFborder: - if(fcall->count >= sizeof(buf)) - return Ebadvalue; - memcpy(buf, fcall->data, fcall->count); - buf[fcall->count] = 0; - if(sscanf(buf, "%d", &i) != 1) - return Ebadvalue; - if(i < 0 || i > 100) - return Ebadvalue; + f = r->fid->aux; + switch(f->tab.type) { + case FsFColRules: + case FsFTagRules: + write_to_buf(r, &f->rule->string, &f->rule->size, 0); + return respond(r, nil); + case FsFKeys: + write_to_buf(r, &def.keys, &def.keyssz, 0); + return respond(r, nil); + case FsFFont: + data_to_cstring(r); + i=strlen(def.font.fontstr); + write_to_buf(r, &def.font.fontstr, &i, 0); + def.font.fontstr[i] = '\0'; + blitz_loadfont(&def.font); + r->ofcall.count = i- r->ifcall.offset; + return respond(r, nil); + case FsFCtags: + data_to_cstring(r); + i=strlen(f->client->tags); + write_to_buf(r, &f->client->tags, &i, 255); + f->client->tags[i] = '\0'; + r->ofcall.count = i- r->ifcall.offset; + return respond(r, nil); + case FsFBorder: + data_to_cstring(r); + i = (unsigned int)strtol((char *)r->ifcall.data, &buf, 10); + if(*buf) + return respond(r, Ebadvalue); def.border = i; - resize_all_clients(); - break; - case FsFtags: - if(!fcall->count || (fcall->count >= sizeof(buf))) - return Ebadvalue; - memcpy(buf, fcall->data, fcall->count); - buf[fcall->count] = 0; - cext_trim(buf, " \t/"); - if(dir_type == FsDclient) - cl = FRAME(i3)->client; - else - cl = CLIENT(i1); - apply_tags(cl, buf); - update_views(); - draw_client(cl); - break; - case FsFdata: - len = fcall->count; - if(len >= sizeof(BAR(i1)->data)) - len = sizeof(BAR(i1)->data) - 1; - memcpy(BAR(i1)->data, fcall->data, len); - BAR(i1)->data[len] = 0; - draw_bar(); - break; - case FsFcolors: - if(!i1 || (fcall->count != 23) || (fcall->data[0] != '#') - || (fcall->data[8] != '#') || (fcall->data[16] != '#')) - return Ebadvalue; - memcpy(BAR(i1)->colstr, fcall->data, fcall->count); - BAR(i1)->colstr[fcall->count] = 0; - blitz_loadcolor(&BAR(i1)->color, BAR(i1)->colstr); - draw_bar(); - break; - case FsFselcolors: - if((fcall->count != 23) || (fcall->data[0] != '#') - || (fcall->data[8] != '#') || (fcall->data[16] != '#')) - return Ebadvalue; - memcpy(def.selcolor.string, fcall->data, fcall->count); - def.selcolor.string[fcall->count] = 0; - blitz_loadcolor(&def.selcolor.col, def.selcolor.string); - draw_clients(); - break; - case FsFnormcolors: - if((fcall->count != 23) || (fcall->data[0] != '#') - || (fcall->data[8] != '#') || (fcall->data[16] != '#')) - return Ebadvalue; - memcpy(def.normcolor.string, fcall->data, fcall->count); - def.normcolor.string[fcall->count] = 0; - blitz_loadcolor(&def.normcolor.col, def.normcolor.string); + return respond(r, nil); + case FsFBar: + /* XXX: This should validate after each write */ + i = strlen(f->bar->buf); + write_to_buf(r, &f->bar->buf, &i, 279); + f->bar->buf[i] = '\0'; + r->ofcall.count = i- r->ifcall.offset; + return respond(r, nil); + case FsFCSel: + case FsFCNorm: + /* XXX: This allows for junk after the color string */ + data_to_cstring(r); + buf = (char *)r->ifcall.data; + i = r->ifcall.count; + if(!parse_colors((char **)&buf, (int *)&i, f->col)) + return respond(r, Ebadvalue); draw_clients(); - break; - case FsFkeys: - if(def.keyssz < fcall->offset + fcall->count + 1) { - def.keyssz = fcall->offset + fcall->count + 1; - tmp = cext_emallocz(def.keyssz); - len = def.keys ? strlen(def.keys) : 0; - if(len) { - memcpy(tmp, def.keys, len); - free(def.keys); - } - def.keys = tmp; - } - memcpy(def.keys + fcall->offset, fcall->data, fcall->count); - def.keys[fcall->offset + fcall->count] = 0; - break; - case FsFtagrules: - if(def.tagrules.size < fcall->offset + fcall->count + 1) { - def.tagrules.size = fcall->offset + fcall->count + 1; - tmp = cext_emallocz(def.tagrules.size); - len = def.tagrules ? strlen(def.tagrules) : 0; - if(len) { - memcpy(tmp, def.tagrules, len); - free(def.tagrules); - } - def.tagrules = tmp; - } - memcpy(def.tagrules + fcall->offset, fcall->data, fcall->count); - def.tagrules[fcall->offset + fcall->count] = 0; - break; - case FsFcolrules: - if(def.colrules.size < fcall->offset + fcall->count + 1) { - def.colrules.size = fcall->offset + fcall->count + 1; - tmp = cext_emallocz(def.colrules.size); - len = def.colrules ? strlen(def.colrules) : 0; - if(len) { - memcpy(tmp, def.colrules, len); - free(def.colrules); - } - def.colrules = tmp; - } - memcpy(def.colrules + fcall->offset, fcall->data, fcall->count); - def.colrules[fcall->offset + fcall->count] = 0; - break; - case FsFgeom: - if(fcall->count >= sizeof(buf)) - return Ebadvalue; - memcpy(buf, fcall->data, fcall->count); - buf[fcall->count] = 0; - if(dir_type == FsDclient) { - XRectangle new; - f = FRAME(i3); - new = f->rect; - strtorect(&new, buf); - if(new.width == 0) - new.width = rect.width; - if(new.height == 0) - new.height = rect.height; - if(i2) - resize_column(f->client, &new, nil); - else - resize_client(f->client, &new, False); - } - break; - case FsFgrabmod: - { - unsigned long mod; - if(fcall->count >= sizeof(buf)) - return Ebadvalue; - memcpy(buf, fcall->data, fcall->count); - buf[fcall->count] = 0; - mod = mod_key_of_str(buf); - if((mod != Mod1Mask) && (mod != Mod2Mask) && (mod != Mod3Mask) - && (mod != Mod4Mask) && (mod != Mod5Mask)) - return Ebadvalue; - cext_strlcpy(def.grabmod, buf, sizeof(def.grabmod)); - def.mod = mod; - if(view) - restack_view(sel); - } - break; - case FsFfont: - if(def.font) - free(def.font); - def.font = cext_emallocz(fcall->count + 1); - memcpy(def.font, fcall->data, fcall->count); - blitz_loadfont(&blitzfont, def.font); - resize_bar(); - break; - case FsFmode: - if(fcall->count >= sizeof(buf)) - return Ebadvalue; - if(dir_type == FsDarea && AREA(i2) == AREA(i2)->view->area) - return Enofile; - memcpy(buf, fcall->data, fcall->count); - buf[fcall->count] = 0; - if((i = column_mode_of_str(buf)) == -1) - return Ebadvalue; - AREA(i2)->mode = i; - arrange_column(AREA(i2), True); - restack_view(VIEW(i1)); - draw_clients(); - break; - case FsFevent: - if(fcall->count >= sizeof(buf)) - return Ebadvalue; - if(fcall->count) { - memcpy(buf, fcall->data, fcall->count); - buf[fcall->count] = 0; - write_event(buf); - } - break; - default: - return Enoperm; - break; + r->ofcall.count = r->ifcall.count - i; + return respond(r, nil); + case FsFTctl: + data_to_cstring(r); + if(r->ifcall.count == 0) + return respond(r, nil); + + if((errstr = message_view(f->view, (char *)r->ifcall.data))) + return respond(r, errstr); + r->ofcall.count = r->ifcall.count; + return respond(r, nil); + case FsFRctl: + data_to_cstring(r); + if(r->ifcall.count == 0) + return respond(r, nil); + + /* XXX: This needs to be moved to client_message(char *) */ + if(!strncmp((char *)r->ifcall.data, "quit", 5)) + srv.running = 0; + else if(!strncmp((char *)r->ifcall.data, "view ", 5)) + select_view((char *)&r->ifcall.data[5]); + else + return respond(r, Enocommand); + r->ofcall.count = r->ifcall.count; + return respond(r, nil); + case FsFEvent: + /* XXX: r->ifcall.count could be very large */ + buf = cext_emallocz(r->ifcall.count + 1); + bcopy(r->ifcall.data, buf, r->ifcall.count); + write_event(buf); + free(buf); + r->ofcall.count = r->ifcall.count; + return respond(r, nil); } - fcall->id = RWRITE; - ixp_server_respond_fcall(c, fcall); - return nil; + respond(r, Enoperm); } -static char * -xclunk(IXPConn *c, Fcall *fcall) -{ - IXPMap *t, *m = ixp_server_fid2map(c, fcall->fid); - Client *cl; - unsigned char type; - - if(!m) - return Enofile; - type = ((PackedQid *)&m->wqid[m->sel])->ptype; - if(type == FsFkeys) - update_keys(); - else if(type == FsFtagrules) { - update_rules(&def.tagrules.rule, def.tagrules.string); - for(cl=client; cl; cl=cl->next) - apply_rules(cl); - update_views(); - } - else if(type == FsFcolrules) { - update_rules(&def.colrules.rule, def.colrules.string); - } - if(c->map == m) - c->map = m->next; - else { - for(t=c->map; t && t->next != m; t=t->next); - if(t) - t->next = m->next; +void +fs_flush(Req *r) { + Req **t; + for(t=&pending_event_reads; *t; t=(Req **)&(*t)->aux) { + if(*t == r->oldreq) { + *t = (*t)->aux; + respond(r->oldreq, Einterrupted); + break; + } } - free(m); - fcall->id = RCLUNK; - ixp_server_respond_fcall(c, fcall); - return nil; + respond(r, nil); } -static void -do_fcall(IXPConn *c) -{ - static Fcall fcall; - unsigned int msize; - char *errstr; - - if((msize = ixp_server_receive_fcall(c, &fcall))) { - switch(fcall.id) { - case TVERSION: errstr = xversion(c, &fcall); break; - case TATTACH: errstr = xattach(c, &fcall); break; - case TWALK: errstr = xwalk(c, &fcall); break; - case TCREATE: errstr = xcreate(c, &fcall); break; - case TOPEN: errstr = xopen(c, &fcall); break; - case TREMOVE: errstr = xremove(c, &fcall); break; - case TREAD: errstr = xread(c, &fcall); break; - case TWRITE: errstr = xwrite(c, &fcall); break; - case TCLUNK: errstr = xclunk(c, &fcall); break; - case TSTAT: errstr = xstat(c, &fcall); break; - default: errstr = Enofunc; break; - } - if(errstr) - ixp_server_respond_error(c, &fcall, errstr); +void +fs_create(Req *r) { + FileId *f = r->fid->aux; + switch(f->tab.type) { + default: + /* XXX: This should be taken care of by the library */ + return respond(r, Enoperm); + case FsDBar: + if(!strlen(r->ifcall.name)) + return respond(r, Ebadvalue); + create_bar(r->ifcall.name); + f = lookup_file(f, r->ifcall.name); + if(!f) + return respond(r, Enofile); + r->ofcall.qid.type = f->tab.qtype; + r->ofcall.qid.path = QID(f->tab.type, f->id); + free_file(f); + respond(r, nil); + break; } - check_x_event(nil); } void -write_event(char *event) -{ - IXPConn *c; - - for(c=srv.conn; c; c=c->next) { - if(c->is_pending) { - /* pending reads on /event only, no qid checking */ - IXPMap *m = ixp_server_fid2map(c, c->pending.fid); - if(!m) { - if(ixp_server_respond_error(c, &c->pending, Enofile)) - return; - } - else if(((PackedQid *)&m->wqid[m->sel])->ptype == FsFevent) { - /* pending reads on /event only, no qid checking */ - c->pending.count = strlen(event); - memcpy(c->pending.data, event, c->pending.count); - c->pending.id = RREAD; - if(ixp_server_respond_fcall(c, &c->pending)) - return; - } - } - } +fs_remove(Req *r) { + respond(r, "not implemented"); } void -new_ixp_conn(IXPConn *c) -{ - int fd = accept(c->fd, nil, nil); +write_event(char *buf) { + Req *aux; + unsigned int len; + if(!(len = strlen(buf))) + return; + for(; pending_event_reads; pending_event_reads=aux) { + aux = pending_event_reads->aux; + /* XXX: It would be nice if strdup wasn't necessary here */ + pending_event_reads->ofcall.data = (void *)strdup(buf); + pending_event_reads->ofcall.count = len; + respond(pending_event_reads, nil); + } +} - if(fd >= 0) - ixp_server_open_conn(c->srv, fd, do_fcall, nil); +static void +dostat(Stat *s, unsigned int len, FileId *f) { + s->type = 0; + s->dev = 0; + s->qid.path = QID(f->tab.type, f->id); + s->qid.version = 0; + s->qid.type = f->tab.qtype; + s->mode = f->tab.perm; + s->atime = time(nil); + s->mtime = time(nil); + s->length = len; + s->name = f->tab.name; + /* XXX This genenv should be called once */ + s->uid = getenv("USER"); + s->gid = getenv("USER"); + s->muid = getenv("USER"); } diff --git a/cmd/wm/fs2.c b/cmd/wm/fs2.c @@ -1,774 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include "wm.h" - -/* Datatypes: */ -typedef struct Dirtab Dirtab; -struct Dirtab { - char *name; - unsigned char qtype; - unsigned int type; - unsigned int perm; -}; - -typedef struct FileId FileId; -struct FileId { - FileId *next; - union { - void *ref; - Bar *bar; - Bar **bar_p; - View *view; - Client *client; - Rules *rule; - BlitzColor *col; - }; - unsigned int id; - unsigned int index; - Dirtab tab; - unsigned short nref; -}; - -/* Function prototypes */ -static void dostat(Stat *s, unsigned int len, FileId *f); - -/* Error messages */ -static char - Enoperm[] = "permission denied", - Enofile[] = "file not found", - Ebadvalue[] = "bad value", - Einterrupted[] = "interrupted", - Enocommand[] = "command not supported"; -/* Old error messages: - Eisdir[] = "file is a directory", - Efidinuse[] = "fid in use", - Enomode[] = "mode not supported", - Enofunc[] = "function not supported", -*/ - -/* Constants */ -enum { /* Dirs */ - FsRoot, FsDClient, FsDClients, FsDBar, - FsDSClient, FsDTag, FsDTags, - /* Files */ - FsFBar, FsFBorder, FsFCNorm, FsFCSel, - FsFCctl, FsFCindex, FsFColRules, FsFCtags, - FsFEvent, FsFFont, FsFKeys, FsFRctl, - FsFTagRules, FsFTctl, FsFTindex, FsFprops, - RsFFont -}; - -/* QID Macros */ -#define QID(t, i) (((long long)((t)&0xFF)<<32)|((i)&0xFFFFFFFF)) -/* Will I ever need these macros? - * I don't think so. */ -#define TYPE(q) ((q)>>32&0xFF) -#define ID(q) ((q)&0xFFFFFFFF) - -/* Global vars */ -FileId *free_fileid = nil; -Req *pending_event_reads = nil; -P9Srv p9srv = { - .open= fs_open, - .walk= fs_walk, - .read= fs_read, - .stat= fs_stat, - .write= fs_write, - .clunk= fs_clunk, - .flush= fs_flush, - .attach=fs_attach, - .create=fs_create, - .remove=fs_remove, - .freefid=fs_freefid -}; - -/* ad-hoc file tree. Empty names ("") indicate a dynamic entry to be filled - * in by lookup_file */ -static Dirtab -dirtab_root[]= {{".", QTDIR, FsRoot, 0500|DMDIR }, - {"rbar", QTDIR, FsDBar, 0700|DMDIR }, - {"lbar", QTDIR, FsDBar, 0700|DMDIR }, - {"client", QTDIR, FsDClients, 0500|DMDIR }, - {"tag", QTDIR, FsDTags, 0500|DMDIR }, - {"ctl", QTAPPEND, FsFRctl, 0600|DMAPPEND }, - {"border", QTFILE, FsFBorder, 0600 }, - {"colrules", QTFILE, FsFColRules, 0600 }, - {"event", QTFILE, FsFEvent, 0600 }, - {"font", QTFILE, FsFFont, 0600 }, - {"keys", QTFILE, FsFKeys, 0600 }, - {"normcolors", QTFILE, FsFCNorm, 0600 }, - {"selcolors", QTFILE, FsFCSel, 0600 }, - {"tagrules", QTFILE, FsFTagRules, 0600 }, - {nil}}, -dirtab_clients[]={{".", QTDIR, FsDClients, 0500|DMDIR }, - {"", QTDIR, FsDClient, 0500|DMDIR }, - {nil}}, -dirtab_client[]= {{".", QTDIR, FsDClient, 0500|DMDIR }, - {"ctl", QTAPPEND, FsFCctl, 0200|DMAPPEND }, - {"tags", QTFILE, FsFCtags, 0600 }, - {"props", QTFILE, FsFprops, 0400 }, - {nil}}, -dirtab_sclient[]={{".", QTDIR, FsDSClient, 0500|DMDIR }, - {"ctl", QTAPPEND, FsFCctl, 0200|DMAPPEND }, - {"index", QTFILE, FsFCindex, 0400 }, - {"tags", QTFILE, FsFCtags, 0600 }, - {"props", QTFILE, FsFprops, 0400 }, - {nil}}, -dirtab_bar[]= {{".", QTDIR, FsDBar, 0700|DMDIR }, - {"", QTFILE, FsFBar, 0600 }, - {nil}}, -dirtab_tags[]= {{".", QTDIR, FsDTags, 0500|DMDIR }, - {"", QTDIR, FsDTag, 0500|DMDIR }, - {nil}}, -dirtab_tag[]= {{".", QTDIR, FsDTag, 0500|DMDIR }, - {"ctl", QTAPPEND, FsFTctl, 0200|DMAPPEND }, - {"index", QTFILE, FsFTindex, 0400 }, - {nil}}; -/* Writing the lists separately and using an array of their references - * removes the need for casting and allows for C90 conformance, - * since otherwise we would need to use compound literals */ -static Dirtab *dirtab[] = { - [FsRoot] dirtab_root, - [FsDBar] dirtab_bar, - [FsDClients] dirtab_clients, - [FsDClient] dirtab_client, - [FsDSClient] dirtab_sclient, - [FsDTags] dirtab_tags, - [FsDTag] dirtab_tag -}; - -/* get_file/free_file save and reuse old FileId structs - * since so many of them are needed for so many - * purposes */ -static FileId * -get_file() { - FileId *temp; - if(!free_fileid) { - unsigned int i = 15; - temp = cext_emallocz(sizeof(FileId) * i); - for(; i; i--) { - temp->next = free_fileid; - free_fileid = temp++; - } - } - temp = free_fileid; - free_fileid = temp->next; - temp->nref = 1; - temp->next = nil; - return temp; -} - -/* Convenience func: */ -/* ugly, though... */ -FileId * -push_file(FileId ***last) { - FileId *ret = get_file(); - **last = ret; - *last = &ret->next; - return ret; -} - -static void -free_file(FileId *f) { - if(--f->nref) - return; - free(f->tab.name); - f->next = free_fileid; - free_fileid = f; -} - -/* This function's name belies it's true purpose. It increases - * the reference count of the FileId list */ -static void -clone_files(FileId *f) { - for(; f; f=f->next) - cext_assert(f->nref++); -} - -/* All lookups and directory organization should be performed through - * lookup_file, mostly through the dirtabs[] tree. */ -static FileId * -lookup_file(FileId *parent, char *name) -{ - FileId *ret, *file, **last; - Dirtab *dir; - Client *c; - View *v; - Bar *b; - unsigned int i, id; - - if(!(parent->tab.perm & DMDIR)) - return nil; - - dir = dirtab[parent->tab.type]; - last = &ret; - ret = nil; - - for(; dir->name; dir++) { - /* Dynamic dirs */ - if(!*dir->name) { /* strlen(dir->name) == 0 */ - switch(parent->tab.type) { - case FsDClients: - if(!name || !strncmp(name, "sel", 4)) { - if((c = sel_client())) { - file = get_file(); - *last = file; - last = &file->next; - file->ref = c; - file->id = c->id; - file->index = idx_of_client(c); - file->tab = *dirtab[FsDSClient]; - file->tab.name = strdup("sel"); - }if(name) goto LastItem; - } - if(name) { - id = (unsigned int)strtol(name, &name, 10); - if(*name) goto NextItem; - } - - i=0; - for(c=client; c; c=c->next, i++) { - if(!name || i == id) { - file = get_file(); - *last = file; - last = &file->next; - file->ref = c; - file->id = c->id; - file->tab = *dir; - asprintf(&file->tab.name, "%d", i); - if(name) goto LastItem; - } - } - break; - case FsDTags: - if(!name || !strncmp(name, "sel", 4)) { - if(sel) { - file = get_file(); - *last = file; - last = &file->next; - file->ref = sel; - file->id = sel->id; - file->tab = *dir; - file->tab.name = strdup("sel"); - }if(name) goto LastItem; - } - for(v=view; v; v=v->next) { - if(!name || !strcmp(name, v->name)) { - file = get_file(); - *last = file; - last = &file->next; - file->ref = v; - file->id = v->id; - file->tab = *dir; - file->tab.name = strdup(v->name); - if(name) goto LastItem; - } - } - break; - case FsDBar: - for(b=*parent->bar_p; b; b=b->next) { - if(!name || !strcmp(name, b->name)) { - file = get_file(); - *last = file; - last = &file->next; - file->ref = b; - file->id = b->id; - file->tab = *dir; - file->tab.name = strdup(b->name); - if(name) goto LastItem; - } - } - break; - } - }else /* Static dirs */ - if(!name || !strcmp(name, dir->name)) { - file = get_file(); - *last = file; - last = &file->next; - file->id = 0; - file->ref = parent->ref; - file->index = parent->index; - file->tab = *dir; - file->tab.name = strdup(file->tab.name); - - /* Special considerations: */ - switch(file->tab.type) { - case FsDBar: - if(!strncmp(file->tab.name, "lbar", 5)) - file->ref = &lbar; - else - file->ref = &rbar; - break; - case FsFColRules: - file->ref = &def.colrules; - break; - case FsFTagRules: - file->ref = &def.tagrules; - break; - case FsFCSel: - file->ref = &def.selcolor; - break; - case FsFCNorm: - file->ref = &def.normcolor; - break; - } - if(name) goto LastItem; - } - NextItem: - continue; - } -LastItem: - *last = nil; - return ret; -} - -void -fs_walk(Req *r) { - FileId *f, *nf; - int i; - - f = r->fid->aux; - - clone_files(f); - for(i=0; i < r->ifcall.nwname; i++) { - if(!strncmp(r->ifcall.wname[i], "..", 3)) { - if(f->next) { - nf=f; - f=f->next; - free_file(nf); - } - }else{ - nf = lookup_file(f, r->ifcall.wname[i]); - if(!nf) - break; - cext_assert(!nf->next); - nf->next = f; - f = nf; - } - r->ofcall.wqid[i].type = f->tab.qtype; - r->ofcall.wqid[i].path = QID(f->tab.type, f->id); - } - /* There should be a way to do this on freefid() */ - if(i < r->ifcall.nwname) { - while((nf = f)) { - f=f->next; - free_file(nf); - } - return respond(r, Enofile); - } - - /* Remove refs for r->fid if no new fid */ - /* If Fids were ref counted, this could be - * done in their decref function */ - if(r->ifcall.fid == r->ifcall.newfid) { - nf=r->fid->aux; - r->fid->aux = f; - while((nf = f)) { - f=f->next; - free_file(nf); - } - } - - r->newfid->aux = f; - r->ofcall.nwqid = i; - respond(r, nil); -} - -void -fs_stat(Req *r) { - Stat s; - int size; - unsigned char *buf; - - dostat(&s, 0, r->fid->aux); - r->ofcall.nstat = size = ixp_sizeof_stat(&s); - buf = cext_emallocz(size); - r->ofcall.stat = buf; - - ixp_pack_stat(&buf, &size, &s); - respond(r, nil); -} - -/* This should be moved to libixp */ -static void -write_buf(Req *r, void *buf, unsigned int len) { - if(r->ifcall.offset >= len) - return; - - len -= r->ifcall.offset; - if(len > r->ifcall.count) - len = r->ifcall.count; - /* XXX: mallocz is not really needed here */ - r->ofcall.data = cext_emallocz(len); - memcpy(r->ofcall.data, buf + r->ifcall.offset, len); - r->ofcall.count = len; -} - -/* This should probably be factored out like lookup_file - * so we can use it to get size for stats and not write - * data anywhere. -KM */ -/* This is obviously not a priority, however. -KM */ -void -fs_read(Req *r) { - unsigned char *buf; - FileId *f, *tf; - int n, offset; - int size; - - offset = 0; - f = r->fid->aux; - - if(f->tab.perm & DMDIR) { - Stat s; - offset = 0; - size = r->ifcall.count; - buf = cext_emallocz(size); - r->ofcall.data = buf; - - tf = f = lookup_file(f, nil); - /* Note: f->tab.name == "."; goto next */ - for(f=f->next; f; f=f->next) { - dostat(&s, 0, f); - n = ixp_sizeof_stat(&s); - if(offset >= r->ifcall.offset) { - if(size < n) - break; - ixp_pack_stat(&buf, &size, &s); - } - offset += n; - } - - while((f = tf)) { - tf=tf->next; - free_file(f); - } - - r->ofcall.count = r->ifcall.count - size; - respond(r, nil); - }else{ - switch(f->tab.type) { - case FsFprops: - write_buf(r, (void *)f->client->props, strlen(f->client->props)); - return respond(r, nil); - case FsFCSel: - case FsFCNorm: - write_buf(r, (void *)f->col->colstr, strlen(f->col->colstr)); - return respond(r, nil); - case FsFColRules: - case FsFTagRules: - write_buf(r, (void *)f->rule->string, f->rule->size); - return respond(r, nil); - case FsFKeys: - write_buf(r, (void *)def.keys, def.keyssz); - return respond(r, nil); - case FsFFont: - write_buf(r, (void *)def.font.fontstr, strlen(def.font.fontstr)); - return respond(r, nil); - case FsFCtags: - write_buf(r, (void *)f->client->tags, strlen(f->client->tags)); - return respond(r, nil); - case FsFCindex: - if(r->ifcall.offset) - return respond(r, nil); - n = asprintf((char **)&r->ofcall.data, "%d", f->index); - cext_assert(n >= 0); - r->ofcall.count = n; - return respond(r, nil); - case FsFBorder: - if(r->ifcall.offset) - return respond(r, nil); - n = asprintf((char **)&r->ofcall.data, "%d", def.border); - cext_assert(n >= 0); - r->ofcall.count = n; - return respond(r, nil); - case FsFTindex: - buf = view_index(f->view); - n = strlen((char *)buf); - write_buf(r, (void *)buf, n); - return respond(r, nil); - case FsFEvent: - r->aux = pending_event_reads; - pending_event_reads = r; - return; - } - /* XXX: This should be taken care of by open */ - /* should probably be an assertion in the future */ - respond(r, Enoperm); - } -} - -void -fs_attach(Req *r) { - FileId *f = get_file(); - f->tab = dirtab[FsRoot][0]; - f->tab.name = strdup("/"); - r->fid->aux = f; - r->fid->qid.type = f->tab.qtype; - r->fid->qid.path = QID(f->tab.type, 0); - r->ofcall.qid = r->fid->qid; - respond(r, nil); -} - -void -fs_open(Req *r) { - /* XXX */ - r->ofcall.mode = r->ifcall.mode; - respond(r, nil); -} - -void -fs_freefid(Fid *f) { - FileId *id, *tid; - - for(id=f->aux; id; id = tid) { - tid = id->next; - free_file(id); - } -} - -void -fs_clunk(Req *r) { - Client *c; - FileId *f = r->fid->aux; - - switch(f->tab.type) { - case FsFTagRules: - update_rules(&f->rule->rule, f->rule->string); - /* no break */ - case FsFColRules: - for(c=client; c; c=c->next) - apply_rules(c); - update_views(); - break; - case FsFKeys: - def.keys[def.keyssz] = '\0'; - update_keys(); - break; - case FsFCtags: - apply_tags(f->client, f->client->tags); - update_views(); - draw_client(f->client); - break; - } - respond(r, nil); -} - -/* This should be moved to libixp */ -void -write_to_buf(Req *r, void *buf, unsigned int *len, unsigned int max) { - unsigned int offset, count; - - offset = (r->fid->omode&OAPPEND) ? *len : r->ifcall.offset; - if(offset > *len || r->ifcall.count == 0) { - r->ofcall.count = 0; - return; - } - - count = r->ifcall.count; - if(max && (count > max - offset)) - count = max - offset; - - *len = offset + count; - - if(max == 0) { - *(void **)buf = realloc(*(void **)buf, *len + 1); - cext_assert(*(void **)buf); - buf = *(void **)buf; - } - - memcpy(buf + offset, r->ifcall.data, count); -} - -/* This should be moved to libixp */ -void -data_to_cstring(Req *r) { - unsigned int i; - if(r->ifcall.count) { - for(i=0; i < r->ifcall.count; i++) - if(r->ifcall.data[i] == '\n') - break; - if(i == r->ifcall.count) - r->ifcall.data = realloc(r->ifcall.data, i + 1); - cext_assert(r->ifcall.data); - r->ifcall.data[i] = '\0'; - } -} - -/* This should be moved to liblitz */ -int -parse_colors(char **buf, int *buflen, BlitzColor *col) { - unsigned int i; - if(*buflen < 23 || 3 != sscanf(*buf, "#%06x #%06x #%06x", &i,&i,&i)) - return 0; - (*buflen) -= 23; - bcopy(*buf, col->colstr, 23); - blitz_loadcolor(col); - return 1; -} - -/* This function needs to be seriously cleaned up */ -void -fs_write(Req *r) { - FileId *f; - char *buf, *errstr; - unsigned int i; - - f = r->fid->aux; - switch(f->tab.type) { - case FsFColRules: - case FsFTagRules: - write_to_buf(r, &f->rule->string, &f->rule->size, 0); - return respond(r, nil); - case FsFKeys: - write_to_buf(r, &def.keys, &def.keyssz, 0); - return respond(r, nil); - case FsFFont: - data_to_cstring(r); - i=strlen(def.font.fontstr); - write_to_buf(r, &def.font.fontstr, &i, 0); - def.font.fontstr[i] = '\0'; - blitz_loadfont(&def.font); - r->ofcall.count = i- r->ifcall.offset; - return respond(r, nil); - case FsFCtags: - data_to_cstring(r); - i=strlen(f->client->tags); - write_to_buf(r, &f->client->tags, &i, 255); - f->client->tags[i] = '\0'; - r->ofcall.count = i- r->ifcall.offset; - return respond(r, nil); - case FsFBorder: - data_to_cstring(r); - i = (unsigned int)strtol((char *)r->ifcall.data, &buf, 10); - if(*buf) - return respond(r, Ebadvalue); - def.border = i; - return respond(r, nil); - case FsFBar: - /* XXX: This should validate after each write */ - i = strlen(f->bar->buf); - write_to_buf(r, &f->bar->buf, &i, 279); - f->bar->buf[i] = '\0'; - r->ofcall.count = i- r->ifcall.offset; - return respond(r, nil); - case FsFCSel: - case FsFCNorm: - /* XXX: This allows for junk after the color string */ - data_to_cstring(r); - buf = (char *)r->ifcall.data; - i = r->ifcall.count; - if(!parse_colors((char **)&buf, (int *)&i, f->col)) - return respond(r, Ebadvalue); - draw_clients(); - r->ofcall.count = r->ifcall.count - i; - return respond(r, nil); - case FsFTctl: - data_to_cstring(r); - if(r->ifcall.count == 0) - return respond(r, nil); - - if((errstr = message_view(f->view, (char *)r->ifcall.data))) - return respond(r, errstr); - r->ofcall.count = r->ifcall.count; - return respond(r, nil); - case FsFRctl: - data_to_cstring(r); - if(r->ifcall.count == 0) - return respond(r, nil); - - /* XXX: This needs to be moved to client_message(char *) */ - if(!strncmp((char *)r->ifcall.data, "quit", 5)) - srv.running = 0; - else if(!strncmp((char *)r->ifcall.data, "view ", 5)) - select_view((char *)&r->ifcall.data[5]); - else - return respond(r, Enocommand); - r->ofcall.count = r->ifcall.count; - return respond(r, nil); - case FsFEvent: - /* XXX: r->ifcall.count could be very large */ - buf = cext_emallocz(r->ifcall.count + 1); - bcopy(r->ifcall.data, buf, r->ifcall.count); - write_event(buf); - free(buf); - r->ofcall.count = r->ifcall.count; - return respond(r, nil); - } - respond(r, Enoperm); -} - -void -fs_flush(Req *r) { - Req **t; - for(t=&pending_event_reads; *t; t=(Req **)&(*t)->aux) { - if(*t == r->oldreq) { - *t = (*t)->aux; - respond(r->oldreq, Einterrupted); - break; - } - } - respond(r, nil); -} - -void -fs_create(Req *r) { - FileId *f = r->fid->aux; - switch(f->tab.type) { - default: - /* XXX: This should be taken care of by the library */ - return respond(r, Enoperm); - case FsDBar: - if(!strlen(r->ifcall.name)) - return respond(r, Ebadvalue); - create_bar(r->ifcall.name); - f = lookup_file(f, r->ifcall.name); - if(!f) - return respond(r, Enofile); - r->ofcall.qid.type = f->tab.qtype; - r->ofcall.qid.path = QID(f->tab.type, f->id); - free_file(f); - respond(r, nil); - break; - } -} - -void -fs_remove(Req *r) { - respond(r, "not implemented"); -} - -void -write_event(char *buf) { - Req *aux; - unsigned int len; - if(!(len = strlen(buf))) - return; - for(; pending_event_reads; pending_event_reads=aux) { - aux = pending_event_reads->aux; - /* XXX: It would be nice if strdup wasn't necessary here */ - pending_event_reads->ofcall.data = (void *)strdup(buf); - pending_event_reads->ofcall.count = len; - respond(pending_event_reads, nil); - } -} - -static void -dostat(Stat *s, unsigned int len, FileId *f) { - s->type = 0; - s->dev = 0; - s->qid.path = QID(f->tab.type, f->id); - s->qid.version = 0; - s->qid.type = f->tab.qtype; - s->mode = f->tab.perm; - s->atime = time(nil); - s->mtime = time(nil); - s->length = len; - s->name = f->tab.name; - /* XXX This genenv should be called once */ - s->uid = getenv("USER"); - s->gid = getenv("USER"); - s->muid = getenv("USER"); -}