[SCM] Samba Shared Repository - branch v3-2-test updated - release-3-2-0pre2-565-ge03d1df

Simo Sorce idra at samba.org
Mon Mar 31 20:10:10 GMT 2008


The branch, v3-2-test has been updated
       via  e03d1dfdb80333c071b600245eb749ef5664aa22 (commit)
      from  0c94918fb52c5345ce30490046b79f81712c30bf (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-2-test


- Log -----------------------------------------------------------------
commit e03d1dfdb80333c071b600245eb749ef5664aa22
Author: Jeff Layton <jlayton at redhat.com>
Date:   Mon Mar 10 15:54:36 2008 -0400

    mount.cifs: fix several problems when mounting subdirectories of shares (try 2)
    
    This patch is the second patch to attempt to fix up some of the problems
    with mounting subdirectories of shares. The earlier patch didn't handle
    this correctly when POSIX extensions were enabled. This one does.
    
    This is a bit of a confusing area since the different components of
    a service string have different rules:
    
    1) hostname: no '/' (slash) or '\' (backslash) is allowed to be
    	     embedded within the string
    
    2) sharename: same rules as hostname
    
    3) prefixpath: '\' *is* allowed to be embedded in a path component,
    	       iff POSIX extensions are enabled. Otherwise, neither
    	       character is allowed.
    
    The idea here is to allow either character to act as a delimiter when we
    know that the character can't be anything but a delimiter (namely
    everywhere up to the start of the prefixpath). The patch will convert
    any '\' unconditionally to '/' in the UNC portion of the string.
    
    However, inside the prefixpath, we can't make assumptions about what
    constitutes a delimiter because POSIX allows for embedded '\'
    characters. So there we don't attempt to do any conversion, and pass the
    prefixpath to the kernel as is. Once the kernel determines whether POSIX
    extensions are enabled, it can then convert the path if needed and it's
    able to do so. A patch to handle this has already been committed to the
    cifs-2.6 git tree.
    
    This patch also fixes an annoyance. When you mount a subdir of a share,
    mount.cifs munges the device string so that you can't tell what the
    prefixpath is. So if I mount:
    
    	//server/share/p1/p2/p3
    
    ..then /proc/mounts and mtab will show only:
    
    	//server/share
    
    Finally, it also tries to apply some consistent rules to the uppercasing
    of strings.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

-----------------------------------------------------------------------

Summary of changes:
 source/client/mount.cifs.c |   90 ++++++++++++++++++++++++++++++++------------
 1 files changed, 66 insertions(+), 24 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/client/mount.cifs.c b/source/client/mount.cifs.c
index e73d908..fdee87a 100644
--- a/source/client/mount.cifs.c
+++ b/source/client/mount.cifs.c
@@ -63,6 +63,8 @@
 #define MS_BIND 4096
 #endif
 
+#define MAX_UNC_LEN 1024
+
 #define CONST_DISCARD(type, ptr)      ((type) ((void *) (ptr)))
 
 const char *thisprogram;
@@ -74,7 +76,6 @@ static int got_ip = 0;
 static int got_unc = 0;
 static int got_uid = 0;
 static int got_gid = 0;
-static int free_share_name = 0;
 static char * user_name = NULL;
 static char * mountpassword = NULL;
 char * domain_name = NULL;
@@ -837,17 +838,31 @@ static char * check_for_domain(char **ppuser)
 	return domainnm;
 }
 
