summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorbp <bp@FreeBSD.org>2002-09-18 09:27:04 +0000
committerbp <bp@FreeBSD.org>2002-09-18 09:27:04 +0000
commit196b315ed80d68650ae09897e65629420c5018a2 (patch)
tree2deb86a7b8564d0b34311eba3e3eee4ab4e29f25 /sys
parent3b0f5df300aab6670942c0704c2106ff3c4224a2 (diff)
downloadFreeBSD-src-196b315ed80d68650ae09897e65629420c5018a2.zip
FreeBSD-src-196b315ed80d68650ae09897e65629420c5018a2.tar.gz
Implement additional SMB calls to allow proper update of file size as some
file servers fail to do it in the right way. New NFLUSHWIRE flag marks pending flush request(s). NB: not all cases covered by this commit. Obtained from: Darwin
Diffstat (limited to 'sys')
-rw-r--r--sys/fs/smbfs/smbfs.h2
-rw-r--r--sys/fs/smbfs/smbfs_node.h1
-rw-r--r--sys/fs/smbfs/smbfs_smb.c236
-rw-r--r--sys/fs/smbfs/smbfs_subr.h3
4 files changed, 239 insertions, 3 deletions
diff --git a/sys/fs/smbfs/smbfs.h b/sys/fs/smbfs/smbfs.h
index 90dc8f0..b6f97be 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 1a5a643..e65337a 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 6610ecf..95e1528 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 058ffe8..bc1279f 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,
OpenPOWER on IntegriCloud