xref: /plan9/sys/src/cmd/cifs/trans2.c (revision 912e5f5442636b48aaa52937edbb904e279d1987)
1671dfc47SDavid du Colombier #include <u.h>
2671dfc47SDavid du Colombier #include <libc.h>
3671dfc47SDavid du Colombier #include <fcall.h>
4671dfc47SDavid du Colombier #include <thread.h>
5671dfc47SDavid du Colombier #include <9p.h>
6671dfc47SDavid du Colombier #include "cifs.h"
7671dfc47SDavid du Colombier 
8671dfc47SDavid du Colombier static Pkt *
t2hdr(Session * s,Share * sp,int cmd)9671dfc47SDavid du Colombier t2hdr(Session *s, Share *sp, int cmd)
10671dfc47SDavid du Colombier {
11671dfc47SDavid du Colombier 	Pkt *p;
12671dfc47SDavid du Colombier 
13671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_TRANSACTION2);
14671dfc47SDavid du Colombier 
15671dfc47SDavid du Colombier 	p->tbase = pl16(p, 0);	/* 0  Total parameter bytes to be sent, filled later */
16671dfc47SDavid du Colombier 	pl16(p, 0);		/* 2  Total data bytes to be sent, filled later */
17671dfc47SDavid du Colombier 	pl16(p, 64);			/* 4  Max parameter to return */
18671dfc47SDavid du Colombier 	pl16(p, (MTU - T2HDRLEN)-64);	/* 6  Max data to return */
19671dfc47SDavid du Colombier 	p8(p, 0);			/* 8  Max setup count to return */
20671dfc47SDavid du Colombier 	p8(p, 0);			/* 9  Reserved */
21671dfc47SDavid du Colombier 	pl16(p, 0);			/* 10 Flags */
22671dfc47SDavid du Colombier 	pl32(p, 1000);			/* 12 Timeout (ms) */
23671dfc47SDavid du Colombier 	pl16(p, 0);			/* 16 Reserved */
24671dfc47SDavid du Colombier 	pl16(p, 0);			/* 18 Parameter count, filled later */
25671dfc47SDavid du Colombier 	pl16(p, 0);			/* 20 Parameter offset, filled later */
26671dfc47SDavid du Colombier 	pl16(p, 0);			/* 22 Data count, filled later */
27671dfc47SDavid du Colombier 	pl16(p, 0);			/* 24 Data offset, filled later */
28671dfc47SDavid du Colombier 	p8(p, 1);			/* 26 Setup count (in words) */
29671dfc47SDavid du Colombier 	p8(p, 0);			/* 27 Reserved */
30671dfc47SDavid du Colombier 	pl16(p, cmd);			/* setup[0] */
31671dfc47SDavid du Colombier 	pbytes(p);
32671dfc47SDavid du Colombier 	p8(p, 0);			/* padding ??!?!? */
33671dfc47SDavid du Colombier 
34671dfc47SDavid du Colombier 	return p;
35671dfc47SDavid du Colombier }
36671dfc47SDavid du Colombier 
37671dfc47SDavid du Colombier static void
pt2param(Pkt * p)38671dfc47SDavid du Colombier pt2param(Pkt *p)
39671dfc47SDavid du Colombier {
40671dfc47SDavid du Colombier 	uchar *pos = p->pos;
41671dfc47SDavid du Colombier 
42671dfc47SDavid du Colombier 	assert(p->tbase != 0);
43671dfc47SDavid du Colombier 	p->pos = p->tbase + 20;
44671dfc47SDavid du Colombier 	pl16(p, (pos - p->buf) - NBHDRLEN); /* param offset */
45671dfc47SDavid du Colombier 
46671dfc47SDavid du Colombier 	p->tparam = p->pos = pos;
47671dfc47SDavid du Colombier }
48671dfc47SDavid du Colombier 
49671dfc47SDavid du Colombier static void
pt2data(Pkt * p)50671dfc47SDavid du Colombier pt2data(Pkt *p)
51671dfc47SDavid du Colombier {
52671dfc47SDavid du Colombier 	uchar *pos = p->pos;
53671dfc47SDavid du Colombier 
54671dfc47SDavid du Colombier 	assert(p->tbase != 0);
55671dfc47SDavid du Colombier 	assert(p->tparam != 0);
56671dfc47SDavid du Colombier 
57671dfc47SDavid du Colombier 	p->pos = p->tbase +0;
58671dfc47SDavid du Colombier 	pl16(p, pos - p->tparam);		/* total param count */
59671dfc47SDavid du Colombier 
60671dfc47SDavid du Colombier 	p->pos = p->tbase +18;
61671dfc47SDavid du Colombier 	pl16(p, pos - p->tparam);		/* param count */
62671dfc47SDavid du Colombier 
63671dfc47SDavid du Colombier 	p->pos = p->tbase +24;
64671dfc47SDavid du Colombier 	pl16(p, (pos - p->buf) - NBHDRLEN);	/* data offset */
65671dfc47SDavid du Colombier 
66671dfc47SDavid du Colombier 	p->tdata = p->pos = pos;
67671dfc47SDavid du Colombier }
68671dfc47SDavid du Colombier 
69671dfc47SDavid du Colombier static int
t2rpc(Pkt * p)70671dfc47SDavid du Colombier t2rpc(Pkt *p)
71671dfc47SDavid du Colombier {
72671dfc47SDavid du Colombier 	int got;
73671dfc47SDavid du Colombier 	uchar *pos;
74671dfc47SDavid du Colombier 
75671dfc47SDavid du Colombier 	assert(p->tbase != 0);
76671dfc47SDavid du Colombier 	assert(p->tdata != 0);
77671dfc47SDavid du Colombier 
78671dfc47SDavid du Colombier 	pos = p->pos;
79671dfc47SDavid du Colombier 
80671dfc47SDavid du Colombier 	p->pos = p->tbase +2;
81671dfc47SDavid du Colombier 	pl16(p, pos - p->tdata);		/* total data count */
82671dfc47SDavid du Colombier 
83671dfc47SDavid du Colombier 	p->pos = p->tbase +22;
84671dfc47SDavid du Colombier 	pl16(p, pos - p->tdata);		/* data count */
85671dfc47SDavid du Colombier 
86671dfc47SDavid du Colombier 	p->pos = pos;
87671dfc47SDavid du Colombier 	if((got = cifsrpc(p)) == -1)
88671dfc47SDavid du Colombier 		return -1;
89671dfc47SDavid du Colombier 
90671dfc47SDavid du Colombier 	gl16(p);			/* Total parameter count */
91671dfc47SDavid du Colombier 	gl16(p);			/* Total data count */
92671dfc47SDavid du Colombier 	gl16(p);			/* Reserved */
93671dfc47SDavid du Colombier 	gl16(p);			/* Parameter count in this buffer */
94671dfc47SDavid du Colombier 	p->tparam = p->buf +NBHDRLEN +gl16(p); /* Parameter offset */
95671dfc47SDavid du Colombier 	gl16(p);			/* Parameter displacement */
96671dfc47SDavid du Colombier 	gl16(p);			/* Data count (this buffer); */
97671dfc47SDavid du Colombier 	p->tdata = p->buf +NBHDRLEN +gl16(p); /* Data offset */
98671dfc47SDavid du Colombier 	gl16(p);			/* Data displacement */
99671dfc47SDavid du Colombier 	g8(p);				/* Setup count */
100671dfc47SDavid du Colombier 	g8(p);				/* Reserved */
101671dfc47SDavid du Colombier 
102671dfc47SDavid du Colombier 	return got;
103671dfc47SDavid du Colombier }
104671dfc47SDavid du Colombier 
105671dfc47SDavid du Colombier static void
gt2param(Pkt * p)106671dfc47SDavid du Colombier gt2param(Pkt *p)
107671dfc47SDavid du Colombier {
108671dfc47SDavid du Colombier 	p->pos = p->tparam;
109671dfc47SDavid du Colombier }
110671dfc47SDavid du Colombier 
111671dfc47SDavid du Colombier static void
gt2data(Pkt * p)112671dfc47SDavid du Colombier gt2data(Pkt *p)
113671dfc47SDavid du Colombier {
114671dfc47SDavid du Colombier 	p->pos = p->tdata;
115671dfc47SDavid du Colombier }
116671dfc47SDavid du Colombier 
117671dfc47SDavid du Colombier 
118671dfc47SDavid du Colombier int
T2findfirst(Session * s,Share * sp,int slots,char * path,int * got,long * resume,FInfo * fip)119671dfc47SDavid du Colombier T2findfirst(Session *s, Share *sp, int slots, char *path, int *got,
120671dfc47SDavid du Colombier 	long *resume, FInfo *fip)
121671dfc47SDavid du Colombier {
122671dfc47SDavid du Colombier 	int pktlen, i, n, sh;
123671dfc47SDavid du Colombier 	uchar *next;
124671dfc47SDavid du Colombier 	Pkt *p;
125671dfc47SDavid du Colombier 
126671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_FIND_FIRST2);
127671dfc47SDavid du Colombier 	p8(p, 'D');			/* OS/2 */
128671dfc47SDavid du Colombier 	p8(p, ' ');			/* OS/2 */
129671dfc47SDavid du Colombier 
130671dfc47SDavid du Colombier 	pt2param(p);
131671dfc47SDavid du Colombier 	pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* Search attributes */
132671dfc47SDavid du Colombier 	pl16(p, slots);			/* Search count */
133671dfc47SDavid du Colombier 	pl16(p, CIFS_SEARCH_RETURN_RESUME); /* Flags */
134671dfc47SDavid du Colombier 	pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
135671dfc47SDavid du Colombier 	pl32(p, 0);			/* SearchStorage type (?) */
136671dfc47SDavid du Colombier 	ppath(p, path);			/* path */
137671dfc47SDavid du Colombier 
138671dfc47SDavid du Colombier 	pt2data(p);
139671dfc47SDavid du Colombier 	if((pktlen = t2rpc(p)) == -1){
140671dfc47SDavid du Colombier 		free(p);
141671dfc47SDavid du Colombier 		return -1;
142671dfc47SDavid du Colombier 	}
143671dfc47SDavid du Colombier 
144671dfc47SDavid du Colombier 	s->lastfind = nsec();
145671dfc47SDavid du Colombier 	gt2param(p);
146671dfc47SDavid du Colombier 
147671dfc47SDavid du Colombier 	sh = gl16(p);			/* Sid (search handle) */
148671dfc47SDavid du Colombier 	*got = gl16(p);			/* number of slots received */
149671dfc47SDavid du Colombier 	gl16(p);			/* End of search flag */
150671dfc47SDavid du Colombier 	gl16(p);			/* Offset into EA list if EA error */
151671dfc47SDavid du Colombier 	gl16(p);			/* Offset into data to file name of last entry */
152671dfc47SDavid du Colombier 
153671dfc47SDavid du Colombier 	gt2data(p);
154671dfc47SDavid du Colombier 	memset(fip, 0, slots * sizeof(FInfo));
155671dfc47SDavid du Colombier 	for(i = 0; i < *got; i++){
156671dfc47SDavid du Colombier 		next = p->pos;
157671dfc47SDavid du Colombier 		next += gl32(p);	/* offset to next entry */
158671dfc47SDavid du Colombier 		/*
159671dfc47SDavid du Colombier 		 * bug in Windows - somtimes it lies about how many
160671dfc47SDavid du Colombier 		 * directory entries it has put in the packet
161671dfc47SDavid du Colombier 		 */
162671dfc47SDavid du Colombier 		if(next - p->buf > pktlen){
163671dfc47SDavid du Colombier 			*got = i;
164671dfc47SDavid du Colombier 			break;
165671dfc47SDavid du Colombier 		}
166671dfc47SDavid du Colombier 
167671dfc47SDavid du Colombier 		*resume = gl32(p);		/* resume key for search */
168671dfc47SDavid du Colombier 		fip[i].created = gvtime(p);	/* creation time */
169671dfc47SDavid du Colombier 		fip[i].accessed = gvtime(p);	/* last access time */
170671dfc47SDavid du Colombier 		fip[i].written = gvtime(p);	/* last written time */
171671dfc47SDavid du Colombier 		fip[i].changed = gvtime(p);	/* change time */
172671dfc47SDavid du Colombier 		fip[i].size = gl64(p);		/* file size */
173671dfc47SDavid du Colombier 		gl64(p);			/* bytes allocated */
174671dfc47SDavid du Colombier 		fip[i].attribs = gl32(p);	/* extended attributes */
175671dfc47SDavid du Colombier 		n = gl32(p);			/* name length */
176671dfc47SDavid du Colombier 		gl32(p);			/* EA size */
177671dfc47SDavid du Colombier 		gstr(p, fip[i].name, n); 	/* name */
178671dfc47SDavid du Colombier 		p->pos = next;
179671dfc47SDavid du Colombier 	}
180671dfc47SDavid du Colombier 
181671dfc47SDavid du Colombier 	free(p);
182671dfc47SDavid du Colombier 	return sh;
183671dfc47SDavid du Colombier 
184671dfc47SDavid du Colombier }
185671dfc47SDavid du Colombier 
186671dfc47SDavid du Colombier int
T2findnext(Session * s,Share * sp,int slots,char * path,int * got,long * resume,FInfo * fip,int sh)187671dfc47SDavid du Colombier T2findnext(Session *s, Share *sp, int slots, char *path, int *got,
188671dfc47SDavid du Colombier 	long *resume, FInfo *fip, int sh)
189671dfc47SDavid du Colombier {
190*912e5f54SDavid du Colombier 	Pkt *p;
191671dfc47SDavid du Colombier 	int i, n;
192671dfc47SDavid du Colombier 	uchar *next;
193671dfc47SDavid du Colombier 
194671dfc47SDavid du Colombier 	/*
195671dfc47SDavid du Colombier 	 * So I believe from comp.protocols.smb if you send
196671dfc47SDavid du Colombier 	 * TRANS2_FIND_NEXT2 requests too quickly to windows 95, it can
197671dfc47SDavid du Colombier 	 * get confused and fail to reply, so we slow up a bit in these
198671dfc47SDavid du Colombier 	 * circumstances.
199671dfc47SDavid du Colombier 	 */
200671dfc47SDavid du Colombier 	if(!(s->caps & CAP_NT_SMBS) && nsec() - s->lastfind < 200000000LL)
201671dfc47SDavid du Colombier 		sleep(200);
202671dfc47SDavid du Colombier 
203671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_FIND_NEXT2);
204671dfc47SDavid du Colombier 	p8(p, 'D');			/* OS/2 */
205671dfc47SDavid du Colombier 	p8(p, ' ');			/* OS/2 */
206671dfc47SDavid du Colombier 
207671dfc47SDavid du Colombier 	pt2param(p);
208671dfc47SDavid du Colombier 	pl16(p, sh);				/* search handle */
209671dfc47SDavid du Colombier 	pl16(p, slots);				/* Search count */
210671dfc47SDavid du Colombier 	pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
211671dfc47SDavid du Colombier 	pl32(p, *resume);			/* resume key */
212671dfc47SDavid du Colombier 	pl16(p, CIFS_SEARCH_CONTINUE_FROM_LAST); /* Flags */
213671dfc47SDavid du Colombier 	ppath(p, path);				/* file+path to resume */
214671dfc47SDavid du Colombier 
215671dfc47SDavid du Colombier 	pt2data(p);
216671dfc47SDavid du Colombier 	if(t2rpc(p) == -1){
217671dfc47SDavid du Colombier 		free(p);
218671dfc47SDavid du Colombier 		return -1;
219671dfc47SDavid du Colombier 	}
220671dfc47SDavid du Colombier 
221671dfc47SDavid du Colombier 	s->lastfind = nsec();
222671dfc47SDavid du Colombier 
223671dfc47SDavid du Colombier 	gt2param(p);
224671dfc47SDavid du Colombier 	*got = gl16(p);		/* number of slots received */
225671dfc47SDavid du Colombier 	gl16(p);		/* End of search flag */
226671dfc47SDavid du Colombier 	gl16(p);		/* Offset into EA list if EA error */
227671dfc47SDavid du Colombier 	gl16(p);		/* Offset into data to file name of last entry */
228671dfc47SDavid du Colombier 
229671dfc47SDavid du Colombier 	gt2data(p);
230671dfc47SDavid du Colombier 	memset(fip, 0, slots * sizeof(FInfo));
231671dfc47SDavid du Colombier 	for(i = 0; i < *got; i++){
232671dfc47SDavid du Colombier 		next = p->pos;
233671dfc47SDavid du Colombier 		next += gl32(p);		/* offset to next entry */
234671dfc47SDavid du Colombier 		*resume = gl32(p);		/* resume key for search */
235671dfc47SDavid du Colombier 		fip[i].created = gvtime(p);	/* creation time */
236671dfc47SDavid du Colombier 		fip[i].accessed = gvtime(p);	/* last access time */
237671dfc47SDavid du Colombier 		fip[i].written = gvtime(p);	/* last written time */
238671dfc47SDavid du Colombier 		fip[i].changed = gvtime(p);	/* change time */
239671dfc47SDavid du Colombier 		fip[i].size = gl64(p);		/* file size */
240671dfc47SDavid du Colombier 		gl64(p);			/* bytes allocated */
241671dfc47SDavid du Colombier 		fip[i].attribs = gl32(p);	/* extended attributes */
242671dfc47SDavid du Colombier 		n = gl32(p);			/* name length */
243671dfc47SDavid du Colombier 		gl32(p);			/* EA size */
244671dfc47SDavid du Colombier 		gstr(p, fip[i].name, n); 	/* name */
245671dfc47SDavid du Colombier 		p->pos = next;
246671dfc47SDavid du Colombier 	}
247671dfc47SDavid du Colombier 	free(p);
248671dfc47SDavid du Colombier 	return 0;
249671dfc47SDavid du Colombier }
250671dfc47SDavid du Colombier 
251671dfc47SDavid du Colombier 
252671dfc47SDavid du Colombier /* supported by 2k/XP/NT4 */
253671dfc47SDavid du Colombier int
T2queryall(Session * s,Share * sp,char * path,FInfo * fip)254671dfc47SDavid du Colombier T2queryall(Session *s, Share *sp, char *path, FInfo *fip)
255671dfc47SDavid du Colombier {
256671dfc47SDavid du Colombier 	int n;
257671dfc47SDavid du Colombier 	Pkt *p;
258671dfc47SDavid du Colombier 
259671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
260671dfc47SDavid du Colombier 	pt2param(p);
261671dfc47SDavid du Colombier 	pl16(p, SMB_QUERY_FILE_ALL_INFO); /* Information level	 */
262671dfc47SDavid du Colombier 	pl32(p, 0);			/* reserved */
263671dfc47SDavid du Colombier 	ppath(p, path);			/* path */
264671dfc47SDavid du Colombier 
265671dfc47SDavid du Colombier 	pt2data(p);
266671dfc47SDavid du Colombier 	if(t2rpc(p) == -1){
267671dfc47SDavid du Colombier 		free(p);
268671dfc47SDavid du Colombier 		return -1;
269671dfc47SDavid du Colombier 	}
270671dfc47SDavid du Colombier 	gt2data(p);
271671dfc47SDavid du Colombier 
272671dfc47SDavid du Colombier 	/*
273671dfc47SDavid du Colombier 	 * The layout of this struct is wrong in the SINA
274671dfc47SDavid du Colombier 	 * document, this layout gained by inspection.
275671dfc47SDavid du Colombier 	 */
276671dfc47SDavid du Colombier 	memset(fip, 0, sizeof(FInfo));
277671dfc47SDavid du Colombier 	fip->created = gvtime(p);	/* creation time */
278671dfc47SDavid du Colombier 	fip->accessed = gvtime(p);	/* last access time */
279671dfc47SDavid du Colombier 	fip->written = gvtime(p);	/* last written time */
280671dfc47SDavid du Colombier 	fip->changed = gvtime(p);	/* change time */
281671dfc47SDavid du Colombier 	fip->attribs = gl32(p);		/* attributes */
282671dfc47SDavid du Colombier 	gl32(p);			/* reserved */
283671dfc47SDavid du Colombier 	gl64(p);			/* bytes allocated */
284671dfc47SDavid du Colombier 	fip->size = gl64(p);		/* file size */
285671dfc47SDavid du Colombier 	gl32(p);			/* number of hard links */
286671dfc47SDavid du Colombier 	g8(p);				/* delete pending */
287671dfc47SDavid du Colombier 	g8(p);				/* is a directory */
288671dfc47SDavid du Colombier 	gl16(p);			/* reserved */
289671dfc47SDavid du Colombier 	gl32(p);			/* EA size */
290671dfc47SDavid du Colombier 
291671dfc47SDavid du Colombier 	n = gl32(p);
292671dfc47SDavid du Colombier 	if(n >= sizeof fip->name)
293671dfc47SDavid du Colombier 		n = sizeof fip->name - 1;
294671dfc47SDavid du Colombier 	gstr(p, fip->name, n);
295671dfc47SDavid du Colombier 
296671dfc47SDavid du Colombier 	free(p);
297671dfc47SDavid du Colombier 	return 0;
298671dfc47SDavid du Colombier }
299671dfc47SDavid du Colombier 
300671dfc47SDavid du Colombier /* supported by 95/98/ME */
301671dfc47SDavid du Colombier int
T2querystandard(Session * s,Share * sp,char * path,FInfo * fip)302671dfc47SDavid du Colombier T2querystandard(Session *s, Share *sp, char *path, FInfo *fip)
303671dfc47SDavid du Colombier {
304671dfc47SDavid du Colombier 	Pkt *p;
305671dfc47SDavid du Colombier 
306671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
307671dfc47SDavid du Colombier 	pt2param(p);
308671dfc47SDavid du Colombier 	pl16(p, SMB_INFO_STANDARD);	/* Information level */
309671dfc47SDavid du Colombier 	pl32(p, 0);			/* reserved */
310671dfc47SDavid du Colombier 	ppath(p, path);			/* path */
311671dfc47SDavid du Colombier 
312671dfc47SDavid du Colombier 	pt2data(p);
313671dfc47SDavid du Colombier 	if(t2rpc(p) == -1){
314671dfc47SDavid du Colombier 		free(p);
315671dfc47SDavid du Colombier 		return -1;
316671dfc47SDavid du Colombier 	}
317671dfc47SDavid du Colombier 	gt2data(p);
318671dfc47SDavid du Colombier 	memset(fip, 0, sizeof(FInfo));
319671dfc47SDavid du Colombier 	fip->created = gdatetime(p);	/* creation time */
320671dfc47SDavid du Colombier 	fip->accessed = gdatetime(p);	/* last access time */
321671dfc47SDavid du Colombier 	fip->written = gdatetime(p);	/* last written time */
322671dfc47SDavid du Colombier 	fip->changed = fip->written;	/* change time */
323671dfc47SDavid du Colombier 	fip->size = gl32(p);		/* file size */
324671dfc47SDavid du Colombier 	gl32(p);			/* bytes allocated */
325671dfc47SDavid du Colombier 	fip->attribs = gl16(p);		/* attributes */
326671dfc47SDavid du Colombier 	gl32(p);			/* EA size */
327671dfc47SDavid du Colombier 
328671dfc47SDavid du Colombier 	free(p);
329671dfc47SDavid du Colombier 	return 0;
330671dfc47SDavid du Colombier }
331671dfc47SDavid du Colombier 
332671dfc47SDavid du Colombier int
T2setpathinfo(Session * s,Share * sp,char * path,FInfo * fip)333671dfc47SDavid du Colombier T2setpathinfo(Session *s, Share *sp, char *path, FInfo *fip)
334671dfc47SDavid du Colombier {
335671dfc47SDavid du Colombier 	int rc;
336671dfc47SDavid du Colombier 	Pkt *p;
337671dfc47SDavid du Colombier 
338671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_SET_PATH_INFORMATION);
339671dfc47SDavid du Colombier 	pt2param(p);
340671dfc47SDavid du Colombier 	pl16(p, SMB_INFO_STANDARD);	/* Information level */
341671dfc47SDavid du Colombier 	pl32(p, 0);			/* reserved */
342671dfc47SDavid du Colombier 	ppath(p, path);			/* path */
343671dfc47SDavid du Colombier 
344671dfc47SDavid du Colombier 	pt2data(p);
345671dfc47SDavid du Colombier 	pdatetime(p, fip->created);	/* created */
346671dfc47SDavid du Colombier 	pdatetime(p, fip->accessed);	/* accessed */
347671dfc47SDavid du Colombier 	pdatetime(p, fip->written);	/* written */
348671dfc47SDavid du Colombier 	pl32(p, fip->size);		/* size */
349671dfc47SDavid du Colombier 	pl32(p, 0);			/* allocated */
350671dfc47SDavid du Colombier 	pl16(p, fip->attribs);		/* attributes */
351671dfc47SDavid du Colombier 	pl32(p, 0);			/* EA size */
352671dfc47SDavid du Colombier 	pl16(p, 0);			/* reserved */
353671dfc47SDavid du Colombier 
354671dfc47SDavid du Colombier 	rc = t2rpc(p);
355671dfc47SDavid du Colombier 	free(p);
356671dfc47SDavid du Colombier 	return rc;
357671dfc47SDavid du Colombier 
358671dfc47SDavid du Colombier }
359671dfc47SDavid du Colombier 
360671dfc47SDavid du Colombier int
T2setfilelength(Session * s,Share * sp,int fh,FInfo * fip)361671dfc47SDavid du Colombier T2setfilelength(Session *s, Share *sp, int fh, FInfo *fip) /* FIXME: maybe broken, needs testing */
362671dfc47SDavid du Colombier {
363671dfc47SDavid du Colombier 	int rc;
364671dfc47SDavid du Colombier 	Pkt *p;
365671dfc47SDavid du Colombier 
366671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_SET_FILE_INFORMATION);
367671dfc47SDavid du Colombier 	pt2param(p);
368671dfc47SDavid du Colombier 	pl16(p, fh);			/* file handle */
369671dfc47SDavid du Colombier 	pl16(p, SMB_SET_FILE_END_OF_FILE_INFO); /* Information level */
370671dfc47SDavid du Colombier 	pl16(p, 0);			/* reserved */
371671dfc47SDavid du Colombier 
372671dfc47SDavid du Colombier 	pt2data(p);
373671dfc47SDavid du Colombier 	pl64(p, fip->size);
374671dfc47SDavid du Colombier 	pl32(p, 0);			/* padding ?! */
375671dfc47SDavid du Colombier 	pl16(p, 0);
376671dfc47SDavid du Colombier 
377671dfc47SDavid du Colombier 	rc = t2rpc(p);
378671dfc47SDavid du Colombier 	free(p);
379671dfc47SDavid du Colombier 	return rc;
380671dfc47SDavid du Colombier }
381671dfc47SDavid du Colombier 
382671dfc47SDavid du Colombier 
383671dfc47SDavid du Colombier int
T2fsvolumeinfo(Session * s,Share * sp,long * created,long * serialno,char * label,int labellen)384671dfc47SDavid du Colombier T2fsvolumeinfo(Session *s, Share *sp, long *created, long *serialno,
385671dfc47SDavid du Colombier 	char *label, int labellen)
386671dfc47SDavid du Colombier {
387671dfc47SDavid du Colombier 	Pkt *p;
388671dfc47SDavid du Colombier 	long ct, sn, n;
389671dfc47SDavid du Colombier 
390671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
391671dfc47SDavid du Colombier 	pt2param(p);
392671dfc47SDavid du Colombier 	pl16(p, SMB_QUERY_FS_VOLUME_INFO);	/* Information level */
393671dfc47SDavid du Colombier 
394671dfc47SDavid du Colombier 	pt2data(p);
395671dfc47SDavid du Colombier 
396671dfc47SDavid du Colombier 	if(t2rpc(p) == -1){
397671dfc47SDavid du Colombier 		free(p);
398671dfc47SDavid du Colombier 		return -1;
399671dfc47SDavid du Colombier 	}
400671dfc47SDavid du Colombier 
401671dfc47SDavid du Colombier 	gt2data(p);
402671dfc47SDavid du Colombier 	ct = gvtime(p);			/* creation time */
403671dfc47SDavid du Colombier 	sn = gl32(p);			/* serial number */
404671dfc47SDavid du Colombier 	n = gl32(p);			/* label name length */
405671dfc47SDavid du Colombier 	g8(p);				/* reserved */
406671dfc47SDavid du Colombier 	g8(p);				/* reserved */
407671dfc47SDavid du Colombier 
408671dfc47SDavid du Colombier 	memset(label, 0, labellen);
409671dfc47SDavid du Colombier 	if(n < labellen && n > 0)
410671dfc47SDavid du Colombier 		gstr(p, label, n);	/* file system label */
411671dfc47SDavid du Colombier 	if(created)
412671dfc47SDavid du Colombier 		*created = ct;
413671dfc47SDavid du Colombier 	if(serialno)
414671dfc47SDavid du Colombier 		*serialno = sn;
415671dfc47SDavid du Colombier 
416671dfc47SDavid du Colombier 	free(p);
417671dfc47SDavid du Colombier 	return 0;
418671dfc47SDavid du Colombier }
419671dfc47SDavid du Colombier 
420671dfc47SDavid du Colombier int
T2fssizeinfo(Session * s,Share * sp,uvlong * total,uvlong * unused)421671dfc47SDavid du Colombier T2fssizeinfo(Session *s, Share *sp, uvlong *total, uvlong *unused)
422671dfc47SDavid du Colombier {
423671dfc47SDavid du Colombier 	Pkt *p;
424671dfc47SDavid du Colombier 	uvlong t, f, n, b;
425671dfc47SDavid du Colombier 
426671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
427671dfc47SDavid du Colombier 	pt2param(p);
428671dfc47SDavid du Colombier 	pl16(p, SMB_QUERY_FS_SIZE_INFO);	/* Information level */
429671dfc47SDavid du Colombier 
430671dfc47SDavid du Colombier 	pt2data(p);
431671dfc47SDavid du Colombier 
432671dfc47SDavid du Colombier 	if(t2rpc(p) == -1){
433671dfc47SDavid du Colombier 		free(p);
434671dfc47SDavid du Colombier 		return -1;
435671dfc47SDavid du Colombier 	}
436671dfc47SDavid du Colombier 
437671dfc47SDavid du Colombier 	gt2data(p);
438671dfc47SDavid du Colombier 	t = gl64(p);		/* total blocks */
439671dfc47SDavid du Colombier 	f = gl64(p);		/* free blocks */
440671dfc47SDavid du Colombier 	n = gl32(p);		/* sectors per block */
441671dfc47SDavid du Colombier 	b = gl32(p);		/* bytes per sector */
442671dfc47SDavid du Colombier 
443671dfc47SDavid du Colombier 	if(free)
444671dfc47SDavid du Colombier 		*unused = f * n * b;
445671dfc47SDavid du Colombier 	if(total)
446671dfc47SDavid du Colombier 		*total = t * n * b;
447671dfc47SDavid du Colombier 
448671dfc47SDavid du Colombier 	free(p);
449671dfc47SDavid du Colombier 	return 0;
450671dfc47SDavid du Colombier }
451671dfc47SDavid du Colombier 
452671dfc47SDavid du Colombier int
T2getdfsreferral(Session * s,Share * sp,char * path,int * gflags,int * used,Refer * re,int nent)453671dfc47SDavid du Colombier T2getdfsreferral(Session *s, Share *sp, char *path, int *gflags, int *used,
454671dfc47SDavid du Colombier 	Refer *re, int nent)
455671dfc47SDavid du Colombier {
456671dfc47SDavid du Colombier 	int i, vers, nret, len;
457671dfc47SDavid du Colombier 	char tmp[1024];
458671dfc47SDavid du Colombier 	uchar *base;
459671dfc47SDavid du Colombier 	Pkt *p;
460671dfc47SDavid du Colombier 
461671dfc47SDavid du Colombier 	p = t2hdr(s, sp, TRANS2_GET_DFS_REFERRAL);
462671dfc47SDavid du Colombier 	pt2param(p);
463671dfc47SDavid du Colombier 	pl16(p, 3); /* max info level we understand, must be >= 3 for domain requests */
464671dfc47SDavid du Colombier 	ppath(p, path);
465671dfc47SDavid du Colombier 
466671dfc47SDavid du Colombier 	pt2data(p);
467671dfc47SDavid du Colombier 
468671dfc47SDavid du Colombier 	if(t2rpc(p) == -1){
469671dfc47SDavid du Colombier 		free(p);
470671dfc47SDavid du Colombier 		return -1;
471671dfc47SDavid du Colombier 	}
472671dfc47SDavid du Colombier 
473671dfc47SDavid du Colombier 	memset(re, 0, sizeof *re * nent);
474671dfc47SDavid du Colombier 	gt2data(p);
475671dfc47SDavid du Colombier 
476671dfc47SDavid du Colombier 	*used = gl16(p) / 2;	/* length used (/2 as Windows counts in runes) */
477671dfc47SDavid du Colombier 	nret = gl16(p);		/* number of referrals returned */
478671dfc47SDavid du Colombier 	*gflags = gl32(p);	/* global flags */
479671dfc47SDavid du Colombier 
480671dfc47SDavid du Colombier 	for(i = 0; i < nret && i < nent && i < 16; i++){
481671dfc47SDavid du Colombier 		base = p->pos;
482671dfc47SDavid du Colombier 		vers = gl16(p);		/* version of records */
483671dfc47SDavid du Colombier 		len = gl16(p);		/* length of records */
484671dfc47SDavid du Colombier 		re[i].type = gl16(p);	/* server type */
485671dfc47SDavid du Colombier 		re[i].flags = gl16(p);	/* referal flags */
486671dfc47SDavid du Colombier 		switch(vers){
487671dfc47SDavid du Colombier 		case 1:
488671dfc47SDavid du Colombier 			re[i].prox = 0;	/* nearby */
489671dfc47SDavid du Colombier 			re[i].ttl = 5*60;	/* 5 mins */
490671dfc47SDavid du Colombier 			gstr(p, tmp, sizeof tmp);
491671dfc47SDavid du Colombier 			re[i].addr = estrdup9p(tmp);
492671dfc47SDavid du Colombier 			re[i].path = estrdup9p(tmp);
493671dfc47SDavid du Colombier 			break;
494671dfc47SDavid du Colombier 		case 2:
495671dfc47SDavid du Colombier 			re[i].prox = gl32(p);	/* not implemented in v2 */
496671dfc47SDavid du Colombier 			re[i].ttl = gl32(p);
497671dfc47SDavid du Colombier 			goff(p, base, re[i].path, sizeof tmp);
498671dfc47SDavid du Colombier 			re[i].path = estrdup9p(tmp);
499671dfc47SDavid du Colombier 			goff(p, base, re[i].path, sizeof tmp);/* spurious 8.3 path */
500671dfc47SDavid du Colombier 			goff(p, base, tmp, sizeof tmp);
501671dfc47SDavid du Colombier 			re[i].addr = estrdup9p(tmp);
502671dfc47SDavid du Colombier 			break;
503671dfc47SDavid du Colombier 		case 3:
504671dfc47SDavid du Colombier 			if(re[i].flags & DFS_REFERAL_LIST){
505671dfc47SDavid du Colombier 				re[i].prox = 0;
506671dfc47SDavid du Colombier 				re[i].ttl = gl32(p);
507671dfc47SDavid du Colombier 				goff(p, base, tmp, sizeof tmp);
508671dfc47SDavid du Colombier 				re[i].path = estrdup9p(tmp);
509671dfc47SDavid du Colombier 				gl16(p);
510671dfc47SDavid du Colombier 				goff(p, base, tmp, sizeof tmp);
511671dfc47SDavid du Colombier 				re[i].addr = estrdup9p(tmp);
512671dfc47SDavid du Colombier 			}
513671dfc47SDavid du Colombier 			else{
514671dfc47SDavid du Colombier 				re[i].prox = 0;
515671dfc47SDavid du Colombier 				re[i].ttl = gl32(p);
516671dfc47SDavid du Colombier 				goff(p, base, tmp, sizeof tmp);
517671dfc47SDavid du Colombier 				re[i].path = estrdup9p(tmp);
518671dfc47SDavid du Colombier 				gl16(p);	/* spurious 8.3 path */
519671dfc47SDavid du Colombier 				goff(p, base, tmp, sizeof tmp);
520671dfc47SDavid du Colombier 				re[i].addr = estrdup9p(tmp);
521671dfc47SDavid du Colombier 				gl16(p);	/* GUID (historic) */
522671dfc47SDavid du Colombier 			}
523671dfc47SDavid du Colombier 			break;
524671dfc47SDavid du Colombier 		default:
525671dfc47SDavid du Colombier 			/*
526671dfc47SDavid du Colombier 			 * this should never happen as we specify our maximum
527671dfc47SDavid du Colombier 			 * understood level in the request (above)
528671dfc47SDavid du Colombier 			 */
529671dfc47SDavid du Colombier 			fprint(2, "%d - unsupported DFS infolevel\n", vers);
530671dfc47SDavid du Colombier 			re[i].path = estrdup9p(tmp);
531671dfc47SDavid du Colombier 			re[i].addr = estrdup9p(tmp);
532671dfc47SDavid du Colombier 			break;
533671dfc47SDavid du Colombier 		}
534671dfc47SDavid du Colombier 		p->pos = base+len;
535671dfc47SDavid du Colombier 	}
536671dfc47SDavid du Colombier 
537671dfc47SDavid du Colombier 	free(p);
538671dfc47SDavid du Colombier 	return i;
539671dfc47SDavid du Colombier }
540