Dear patch moderator, if you are not JMK please don't apply this, he knows about it. added support for smb_com_create which allows Linux smbmount to create files. tidied up the existing debug and added a load more. added basic manual for aquarela. -Steve updated the patch with a newer version of smbcomopen.c the fix enables GENERIC modes of opening files used by aux/cifs. This together with a seperate fix for authserv means aux/cifs now seems Reference: /n/sources/patch/applied/aquarela-smbmount Date: Mon Mar 26 18:59:31 CES 2007 Signed-off-by: steve@quintile.net --- /sys/src/cmd/aquarela/smbtrans2query.c Mon Mar 26 14:41:14 2007 +++ /sys/src/cmd/aquarela/smbtrans2query.c Mon Mar 26 14:41:11 2007 @@ -18,6 +18,13 @@ ntatime = smbplan9time2time(d->atime); ntmtime = smbplan9time2time(d->mtime); dosmode = smbplan9mode2dosattr(d->mode); + + translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_BASIC_INFO\n"); + translogprint(s->transaction.in.setup[0], "REPLY:\n"); + translogprint(s->transaction.in.setup[0], "atime=%s", ctime(d->atime)); + translogprint(s->transaction.in.setup[0], "atime=%s", ctime(d->mtime)); + translogprint(s->transaction.in.setup[0], "mode=0%o -> dosmode=0x%x\n", d->mode, dosmode); + if (!smbbufferputv(s->transaction.out.data, ntmtime) || !smbbufferputv(s->transaction.out.data, ntatime) || !smbbufferputv(s->transaction.out.data, ntmtime) @@ -31,6 +38,15 @@ ntmtime = smbplan9time2time(d->mtime); dosmode = smbplan9mode2dosattr(d->mode); allocsize = (d->length + (1 << smbglobals.l2allocationsize) - 1) & ~((1 << smbglobals.l2allocationsize) - 1); + + translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_ALL_INFO\n"); + translogprint(s->transaction.in.setup[0], "REPLY:\n"); + translogprint(s->transaction.in.setup[0], "atime=%s", ctime(d->atime)); + translogprint(s->transaction.in.setup[0], "atime=%s", ctime(d->mtime)); + translogprint(s->transaction.in.setup[0], "mode=0%o -> dosmode=0x%x\n", d->mode, dosmode); + translogprint(s->transaction.in.setup[0], "allocsize=%d\n", allocsize); + translogprint(s->transaction.in.setup[0], "isdir=%d\n", (d->mode & DMDIR) != 0); + if (!smbbufferputv(s->transaction.out.data, ntmtime) || !smbbufferputv(s->transaction.out.data, ntatime) || !smbbufferputv(s->transaction.out.data, ntmtime) @@ -51,11 +67,16 @@ return SmbProcessResultMisc; fnlfixupoffset = smbbufferwriteoffset(s->transaction.out.data); if (!smbbufferputl(s->transaction.out.data, 0) - || !smbbufferputstring(s->transaction.out.data, &s->peerinfo, SMB_STRING_REVPATH, filename) - || !smbbufferfixuprelativel(s->transaction.out.data, fnlfixupoffset)) + || !smbbufferputstring(s->transaction.out.data, &s->peerinfo, SMB_STRING_REVPATH, filename) + || !smbbufferfixuprelativel(s->transaction.out.data, fnlfixupoffset)) return SmbProcessResultMisc; break; case SMB_QUERY_FILE_STANDARD_INFO: + translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_STANDARD_INFO\n"); + translogprint(s->transaction.in.setup[0], "REPLY:\n"); + translogprint(s->transaction.in.setup[0], "length=%lld", d->length); + translogprint(s->transaction.in.setup[0], "isdir=%d\n", (d->qid.type & QTDIR) != 0); + if (!smbbufferputv(s->transaction.out.data, smbl2roundupvlong(d->length, smbglobals.l2allocationsize)) || !smbbufferputv(s->transaction.out.data, d->length) || !smbbufferputl(s->transaction.out.data, 1) @@ -64,15 +85,21 @@ return SmbProcessResultMisc; break; case SMB_QUERY_FILE_EA_INFO: + translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_EA_INFO\n"); + translogprint(s->transaction.in.setup[0], "REPLY:\n"); + translogprint(s->transaction.in.setup[0], "ea_len=0\n"); if (!smbbufferputl(s->transaction.out.data, 0)) return SmbProcessResultMisc; break; case SMB_QUERY_FILE_STREAM_INFO: + translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_STREAM_INFO\n"); + translogprint(s->transaction.in.setup[0], "REPLY: failed\n"); /* don't do it, never will */ goto unknownlevel; default: smblogprint(-1, "smbtrans2query%sinformation: infolevel 0x%.4ux not implemented\n", cmdname, infolevel); unknownlevel: + translogprint(s->transaction.in.setup[0], "[not supported]\n"); smbseterror(s, ERRDOS, ERRunknownlevel); return SmbProcessResultError; } @@ -102,11 +129,11 @@ pr = SmbProcessResultMisc; goto done; } - smblogprintif(smbglobals.log.query, "infolevel 0x%.4ux\n", infolevel); - smblogprintif(smbglobals.log.query, "path %s\n", path); + translogprint(s->transaction.in.setup[0], "infolevel 0x%.4ux\n", infolevel); + translogprint(s->transaction.in.setup[0], "path %s\n", path); fullpath = nil; smbstringprint(&fullpath, "%s%s", t->serv->path, path); - smblogprintif(smbglobals.log.query, "fullpath %s\n", fullpath); + translogprint(s->transaction.in.setup[0], "fullpath %s\n", fullpath); d = dirstat(fullpath); pr = query(s, "path", path, infolevel, 0, d); free(d); @@ -139,8 +166,8 @@ pr = SmbProcessResultMisc; goto done; } - smblogprintif(smbglobals.log.query, "fid 0x%.4ux\n", fid); - smblogprintif(smbglobals.log.query, "infolevel 0x%.4ux\n", infolevel); + translogprint(s->transaction.in.setup[0], "fid 0x%.4ux\n", fid); + translogprint(s->transaction.in.setup[0], "infolevel 0x%.4ux\n", infolevel); f = smbidmapfind(s->fidmap, fid); if (f == nil) { smbseterror(s, ERRDOS, ERRbadfid); @@ -180,6 +207,7 @@ pr = SmbProcessResultReply; switch (infolevel) { case SMB_INFO_ALLOCATION: + translogprint(s->transaction.in.setup[0], "SMB_INFO_ALLOCATION\n"); if (!smbbufferputl(s->transaction.out.data, 0) || !smbbufferputl(s->transaction.out.data, 1 << (smbglobals.l2allocationsize - smbglobals.l2sectorsize)) || !smbbufferputl(s->transaction.out.data, 0xffffffff) @@ -188,11 +216,13 @@ goto misc; break; case SMB_INFO_VOLUME: + translogprint(s->transaction.in.setup[0], "SMB_INFO_VOLUME\n"); if (!smbbufferputl(s->transaction.out.data, 0xdeadbeef) || !smbbufferputstring(s->transaction.out.data, &s->peerinfo, 0, t->serv->name)) goto misc; break; case SMB_QUERY_FS_VOLUME_INFO: + translogprint(s->transaction.in.setup[0], "SMB_QUERY_FS_VOLUME_INFO\n"); if (!smbbufferputv(s->transaction.out.data, 0) || !smbbufferputl(s->transaction.out.data, 0xdeadbeef)) goto misc; @@ -207,6 +237,7 @@ goto misc; break; case SMB_QUERY_FS_SIZE_INFO: + translogprint(s->transaction.in.setup[0], "SMB_QUERY_FS_SIZE_INFO\n"); if (!smbbufferputv(s->transaction.out.data, 0xffffffffffffffffLL) || !smbbufferputv(s->transaction.out.data, 0xffffffffffffffffLL) || !smbbufferputl(s->transaction.out.data, 1 << (smbglobals.l2allocationsize - smbglobals.l2sectorsize)) @@ -214,7 +245,7 @@ goto misc; break; case SMB_QUERY_FS_ATTRIBUTE_INFO: -//print("doing attribute info\n"); + translogprint(s->transaction.in.setup[0], "SMB_QUERY_FS_ATTRIBUTE_INFO\n"); if (!smbbufferputl(s->transaction.out.data, 3) || !smbbufferputl(s->transaction.out.data, 255)) goto misc; @@ -223,7 +254,6 @@ || !smbbufferputstring(s->transaction.out.data, &s->peerinfo, SMB_STRING_UNTERMINATED, smbglobals.serverinfo.nativelanman) || !smbbufferfixuprelativel(s->transaction.out.data, fixup)) goto misc; -//print("done attribute info\n"); break; default: smblogprint(-1, "smbtrans2queryfsinformation: infolevel 0x%.4ux not implemented\n", infolevel); --- /sys/src/cmd/aquarela/smbfns.h Mon Mar 26 14:41:31 2007 +++ /sys/src/cmd/aquarela/smbfns.h Mon Mar 26 14:41:27 2007 @@ -13,9 +13,11 @@ SMBPROCESSFN smbcomtransaction2; SMBPROCESSFN smbcomecho; SMBPROCESSFN smbcomopenandx; +SMBPROCESSFN smbcomcreate; SMBPROCESSFN smbcomopen; SMBPROCESSFN smbcomclose; SMBPROCESSFN smbcomreadandx; +SMBPROCESSFN smbcomwriteandx; SMBPROCESSFN smbcomqueryinformation; SMBPROCESSFN smbcomfindclose2; SMBPROCESSFN smbcomtreedisconnect; @@ -173,6 +175,7 @@ SmbProcessResult smbtrans2queryfsinformation(SmbSession *s, SmbHeader *h); SmbProcessResult smbtrans2querypathinformation(SmbSession *s, SmbHeader *h); SmbProcessResult smbtrans2setfileinformation(SmbSession *s, SmbHeader *h); +SmbProcessResult smbtrans2setpathinformation(SmbSession *s, SmbHeader *h); SmbIdMap *smbidmapnew(void); long smbidmapadd(SmbIdMap *m, void *p); @@ -209,6 +212,7 @@ void smbloglock(void); void smblogunlock(void); int smblogvprint(int cmd, char *fmt, va_list ap); +int translogprint(int cmd, char *fmt, ...); int smblogprint(int cmd, char *fmt, ...); int smblogprintif(int v, char *fmt, ...); void smblogdata(int cmd, int (*print)(int cmd, char *fmt, ...), void *p, long data, long limit); --- /sys/src/cmd/aquarela/smboptable.c Mon Mar 26 14:41:49 2007 +++ /sys/src/cmd/aquarela/smboptable.c Mon Mar 26 14:41:46 2007 @@ -4,7 +4,7 @@ [SMB_COM_CREATE_DIRECTORY] { "SMB_COM_CREATE_DIRECTORY", smbcomcreatedirectory }, [SMB_COM_DELETE_DIRECTORY] { "SMB_COM_DELETE_DIRECTORY", smbcomdeletedirectory }, [SMB_COM_OPEN] { "SMB_COM_OPEN", smbcomopen }, -[SMB_COM_CREATE] { "SMB_COM_CREATE", nil }, +[SMB_COM_CREATE] { "SMB_COM_CREATE", smbcomcreate }, [SMB_COM_CLOSE] { "SMB_COM_CLOSE", smbcomclose }, [SMB_COM_FLUSH] { "SMB_COM_FLUSH", smbcomflush }, [SMB_COM_DELETE] { "SMB_COM_DELETE", smbcomdelete }, @@ -43,7 +43,7 @@ [SMB_COM_WRITE_AND_CLOSE] { "SMB_COM_WRITE_AND_CLOSE", nil }, [SMB_COM_OPEN_ANDX] { "SMB_COM_OPEN_ANDX", smbcomopenandx }, [SMB_COM_READ_ANDX] { "SMB_COM_READ_ANDX", smbcomreadandx }, -[SMB_COM_WRITE_ANDX] { "SMB_COM_WRITE_ANDX", nil }, +[SMB_COM_WRITE_ANDX] { "SMB_COM_WRITE_ANDX", smbcomwriteandx }, [SMB_COM_NEW_FILE_SIZE] { "SMB_COM_NEW_FILE_SIZE", nil }, [SMB_COM_CLOSE_AND_TREE_DISC] { "SMB_COM_CLOSE_AND_TREE_DISC", nil }, [SMB_COM_TRANSACTION2] { "SMB_COM_TRANSACTION2", smbcomtransaction2 }, @@ -83,7 +83,7 @@ [SMB_TRANS2_QUERY_FS_INFORMATION] { "SMB_TRANS2_QUERY_FS_INFORMATION", smbtrans2queryfsinformation }, [SMB_TRANS2_SET_FS_INFORMATION] { "SMB_TRANS2_SET_FS_INFORMATION", nil }, [SMB_TRANS2_QUERY_PATH_INFORMATION] { "SMB_TRANS2_QUERY_PATH_INFORMATION", smbtrans2querypathinformation }, -[SMB_TRANS2_SET_PATH_INFORMATION] { "SMB_TRANS2_SET_PATH_INFORMATION", nil }, +[SMB_TRANS2_SET_PATH_INFORMATION] { "SMB_TRANS2_SET_PATH_INFORMATION", smbtrans2setpathinformation }, [SMB_TRANS2_QUERY_FILE_INFORMATION] { "SMB_TRANS2_QUERY_FILE_INFORMATION", smbtrans2queryfileinformation }, [SMB_TRANS2_SET_FILE_INFORMATION] { "SMB_TRANS2_SET_FILE_INFORMATION", smbtrans2setfileinformation }, [SMB_TRANS2_FSCTL] { "SMB_TRANS2_FSCTL", nil }, --- /sys/src/cmd/aquarela/smbcomopen.c Mon Mar 26 14:42:13 2007 +++ /sys/src/cmd/aquarela/smbcomopen.c Mon Mar 26 18:57:58 2007 @@ -29,10 +29,12 @@ 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; } @@ -114,6 +116,7 @@ } } } +smblogprint(-1, "%s D %r", fullpath); if (!diropen && fd < 0) { smbseterror(s, ERRSRV, ERRaccess); goto done; @@ -136,6 +139,7 @@ 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; @@ -354,6 +358,82 @@ 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; @@ -513,11 +593,25 @@ goto unimp; } - if (desiredaccess & SMB_DA_GENERIC_MASK) { - smblogprint(-1, "smbcomntcreateandx: generic bits in desiredaccess 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; --- /sys/src/cmd/aquarela/aquarela.man Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aquarela/aquarela.man Mon Mar 26 14:42:33 2007 @@ -0,0 +1,81 @@ +.TH aquarela 8 +.SH NAME +aquarela \- Microsoft\(tm Windows filesystem server +.SH SYNOPSIS +.B aquarela +[ +.B -n +] [ +.B -d +.I option +] [ +.B -p +] [ +.B -w +.I workgroup +] [ +.B -u +.I 0|1 +] +.PP +.I Aquarela +listens on port 455 and port 137, and optionally 129 for incomming +MicroSoft file shareing protocol (a.k.a SMB and CIFS) requests and serves and fulfills +these from its current namespace. +.PP +Transcoding is peformed between spaces and non breaking spaces to accommodate +fileservers other than fossil. +.PP +Log messages are appended to +.I /sys/log/aquarela +if it exists. +.PP +The options are: +.TP +.B -u +.I 0|1 +Force unicode support off/on; since there is no code page support, +the server actually sends UTF if this is disabled +.TP +.B -w +.I workgroup +Sets the workgroup (aka primary domain) to +.IR workgroup . +By default the workgroup is +.IR PLAN9 . +.TP +.B -n +Enable vestigial Netbios support, it starts up a Netbios listener to answer +name queries, and attempts to register the server with the local +master browser for the chosen workgroup. It will not act as LMB +itself, so relies on the existence of another one, e.g. samba's +.IR nmbd(1) . +This option should not be used unless strictly nescessary. +.TP +.B -p +Sends logging to standard output, as well as to the log file. +.TP +.B -d +.I option +Enable one of many possible debugging options +.PP +By default only the share +.B local +is offered, which maps to the plan9 directory +.IR /n/local " \-" +which is usually bound over the root of the +plan9 fileserver. If a different share is requested then +.IR 9fs (1) +is envoked to provide access to that filesyetem. +.SH EXAMPLES +To mount /boot on a plan9 system from a +.I linux +machine, using smbfs +.EX + + $ smbumount $home/mnt + $ smbmount //celeste/boot /mnt/celeste -o username=glenda +.EE +.SH BUGS +.I Aquarela +should be regarded as a work in progress.