cifs: parse the device name into UNC and prepath
This should fix a regression that was introduced when the new mount option parser went in. Also, when the unc= and prefixpath= options are provided, check their values against the ones we parsed from the device string. If they differ, then throw a warning that tells the user that we're using the values from the unc= option for now, but that that will change in 3.10. Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								839db3d10a
							
						
					
				
			
			
				commit
				
					
						d387a5c50b
					
				
			
		
					 1 changed files with 88 additions and 7 deletions
				
			
		| 
						 | 
					@ -1096,6 +1096,52 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Parse a devname into substrings and populate the vol->UNC and vol->prepath
 | 
				
			||||||
 | 
					 * fields with the result. Returns 0 on success and an error otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					cifs_parse_devname(const char *devname, struct smb_vol *vol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *pos;
 | 
				
			||||||
 | 
						const char *delims = "/\\";
 | 
				
			||||||
 | 
						size_t len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* make sure we have a valid UNC double delimiter prefix */
 | 
				
			||||||
 | 
						len = strspn(devname, delims);
 | 
				
			||||||
 | 
						if (len != 2)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* find delimiter between host and sharename */
 | 
				
			||||||
 | 
						pos = strpbrk(devname + 2, delims);
 | 
				
			||||||
 | 
						if (!pos)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* skip past delimiter */
 | 
				
			||||||
 | 
						++pos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* now go until next delimiter or end of string */
 | 
				
			||||||
 | 
						len = strcspn(pos, delims);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* move "pos" up to delimiter or NULL */
 | 
				
			||||||
 | 
						pos += len;
 | 
				
			||||||
 | 
						vol->UNC = kstrndup(devname, pos - devname, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!vol->UNC)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						convert_delimiter(vol->UNC, '\\');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If pos is NULL, or is a bogus trailing delimiter then no prepath */
 | 
				
			||||||
 | 
						if (!*pos++ || !*pos)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vol->prepath = kstrdup(pos, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!vol->prepath)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
cifs_parse_mount_options(const char *mountdata, const char *devname,
 | 
					cifs_parse_mount_options(const char *mountdata, const char *devname,
 | 
				
			||||||
			 struct smb_vol *vol)
 | 
								 struct smb_vol *vol)
 | 
				
			||||||
| 
						 | 
					@ -1181,6 +1227,16 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 | 
				
			||||||
	vol->backupuid_specified = false; /* no backup intent for a user */
 | 
						vol->backupuid_specified = false; /* no backup intent for a user */
 | 
				
			||||||
	vol->backupgid_specified = false; /* no backup intent for a group */
 | 
						vol->backupgid_specified = false; /* no backup intent for a group */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * For now, we ignore -EINVAL errors under the assumption that the
 | 
				
			||||||
 | 
						 * unc= and prefixpath= options will be usable.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (cifs_parse_devname(devname, vol) == -ENOMEM) {
 | 
				
			||||||
 | 
							printk(KERN_ERR "CIFS: Unable to allocate memory to parse "
 | 
				
			||||||
 | 
									"device string.\n");
 | 
				
			||||||
 | 
							goto out_nomem;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((data = strsep(&options, separator)) != NULL) {
 | 
						while ((data = strsep(&options, separator)) != NULL) {
 | 
				
			||||||
		substring_t args[MAX_OPT_ARGS];
 | 
							substring_t args[MAX_OPT_ARGS];
 | 
				
			||||||
		unsigned long option;
 | 
							unsigned long option;
 | 
				
			||||||
| 
						 | 
					@ -1566,18 +1622,31 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 | 
				
			||||||
			got_ip = true;
 | 
								got_ip = true;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case Opt_unc:
 | 
							case Opt_unc:
 | 
				
			||||||
			kfree(vol->UNC);
 | 
								string = vol->UNC;
 | 
				
			||||||
			vol->UNC = match_strdup(args);
 | 
								vol->UNC = match_strdup(args);
 | 
				
			||||||
			if (vol->UNC == NULL)
 | 
								if (vol->UNC == NULL) {
 | 
				
			||||||
 | 
									kfree(string);
 | 
				
			||||||
				goto out_nomem;
 | 
									goto out_nomem;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			convert_delimiter(vol->UNC, '\\');
 | 
								convert_delimiter(vol->UNC, '\\');
 | 
				
			||||||
			if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') {
 | 
								if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') {
 | 
				
			||||||
				printk(KERN_WARNING "CIFS: UNC Path does not "
 | 
									kfree(string);
 | 
				
			||||||
 | 
									printk(KERN_ERR "CIFS: UNC Path does not "
 | 
				
			||||||
						"begin with // or \\\\\n");
 | 
											"begin with // or \\\\\n");
 | 
				
			||||||
				goto cifs_parse_mount_err;
 | 
									goto cifs_parse_mount_err;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* Compare old unc= option to new one */
 | 
				
			||||||
 | 
								if (!string || strcmp(string, vol->UNC))
 | 
				
			||||||
 | 
									printk(KERN_WARNING "CIFS: the value of the "
 | 
				
			||||||
 | 
										"unc= mount option does not match the "
 | 
				
			||||||
 | 
										"device string. Using the unc= option "
 | 
				
			||||||
 | 
										"for now. In 3.10, that option will "
 | 
				
			||||||
 | 
										"be ignored and the contents of the "
 | 
				
			||||||
 | 
										"device string will be used "
 | 
				
			||||||
 | 
										"instead. (%s != %s)\n", string,
 | 
				
			||||||
 | 
										vol->UNC);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case Opt_domain:
 | 
							case Opt_domain:
 | 
				
			||||||
			string = match_strdup(args);
 | 
								string = match_strdup(args);
 | 
				
			||||||
| 
						 | 
					@ -1616,10 +1685,22 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 | 
				
			||||||
			if (*args[0].from == '/' || *args[0].from == '\\')
 | 
								if (*args[0].from == '/' || *args[0].from == '\\')
 | 
				
			||||||
				args[0].from++;
 | 
									args[0].from++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			kfree(vol->prepath);
 | 
								string = vol->prepath;
 | 
				
			||||||
			vol->prepath = match_strdup(args);
 | 
								vol->prepath = match_strdup(args);
 | 
				
			||||||
			if (vol->prepath == NULL)
 | 
								if (vol->prepath == NULL) {
 | 
				
			||||||
 | 
									kfree(string);
 | 
				
			||||||
				goto out_nomem;
 | 
									goto out_nomem;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								/* Compare old prefixpath= option to new one */
 | 
				
			||||||
 | 
								if (!string || strcmp(string, vol->prepath))
 | 
				
			||||||
 | 
									printk(KERN_WARNING "CIFS: the value of the "
 | 
				
			||||||
 | 
										"prefixpath= mount option does not "
 | 
				
			||||||
 | 
										"match the device string. Using the "
 | 
				
			||||||
 | 
										"prefixpath= option for now. In 3.10, "
 | 
				
			||||||
 | 
										"that option will be ignored and the "
 | 
				
			||||||
 | 
										"contents of the device string will be "
 | 
				
			||||||
 | 
										"used instead.(%s != %s)\n", string,
 | 
				
			||||||
 | 
										vol->prepath);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case Opt_iocharset:
 | 
							case Opt_iocharset:
 | 
				
			||||||
			string = match_strdup(args);
 | 
								string = match_strdup(args);
 | 
				
			||||||
| 
						 | 
					@ -1777,8 +1858,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if (!vol->UNC) {
 | 
						if (!vol->UNC) {
 | 
				
			||||||
		cERROR(1, "CIFS mount error: No UNC path (e.g. -o "
 | 
							cERROR(1, "CIFS mount error: No usable UNC path provided in "
 | 
				
			||||||
			"unc=\\\\192.168.1.100\\public) specified");
 | 
								  "device string or in unc= option!");
 | 
				
			||||||
		goto cifs_parse_mount_err;
 | 
							goto cifs_parse_mount_err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue