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);
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;
/*
* 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;
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].ttl = 300; /* 30 mins */
gstr(p, tmp, sizeof tmp);
re[i].addr = estrdup9p(tmp);
re[i].path = estrdup9p(tmp);
break;
case 2:
re[i].ttl = gl32(p);
if(re[i].ttl == 0)
re[i].ttl = 1800;
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){ /* normal referal */
re[i].ttl = gl32(p);
if(re[i].ttl == 0)
re[i].ttl = 1800;
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{ /* domain root */
re[i].ttl = gl32(p);
if(re[i].ttl == 0)
re[i].ttl = 300;
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);
/* GUID (historic) here, skipped below as we know the record length */
}
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;
}