]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/cifsd/file.c
separate MSCHAP(v2) and NTLM(v2) authentication
[plan9front.git] / sys / src / cmd / ip / cifsd / file.c
1 #include <u.h>
2 #include <libc.h>
3 #include "dat.h"
4 #include "fns.h"
5
6 typedef struct Opl Opl;
7 struct Opl
8 {
9         int ref;
10         ulong hash;
11         char *path;
12         Opl *next;
13         File *locked;
14         int dacc;
15         int sacc;
16         int delete;
17 };
18
19 static Opl *locktab[64];
20
21 static Opl*
22 getopl(char **path, int (*namecmp)(char *, char *), int dacc, int sacc)
23 {
24         Opl *opl, **pp;
25         ulong h;
26
27         h = namehash(*path);
28         for(pp = &locktab[h % nelem(locktab)]; *pp; pp=&((*pp)->next)){
29                 opl = *pp;
30                 if(namecmp(opl->path, *path))
31                         continue;
32                 if(sacc == FILE_SHARE_COMPAT){
33                         if(sacc != opl->sacc)
34                                 return nil;
35                         if((opl->dacc | dacc) & WRITEMASK)
36                                 return nil;
37                 } else {
38                         if(opl->sacc == FILE_SHARE_COMPAT)
39                                 return nil;
40                         if((dacc & READMASK) && (opl->sacc & FILE_SHARE_READ)==0)
41                                 return nil;
42                         if((dacc & WRITEMASK) && (opl->sacc & FILE_SHARE_WRITE)==0)
43                                 return nil;
44                         if((dacc & FILE_DELETE) && (opl->sacc & FILE_SHARE_DELETE)==0)
45                                 return nil;
46                 }
47                 opl->ref++;
48                 if(strcmp(opl->path, *path)){
49                         free(*path);
50                         *path = strdup(opl->path);
51                 }
52                 return opl;
53         }
54
55         opl = mallocz(sizeof(*opl), 1);
56         opl->ref = 1;
57         opl->hash = h;
58         opl->dacc = dacc;
59         opl->sacc = sacc;
60         *pp = opl;
61         return opl;
62 }
63
64 static void
65 putopl(Opl *opl)
66 {
67         Opl **pp;
68
69         if(opl==nil || --opl->ref)
70                 return;
71         for(pp = &locktab[opl->hash % nelem(locktab)]; *pp; pp=&((*pp)->next)){
72                 if(*pp == opl){
73                         *pp = opl->next;
74                         opl->next = nil;
75                         break;
76                 }
77         }
78         if(opl->path && opl->delete){
79                 if(debug)
80                         fprint(2, "remove on close: %s\n", opl->path);
81                 if(remove(opl->path) < 0)
82                         logit("remove %s: %r", opl->path);
83         }
84         free(opl->path);
85         free(opl);
86 }
87
88 File*
89 createfile(char *path, int (*namecmp)(char *, char *),
90         int dacc, int sacc, int cdisp, int copt, vlong csize, int fattr, int *pact, Dir **pdir, int *perr)
91 {
92         int err, act, fd, mode, perm, isdir, delete;
93         Opl *o;
94         File *f;
95         Dir *d;
96
97         o = nil;
98         f = nil;
99         d = nil;
100         fd = -1;
101         path = strdup(path);
102
103         if(copt & FILE_OPEN_BY_FILE_ID){
104 unsup:
105                 err = STATUS_NOT_SUPPORTED;
106                 goto out;
107         }
108         if((o = getopl(&path, namecmp, dacc, sacc)) == nil){
109                 err = STATUS_SHARING_VIOLATION;
110                 goto out;
111         }
112         mode = -1;
113         if(dacc & READMASK)
114                 mode += 1;
115         if(dacc & WRITEMASK)
116                 mode += 2;
117         delete = isdir = 0;
118         if(d = xdirstat(&path, namecmp)){
119                 if(mode >= 0 && d->type != '/' && d->type != 'M'){
120 noaccess:
121                         err = STATUS_ACCESS_DENIED;
122                         goto out;
123                 }
124
125                 isdir = (d->qid.type & QTDIR) != 0;
126                 switch(cdisp){
127                 case FILE_SUPERSEDE:
128                         act = FILE_SUPERSEDED;
129                         if(remove(path) < 0){
130                                 logit("remove: %r");
131 oserror:
132                                 err = smbmkerror();
133                                 goto out;
134                         }
135                         goto docreate;
136                 case FILE_OVERWRITE:
137                 case FILE_OVERWRITE_IF:
138                         act = FILE_OVERWRITTEN;
139                         if(isdir || (mode != OWRITE && mode != ORDWR))
140                                 goto noaccess;
141                         d->length = 0;
142                         mode |= OTRUNC;
143                         break;
144                 case FILE_OPEN:
145                 case FILE_OPEN_IF:
146                         act = FILE_OPEND;
147                         break;
148                 case FILE_CREATE:
149                         err = STATUS_OBJECT_NAME_COLLISION;
150                         goto out;
151                 default:
152                         goto unsup;
153                 }
154                 if((copt & FILE_DIRECTORY_FILE) && !isdir)
155                         goto noaccess;
156                 if((copt & FILE_NON_DIRECTORY_FILE) && isdir){
157                         err = STATUS_FILE_IS_A_DIRECTORY;
158                         goto out;
159                 }
160                 if(copt & FILE_DELETE_ON_CLOSE){
161                         if(isdir || (dacc & FILE_DELETE)==0)
162                                 goto noaccess;
163                         delete = 1;
164                 }
165                 if(mode >= 0 && !isdir)
166                         if((fd = open(path, mode)) < 0)
167                                 goto oserror;
168         } else {
169                 switch(cdisp){
170                 case FILE_SUPERSEDE:
171                 case FILE_CREATE:
172                 case FILE_OPEN_IF:
173                 case FILE_OVERWRITE_IF:
174                         act = FILE_CREATED;
175                         break;
176                 case FILE_OVERWRITE:
177                 case FILE_OPEN:
178                         err = smbmkerror();
179                         goto out;
180                 default:
181                         goto unsup;
182                 }
183
184 docreate:
185                 perm = 0666;
186                 if(fattr & ATTR_READONLY)
187                         perm &= ~0222;
188                 if(copt & FILE_DIRECTORY_FILE){
189                         perm |= DMDIR | 0111;
190                         mode = OREAD;
191                         isdir = 1;
192                 }
193                 if(mode < 0)
194                         mode = OREAD;
195                 if(copt & FILE_DELETE_ON_CLOSE){
196                         if(isdir || (dacc & FILE_DELETE)==0)
197                                 goto noaccess;
198                         delete = 1;
199                 }
200                 if((fd = create(path, mode, perm)) < 0){
201                         char *name, *base;
202                         Dir *t;
203
204                         err = smbmkerror();
205                         if(!splitpath(path, &base, &name))
206                                 goto out;
207                         if((t = xdirstat(&base, namecmp)) == nil){
208                                 free(base); free(name);
209                                 goto out;
210                         }
211                         free(t);
212                         free(path); path = conspath(base, name);
213                         free(base); free(name);
214                         if((fd = create(path, mode, perm)) < 0)
215                                 goto oserror;
216                 }
217                 if(csize > 0 && !isdir){
218                         Dir nd;
219
220                         nulldir(&nd);
221                         nd.length = csize;
222                         if(dirfwstat(fd, &nd) < 0)
223                                 goto oserror;
224                 }
225                 if(pdir)
226                         if((d = dirfstat(fd)) == nil)
227                                 goto oserror;
228                 if(isdir){
229                         close(fd);
230                         fd = -1;
231                 }
232         }
233
234         f = mallocz(sizeof(*f), 1);
235         f->ref = 1;
236         f->fd = fd; fd = -1;
237         f->rtype = FileTypeDisk;
238         f->dacc = dacc;
239         o->delete |= delete;
240         if(o->path == nil){
241                 o->path = path;
242                 path = nil;
243         }
244         f->path = o->path;
245         f->aux = o; o = nil;
246         if(pact)
247                 *pact = act;
248         if(pdir){
249                 *pdir = d;
250                 d = nil;
251         }
252         err = 0;
253
254 out:
255         if(perr)
256                 *perr = err;
257         if(fd >= 0)
258                 close(fd);
259         free(path);
260         putopl(o);
261         free(d);
262
263         return f;
264 }
265
266 Dir*
267 statfile(File *f)
268 {
269         if(f == nil)
270                 return nil;
271         if(f->fd >= 0)
272                 return dirfstat(f->fd);
273         else
274                 return dirstat(f->path);
275 }
276
277 int
278 lockfile(File *f)
279 {
280         Opl *opl = f->aux;
281         if(opl->locked && opl->locked != f)
282                 return 0;
283         opl->locked = f;
284         return 1;
285 }
286
287 void
288 deletefile(File *f, int delete)
289 {
290         Opl *opl = f->aux;
291         if(opl->delete == delete)
292                 return;
293         opl->delete = delete;
294 }
295
296 int
297 deletedfile(File *f)
298 {
299         Opl *opl = f->aux;
300         return opl->delete;
301 }
302
303
304 void
305 putfile(File *f)
306 {
307         Opl *opl;
308
309         if(f == nil || --f->ref)
310                 return;
311         if(f->fd >= 0)
312                 close(f->fd);
313         opl = f->aux;
314         if(opl->locked == f)
315                 opl->locked = nil;
316         putopl(opl);
317         free(f);
318 }
319