summaryrefslogtreecommitdiff
path: root/sys/src/cmd/cifs/trans2.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cifs/trans2.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cifs/trans2.c')
-rwxr-xr-xsys/src/cmd/cifs/trans2.c539
1 files changed, 539 insertions, 0 deletions
diff --git a/sys/src/cmd/cifs/trans2.c b/sys/src/cmd/cifs/trans2.c
new file mode 100755
index 000000000..090054096
--- /dev/null
+++ b/sys/src/cmd/cifs/trans2.c
@@ -0,0 +1,539 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "cifs.h"
+
+static Pkt *
+t2hdr(Session *s, Share *sp, int cmd)
+{
+ Pkt *p;
+
+ p = cifshdr(s, sp, SMB_COM_TRANSACTION2);
+
+ p->tbase = pl16(p, 0); /* 0 Total parameter bytes to be sent, filled later */
+ pl16(p, 0); /* 2 Total data bytes to be sent, filled later */
+ pl16(p, 64); /* 4 Max parameter to return */
+ pl16(p, (MTU - T2HDRLEN)-64); /* 6 Max data to return */
+ p8(p, 0); /* 8 Max setup count to return */
+ p8(p, 0); /* 9 Reserved */
+ pl16(p, 0); /* 10 Flags */
+ pl32(p, 1000); /* 12 Timeout (ms) */
+ pl16(p, 0); /* 16 Reserved */
+ pl16(p, 0); /* 18 Parameter count, filled later */
+ pl16(p, 0); /* 20 Parameter offset, filled later */
+ pl16(p, 0); /* 22 Data count, filled later */
+ pl16(p, 0); /* 24 Data offset, filled later */
+ p8(p, 1); /* 26 Setup count (in words) */
+ p8(p, 0); /* 27 Reserved */
+ pl16(p, cmd); /* setup[0] */
+ pbytes(p);
+ p8(p, 0); /* padding ??!?!? */
+
+ return p;
+}
+
+static void
+pt2param(Pkt *p)
+{
+ uchar *pos = p->pos;
+
+ assert(p->tbase != 0);
+ p->pos = p->tbase + 20;
+ pl16(p, (pos - p->buf) - NBHDRLEN); /* param offset */
+
+ p->tparam = p->pos = pos;
+}
+
+static void
+pt2data(Pkt *p)
+{
+ uchar *pos = p->pos;
+
+ assert(p->tbase != 0);
+ assert(p->tparam != 0);
+
+ p->pos = p->tbase +0;
+ pl16(p, pos - p->tparam); /* total param count */
+
+ p->pos = p->tbase +18;
+ pl16(p, pos - p->tparam); /* param count */
+
+ p->pos = p->tbase +24;
+ pl16(p, (pos - p->buf) - NBHDRLEN); /* data offset */
+
+ p->tdata = p->pos = pos;
+}
+
+static int
+t2rpc(Pkt *p)
+{
+ int got;
+ uchar *pos;
+
+ assert(p->tbase != 0);
+ assert(p->tdata != 0);
+
+ pos = p->pos;
+
+ p->pos = p->tbase +2;
+ pl16(p, pos - p->tdata); /* total data count */
+
+ p->pos = p->tbase +22;
+ pl16(p, pos - p->tdata); /* data count */
+
+ p->pos = pos;
+ if((got = cifsrpc(p)) == -1)
+ return -1;
+
+ gl16(p); /* Total parameter count */
+ gl16(p); /* Total data count */
+ gl16(p); /* Reserved */
+ gl16(p); /* Parameter count in this buffer */
+ p->tparam = p->buf +NBHDRLEN +gl16(p); /* Parameter offset */
+ gl16(p); /* Parameter displacement */
+ gl16(p); /* Data count (this buffer); */
+ p->tdata = p->buf +NBHDRLEN +gl16(p); /* Data offset */
+ gl16(p); /* Data displacement */
+ g8(p); /* Setup count */
+ g8(p); /* Reserved */
+
+ return got;
+}
+
+static void
+gt2param(Pkt *p)
+{
+ p->pos = p->tparam;
+}
+
+static void
+gt2data(Pkt *p)
+{
+ p->pos = p->tdata;
+}
+
+
+int
+T2findfirst(Session *s, Share *sp, int slots, char *path, int *got,
+ long *resume, FInfo *fip)
+{
+ int pktlen, i, n, sh;
+ uchar *next;
+ Pkt *p;
+
+ p = t2hdr(s, sp, TRANS2_FIND_FIRST2);
+ p8(p, 'D'); /* OS/2 */
+ p8(p, ' '); /* OS/2 */
+
+ pt2param(p);
+ pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* Search attributes */
+ pl16(p, slots); /* Search count */
+ pl16(p, CIFS_SEARCH_RETURN_RESUME); /* Flags */
+ pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
+ pl32(p, 0); /* SearchStorage type (?) */
+ ppath(p, path); /* path */
+
+ pt2data(p);
+ if((pktlen = t2rpc(p)) == -1){
+ free(p);
+ return -1;
+ }
+
+ s->lastfind = nsec();
+ gt2param(p);
+
+ sh = gl16(p); /* Sid (search handle) */
+ *got = gl16(p); /* number of slots received */
+ gl16(p); /* End of search flag */
+ gl16(p); /* Offset into EA list if EA error */
+ gl16(p); /* Offset into data to file name of last entry */
+
+ gt2data(p);
+ memset(fip, 0, slots * sizeof(FInfo));
+ for(i = 0; i < *got; i++){
+ next = p->pos;
+ next += gl32(p); /* offset to next entry */
+ /*
+ * bug in Windows - somtimes it lies about how many
+ * directory entries it has put in the packet
+ */
+ if(next - p->buf > pktlen){
+ *got = i;
+ break;
+ }
+
+ *resume = gl32(p); /* resume key for search */
+ fip[i].created = gvtime(p); /* creation time */
+ fip[i].accessed = gvtime(p); /* last access time */
+ fip[i].written = gvtime(p); /* last written time */
+ fip[i].changed = gvtime(p); /* change time */
+ fip[i].size = gl64(p); /* file size */
+ gl64(p); /* bytes allocated */
+ fip[i].attribs = gl32(p); /* extended attributes */
+ n = gl32(p); /* name length */
+ gl32(p); /* EA size */
+ gstr(p, fip[i].name, n); /* name */
+ p->pos = next;
+ }
+
+ free(p);
+ return sh;
+
+}
+
+int
+T2findnext(Session *s, Share *sp, int slots, char *path, int *got,
+ long *resume, FInfo *fip, int sh)
+{
+ Pkt *p;
+ int i, n;
+ uchar *next;
+
+ /*
+ * So I believe from comp.protocols.smb if you send
+ * TRANS2_FIND_NEXT2 requests too quickly to windows 95, it can
+ * get confused and fail to reply, so we slow up a bit in these
+ * circumstances.
+ */
+ if(!(s->caps & CAP_NT_SMBS) && nsec() - s->lastfind < 200000000LL)
+ sleep(200);
+
+ p = t2hdr(s, sp, TRANS2_FIND_NEXT2);
+ p8(p, 'D'); /* OS/2 */
+ p8(p, ' '); /* OS/2 */
+
+ pt2param(p);
+ pl16(p, sh); /* search handle */
+ pl16(p, slots); /* Search count */
+ pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
+ pl32(p, *resume); /* resume key */
+ pl16(p, CIFS_SEARCH_CONTINUE_FROM_LAST); /* Flags */
+ ppath(p, path); /* file+path to resume */
+
+ pt2data(p);
+ if(t2rpc(p) == -1){
+ free(p);
+ return -1;
+ }
+
+ s->lastfind = nsec();
+
+ gt2param(p);
+ *got = gl16(p); /* number of slots received */
+ gl16(p); /* End of search flag */
+ gl16(p); /* Offset into EA list if EA error */
+ gl16(p); /* Offset into data to file name of last entry */
+
+ gt2data(p);
+ memset(fip, 0, slots * sizeof(FInfo));
+ for(i = 0; i < *got; i++){
+ next = p->pos;
+ next += gl32(p); /* offset to next entry */
+ *resume = gl32(p); /* resume key for search */
+ fip[i].created = gvtime(p); /* creation time */
+ fip[i].accessed = gvtime(p); /* last access time */
+ fip[i].written = gvtime(p); /* last written time */
+ fip[i].changed = gvtime(p); /* change time */
+ fip[i].size = gl64(p); /* file size */
+ gl64(p); /* bytes allocated */
+ fip[i].attribs = gl32(p); /* extended attributes */
+ n = gl32(p); /* name length */
+ gl32(p); /* EA size */
+ gstr(p, fip[i].name, n); /* name */
+ p->pos = next;
+ }
+ free(p);
+ return 0;
+}
+
+
+/* supported by 2k/XP/NT4 */
+int
+T2queryall(Session *s, Share *sp, char *path, FInfo *fip)
+{
+ int n;
+ Pkt *p;
+
+ p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
+ pt2param(p);
+ pl16(p, SMB_QUERY_FILE_ALL_INFO); /* Information level */
+ pl32(p, 0); /* reserved */
+ ppath(p, path); /* path */
+
+ pt2data(p);
+ if(t2rpc(p) == -1){
+ free(p);
+ return -1;
+ }
+ gt2data(p);
+
+ /*
+ * The layout of this struct is wrong in the SINA
+ * document, this layout gained by inspection.
+ */
+ memset(fip, 0, sizeof(FInfo));
+ fip->created = gvtime(p); /* creation time */
+ fip->accessed = gvtime(p); /* last access time */
+ fip->written = gvtime(p); /* last written time */
+ fip->changed = gvtime(p); /* change time */
+ fip->attribs = gl32(p); /* attributes */
+ gl32(p); /* reserved */
+ gl64(p); /* bytes allocated */
+ fip->size = gl64(p); /* file size */
+ gl32(p); /* number of hard links */
+ g8(p); /* delete pending */
+ g8(p); /* is a directory */
+ gl16(p); /* reserved */
+ gl32(p); /* EA size */
+
+ n = gl32(p);
+ if(n >= sizeof fip->name)
+ n = sizeof fip->name - 1;
+ gstr(p, fip->name, n);
+
+ free(p);
+ return 0;
+}
+
+/* supported by 95/98/ME */
+int
+T2querystandard(Session *s, Share *sp, char *path, FInfo *fip)
+{
+ Pkt *p;
+
+ p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
+ pt2param(p);
+ pl16(p, SMB_INFO_STANDARD); /* Information level */
+ pl32(p, 0); /* reserved */
+ ppath(p, path); /* path */
+
+ pt2data(p);
+ if(t2rpc(p) == -1){
+ free(p);
+ return -1;
+ }
+ gt2data(p);
+ memset(fip, 0, sizeof(FInfo));
+ fip->created = gdatetime(p); /* creation time */
+ fip->accessed = gdatetime(p); /* last access time */
+ fip->written = gdatetime(p); /* last written time */
+ fip->changed = fip->written; /* change time */
+ fip->size = gl32(p); /* file size */
+ gl32(p); /* bytes allocated */
+ fip->attribs = gl16(p); /* attributes */
+ gl32(p); /* EA size */
+
+ free(p);
+ return 0;
+}
+
+int
+T2setpathinfo(Session *s, Share *sp, char *path, FInfo *fip)
+{
+ int rc;
+ Pkt *p;
+
+ p = t2hdr(s, sp, TRANS2_SET_PATH_INFORMATION);
+ pt2param(p);
+ pl16(p, SMB_INFO_STANDARD); /* Information level */
+ pl32(p, 0); /* reserved */
+ ppath(p, path); /* path */
+
+ pt2data(p);
+ pdatetime(p, fip->created); /* created */
+ pdatetime(p, fip->accessed); /* accessed */
+ pdatetime(p, fip->written); /* written */
+ pl32(p, fip->size); /* size */
+ pl32(p, 0); /* allocated */
+ pl16(p, fip->attribs); /* attributes */
+ pl32(p, 0); /* EA size */
+ pl16(p, 0); /* reserved */
+
+ rc = t2rpc(p);
+ free(p);
+ return rc;
+
+}
+
+int
+T2setfilelength(Session *s, Share *sp, int fh, FInfo *fip) /* FIXME: maybe broken, needs testing */
+{
+ int rc;
+ Pkt *p;
+
+ p = t2hdr(s, sp, TRANS2_SET_FILE_INFORMATION);
+ pt2param(p);
+ pl16(p, fh); /* file handle */
+ pl16(p, SMB_SET_FILE_END_OF_FILE_INFO); /* Information level */
+ pl16(p, 0); /* reserved */
+
+ pt2data(p);
+ pl64(p, fip->size);
+ pl32(p, 0); /* padding ?! */
+ pl16(p, 0);
+
+ rc = t2rpc(p);
+ free(p);
+ return rc;
+}
+
+
+int
+T2fsvolumeinfo(Session *s, Share *sp, long *created, long *serialno,
+ char *label, int labellen)
+{
+ Pkt *p;
+ long ct, sn, n;
+
+ p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
+ pt2param(p);
+ pl16(p, SMB_QUERY_FS_VOLUME_INFO); /* Information level */
+
+ pt2data(p);
+
+ if(t2rpc(p) == -1){
+ free(p);
+ return -1;
+ }
+
+ gt2data(p);
+ ct = gvtime(p); /* creation time */
+ sn = gl32(p); /* serial number */
+ n = gl32(p); /* label name length */
+ g8(p); /* reserved */
+ g8(p); /* reserved */
+
+ memset(label, 0, labellen);
+ if(n < labellen && n > 0)
+ gstr(p, label, n); /* file system label */
+ if(created)
+ *created = ct;
+ if(serialno)
+ *serialno = sn;
+
+ free(p);
+ return 0;
+}
+
+int
+T2fssizeinfo(Session *s, Share *sp, uvlong *total, uvlong *unused)
+{
+ Pkt *p;
+ uvlong t, f, n, b;
+
+ p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
+ pt2param(p);
+ pl16(p, SMB_QUERY_FS_SIZE_INFO); /* Information level */
+
+ pt2data(p);
+
+ if(t2rpc(p) == -1){
+ free(p);
+ return -1;
+ }
+
+ gt2data(p);
+ t = gl64(p); /* total blocks */
+ f = gl64(p); /* free blocks */
+ n = gl32(p); /* sectors per block */
+ b = gl32(p); /* bytes per sector */
+
+ if(free)
+ *unused = f * n * b;
+ if(total)
+ *total = t * n * b;
+
+ free(p);
+ return 0;
+}
+
+int
+T2getdfsreferral(Session *s, Share *sp, char *path, int *gflags, int *used,
+ Refer *re, int nent)
+{
+ int i, vers, nret, len;
+ char tmp[1024];
+ uchar *base;
+ Pkt *p;
+
+ p = t2hdr(s, sp, TRANS2_GET_DFS_REFERRAL);
+ pt2param(p);
+ pl16(p, 3); /* max info level we understand, must be >= 3 for domain requests */
+ ppath(p, path);
+
+ pt2data(p);
+
+ if(t2rpc(p) == -1){
+ free(p);
+ return -1;
+ }
+
+ memset(re, 0, sizeof *re * nent);
+ gt2data(p);
+
+ *used = gl16(p) / 2; /* length used (/2 as Windows counts in runes) */
+ nret = gl16(p); /* number of referrals returned */
+ *gflags = gl32(p); /* global flags */
+
+ for(i = 0; i < nret && i < nent && i < 16; i++){
+ base = p->pos;
+ vers = gl16(p); /* version of records */
+ len = gl16(p); /* length of records */
+ re[i].type = gl16(p); /* server type */
+ re[i].flags = gl16(p); /* referal flags */
+ switch(vers){
+ case 1:
+ re[i].prox = 0; /* nearby */
+ re[i].ttl = 5*60; /* 5 mins */
+ gstr(p, tmp, sizeof tmp);
+ re[i].addr = estrdup9p(tmp);
+ re[i].path = estrdup9p(tmp);
+ break;
+ case 2:
+ re[i].prox = gl32(p); /* not implemented in v2 */
+ re[i].ttl = gl32(p);
+ goff(p, base, re[i].path, sizeof tmp);
+ re[i].path = estrdup9p(tmp);
+ goff(p, base, re[i].path, sizeof tmp);/* spurious 8.3 path */
+ goff(p, base, tmp, sizeof tmp);
+ re[i].addr = estrdup9p(tmp);
+ break;
+ case 3:
+ if(re[i].flags & DFS_REFERAL_LIST){
+ re[i].prox = 0;
+ re[i].ttl = gl32(p);
+ goff(p, base, tmp, sizeof tmp);
+ re[i].path = estrdup9p(tmp);
+ gl16(p);
+ goff(p, base, tmp, sizeof tmp);
+ re[i].addr = estrdup9p(tmp);
+ }
+ else{
+ re[i].prox = 0;
+ re[i].ttl = gl32(p);
+ goff(p, base, tmp, sizeof tmp);
+ re[i].path = estrdup9p(tmp);
+ gl16(p); /* spurious 8.3 path */
+ goff(p, base, tmp, sizeof tmp);
+ re[i].addr = estrdup9p(tmp);
+ gl16(p); /* GUID (historic) */
+ }
+ break;
+ default:
+ /*
+ * this should never happen as we specify our maximum
+ * understood level in the request (above)
+ */
+ fprint(2, "%d - unsupported DFS infolevel\n", vers);
+ re[i].path = estrdup9p(tmp);
+ re[i].addr = estrdup9p(tmp);
+ break;
+ }
+ p->pos = base+len;
+ }
+
+ free(p);
+ return i;
+}