[linux-cifs-client] [PATCH 3/7] [CIFS] add codepage= mount option and have it set up remote_nls

Jeff Layton jlayton at redhat.com
Fri Jul 25 15:23:16 GMT 2008


For non-ASCII, non-UTF8 legacy servers, we need to be able to translate
to and from their codepage. Add a "codepage" mount option that performs
a similar function to the one used in smbfs. The idea is to translate
strings to and from our local character set from and to the remote one.

Signed-off-by: Jeff Layton <jlayton at redhat.com>
---

 fs/cifs/cifs_fs_sb.h |    1 +
 fs/cifs/cifsfs.c     |    4 ++++
 fs/cifs/connect.c    |   29 +++++++++++++++++++++++++++++
 3 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 877c854..41e46b9 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -36,6 +36,7 @@ struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
 	struct list_head nested_tcon_q;
 	struct nls_table *local_nls;
+	struct nls_table *remote_nls;
 	unsigned int rsize;
 	unsigned int wsize;
 	uid_t	mnt_uid;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 22857c6..0fb9ff2 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -185,6 +185,8 @@ out_mount_failed:
 #endif
 		if (cifs_sb->local_nls)
 			unload_nls(cifs_sb->local_nls);
+		if (cifs_sb->remote_nls)
+			unload_nls(cifs_sb->remote_nls);
 		kfree(cifs_sb);
 	}
 	return rc;
@@ -213,6 +215,8 @@ cifs_put_super(struct super_block *sb)
 #endif
 
 	unload_nls(cifs_sb->local_nls);
+	if (cifs_sb->remote_nls)
+		unload_nls(cifs_sb->remote_nls);
 	kfree(cifs_sb);
 	return;
 }
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 0332961..f4cff66 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -62,6 +62,7 @@ struct smb_vol {
 	char *UNCip;
 	char *in6_addr;   /* ipv6 address as human readable form of in6_addr */
 	char *iocharset;  /* local code page for mapping to and from Unicode */
+	char *codepage;	  /* remote code page in use by server */
 	char source_rfc1001_name[16]; /* netbios name of client */
 	char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
 	uid_t linux_uid;
@@ -1086,6 +1087,21 @@ cifs_parse_mount_options(char *options, const char *devname,
 						    "too long.\n");
 				return 1;
 			}
+		} else if (strnicmp(data, "codepage", 8) == 0) {
+			if (!value || !*value) {
+				printk(KERN_WARNING "CIFS: invalid codepage "
+						    "specified\n");
+				return 1;	/* needs_arg; */
+			}
+			if (strnlen(value, 65) < 65) {
+				if (strnicmp(value, "default", 7))
+					vol->codepage = value;
+				cFYI(1, ("codepage set to %s", value));
+			} else {
+				printk(KERN_WARNING "CIFS: codepage name "
+						    "too long.\n");
+				return 1;
+			}
 		} else if (strnicmp(data, "uid", 3) == 0) {
 			if (value && *value) {
 				vol->linux_uid =
@@ -1941,6 +1957,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 		}
 	}
 
+	/* this is needed when non-ascii/non-utf8 codepage in use on server */
+	if (volume_info.codepage == NULL) {
+		cifs_sb->remote_nls = NULL;
+	} else {
+		cifs_sb->remote_nls = load_nls(volume_info.codepage);
+		if (cifs_sb->remote_nls == NULL) {
+			cERROR(1, ("CIFS mount error: codepage %s not found",
+				 volume_info.codepage));
+			rc = -ELIBACC;
+			goto out;
+		}
+	}
+
 	if (address_type == AF_INET)
 		existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
 			NULL /* no ipv6 addr */,



More information about the linux-cifs-client mailing list