예제 #1
0
파일: auth.c 프로젝트: 99years/plan9
static Auth *
auth_plain(char *windom, char *keyp, uchar *chal, int len)
{
	UserPasswd *up;
	static Auth *ap;

	USED(chal, len);

	up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs %s",
		windom, keyp);
	if(! up)
		sysfatal("cannot get key - %r");

	ap = emalloc9p(sizeof(Auth));
	memset(ap, 0, sizeof(ap));
	ap->user = estrdup9p(up->user);
	ap->windom = estrdup9p(windom);

	ap->resp[0] = estrdup9p(up->passwd);
	ap->len[0] = strlen(up->passwd);
	memset(up->passwd, 0, strlen(up->passwd));
	free(up);

	return ap;
}
예제 #2
0
파일: auth.c 프로젝트: 99years/plan9
static Auth *
auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
{
	int err;
	char user[64];
	Auth *ap;
	MSchapreply mcr;

	err = auth_respond(chal, len, user, sizeof user, &mcr, sizeof mcr,
		auth_getkey, "windom=%s proto=mschap role=client service=cifs %s",
		windom, keyp);
	if(err == -1)
		sysfatal("cannot get key - %r");

	ap = emalloc9p(sizeof(Auth));
	memset(ap, 0, sizeof(ap));
	ap->user = estrdup9p(user);
	ap->windom = estrdup9p(windom);

	/* LM response */
	ap->len[0] = sizeof(mcr.LMresp);
	ap->resp[0] = emalloc9p(ap->len[0]);
	memcpy(ap->resp[0], mcr.LMresp, ap->len[0]);

	/* NTLM response */
	ap->len[1] = sizeof(mcr.NTresp);
	ap->resp[1] = emalloc9p(ap->len[1]);
	memcpy(ap->resp[1], mcr.NTresp, ap->len[1]);

	return ap;
}
예제 #3
0
파일: main.c 프로젝트: Nurb432/plan9front
static void
I2D(Dir *d, Share *sp, char *path, FInfo *fi)
{
	char *name;

	if((name = strrchr(fi->name, '\\')) != nil)
		name++;
	else
		name = fi->name;
	d->name = estrdup9p(name);
	d->type = 'C';
	d->dev = sp->tid;
	d->uid = estrdup9p("bill");
	d->gid = estrdup9p("trog");
	d->muid = estrdup9p("boyd");
	d->atime = fi->accessed;
	d->mtime = fi->written;

	if(fi->attribs & ATTR_READONLY)
		d->mode = 0444;
	else
		d->mode = 0666;

	d->length = fi->size;
	d->qid = mkqid(path, fi->attribs & ATTR_DIRECTORY, fi->changed, 0, 0);

	if(fi->attribs & ATTR_DIRECTORY){
		d->length = 0;
		d->mode |= DMDIR|0111;
	}
}
예제 #4
0
파일: grepfs.c 프로젝트: spewspew/grepfs
int
fill(Dir *dir, int path)
{
	ulong mode;

	if(grepstate == Waiting)
		mode = 0200;
	else
		mode = 0400;
	switch(path){
	case Qroot:
		dir->qid = (Qid){Qroot, 0, QTDIR};
		dir->mode = 0755 | DMDIR;
		dir->atime = starttime;
		dir->mtime = starttime;
		dir->name = estrdup9p("/");
		break;
	case Qgrep:
		dir->qid = (Qid){Qgrep, grepvers, QTFILE};
		dir->mode = mode;
		dir->atime = grepatime;
		dir->mtime = grepmtime;
		dir->name = estrdup9p(grepname);
		break;
	default:
		return -1;
	}
	dir->uid = estrdup9p(grepuser);
	dir->gid = estrdup9p("glenda");
	dir->muid = estrdup9p("ron");
	return 0;
}
예제 #5
0
파일: srv.c 프로젝트: 99years/plan9
static void
sstat(Srv *srv, Req *r)
{
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
		respond(r, Eunknownfid);
		return;
	}
	if(r->fid->file){
		/* should we rlock the file? */
		r->d = r->fid->file->Dir;
		if(r->d.name)
			r->d.name = estrdup9p(r->d.name);
		if(r->d.uid)
			r->d.uid = estrdup9p(r->d.uid);
		if(r->d.gid)
			r->d.gid = estrdup9p(r->d.gid);
		if(r->d.muid)
			r->d.muid = estrdup9p(r->d.muid);
	}
	if(srv->stat)	
		srv->stat(r);	
	else if(r->fid->file)
		respond(r, nil);
	else
		respond(r, Enostat);
}
예제 #6
0
파일: sid2name.c 프로젝트: 99years/plan9
void
upd_names(Session *s, Share *sp, char *path, Dir *d)
{
	int fh, result;
	char *usid, *gsid;
	FInfo fi;

	if(d->uid)
		free(d->uid);
	if(d->gid)
		free(d->gid);

	if((fh = CIFS_NT_opencreate(s, sp, path, 0, 0, 0, READ_CONTROL,
	    FILE_SHARE_ALL, FILE_OPEN, &result, &fi)) == -1){
		d->uid = estrdup9p("unknown");
		d->gid = estrdup9p("unknown");
		return;
	}
	usid = nil;
	gsid = nil;
	TNTquerysecurity(s, sp, fh, &usid, &gsid);
	d->uid = sid2name(usid);
	d->gid = sid2name(gsid);
	if(fh != -1)
		CIFSclose(s, sp, fh);
}
예제 #7
0
파일: disksim.c 프로젝트: 99years/plan9
void
main(int argc, char **argv)
{
	char *file;

	file = nil;
	quotefmtinstall();
	time0 = time(0);
	if(NPTR != BLKSZ/sizeof(void*))
		sysfatal("unexpected pointer size");

	ARGBEGIN{
	case 'D':
		chatty9p++;
		break;
	case 'f':
		file = EARGF(usage());
		break;
	case 'r':
		rdonly = 1;
		break;
	case 's':
		srvname = EARGF(usage());
		break;
	case 'm':
		mtpt = EARGF(usage());
		break;
	default:
		usage();
	}ARGEND

	if(argc > 1)
		usage();
	if(argc == 1)
		sdname = argv[0];

	if(file){
		if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)
			sysfatal("open %s: %r", file);
	}

	inquiry = estrdup9p(inquiry);
	tab[0].name = estrdup9p("data");
	tab[0].inuse = 1;
	tab[0].mode = 0666;

	postmountsrv(&fs, srvname, mtpt, MBEFORE);
	exits(nil);
}
예제 #8
0
파일: tagfs.c 프로젝트: ericvh/tagfs
static void
fscreate(Req* r)
{
	File*	file;
	Query*	q;
	char*	name;
	char*	uid;
	int	mode;
	File*	f;

	file = r->fid->file;
	name = r->ifcall.name;
	uid = r->fid->uid;
	mode = r->fid->file->dir.mode & 0x777 & r->ifcall.perm;
	mode |= (r->ifcall.perm & ~0x777);
	if(mode&DMDIR){
		respond(r, "queries cannot be directories");
		return;
	}
	if(f = createfile(file, name, uid, mode, nil)){
		q = emalloc9p(sizeof *q);
		q->text = estrdup9p("");
		q->expr = nil;
		f->aux = q;
		closefile(r->fid->file);
		r->fid->file = f;
		r->ofcall.qid = f->dir.qid;
		respond(r, nil);
	} else
		respond(r, "problem creating file");
}
예제 #9
0
파일: main.c 프로젝트: Nurb432/plan9front
/*
 * used only for root dir and shares
 */
