diff --git a/sys/fs/smbfs/smbfs.h b/sys/fs/smbfs/smbfs.h index 90dc8f04457f..b6f97bec7047 100644 --- a/sys/fs/smbfs/smbfs.h +++ b/sys/fs/smbfs/smbfs.h @@ -49,7 +49,7 @@ #define SMBFS_MAXPATHCOMP 256 /* maximum number of path components */ -/* Layout of the mount control block for a netware filesystem. */ +/* Layout of the mount control block for an smb file system. */ struct smbfs_args { int version; int dev; diff --git a/sys/fs/smbfs/smbfs_node.h b/sys/fs/smbfs/smbfs_node.h index 1a5a643a2e0a..e65337a91ae0 100644 --- a/sys/fs/smbfs/smbfs_node.h +++ b/sys/fs/smbfs/smbfs_node.h @@ -42,6 +42,7 @@ #define NMODIFIED 0x0004 /* bogus, until async IO implemented */ /*efine NNEW 0x0008*//* smb/vnode has been allocated */ #define NREFPARENT 0x0010 /* node holds parent from recycling */ +#define NFLUSHWIRE 0x1000 /* pending flush request */ struct smbfs_fctx; diff --git a/sys/fs/smbfs/smbfs_smb.c b/sys/fs/smbfs/smbfs_smb.c index 6610ecf60f6c..95e15280365e 100644 --- a/sys/fs/smbfs/smbfs_smb.c +++ b/sys/fs/smbfs/smbfs_smb.c @@ -104,13 +104,13 @@ smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t return error; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); - mb_put_uint8(mbp, 0xff); /* secondary command */ + mb_put_uint8(mbp, 0xff); /* secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); mb_put_uint8(mbp, ltype); /* locktype */ mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ - mb_put_uint32le(mbp, 0); /* timeout - break immediately */ + mb_put_uint32le(mbp, 0); /* timeout - break immediately */ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); smb_rq_wend(rqp); @@ -139,6 +139,116 @@ smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, return smbfs_smb_lockandx(np, op, (u_int32_t)id, start, end, scred); } +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; +} + int smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp, struct smb_cred *scred) @@ -216,6 +326,69 @@ smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, return 0; } +static int +smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred) +{ + struct smb_t2rq *t2p; + struct smb_share *ssp = np->n_mount->sm_share; + struct mbchain *mbp; + int error; + + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, + scred, &t2p); + if (error) + return error; + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); + mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO); + mb_put_uint32le(mbp, 0); + mbp = &t2p->t2_tdata; + mb_init(mbp); + mb_put_int64le(mbp, newsize); + mb_put_uint32le(mbp, 0); /* padding */ + mb_put_uint16le(mbp, 0); + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = 0; + error = smb_t2_request(t2p); + smb_t2_done(t2p); + return error; +} + +static int +smb_smb_flush(struct smbnode *np, struct smb_cred *scred) +{ + struct smb_share *ssp = np->n_mount->sm_share; + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + int error; + + if (np->n_opencount <= 0 || !SMBTOV(np) || SMBTOV(np)->v_type != VREG) + return 0; /* not an regular open file */ + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + smb_rq_done(rqp); + if (!error) + np->n_flag &= ~NFLUSHWIRE; + return (error); +} + +int +smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred) +{ + if (np->n_flag & NFLUSHWIRE) + return (smb_smb_flush(np, scred)); + return (0); +} + int smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) { @@ -224,6 +397,11 @@ smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) struct mbchain *mbp; int error; + if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) { + np->n_flag |= NFLUSHWIRE; + return (0); + } + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); if (error) return error; @@ -243,6 +421,58 @@ smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) 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 rq, *rqp = &rq; + 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; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred); + if (error) + 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); + return error; +} /* * Set DOS file attributes. mtime should be NULL for dialects above lm10 @@ -311,6 +541,7 @@ smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, mb_init(mbp); mb_put_uint16le(mbp, SMB_INFO_STANDARD); mb_put_uint32le(mbp, 0); /* MBZ */ + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ error = smbfs_fullpath(mbp, vcp, np, NULL, 0); if (error) { smb_t2_done(t2p); @@ -365,6 +596,7 @@ smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, mb_init(mbp); mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); mb_put_uint32le(mbp, 0); /* MBZ */ + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ error = smbfs_fullpath(mbp, vcp, np, NULL, 0); if (error) { smb_t2_done(t2p); diff --git a/sys/fs/smbfs/smbfs_subr.h b/sys/fs/smbfs/smbfs_subr.h index 058ffe8a0e57..bc1279fae164 100644 --- a/sys/fs/smbfs/smbfs_subr.h +++ b/sys/fs/smbfs/smbfs_subr.h @@ -140,6 +140,8 @@ int smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, struct smb_cred *scred); int smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred); +int smbfs_smb_query_info(struct smbnode *np, const char *name, int len, + struct smbfattr *fap, struct smb_cred *scred); int smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, struct smb_cred *scred); int smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, @@ -158,6 +160,7 @@ int smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, int smbfs_smb_create(struct smbnode *dnp, const char *name, int len, struct smb_cred *scred); int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred); +int smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred); int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, const char *tname, int tnmlen, struct smb_cred *scred); int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,