diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aquarela/smbsharedfile.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aquarela/smbsharedfile.c')
-rwxr-xr-x | sys/src/cmd/aquarela/smbsharedfile.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/sys/src/cmd/aquarela/smbsharedfile.c b/sys/src/cmd/aquarela/smbsharedfile.c new file mode 100755 index 000000000..6203fe60a --- /dev/null +++ b/sys/src/cmd/aquarela/smbsharedfile.c @@ -0,0 +1,271 @@ +#include "headers.h" + +typedef struct SmbSharedFileEntry SmbSharedFileEntry; +struct SmbSharedFileEntry { + SmbSharedFile; + Ref; + SmbSharedFileEntry *next; +}; + +static struct { + QLock; + SmbSharedFileEntry *list; +} sharedfiletable; + +typedef struct SmbLockListEntry SmbLockListEntry; + +struct SmbLockListEntry { + SmbLock; + SmbLockListEntry *next; +}; + +struct SmbLockList { + SmbLockListEntry *head; +}; + +static int +lockconflict(SmbLock *l1, SmbLock *l2) +{ + return l1->base < l2->limit && l2->base < l1->limit; +} + +static int +lockorder(SmbLock *l1, SmbLock *l2) +{ + if (l1->base < l2->base) + return -1; + if (l1->base > l2->base) + return 1; + if (l1->limit > l2->limit) + return -1; + if (l1->limit < l2->limit) + return 1; + return 0; +} + +static void +locklistfree(SmbLockList **llp) +{ + SmbLockList *ll = *llp; + if (ll) { + while (ll->head) { + SmbLockListEntry *next = ll->head->next; + free(ll->head); + ll->head = next; + } + free(ll); + *llp = nil; + } +} + +int +smbsharedfilelock(SmbSharedFile *sf, SmbSession *s, ushort pid, vlong base, vlong limit) +{ + SmbLockListEntry smblock; + SmbLockListEntry *l, *nl, **lp; + smblock.s = s; + smblock.pid = pid; + smblock.base = base; + smblock.limit = limit; + if (sf->locklist) { + for (l = sf->locklist->head; l; l = l->next) + if (lockconflict(l, &smblock)) { + smblogprintif(smbglobals.log.locks, "smbsharedfilelock: lock [%lld, %lld) failed because conflicts with [%lld, %lld)\n", + base, limit, l->base, l->limit); + return 0; + } + } + if (sf->locklist == nil) + sf->locklist = smbemallocz(sizeof(SmbLockList), 1); + for (lp = &sf->locklist->head; (l = *lp) != nil; lp = &l->next) + if (lockorder(&smblock, l) <= 0) + break; + smblogprintif(smbglobals.log.locks, "smbsharedfilelock: lock [%lld, %lld) succeeded\n", base, limit); + nl = smbemalloc(sizeof(*nl)); + *nl = smblock; + nl->next = *lp; + *lp = nl; +//{ +// smblogprintif(smbglobals.log.locks,"smbsharedfilelock: list\n"); +// for (l = sf->locklist->head; l; l = l->next) +// smblogprintif(smbglobals.log.locks, "smbsharedfilelock: [%lld, %lld)\n", l->base, l->limit); +//} + return 1; +} + +int +smbsharedfileunlock(SmbSharedFile *sf, SmbSession *s, ushort pid, vlong base, vlong limit) +{ + SmbLockListEntry smblock; + SmbLockListEntry *l, **lp; + smblock.s = s; + smblock.pid = pid; + smblock.base = base; + smblock.limit = limit; + if (sf->locklist == nil) + goto failed; + for (lp = &sf->locklist->head; (l = *lp) != nil; lp = &l->next) { + if (l->s != s || l->pid != pid) + continue; + switch (lockorder(&smblock, l)) { + case 0: + *lp = l->next; + free(l); + smblogprintif(smbglobals.log.locks, "smbsharedfilelock: unlock [%lld, %lld) succeeded\n", base, limit); + return 1; + case -1: + goto failed; + } + } +failed: + smblogprintif(smbglobals.log.locks, "smbsharedfilelock: unlock [%lld, %lld) failed\n", base, limit); + return 0; +} + +static int +p9denied(int p9mode, int share) +{ +//smblogprint(-1, "p9denied(%d, %d)\n", p9mode, share); + if (share == SMB_OPEN_MODE_SHARE_EXCLUSIVE) + return 1; + switch (p9mode & 3) { + case OREAD: + case OEXEC: + if (share == SMB_OPEN_MODE_SHARE_DENY_READOREXEC) + return 1; + break; + case OWRITE: + if (share == SMB_OPEN_MODE_SHARE_DENY_WRITE) + return 1; + break; + case ORDWR: + if (share != SMB_OPEN_MODE_SHARE_DENY_NONE) + return 1; + break; + } + return 0; +} + +static void +sharesplit(int share, int *denyread, int *denywrite) +{ + switch (share) { + case SMB_OPEN_MODE_SHARE_EXCLUSIVE: + *denyread = 1; + *denywrite = 1; + break; + case SMB_OPEN_MODE_SHARE_DENY_READOREXEC: + *denyread = 1; + *denywrite = 0; + break; + case SMB_OPEN_MODE_SHARE_DENY_WRITE: + *denywrite = 0; + *denywrite = 1; + break; + default: + *denyread = 0; + *denywrite = 0; + } +} + +static int +sharemake(int denyread, int denywrite) +{ + if (denyread) + if (denywrite) + return SMB_OPEN_MODE_SHARE_EXCLUSIVE; + else + return SMB_OPEN_MODE_SHARE_DENY_READOREXEC; + else if (denywrite) + return SMB_OPEN_MODE_SHARE_DENY_WRITE; + else + return SMB_OPEN_MODE_SHARE_DENY_NONE; +} + +static ushort +sharesubtract(int share1, int share2) +{ + int dr1, dw1; + int dr2, dw2; + sharesplit(share1, &dr1, &dw1); + sharesplit(share2, &dr2, &dw2); + if (dw2) + dw1 = 0; + if (dr2) + dr1 = 0; + return sharemake(dr1, dw1); +} + +static int +shareadd(int share1, int share2) +{ + int dr1, dw1; + int dr2, dw2; + sharesplit(share1, &dr1, &dw1); + sharesplit(share2, &dr2, &dw2); + if (dw2) + dw1 = 1; + if (dr2) + dr1 = 1; + return sharemake(dr1, dw1); +} + +SmbSharedFile * +smbsharedfileget(Dir *d, int p9mode, int *sharep) +{ + SmbSharedFileEntry *sfe; + qlock(&sharedfiletable); + for (sfe = sharedfiletable.list; sfe; sfe = sfe->next) { + if (sfe->type == d->type && sfe->dev == d->dev && sfe->path == d->qid.path) { + if (p9denied(p9mode, sfe->share)) { + qunlock(&sharedfiletable); + return nil; + } + *sharep = sharesubtract(*sharep, sfe->share); + sfe->share = shareadd(sfe->share, *sharep); + sfe->ref++; + goto done; + } + } + sfe = smbemallocz(sizeof(SmbSharedFileEntry), 1); + sfe->type = d->type; + sfe->dev = d->dev; + sfe->path = d->qid.path; +// sfe->name = smbestrdup(name); + sfe->ref = 1; + sfe->share = *sharep; + sfe->next = sharedfiletable.list; + sharedfiletable.list = sfe; +done: + smblogprintif(smbglobals.log.sharedfiles, "smbsharedfileget: ref %d share %d\n", + sfe->ref, sfe->share); + qunlock(&sharedfiletable); + return sfe; +} + +void +smbsharedfileput(SmbFile *f, SmbSharedFile *sf, int share) +{ + SmbSharedFileEntry *sfe, **sfep; + qlock(&sharedfiletable); + for (sfep = &sharedfiletable.list; (sfe = *sfep) != nil; sfep = &sfe->next) { + if (sfe == sf) { + sfe->ref--; + if (sfe->ref == 0) { + *sfep = sfe->next; + if (sfe->deleteonclose && f) + smbremovefile(f->t, nil, f->name); + smblogprintif(smbglobals.log.sharedfiles, "smbsharedfileput: removed\n"); + locklistfree(&sfe->locklist); + free(sfe); + } + else { + sfe->share = sharesubtract(sfe->share, share); + smblogprintif(smbglobals.log.sharedfiles, + "smbsharedfileput: ref %d share %d\n", sfe->ref, sfe->share); + } + break; + } + } + qunlock(&sharedfiletable); +} |