The branch, v3-0-test has been updated via f94e4619d1b2985881ec7ed76587057f00fbf1f7 (commit) via e8f569735e2c0523efa175ca44dd919f838ae49e (commit) from 76dcbbd1213ebf0212997d9a0599c894076d77bb (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-0-test - Log ----------------------------------------------------------------- commit f94e4619d1b2985881ec7ed76587057f00fbf1f7 Merge: e8f569735e2c0523efa175ca44dd919f838ae49e 76dcbbd1213ebf0212997d9a0599c894076d77bb Author: Simo Sorce <[EMAIL PROTECTED]> Date: Mon Dec 17 09:40:10 2007 -0500 Resolve conflict of merging in J.Layton patch Merge branch 'v3-0-test' of ssh://git.samba.org/data/git/samba into v3-0-simo Conflicts: source/client/mount.cifs.c commit e8f569735e2c0523efa175ca44dd919f838ae49e Author: Jeff Layton <[EMAIL PROTECTED]> Date: Tue Nov 13 09:04:33 2007 -0500 mount.cifs: fix several problems when mounting subdirectories of shares This is essentially the same patch as I posted yesterday. The only difference is that I added the replace_char helper function and now have the code call it instead of doing the conversion internally. Thoughts? -------[snip]------- CIFS has a few problems when mounting subdirectories of shares: a) mount.cifs assumes that the prefixpath will always begin with a forward slash. If it begins with a backslash, then it fails to parse out the prefixpath and leaves it appended to the sharename. This causes the mount to fail. b) if the prefixpath uses '/' as a delimiter, it doesn't convert that to a "native" prefixpath ('\\' delimiter). The kernel will blindly stuff this prefix into the beginning of a path when it builds one from a dentry, and this confuses windows servers (samba doesn't seem to care). c) 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 d) If the client has to retry the mount with an uppercase sharename, it doesn't also uppercase the prefixpath (not sure if that's a real issue, but it seems inconsistent). The following patch fixes all of these problems. It separates the "share_name" from the "device_name", and passes the share_name as the unc= string, and the device_name as the first arg to mount(), and to setmntent(). It also changes mount.cifs to use '\\' exclusively as a delimiter for the unc= and prefixpath= options, and to use '/' exclusively as a delimiter in the device string (seemingly necessary since the kernel doesn't deal well with backslashes in the device string). Signed-off-by: Jeff Layton <[EMAIL PROTECTED]> ----------------------------------------------------------------------- Summary of changes: source/client/mount.cifs.c | 94 +++++++++++++++++++++++++++++++------------- 1 files changed, 66 insertions(+), 28 deletions(-) mode change 100755 => 100644 source/client/mount.cifs.c Changeset truncated at 500 lines: diff --git a/source/client/mount.cifs.c b/source/client/mount.cifs.c old mode 100755 new mode 100644 index 33da1a2..3761adb --- 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; @@ -829,17 +830,27 @@ 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) +{ + while (string) { + string = strchr(string, from); + if (string) + *string = to; + } +} + /* 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; } @@ -858,7 +869,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 @@ -866,9 +876,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; @@ -879,18 +889,21 @@ static char * parse_server(char ** punc_name) } } else { continue_unc_parsing: - unc_name[0] = '/'; - unc_name[1] = '/'; + unc_name[0] = '\\'; + unc_name[1] = '\\'; unc_name += 2; - if ((share = strchr(unc_name, '/')) || - (share = strchr(unc_name,'\\'))) { + + /* convert any '/' in unc to '\\' */ + replace_char(unc_name, '/', '\\'); + + if ((share = strchr(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 */ + if ((prefixpath = strchr(share, '\\'))) { *prefixpath = 0; /* permanently terminate the string */ if (!strlen(++prefixpath)) prefixpath = NULL; /* this needs to be done explicitly */ @@ -955,6 +968,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; @@ -967,6 +999,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; @@ -1003,8 +1036,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 */ @@ -1144,7 +1185,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); } @@ -1302,10 +1343,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 '/' so that /proc/mounts looks pretty */ + replace_char(dev_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"); @@ -1316,12 +1359,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; } @@ -1335,9 +1375,9 @@ mount_retry: } else { pmntfile = setmntent(MOUNTED, "a+"); if(pmntfile) { - mountent.mnt_fsname = share_name; - mountent.mnt_dir = mountpoint; - mountent.mnt_type = CONST_DISCARD(char *,"cifs"); + mountent.mnt_fsname = dev_name; + mountent.mnt_dir = mountpoint; + mountent.mnt_type = CONST_DISCARD(char *,"cifs"); mountent.mnt_opts = (char *)malloc(220); if(mountent.mnt_opts) { char * mount_user = getusername(); @@ -1395,8 +1435,6 @@ mount_exit: free(resolved_path); } - if(free_share_name) { - free(share_name); - } + free(share_name); return rc; } -- Samba Shared Repository