[linux-cifs-client] [PATCH] CIFS: convert all delimiters in prefix path to match unix extensions

Jeff Layton jlayton at redhat.com
Thu Feb 7 16:33:23 GMT 2008


Currently, when we get a prefixpath as part of mount, the kernel only
changes the first character to be a '/' or '\' depending on whether
posix extensions are enabled. This is problematic as it expects
mount.cifs to pass in the correct delimiter in the rest of the
prefixpath. But, mount.cifs may not know *what* the correct delimiter
is. It's a chicken and egg problem.

Compounding this is the patch that I recently had committed for
mount.cifs that makes it always covert all '/' in the prefixpath to '\'
chars. This makes prefixpaths work correctly when mounting servers
without unix extensions, but breaks the case when unix extensions are
enabled.

The following patch fixes this by having the kernel change all '/' or
'\' to the "proper" CIFS_DIR_SEP character in the prefixpath at mount
and reconnect time.

Note that like the mount.cifs code, this makes no provision for
prefixpaths that have embedded delimiters of the other flavor (i.e.
posix paths with embedded backslashes, or "normal" paths with embedded
forward slashes).

For the future we should probably consider these cases and allow for
them. But that means that we need to determine how to allow these
characters to be escaped, and how to deal with these conversions when
the paths contain embedded characters.

Signed-off-by: Jeff Layton <jlayton at redhat.com>
---
 fs/cifs/connect.c |   25 ++++++++++++++++++++-----
 1 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 65d0ba7..aed5a78 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -789,6 +789,18 @@ extract_hostname(const char *unc)
 	return dst;
 }
 
+/* convert all delimiters in a path to given delimiter */
+static void
+convert_delimiter(char *path, char new_delim)
+{
+	char *p;
+
+	for (p = path; *p != '\0'; p++) {
+		if (*p == '/' || *p == '\\')
+			*p = new_delim;
+	}
+}
+
 static int
 cifs_parse_mount_options(char *options, const char *devname,
 			 struct smb_vol *vol)
@@ -1044,14 +1056,15 @@ cifs_parse_mount_options(char *options, const char *devname,
 					"CIFS: invalid path prefix\n");
 				return 1;       /* needs_argument */
 			}
+			/* mount.cifs should use '\\' for prefixpath delimiter now */
 			if ((temp_len = strnlen(value, 1024)) < 1024) {
-				if (value[0] != '/')
+				if (value[0] != '\\')
 					temp_len++;  /* missing leading slash */
 				vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
 				if (vol->prepath == NULL)
 					return 1;
-				if (value[0] != '/') {
-					vol->prepath[0] = '/';
+				if (value[0] != '\\') {
+					vol->prepath[0] = '\\';
 					strcpy(vol->prepath+1, value);
 				} else
 					strcpy(vol->prepath, value);
@@ -1748,7 +1761,8 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
 		form if we are reconnecting and the server switched its
 		posix path capability for this share */
 		if (sb && (CIFS_SB(sb)->prepathlen > 0))
-			CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
+			convert_delimiter(CIFS_SB(sb)->prepath,
+					  CIFS_DIR_SEP(CIFS_SB(sb)));
 
 		if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
 			if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
@@ -2057,7 +2071,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 		cifs_sb->prepath = volume_info.prepath;
 		if (cifs_sb->prepath) {
 			cifs_sb->prepathlen = strlen(cifs_sb->prepath);
-			cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
+			convert_delimiter(cifs_sb->prepath,
+					  CIFS_DIR_SEP(cifs_sb));
 			volume_info.prepath = NULL;
 		} else
 			cifs_sb->prepathlen = 0;
-- 
1.5.3.8



More information about the linux-cifs-client mailing list