852 lines
15 KiB
C
852 lines
15 KiB
C
/* Copyright (c) 20XX 9front
|
||
*
|
||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
* of this software and associated documentation files (the "Software"), to deal
|
||
* in the Software without restriction, including without limitation the rights
|
||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
* copies of the Software, and to permit persons to whom the Software is
|
||
* furnished to do so, subject to the following conditions:
|
||
*
|
||
* The above copyright notice and this permission notice shall be included in all
|
||
* copies or substantial portions of the Software.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
* SOFTWARE.
|
||
*/
|
||
#include "u.h"
|
||
#include "../port/lib.h"
|
||
#include "mem.h"
|
||
#include "dat.h"
|
||
#include "fns.h"
|
||
#include "../port/error.h"
|
||
|
||
extern Dev* devtab[];
|
||
|
||
enum {
|
||
Qroot,
|
||
Qcroot,
|
||
Qshr,
|
||
Qcshr,
|
||
Qcmpt,
|
||
};
|
||
|
||
typedef struct Ent Ent;
|
||
typedef struct Shr Shr;
|
||
typedef struct Mpt Mpt;
|
||
typedef struct Sch Sch;
|
||
|
||
struct Ent
|
||
{
|
||
Ref ref;
|
||
int id;
|
||
char *name;
|
||
char *owner;
|
||
uint32_t perm;
|
||
};
|
||
|
||
struct Shr
|
||
{
|
||
Ent;
|
||
Mhead umh;
|
||
Shr *next;
|
||
};
|
||
|
||
struct Mpt
|
||
{
|
||
Ent;
|
||
Mount m;
|
||
};
|
||
|
||
struct Sch
|
||
{
|
||
int level;
|
||
|
||
Shr *shr;
|
||
Mpt *mpt;
|
||
|
||
Chan *chan;
|
||
};
|
||
|
||
static QLock shrslk;
|
||
static Shr *shrs;
|
||
|
||
static int shrid;
|
||
static int mptid;
|
||
|
||
static Mpt*
|
||
tompt(Mount *m)
|
||
{
|
||
return (Mpt*)((char*)m - (char*)&((Mpt*)0)->m);
|
||
}
|
||
|
||
static Sch*
|
||
tosch(Chan *c)
|
||
{
|
||
Sch *sch;
|
||
|
||
if(c == nil)
|
||
error("nil chan");
|
||
sch = c->aux;
|
||
if(sch == nil)
|
||
error("nil chan aux");
|
||
if(sch->chan != c)
|
||
error("bad chan");
|
||
return sch;
|
||
}
|
||
|
||
static void
|
||
shrinit(void)
|
||
{
|
||
shrid = 1;
|
||
mptid = 1;
|
||
}
|
||
|
||
static void
|
||
putmpt(Mpt *mpt)
|
||
{
|
||
if(decref(&mpt->ref))
|
||
return;
|
||
if(mpt->m.to != nil)
|
||
cclose(mpt->m.to);
|
||
jehanne_free(mpt->name);
|
||
jehanne_free(mpt->owner);
|
||
jehanne_free(mpt);
|
||
}
|
||
|
||
static void
|
||
putshr(Shr *shr)
|
||
{
|
||
if(decref(&shr->ref))
|
||
return;
|
||
jehanne_free(shr->name);
|
||
jehanne_free(shr->owner);
|
||
jehanne_free(shr);
|
||
}
|
||
|
||
static Qid
|
||
shrqid(int level, int id)
|
||
{
|
||
Qid q;
|
||
|
||
q.type = (level == Qcmpt) ? QTFILE : QTDIR;
|
||
q.path = (uint64_t)id<<4 | level;
|
||
q.vers = 0;
|
||
return q;
|
||
}
|
||
|
||
static Chan*
|
||
shrattach(Chan *c, Chan *ac, char *spec, int flags)
|
||
{
|
||
Sch *sch;
|
||
|
||
if(!(spec[0] == 'c' && spec[1] == 0 || spec[0] == 0))
|
||
error(Enoattach);
|
||
c = devattach(L'σ', spec);
|
||
|
||
sch = smalloc(sizeof(*sch));
|
||
sch->level = spec[0] == 'c' ? Qcroot : Qroot;
|
||
sch->mpt = nil;
|
||
sch->shr = nil;
|
||
sch->chan = c;
|
||
c->aux = sch;
|
||
c->qid = shrqid(sch->level, 0);
|
||
|
||
return c;
|
||
}
|
||
|
||
static Chan*
|
||
shrclone(Chan *c)
|
||
{
|
||
Chan *nc;
|
||
Sch *sch, *och;
|
||
|
||
och = tosch(c);
|
||
nc = devclone(c);
|
||
nc->dev = c->dev; // devclone does not fill ->dev
|
||
// this is a plan9-9k specific behaviour, but why?
|
||
// many related places are marked with XDYNX
|
||
sch = smalloc(sizeof(*sch));
|
||
jehanne_memmove(sch, och, sizeof(*sch));
|
||
if(sch->shr != nil)
|
||
incref(&sch->shr->ref);
|
||
if(sch->mpt != nil)
|
||
incref(&sch->mpt->ref);
|
||
sch->chan = nc;
|
||
nc->aux = sch;
|
||
return nc;
|
||
}
|
||
|
||
static void
|
||
shrclunk(Chan *c)
|
||
{
|
||
Sch *sch;
|
||
|
||
sch = tosch(c);
|
||
c->aux = nil;
|
||
sch->chan = nil;
|
||
if(sch->mpt != nil)
|
||
putmpt(sch->mpt);
|
||
if(sch->shr != nil)
|
||
putshr(sch->shr);
|
||
jehanne_free(sch);
|
||
}
|
||
|
||
static Walkqid*
|
||
shrwalk(Chan *c, Chan *nc, char **name, int nname)
|
||
{
|
||
Walkqid *wq, *wq2;
|
||
int alloc, j;
|
||
char *nam;
|
||
Sch *sch;
|
||
Shr *shr;
|
||
Mpt *mpt;
|
||
Mount *m;
|
||
Mhead *h;
|
||
|
||
alloc = 0;
|
||
if(nc == nil){
|
||
nc = shrclone(c);
|
||
alloc = 1;
|
||
}
|
||
wq = smalloc(sizeof(Walkqid) + (nname - 1) * sizeof(Qid));
|
||
wq->nqid = 0;
|
||
wq->clone = nc;
|
||
if(waserror()){
|
||
if(alloc)
|
||
cclose(wq->clone);
|
||
if(wq->nqid > 0)
|
||
wq->clone = nil;
|
||
else {
|
||
jehanne_free(wq);
|
||
wq = nil;
|
||
}
|
||
return wq;
|
||
}
|
||
sch = tosch(nc);
|
||
for(j = 0; j < nname; j++){
|
||
if(nc->qid.type != QTDIR)
|
||
error(Enotdir);
|
||
|
||
nam = name[j];
|
||
if(nam[0] == '.' && nam[1] == 0) {
|
||
/* nop */
|
||
} else if(nam[0] == '.' && nam[1] == '.' && nam[2] == 0) {
|
||
switch(sch->level){
|
||
default:
|
||
error(Egreg);
|
||
case Qshr:
|
||
nc->qid = shrqid(sch->level = Qroot, 0);
|
||
break;
|
||
case Qcshr:
|
||
nc->qid = shrqid(sch->level = Qcroot, 0);
|
||
break;
|
||
}
|
||
putshr(sch->shr);
|
||
sch->shr = nil;
|
||
} else if(sch->level == Qcroot || sch->level == Qroot) {
|
||
qlock(&shrslk);
|
||
for(shr = shrs; shr != nil; shr = shr->next)
|
||
if(jehanne_strcmp(nam, shr->name) == 0){
|
||
incref(&shr->ref);
|
||
break;
|
||
}
|
||
qunlock(&shrslk);
|
||
if(shr == nil)
|
||
error(Enonexist);
|
||
sch->level = sch->level == Qcroot ? Qcshr : Qshr;
|
||
sch->shr = shr;
|
||
nc->qid = shrqid(sch->level, shr->id);
|
||
} else if(sch->level == Qcshr) {
|
||
mpt = nil;
|
||
shr = sch->shr;
|
||
h = &shr->umh;
|
||
rlock(&h->lock);
|
||
for(m = h->mount; m != nil; m = m->next){
|
||
mpt = tompt(m);
|
||
if(jehanne_strcmp(nam, mpt->name) == 0){
|
||
incref(&mpt->ref);
|
||
break;
|
||
}
|
||
}
|
||
runlock(&h->lock);
|
||
if(m == nil)
|
||
error(Enonexist);
|
||
sch->mpt = mpt;
|
||
nc->qid = shrqid(sch->level = Qcmpt, mpt->id);
|
||
} else if(sch->level == Qshr) {
|
||
shr = sch->shr;
|
||
h = &shr->umh;
|
||
wq2 = nil;
|
||
rlock(&h->lock);
|
||
for(m = h->mount; m != nil && wq2 == nil; m = m->next){
|
||
if(m->to == nil)
|
||
continue;
|
||
if(waserror())
|
||
continue;
|
||
wq2 = m->to->dev->walk(m->to, nil, name + j, nname - j);
|
||
poperror();
|
||
}
|
||
runlock(&h->lock);
|
||
if(wq2 == nil)
|
||
error(Enonexist);
|
||
jehanne_memmove(wq->qid + wq->nqid, wq2->qid, wq2->nqid);
|
||
wq->nqid += wq2->nqid;
|
||
if(alloc)
|
||
cclose(wq->clone);
|
||
wq->clone = wq2->clone;
|
||
jehanne_free(wq2);
|
||
poperror();
|
||
return wq;
|
||
} else
|
||
error(Egreg);
|
||
wq->qid[wq->nqid++] = nc->qid;
|
||
}
|
||
poperror();
|
||
return wq;
|
||
}
|
||
|
||
static int
|
||
shrgen(Chan *c, char* _, Dirtab* __, int ___, int s, Dir *dp)
|
||
{
|
||
Mpt *mpt;
|
||
Sch *sch;
|
||
Shr *shr;
|
||
Mhead *h;
|
||
Mount *m;
|
||
|
||
sch = tosch(c);
|
||
switch(sch->level){
|
||
default:
|
||
return -1;
|
||
case Qroot:
|
||
case Qcroot:
|
||
qlock(&shrslk);
|
||
for(shr = shrs; shr != nil && s > 0; shr = shr->next)
|
||
s--;
|
||
if(shr == nil){
|
||
qunlock(&shrslk);
|
||
return -1;
|
||
}
|
||
kstrcpy(up->genbuf, shr->name, sizeof up->genbuf);
|
||
if(sch->level == Qroot)
|
||
devdir(c, shrqid(Qshr, shr->id), up->genbuf, 0, shr->owner,
|
||
shr->perm & ~0222, dp);
|
||
else
|
||
devdir(c, shrqid(Qcshr, shr->id), up->genbuf, 0, shr->owner,
|
||
shr->perm, dp);
|
||
qunlock(&shrslk);
|
||
return 1;
|
||
case Qcshr:
|
||
shr = sch->shr;
|
||
h = &shr->umh;
|
||
rlock(&h->lock);
|
||
for(m = h->mount; m != nil && s > 0; m = m->next)
|
||
s--;
|
||
if(m == nil){
|
||
runlock(&h->lock);
|
||
return -1;
|
||
}
|
||
mpt = tompt(m);
|
||
kstrcpy(up->genbuf, mpt->name, sizeof up->genbuf);
|
||
devdir(c, shrqid(Qcmpt, mpt->id), up->genbuf, 0, mpt->owner, mpt->perm, dp);
|
||
runlock(&h->lock);
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
static long
|
||
shrstat(Chan *c, uint8_t *db, long n)
|
||
{
|
||
Sch *sch;
|
||
Dir dir;
|
||
int rc;
|
||
|
||
sch = tosch(c);
|
||
switch(sch->level){
|
||
default:
|
||
error(Egreg);
|
||
case Qroot:
|
||
devdir(c, c->qid, "#σ", 0, eve, 0555, &dir);
|
||
break;
|
||
case Qcroot:
|
||
devdir(c, c->qid, "#σc", 0, eve, 0777, &dir);
|
||
break;
|
||
case Qshr:
|
||
devdir(c, c->qid, sch->shr->name, 0, sch->shr->owner, sch->shr->perm & ~0222, &dir);
|
||
break;
|
||
case Qcshr:
|
||
devdir(c, c->qid, sch->shr->name, 0, sch->shr->owner, sch->shr->perm, &dir);
|
||
break;
|
||
case Qcmpt:
|
||
devdir(c, c->qid, sch->mpt->name, 0, sch->mpt->owner, sch->mpt->perm, &dir);
|
||
break;
|
||
}
|
||
rc = jehanne_convD2M(&dir, db, n);
|
||
if(rc == 0)
|
||
error(Ebadarg);
|
||
return rc;
|
||
}
|
||
|
||
static Chan*
|
||
shropen(Chan *c, unsigned long omode)
|
||
{
|
||
Chan *nc;
|
||
Sch *sch;
|
||
Shr *shr;
|
||
Mpt *mpt;
|
||
int mode;
|
||
|
||
if(c->qid.type == QTDIR && omode != OREAD)
|
||
error(Eisdir);
|
||
|
||
mode = openmode(omode);
|
||
sch = tosch(c);
|
||
switch(sch->level){
|
||
default:
|
||
error(Egreg);
|
||
case Qroot:
|
||
case Qcroot:
|
||
break;
|
||
case Qshr:
|
||
case Qcshr:
|
||
shr = sch->shr;
|
||
devpermcheck(shr->owner, shr->perm, mode);
|
||
break;
|
||
case Qcmpt:
|
||
if(omode&OTRUNC)
|
||
error(Eexist);
|
||
shr = sch->shr;
|
||
mpt = sch->mpt;
|
||
devpermcheck(mpt->owner, mpt->perm, mode);
|
||
rlock(&shr->umh.lock);
|
||
if(mpt->m.to == nil || mpt->m.to->mchan == nil){
|
||
runlock(&shr->umh.lock);
|
||
error(Eshutdown);
|
||
}
|
||
nc = mpt->m.to->mchan;
|
||
incref(&nc->r);
|
||
runlock(&shr->umh.lock);
|
||
if(mode != nc->mode){
|
||
cclose(nc);
|
||
error(Eperm);
|
||
}
|
||
cclose(c);
|
||
return nc;
|
||
}
|
||
c->mode = mode;
|
||
c->flag |= COPEN;
|
||
c->offset = 0;
|
||
return c;
|
||
}
|
||
|
||
/* chan.c */
|
||
Chan* createdir(Chan *c, Mhead *m);
|
||
|
||
static Chan*
|
||
shrcreate(Chan *c, char *name, unsigned long omode, unsigned long perm)
|
||
{
|
||
Sch *sch;
|
||
Shr *shr;
|
||
Mpt *mpt;
|
||
Mhead *h;
|
||
Mount *m;
|
||
Chan *nc;
|
||
int mode;
|
||
|
||
mode = openmode(omode);
|
||
sch = tosch(c);
|
||
switch(sch->level){
|
||
case Qcroot:
|
||
case Qcshr:
|
||
if(jehanne_strcmp(up->user, "none") == 0)
|
||
error(Eperm);
|
||
}
|
||
switch(sch->level){
|
||
default:
|
||
error(Eperm);
|
||
case Qshr:
|
||
incref(&c->r);
|
||
if(waserror()){
|
||
cclose(c);
|
||
nexterror();
|
||
}
|
||
nc = createdir(c, &sch->shr->umh);
|
||
poperror();
|
||
if(waserror()){
|
||
cclose(nc);
|
||
nexterror();
|
||
}
|
||
nc->dev->create(nc, name, omode, perm);
|
||
poperror();
|
||
cclose(c);
|
||
return nc;
|
||
case Qcroot:
|
||
if(up->pgrp->noattach)
|
||
error(Enoattach);
|
||
if((perm & DMDIR) == 0 || mode != OREAD)
|
||
error(Eperm);
|
||
if(jehanne_strlen(name) >= sizeof(up->genbuf))
|
||
error(Etoolong);
|
||
qlock(&shrslk);
|
||
if(waserror()){
|
||
qunlock(&shrslk);
|
||
nexterror();
|
||
}
|
||
for(shr = shrs; shr != nil; shr = shr->next)
|
||
if(jehanne_strcmp(name, shr->name) == 0)
|
||
error(Eexist);
|
||
|
||
shr = smalloc(sizeof(*shr));
|
||
incref(&shr->ref);
|
||
shr->id = shrid++;
|
||
|
||
kstrdup(&shr->name, name);
|
||
kstrdup(&shr->owner, up->user);
|
||
shr->perm = perm;
|
||
|
||
incref(&shr->ref);
|
||
shr->next = shrs;
|
||
shrs = shr;
|
||
|
||
poperror();
|
||
qunlock(&shrslk);
|
||
|
||
c->qid = shrqid(sch->level = Qcshr, shr->id);
|
||
sch->shr = shr;
|
||
break;
|
||
case Qcshr:
|
||
if(up->pgrp->noattach)
|
||
error(Enoattach);
|
||
if((perm & DMDIR) != 0 || mode != OWRITE)
|
||
error(Eperm);
|
||
|
||
shr = sch->shr;
|
||
if(jehanne_strcmp(shr->owner, eve) == 0 && !iseve())
|
||
error(Eperm);
|
||
devpermcheck(shr->owner, shr->perm, ORDWR);
|
||
|
||
if(jehanne_strlen(name) >= sizeof(up->genbuf))
|
||
error(Etoolong);
|
||
|
||
h = &shr->umh;
|
||
wlock(&h->lock);
|
||
if(waserror()){
|
||
wunlock(&h->lock);
|
||
nexterror();
|
||
}
|
||
for(m = h->mount; m != nil; m = m->next){
|
||
mpt = tompt(m);
|
||
if(jehanne_strcmp(name, mpt->name) == 0)
|
||
error(Eexist);
|
||
}
|
||
|
||
mpt = smalloc(sizeof(*mpt));
|
||
incref(&mpt->ref);
|
||
mpt->id = mptid++;
|
||
|
||
kstrdup(&mpt->name, name);
|
||
kstrdup(&mpt->owner, up->user);
|
||
mpt->perm = perm;
|
||
|
||
incref(&mpt->ref);
|
||
mpt->m.mflag = (h->mount == nil) ? MCREATE : 0;
|
||
mpt->m.next = h->mount;
|
||
h->mount = &mpt->m;
|
||
|
||
poperror();
|
||
wunlock(&h->lock);
|
||
|
||
c->qid = shrqid(sch->level = Qcmpt, mpt->id);
|
||
sch->mpt = mpt;
|
||
break;
|
||
}
|
||
c->flag |= COPEN;
|
||
c->mode = mode;
|
||
return c;
|
||
}
|
||
|
||
static void
|
||
shrremove(Chan *c)
|
||
{
|
||
Mount *m, **ml;
|
||
Shr *shr, **sl;
|
||
Sch *sch;
|
||
Mpt *mpt;
|
||
Mhead *h;
|
||
|
||
sch = tosch(c);
|
||
if(waserror()){
|
||
shrclunk(c);
|
||
nexterror();
|
||
}
|
||
switch(sch->level){
|
||
default:
|
||
error(Eperm);
|
||
case Qcshr:
|
||
case Qcmpt:
|
||
shr = sch->shr;
|
||
if(!iseve()){
|
||
if(jehanne_strcmp(shr->owner, eve) == 0)
|
||
error(Eperm);
|
||
devpermcheck(shr->owner, shr->perm, ORDWR);
|
||
}
|
||
}
|
||
switch(sch->level){
|
||
case Qcshr:
|
||
h = &shr->umh;
|
||
qlock(&shrslk);
|
||
rlock(&h->lock);
|
||
if(h->mount != nil){
|
||
runlock(&h->lock);
|
||
qunlock(&shrslk);
|
||
error("directory not empty");
|
||
}
|
||
runlock(&h->lock);
|
||
for(sl = &shrs; *sl != nil; sl = &((*sl)->next))
|
||
if(*sl == shr){
|
||
*sl = shr->next;
|
||
shr->next = nil;
|
||
putshr(shr);
|
||
break;
|
||
}
|
||
qunlock(&shrslk);
|
||
break;
|
||
case Qcmpt:
|
||
mpt = sch->mpt;
|
||
m = &mpt->m;
|
||
h = &shr->umh;
|
||
wlock(&h->lock);
|
||
for(ml = &h->mount; *ml != nil; ml = &((*ml)->next))
|
||
if(*ml == m){
|
||
*ml = m->next;
|
||
m->next = nil;
|
||
putmpt(mpt);
|
||
break;
|
||
}
|
||
wunlock(&h->lock);
|
||
break;
|
||
}
|
||
poperror();
|
||
shrclunk(c);
|
||
}
|
||
|
||
static long
|
||
shrwstat(Chan *c, uint8_t *dp, long n)
|
||
{
|
||
char *strs;
|
||
Mhead *h;
|
||
Sch *sch;
|
||
Ent *ent;
|
||
Dir d;
|
||
|
||
strs = smalloc(n);
|
||
if(waserror()){
|
||
jehanne_free(strs);
|
||
nexterror();
|
||
}
|
||
n = jehanne_convM2D(dp, n, &d, strs);
|
||
if(n == 0)
|
||
error(Eshortstat);
|
||
|
||
h = nil;
|
||
sch = tosch(c);
|
||
switch(sch->level){
|
||
default:
|
||
error(Eperm);
|
||
case Qcshr:
|
||
ent = sch->shr;
|
||
qlock(&shrslk);
|
||
if(waserror()){
|
||
qunlock(&shrslk);
|
||
nexterror();
|
||
}
|
||
break;
|
||
case Qcmpt:
|
||
ent = sch->mpt;
|
||
h = &sch->shr->umh;
|
||
wlock(&h->lock);
|
||
if(waserror()){
|
||
wunlock(&h->lock);
|
||
nexterror();
|
||
}
|
||
break;
|
||
}
|
||
|
||
if(jehanne_strcmp(ent->owner, up->user) && !iseve())
|
||
error(Eperm);
|
||
|
||
if(d.name != nil && *d.name && jehanne_strcmp(ent->name, d.name) != 0) {
|
||
if(jehanne_strchr(d.name, '/') != nil)
|
||
error(Ebadchar);
|
||
if(jehanne_strlen(d.name) >= sizeof(up->genbuf))
|
||
error(Etoolong);
|
||
kstrdup(&ent->name, d.name);
|
||
}
|
||
if(d.uid != nil && *d.uid)
|
||
kstrdup(&ent->owner, d.uid);
|
||
if(d.mode != ~0U)
|
||
ent->perm = d.mode & 0777;
|
||
|
||
switch(sch->level){
|
||
case Qcshr:
|
||
poperror();
|
||
qunlock(&shrslk);
|
||
break;
|
||
case Qcmpt:
|
||
poperror();
|
||
wunlock(&h->lock);
|
||
break;
|
||
}
|
||
|
||
poperror();
|
||
jehanne_free(strs);
|
||
|
||
return n;
|
||
}
|
||
|
||
static long
|
||
shrread(Chan *c, void *va, long n, int64_t _)
|
||
{
|
||
Mhead *omh;
|
||
Sch *sch;
|
||
|
||
sch = tosch(c);
|
||
switch(sch->level){
|
||
default:
|
||
error(Egreg);
|
||
case Qroot:
|
||
case Qcroot:
|
||
case Qcshr:
|
||
return devdirread(c, va, n, 0, 0, shrgen);
|
||
case Qshr:
|
||
omh = c->umh;
|
||
c->umh = &sch->shr->umh;
|
||
if(waserror()){
|
||
c->umh = omh;
|
||
nexterror();
|
||
}
|
||
n = unionread(c, va, n);
|
||
poperror();
|
||
c->umh = omh;
|
||
return n;
|
||
}
|
||
}
|
||
|
||
static long
|
||
shrwrite(Chan *c, void *va, long n, int64_t _)
|
||
{
|
||
Sch *sch;
|
||
char *buf, *p, *aname;
|
||
int fd;
|
||
Chan *bc, *c0;
|
||
Mhead *h;
|
||
Mount *m;
|
||
|
||
if(up->pgrp->noattach)
|
||
error(Enoattach);
|
||
sch = tosch(c);
|
||
if(sch->level != Qcmpt)
|
||
error(Egreg);
|
||
|
||
buf = smalloc(n+1);
|
||
if(waserror()){
|
||
jehanne_free(buf);
|
||
nexterror();
|
||
}
|
||
jehanne_memmove(buf, va, n);
|
||
buf[n] = 0;
|
||
|
||
fd = jehanne_strtol(buf, &p, 10);
|
||
if(p == buf || (*p != 0 && *p != '\n'))
|
||
error(Ebadarg);
|
||
if(*p == '\n' && *(p+1) != 0)
|
||
aname = p + 1;
|
||
else
|
||
aname = nil;
|
||
|
||
bc = fdtochan(fd, ORDWR, 0, 1);
|
||
if(waserror()) {
|
||
cclose(bc);
|
||
nexterror();
|
||
}
|
||
c0 = mntattach(bc, nil, aname, 0);
|
||
poperror();
|
||
cclose(bc);
|
||
poperror();
|
||
jehanne_free(buf);
|
||
|
||
if(c0 == nil)
|
||
error(Egreg);
|
||
|
||
m = &sch->mpt->m;
|
||
h = &sch->shr->umh;
|
||
wlock(&h->lock);
|
||
bc = m->to;
|
||
m->to = c0;
|
||
wunlock(&h->lock);
|
||
|
||
if(bc != nil)
|
||
cclose(bc);
|
||
|
||
return n;
|
||
}
|
||
|
||
static void
|
||
shrclose(Chan *c)
|
||
{
|
||
if(c->flag & CRCLOSE)
|
||
shrremove(c);
|
||
else
|
||
shrclunk(c);
|
||
}
|
||
|
||
Dev shrdevtab = {
|
||
L'σ',
|
||
"shr",
|
||
|
||
devreset,
|
||
shrinit,
|
||
devshutdown,
|
||
shrattach,
|
||
shrwalk,
|
||
shrstat,
|
||
shropen,
|
||
shrcreate,
|
||
shrclose,
|
||
shrread,
|
||
devbread,
|
||
shrwrite,
|
||
devbwrite,
|
||
shrremove,
|
||
shrwstat,
|
||
};
|
||
|
||
static void
|
||
chowner(Ent *ent, char *old, char *new)
|
||
{
|
||
if(ent->owner != nil && jehanne_strcmp(old, ent->owner) == 0)
|
||
kstrdup(&ent->owner, new);
|
||
}
|
||
|
||
void
|
||
shrrenameuser(char *old, char *new)
|
||
{
|
||
Shr *shr;
|
||
Mount *m;
|
||
|
||
qlock(&shrslk);
|
||
for(shr = shrs; shr != nil; shr = shr->next){
|
||
wlock(&shr->umh.lock);
|
||
for(m = shr->umh.mount; m != nil; m = m->next)
|
||
chowner(tompt(m), old, new);
|
||
wunlock(&shr->umh.lock);
|
||
chowner(shr, old, new);
|
||
}
|
||
qunlock(&shrslk);
|
||
}
|