Message ID | 1369270472-16408-1-git-send-email-jlayton@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, 22 May 2013 20:54:32 -0400 Jeff Layton <jlayton@redhat.com> wrote: > With the change to ignore the unc= and prefixpath= mount options, there > is no longer any need to add them to the options string when mounting. > By the same token, we now need to build a device name that includes the > prefixpath when mounting. > > To make things neater, the delimiters on the devicename are changed > to '/' since that's preferred when mounting anyway. > > While we're at it, fix a potential buffer overrun when building the > mount options string, if the new ip= option is much longer than the > original one. > > Signed-off-by: Jeff Layton <jlayton@redhat.com> > --- > fs/cifs/cifs_dfs_ref.c | 151 +++++++++++++++++++++++++++---------------------- > fs/cifs/dns_resolve.c | 4 +- > 2 files changed, 84 insertions(+), 71 deletions(-) > > diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c > index 8e33ec6..f4a19d1 100644 > --- a/fs/cifs/cifs_dfs_ref.c > +++ b/fs/cifs/cifs_dfs_ref.c > @@ -18,6 +18,7 @@ > #include <linux/slab.h> > #include <linux/vfs.h> > #include <linux/fs.h> > +#include <linux/inet.h> > #include "cifsglob.h" > #include "cifsproto.h" > #include "cifsfs.h" > @@ -48,58 +49,75 @@ void cifs_dfs_release_automount_timer(void) > } > > /** > - * cifs_get_share_name - extracts share name from UNC > - * @node_name: pointer to UNC string > + * cifs_build_devname - build a devicename from a UNC and optional prepath > + * @nodename: pointer to UNC string > + * @prepath: pointer to prefixpath (or NULL if there isn't one) > * > - * Extracts sharename form full UNC. > - * i.e. strips from UNC trailing path that is not part of share > - * name and fixup missing '\' in the beginning of DFS node refferal > - * if necessary. > - * Returns pointer to share name on success or ERR_PTR on error. > - * Caller is responsible for freeing returned string. > + * Build a new cifs devicename after chasing a DFS referral. Allocate a buffer > + * big enough to hold the final thing. Copy the UNC from the nodename, trimming > + * off anything after the sharename. Concatenate the prepath onto the end of it Sorry, the above comment is wrong and from an earlier version of this patch. The final version doesn't trim off anything after the sharename. It just concantenates the unconsumed portion of the fullpath onto the end of the referral node. Let me know if you want me to respin this or if I should just do a fix for the comments on top of this one. > + * if there is one. > + * > + * Returns pointer to the built string, or a ERR_PTR. Caller is responsible > + * for freeing the returned string. > */ > -static char *cifs_get_share_name(const char *node_name) > +static char * > +cifs_build_devname(char *nodename, const char *prepath) > { > - int len; > - char *UNC; > - char *pSep; > - > - len = strlen(node_name); > - UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */, > - GFP_KERNEL); > - if (!UNC) > - return ERR_PTR(-ENOMEM); > + size_t pplen; > + size_t unclen; > + char *dev; > + char *pos; > + > + /* skip over any preceding delimiters */ > + nodename += strspn(nodename, "\\"); > + if (!*nodename) > + return ERR_PTR(-EINVAL); > > - /* get share name and server name */ > - if (node_name[1] != '\\') { > - UNC[0] = '\\'; > - strncpy(UNC+1, node_name, len); > - len++; > - UNC[len] = 0; > - } else { > - strncpy(UNC, node_name, len); > - UNC[len] = 0; > - } > + /* get length of UNC and set pos to last char */ > + unclen = strlen(nodename); > + pos = nodename + unclen - 1; > > - /* find server name end */ > - pSep = memchr(UNC+2, '\\', len-2); > - if (!pSep) { > - cifs_dbg(VFS, "%s: no server name end in node name: %s\n", > - __func__, node_name); > - kfree(UNC); > - return ERR_PTR(-EINVAL); > + /* trim off any trailing delimiters */ > + while(*pos == '\\') { > + --pos; > + --unclen; > } > > - /* find sharename end */ > - pSep++; > - pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC)); > - if (pSep) { > - /* trim path up to sharename end > - * now we have share name in UNC */ > - *pSep = 0; > + /* allocate a buffer: > + * +2 for preceding "//" > + * +1 for delimiter between UNC and prepath > + * +1 for trailing NULL > + */ > + pplen = prepath ? strlen(prepath) : 0; > + dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL); > + if (!dev) > + return ERR_PTR(-ENOMEM); > + > + pos = dev; > + /* add the initial "//" */ > + *pos = '/'; > + ++pos; > + *pos = '/'; > + ++pos; > + > + /* copy in the UNC portion from referral */ > + memcpy(pos, nodename, unclen); > + pos += unclen; > + > + /* copy the prefixpath remainder (if there is one) */ > + if (pplen) { > + *pos = '/'; > + ++pos; > + memcpy(pos, prepath, pplen); > + pos += pplen; > } > > - return UNC; > + /* NULL terminator */ > + *pos = '\0'; > + > + convert_delimiter(dev, '/'); > + return dev; > } > > > @@ -123,6 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, > { > int rc; > char *mountdata = NULL; > + const char *prepath = NULL; > int md_len; > char *tkn_e; > char *srvIP = NULL; > @@ -132,7 +151,19 @@ char *cifs_compose_mount_options(const char *sb_mountdata, > if (sb_mountdata == NULL) > return ERR_PTR(-EINVAL); > > - *devname = cifs_get_share_name(ref->node_name); > + /* find & copy prefixpath */ > + tkn_e = strchr(ref->node_name + 2, '\\'); > + if (tkn_e == NULL) { > + /* invalid unc, missing share name*/ > + rc = -EINVAL; > + goto compose_mount_options_err; > + } > + > + tkn_e = strchr(tkn_e + 1, '\\'); > + if (tkn_e || (strlen(fullpath) - ref->path_consumed)) > + prepath = fullpath + ref->path_consumed; > + > + *devname = cifs_build_devname(ref->node_name, prepath); > if (IS_ERR(*devname)) { > rc = PTR_ERR(*devname); > *devname = NULL; > @@ -146,12 +177,14 @@ char *cifs_compose_mount_options(const char *sb_mountdata, > goto compose_mount_options_err; > } > > - /* md_len = strlen(...) + 12 for 'sep+prefixpath=' > - * assuming that we have 'unc=' and 'ip=' in > - * the original sb_mountdata > + /* > + * In most cases, we'll be building a shorter string than the original, > + * but we do have to assume that the address in the ip= option may be > + * much longer than the original. Add the max length of an address > + * string to the length of the original string to allow for worse case. > */ > - md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12; > - mountdata = kzalloc(md_len+1, GFP_KERNEL); > + md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN; > + mountdata = kzalloc(md_len + 1, GFP_KERNEL); > if (mountdata == NULL) { > rc = -ENOMEM; > goto compose_mount_options_err; > @@ -195,26 +228,6 @@ char *cifs_compose_mount_options(const char *sb_mountdata, > strncat(mountdata, &sep, 1); > strcat(mountdata, "ip="); > strcat(mountdata, srvIP); > - strncat(mountdata, &sep, 1); > - strcat(mountdata, "unc="); > - strcat(mountdata, *devname); > - > - /* find & copy prefixpath */ > - tkn_e = strchr(ref->node_name + 2, '\\'); > - if (tkn_e == NULL) { > - /* invalid unc, missing share name*/ > - rc = -EINVAL; > - goto compose_mount_options_err; > - } > - > - tkn_e = strchr(tkn_e + 1, '\\'); > - if (tkn_e || (strlen(fullpath) - ref->path_consumed)) { > - strncat(mountdata, &sep, 1); > - strcat(mountdata, "prefixpath="); > - if (tkn_e) > - strcat(mountdata, tkn_e + 1); > - strcat(mountdata, fullpath + ref->path_consumed); > - } > > /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/ > /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/ > diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c > index e7512e4..7ede730 100644 > --- a/fs/cifs/dns_resolve.c > +++ b/fs/cifs/dns_resolve.c > @@ -34,7 +34,7 @@ > > /** > * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address. > - * @unc: UNC path specifying the server > + * @unc: UNC path specifying the server (with '/' as delimiter) > * @ip_addr: Where to return the IP address. > * > * The IP address will be returned in string form, and the caller is > @@ -64,7 +64,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) > hostname = unc + 2; > > /* Search for server name delimiter */ > - sep = memchr(hostname, '\\', len); > + sep = memchr(hostname, '/', len); > if (sep) > len = sep - hostname; > else
I will try to fix the comment up - and we can always update it later. I will try to create the for 3.10 and for 3.11 branches later today (for-linus and for-next) so it is clearer what is going where On Thu, May 23, 2013 at 5:37 AM, Jeff Layton <jlayton@redhat.com> wrote: > > On Wed, 22 May 2013 20:54:32 -0400 > Jeff Layton <jlayton@redhat.com> wrote: > > > With the change to ignore the unc= and prefixpath= mount options, there > > is no longer any need to add them to the options string when mounting. > > By the same token, we now need to build a device name that includes the > > prefixpath when mounting. > > > > To make things neater, the delimiters on the devicename are changed > > to '/' since that's preferred when mounting anyway. > > > > While we're at it, fix a potential buffer overrun when building the > > mount options string, if the new ip= option is much longer than the > > original one. > > > > Signed-off-by: Jeff Layton <jlayton@redhat.com> > > --- > > fs/cifs/cifs_dfs_ref.c | 151 > > +++++++++++++++++++++++++++---------------------- > > fs/cifs/dns_resolve.c | 4 +- > > 2 files changed, 84 insertions(+), 71 deletions(-) > > > > diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c > > index 8e33ec6..f4a19d1 100644 > > --- a/fs/cifs/cifs_dfs_ref.c > > +++ b/fs/cifs/cifs_dfs_ref.c > > @@ -18,6 +18,7 @@ > > #include <linux/slab.h> > > #include <linux/vfs.h> > > #include <linux/fs.h> > > +#include <linux/inet.h> > > #include "cifsglob.h" > > #include "cifsproto.h" > > #include "cifsfs.h" > > @@ -48,58 +49,75 @@ void cifs_dfs_release_automount_timer(void) > > } > > > > /** > > - * cifs_get_share_name - extracts share name from UNC > > - * @node_name: pointer to UNC string > > + * cifs_build_devname - build a devicename from a UNC and optional > > prepath > > + * @nodename: pointer to UNC string > > + * @prepath: pointer to prefixpath (or NULL if there isn't one) > > * > > - * Extracts sharename form full UNC. > > - * i.e. strips from UNC trailing path that is not part of share > > - * name and fixup missing '\' in the beginning of DFS node refferal > > - * if necessary. > > - * Returns pointer to share name on success or ERR_PTR on error. > > - * Caller is responsible for freeing returned string. > > + * Build a new cifs devicename after chasing a DFS referral. Allocate a > > buffer > > + * big enough to hold the final thing. Copy the UNC from the nodename, > > trimming > > + * off anything after the sharename. Concatenate the prepath onto the > > end of it > > Sorry, the above comment is wrong and from an earlier version of this > patch. The final version doesn't trim off anything after the sharename. > It just concantenates the unconsumed portion of the fullpath onto the > end of the referral node. > > Let me know if you want me to respin this or if I should just do a fix > for the comments on top of this one. > > > + * if there is one. > > + * > > + * Returns pointer to the built string, or a ERR_PTR. Caller is > > responsible > > + * for freeing the returned string. > > */ > > -static char *cifs_get_share_name(const char *node_name) > > +static char * > > +cifs_build_devname(char *nodename, const char *prepath) > > { > > - int len; > > - char *UNC; > > - char *pSep; > > - > > - len = strlen(node_name); > > - UNC = kmalloc(len+2 /*for term null and additional \ if it's > > missed */, > > - GFP_KERNEL); > > - if (!UNC) > > - return ERR_PTR(-ENOMEM); > > + size_t pplen; > > + size_t unclen; > > + char *dev; > > + char *pos; > > + > > + /* skip over any preceding delimiters */ > > + nodename += strspn(nodename, "\\"); > > + if (!*nodename) > > + return ERR_PTR(-EINVAL); > > > > - /* get share name and server name */ > > - if (node_name[1] != '\\') { > > - UNC[0] = '\\'; > > - strncpy(UNC+1, node_name, len); > > - len++; > > - UNC[len] = 0; > > - } else { > > - strncpy(UNC, node_name, len); > > - UNC[len] = 0; > > - } > > + /* get length of UNC and set pos to last char */ > > + unclen = strlen(nodename); > > + pos = nodename + unclen - 1; > > > > - /* find server name end */ > > - pSep = memchr(UNC+2, '\\', len-2); > > - if (!pSep) { > > - cifs_dbg(VFS, "%s: no server name end in node name: %s\n", > > - __func__, node_name); > > - kfree(UNC); > > - return ERR_PTR(-EINVAL); > > + /* trim off any trailing delimiters */ > > + while(*pos == '\\') { > > + --pos; > > + --unclen; > > } > > > > - /* find sharename end */ > > - pSep++; > > - pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC)); > > - if (pSep) { > > - /* trim path up to sharename end > > - * now we have share name in UNC */ > > - *pSep = 0; > > + /* allocate a buffer: > > + * +2 for preceding "//" > > + * +1 for delimiter between UNC and prepath > > + * +1 for trailing NULL > > + */ > > + pplen = prepath ? strlen(prepath) : 0; > > + dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL); > > + if (!dev) > > + return ERR_PTR(-ENOMEM); > > + > > + pos = dev; > > + /* add the initial "//" */ > > + *pos = '/'; > > + ++pos; > > + *pos = '/'; > > + ++pos; > > + > > + /* copy in the UNC portion from referral */ > > + memcpy(pos, nodename, unclen); > > + pos += unclen; > > + > > + /* copy the prefixpath remainder (if there is one) */ > > + if (pplen) { > > + *pos = '/'; > > + ++pos; > > + memcpy(pos, prepath, pplen); > > + pos += pplen; > > } > > > > - return UNC; > > + /* NULL terminator */ > > + *pos = '\0'; > > + > > + convert_delimiter(dev, '/'); > > + return dev; > > } > > > > > > @@ -123,6 +141,7 @@ char *cifs_compose_mount_options(const char > > *sb_mountdata, > > { > > int rc; > > char *mountdata = NULL; > > + const char *prepath = NULL; > > int md_len; > > char *tkn_e; > > char *srvIP = NULL; > > @@ -132,7 +151,19 @@ char *cifs_compose_mount_options(const char > > *sb_mountdata, > > if (sb_mountdata == NULL) > > return ERR_PTR(-EINVAL); > > > > - *devname = cifs_get_share_name(ref->node_name); > > + /* find & copy prefixpath */ > > + tkn_e = strchr(ref->node_name + 2, '\\'); > > + if (tkn_e == NULL) { > > + /* invalid unc, missing share name*/ > > + rc = -EINVAL; > > + goto compose_mount_options_err; > > + } > > + > > + tkn_e = strchr(tkn_e + 1, '\\'); > > + if (tkn_e || (strlen(fullpath) - ref->path_consumed)) > > + prepath = fullpath + ref->path_consumed; > > + > > + *devname = cifs_build_devname(ref->node_name, prepath); > > if (IS_ERR(*devname)) { > > rc = PTR_ERR(*devname); > > *devname = NULL; > > @@ -146,12 +177,14 @@ char *cifs_compose_mount_options(const char > > *sb_mountdata, > > goto compose_mount_options_err; > > } > > > > - /* md_len = strlen(...) + 12 for 'sep+prefixpath=' > > - * assuming that we have 'unc=' and 'ip=' in > > - * the original sb_mountdata > > + /* > > + * In most cases, we'll be building a shorter string than the > > original, > > + * but we do have to assume that the address in the ip= option may > > be > > + * much longer than the original. Add the max length of an address > > + * string to the length of the original string to allow for worse > > case. > > */ > > - md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12; > > - mountdata = kzalloc(md_len+1, GFP_KERNEL); > > + md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN; > > + mountdata = kzalloc(md_len + 1, GFP_KERNEL); > > if (mountdata == NULL) { > > rc = -ENOMEM; > > goto compose_mount_options_err; > > @@ -195,26 +228,6 @@ char *cifs_compose_mount_options(const char > > *sb_mountdata, > > strncat(mountdata, &sep, 1); > > strcat(mountdata, "ip="); > > strcat(mountdata, srvIP); > > - strncat(mountdata, &sep, 1); > > - strcat(mountdata, "unc="); > > - strcat(mountdata, *devname); > > - > > - /* find & copy prefixpath */ > > - tkn_e = strchr(ref->node_name + 2, '\\'); > > - if (tkn_e == NULL) { > > - /* invalid unc, missing share name*/ > > - rc = -EINVAL; > > - goto compose_mount_options_err; > > - } > > - > > - tkn_e = strchr(tkn_e + 1, '\\'); > > - if (tkn_e || (strlen(fullpath) - ref->path_consumed)) { > > - strncat(mountdata, &sep, 1); > > - strcat(mountdata, "prefixpath="); > > - if (tkn_e) > > - strcat(mountdata, tkn_e + 1); > > - strcat(mountdata, fullpath + ref->path_consumed); > > - } > > > > /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, > > sb_mountdata);*/ > > /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, > > mountdata );*/ > > diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c > > index e7512e4..7ede730 100644 > > --- a/fs/cifs/dns_resolve.c > > +++ b/fs/cifs/dns_resolve.c > > @@ -34,7 +34,7 @@ > > > > /** > > * dns_resolve_server_name_to_ip - Resolve UNC server name to ip > > address. > > - * @unc: UNC path specifying the server > > + * @unc: UNC path specifying the server (with '/' as delimiter) > > * @ip_addr: Where to return the IP address. > > * > > * The IP address will be returned in string form, and the caller is > > @@ -64,7 +64,7 @@ dns_resolve_server_name_to_ip(const char *unc, char > > **ip_addr) > > hostname = unc + 2; > > > > /* Search for server name delimiter */ > > - sep = memchr(hostname, '\\', len); > > + sep = memchr(hostname, '/', len); > > if (sep) > > len = sep - hostname; > > else > > > -- > Jeff Layton <jlayton@redhat.com> -- Thanks, Steve -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, 23 May 2013 07:48:21 -0500 Steve French <smfrench@gmail.com> wrote: > I will try to fix the comment up - and we can always update it later. I > will try to create the for 3.10 and for 3.11 branches later today > (for-linus and for-next) so it is clearer what is going where > Ok, thanks. I think all of the patches I sent yesterday are candidates for 3.10. It's good to have a consistency when it comes to mount options, and we want DFS to continue working.
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 8e33ec6..f4a19d1 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/vfs.h> #include <linux/fs.h> +#include <linux/inet.h> #include "cifsglob.h" #include "cifsproto.h" #include "cifsfs.h" @@ -48,58 +49,75 @@ void cifs_dfs_release_automount_timer(void) } /** - * cifs_get_share_name - extracts share name from UNC - * @node_name: pointer to UNC string + * cifs_build_devname - build a devicename from a UNC and optional prepath + * @nodename: pointer to UNC string + * @prepath: pointer to prefixpath (or NULL if there isn't one) * - * Extracts sharename form full UNC. - * i.e. strips from UNC trailing path that is not part of share - * name and fixup missing '\' in the beginning of DFS node refferal - * if necessary. - * Returns pointer to share name on success or ERR_PTR on error. - * Caller is responsible for freeing returned string. + * Build a new cifs devicename after chasing a DFS referral. Allocate a buffer + * big enough to hold the final thing. Copy the UNC from the nodename, trimming + * off anything after the sharename. Concatenate the prepath onto the end of it + * if there is one. + * + * Returns pointer to the built string, or a ERR_PTR. Caller is responsible + * for freeing the returned string. */ -static char *cifs_get_share_name(const char *node_name) +static char * +cifs_build_devname(char *nodename, const char *prepath) { - int len; - char *UNC; - char *pSep; - - len = strlen(node_name); - UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */, - GFP_KERNEL); - if (!UNC) - return ERR_PTR(-ENOMEM); + size_t pplen; + size_t unclen; + char *dev; + char *pos; + + /* skip over any preceding delimiters */ + nodename += strspn(nodename, "\\"); + if (!*nodename) + return ERR_PTR(-EINVAL); - /* get share name and server name */ - if (node_name[1] != '\\') { - UNC[0] = '\\'; - strncpy(UNC+1, node_name, len); - len++; - UNC[len] = 0; - } else { - strncpy(UNC, node_name, len); - UNC[len] = 0; - } + /* get length of UNC and set pos to last char */ + unclen = strlen(nodename); + pos = nodename + unclen - 1; - /* find server name end */ - pSep = memchr(UNC+2, '\\', len-2); - if (!pSep) { - cifs_dbg(VFS, "%s: no server name end in node name: %s\n", - __func__, node_name); - kfree(UNC); - return ERR_PTR(-EINVAL); + /* trim off any trailing delimiters */ + while(*pos == '\\') { + --pos; + --unclen; } - /* find sharename end */ - pSep++; - pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC)); - if (pSep) { - /* trim path up to sharename end - * now we have share name in UNC */ - *pSep = 0; + /* allocate a buffer: + * +2 for preceding "//" + * +1 for delimiter between UNC and prepath + * +1 for trailing NULL + */ + pplen = prepath ? strlen(prepath) : 0; + dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + pos = dev; + /* add the initial "//" */ + *pos = '/'; + ++pos; + *pos = '/'; + ++pos; + + /* copy in the UNC portion from referral */ + memcpy(pos, nodename, unclen); + pos += unclen; + + /* copy the prefixpath remainder (if there is one) */ + if (pplen) { + *pos = '/'; + ++pos; + memcpy(pos, prepath, pplen); + pos += pplen; } - return UNC; + /* NULL terminator */ + *pos = '\0'; + + convert_delimiter(dev, '/'); + return dev; } @@ -123,6 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, { int rc; char *mountdata = NULL; + const char *prepath = NULL; int md_len; char *tkn_e; char *srvIP = NULL; @@ -132,7 +151,19 @@ char *cifs_compose_mount_options(const char *sb_mountdata, if (sb_mountdata == NULL) return ERR_PTR(-EINVAL); - *devname = cifs_get_share_name(ref->node_name); + /* find & copy prefixpath */ + tkn_e = strchr(ref->node_name + 2, '\\'); + if (tkn_e == NULL) { + /* invalid unc, missing share name*/ + rc = -EINVAL; + goto compose_mount_options_err; + } + + tkn_e = strchr(tkn_e + 1, '\\'); + if (tkn_e || (strlen(fullpath) - ref->path_consumed)) + prepath = fullpath + ref->path_consumed; + + *devname = cifs_build_devname(ref->node_name, prepath); if (IS_ERR(*devname)) { rc = PTR_ERR(*devname); *devname = NULL; @@ -146,12 +177,14 @@ char *cifs_compose_mount_options(const char *sb_mountdata, goto compose_mount_options_err; } - /* md_len = strlen(...) + 12 for 'sep+prefixpath=' - * assuming that we have 'unc=' and 'ip=' in - * the original sb_mountdata + /* + * In most cases, we'll be building a shorter string than the original, + * but we do have to assume that the address in the ip= option may be + * much longer than the original. Add the max length of an address + * string to the length of the original string to allow for worse case. */ - md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12; - mountdata = kzalloc(md_len+1, GFP_KERNEL); + md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN; + mountdata = kzalloc(md_len + 1, GFP_KERNEL); if (mountdata == NULL) { rc = -ENOMEM; goto compose_mount_options_err; @@ -195,26 +228,6 @@ char *cifs_compose_mount_options(const char *sb_mountdata, strncat(mountdata, &sep, 1); strcat(mountdata, "ip="); strcat(mountdata, srvIP); - strncat(mountdata, &sep, 1); - strcat(mountdata, "unc="); - strcat(mountdata, *devname); - - /* find & copy prefixpath */ - tkn_e = strchr(ref->node_name + 2, '\\'); - if (tkn_e == NULL) { - /* invalid unc, missing share name*/ - rc = -EINVAL; - goto compose_mount_options_err; - } - - tkn_e = strchr(tkn_e + 1, '\\'); - if (tkn_e || (strlen(fullpath) - ref->path_consumed)) { - strncat(mountdata, &sep, 1); - strcat(mountdata, "prefixpath="); - if (tkn_e) - strcat(mountdata, tkn_e + 1); - strcat(mountdata, fullpath + ref->path_consumed); - } /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/ /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/ diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index e7512e4..7ede730 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c @@ -34,7 +34,7 @@ /** * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address. - * @unc: UNC path specifying the server + * @unc: UNC path specifying the server (with '/' as delimiter) * @ip_addr: Where to return the IP address. * * The IP address will be returned in string form, and the caller is @@ -64,7 +64,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) hostname = unc + 2; /* Search for server name delimiter */ - sep = memchr(hostname, '\\', len); + sep = memchr(hostname, '/', len); if (sep) len = sep - hostname; else
With the change to ignore the unc= and prefixpath= mount options, there is no longer any need to add them to the options string when mounting. By the same token, we now need to build a device name that includes the prefixpath when mounting. To make things neater, the delimiters on the devicename are changed to '/' since that's preferred when mounting anyway. While we're at it, fix a potential buffer overrun when building the mount options string, if the new ip= option is much longer than the original one. Signed-off-by: Jeff Layton <jlayton@redhat.com> --- fs/cifs/cifs_dfs_ref.c | 151 +++++++++++++++++++++++++++---------------------- fs/cifs/dns_resolve.c | 4 +- 2 files changed, 84 insertions(+), 71 deletions(-)