diff options
author | davide <davide@FreeBSD.org> | 2012-11-22 08:58:29 +0000 |
---|---|---|
committer | davide <davide@FreeBSD.org> | 2012-11-22 08:58:29 +0000 |
commit | 017de7d0303ff918f52d32ec10a552ddb5c8906f (patch) | |
tree | e433574688bbdd45f9dafc017b3a702122efbb9f /sys/fs/smbfs/smbfs_subr.c | |
parent | 855b0bb00b49b02f2815692ca7f316366059c89e (diff) | |
download | FreeBSD-src-017de7d0303ff918f52d32ec10a552ddb5c8906f.zip FreeBSD-src-017de7d0303ff918f52d32ec10a552ddb5c8906f.tar.gz |
Until now, smbfs_fullpath() computed the full path starting from the
vnode and following back the chain of n_parent pointers up to the root,
without acquiring the locks of the n_parent vnodes analyzed during the
computation. This is immediately wrong because if the vnode lock is not
held there's no guarantee on the validity of the vnode pointer or the data.
In order to fix, store the whole path in the smbnode structure so that
smbfs_fullpath() can use this information.
Discussed with: kib
Reported and tested by: pho
Sponsored by: iXsystems inc.
Diffstat (limited to 'sys/fs/smbfs/smbfs_subr.c')
-rw-r--r-- | sys/fs/smbfs/smbfs_subr.c | 71 |
1 files changed, 19 insertions, 52 deletions
diff --git a/sys/fs/smbfs/smbfs_subr.c b/sys/fs/smbfs/smbfs_subr.c index b95f92b..aa03101 100644 --- a/sys/fs/smbfs/smbfs_subr.c +++ b/sys/fs/smbfs/smbfs_subr.c @@ -107,44 +107,6 @@ smb_dos2unixtime(u_int dd, u_int dt, u_int dh, int tzoff, smb_time_server2local(tsp->tv_sec, tzoff, tsp); } -static int -smb_fphelp(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *np, - int caseopt) -{ - struct smbmount *smp= np->n_mount; - struct smbnode **npp = smp->sm_npstack; - int i, error = 0; - -/* simple_lock(&smp->sm_npslock);*/ - i = 0; - while (np->n_parent) { - if (i++ == SMBFS_MAXPATHCOMP) { -/* simple_unlock(&smp->sm_npslock);*/ - return ENAMETOOLONG; - } - *npp++ = np; - if ((np->n_flag & NREFPARENT) == 0) - break; - np = VTOSMB(np->n_parent); - } -/* if (i == 0) - return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/ - while (i--) { - np = *--npp; - if (SMB_UNICODE_STRINGS(vcp)) - error = mb_put_uint16le(mbp, '\\'); - else - error = mb_put_uint8(mbp, '\\'); - if (error) - break; - error = smb_put_dmem(mbp, vcp, np->n_name, np->n_nmlen, caseopt); - if (error) - break; - } -/* simple_unlock(&smp->sm_npslock);*/ - return error; -} - int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, const char *name, int nmlen) @@ -160,23 +122,28 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0) caseopt |= SMB_CS_UPPER; if (dnp != NULL) { - error = smb_fphelp(mbp, vcp, dnp, caseopt); - if (error) - return error; - } - if (name) { - if (SMB_UNICODE_STRINGS(vcp)) - error = mb_put_uint16le(mbp, '\\'); - else - error = mb_put_uint8(mbp, '\\'); - if (error) - return error; - error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt); + error = smb_put_dmem(mbp, vcp, dnp->n_rpath, dnp->n_rplen, + caseopt); if (error) return error; + if (name) { + /* Put the separator */ + if (SMB_UNICODE_STRINGS(vcp)) + error = mb_put_uint16le(mbp, '\\'); + else + error = mb_put_uint8(mbp, '\\'); + if (error) + return error; + /* Put the name */ + error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt); + if (error) + return error; + } } - error = mb_put_uint8(mbp, 0); - if (SMB_UNICODE_STRINGS(vcp) && error == 0) + /* Put NULL terminator. */ + if (SMB_UNICODE_STRINGS(vcp)) + error = mb_put_uint16le(mbp, 0); + else error = mb_put_uint8(mbp, 0); return error; } |