static void
V2D(Dir *d, Qid qid, char *name)
{
	memset(d, 0, sizeof(Dir));
	d->type = 'C';
	d->dev = 1;
	d->name = estrdup9p(name);
	d->uid = estrdup9p("bill");
	d->muid = estrdup9p("boyd");
	d->gid = estrdup9p("trog");
	d->mode = 0755 | DMDIR;
	d->atime = time(nil);
	d->mtime = d->atime;
	d->length = 0;
	d->qid = qid;
}
예제 #10
0
파일: main.c 프로젝트: Nurb432/plan9front
static char*
fsclone(Fid *ofid, Fid *fid)
{
	Aux *oa = ofid->aux;
	Aux *a = emalloc9p(sizeof(Aux));

	fid->aux = a;

	memset(a, 0, sizeof(Aux));
	a->sh = -1;
	a->fh = -1;
	a->sp = oa->sp;
	a->path = estrdup9p(oa->path);

	if(Auxroot){
		a->prev = Auxroot;
		a->next = Auxroot->next;
		Auxroot->next->prev = a;
		Auxroot->next = a;
	} else {
		Auxroot = a;
		a->next = a;
		a->prev = a;
	}
	return nil;
}
예제 #11
0
파일: disksim.c 프로젝트: 99years/plan9
int
addpart(char *name, vlong start, vlong end)
{
	int i;

	if(start < 0 || start > end || end > nsect){
		werrstr("bad partition boundaries");
		return -1;
	}

	for(i=0; i<nelem(tab); i++)
		if(tab[i].inuse == 0)
			break;
	if(i == nelem(tab)){
		werrstr("no free partition slots");
		return -1;	
	}

	free(tab[i].name);
	tab[i].inuse = 1;
	tab[i].name = estrdup9p(name);
	tab[i].offset = start;
	tab[i].length = end - start;
	tab[i].mode = ctlmode;
	tab[i].vers++;

	return 0;
}
예제 #12
0
파일: srv.c 프로젝트: 99years/plan9
static void
swalk(Srv *srv, Req *r)
{
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
		respond(r, Eunknownfid);
		return;
	}
	if(r->fid->omode != -1){
		respond(r, "cannot clone open fid");
		return;
	}
	if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){
		respond(r, Ewalknodir);
		return;
	}
	if(r->ifcall.fid != r->ifcall.newfid){
		if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){
			respond(r, Edupfid);
			return;
		}
		r->newfid->uid = estrdup9p(r->fid->uid);
	}else{
		incref(&r->fid->ref);
		r->newfid = r->fid;
	}
	if(r->fid->file){
		filewalk(r);
	}else if(srv->walk1)
		walkandclone(r, oldwalk1, oldclone, srv);
	else if(srv->walk)
		srv->walk(r);
	else
		sysfatal("no walk function, no file trees");
}
예제 #13
0
파일: srv.c 프로젝트: 99years/plan9
static void
sattach(Srv *srv, Req *r)
{
	if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){
		respond(r, Edupfid);
		return;
	}
	r->afid = nil;
	if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){
		respond(r, Eunknownfid);
		return;
	}
	r->fid->uid = estrdup9p(r->ifcall.uname);
	if(srv->tree){
		r->fid->file = srv->tree->root;
		incref(r->fid->file);
		r->ofcall.qid = r->fid->file->qid;
		r->fid->qid = r->ofcall.qid;
	}
	if(srv->attach)
		srv->attach(r);
	else
		respond(r, nil);
	return;
}
예제 #14
0
파일: auth.c 프로젝트: AustenConrad/plan-9
void
auth9p(Req *r)
{
	char *spec;
	Afid *afid;
	
	afid = emalloc9p(sizeof(Afid));
	afid->afd = open("/mnt/factotum/rpc", ORDWR);
	if(afid->afd < 0)
		goto error;

	if((afid->rpc = auth_allocrpc(afid->afd)) == nil)
		goto error;

	if(r->ifcall.uname[0] == 0)
		goto error;
	afid->uname = estrdup9p(r->ifcall.uname);
	afid->aname = estrdup9p(r->ifcall.aname);

	spec = r->srv->keyspec;
	if(spec == nil)
		spec = "proto=p9any role=server";

	if(auth_rpc(afid->rpc, "start", spec, strlen(spec)) != ARok)
		goto error;

	r->afid->qid.type = QTAUTH;
	r->afid->qid.path = ++authgen;
	r->afid->qid.vers = 0;
	r->afid->omode = ORDWR;
	r->ofcall.qid = r->afid->qid;
	r->afid->aux = afid;
	respond(r, nil);
	return;

error:
	if(afid->rpc)
		auth_freerpc(afid->rpc);
	if(afid->uname)
		free(afid->uname);
	if(afid->aname)
		free(afid->aname);
	if(afid->afd >= 0)
		close(afid->afd);
	free(afid);
	responderror(r);
}
예제 #15
0
파일: grepfs.c 프로젝트: spewspew/grepfs
void
fsattach(Req *r)
{
	if(grepuser == nil)
		grepuser = estrdup9p(r->ifcall.uname);
	r->fid->qid = (Qid){Qroot, 0, QTDIR};
	r->ofcall.qid = r->fid->qid;
	respond(r, nil);
}
예제 #16
0
파일: disksim.c 프로젝트: 99years/plan9
int
rootgen(int off, Dir *d, void*)
{
	memset(d, 0, sizeof *d);
	d->atime = time0;
	d->mtime = time0;
	if(off == 0){
		d->name = estrdup9p(sdname);
		d->mode = DMDIR|0777;
		d->qid.path = Qdir;
		d->qid.type = QTDIR;
		d->uid = estrdup9p("disksim");
		d->gid = estrdup9p("disksim");
		d->muid = estrdup9p("");
		return 0;
	}
	return -1;
}	
예제 #17
0
파일: file.c 프로젝트: dancrossnyc/harvey
Tree*
alloctree(char *uid, char *gid, uint32_t mode, void (*destroy)(File*))
{
	char *muid;
	Tree *t;
	File *f;

	t = emalloc9p(sizeof *t);
	f = allocfile();
	f->Dir.name = estrdup9p("/");
	if(uid == nil){
		uid = getuser();
		if(uid == nil)
			uid = "none";
	}
	uid = estrdup9p(uid);

	if(gid == nil)
		gid = estrdup9p(uid);
	else
		gid = estrdup9p(gid);

	muid = estrdup9p(uid);

	f->Dir.qid = (Qid){0, 0, QTDIR};
	f->Dir.length = 0;
	f->Dir.atime = f->Dir.mtime = time(0);
	f->Dir.mode = DMDIR | mode;
	f->tree = t;
	f->parent = f;
	f->Dir.uid = uid;
	f->Dir.gid = gid;
	f->Dir.muid = muid;

	incref(&f->Ref);
	t->root = f;
	t->qidgen = 0;
	t->dirqidgen = 1;
	if(destroy == nil)
		destroy = nop;
	t->destroy = destroy;

	return t;
}
예제 #18
0
static void
tfilestat(Req *r, char *path, vlong length)
{
	memset(&r->d, 0, sizeof(r->d));
	r->d.uid = estrdup9p("tftp");
	r->d.gid = estrdup9p("tftp");
	r->d.name = estrdup9p(basename(path));
	r->d.atime = r->d.mtime = time0;
	r->d.length = length;
	r->d.qid.path = r->fid->qid.path;
	if(r->fid->qid.path & Qdata){
		r->d.qid.type = 0;
		r->d.mode = 0555;
	} else {
		r->d.qid.type = QTDIR;
		r->d.mode = DMDIR|0555;
	}
	respond(r, nil);
}
예제 #19
0
파일: mntgen.c 프로젝트: 99years/plan9
static int
dirgen(int i, Dir *d, void*)
{
	if(i >= ntab)
		return -1;
	memset(d, 0, sizeof *d);
	d->qid.type = QTDIR;
	d->uid = estrdup9p("sys");
	d->gid = estrdup9p("sys");
	d->mode = DMDIR|0555;
	d->length = 0;
	if(i == -1){
		d->name = estrdup9p("/");
		d->atime = d->mtime = time0;
	}else{
		d->qid.path = tab[i].qid;
		d->name = estrdup9p(tab[i].name);
		d->atime = d->mtime = tab[i].time;
	}
	return 0;
}
예제 #20
0
파일: sid2name.c 프로젝트: 99years/plan9
static char *
sid2name(char *sid)
{
	int i;
	char *rid;

	if(sid == nil || (rid = strrchr(sid, '-')) == nil || *++rid == 0)
		return estrdup9p("-");

	for(i = 0; i < nelem(known); i++){
		if(strcmp(known[i].auth, sid) == 0 && known[i].rid == nil)
			return estrdup9p(known[i].name);

		if(strlen(known[i].auth) < strlen(sid) &&
		    strncmp(known[i].auth, sid, strlen(known[i].auth)) == 0 &&
		    known[i].rid && strcmp(known[i].rid, rid) == 0)
			return estrdup9p(known[i].name);
	}

	return estrdup9p(rid);
}
예제 #21
0
파일: fs.c 프로젝트: grobe0ba/plan9front
static char*
fsmkuid(char *s)
{
	if(s){
		char *x;

		while(x = strchr(s, '<'))
			s = x+1;
		s = estrdup9p(s);
		if(x = strchr(s, '>'))
			*x = 0;
		if(x = strchr(s, '@'))
			*x = 0;
		if(x = strchr(s, '\n'))
			*x = 0;
	}
	if(s == nil || *s == 0){
		free(s);
		s = estrdup9p("hgfs");
	}
	return s;
}
예제 #22
0
파일: disksim.c 프로젝트: 99years/plan9
int
dirgen(int off, Dir *d, void*)
{
	int n, j;

	memset(d, 0, sizeof *d);
	d->atime = time0;
	d->mtime = time0;
	if(off == 0){
		d->name = estrdup9p("ctl");
		d->mode = ctlmode;
		d->qid.path = Qctl;
		goto Have;
	}

	off--;
	n = 0;
	for(j=0; j<nelem(tab); j++){
		if(tab[j].inuse==0)
			continue;
		if(n == off){
			d->name = estrdup9p(tab[j].name);
			d->length = tab[j].length*sectsize;
			d->mode = tab[j].mode;
			d->qid.path = Qpart+j;
			d->qid.vers = tab[j].vers;
			goto Have;
		}
		n++;
	}
	return -1;

Have:
	d->uid = estrdup9p("disksim");
	d->gid = estrdup9p("disksim");
	d->muid = estrdup9p("");
	return 0;
}
예제 #23
0
파일: partfs.c 프로젝트: Nurb432/plan9front
int
dirgen(int off, Dir *d, void*)
{
	int n;
	Part *p;

	memset(d, 0, sizeof *d);
	d->atime = time0;
	d->mtime = time0;
	if(off == 0){
		d->name = estrdup9p("ctl");
		d->mode = ctlmode;
		d->qid.path = Qctl;
		goto Have;
	}

	off--;
	n = 0;
	for(p = tab; p < tab + nelem(tab); p++, n++){
		if(!p->inuse)
			continue;
		if(off-- == 0){
			d->name = estrdup9p(p->name);
			d->length = p->length*sectsize;
			d->mode = p->mode;
			d->qid.path = Qpart + p - tab;
			d->qid.vers = p->vers;
			goto Have;
		}
	}
	return -1;

Have:
	d->uid = estrdup9p("partfs");
	d->gid = estrdup9p("partfs");
	d->muid = estrdup9p("");
	return 0;
}
예제 #24
0
파일: info.c 프로젝트: Nurb432/plan9front
int
dirgeninfo(int slot, Dir *d)
{
	if(slot < 0 || slot > nelem(Infdir))
		return -1;

	memset(d, 0, sizeof(Dir));
	d->type = 'N';
	d->dev = 99;
	d->name = estrdup9p(Infdir[slot].name);
	d->uid = estrdup9p("other");
	d->muid = estrdup9p("other");
	d->gid = estrdup9p("other");
	d->mode = 0666;
	d->atime = time(0);
	d->mtime = d->atime;
	d->qid = mkqid(Infdir[slot].name, 0, 1, Pinfo, slot);
	d->qid.vers = 1;
	d->qid.path = slot;
	d->qid.type = 0;

	return 0;
}
예제 #25
0
파일: mntgen.c 프로젝트: 99years/plan9
static char*
fswalk1(Fid *fid, char *name, void*)
{
	int i;
	Tab *t;
	vlong h;

	if(fid->qid.path != 0){
		/* nothing in child directory */
		if(strcmp(name, "..") == 0){
			if((t = findtab(fid->qid.path)) != nil)
				t->ref--;
			fid->qid.path = 0;
			return nil;
		}
		return "path not found";
	}
	/* root */
	if(strcmp(name, "..") == 0)
		return nil;
	for(i=0; i<ntab; i++)
		if(strcmp(tab[i].name, name) == 0){
			tab[i].ref++;
			fid->qid.path = tab[i].qid;
			return nil;
		}
	h = hash(name);
	if(findtab(h) != nil)
		return "hash collision";

	/* create it */
	if(ntab == mtab){
		if(mtab == 0)
			mtab = 16;
		else
			mtab *= 2;
		tab = erealloc9p(tab, sizeof(tab[0])*mtab);
	}
	tab[ntab].qid = h;
	fid->qid.path = tab[ntab].qid;
	tab[ntab].name = estrdup9p(name);
	tab[ntab].time = time(0);
	tab[ntab].ref = 1;
	ntab++;

	return nil;
}
예제 #26
0
파일: partfs.c 프로젝트: Nurb432/plan9front
void
fsstat(Req *r)
{
	int q;
	Dir *d;
	Part *p;

	d = &r->d;
	memset(d, 0, sizeof *d);
	d->qid = r->fid->qid;
	d->atime = d->mtime = time0;
	q = r->fid->qid.path;
	switch(q){
	case Qroot:
		d->name = estrdup9p("/");
		d->mode = DMDIR|0777;
		break;

	case Qdir:
		d->name = estrdup9p(sdname);
		d->mode = DMDIR|0777;
		break;

	case Qctl:
		d->name = estrdup9p("ctl");
		d->mode = 0666;
		break;

	default:
		q -= Qpart;
		if(q < 0 || q > nelem(tab) || tab[q].inuse == 0 ||
		    r->fid->qid.vers != tab[q].vers){
			respond(r, "partition no longer exists");
			return;
		}
		p = &tab[q];
		d->name = estrdup9p(p->name);
		d->length = p->length * sectsize;
		d->mode = p->mode;
		break;
	}

	d->uid = estrdup9p("partfs");
	d->gid = estrdup9p("partfs");
	d->muid = estrdup9p("");
	respond(r, nil);
}
예제 #27
0
파일: main.c 프로젝트: Nurb432/plan9front
static char *
newpath(char *path, char *name)
{
	char *p, *q;

	assert((p = strrchr(path, '/')) != nil);

	if(strcmp(name, "..") == 0){
		if(p == path)
			return estrdup9p("/");
		q = emalloc9p((p-path)+1);
		strecpy(q, q+(p-path)+1, path);
		return q;
	}
	if(strcmp(path, "/") == 0)
		return smprint("/%s", name);
	return smprint("%s/%s", path, name);
}
예제 #28
0
파일: httpfile.c 프로젝트: 99years/plan9
char*
readhttphdr(Biobuf *netbio, vlong *size)
{
	char *s, *stat;

	stat = nil;
	while((s = Brdstr(netbio, '\n', 1)) != nil && s[0] != '\r'
			&& s[0] != '\0'){
		if(stat == nil)
			stat = estrdup9p(s);
		if(strncmp(s, "Content-Length: ", 16) == 0 && size != nil)
			*size = atoll(s + 16);
		free(s);
	}
	if(stat)
		nocr(stat);

	return stat;
}
예제 #29
0
파일: fs.c 프로젝트: grobe0ba/plan9front
static char*
fsclone(Fid *oldfid, Fid *newfid)
{
	Revfile *orf, *rf;

	rf = nil;
	if(orf = oldfid->aux){
		rf = emalloc9p(sizeof(*rf));
		*rf = *orf;
		if(rf->rlog)
			incref(rf->rlog);
		if(rf->tree)
			incref(rf->tree);
		if(rf->fd >= 0)
			rf->fd = dup(rf->fd, -1);
		if(rf->buf)
			rf->buf = estrdup9p(rf->buf);
	}
	newfid->aux = rf;
	return nil;
}
예제 #30
0
파일: file.c 프로젝트: dancrossnyc/harvey
File*
walkfile(File *f, char *path)
{
	char *os, *s, *nexts;

	if(strchr(path, '/') == nil)
		return walkfile1(f, path);	/* avoid malloc */

	os = s = estrdup9p(path);
	for(; *s; s=nexts){
		if((nexts = strchr(s, '/')) != nil)
			*nexts++ = '\0';
		else
			nexts = s+strlen(s);
		f = walkfile1(f, s);
		if(f == nil)
			break;
	}
	free(os);
	return f;
}