]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cifs/trans2.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / cmd / cifs / trans2.c
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <thread.h>
5 #include <9p.h>
6 #include "cifs.h"
7
8 static Pkt *
9 t2hdr(Session *s, Share *sp, int cmd)
10 {
11         Pkt *p;
12
13         p = cifshdr(s, sp, SMB_COM_TRANSACTION2);
14
15         p->tbase = pl16(p, 0);  /* 0  Total parameter bytes to be sent, filled later */
16         pl16(p, 0);             /* 2  Total data bytes to be sent, filled later */
17         pl16(p, 64);                    /* 4  Max parameter to return */
18         pl16(p, (MTU - T2HDRLEN)-64);   /* 6  Max data to return */
19         p8(p, 0);                       /* 8  Max setup count to return */
20         p8(p, 0);                       /* 9  Reserved */
21         pl16(p, 0);                     /* 10 Flags */
22         pl32(p, 1000);                  /* 12 Timeout (ms) */
23         pl16(p, 0);                     /* 16 Reserved */
24         pl16(p, 0);                     /* 18 Parameter count, filled later */
25         pl16(p, 0);                     /* 20 Parameter offset, filled later */
26         pl16(p, 0);                     /* 22 Data count, filled later */
27         pl16(p, 0);                     /* 24 Data offset, filled later */
28         p8(p, 1);                       /* 26 Setup count (in words) */
29         p8(p, 0);                       /* 27 Reserved */
30         pl16(p, cmd);                   /* setup[0] */
31         pbytes(p);
32         p8(p, 0);                       /* padding ??!?!? */
33
34         return p;
35 }
36
37 static void
38 pt2param(Pkt *p)
39 {
40         uchar *pos = p->pos;
41
42         assert(p->tbase != 0);
43         p->pos = p->tbase + 20;
44         pl16(p, (pos - p->buf) - NBHDRLEN); /* param offset */
45
46         p->tparam = p->pos = pos;
47 }
48
49 static void
50 pt2data(Pkt *p)
51 {
52         uchar *pos = p->pos;
53
54         assert(p->tbase != 0);
55         assert(p->tparam != 0);
56
57         p->pos = p->tbase +0;
58         pl16(p, pos - p->tparam);               /* total param count */
59
60         p->pos = p->tbase +18;
61         pl16(p, pos - p->tparam);               /* param count */
62
63         p->pos = p->tbase +24;
64         pl16(p, (pos - p->buf) - NBHDRLEN);     /* data offset */
65
66         p->tdata = p->pos = pos;
67 }
68
69 static int
70 t2rpc(Pkt *p)
71 {
72         int got;
73         uchar *pos;
74
75         assert(p->tbase != 0);
76         assert(p->tdata != 0);
77
78         pos = p->pos;
79
80         p->pos = p->tbase +2;
81         pl16(p, pos - p->tdata);                /* total data count */
82
83         p->pos = p->tbase +22;
84         pl16(p, pos - p->tdata);                /* data count */
85
86         p->pos = pos;
87         if((got = cifsrpc(p)) == -1)
88                 return -1;
89
90         gl16(p);                        /* Total parameter count */
91         gl16(p);                        /* Total data count */
92         gl16(p);                        /* Reserved */
93         gl16(p);                        /* Parameter count in this buffer */
94         p->tparam = p->buf +NBHDRLEN +gl16(p); /* Parameter offset */
95         gl16(p);                        /* Parameter displacement */
96         gl16(p);                        /* Data count (this buffer); */
97         p->tdata = p->buf +NBHDRLEN +gl16(p); /* Data offset */
98         gl16(p);                        /* Data displacement */
99         g8(p);                          /* Setup count */
100         g8(p);                          /* Reserved */
101
102         return got;
103 }
104
105 static void
106 gt2param(Pkt *p)
107 {
108         p->pos = p->tparam;
109 }
110
111 static void
112 gt2data(Pkt *p)
113 {
114         p->pos = p->tdata;
115 }
116
117
118 int
119 T2findfirst(Session *s, Share *sp, int slots, char *path, int *got,
120         long *resume, FInfo *fip)
121 {
122         int pktlen, i, n, sh;
123         uchar *next;
124         Pkt *p;
125
126         p = t2hdr(s, sp, TRANS2_FIND_FIRST2);
127         p8(p, 'D');                     /* OS/2 */
128         p8(p, ' ');                     /* OS/2 */
129
130         pt2param(p);
131         pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* Search attributes */
132         pl16(p, slots);                 /* Search count */
133         pl16(p, CIFS_SEARCH_RETURN_RESUME); /* Flags */
134         pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
135         pl32(p, 0);                     /* SearchStorage type (?) */
136         ppath(p, path);                 /* path */
137
138         pt2data(p);
139         if((pktlen = t2rpc(p)) == -1){
140                 free(p);
141                 return -1;
142         }
143
144         s->lastfind = nsec();
145         gt2param(p);
146
147         sh = gl16(p);                   /* Sid (search handle) */
148         *got = gl16(p);                 /* number of slots received */
149         gl16(p);                        /* End of search flag */
150         gl16(p);                        /* Offset into EA list if EA error */
151         gl16(p);                        /* Offset into data to file name of last entry */
152
153         gt2data(p);
154         memset(fip, 0, slots * sizeof(FInfo));
155         for(i = 0; i < *got; i++){
156                 next = p->pos;
157                 next += gl32(p);        /* offset to next entry */
158                 /*
159                  * bug in Windows - somtimes it lies about how many
160                  * directory entries it has put in the packet
161                  */
162                 if(next - p->buf > pktlen){
163                         *got = i;
164                         break;
165                 }
166
167                 *resume = gl32(p);              /* resume key for search */
168                 fip[i].created = gvtime(p);     /* creation time */
169                 fip[i].accessed = gvtime(p);    /* last access time */
170                 fip[i].written = gvtime(p);     /* last written time */
171                 fip[i].changed = gvtime(p);     /* change time */
172                 fip[i].size = gl64(p);          /* file size */
173                 gl64(p);                        /* bytes allocated */
174                 fip[i].attribs = gl32(p);       /* extended attributes */
175                 n = gl32(p);                    /* name length */
176                 gl32(p);                        /* EA size */
177                 gstr(p, fip[i].name, n);        /* name */
178                 p->pos = next;
179         }
180
181         free(p);
182         return sh;
183
184 }
185
186 int
187 T2findnext(Session *s, Share *sp, int slots, char *path, int *got,
188         long *resume, FInfo *fip, int sh)
189 {
190         Pkt *p;
191         int i, n;
192         uchar *next;
193
194         /*
195          * So I believe from comp.protocols.smb if you send
196          * TRANS2_FIND_NEXT2 requests too quickly to windows 95, it can
197          * get confused and fail to reply, so we slow up a bit in these
198          * circumstances.
199          */
200         if(!(s->caps & CAP_NT_SMBS) && nsec() - s->lastfind < 200000000LL)
201                 sleep(200);
202
203         p = t2hdr(s, sp, TRANS2_FIND_NEXT2);
204         p8(p, 'D');                     /* OS/2 */
205         p8(p, ' ');                     /* OS/2 */
206
207         pt2param(p);
208         pl16(p, sh);                            /* search handle */
209         pl16(p, slots);                         /* Search count */
210         pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
211         pl32(p, *resume);                       /* resume key */
212         pl16(p, CIFS_SEARCH_CONTINUE_FROM_LAST); /* Flags */
213         ppath(p, path);                         /* file+path to resume */
214
215         pt2data(p);
216         if(t2rpc(p) == -1){
217                 free(p);
218                 return -1;
219         }
220
221         s->lastfind = nsec();
222
223         gt2param(p);
224         *got = gl16(p);         /* number of slots received */
225         gl16(p);                /* End of search flag */
226         gl16(p);                /* Offset into EA list if EA error */
227         gl16(p);                /* Offset into data to file name of last entry */
228
229         gt2data(p);
230         memset(fip, 0, slots * sizeof(FInfo));
231         for(i = 0; i < *got; i++){
232                 next = p->pos;
233                 next += gl32(p);                /* offset to next entry */
234                 *resume = gl32(p);              /* resume key for search */
235                 fip[i].created = gvtime(p);     /* creation time */
236                 fip[i].accessed = gvtime(p);    /* last access time */
237                 fip[i].written = gvtime(p);     /* last written time */
238                 fip[i].changed = gvtime(p);     /* change time */
239                 fip[i].size = gl64(p);          /* file size */
240                 gl64(p);                        /* bytes allocated */
241                 fip[i].attribs = gl32(p);       /* extended attributes */
242                 n = gl32(p);                    /* name length */
243                 gl32(p);                        /* EA size */
244                 gstr(p, fip[i].name, n);        /* name */
245                 p->pos = next;
246         }
247         free(p);
248         return 0;
249 }
250
251
252 /* supported by 2k/XP/NT4 */
253 int
254 T2queryall(Session *s, Share *sp, char *path, FInfo *fip)
255 {
256         int n;
257         Pkt *p;
258
259         p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
260         pt2param(p);
261         pl16(p, SMB_QUERY_FILE_ALL_INFO); /* Information level   */
262         pl32(p, 0);                     /* reserved */
263         ppath(p, path);                 /* path */
264
265         pt2data(p);
266         if(t2rpc(p) == -1){
267                 free(p);
268                 return -1;
269         }
270         gt2data(p);
271
272         /*
273          * The layout of this struct is wrong in the SINA
274          * document, this layout gained by inspection.
275          */
276         memset(fip, 0, sizeof(FInfo));
277         fip->created = gvtime(p);       /* creation time */
278         fip->accessed = gvtime(p);      /* last access time */
279         fip->written = gvtime(p);       /* last written time */
280         fip->changed = gvtime(p);       /* change time */
281         fip->attribs = gl32(p);         /* attributes */
282         gl32(p);                        /* reserved */
283         gl64(p);                        /* bytes allocated */
284         fip->size = gl64(p);            /* file size */
285         gl32(p);                        /* number of hard links */
286         g8(p);                          /* delete pending */
287         g8(p);                          /* is a directory */
288         gl16(p);                        /* reserved */
289         gl32(p);                        /* EA size */
290
291         n = gl32(p);
292         if(n >= sizeof fip->name)
293                 n = sizeof fip->name - 1;
294         gstr(p, fip->name, n);
295
296         free(p);
297         return 0;
298 }
299
300 /* supported by 95/98/ME */
301 int
302 T2querystandard(Session *s, Share *sp, char *path, FInfo *fip)
303 {
304         Pkt *p;
305
306         p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
307         pt2param(p);
308         pl16(p, SMB_INFO_STANDARD);     /* Information level */
309         pl32(p, 0);                     /* reserved */
310         ppath(p, path);                 /* path */
311
312         pt2data(p);
313         if(t2rpc(p) == -1){
314                 free(p);
315                 return -1;
316         }
317         gt2data(p);
318         memset(fip, 0, sizeof(FInfo));
319         fip->created = gdatetime(p);    /* creation time */
320         fip->accessed = gdatetime(p);   /* last access time */
321         fip->written = gdatetime(p);    /* last written time */
322         fip->changed = fip->written;    /* change time */
323         fip->size = gl32(p);            /* file size */
324         gl32(p);                        /* bytes allocated */
325         fip->attribs = gl16(p);         /* attributes */
326         gl32(p);                        /* EA size */
327
328         free(p);
329         return 0;
330 }
331
332 int
333 T2setpathinfo(Session *s, Share *sp, char *path, FInfo *fip)
334 {
335         int rc;
336         Pkt *p;
337
338         p = t2hdr(s, sp, TRANS2_SET_PATH_INFORMATION);
339         pt2param(p);
340         pl16(p, SMB_INFO_STANDARD);     /* Information level */
341         pl32(p, 0);                     /* reserved */
342         ppath(p, path);                 /* path */
343
344         pt2data(p);
345         pdatetime(p, fip->created);     /* created */
346         pdatetime(p, fip->accessed);    /* accessed */
347         pdatetime(p, fip->written);     /* written */
348         pl32(p, fip->size);             /* size */
349         pl32(p, 0);                     /* allocated */
350         pl16(p, fip->attribs);          /* attributes */
351         pl32(p, 0);                     /* EA size */
352         pl16(p, 0);                     /* reserved */
353
354         rc = t2rpc(p);
355         free(p);
356         return rc;
357
358 }
359
360 int
361 T2setfilelength(Session *s, Share *sp, int fh, FInfo *fip) /* FIXME: maybe broken, needs testing */
362 {
363         int rc;
364         Pkt *p;
365
366         p = t2hdr(s, sp, TRANS2_SET_FILE_INFORMATION);
367         pt2param(p);
368         pl16(p, fh);                    /* file handle */
369         pl16(p, SMB_SET_FILE_END_OF_FILE_INFO); /* Information level */
370         pl16(p, 0);                     /* reserved */
371
372         pt2data(p);
373         pl64(p, fip->size);
374         pl32(p, 0);                     /* padding ?! */
375         pl16(p, 0);
376
377         rc = t2rpc(p);
378         free(p);
379         return rc;
380 }
381
382
383 int
384 T2fsvolumeinfo(Session *s, Share *sp, long *created, long *serialno,
385         char *label, int labellen)
386 {
387         Pkt *p;
388         long ct, sn, n;
389
390         p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
391         pt2param(p);
392         pl16(p, SMB_QUERY_FS_VOLUME_INFO);      /* Information level */
393
394         pt2data(p);
395
396         if(t2rpc(p) == -1){
397                 free(p);
398                 return -1;
399         }
400
401         gt2data(p);
402         ct = gvtime(p);                 /* creation time */
403         sn = gl32(p);                   /* serial number */
404         n = gl32(p);                    /* label name length */
405         g8(p);                          /* reserved */
406         g8(p);                          /* reserved */
407
408         memset(label, 0, labellen);
409         if(n < labellen && n > 0)
410                 gstr(p, label, n);      /* file system label */
411         if(created)
412                 *created = ct;
413         if(serialno)
414                 *serialno = sn;
415
416         free(p);
417         return 0;
418 }
419
420 int
421 T2fssizeinfo(Session *s, Share *sp, uvlong *total, uvlong *unused)
422 {
423         Pkt *p;
424         uvlong t, f, n, b;
425
426         p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
427         pt2param(p);
428         pl16(p, SMB_QUERY_FS_SIZE_INFO);        /* Information level */
429
430         pt2data(p);
431
432         if(t2rpc(p) == -1){
433                 free(p);
434                 return -1;
435         }
436
437         gt2data(p);
438         t = gl64(p);            /* total blocks */
439         f = gl64(p);            /* free blocks */
440         n = gl32(p);            /* sectors per block */
441         b = gl32(p);            /* bytes per sector */
442
443         if(free)
444                 *unused = f * n * b;
445         if(total)
446                 *total = t * n * b;
447
448         free(p);
449         return 0;
450 }
451
452 int
453 T2getdfsreferral(Session *s, Share *sp, char *path, int *gflags, int *used,
454         Refer *re, int nent)
455 {
456         int i, vers, nret, len;
457         char tmp[1024];
458         uchar *base;
459         Pkt *p;
460
461         p = t2hdr(s, sp, TRANS2_GET_DFS_REFERRAL);
462         pt2param(p);
463         pl16(p, 3); /* max info level we understand, must be >= 3 for domain requests */
464         ppath(p, path);
465
466         pt2data(p);
467
468         if(t2rpc(p) == -1){
469                 free(p);
470                 return -1;
471         }
472
473         memset(re, 0, sizeof *re * nent);
474         gt2data(p);
475
476         *used = gl16(p) / 2;    /* length used (/2 as Windows counts in runes) */
477         nret = gl16(p);         /* number of referrals returned */
478         *gflags = gl32(p);      /* global flags */
479
480         for(i = 0; i < nret && i < nent && i < 16; i++){
481                 base = p->pos;
482                 vers = gl16(p);         /* version of records */
483                 len = gl16(p);          /* length of records */
484                 re[i].type = gl16(p);   /* server type */
485                 re[i].flags = gl16(p);  /* referal flags */
486                 switch(vers){
487                 case 1:
488                         re[i].prox = 0; /* nearby */
489                         re[i].ttl = 5*60;       /* 5 mins */
490                         gstr(p, tmp, sizeof tmp);
491                         re[i].addr = estrdup9p(tmp);
492                         re[i].path = estrdup9p(tmp);
493                         break;
494                 case 2:
495                         re[i].prox = gl32(p);   /* not implemented in v2 */
496                         re[i].ttl = gl32(p);
497                         goff(p, base, re[i].path, sizeof tmp);
498                         re[i].path = estrdup9p(tmp);
499                         goff(p, base, re[i].path, sizeof tmp);/* spurious 8.3 path */
500                         goff(p, base, tmp, sizeof tmp);
501                         re[i].addr = estrdup9p(tmp);
502                         break;
503                 case 3:
504                         if(re[i].flags & DFS_REFERAL_LIST){
505                                 re[i].prox = 0;
506                                 re[i].ttl = gl32(p);
507                                 goff(p, base, tmp, sizeof tmp);
508                                 re[i].path = estrdup9p(tmp);
509                                 gl16(p);
510                                 goff(p, base, tmp, sizeof tmp);
511                                 re[i].addr = estrdup9p(tmp);
512                         }
513                         else{
514                                 re[i].prox = 0;
515                                 re[i].ttl = gl32(p);
516                                 goff(p, base, tmp, sizeof tmp);
517                                 re[i].path = estrdup9p(tmp);
518                                 gl16(p);        /* spurious 8.3 path */
519                                 goff(p, base, tmp, sizeof tmp);
520                                 re[i].addr = estrdup9p(tmp);
521                                 gl16(p);        /* GUID (historic) */
522                         }
523                         break;
524                 default:
525                         /*
526                          * this should never happen as we specify our maximum
527                          * understood level in the request (above)
528                          */
529                         fprint(2, "%d - unsupported DFS infolevel\n", vers);
530                         re[i].path = estrdup9p(tmp);
531                         re[i].addr = estrdup9p(tmp);
532                         break;
533                 }
534                 p->pos = base+len;
535         }
536
537         free(p);
538         return i;
539 }