#include "headers.h" static void smblogprintattr(int cmd, ushort attr) { if (attr & SMB_ATTR_READ_ONLY) smblogprint(cmd, " readonly"); if (attr & SMB_ATTR_HIDDEN) smblogprint(cmd, " hidden"); if (attr & SMB_ATTR_SYSTEM) smblogprint(cmd, " system"); if (attr & SMB_ATTR_DIRECTORY) smblogprint(cmd, " directory"); if (attr & SMB_ATTR_ARCHIVE) smblogprint(cmd, " archive"); } static SmbFile * openfile(SmbSession *s, SmbTree *t, char *path, ushort mode, ushort attr, ushort ofun, ulong createoptions, uvlong createsize, ushort *fidp, Dir **dp, ushort *actionp) { int p9mode; int share; Dir *d = nil; int fd = -1; ushort action; SmbFile *f = nil; SmbSharedFile *sf = nil; char *fullpath = nil; int diropen = 0; //smblogprint(-1, "%s A %r", path); p9mode = (mode >> SMB_OPEN_MODE_ACCESS_SHIFT) & SMB_OPEN_MODE_ACCESS_MASK; share = (mode >> SMB_OPEN_MODE_SHARE_SHIFT) & SMB_OPEN_MODE_SHARE_MASK; if (share == SMB_OPEN_MODE_SHARE_COMPATIBILITY) { badshare: //smblogprint(-1, "%s SMB_OPEN_MODE_SHARE_COMPATIBILITY", path); smbseterror(s, ERRDOS, ERRbadshare); goto done; } smbstringprint(&fullpath, "%s%s", t->serv->path, path); d = dirstat(fullpath); if (d) { /* file exists */ int ofunexist; if (d->mode & DMDIR) { if (createoptions & SMB_CO_FILE) { smbseterror(s, ERRDOS, ERRnoaccess); goto done; } } else if (createoptions & SMB_CO_DIRECTORY) { smbseterror(s, ERRDOS, ERRnoaccess); goto done; } sf = smbsharedfileget(d, p9mode, &share); if (sf == nil) goto badshare; action = 1; ofunexist = (ofun >> SMB_OFUN_EXIST_SHIFT) & SMB_OFUN_EXIST_MASK; if (ofunexist == SMB_OFUN_EXIST_FAIL) { smbseterror(s, ERRDOS, ERRfilexists); goto done; } else if (ofunexist == SMB_OFUN_EXIST_TRUNCATE) { if ((d->mode & DMDIR) || (p9mode != OWRITE && p9mode != ORDWR)) { smbseterror(s, ERRDOS, ERRbadaccess); goto done; } p9mode |= OTRUNC; action = 3; } else if (ofunexist != SMB_OFUN_EXIST_OPEN) { smbseterror(s, ERRDOS, ERRbadaccess); goto done; } if (d->mode & DMDIR) diropen = 1; else fd = open(fullpath, p9mode); } else { /* file does not exist */ ulong p9attr; action = 3; if ((ofun & SMB_OFUN_NOEXIST_CREATE) == 0) { smbseterror(s, ERRDOS, ERRbadfile); goto done; } if (createsize != 0) { smbseterror(s, ERRDOS, ERRunsup); goto done; } //smblogprint(-1, "creating: attr 0x%.4ux co 0x%.8lux\n", attr, createoptions); if (createoptions & SMB_CO_FILE) { attr &= SMB_ATTR_DIRECTORY; if (attr == 0) attr = SMB_ATTR_NORMAL; } else if (createoptions & SMB_CO_DIRECTORY) { attr &= ~SMB_ATTR_NORMAL; attr |= SMB_ATTR_DIRECTORY; p9mode = OREAD; } //smblogprint(-1, "creating: before conversion attr 0x%.4ux\n", attr); p9attr = smbdosattr2plan9mode(attr); //smblogprint(-1, "creating: after conversion p9attr 0%.uo\n", p9attr); fd = create(fullpath, p9mode, p9attr); if (fd >= 0) { d = dirfstat(fd); sf = smbsharedfileget(d, p9mode, &share); if (sf == nil) { close(fd); remove(path); goto badshare; } } } //smblogprint(-1, "%s D %r", fullpath); if (!diropen && fd < 0) { smbseterror(s, ERRSRV, ERRaccess); goto done; } f = smbemalloc(sizeof(SmbFile)); if (diropen) { f->ioallowed = 0; f->fd = -1; } else { f->ioallowed = 1; f->fd = fd; } f->name = smbestrdup(path); f->sf = sf; sf = nil; f->share = share; f->p9mode = p9mode; f->t = t; if (s->fidmap == nil) s->fidmap = smbidmapnew(); *fidp = smbidmapadd(s->fidmap, f); //smblogprint(h->command, "REPLY:\n t->id=0x%ux fid=%d path=%s\n", t->id, *fidp, path); smblogprintif(smbglobals.log.fids, "openfile: 0x%.4ux/0x%.4ux %s\n", t->id, *fidp, path); if (actionp) *actionp = action; if (dp) { *dp = d; d = nil; } done: if (sf) smbsharedfileput(nil, sf, share); free(d); free(fullpath); return f; } SmbProcessResult smbcomopenandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) { uchar andxcommand; ushort andxoffset, flags, mode, sattr, attr; ulong createtime; ushort ofun; ulong createsize, timeout; char *path = nil; ulong andxoffsetfixupoffset; SmbProcessResult pr; ushort action; Dir *d = nil; SmbFile *f; SmbTree *t; ushort fid; if (!smbcheckwordcount("comopenandx", h, 15)) return SmbProcessResultFormat; andxcommand = *pdata++; pdata++; andxoffset = smbnhgets(pdata); pdata += 2; flags = smbnhgets(pdata); pdata += 2; mode = smbnhgets(pdata); pdata += 2; sattr = smbnhgets(pdata); pdata += 2; attr = smbnhgets(pdata); pdata += 2; createtime = smbnhgetl(pdata); pdata += 4; ofun = smbnhgets(pdata); pdata += 2; createsize = smbnhgetl(pdata); pdata += 4; timeout = smbnhgetl(pdata); pdata += 4; pdata += 4; USED(pdata); if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) { pr = SmbProcessResultFormat; goto done; } smbloglock(); smblogprint(h->command, "flags 0x%.4ux", flags); if (flags & SMB_OPEN_FLAGS_ADDITIONAL) smblogprint(h->command, " additional"); if (flags & SMB_OPEN_FLAGS_OPLOCK) smblogprint(h->command, " oplock"); if (flags & SMB_OPEN_FLAGS_OPBATCH) smblogprint(h->command, " opbatch"); smblogprint(h->command, "\n"); smblogprint(h->command, "mode 0x%.4ux", mode); switch ((mode >> SMB_OPEN_MODE_ACCESS_SHIFT) & SMB_OPEN_MODE_ACCESS_MASK) { case OREAD: smblogprint(h->command, " OREAD"); break; case OWRITE: smblogprint(h->command, " OWRITE"); break; case ORDWR: smblogprint(h->command, " ORDWR"); break; case OEXEC: smblogprint(h->command, " OEXEC"); break; } switch ((mode >> SMB_OPEN_MODE_SHARE_SHIFT) & SMB_OPEN_MODE_SHARE_MASK) { case SMB_OPEN_MODE_SHARE_COMPATIBILITY: smblogprint(h->command, " compatinility"); break; case SMB_OPEN_MODE_SHARE_EXCLUSIVE: smblogprint(h->command, " exclusive"); break; case SMB_OPEN_MODE_SHARE_DENY_WRITE: smblogprint(h->command, " deny write"); break; case SMB_OPEN_MODE_SHARE_DENY_READOREXEC: smblogprint(h->command, " deny readorxec"); break; case SMB_OPEN_MODE_SHARE_DENY_NONE: smblogprint(h->command, " deny none"); break; } if (mode & SMB_OPEN_MODE_WRITE_THROUGH) smblogprint(h->command, " write through"); smblogprint(h->command, "\n"); smblogprint(h->command, "sattr 0x%.4ux", sattr); smblogprintattr(h->command, sattr); smblogprint(h->command, "\n"); smblogprint(h->command, "attr 0x%.4ux", attr); smblogprintattr(h->command, attr); smblogprint(h->command, "\n"); smblogprint(h->command, "createtime 0x%.8lux\n", createtime); smblogprint(h->command, "ofun 0x%.4ux", ofun); if (ofun & SMB_OFUN_NOEXIST_CREATE) smblogprint(h->command, " noexistscreate"); else smblogprint(h->command, " noexistfail"); switch ((ofun >> SMB_OFUN_EXIST_SHIFT) & SMB_OFUN_EXIST_MASK) { case SMB_OFUN_EXIST_FAIL: smblogprint(h->command, " existfail"); break; case SMB_OFUN_EXIST_OPEN: smblogprint(h->command, " existopen"); break; case SMB_OFUN_EXIST_TRUNCATE: smblogprint(h->command, " existtruncate"); break; } smblogprint(h->command, "\n"); smblogprint(h->command, "createsize 0x%.8lux\n", createsize); smblogprint(h->command, "timeout 0x%.8lux\n", timeout); smblogprint(h->command, "path %s\n", path); smblogunlock(); t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); goto errordone; } f = openfile(s, t, path, mode, attr, ofun, 0, createsize, &fid, &d, &action); if (f == nil) { pr = SmbProcessResultError; goto done; } h->wordcount = 15; if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixupoffset) || !smbbufferputs(s->response, fid) || !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode)) || !smbbufferputl(s->response, smbplan9time2utime(d->mtime, s->tzoff)) || !smbbufferputl(s->response, smbplan9length2size32(d->length)) || !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode)) // probbaly bogus || !smbbufferputs(s->response, 0) // all files are files || !smbbufferputs(s->response, 0) // pipe state || !smbbufferputs(s->response, action) || !smbbufferputl(s->response, 0) // fileID || !smbbufferputs(s->response, 0) || !smbbufferputs(s->response, 0)) { // bytecount 0 smbfileclose(s, f); pr = SmbProcessResultMisc; goto done; } if (andxcommand != SMB_COM_NO_ANDX_COMMAND) pr = smbchaincommand(s, h, andxoffsetfixupoffset, andxcommand, andxoffset, b); else pr = SmbProcessResultReply; goto done; errordone: pr = SmbProcessResultError; done: free(path); free(d); return pr; } SmbProcessResult smbcomopen(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) { uchar fmt; char *path; ushort mode, attr; SmbTree *t; ushort fid; Dir *d = nil; SmbFile *f; SmbProcessResult pr; if (!smbcheckwordcount("comopen", h, 2)) return SmbProcessResultFormat; mode = smbnhgets(pdata); attr = smbnhgets(pdata + 2); if (!smbbuffergetb(b, &fmt) || fmt != 4 || !smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) { pr = SmbProcessResultFormat; goto done; } t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); error: pr = SmbProcessResultError; goto done; } f = openfile(s, t, path, mode, attr, SMB_OFUN_EXIST_OPEN << SMB_OFUN_EXIST_SHIFT, 0, 0, &fid, &d, nil); if (f == nil) goto error; h->wordcount = 7; if (!smbbufferputheader(s->response, h, &s->peerinfo) || !smbbufferputs(s->response, fid) || !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode)) || !smbbufferputl(s->response, smbplan9time2utime(d->mtime, s->tzoff)) || !smbbufferputl(s->response, smbplan9length2size32(d->length)) || !smbbufferputs(s->response, 2) // lies - this should be the actual access allowed || !smbbufferputs(s->response, 0)) pr = SmbProcessResultMisc; else pr = SmbProcessResultReply; done: free(path); free(d); return pr; } /* smb_com SMBcreate smb_com SMBcreate smb_wct 3 smb_wct 1 smb_vwv[0] attribute smb_vwv[0] file handle smb_vwv[1] time low smb_bcc 0 smb_vwv[2] time high smb_bcc min = 2 smb_buf[] ASCII -- 04 file pathname */ SmbProcessResult smbcomcreate(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) { int ofun, attr, mode; long createtime; char *path; uchar fmt; SmbFile *f; SmbTree *t; ushort fid; SmbProcessResult pr; path = nil; if (!smbcheckwordcount("comcreate", h, 3)) return SmbProcessResultFormat; smblogprint(h->command, "tid=%d\n", h->tid); attr = smbnhgets(pdata); pdata += 2; createtime = smbnhgetl(pdata); if (!smbbuffergetb(b, &fmt) || fmt != 0x04 || !smbbuffergetstring(b, h, SMB_STRING_PATH, &path)){ pr = SmbProcessResultError; goto done; } smbloglock(); smblogprint(h->command, "path %s\n", path); smblogprint(h->command, "attr 0x%.4ux", attr); smblogprintattr(h->command, attr); smblogprint(h->command, "\n"); smblogprint(h->command, "createtime 0x%.8lux\n", createtime); smblogunlock(); t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { pr = SmbProcessResultError; goto done; } mode = (ORDWR<wordcount = 1; // SFS: FIXME: unsure of this constant, maybe should be 3 if (!smbbufferputheader(s->response, h, &s->peerinfo) || !smbbufferputs(s->response, fid) || !smbbufferputs(s->response, 0)){ // bytecount 0 pr = SmbProcessResultMisc; goto done; } pr = SmbProcessResultReply; goto done; done: free(path); return pr; } typedef struct SmbSblut { char *s; ulong mask; } SmbSblut; static SmbSblut dasblut[] = { { "SMB_DA_SPECIFIC_READ_DATA", SMB_DA_SPECIFIC_READ_DATA }, { "SMB_DA_SPECIFIC_WRITE_DATA", SMB_DA_SPECIFIC_WRITE_DATA }, { "SMB_DA_SPECIFIC_APPEND_DATA", SMB_DA_SPECIFIC_APPEND_DATA }, { "SMB_DA_SPECIFIC_READ_EA", SMB_DA_SPECIFIC_READ_EA }, { "SMB_DA_SPECIFIC_WRITE_EA", SMB_DA_SPECIFIC_WRITE_EA }, { "SMB_DA_SPECIFIC_EXECUTE", SMB_DA_SPECIFIC_EXECUTE }, { "SMB_DA_SPECIFIC_DELETE_CHILD", SMB_DA_SPECIFIC_DELETE_CHILD }, { "SMB_DA_SPECIFIC_READ_ATTRIBUTES", SMB_DA_SPECIFIC_READ_ATTRIBUTES }, { "SMB_DA_SPECIFIC_WRITE_ATTRIBUTES", SMB_DA_SPECIFIC_WRITE_ATTRIBUTES }, { "SMB_DA_STANDARD_DELETE_ACCESS", SMB_DA_STANDARD_DELETE_ACCESS }, { "SMB_DA_STANDARD_READ_CONTROL_ACCESS", SMB_DA_STANDARD_READ_CONTROL_ACCESS }, { "SMB_DA_STANDARD_WRITE_DAC_ACCESS", SMB_DA_STANDARD_WRITE_DAC_ACCESS }, { "SMB_DA_STANDARD_WRITE_OWNER_ACCESS", SMB_DA_STANDARD_WRITE_OWNER_ACCESS }, { "SMB_DA_STANDARD_SYNCHRONIZE_ACCESS", SMB_DA_STANDARD_SYNCHRONIZE_ACCESS }, { "SMB_DA_GENERIC_ALL_ACCESS", SMB_DA_GENERIC_ALL_ACCESS }, { "SMB_DA_GENERIC_EXECUTE_ACCESS", SMB_DA_GENERIC_EXECUTE_ACCESS }, { "SMB_DA_GENERIC_WRITE_ACCESS", SMB_DA_GENERIC_WRITE_ACCESS }, { "SMB_DA_GENERIC_READ_ACCESS", SMB_DA_GENERIC_READ_ACCESS }, { 0 } }; static SmbSblut efasblut[] = { { "SMB_ATTR_READ_ONLY", SMB_ATTR_READ_ONLY }, { "SMB_ATTR_HIDDEN", SMB_ATTR_HIDDEN }, { "SMB_ATTR_SYSTEM", SMB_ATTR_SYSTEM }, { "SMB_ATTR_DIRECTORY", SMB_ATTR_DIRECTORY }, { "SMB_ATTR_ARCHIVE", SMB_ATTR_ARCHIVE }, { "SMB_ATTR_NORMAL", SMB_ATTR_NORMAL }, { "SMB_ATTR_COMPRESSED", SMB_ATTR_COMPRESSED }, { "SMB_ATTR_TEMPORARY", SMB_ATTR_TEMPORARY }, { "SMB_ATTR_WRITETHROUGH", SMB_ATTR_WRITETHROUGH }, { "SMB_ATTR_NO_BUFFERING", SMB_ATTR_NO_BUFFERING }, { "SMB_ATTR_RANDOM_ACCESS", SMB_ATTR_RANDOM_ACCESS }, { 0 } }; static SmbSblut sasblut[] = { { "SMB_SA_SHARE_READ", SMB_SA_SHARE_READ }, { "SMB_SA_SHARE_WRITE", SMB_SA_SHARE_WRITE }, { "SMB_SA_SHARE_DELETE", SMB_SA_SHARE_DELETE }, { "SMB_SA_NO_SHARE", SMB_SA_NO_SHARE }, { 0 } }; static SmbSblut cosblut[] = { { "SMB_CO_DIRECTORY", SMB_CO_DIRECTORY }, { "SMB_CO_WRITETHROUGH", SMB_CO_WRITETHROUGH }, { "SMB_CO_SEQUENTIAL_ONLY", SMB_CO_SEQUENTIAL_ONLY }, { "SMB_CO_FILE", SMB_CO_FILE }, { "SMB_CO_NO_EA_KNOWLEDGE", SMB_CO_NO_EA_KNOWLEDGE }, { "SMB_CO_EIGHT_DOT_THREE_ONLY", SMB_CO_EIGHT_DOT_THREE_ONLY }, { "SMB_CO_RANDOM_ACCESS", SMB_CO_RANDOM_ACCESS }, { "SMB_CO_DELETE_ON_CLOSE", SMB_CO_DELETE_ON_CLOSE }, { 0 } }; static SmbSlut cdslut[] = { { "SMB_CD_SUPERCEDE", SMB_CD_SUPERCEDE }, { "SMB_CD_OPEN", SMB_CD_OPEN }, { "SMB_CD_CREATE", SMB_CD_CREATE }, { "SMB_CD_OPEN_IF", SMB_CD_OPEN_IF }, { "SMB_CD_OVERWRITE", SMB_CD_OVERWRITE }, { "SMB_CD_OVERWRITE_IF", SMB_CD_OVERWRITE_IF }, { 0 } }; static void smbsblutlogprint(uchar cmd, SmbSblut *sblut, ulong mask) { while (sblut->s) { if (mask && (sblut->mask & mask) || (mask == 0 && sblut->mask == 0)) smblogprint(cmd, " %s", sblut->s); sblut++; } } SmbProcessResult smbcomntcreateandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) { uchar andxcommand; ushort andxoffset; char *path = nil; SmbProcessResult pr; ulong namelength; ulong flags; ulong rootdirectoryfid, desiredaccess; uvlong allocationsize; ulong extfileattributes, shareaccess, createdisposition, createoptions, impersonationlevel; uchar securityflags; int p9mode; int sharemode; ushort mode; SmbTree *t; ushort ofun; SmbFile *f; ushort fid; Dir *d = nil; ushort action; uvlong mtime; ulong andxoffsetfixup; if (!smbcheckwordcount("comntcreateandx", h, 24)) return SmbProcessResultFormat; andxcommand = *pdata++; pdata++; andxoffset = smbnhgets(pdata); pdata += 2; pdata++; namelength = smbnhgets(pdata); pdata += 2; flags = smbnhgetl(pdata); pdata += 4; rootdirectoryfid = smbnhgetl(pdata); pdata += 4; desiredaccess = smbnhgetl(pdata); pdata += 4; allocationsize = smbnhgetv(pdata); pdata += 8; extfileattributes = smbnhgetl(pdata); pdata += 4; shareaccess = smbnhgetl(pdata); pdata += 4; createdisposition = smbnhgetl(pdata); pdata += 4; createoptions = smbnhgetl(pdata); pdata += 4; impersonationlevel = smbnhgetl(pdata); pdata += 4; securityflags = *pdata++; USED(pdata); if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) { pr = SmbProcessResultFormat; goto done; } smblogprint(h->command, "namelength %d\n", namelength); smblogprint(h->command, "flags 0x%.8lux\n", flags); smblogprint(h->command, "rootdirectoryfid %lud\n", rootdirectoryfid); smblogprint(h->command, "desiredaccess 0x%.8lux", desiredaccess); smbsblutlogprint(h->command, dasblut, desiredaccess); smblogprint(h->command, "\n"); smblogprint(h->command, "allocationsize %llud\n", allocationsize); smblogprint(h->command, "extfileattributes 0x%.8lux", extfileattributes); smbsblutlogprint(h->command, efasblut, extfileattributes); smblogprint(h->command, "\n"); smblogprint(h->command, "shareaccess 0x%.8lux", shareaccess); smbsblutlogprint(h->command, sasblut, shareaccess); smblogprint(h->command, "\n"); smblogprint(h->command, "createdisposition 0x%.8lux %s\n", createdisposition, smbrevslut(cdslut, createdisposition)); smblogprint(h->command, "createoptions 0x%.8lux", createoptions); smbsblutlogprint(h->command, cosblut, createoptions); smblogprint(h->command, "\n"); smblogprint(h->command, "impersonationlevel 0x%.8lux\n", impersonationlevel); smblogprint(h->command, "securityflags 0x%.2ux\n", securityflags); smblogprint(h->command, "path %s\n", path); if (rootdirectoryfid != 0) { smblogprint(-1, "smbcomntcreateandx: fid relative not implemented\n"); goto unimp; } if (desiredaccess & SMB_DA_GENERIC_MASK) switch (desiredaccess & SMB_DA_GENERIC_MASK){ case SMB_DA_GENERIC_READ_ACCESS: p9mode = OREAD; break; case SMB_DA_GENERIC_WRITE_ACCESS: p9mode = OWRITE; break; case SMB_DA_GENERIC_ALL_ACCESS: p9mode = ORDWR; break; case SMB_DA_GENERIC_EXECUTE_ACCESS: p9mode = OEXEC; break; default: p9mode = OREAD; break; } else if (desiredaccess & SMB_DA_SPECIFIC_READ_DATA) if (desiredaccess & (SMB_DA_SPECIFIC_WRITE_DATA | SMB_DA_SPECIFIC_APPEND_DATA)) p9mode = ORDWR; else p9mode = OREAD; else if (desiredaccess & (SMB_DA_SPECIFIC_WRITE_DATA | SMB_DA_SPECIFIC_APPEND_DATA)) p9mode = ORDWR; else p9mode = OREAD; if (shareaccess == SMB_SA_NO_SHARE) sharemode = SMB_OPEN_MODE_SHARE_EXCLUSIVE; else if (shareaccess & (SMB_SA_SHARE_READ | SMB_SA_SHARE_WRITE) == (SMB_SA_SHARE_READ | SMB_SA_SHARE_WRITE)) sharemode = SMB_OPEN_MODE_SHARE_DENY_NONE; else if (shareaccess & SMB_SA_SHARE_READ) sharemode = SMB_OPEN_MODE_SHARE_DENY_WRITE; else if (shareaccess & SMB_SA_SHARE_WRITE) sharemode = SMB_OPEN_MODE_SHARE_DENY_READOREXEC; else sharemode = SMB_OPEN_MODE_SHARE_DENY_NONE; mode = (sharemode << SMB_OPEN_MODE_SHARE_SHIFT) | (p9mode << SMB_OPEN_MODE_ACCESS_SHIFT); switch (createdisposition) { default: smblogprint(-1, "smbcomntcreateandx: createdisposition 0x%.8lux not implemented\n", createdisposition); goto unimp; case SMB_CD_OPEN: ofun = SMB_OFUN_EXIST_OPEN; break; case SMB_CD_CREATE: ofun = SMB_OFUN_EXIST_FAIL | SMB_OFUN_NOEXIST_CREATE; break; case SMB_CD_OPEN_IF: ofun = SMB_OFUN_EXIST_OPEN | SMB_OFUN_NOEXIST_CREATE; break; case SMB_CD_OVERWRITE: ofun = SMB_OFUN_EXIST_TRUNCATE; break; case SMB_CD_OVERWRITE_IF: ofun = SMB_OFUN_EXIST_TRUNCATE | SMB_OFUN_NOEXIST_CREATE; break; } t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); pr = SmbProcessResultError; goto done; } f = openfile(s, t, path, mode, extfileattributes, ofun, createoptions, allocationsize, &fid, &d, &action); if (f == nil) { pr = SmbProcessResultError; goto done; } h->wordcount = 42; mtime = smbplan9time2time(d->mtime); if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup) || !smbbufferputb(s->response, 0) // oplocks? pah || !smbbufferputs(s->response, fid) || !smbbufferputl(s->response, action) || !smbbufferputv(s->response, mtime) || !smbbufferputv(s->response, smbplan9time2time(d->atime)) || !smbbufferputv(s->response, mtime) || !smbbufferputv(s->response, mtime) || !smbbufferputl(s->response, smbplan9mode2dosattr(d->mode)) || !smbbufferputv(s->response, smbl2roundupvlong(d->length, smbglobals.l2allocationsize)) || !smbbufferputv(s->response, d->length) || !smbbufferputbytes(s->response, nil, 4) || !smbbufferputb(s->response, (d->qid.type & QTDIR) != 0) || !smbbufferputbytes(s->response, nil, 8) || !smbbufferputs(s->response, 0)) { pr = SmbProcessResultMisc; goto done; } if (andxcommand != SMB_COM_NO_ANDX_COMMAND) pr = smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b); else pr = SmbProcessResultReply; goto done; unimp: pr = SmbProcessResultUnimp; done: free(path); free(d); return pr; }