void * cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = direntry->d_inode; int rc = -EACCES; int xid; char *full_path = NULL; char * target_path = ERR_PTR(-ENOMEM); struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; xid = GetXid(); full_path = build_path_from_dentry(direntry); if (!full_path) goto out_no_free; cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; target_path = kmalloc(PATH_MAX, GFP_KERNEL); if (!target_path) { target_path = ERR_PTR(-ENOMEM); goto out; } /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ if (pTcon->ses->capabilities & CAP_UNIX) rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, target_path, PATH_MAX-1, cifs_sb->local_nls); else { /* rc = CIFSSMBQueryReparseLinkInfo */ /* BB Add code to Query ReparsePoint info */ /* BB Add MAC style xsymlink check here if enabled */ } if (rc == 0) { /* BB Add special case check for Samba DFS symlinks */ target_path[PATH_MAX-1] = 0; } else { kfree(target_path); target_path = ERR_PTR(rc); } out: kfree(full_path); out_no_free: FreeXid(xid); nd_set_link(nd, target_path); return NULL; /* No cookie */ }
void * cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = direntry->d_inode; int rc = -ENOMEM; int xid; char *full_path = NULL; char *target_path = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsTconInfo *tcon = cifs_sb->tcon; xid = GetXid(); /* * For now, we just handle symlinks with unix extensions enabled. * Eventually we should handle NTFS reparse points, and MacOS * symlink support. For instance... * * rc = CIFSSMBQueryReparseLinkInfo(...) * * For now, just return -EACCES when the server doesn't support posix * extensions. Note that we still allow querying symlinks when posix * extensions are manually disabled. We could disable these as well * but there doesn't seem to be any harm in allowing the client to * read them. */ if (!(tcon->ses->capabilities & CAP_UNIX)) { rc = -EACCES; goto out; } full_path = build_path_from_dentry(direntry); if (!full_path) goto out; cFYI(1, "Full path: %s inode = 0x%p", full_path, inode); rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, cifs_sb->local_nls); kfree(full_path); out: if (rc != 0) { kfree(target_path); target_path = ERR_PTR(rc); } FreeXid(xid); nd_set_link(nd, target_path); return NULL; }
void * cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = direntry->d_inode; int rc = -ENOMEM; int xid; char *full_path = NULL; char *target_path = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = NULL; struct cifsTconInfo *tcon; xid = GetXid(); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); tlink = NULL; goto out; } tcon = tlink_tcon(tlink); /* * For now, we just handle symlinks with unix extensions enabled. * Eventually we should handle NTFS reparse points, and MacOS * symlink support. For instance... * * rc = CIFSSMBQueryReparseLinkInfo(...) * * For now, just return -EACCES when the server doesn't support posix * extensions. Note that we still allow querying symlinks when posix * extensions are manually disabled. We could disable these as well * but there doesn't seem to be any harm in allowing the client to * read them. */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && !(tcon->ses->capabilities & CAP_UNIX)) { rc = -EACCES; goto out; } full_path = build_path_from_dentry(direntry); if (!full_path) goto out; cFYI(1, "Full path: %s inode = 0x%p", full_path, inode); rc = -EACCES; /* * First try Minshall+French Symlinks, if configured * and fallback to UNIX Extensions Symlinks. */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX)) rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, cifs_sb->local_nls); kfree(full_path); out: if (rc != 0) { kfree(target_path); target_path = ERR_PTR(rc); } FreeXid(xid); if (tlink) cifs_put_tlink(tlink); nd_set_link(nd, target_path); return NULL; }
int cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) { struct inode *inode = direntry->d_inode; int rc = -EACCES; int xid; int oplock = FALSE; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; char *tmp_path = NULL; char *tmpbuffer; unsigned char *referrals = NULL; unsigned int num_referrals = 0; int len; __u16 fid; xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; /* BB would it be safe against deadlock to grab this sem even though rename itself grabs the sem and calls lookup? */ /* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/ full_path = build_path_from_dentry(direntry); /* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/ if (full_path == NULL) { FreeXid(xid); return -ENOMEM; } cFYI(1, ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", full_path, inode, pBuffer, buflen)); if (buflen > PATH_MAX) len = PATH_MAX; else len = buflen; tmpbuffer = kmalloc(len, GFP_KERNEL); if (tmpbuffer == NULL) { kfree(full_path); FreeXid(xid); return -ENOMEM; } /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ /* We could disable this based on pTcon->unix_ext flag instead ... but why? */ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, tmpbuffer, len - 1, cifs_sb->local_nls); else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { cERROR(1, ("SFU style symlinks not implemented yet")); /* add open and read as in fs/cifs/inode.c */ } else { rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, OPEN_REPARSE_POINT, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, tmpbuffer, len - 1, fid, cifs_sb->local_nls); if (CIFSSMBClose(xid, pTcon, fid)) { cFYI(1, ("Error closing junction point " "(open for ioctl)")); } if (rc == -EIO) { /* Query if DFS Junction */ tmp_path = kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, GFP_KERNEL); if (tmp_path) { strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); strncat(tmp_path, full_path, MAX_PATHCONF); rc = get_dfs_path(xid, pTcon->ses, tmp_path, cifs_sb->local_nls, &num_referrals, &referrals, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1, ("Get DFS for %s rc = %d ", tmp_path, rc)); if ((num_referrals == 0) && (rc == 0)) rc = -EACCES; else { cFYI(1, ("num referral: %d", num_referrals)); if (referrals) { cFYI(1,("referral string: %s", referrals)); strncpy(tmpbuffer, referrals, len-1); } } kfree(referrals); kfree(tmp_path); } /* BB add code like else decode referrals then memcpy to tmpbuffer and free referrals string array BB */ } } } /* BB Anything else to do to handle recursive links? */ /* BB Should we be using page ops here? */ /* BB null terminate returned string in pBuffer? BB */ if (rc == 0) { rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer); cFYI(1, ("vfs_readlink called from cifs_readlink returned %d", rc)); } kfree(tmpbuffer); kfree(full_path); FreeXid(xid); return rc; }
int cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) { struct inode *inode = direntry->d_inode; int rc = -EACCES; int xid; int oplock = 0; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; char *tmpbuffer; int len; __u16 fid; xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; /* BB would it be safe against deadlock to grab this sem even though rename itself grabs the sem and calls lookup? */ /* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/ full_path = build_path_from_dentry(direntry); /* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/ if (full_path == NULL) { FreeXid(xid); return -ENOMEM; } cFYI(1, ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", full_path, inode, pBuffer, buflen)); if (buflen > PATH_MAX) len = PATH_MAX; else len = buflen; tmpbuffer = kmalloc(len, GFP_KERNEL); if (tmpbuffer == NULL) { kfree(full_path); FreeXid(xid); return -ENOMEM; } /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ /* We could disable this based on pTcon->unix_ext flag instead ... but why? */ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, tmpbuffer, len - 1, cifs_sb->local_nls); else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { cERROR(1, ("SFU style symlinks not implemented yet")); /* add open and read as in fs/cifs/inode.c */ } else { rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, FILE_SHARE_ALL, OPEN_REPARSE_POINT, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, tmpbuffer, len - 1, fid, cifs_sb->local_nls); if (CIFSSMBClose(xid, pTcon, fid)) { cFYI(1, ("Error closing junction point " "(open for ioctl)")); } /* If it is a DFS junction earlier we would have gotten PATH_NOT_COVERED returned from server so we do not need to request the DFS info here */ } } /* BB Anything else to do to handle recursive links? */ /* BB Should we be using page ops here? */ /* BB null terminate returned string in pBuffer? BB */ if (rc == 0) { rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer); cFYI(1, ("vfs_readlink called from cifs_readlink returned %d", rc)); } kfree(tmpbuffer); kfree(full_path); FreeXid(xid); return rc; }
int cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = direntry->d_inode; int rc = -EACCES; int xid; char *full_path = NULL; char * target_path; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; xid = GetXid(); down(&direntry->d_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) { FreeXid(xid); return -ENOMEM; } cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; target_path = kmalloc(PATH_MAX, GFP_KERNEL); if(target_path == NULL) { if (full_path) kfree(full_path); FreeXid(xid); return -ENOMEM; } /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */ /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */ /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ if (pTcon->ses->capabilities & CAP_UNIX) rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, target_path, PATH_MAX-1, cifs_sb->local_nls); else { /* rc = CIFSSMBQueryReparseLinkInfo */ /* BB Add code to Query ReparsePoint info */ } /* BB Anything else to do to handle recursive links? */ /* BB Should we be using page symlink ops here? */ if (rc == 0) { /* BB Add special case check for Samba DFS symlinks */ target_path[PATH_MAX-1] = 0; rc = vfs_follow_link(nd, target_path); } /* else EACCESS */ if (target_path) kfree(target_path); if (full_path) kfree(full_path); FreeXid(xid); return rc; }