static int smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) { struct mdchain *mbp; struct smb_t2rq *t2p; char *cp; u_int8_t tb; u_int16_t date, time, wattr; u_int32_t size, next, dattr; int64_t lint; int error, svtz, cnt, fxsz, nmlen, recsz; if (ctx->f_ecnt == 0) { if (ctx->f_flags & SMBFS_RDD_EOF) return ENOENT; ctx->f_left = ctx->f_limit = limit; error = smbfs_smb_trans2find2(ctx); if (error) return error; } t2p = ctx->f_t2; mbp = &t2p->t2_rdata; svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; switch (ctx->f_infolevel) { case SMB_INFO_STANDARD: next = 0; fxsz = 0; md_get_uint16le(mbp, &date); md_get_uint16le(mbp, &time); /* creation time */ md_get_uint16le(mbp, &date); md_get_uint16le(mbp, &time); /* access time */ smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); md_get_uint16le(mbp, &date); md_get_uint16le(mbp, &time); /* access time */ smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); md_get_uint32le(mbp, &size); ctx->f_attr.fa_size = size; md_get_uint32(mbp, NULL); /* allocation size */ md_get_uint16le(mbp, &wattr); ctx->f_attr.fa_attr = wattr; md_get_uint8(mbp, &tb); size = nmlen = tb; fxsz = 23; recsz = next = 24 + nmlen; /* docs misses zero byte at end */ break; case SMB_FIND_FILE_DIRECTORY_INFO: md_get_uint32le(mbp, &next); md_get_uint32(mbp, NULL); /* file index */ md_get_int64(mbp, NULL); /* creation time */ md_get_int64le(mbp, &lint); smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); md_get_int64le(mbp, &lint); smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); md_get_int64le(mbp, &lint); smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); md_get_int64le(mbp, &lint); /* file size */ ctx->f_attr.fa_size = lint; md_get_int64(mbp, NULL); /* real size (should use) */ md_get_uint32le(mbp, &dattr); /* EA */ ctx->f_attr.fa_attr = dattr; md_get_uint32le(mbp, &size); /* name len */ fxsz = 64; recsz = next ? next : fxsz + size; break; default: SMBERROR("unexpected info level %d\n", ctx->f_infolevel); return EINVAL; } if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { nmlen = min(size, SMB_MAXFNAMELEN * 2); } else nmlen = min(size, SMB_MAXFNAMELEN); cp = ctx->f_name; error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); if (error) return error; if (next) { cnt = next - nmlen - fxsz; if (cnt > 0) md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); else if (cnt < 0) { SMBERROR("out of sync\n"); return EBADRPC; } } if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0) nmlen -= 2; } else if (nmlen && cp[nmlen - 1] == 0) nmlen--; if (nmlen == 0) return EBADRPC; next = ctx->f_eofs + recsz; if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { /* * Server needs a resume filename. */ if (ctx->f_rnamelen <= nmlen) { if (ctx->f_rname) free(ctx->f_rname, M_SMBFSDATA); ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); ctx->f_rnamelen = nmlen; } bcopy(ctx->f_name, ctx->f_rname, nmlen); ctx->f_rname[nmlen] = 0; ctx->f_flags |= SMBFS_RDD_GOTRNAME; } ctx->f_nmlen = nmlen; ctx->f_eofs = next; ctx->f_ecnt--; ctx->f_left--; return 0; }
static int smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, struct smb_cred *scred, short infolevel) { struct smb_share *ssp = np->n_mount->sm_share; struct smb_vc *vcp = SSTOVC(ssp); struct smb_t2rq *t2p; int error, svtz, timesok = 1; struct mbchain *mbp; struct mdchain *mdp; u_int16_t date, time, wattr; int64_t lint; u_int32_t size, dattr; error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION, scred, &t2p); if (error) return error; mbp = &t2p->t2_tparam; mb_init(mbp); if (!infolevel) { if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) infolevel = SMB_QUERY_FILE_STANDARD; else infolevel = SMB_QUERY_FILE_BASIC_INFO; } mb_put_uint16le(mbp, infolevel); mb_put_uint32le(mbp, 0); /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ error = smbfs_fullpath(mbp, vcp, np, NULL, 0); if (error) { smb_t2_done(t2p); return error; } t2p->t2_maxpcount = 2; t2p->t2_maxdcount = vcp->vc_txmax; error = smb_t2_request(t2p); if (error) { smb_t2_done(t2p); if (infolevel == SMB_QUERY_FILE_STANDARD || error != EINVAL) return error; return smbfs_smb_qpathinfo(np, fap, scred, SMB_QUERY_FILE_STANDARD); } mdp = &t2p->t2_rdata; svtz = vcp->vc_sopt.sv_tz; switch (infolevel) { case SMB_QUERY_FILE_STANDARD: timesok = 0; md_get_uint16le(mdp, NULL); md_get_uint16le(mdp, NULL); /* creation time */ md_get_uint16le(mdp, &date); md_get_uint16le(mdp, &time); /* access time */ if (date || time) { timesok++; smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); } md_get_uint16le(mdp, &date); md_get_uint16le(mdp, &time); /* modify time */ if (date || time) { timesok++; smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); } md_get_uint32le(mdp, &size); fap->fa_size = size; md_get_uint32(mdp, NULL); /* allocation size */ md_get_uint16le(mdp, &wattr); fap->fa_attr = wattr; break; case SMB_QUERY_FILE_BASIC_INFO: timesok = 0; md_get_int64(mdp, NULL); /* creation time */ md_get_int64le(mdp, &lint); if (lint) { timesok++; smb_time_NT2local(lint, svtz, &fap->fa_atime); } md_get_int64le(mdp, &lint); if (lint) { timesok++; smb_time_NT2local(lint, svtz, &fap->fa_mtime); } md_get_int64le(mdp, &lint); if (lint) { timesok++; smb_time_NT2local(lint, svtz, &fap->fa_ctime); } md_get_uint32le(mdp, &dattr); fap->fa_attr = dattr; md_get_uint32(mdp, NULL); /* XXX could use ALL_INFO to get size */ break; default: SMBERROR("unexpected info level %d\n", infolevel); error = EINVAL; } smb_t2_done(t2p); /* * if all times are zero (observed with FAT on NT4SP6) * then fall back to older info level */ if (!timesok) { if (infolevel != SMB_QUERY_FILE_STANDARD) return smbfs_smb_qpathinfo(np, fap, scred, SMB_QUERY_FILE_STANDARD); error = EINVAL; } return error; }