xref: /inferno-os/liblogfs/create.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 #include "lib9.h"
2 #include "logfs.h"
3 #include "local.h"
4 
5 char *
6 logfsservercreate(LogfsServer *server, u32int fid, char *name, u32int perm, uchar mode, Qid *qid)
7 {
8 	Fid *f;
9 	char *uid;
10 	ulong newpath;
11 	char *errmsg;
12 	Entry *e, *xe, *pe;
13 	Path *pp;
14 	LogMessage s;
15 
16 	if(server->trace > 1)
17 		print("logfsservercreate(%ud, %s, 0%uo, %.2ux)\n", fid, name, perm, mode);
18 	f = logfsfidmapfindentry(server->fidmap, fid);
19 	if(f == nil)
20 		return logfsebadfid;
21 	if(f->openmode >= 0)
22 		return logfsefidopen;
23 	pe = f->entry;
24 	if((pe->qid.type & QTDIR) == 0)
25 		return Enotdir;
26 	if((perm & DMDIR) != 0 && ((mode & OTRUNC) != 0 || (mode &  3) != OREAD))
27 		return Eperm;
28 	if(!logfsuserpermcheck(server, pe, f, DMWRITE))
29 		return Eperm;
30 	/*
31 	 * illegal names
32 	 */
33 	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
34 		return Eperm;
35 	for(xe = pe->u.dir.list; xe; xe = xe->next)
36 		if(strcmp(xe->name, name) == 0)
37 			return Eexist;
38 	newpath = ++server->path;
39 	while(logfspathmapfindentry(server->pathmap, newpath))
40 		newpath++;	/* shouldn't happen */
41 	uid = logfsisfindidfromname(server->is, f->uname);
42 	errmsg = logfsentrynew(server, 1, newpath,
43 		pe, name, uid, f->entry->gid, logfsnow(), uid, perm, 0, 0, &e);
44 	if(errmsg)
45 		return errmsg;
46 	errmsg = logfspathmapnewentry(server->pathmap, newpath, e, &pp);
47 	/* pp is guaranteed to be non-null */
48 	if(errmsg) {
49 		logfsfreemem(e);
50 		return errmsg;
51 	}
52 	s.type = LogfsLogTcreate;
53 	s.path = e->parent->qid.path;
54 	s.u.create.perm = e->perm;
55 	s.u.create.newpath = e->qid.path;
56 	s.u.create.mtime = e->mtime;
57 	/* TODO - check with forsyth whether cvers is needed in dirs */
58 	s.u.create.cvers = (e->qid.type & QTDIR) ? 0 : e->u.file.cvers;
59 	s.u.create.name = e->name;
60 	s.u.create.uid = e->uid;
61 	s.u.create.gid = e->gid;
62 	errmsg = logfslog(server, 1, &s);
63 	if(errmsg) {
64 		logfsfreemem(e);
65 		logfspathmapdeleteentry(server->pathmap, newpath);
66 		return errmsg;
67 	}
68 	server->path = newpath;
69 	e->inuse++;
70 	e->qid.vers++;
71 	e->next = pe->u.dir.list;
72 	pe->u.dir.list = e;
73 	f->openmode = mode;
74 	/*
75 	 * TODO why does forsyth increment inuse for dir? - we're moving the fid onto the new file
76 	 * so a decrement seems better
77 	 */
78 	logfsentryclunk(pe);
79 	f->entry = e;
80 	*qid = e->qid;
81 	return nil;
82 }
83