+/* replace all occurances of "from" in a string with "to" */
+static void replace_char(char *string, char from, char to, int maxlen)
+{
+	char *lastchar = string + maxlen;
+	while (string) {
+		string = strchr(string, from);
+		if (string) {
+			*string = to;
+			if (string >= lastchar)
+				return;
+		}
+	}
+}
+
 /* Note that caller frees the returned buffer if necessary */
 static char * parse_server(char ** punc_name)
 {
 	char * unc_name = *punc_name;
-	int length = strnlen(unc_name,1024);
+	int length = strnlen(unc_name, MAX_UNC_LEN);
 	char * share;
 	char * ipaddress_string = NULL;
 	struct hostent * host_entry = NULL;
 	struct in_addr server_ipaddr;
 
-	if(length > 1023) {
+	if(length > (MAX_UNC_LEN - 1)) {
 		printf("mount error: UNC name too long");
 		return NULL;
 	}
@@ -866,7 +881,6 @@ static char * parse_server(char ** punc_name)
 			/* check for nfs syntax ie server:share */
 			share = strchr(unc_name,':');
 			if(share) {
-				free_share_name = 1;
 				*punc_name = (char *)malloc(length+3);
 				if(*punc_name == NULL) {
 					/* put the original string back  if 
@@ -874,9 +888,9 @@ static char * parse_server(char ** punc_name)
 					*punc_name = unc_name;
 					return NULL;
 				}
-					
 				*share = '/';
 				strncpy((*punc_name)+2,unc_name,length);
+				free(unc_name);
 				unc_name = *punc_name;
 				unc_name[length+2] = 0;
 				goto continue_unc_parsing;
@@ -890,15 +904,18 @@ continue_unc_parsing:
 			unc_name[0] = '/';
 			unc_name[1] = '/';
 			unc_name += 2;
-			if ((share = strchr(unc_name, '/')) || 
-				(share = strchr(unc_name,'\\'))) {
+
+			/* allow for either delimiter between host and sharename */
+			if ((share = strpbrk(unc_name, "/\\"))) {
 				*share = 0;  /* temporarily terminate the string */
 				share += 1;
 				if(got_ip == 0) {
 					host_entry = gethostbyname(unc_name);
 				}
-				*(share - 1) = '/'; /* put the slash back */
-				if ((prefixpath = strchr(share, '/'))) {
+				*(share - 1) = '/'; /* put delimiter back */
+
+				/* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
+				if ((prefixpath = strpbrk(share, "/\\"))) {
 					*prefixpath = 0;  /* permanently terminate the string */
 					if (!strlen(++prefixpath))
 						prefixpath = NULL; /* this needs to be done explicitly */
@@ -963,6 +980,25 @@ static struct option longopts[] = {
 	{ NULL, 0, NULL, 0 }
 };
 
+/* convert a string to uppercase. return false if the string
+ * wasn't ASCII or was a NULL ptr */
+static int
+uppercase_string(char *string)
+{
+	if (!string)
+		return 0;
+
+	while (*string) {
+		/* check for unicode */
+		if ((unsigned char) string[0] & 0x80)
+			return 0;
+		*string = toupper((unsigned char) *string);
+		string++;
+	}
+
+	return 1;
+}
+
 int main(int argc, char ** argv)
 {
 	int c;
@@ -975,6 +1011,7 @@ int main(int argc, char ** argv)
 	char * options = NULL;
 	char * resolved_path = NULL;
 	char * temp;
+	char * dev_name;
 	int rc;
 	int rsize = 0;
 	int wsize = 0;
@@ -1011,8 +1048,16 @@ int main(int argc, char ** argv)
 	printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
 #endif */
 	if(argc > 2) {
-		share_name = argv[1];
+		dev_name = argv[1];
+		share_name = strndup(argv[1], MAX_UNC_LEN);
+		if (share_name == NULL) {
+			fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
+			exit(1);
+		}
 		mountpoint = argv[2];
+	} else {
+		mount_cifs_usage();
+		exit(1);
 	}
 
 	/* add sharename in opts string as unc= parm */
@@ -1152,7 +1197,7 @@ int main(int argc, char ** argv)
 		}
 	}
 
-	if((argc < 3) || (share_name == NULL) || (mountpoint == NULL)) {
+	if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
 		mount_cifs_usage();
 		exit(1);
 	}
@@ -1310,10 +1355,12 @@ mount_retry:
 	}
 	if(verboseflag)
 		printf("\nmount.cifs kernel mount options %s \n",options);
-	if(mount(share_name, mountpoint, "cifs", flags, options)) {
-	/* remember to kill daemon on error */
-		char * tmp;
 
+	/* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
+	replace_char(dev_name, '\\', '/', strlen(share_name));
+
+	if(mount(dev_name, mountpoint, "cifs", flags, options)) {
+	/* remember to kill daemon on error */
 		switch (errno) {
 		case 0:
 			printf("mount failed but no error number set\n");
@@ -1324,12 +1371,9 @@ mount_retry:
 		case ENXIO:
 			if(retry == 0) {
 				retry = 1;
-				tmp = share_name;
-				while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
-					*tmp = toupper((unsigned char)*tmp);
-		        		tmp++;
-				}
-				if(!*tmp) {
+				if (uppercase_string(dev_name) &&
+				    uppercase_string(share_name) &&
+				    uppercase_string(prefixpath)) {
 					printf("retrying with upper case share name\n");
 					goto mount_retry;
 				}
@@ -1343,7 +1387,7 @@ mount_retry:
 	} else {
 		pmntfile = setmntent(MOUNTED, "a+");
 		if(pmntfile) {
-			mountent.mnt_fsname = share_name;
+			mountent.mnt_fsname = dev_name;
 			mountent.mnt_dir = mountpoint;
 			mountent.mnt_type = CONST_DISCARD(char *,"cifs");
 			mountent.mnt_opts = (char *)malloc(220);
@@ -1403,8 +1447,6 @@ mount_exit:
 		free(resolved_path);
 	}
 
-	if(free_share_name) {
-		free(share_name);
-		}
+	free(share_name);
 	return rc;
 }


-- 
Samba Shared Repository


More information about the samba-cvs mailing list