xref: /plan9/sys/src/cmd/aquarela/smbsharedfile.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
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