Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 143690
b: refs/heads/master
c: 1bfe73c
h: refs/heads/master
v: v3
  • Loading branch information
Igor Mammedov authored and Steve French committed Apr 17, 2009
1 parent d014297 commit eb1eb53
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 33 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: 85a6dac54a7e28112488b02523202985edc7e639
refs/heads/master: 1bfe73c258addc388b90fe8c2c6bbc0f0c9c10dd
152 changes: 120 additions & 32 deletions trunk/fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2214,9 +2214,56 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon,
return rc;
}

static void
cleanup_volume_info(struct smb_vol **pvolume_info)
{
struct smb_vol *volume_info;

if (!pvolume_info && !*pvolume_info)
return;

volume_info = *pvolume_info;
kzfree(volume_info->password);
kfree(volume_info->UNC);
kfree(volume_info->prepath);
kfree(volume_info);
*pvolume_info = NULL;
return;
}

/* build_path_to_root returns full path to root when
* we do not have an exiting connection (tcon) */
static char *
build_unc_path_to_root(const struct smb_vol *volume_info,
const struct cifs_sb_info *cifs_sb)
{
char *full_path;

int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
if (full_path == NULL)
return ERR_PTR(-ENOMEM);

strncpy(full_path, volume_info->UNC, unc_len);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
int i;
for (i = 0; i < unc_len; i++) {
if (full_path[i] == '\\')
full_path[i] = '/';
}
}

if (cifs_sb->prepathlen)
strncpy(full_path + unc_len, cifs_sb->prepath,
cifs_sb->prepathlen);

full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
return full_path;
}

int
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
char *mount_data, const char *devname)
char *mount_data_global, const char *devname)
{
int rc = 0;
int xid;
Expand All @@ -2225,6 +2272,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
struct cifsTconInfo *tcon = NULL;
struct TCP_Server_Info *srvTcp = NULL;
char *full_path;
struct dfs_info3_param *referrals = NULL;
unsigned int num_referrals = 0;

char *mount_data = mount_data_global;

try_mount_again:
full_path = NULL;

xid = GetXid();

Expand Down Expand Up @@ -2371,11 +2425,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
}

/* check for null share name ie connect to dfs root */
if ((strchr(volume_info->UNC + 3, '\\') == NULL)
&& (strchr(volume_info->UNC + 3, '/') == NULL)) {
/* rc = connect_to_dfs_path(...) */
cFYI(1, ("DFS root not supported"));
cERROR(1, ("Missing share name"));
rc = -ENODEV;
goto mount_fail_check;
} else {
Expand All @@ -2392,7 +2444,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
}
if (rc)
goto mount_fail_check;
goto remote_path_check;
tcon->seal = volume_info->seal;
write_lock(&cifs_tcp_ses_lock);
list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
Expand All @@ -2417,19 +2469,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
sb->s_time_gran = 100;

mount_fail_check:
/* on error free sesinfo and tcon struct if needed */
if (rc) {
/* If find_unc succeeded then rc == 0 so we can not end */
/* up accidently freeing someone elses tcon struct */
if (tcon)
cifs_put_tcon(tcon);
else if (pSesInfo)
cifs_put_smb_ses(pSesInfo);
else
cifs_put_tcp_session(srvTcp);
goto out;
}
if (rc)
goto remote_path_check;

cifs_sb->tcon = tcon;

/* do not care if following two calls succeed - informational */
Expand Down Expand Up @@ -2461,39 +2503,85 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb->rsize = min(cifs_sb->rsize,
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));

if (!rc && cifs_sb->prepathlen) {
remote_path_check:
/* check if a whole path (including prepath) is not remote */
if (!rc && cifs_sb->prepathlen && tcon) {
/* build_path_to_root works only when we have a valid tcon */
full_path = cifs_build_path_to_root(cifs_sb);
if (full_path == NULL) {
rc = -ENOMEM;
goto mount_fail_check;
}
rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
if (rc) {
cERROR(1, ("Path %s in not accessible: %d",
full_path, rc));
if (rc != -EREMOTE) {
kfree(full_path);
goto mount_fail_check;
}
kfree(full_path);
}

/* get referral if needed */
if (rc == -EREMOTE) {
/* convert forward to back slashes in prepath here if needed */
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
convert_delimiter(cifs_sb->prepath,
CIFS_DIR_SEP(cifs_sb));
full_path = build_unc_path_to_root(volume_info, cifs_sb);
if (IS_ERR(full_path)) {
rc = PTR_ERR(full_path);
goto mount_fail_check;
}

cFYI(1, ("Getting referral for: %s", full_path));
rc = get_dfs_path(xid, pSesInfo , full_path + 1,
cifs_sb->local_nls, &num_referrals, &referrals,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc && num_referrals > 0) {
char *fake_devname = NULL;

if (mount_data != mount_data_global)
kfree(mount_data);
mount_data = cifs_compose_mount_options(
cifs_sb->mountdata, full_path + 1,
referrals, &fake_devname);
kfree(fake_devname);
free_dfs_info_array(referrals, num_referrals);

if (tcon)
cifs_put_tcon(tcon);
else if (pSesInfo)
cifs_put_smb_ses(pSesInfo);

cleanup_volume_info(&volume_info);
FreeXid(xid);
kfree(full_path);
goto try_mount_again;
}
}

mount_fail_check:
/* on error free sesinfo and tcon struct if needed */
if (rc) {
if (mount_data != mount_data_global)
kfree(mount_data);
/* If find_unc succeeded then rc == 0 so we can not end */
/* up accidently freeing someone elses tcon struct */
if (tcon)
cifs_put_tcon(tcon);
else if (pSesInfo)
cifs_put_smb_ses(pSesInfo);
else
cifs_put_tcp_session(srvTcp);
goto out;
}

/* volume_info->password is freed above when existing session found
(in which case it is not needed anymore) but when new sesion is created
the password ptr is put in the new session structure (in which case the
password will be freed at unmount time) */
out:
/* zero out password before freeing */
if (volume_info) {
if (volume_info->password != NULL) {
memset(volume_info->password, 0,
strlen(volume_info->password));
kfree(volume_info->password);
}
kfree(volume_info->UNC);
kfree(volume_info->prepath);
kfree(volume_info);
}
cleanup_volume_info(&volume_info);
FreeXid(xid);
return rc;
}
Expand Down

0 comments on commit eb1eb53

Please sign in to comment.