int smb_rq_simple(struct smb_rq *rqp) { struct smbioc_rq krq; struct mbdata *mbp; char *data; mbp = smb_rq_getrequest(rqp); m_lineup(mbp->mb_top, &mbp->mb_top); data = mtod(mbp->mb_top, char*); bzero(&krq, sizeof(krq)); krq.ioc_cmd = rqp->rq_cmd; krq.ioc_twc = rqp->rq_wcount; krq.ioc_twords = data; krq.ioc_tbc = mbp->mb_count; krq.ioc_tbytes = data + rqp->rq_wcount * 2; mbp = smb_rq_getreply(rqp); krq.ioc_rpbufsz = mbp->mb_top->m_maxlen; krq.ioc_rpbuf = mtod(mbp->mb_top, char *); if (ioctl(rqp->rq_ctx->ct_fd, SMBIOC_REQUEST, &krq) == -1) return errno; mbp->mb_top->m_len = krq.ioc_rwc * 2 + krq.ioc_rbc; rqp->rq_wcount = krq.ioc_rwc; rqp->rq_bcount = krq.ioc_rbc; return 0; }
int smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, struct smb_cred *scred) { struct smb_rq rq, *rqp = &rq; struct mdchain *mdp; u_int16_t units, bpu, bsize, funits; int error; error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred); if (error) return error; smb_rq_wstart(rqp); smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) { smb_rq_done(rqp); return error; } smb_rq_getreply(rqp, &mdp); md_get_uint16le(mdp, &units); md_get_uint16le(mdp, &bpu); md_get_uint16le(mdp, &bsize); md_get_uint16le(mdp, &funits); sbp->f_bsize = bpu * bsize; /* fundamental file system block size */ sbp->f_blocks= units; /* total data blocks in file system */ sbp->f_bfree = funits; /* free blocks in fs */ sbp->f_bavail= funits; /* free blocks avail to non-superuser */ sbp->f_files = 0xffff; /* total file nodes in file system */ sbp->f_ffree = 0xffff; /* free file nodes in fs */ smb_rq_done(rqp); return 0; }
int smb_smb_open_print_file(struct smb_ctx *ctx, int setuplen, int mode, const char *ident, smbfh *fhp) { struct smb_rq *rqp; struct mbdata *mbp; int error; error = smb_rq_init(ctx, SMB_COM_OPEN_PRINT_FILE, 2, &rqp); if (error) return error; mbp = smb_rq_getrequest(rqp); mb_put_uint16le(mbp, setuplen); mb_put_uint16le(mbp, mode); smb_rq_wend(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); smb_rq_dstring(mbp, ident); error = smb_rq_simple(rqp); if (!error) { mbp = smb_rq_getreply(rqp); mb_get_uint16(mbp, fhp); } smb_rq_done(rqp); return error; }
static int smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; int error; uint32_t off32; uint16_t cnt, rcnt, todo; uint8_t wc; ASSERT(uiop->uio_loffset <= UINT32_MAX); off32 = (uint32_t)uiop->uio_loffset; ASSERT(*lenp <= UINT16_MAX); cnt = (uint16_t)*lenp; /* This next is an "estimate" of planned writes. */ todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); if (error) return (error); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint16le(mbp, fid); mb_put_uint16le(mbp, cnt); mb_put_uint32le(mbp, off32); mb_put_uint16le(mbp, todo); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, cnt); error = mb_put_uio(mbp, uiop, *lenp); if (error) goto out; smb_rq_bend(rqp); if (timo == 0) timo = smb_timo_write; error = smb_rq_simple_timed(rqp, timo); if (error) goto out; smb_rq_getreply(rqp, &mdp); error = md_get_uint8(mdp, &wc); if (error) goto out; if (wc != 1) { error = EBADRPC; goto out; } error = md_get_uint16le(mdp, &rcnt); if (error) goto out; *lenp = rcnt; out: smb_rq_done(rqp); return (error); }
static inline int smb_smb_read(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int16_t resid, bc; u_int8_t wc; int error, rlen, blksz; /* Cannot read at/beyond 4G */ if (uio->uio_offset >= (1LL << 32)) return (EFBIG); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); if (error) return error; blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; rlen = *len = min(blksz, *len); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint16le(mbp, rlen); mb_put_uint32le(mbp, uio->uio_offset); mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); do { error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 5) { error = EBADRPC; break; } md_get_uint16le(mdp, &resid); md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); md_get_uint16le(mdp, &bc); md_get_uint8(mdp, NULL); /* ignore buffer type */ md_get_uint16le(mdp, &resid); if (resid == 0) { *rresid = resid; break; } error = md_get_uio(mdp, uio, resid); if (error) break; *rresid = resid; } while(0); smb_rq_done(rqp); return error; }
static inline int smb_smb_writex(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; int error; u_int8_t wc; u_int16_t resid; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); if (error) return (error); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* no secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); /* offset to secondary */ mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint32le(mbp, uio->uio_offset); mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ mb_put_uint16le(mbp, 0); /* !write-thru */ mb_put_uint16le(mbp, 0); *len = min(SSTOVC(ssp)->vc_wxmax, *len); mb_put_uint16le(mbp, *len >> 16); mb_put_uint16le(mbp, *len); mb_put_uint16le(mbp, 64); /* data offset from header start */ mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ smb_rq_wend(rqp); smb_rq_bstart(rqp); do { mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */ error = mb_put_uio(mbp, uio, *len); if (error) break; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 6) { error = EBADRPC; break; } md_get_uint8(mdp, NULL); md_get_uint8(mdp, NULL); md_get_uint16(mdp, NULL); md_get_uint16le(mdp, &resid); *rresid = resid; } while(0); smb_rq_done(rqp); return (error); }
int smbfs_smb_query_info(struct smbnode *np, const char *name, int len, struct smbfattr *fap, struct smb_cred *scred) { struct smb_rq *rqp; struct smb_share *ssp = np->n_mount->sm_share; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc; int error; u_int16_t wattr; u_int32_t lint; rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK); error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred); if (error) { free(rqp, M_SMBFSDATA); return error; } smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); do { error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len); if (error) break; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { error = EBADRPC; break; } md_get_uint16le(mdp, &wattr); fap->fa_attr = wattr; /* * Be careful using the time returned here, as * with FAT on NT4SP6, at least, the time returned is low * 32 bits of 100s of nanoseconds (since 1601) so it rolls * over about every seven minutes! */ md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */ if (lint) /* avoid bogus zero returns */ smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime); md_get_uint32le(mdp, &lint); fap->fa_size = lint; } while(0); smb_rq_done(rqp); free(rqp, M_SMBFSDATA); return error; }
static inline int smb_smb_write(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int16_t resid; u_int8_t wc; int error, blksz; /* Cannot write at/beyond 4G */ if (uio->uio_offset >= (1LL << 32)) return (EFBIG); blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; if (blksz > 0xffff) blksz = 0xffff; resid = *len = min(blksz, *len); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint16le(mbp, resid); mb_put_uint32le(mbp, uio->uio_offset); mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, resid); do { error = mb_put_uio(mbp, uio, resid); if (error) break; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 1) { error = EBADRPC; break; } md_get_uint16le(mdp, &resid); *rresid = resid; } while(0); smb_rq_done(rqp); return error; }
int smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) { struct smb_rq *rqp; struct smb_share *ssp = np->n_mount->sm_share; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc; u_int16_t fid, wattr, grantedmode; int error; rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK); error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred); if (error) { free(rqp, M_SMBFSDATA); return error; } smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint16le(mbp, accmode); mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); do { error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); if (error) break; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { error = EBADRPC; break; } md_get_uint16(mdp, &fid); md_get_uint16le(mdp, &wattr); md_get_uint32(mdp, NULL); /* mtime */ md_get_uint32(mdp, NULL); /* fsize */ md_get_uint16le(mdp, &grantedmode); /* * TODO: refresh attributes from this reply */ } while(0); smb_rq_done(rqp); free(rqp, M_SMBFSDATA); if (error) return error; np->n_fid = fid; np->n_rwstate = grantedmode; return 0; }
static __inline int smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int16_t resid; u_int8_t wc; int error, blksz; /* write data must be real */ KKASSERT(uio->uio_segflg != UIO_NOCOPY); blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; if (blksz > 0xffff) blksz = 0xffff; resid = *len = min(blksz, *len); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint16le(mbp, resid); mb_put_uint32le(mbp, uio->uio_offset); mb_put_uint16le(mbp, (unsigned short)szmin(uio->uio_resid, 0xffff)); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, resid); do { error = mb_put_uio(mbp, uio, resid); if (error) break; smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 1) { error = EBADRPC; break; } md_get_uint16le(mdp, &resid); *rresid = resid; } while(0); smb_rq_done(rqp); return error; }
int smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, struct smb_cred *scred) { struct smb_rq *rqp; struct smb_share *ssp = dnp->n_mount->sm_share; struct mbchain *mbp; struct mdchain *mdp; struct timespec ctime; u_int8_t wc; u_int16_t fid; u_long tm; int error; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_NEW, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); /* get current time */ getnanotime(&ctime); smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); smb_rq_wstart(rqp); mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ mb_put_uint32le(mbp, tm); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); if (!error) { smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (!error) { smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc == 1) md_get_uint16(mdp, &fid); else error = EBADRPC; } } smb_rq_done(rqp); if (!error) smbfs_smb_close(ssp, fid, &ctime, scred); return (error); }
static int smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) { struct mdchain *mbp; struct smb_rq *rqp; char *cp; u_int8_t battr; u_int16_t xdate, xtime; u_int32_t size; int error; if (ctx->f_ecnt == 0) { if (ctx->f_flags & SMBFS_RDD_EOF) return ENOENT; ctx->f_left = ctx->f_limit = limit; error = smbfs_smb_search(ctx); if (error) return error; } rqp = ctx->f_rq; smb_rq_getreply(rqp, &mbp); md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); md_get_uint8(mbp, &battr); md_get_uint16le(mbp, &xtime); md_get_uint16le(mbp, &xdate); md_get_uint32le(mbp, &size); KASSERT(ctx->f_name == ctx->f_fname); cp = ctx->f_name; md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); cp[sizeof(ctx->f_fname) - 1] = '\0'; cp += strlen(cp) - 1; while(*cp == ' ' && cp > ctx->f_name) *cp-- = '\0'; ctx->f_attr.fa_attr = battr; smb_dos2unixtime(xdate, xtime, 0, rqp->sr_vc->vc_sopt.sv_tz, &ctx->f_attr.fa_mtime); ctx->f_attr.fa_size = size; ctx->f_nmlen = strlen(ctx->f_name); ctx->f_ecnt--; ctx->f_left--; return 0; }
static int smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; int error; uint32_t offlo, offhi, rlen; uint16_t lenhi, lenlo, off, doff; uint8_t wc; lenhi = (uint16_t)(*lenp >> 16); lenlo = (uint16_t)*lenp; offhi = (uint32_t)(uiop->uio_loffset >> 32); offlo = (uint32_t)uiop->uio_loffset; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); if (error) return (error); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* no secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); /* offset to secondary */ mb_put_uint16le(mbp, fid); mb_put_uint32le(mbp, offlo); /* offset (low part) */ mb_put_uint16le(mbp, lenlo); /* MaxCount */ mb_put_uint16le(mbp, 1); /* MinCount */ /* (only indicates blocking) */ mb_put_uint32le(mbp, lenhi); /* MaxCountHigh */ mb_put_uint16le(mbp, lenlo); /* Remaining ("obsolete") */ mb_put_uint32le(mbp, offhi); /* offset (high part) */ smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); if (timo == 0) timo = smb_timo_read; error = smb_rq_simple_timed(rqp, timo); if (error) goto out; smb_rq_getreply(rqp, &mdp); error = md_get_uint8(mdp, &wc); if (error) goto out; if (wc != 12) { error = EBADRPC; goto out; } md_get_uint8(mdp, NULL); md_get_uint8(mdp, NULL); md_get_uint16le(mdp, NULL); md_get_uint16le(mdp, NULL); md_get_uint16le(mdp, NULL); /* data compaction mode */ md_get_uint16le(mdp, NULL); md_get_uint16le(mdp, &lenlo); /* data len ret. */ md_get_uint16le(mdp, &doff); /* data offset */ md_get_uint16le(mdp, &lenhi); rlen = (lenhi << 16) | lenlo; md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); error = md_get_uint16le(mdp, NULL); /* ByteCount */ if (error) goto out; /* * Does the data offset indicate padding? * The current offset is a constant, found * by counting the md_get_ calls above. */ off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */ if (doff > off) /* pad byte(s)? */ md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); if (rlen == 0) { *lenp = rlen; goto out; } /* paranoid */ if (rlen > *lenp) { SMBSDEBUG("bad server! rlen %d, len %d\n", rlen, *lenp); rlen = *lenp; } error = md_get_uio(mdp, uiop, rlen); if (error) goto out; /* Success */ *lenp = rlen; out: smb_rq_done(rqp); return (error); }
static int smbfs_smb_search(struct smbfs_fctx *ctx) { struct smb_vc *vcp = SSTOVC(ctx->f_ssp); struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc, bt; u_int16_t ec, dlen, bc; int maxent, error, iseof = 0; maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); if (ctx->f_rq) { smb_rq_done(ctx->f_rq); ctx->f_rq = NULL; } error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); if (error) return error; ctx->f_rq = rqp; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint16le(mbp, maxent); /* max entries to return */ mb_put_uint16le(mbp, ctx->f_attrmask); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); if (error) return error; mb_put_uint8(mbp, SMB_DT_VARIABLE); mb_put_uint16le(mbp, 0); /* context length */ ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; } else { if (SMB_UNICODE_STRINGS(vcp)) { mb_put_padbyte(mbp); mb_put_uint8(mbp, 0); } mb_put_uint8(mbp, 0); /* file name length */ mb_put_uint8(mbp, SMB_DT_VARIABLE); mb_put_uint16le(mbp, SMB_SKEYLEN); mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); } smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) { if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { error = 0; iseof = 1; ctx->f_flags |= SMBFS_RDD_EOF; } else return error; } smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 1) return iseof ? ENOENT : EBADRPC; md_get_uint16le(mdp, &ec); if (ec == 0) return ENOENT; ctx->f_ecnt = ec; md_get_uint16le(mdp, &bc); if (bc < 3) return EBADRPC; bc -= 3; md_get_uint8(mdp, &bt); if (bt != SMB_DT_VARIABLE) return EBADRPC; md_get_uint16le(mdp, &dlen); if (dlen != bc || dlen % SMB_DENTRYLEN != 0) return EBADRPC; return 0; }
int smbfs_smb_statvfs(struct smb_share *ssp, struct statvfs *sbp, struct smb_cred *scred) { unsigned long bsize; /* Block (allocation unit) size */ unsigned long bavail, bfree; /* * The SMB request work with notion of sector size and * allocation units. Allocation unit is what 'block' * means in Unix context, sector size might be HW sector size. */ if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) { struct smb_t2rq *t2p; struct mbchain *mbp; struct mdchain *mdp; u_int16_t secsz; u_int32_t units, bpu, funits; int error; error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, scred, &t2p); if (error) return error; mbp = &t2p->t2_tparam; mb_init(mbp); mb_put_uint16le(mbp, SMB_INFO_ALLOCATION); t2p->t2_maxpcount = 4; t2p->t2_maxdcount = 4 * 4 + 2; error = smb_t2_request(t2p); if (error) { smb_t2_done(t2p); return error; } mdp = &t2p->t2_rdata; md_get_uint32(mdp, NULL); /* fs id */ md_get_uint32le(mdp, &bpu); /* Number of sectors per unit */ md_get_uint32le(mdp, &units); /* Total number of units */ md_get_uint32le(mdp, &funits); /* Number of available units */ md_get_uint16le(mdp, &secsz); /* Number of bytes per sector */ smb_t2_done(t2p); bsize = bpu * secsz; bavail = units; bfree = funits; } else { struct smb_rq *rqp; struct mdchain *mdp; u_int16_t units, bpu, secsz, funits; int error; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred, &rqp); if (error) return error; smb_rq_wstart(rqp); smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) { smb_rq_done(rqp); return error; } smb_rq_getreply(rqp, &mdp); md_get_uint16le(mdp, &units); /* Total units per server */ md_get_uint16le(mdp, &bpu); /* Blocks per allocation unit */ md_get_uint16le(mdp, &secsz); /* Block size (in bytes) */ md_get_uint16le(mdp, &funits); /* Number of free units */ smb_rq_done(rqp); bsize = bpu * secsz; bavail = units; bfree = funits; } sbp->f_bsize = bsize; /* fundamental file system block size */ sbp->f_frsize = bsize; /* fundamental file system frag size */ sbp->f_iosize = bsize; /* optimal I/O size */ sbp->f_blocks = bavail; /* total data blocks in file system */ sbp->f_bfree = bfree; /* free blocks in fs */ sbp->f_bresvd = 0; /* reserved blocks in fs */ sbp->f_bavail= bfree; /* free blocks avail to non-superuser */ sbp->f_files = 0xffff; /* total file nodes in file system */ sbp->f_ffree = 0xffff; /* free file nodes to non-superuser */ sbp->f_favail = 0xffff; /* free file nodes in fs */ sbp->f_fresvd = 0; /* reserved file nodes in fs */ return 0; }
static inline int smb_smb_readx(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc; int error; u_int16_t residhi, residlo, off, doff; u_int32_t resid; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* no secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); /* offset to secondary */ mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); mb_put_uint32le(mbp, uio->uio_offset); *len = min(SSTOVC(ssp)->vc_rxmax, *len); mb_put_uint16le(mbp, *len); /* MaxCount */ mb_put_uint16le(mbp, *len); /* MinCount (only indicates blocking) */ mb_put_uint32le(mbp, *len >> 16); /* MaxCountHigh */ mb_put_uint16le(mbp, *len); /* Remaining ("obsolete") */ mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); do { error = smb_rq_simple(rqp); if (error) break; smb_rq_getreply(rqp, &mdp); off = SMB_HDRLEN; md_get_uint8(mdp, &wc); off++; if (wc != 12) { error = EBADRPC; break; } md_get_uint8(mdp, NULL); off++; md_get_uint8(mdp, NULL); off++; md_get_uint16(mdp, NULL); off += 2; md_get_uint16(mdp, NULL); off += 2; md_get_uint16(mdp, NULL); /* data compaction mode */ off += 2; md_get_uint16(mdp, NULL); off += 2; md_get_uint16le(mdp, &residlo); off += 2; md_get_uint16le(mdp, &doff); /* data offset */ off += 2; md_get_uint16le(mdp, &residhi); off += 2; resid = (residhi << 16) | residlo; md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); off += 4*2; md_get_uint16(mdp, NULL); /* ByteCount */ off += 2; if (doff > off) /* pad byte(s)? */ md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); if (resid == 0) { *rresid = resid; break; } error = md_get_uio(mdp, uio, resid); if (error) break; *rresid = resid; } while(0); smb_rq_done(rqp); return (error); }
int smbfs_smb_nt_dirnotify_fetch(struct smb_rq *rqp, int *hint) { int error; struct mdchain *mdp; u_int8_t sc; u_int32_t nextentry; error = smb_rq_reply(rqp); if (error) { /* * If we get EMSGSIZE, there is already too many notifications * available for the directory, and the internal buffer * overflew. Just flag any possible relevant change. */ if (error == EMSGSIZE) { *hint = NOTE_ATTRIB | NOTE_WRITE; error = 0; } goto bad; } smb_rq_getreply(rqp, &mdp); /* Parse reply */ error = md_get_mem(mdp, NULL, 4 + (8*4), MB_MZERO); /* skip */ if (error) goto bad; md_get_uint8(mdp, &sc); /* SetupCount */ if (sc > 0) md_get_mem(mdp, NULL, sc * sizeof(u_int16_t), MB_MZERO); md_get_uint16(mdp, NULL); /* ByteCount */ md_get_mem(mdp, NULL, 1 + (sc % 2) * 2, MB_MZERO); /* Pad */ /* * The notify data are blocks of * ULONG nextentry - offset of next entry from start of this one * ULONG action - type of notification * ULONG filenamelen - length of filename in bytes * WCHAR filename[filenamelen/2] - Unicode filename * nexentry == 0 means last notification, filename is in 16bit LE * unicode */ *hint = 0; do { u_int32_t action; #if 0 u_int32_t fnlen; u_int16_t fnc; #endif md_get_uint32le(mdp, &nextentry); md_get_uint32le(mdp, &action); if (nextentry) md_get_mem(mdp, NULL, nextentry - 2 * 4, MB_MZERO); #if 0 md_get_uint32le(mdp, &fnlen); printf("notify: next %u act %u fnlen %u fname '", nextentry, action, fnlen); for(; fnlen > 0; fnlen -= 2) { md_get_uint16le(mdp, &fnc); printf("%c", fnc&0xff); } printf("'\n"); #endif switch(action) { case FILE_ACTION_ADDED: case FILE_ACTION_REMOVED: case FILE_ACTION_RENAMED_OLD_NAME: case FILE_ACTION_RENAMED_NEW_NAME: *hint |= NOTE_ATTRIB | NOTE_WRITE; break; case FILE_ACTION_MODIFIED: *hint |= NOTE_ATTRIB; break; } } while(nextentry > 0); bad: smb_rq_done(rqp); return error; }
static int smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; int error; uint32_t offlo, offhi, rlen; uint16_t lenhi, lenlo; uint8_t wc; lenhi = (uint16_t)(*lenp >> 16); lenlo = (uint16_t)*lenp; offhi = (uint32_t)(uiop->uio_loffset >> 32); offlo = (uint32_t)uiop->uio_loffset; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); if (error) return (error); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* no secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); /* offset to secondary */ mb_put_uint16le(mbp, fid); mb_put_uint32le(mbp, offlo); /* offset (low part) */ mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ mb_put_uint16le(mbp, 0); /* !write-thru */ mb_put_uint16le(mbp, 0); mb_put_uint16le(mbp, lenhi); mb_put_uint16le(mbp, lenlo); mb_put_uint16le(mbp, 64); /* data offset from header start */ mb_put_uint32le(mbp, offhi); /* offset (high part) */ smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, 0); /* pad byte */ error = mb_put_uio(mbp, uiop, *lenp); if (error) goto out; smb_rq_bend(rqp); if (timo == 0) timo = smb_timo_write; error = smb_rq_simple_timed(rqp, timo); if (error) goto out; smb_rq_getreply(rqp, &mdp); error = md_get_uint8(mdp, &wc); if (error) goto out; if (wc != 6) { error = EBADRPC; goto out; } md_get_uint8(mdp, NULL); /* andx cmd */ md_get_uint8(mdp, NULL); /* reserved */ md_get_uint16le(mdp, NULL); /* andx offset */ md_get_uint16le(mdp, &lenlo); /* data len ret. */ md_get_uint16le(mdp, NULL); /* remaining */ error = md_get_uint16le(mdp, &lenhi); if (error) goto out; /* Success */ rlen = (lenhi << 16) | lenlo; *lenp = rlen; out: smb_rq_done(rqp); return (error); }
static int smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo) { struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; int error; uint32_t off32; uint16_t bc, cnt, dlen, rcnt, todo; uint8_t wc; ASSERT(uiop->uio_loffset <= UINT32_MAX); off32 = (uint32_t)uiop->uio_loffset; ASSERT(*lenp <= UINT16_MAX); cnt = (uint16_t)*lenp; /* This next is an "estimate" of planned reads. */ todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); if (error) return (error); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint16le(mbp, fid); mb_put_uint16le(mbp, cnt); mb_put_uint32le(mbp, off32); mb_put_uint16le(mbp, todo); smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); if (timo == 0) timo = smb_timo_read; error = smb_rq_simple_timed(rqp, timo); if (error) goto out; smb_rq_getreply(rqp, &mdp); error = md_get_uint8(mdp, &wc); if (error) goto out; if (wc != 5) { error = EBADRPC; goto out; } md_get_uint16le(mdp, &rcnt); /* ret. count */ md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */ md_get_uint16le(mdp, &bc); /* byte count */ md_get_uint8(mdp, NULL); /* buffer format */ error = md_get_uint16le(mdp, &dlen); /* data len */ if (error) goto out; if (dlen < rcnt) { SMBSDEBUG("oops: dlen=%d rcnt=%d\n", (int)dlen, (int)rcnt); rcnt = dlen; } if (rcnt == 0) { *lenp = 0; goto out; } /* paranoid */ if (rcnt > cnt) { SMBSDEBUG("bad server! rcnt %d, cnt %d\n", (int)rcnt, (int)cnt); rcnt = cnt; } error = md_get_uio(mdp, uiop, (int)rcnt); if (error) goto out; /* success */ *lenp = (int)rcnt; out: smb_rq_done(rqp); return (error); }
int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) { struct smb_dialect *dp; struct smb_sopt *sp = NULL; struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; u_int8_t wc, stime[8], sblen; u_int16_t dindex, tw, tw1, swlen, bc; int error, maxqsz; if (smb_smb_nomux(vcp, scred, __func__) != 0) return EINVAL; vcp->vc_hflags = 0; vcp->vc_hflags2 = 0; vcp->obj.co_flags &= ~(SMBV_ENCRYPT); sp = &vcp->vc_sopt; bzero(sp, sizeof(struct smb_sopt)); error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); smb_rq_wend(rqp); smb_rq_bstart(rqp); for(dp = smb_dialects; dp->d_id != -1; dp++) { mb_put_uint8(mbp, SMB_DT_DIALECT); smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE); } smb_rq_bend(rqp); error = smb_rq_simple(rqp); SMBSDEBUG("%d\n", error); if (error) goto bad; smb_rq_getreply(rqp, &mdp); do { error = md_get_uint8(mdp, &wc); if (error) break; error = md_get_uint16le(mdp, &dindex); if (error) break; if (dindex > 7) { SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex); error = EBADRPC; break; } dp = smb_dialects + dindex; sp->sv_proto = dp->d_id; SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc); error = EBADRPC; if (dp->d_id >= SMB_DIALECT_NTLM0_12) { if (wc != 17) break; md_get_uint8(mdp, &sp->sv_sm); md_get_uint16le(mdp, &sp->sv_maxmux); md_get_uint16le(mdp, &sp->sv_maxvcs); md_get_uint32le(mdp, &sp->sv_maxtx); md_get_uint32le(mdp, &sp->sv_maxraw); md_get_uint32le(mdp, &sp->sv_skey); md_get_uint32le(mdp, &sp->sv_caps); md_get_mem(mdp, stime, 8, MB_MSYSTEM); md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); md_get_uint8(mdp, &sblen); if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) { if (sblen != SMB_MAXCHALLENGELEN) { SMBERROR("Unexpected length of security blob (%d)\n", sblen); break; } error = md_get_uint16(mdp, &bc); if (error) break; if (sp->sv_caps & SMB_CAP_EXT_SECURITY) md_get_mem(mdp, NULL, 16, MB_MSYSTEM); error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM); if (error) break; vcp->vc_chlen = sblen; vcp->obj.co_flags |= SMBV_ENCRYPT; } vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; if (dp->d_id == SMB_DIALECT_NTLM0_12 && sp->sv_maxtx < 4096 && (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) { vcp->obj.co_flags |= SMBV_WIN95; SMBSDEBUG("Win95 detected\n"); } } else if (dp->d_id > SMB_DIALECT_CORE) { md_get_uint16le(mdp, &tw); sp->sv_sm = tw; md_get_uint16le(mdp, &tw); sp->sv_maxtx = tw; md_get_uint16le(mdp, &sp->sv_maxmux); md_get_uint16le(mdp, &sp->sv_maxvcs); md_get_uint16le(mdp, &tw); /* rawmode */ md_get_uint32le(mdp, &sp->sv_skey); if (wc == 13) { /* >= LANMAN1 */ md_get_uint16(mdp, &tw); /* time */ md_get_uint16(mdp, &tw1); /* date */ md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); md_get_uint16le(mdp, &swlen); if (swlen > SMB_MAXCHALLENGELEN) break; md_get_uint16(mdp, NULL); /* mbz */ if (md_get_uint16(mdp, &bc) != 0) break; if (bc < swlen) break; if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) { error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM); if (error) break; vcp->vc_chlen = swlen; vcp->obj.co_flags |= SMBV_ENCRYPT; } } vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; } else { /* an old CORE protocol */ sp->sv_maxmux = 1; } error = 0; } while (0); if (error == 0) { vcp->vc_maxvcs = sp->sv_maxvcs; if (vcp->vc_maxvcs <= 1) { if (vcp->vc_maxvcs == 0) vcp->vc_maxvcs = 1; } if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff) sp->sv_maxtx = 1024; SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz); vcp->vc_txmax = min(sp->sv_maxtx, maxqsz); SMBSDEBUG("TZ = %d\n", sp->sv_tz); SMBSDEBUG("CAPS = %x\n", sp->sv_caps); SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux); SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs); SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw); SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx); } bad: smb_rq_done(rqp); return error; }
int smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) { struct smb_vc *vcp; struct smb_rq *rqp = NULL; struct mbchain *mbp; struct mdchain *mdp; char *pbuf, *unc_name = NULL; int error, tlen, plen, unc_len; uint16_t bcnt, options; uint8_t wc; vcp = SSTOVC(ssp); /* * Make this a "VC-level" request, so it will have * rqp->sr_share == NULL, and smb_iod_sendrq() * will send it with TID = SMB_TID_UNKNOWN * * This also serves to bypass the wait for * share state changes, which this call is * trying to carry out. */ error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); if (error) return (error); /* * Build the UNC name, i.e. "//server/share" * but with backslashes of course. * size math: three slashes, one null. */ unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name); unc_name = kmem_alloc(unc_len, KM_SLEEP); (void) snprintf(unc_name, unc_len, "\\\\%s\\%s", vcp->vc_srvname, ssp->ss_name); SMBSDEBUG("unc_name: \"%s\"", unc_name); /* * The password is now pre-computed in the * user-space helper process. */ plen = ssp->ss_pwlen; pbuf = ssp->ss_pass; /* * Build the request. */ mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); mb_put_uint8(mbp, 0); mb_put_uint16le(mbp, 0); mb_put_uint16le(mbp, 0); /* Flags */ mb_put_uint16le(mbp, plen); smb_rq_wend(rqp); smb_rq_bstart(rqp); /* Tree connect password, if any */ error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM); if (error) goto out; /* UNC resource name */ error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE); if (error) goto out; /* * Put the type string (always ASCII), * including the null. */ tlen = strlen(ssp->ss_type_req) + 1; error = mb_put_mem(mbp, ssp->ss_type_req, tlen, MB_MSYSTEM); if (error) goto out; smb_rq_bend(rqp); /* * Run the request. * * Using NOINTR_RECV because we don't want to risk * missing a successful tree connect response, * which would "leak" Tree IDs. */ rqp->sr_flags |= SMBR_NOINTR_RECV; error = smb_rq_simple(rqp); SMBSDEBUG("%d\n", error); if (error) { /* * If we get the server name wrong, i.e. due to * mis-configured name services, this will be * NT_STATUS_DUPLICATE_NAME. Log this error. */ SMBERROR("(%s) failed, status=0x%x", unc_name, rqp->sr_error); goto out; } /* * Parse the TCON response */ smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); if (wc != 3 && wc != 7) { error = EBADRPC; goto out; } md_get_uint16le(mdp, NULL); /* AndX cmd */ md_get_uint16le(mdp, NULL); /* AndX off */ md_get_uint16le(mdp, &options); /* option bits (DFS, search) */ if (wc == 7) { md_get_uint32le(mdp, NULL); /* MaximalShareAccessRights */ md_get_uint32le(mdp, NULL); /* GuestMaximalShareAcc... */ } error = md_get_uint16le(mdp, &bcnt); /* byte count */ if (error) goto out; /* * Get the returned share type string, * i.e. "IPC" or whatever. Don't care * if we get an error reading the type. */ tlen = sizeof (ssp->ss_type_ret); bzero(ssp->ss_type_ret, tlen--); if (tlen > bcnt) tlen = bcnt; md_get_mem(mdp, ssp->ss_type_ret, tlen, MB_MSYSTEM); /* Success! */ SMB_SS_LOCK(ssp); ssp->ss_tid = rqp->sr_rptid; ssp->ss_vcgenid = vcp->vc_genid; ssp->ss_options = options; ssp->ss_flags |= SMBS_CONNECTED; SMB_SS_UNLOCK(ssp); out: if (unc_name) kmem_free(unc_name, unc_len); smb_rq_done(rqp); return (error); }
/* * This call is used to fetch FID for directories. For normal files, * SMB_COM_OPEN is used. */ int smbfs_smb_ntcreatex(struct smbnode *np, int accmode, struct smb_cred *scred) { struct smb_rq *rqp; struct smb_share *ssp = np->n_mount->sm_share; struct mbchain *mbp; struct mdchain *mdp; int error; u_int8_t wc; u_int8_t *nmlen; u_int16_t flen; KASSERT(SMBTOV(np)->v_type == VDIR); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scred, &rqp); if (error) return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); mb_put_uint8(mbp, 0xff); /* Secondary command; 0xFF = None */ mb_put_uint8(mbp, 0); /* Reserved (must be 0) */ mb_put_uint16le(mbp, 0); /* Off to next cmd WordCount */ mb_put_uint8(mbp, 0); /* Reserved (must be 0) */ nmlen = mb_reserve(mbp, sizeof(u_int16_t)); /* Length of Name[] in bytes */ mb_put_uint32le(mbp, SMB_FL_CANONICAL_PATHNAMES); /* Flags - Create bit set */ mb_put_uint32le(mbp, 0); /* If nonzero, open relative to this */ mb_put_uint32le(mbp, NT_FILE_LIST_DIRECTORY); /* Access mask */ mb_put_uint32le(mbp, 0); /* Low 32bit */ mb_put_uint32le(mbp, 0); /* Hi 32bit */ /* Initial allocation size */ mb_put_uint32le(mbp, 0); /* File attributes */ mb_put_uint32le(mbp, NT_FILE_SHARE_READ|NT_FILE_SHARE_WRITE); /* Type of share access */ mb_put_uint32le(mbp, NT_OPEN_EXISTING); /* Create disposition - just open */ mb_put_uint32le(mbp, NT_FILE_DIRECTORY_FILE); /* Options to use if creating a file */ mb_put_uint32le(mbp, 0); /* Security QOS information */ mb_put_uint8(mbp, 0); /* Security tracking mode flags */ smb_rq_wend(rqp); smb_rq_bstart(rqp); error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); if (error) return error; /* Windows XP seems to include the final zero. Better do that too. */ mb_put_uint8(mbp, 0); flen = mbp->mb_count; SMBRQ_PUTLE16(nmlen, flen); smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) goto bad; smb_rq_getreply(rqp, &mdp); md_get_uint8(mdp, &wc); /* WordCount - check? */ md_get_uint8(mdp, NULL); /* AndXCommand */ md_get_uint8(mdp, NULL); /* Reserved - must be zero */ md_get_uint16(mdp, NULL); /* Offset to next cmd WordCount */ md_get_uint8(mdp, NULL); /* Oplock level granted */ md_get_uint16(mdp, &np->n_fid); /* FID */ /* ignore rest */ bad: smb_rq_done(rqp); return (error); }