aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifs_dfs_ref.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/cifs_dfs_ref.c')
-rw-r--r--fs/cifs/cifs_dfs_ref.c71
1 files changed, 47 insertions, 24 deletions
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index d2c8eef84f3c..e1c18362ba46 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -106,7 +106,8 @@ static char *cifs_get_share_name(const char *node_name)
106/** 106/**
107 * compose_mount_options - creates mount options for refferral 107 * compose_mount_options - creates mount options for refferral
108 * @sb_mountdata: parent/root DFS mount options (template) 108 * @sb_mountdata: parent/root DFS mount options (template)
109 * @ref_unc: refferral server UNC 109 * @dentry: point where we are going to mount
110 * @ref: server's referral
110 * @devname: pointer for saving device name 111 * @devname: pointer for saving device name
111 * 112 *
112 * creates mount options for submount based on template options sb_mountdata 113 * creates mount options for submount based on template options sb_mountdata
@@ -116,7 +117,8 @@ static char *cifs_get_share_name(const char *node_name)
116 * Caller is responcible for freeing retunrned value if it is not error. 117 * Caller is responcible for freeing retunrned value if it is not error.
117 */ 118 */
118static char *compose_mount_options(const char *sb_mountdata, 119static char *compose_mount_options(const char *sb_mountdata,
119 const char *ref_unc, 120 struct dentry *dentry,
121 const struct dfs_info3_param *ref,
120 char **devname) 122 char **devname)
121{ 123{
122 int rc; 124 int rc;
@@ -126,11 +128,12 @@ static char *compose_mount_options(const char *sb_mountdata,
126 char *srvIP = NULL; 128 char *srvIP = NULL;
127 char sep = ','; 129 char sep = ',';
128 int off, noff; 130 int off, noff;
131 char *fullpath;
129 132
130 if (sb_mountdata == NULL) 133 if (sb_mountdata == NULL)
131 return ERR_PTR(-EINVAL); 134 return ERR_PTR(-EINVAL);
132 135
133 *devname = cifs_get_share_name(ref_unc); 136 *devname = cifs_get_share_name(ref->node_name);
134 rc = dns_resolve_server_name_to_ip(*devname, &srvIP); 137 rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
135 if (rc != 0) { 138 if (rc != 0) {
136 cERROR(1, ("%s: Failed to resolve server part of %s to IP", 139 cERROR(1, ("%s: Failed to resolve server part of %s to IP",
@@ -138,7 +141,12 @@ static char *compose_mount_options(const char *sb_mountdata,
138 mountdata = ERR_PTR(rc); 141 mountdata = ERR_PTR(rc);
139 goto compose_mount_options_out; 142 goto compose_mount_options_out;
140 } 143 }
141 md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3; 144 /* md_len = strlen(...) + 12 for 'sep+prefixpath='
145 * assuming that we have 'unc=' and 'ip=' in
146 * the original sb_mountdata
147 */
148 md_len = strlen(sb_mountdata) + strlen(srvIP) +
149 strlen(ref->node_name) + 12;
142 mountdata = kzalloc(md_len+1, GFP_KERNEL); 150 mountdata = kzalloc(md_len+1, GFP_KERNEL);
143 if (mountdata == NULL) { 151 if (mountdata == NULL) {
144 mountdata = ERR_PTR(-ENOMEM); 152 mountdata = ERR_PTR(-ENOMEM);
@@ -152,41 +160,56 @@ static char *compose_mount_options(const char *sb_mountdata,
152 strncpy(mountdata, sb_mountdata, 5); 160 strncpy(mountdata, sb_mountdata, 5);
153 off += 5; 161 off += 5;
154 } 162 }
155 while ((tkn_e = strchr(sb_mountdata+off, sep))) { 163
156 noff = (tkn_e - (sb_mountdata+off)) + 1; 164 do {
157 if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) { 165 tkn_e = strchr(sb_mountdata + off, sep);
166 if (tkn_e == NULL)
167 noff = strlen(sb_mountdata + off);
168 else
169 noff = tkn_e - (sb_mountdata + off) + 1;
170
171 if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) {
158 off += noff; 172 off += noff;
159 continue; 173 continue;
160 } 174 }
161 if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) { 175 if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) {
162 off += noff; 176 off += noff;
163 continue; 177 continue;
164 } 178 }
165 if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) { 179 if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
166 off += noff; 180 off += noff;
167 continue; 181 continue;
168 } 182 }
169 strncat(mountdata, sb_mountdata+off, noff); 183 strncat(mountdata, sb_mountdata + off, noff);
170 off += noff; 184 off += noff;
171 } 185 } while (tkn_e);
172 strcat(mountdata, sb_mountdata+off); 186 strcat(mountdata, sb_mountdata + off);
173 mountdata[md_len] = '\0'; 187 mountdata[md_len] = '\0';
174 188
175 /* copy new IP and ref share name */ 189 /* copy new IP and ref share name */
176 strcat(mountdata, ",ip="); 190 if (mountdata[strlen(mountdata) - 1] != sep)
191 strncat(mountdata, &sep, 1);
192 strcat(mountdata, "ip=");
177 strcat(mountdata, srvIP); 193 strcat(mountdata, srvIP);
178 strcat(mountdata, ",unc="); 194 strncat(mountdata, &sep, 1);
195 strcat(mountdata, "unc=");
179 strcat(mountdata, *devname); 196 strcat(mountdata, *devname);
180 197
181 /* find & copy prefixpath */ 198 /* find & copy prefixpath */
182 tkn_e = strchr(ref_unc+2, '\\'); 199 tkn_e = strchr(ref->node_name + 2, '\\');
183 if (tkn_e) { 200 if (tkn_e == NULL) /* invalid unc, missing share name*/
184 tkn_e = strchr(tkn_e+1, '\\'); 201 goto compose_mount_options_out;
185 if (tkn_e) { 202
186 strcat(mountdata, ",prefixpath="); 203 fullpath = build_path_from_dentry(dentry);
187 strcat(mountdata, tkn_e+1); 204 tkn_e = strchr(tkn_e + 1, '\\');
188 } 205 if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
206 strncat(mountdata, &sep, 1);
207 strcat(mountdata, "prefixpath=");
208 if (tkn_e)
209 strcat(mountdata, tkn_e + 1);
210 strcat(mountdata, fullpath + (ref->path_consumed));
189 } 211 }
212 kfree(fullpath);
190 213
191 /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/ 214 /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
192 /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/ 215 /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/
@@ -198,7 +221,7 @@ compose_mount_options_out:
198 221
199 222
200static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, 223static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
201 struct dentry *dentry, char *ref_unc) 224 struct dentry *dentry, const struct dfs_info3_param *ref)
202{ 225{
203 struct cifs_sb_info *cifs_sb; 226 struct cifs_sb_info *cifs_sb;
204 struct vfsmount *mnt; 227 struct vfsmount *mnt;
@@ -207,7 +230,7 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
207 230
208 cifs_sb = CIFS_SB(dentry->d_inode->i_sb); 231 cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
209 mountdata = compose_mount_options(cifs_sb->mountdata, 232 mountdata = compose_mount_options(cifs_sb->mountdata,
210 ref_unc, &devname); 233 dentry, ref, &devname);
211 234
212 if (IS_ERR(mountdata)) 235 if (IS_ERR(mountdata))
213 return (struct vfsmount *)mountdata; 236 return (struct vfsmount *)mountdata;
@@ -310,7 +333,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
310 } 333 }
311 mnt = cifs_dfs_do_refmount(nd->path.mnt, 334 mnt = cifs_dfs_do_refmount(nd->path.mnt,
312 nd->path.dentry, 335 nd->path.dentry,
313 referrals[i].node_name); 336 referrals + i);
314 cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", 337 cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
315 __func__, 338 __func__,
316 referrals[i].node_name, mnt)); 339 referrals[i].node_name, mnt));