1 #include "headers.h"
2
3 typedef struct SmbSharedFileEntry SmbSharedFileEntry;
4 struct SmbSharedFileEntry {
5 SmbSharedFile;
6 Ref;
7 SmbSharedFileEntry *next;
8 };
9
10 static struct {
11 QLock;
12 SmbSharedFileEntry *list;
13 } sharedfiletable;
14
15 typedef struct SmbLockListEntry SmbLockListEntry;
16
17 struct SmbLockListEntry {
18 SmbLock;
19 SmbLockListEntry *next;
20 };
21
22 struct SmbLockList {
23 SmbLockListEntry *head;
24 };
25
26 static int
lockconflict(SmbLock * l1,SmbLock * l2)27 lockconflict(SmbLock *l1, SmbLock *l2)
28 {
29 return l1->base < l2->limit && l2->base < l1->limit;
30 }
31
32 static int
lockorder(SmbLock * l1,SmbLock * l2)33 lockorder(SmbLock *l1, SmbLock *l2)
34 {
35 if (l1->base < l2->base)
36 return -1;
37 if (l1->base > l2->base)
38 return 1;
39 if (l1->limit > l2->limit)
40 return -1;
41 if (l1->limit < l2->limit)
42 return 1;
43 return 0;
44 }
45
46 static void
locklistfree(SmbLockList ** llp)47 locklistfree(SmbLockList **llp)
48 {
49 SmbLockList *ll = *llp;
50 if (ll) {
51 while (ll->head) {
52 SmbLockListEntry *next = ll->head->next;
53 free(ll->head);
54 ll->head = next;
55 }
56 free(ll);
57 *llp = nil;
58 }
59 }
60
61 int
smbsharedfilelock(SmbSharedFile * sf,SmbSession * s,ushort pid,vlong base,vlong limit)62 smbsharedfilelock(SmbSharedFile *sf, SmbSession *s, ushort pid, vlong base, vlong limit)
63 {
64 SmbLockListEntry smblock;
65 SmbLockListEntry *l, *nl, **lp;
66 smblock.s = s;
67 smblock.pid = pid;
68 smblock.base = base;
69 smblock.limit = limit;
70 if (sf->locklist) {
71 for (l = sf->locklist->head; l; l = l->next)
72 if (lockconflict(l, &smblock)) {
73 smblogprintif(smbglobals.log.locks, "smbsharedfilelock: lock [%lld, %lld) failed because conflicts with [%lld, %lld)\n",
74 base, limit, l->base, l->limit);
75 return 0;
76 }
77 }
78 if (sf->locklist == nil)
79 sf->locklist = smbemallocz(sizeof(SmbLockList), 1);
80 for (lp = &sf->locklist->head; (l = *lp) != nil; lp = &l->next)
81 if (lockorder(&smblock, l) <= 0)
82 break;
83 smblogprintif(smbglobals.log.locks, "smbsharedfilelock: lock [%lld, %lld) succeeded\n", base, limit);
84 nl = smbemalloc(sizeof(*nl));
85 *nl = smblock;
86 nl->next = *lp;
87 *lp = nl;
88 //{
89 // smblogprintif(smbglobals.log.locks,"smbsharedfilelock: list\n");
90 // for (l = sf->locklist->head; l; l = l->next)
91 // smblogprintif(smbglobals.log.locks, "smbsharedfilelock: [%lld, %lld)\n", l->base, l->limit);
92 //}
93 return 1;
94 }
95
96 int
smbsharedfileunlock(SmbSharedFile * sf,SmbSession * s,ushort pid,vlong base,vlong limit)97 smbsharedfileunlock(SmbSharedFile *sf, SmbSession *s, ushort pid, vlong base, vlong limit)
98 {
99 SmbLockListEntry smblock;
100 SmbLockListEntry *l, **lp;
101 smblock.s = s;
102 smblock.pid = pid;
103 smblock.base = base;
104 smblock.limit = limit;
105 if (sf->locklist == nil)
106 goto failed;
107 for (lp = &sf->locklist->head; (l = *lp) != nil; lp = &l->next) {
108 if (l->s != s || l->pid != pid)
109 continue;
110 switch (lockorder(&smblock, l)) {
111 case 0:
112 *lp = l->next;
113 free(l);
114 smblogprintif(smbglobals.log.locks, "smbsharedfilelock: unlock [%lld, %lld) succeeded\n", base, limit);
115 return 1;
116 case -1:
117 goto failed;
118 }
119 }
120 failed:
121 smblogprintif(smbglobals.log.locks, "smbsharedfilelock: unlock [%lld, %lld) failed\n", base, limit);
122 return 0;
123 }
124
125 static int
p9denied(int p9mode,int share)126 p9denied(int p9mode, int share)
127 {
128 //smblogprint(-1, "p9denied(%d, %d)\n", p9mode, share);
129 if (share == SMB_OPEN_MODE_SHARE_EXCLUSIVE)
130 return 1;
131 switch (p9mode & 3) {
132 case OREAD:
133 case OEXEC:
134 if (share == SMB_OPEN_MODE_SHARE_DENY_READOREXEC)
135 return 1;
136 break;
137 case OWRITE:
138 if (share == SMB_OPEN_MODE_SHARE_DENY_WRITE)
139 return 1;
140 break;
141 case ORDWR:
142 if (share != SMB_OPEN_MODE_SHARE_DENY_NONE)
143 return 1;
144 break;
145 }
146 return 0;
147 }
148
149 static void
sharesplit(int share,int * denyread,int * denywrite)150 sharesplit(int share, int *denyread, int *denywrite)
151 {
152 switch (share) {
153 case SMB_OPEN_MODE_SHARE_EXCLUSIVE:
154 *denyread = 1;
155 *denywrite = 1;
156 break;
157 case SMB_OPEN_MODE_SHARE_DENY_READOREXEC:
158 *denyread = 1;
159 *denywrite = 0;
160 break;
161 case SMB_OPEN_MODE_SHARE_DENY_WRITE:
162 *denywrite = 0;
163 *denywrite = 1;
164 break;
165 default:
166 *denyread = 0;
167 *denywrite = 0;
168 }
169 }
170
171 static int
sharemake(int denyread,int denywrite)172 sharemake(int denyread, int denywrite)
173 {
174 if (denyread)
175 if (denywrite)
176 return SMB_OPEN_MODE_SHARE_EXCLUSIVE;
177 else
178 return SMB_OPEN_MODE_SHARE_DENY_READOREXEC;
179 else if (denywrite)
180 return SMB_OPEN_MODE_SHARE_DENY_WRITE;
181 else
182 return SMB_OPEN_MODE_SHARE_DENY_NONE;
183 }
184
185 static ushort
sharesubtract(int share1,int share2)186 sharesubtract(int share1, int share2)
187 {
188 int dr1, dw1;
189 int dr2, dw2;
190 sharesplit(share1, &dr1, &dw1);
191 sharesplit(share2, &dr2, &dw2);
192 if (dw2)
193 dw1 = 0;
194 if (dr2)
195 dr1 = 0;
196 return sharemake(dr1, dw1);
197 }
198
199 static int
shareadd(int share1,int share2)200 shareadd(int share1, int share2)
201 {
202 int dr1, dw1;
203 int dr2, dw2;
204 sharesplit(share1, &dr1, &dw1);
205 sharesplit(share2, &dr2, &dw2);
206 if (dw2)
207 dw1 = 1;
208 if (dr2)
209 dr1 = 1;
210 return sharemake(dr1, dw1);
211 }
212
213 SmbSharedFile *
smbsharedfileget(Dir * d,int p9mode,int * sharep)214 smbsharedfileget(Dir *d, int p9mode, int *sharep)
215 {
216 SmbSharedFileEntry *sfe;
217 qlock(&sharedfiletable);
218 for (sfe = sharedfiletable.list; sfe; sfe = sfe->next) {
219 if (sfe->type == d->type && sfe->dev == d->dev && sfe->path == d->qid.path) {
220 if (p9denied(p9mode, sfe->share)) {
221 qunlock(&sharedfiletable);
222 return nil;
223 }
224 *sharep = sharesubtract(*sharep, sfe->share);
225 sfe->share = shareadd(sfe->share, *sharep);
226 sfe->ref++;
227 goto done;
228 }
229 }
230 sfe = smbemallocz(sizeof(SmbSharedFileEntry), 1);
231 sfe->type = d->type;
232 sfe->dev = d->dev;
233 sfe->path = d->qid.path;
234 // sfe->name = smbestrdup(name);
235 sfe->ref = 1;
236 sfe->share = *sharep;
237 sfe->next = sharedfiletable.list;
238 sharedfiletable.list = sfe;
239 done:
240 smblogprintif(smbglobals.log.sharedfiles, "smbsharedfileget: ref %d share %d\n",
241 sfe->ref, sfe->share);
242 qunlock(&sharedfiletable);
243 return sfe;
244 }
245
246 void
smbsharedfileput(SmbFile * f,SmbSharedFile * sf,int share)247 smbsharedfileput(SmbFile *f, SmbSharedFile *sf, int share)
248 {
249 SmbSharedFileEntry *sfe, **sfep;
250 qlock(&sharedfiletable);
251 for (sfep = &sharedfiletable.list; (sfe = *sfep) != nil; sfep = &sfe->next) {
252 if (sfe == sf) {
253 sfe->ref--;
254 if (sfe->ref == 0) {
255 *sfep = sfe->next;
256 if (sfe->deleteonclose && f)
257 smbremovefile(f->t, nil, f->name);
258 smblogprintif(smbglobals.log.sharedfiles, "smbsharedfileput: removed\n");
259 locklistfree(&sfe->locklist);
260 free(sfe);
261 }
262 else {
263 sfe->share = sharesubtract(sfe->share, share);
264 smblogprintif(smbglobals.log.sharedfiles,
265 "smbsharedfileput: ref %d share %d\n", sfe->ref, sfe->share);
266 }
267 break;
268 }
269 }
270 qunlock(&sharedfiletable);
271 }
272