548 lines · 12.5 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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 voidpt2param(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 voidpt2data(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 intt2rpc(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 voidgt2param(Pkt *p){	p->pos = p->tparam;} static voidgt2data(Pkt *p){	p->pos = p->tdata;}  intT2findfirst(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; } intT2findnext(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 */intT2queryall(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 */intT2querystandard(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;} intT2setpathinfo(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; } intT2setfilelength(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;}  intT2fsvolumeinfo(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;} intT2fssizeinfo(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;} intT2getdfsreferral(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);

Lines 1–500 of 548.