Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 119119
b: refs/heads/master
c: 2c55608
h: refs/heads/master
i:
  119117: 39647cc
  119115: d177e0c
  119111: 960e3a6
  119103: 73025b8
v: v3
  • Loading branch information
Igor Mammedov authored and Steve French committed Nov 18, 2008
1 parent 6e39c0d commit fce92d5
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 28 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ab3f992983062440b4f37c666dac66d987902d91
refs/heads/master: 2c55608f28444c3f33b10312881384c470ceed56
71 changes: 47 additions & 24 deletions trunk/fs/cifs/cifs_dfs_ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ static char *cifs_get_share_name(const char *node_name)
/**
* compose_mount_options - creates mount options for refferral
* @sb_mountdata: parent/root DFS mount options (template)
* @ref_unc: refferral server UNC
* @dentry: point where we are going to mount
* @ref: server's referral
* @devname: pointer for saving device name
*
* creates mount options for submount based on template options sb_mountdata
Expand All @@ -116,7 +117,8 @@ static char *cifs_get_share_name(const char *node_name)
* Caller is responcible for freeing retunrned value if it is not error.
*/
static char *compose_mount_options(const char *sb_mountdata,
const char *ref_unc,
struct dentry *dentry,
const struct dfs_info3_param *ref,
char **devname)
{
int rc;
Expand All @@ -126,19 +128,25 @@ static char *compose_mount_options(const char *sb_mountdata,
char *srvIP = NULL;
char sep = ',';
int off, noff;
char *fullpath;

if (sb_mountdata == NULL)
return ERR_PTR(-EINVAL);

*devname = cifs_get_share_name(ref_unc);
*devname = cifs_get_share_name(ref->node_name);
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
if (rc != 0) {
cERROR(1, ("%s: Failed to resolve server part of %s to IP",
__func__, *devname));
mountdata = ERR_PTR(rc);
goto compose_mount_options_out;
}
md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3;
/* md_len = strlen(...) + 12 for 'sep+prefixpath='
* assuming that we have 'unc=' and 'ip=' in
* the original sb_mountdata
*/
md_len = strlen(sb_mountdata) + strlen(srvIP) +
strlen(ref->node_name) + 12;
mountdata = kzalloc(md_len+1, GFP_KERNEL);
if (mountdata == NULL) {
mountdata = ERR_PTR(-ENOMEM);
Expand All @@ -152,41 +160,56 @@ static char *compose_mount_options(const char *sb_mountdata,
strncpy(mountdata, sb_mountdata, 5);
off += 5;
}
while ((tkn_e = strchr(sb_mountdata+off, sep))) {
noff = (tkn_e - (sb_mountdata+off)) + 1;
if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) {

do {
tkn_e = strchr(sb_mountdata + off, sep);
if (tkn_e == NULL)
noff = strlen(sb_mountdata + off);
else
noff = tkn_e - (sb_mountdata + off) + 1;

if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) {
off += noff;
continue;
}
if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) {
if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) {
off += noff;
continue;
}
if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) {
if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
off += noff;
continue;
}
strncat(mountdata, sb_mountdata+off, noff);
strncat(mountdata, sb_mountdata + off, noff);
off += noff;
}
strcat(mountdata, sb_mountdata+off);
} while (tkn_e);
strcat(mountdata, sb_mountdata + off);
mountdata[md_len] = '\0';

/* copy new IP and ref share name */
strcat(mountdata, ",ip=");
if (mountdata[strlen(mountdata) - 1] != sep)
strncat(mountdata, &sep, 1);
strcat(mountdata, "ip=");
strcat(mountdata, srvIP);
strcat(mountdata, ",unc=");
strncat(mountdata, &sep, 1);
strcat(mountdata, "unc=");
strcat(mountdata, *devname);

/* find & copy prefixpath */
tkn_e = strchr(ref_unc+2, '\\');
if (tkn_e) {
tkn_e = strchr(tkn_e+1, '\\');
if (tkn_e) {
strcat(mountdata, ",prefixpath=");
strcat(mountdata, tkn_e+1);
}
tkn_e = strchr(ref->node_name + 2, '\\');
if (tkn_e == NULL) /* invalid unc, missing share name*/
goto compose_mount_options_out;

fullpath = build_path_from_dentry(dentry);
tkn_e = strchr(tkn_e + 1, '\\');
if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
strncat(mountdata, &sep, 1);
strcat(mountdata, "prefixpath=");
if (tkn_e)
strcat(mountdata, tkn_e + 1);
strcat(mountdata, fullpath + (ref->path_consumed));
}
kfree(fullpath);

/*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
/*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/
Expand All @@ -198,7 +221,7 @@ static char *compose_mount_options(const char *sb_mountdata,


static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
struct dentry *dentry, char *ref_unc)
struct dentry *dentry, const struct dfs_info3_param *ref)
{
struct cifs_sb_info *cifs_sb;
struct vfsmount *mnt;
Expand All @@ -207,7 +230,7 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,

cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
mountdata = compose_mount_options(cifs_sb->mountdata,
ref_unc, &devname);
dentry, ref, &devname);

if (IS_ERR(mountdata))
return (struct vfsmount *)mountdata;
Expand Down Expand Up @@ -310,7 +333,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
}
mnt = cifs_dfs_do_refmount(nd->path.mnt,
nd->path.dentry,
referrals[i].node_name);
referrals + i);
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
__func__,
referrals[i].node_name, mnt));
Expand Down
39 changes: 36 additions & 3 deletions trunk/fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -3899,6 +3899,27 @@ CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
return rc;
}

/* computes length of UCS string converted to host codepage
* @src: UCS string
* @maxlen: length of the input string in UCS characters
* (not in bytes)
*
* return: size of input string in host codepage
*/
static int hostlen_fromUCS(const __le16 *src, const int maxlen,
const struct nls_table *nls_codepage) {
int i;
int hostlen = 0;
char to[4];
int charlen;
for (i = 0; (i < maxlen) && src[i]; ++i) {
charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
to, NLS_MAX_CHARSET_SIZE);
hostlen += charlen > 0 ? charlen : 1;
}
return hostlen;
}

/* parses DFS refferal V3 structure
* caller is responsible for freeing target_nodes
* returns:
Expand All @@ -3909,7 +3930,8 @@ static int
parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
unsigned int *num_of_nodes,
struct dfs_info3_param **target_nodes,
const struct nls_table *nls_codepage)
const struct nls_table *nls_codepage, int remap,
const char *searchName)
{
int i, rc = 0;
char *data_end;
Expand Down Expand Up @@ -3960,7 +3982,17 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
struct dfs_info3_param *node = (*target_nodes)+i;

node->flags = le16_to_cpu(pSMBr->DFSFlags);
node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
if (is_unicode) {
__le16 *tmp = kmalloc(strlen(searchName)*2, GFP_KERNEL);
cifsConvertToUCS((__le16 *) tmp, searchName,
PATH_MAX, nls_codepage, remap);
node->path_consumed = hostlen_fromUCS(tmp,
le16_to_cpu(pSMBr->PathConsumed)/2,
nls_codepage);
kfree(tmp);
} else
node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);

node->server_type = le16_to_cpu(ref->ServerType);
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);

Expand Down Expand Up @@ -4093,7 +4125,8 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,

/* parse returned result into more usable form */
rc = parse_DFS_referrals(pSMBr, num_of_nodes,
target_nodes, nls_codepage);
target_nodes, nls_codepage, remap,
searchName);

GetDFSRefExit:
cifs_buf_release(pSMB);
Expand Down

0 comments on commit fce92d5

Please sign in to comment.