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
This commit is contained in:
bp 2002-09-18 09:27:04 +00:00
parent 3b0f5df300
commit 196b315ed8
4 changed files with 239 additions and 3 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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,