/** * cifs_compose_mount_options - creates mount options for refferral * @sb_mountdata: parent/root DFS mount options (template) * @fullpath: full path in UNC format * @ref: server's referral * @devname: pointer for saving device name * * creates mount options for submount based on template options sb_mountdata * and replacing unc,ip,prefixpath options with ones we've got form ref_unc. * * Returns: pointer to new mount options or ERR_PTR. * Caller is responcible for freeing retunrned value if it is not error. */ char *cifs_compose_mount_options(const char *sb_mountdata, const char *fullpath, const struct dfs_info3_param *ref, char **devname) { int rc; char *mountdata = NULL; int md_len; char *tkn_e; char *srvIP = NULL; char sep = ','; int off, noff; if (sb_mountdata == NULL) return ERR_PTR(-EINVAL); *devname = cifs_get_share_name(ref->node_name); if (IS_ERR(*devname)) { rc = PTR_ERR(*devname); *devname = NULL; goto compose_mount_options_err; } rc = dns_resolve_server_name_to_ip(*devname, &srvIP); if (rc < 0) { cERROR(1, "%s: Failed to resolve server part of %s to IP: %d", __func__, *devname, rc); goto compose_mount_options_err; } /* md_len = strlen(...) + 12 for 'sep+prefixpath=' * assuming that we have 'unc=' and 'ip=' in * the original sb_mountdata */ md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12; mountdata = kzalloc(md_len+1, GFP_KERNEL); if (mountdata == NULL) { rc = -ENOMEM; goto compose_mount_options_err; } /* copy all options except of unc,ip,prefixpath */ off = 0; if (strncmp(sb_mountdata, "sep=", 4) == 0) { sep = sb_mountdata[4]; strncpy(mountdata, sb_mountdata, 5); off += 5; } do { tkn_e = strchr(sb_mountdata + off, sep); if (tkn_e == NULL) noff = strlen(sb_mountdata + off); else noff = tkn_e - (sb_mountdata + off) + 1; if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) { off += noff; continue; } if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) { off += noff; continue; } if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) { off += noff; continue; } strncat(mountdata, sb_mountdata + off, noff); off += noff; } while (tkn_e); strcat(mountdata, sb_mountdata + off); mountdata[md_len] = '\0'; /* copy new IP and ref share name */ if (mountdata[strlen(mountdata) - 1] != sep) 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); } /*cFYI(1, "%s: parent mountdata: %s", __func__,sb_mountdata);*/ /*cFYI(1, "%s: submount mountdata: %s", __func__, mountdata );*/ compose_mount_options_out: kfree(srvIP); return mountdata; compose_mount_options_err: kfree(mountdata); mountdata = ERR_PTR(rc); goto compose_mount_options_out; }
struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry, char *ref_unc) { int rc; struct cifs_sb_info *cifs_sb; struct sockaddr_in sin_server; struct vfsmount *mnt = ERR_PTR(-ENOENT); char *mountdata; int md_len; char *devname; char *tkn_e; char srvIP[16]; char sep = ','; int off, noff; cFYI(1, ("in %s", __FUNCTION__ )); cifs_sb = CIFS_SB(dentry->d_inode->i_sb); if ( cifs_sb->mountdata == NULL ) { return ERR_PTR(-EINVAL); } devname = cifs_get_share_name(ref_unc); rc = cifs_resolve_server_name_to_ip( devname, &(sin_server.sin_addr)); snprintf(srvIP, sizeof(srvIP), "%u.%u.%u.%u", NIPQUAD(sin_server.sin_addr)); if (rc != 0) { if (devname) kfree(devname); cERROR(1, ("%s: failed to resolve server part of %s to IP", __FUNCTION__, devname )); rc = -EINVAL; return ERR_PTR(rc); } srvIP[sizeof(srvIP)-1] = '\0'; md_len = strlen(cifs_sb->mountdata) + sizeof(srvIP) + strlen(ref_unc) + 3; mountdata = kzalloc(md_len+1, GFP_KERNEL); /* copy all options except unc,ip,prefixpath */ off = 0; if (strncmp(cifs_sb->mountdata, "sep=", 4) == 0) { sep = cifs_sb->mountdata[4]; strncpy(mountdata, cifs_sb->mountdata, 5); off += 5; } while ( (tkn_e = strchr(cifs_sb->mountdata+off, sep)) ) { noff = (tkn_e - (cifs_sb->mountdata+off)) + 1; if (strnicmp(cifs_sb->mountdata+off, "unc=", 4) == 0) { off += noff; continue; } if (strnicmp(cifs_sb->mountdata+off, "ip=", 3) == 0) { off += noff; continue; } if (strnicmp(cifs_sb->mountdata+off, "prefixpath=", 3) == 0) { off += noff; continue; } strncat(mountdata, cifs_sb->mountdata+off, noff); off += noff; } strcat(mountdata, cifs_sb->mountdata+off); mountdata[md_len] = '\0'; strcat(mountdata, ", ip="); strcat(mountdata, srvIP); strcat(mountdata, ", unc="); strcat(mountdata, devname); /* find prefixpath */ tkn_e = strchr(ref_unc+2, '\\'); if ( tkn_e ) { tkn_e = strchr(tkn_e+1, '\\'); if ( tkn_e ) { strcat(mountdata, ",prefixpath="); strcat(mountdata, tkn_e); } } /*cFYI(1,("%s: old mountdata: %s", __FUNCTION__,cifs_sb->mountdata));*/ /*cFYI(1, ("%s: new mountdata: %s", __FUNCTION__, mountdata ));*/ mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata); if (devname) kfree(devname); if (mountdata) kfree(mountdata); cFYI(1, ("leaving %s", __FUNCTION__ )); return mnt; }
char *cifs_compose_mount_options(const char *sb_mountdata, const char *fullpath, const struct dfs_info3_param *ref, char **devname) { int rc; char *mountdata = NULL; int md_len; char *tkn_e; char *srvIP = NULL; char sep = ','; int off, noff; if (sb_mountdata == NULL) return ERR_PTR(-EINVAL); *devname = cifs_get_share_name(ref->node_name); if (IS_ERR(*devname)) { rc = PTR_ERR(*devname); *devname = NULL; goto compose_mount_options_err; } rc = dns_resolve_server_name_to_ip(*devname, &srvIP); if (rc < 0) { cFYI(1, "%s: Failed to resolve server part of %s to IP: %d", __func__, *devname, rc); goto compose_mount_options_err; } md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12; mountdata = kzalloc(md_len+1, GFP_KERNEL); if (mountdata == NULL) { rc = -ENOMEM; goto compose_mount_options_err; } off = 0; if (strncmp(sb_mountdata, "sep=", 4) == 0) { sep = sb_mountdata[4]; strncpy(mountdata, sb_mountdata, 5); off += 5; } do { tkn_e = strchr(sb_mountdata + off, sep); if (tkn_e == NULL) noff = strlen(sb_mountdata + off); else noff = tkn_e - (sb_mountdata + off) + 1; if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) { off += noff; continue; } if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) { off += noff; continue; } if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) { off += noff; continue; } strncat(mountdata, sb_mountdata + off, noff); off += noff; } while (tkn_e); strcat(mountdata, sb_mountdata + off); mountdata[md_len] = '\0'; if (mountdata[strlen(mountdata) - 1] != sep) strncat(mountdata, &sep, 1); strcat(mountdata, "ip="); strcat(mountdata, srvIP); strncat(mountdata, &sep, 1); strcat(mountdata, "unc="); strcat(mountdata, *devname); tkn_e = strchr(ref->node_name + 2, '\\'); if (tkn_e == NULL) { 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); } compose_mount_options_out: kfree(srvIP); return mountdata; compose_mount_options_err: kfree(mountdata); mountdata = ERR_PTR(rc); kfree(*devname); *devname = NULL; goto compose_mount_options_out; }
/** * compose_mount_options - creates mount options for refferral * @sb_mountdata: parent/root DFS mount options (template) * @ref_unc: refferral server UNC * @devname: pointer for saving device name * * creates mount options for submount based on template options sb_mountdata * and replacing unc,ip,prefixpath options with ones we've got form ref_unc. * * Returns: pointer to new mount options or ERR_PTR. * Caller is responcible for freeing retunrned value if it is not error. */ static char *compose_mount_options(const char *sb_mountdata, const char *ref_unc, char **devname) { int rc; char *mountdata; int md_len; char *tkn_e; char *srvIP = NULL; char sep = ','; int off, noff; if (sb_mountdata == NULL) return ERR_PTR(-EINVAL); *devname = cifs_get_share_name(ref_unc); rc = dns_resolve_server_name_to_ip(*devname, &srvIP); if (rc != 0) { cERROR(1, ("%s: Failed to resolve server part of %s to IP", __func__, *devname)); mountdata = ERR_PTR(rc); goto compose_mount_options_out; } md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3; mountdata = kzalloc(md_len+1, GFP_KERNEL); if (mountdata == NULL) { mountdata = ERR_PTR(-ENOMEM); goto compose_mount_options_out; } /* copy all options except of unc,ip,prefixpath */ off = 0; if (strncmp(sb_mountdata, "sep=", 4) == 0) { sep = sb_mountdata[4]; strncpy(mountdata, sb_mountdata, 5); off += 5; } while ((tkn_e = strchr(sb_mountdata+off, sep))) { noff = (tkn_e - (sb_mountdata+off)) + 1; if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) { off += noff; continue; } if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) { off += noff; continue; } if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) { off += noff; continue; } strncat(mountdata, sb_mountdata+off, noff); off += noff; } strcat(mountdata, sb_mountdata+off); mountdata[md_len] = '\0'; /* copy new IP and ref share name */ strcat(mountdata, ",ip="); strcat(mountdata, srvIP); strcat(mountdata, ",unc="); strcat(mountdata, *devname); /* find & copy prefixpath */ tkn_e = strchr(ref_unc+2, '\\'); if (tkn_e) { tkn_e = strchr(tkn_e+1, '\\'); if (tkn_e) { strcat(mountdata, ",prefixpath="); strcat(mountdata, tkn_e+1); } } /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/ /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/ compose_mount_options_out: kfree(srvIP); return mountdata; }