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 27 lockconflict(SmbLock *l1, SmbLock *l2) 28 { 29 return l1->base < l2->limit && l2->base < l1->limit; 30 } 31 32 static int 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 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 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 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 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 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 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 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 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 * 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 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