*/
#include <linux/fs.h>
#include <linux/stat.h>
+#include <linux/namei.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
cifs_sb_target = CIFS_SB(inode->i_sb);
pTcon = cifs_sb_target->tcon;
-/* No need to check for cross device links since server will do that - BB note DFS case in future though (when we may have to check) */
+/* No need to check for cross device links since server will do that
+ BB note DFS case in future though (when we may have to check) */
+ down(&inode->i_sb->s_vfs_rename_sem);
fromName = build_path_from_dentry(old_file);
toName = build_path_from_dentry(direntry);
+ up(&inode->i_sb->s_vfs_rename_sem);
+ if((fromName == NULL) || (toName == NULL)) {
+ rc = -ENOMEM;
+ goto cifs_hl_exit;
+ }
+
if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
- cifs_sb_target->local_nls);
+ cifs_sb_target->local_nls,
+ cifs_sb_target->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
else {
rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
- cifs_sb_target->local_nls);
+ cifs_sb_target->local_nls,
+ cifs_sb_target->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if(rc == -EIO)
rc = -EOPNOTSUPP;
}
cifsInode = CIFS_I(old_file->d_inode);
cifsInode->time = 0; /* will force revalidate to go get info when needed */
- if (fromName)
- kfree(fromName);
- if (toName)
- kfree(toName);
+cifs_hl_exit:
+ kfree(fromName);
+ kfree(toName);
FreeXid(xid);
return rc;
}
-int
+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;
+ char * target_path = ERR_PTR(-ENOMEM);
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)
+ 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 == NULL) {
- if (full_path)
- kfree(full_path);
- FreeXid(xid);
- return -ENOMEM;
+ if (!target_path) {
+ target_path = ERR_PTR(-ENOMEM);
+ goto out;
}
- /* 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)
else {
/* rc = CIFSSMBQueryReparseLinkInfo */
/* BB Add code to Query ReparsePoint info */
+ /* BB Add MAC style xsymlink check here if enabled */
}
- /* 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 {
+ kfree(target_path);
+ target_path = ERR_PTR(rc);
}
- /* else EACCESS */
- if (target_path)
- kfree(target_path);
- if (full_path)
- kfree(full_path);
+out:
+ kfree(full_path);
+out_no_free:
FreeXid(xid);
- return rc;
+ nd_set_link(nd, target_path);
+ return NULL; /* No cookie */
}
int
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
+ down(&inode->i_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry);
+ up(&inode->i_sb->s_vfs_rename_sem);
+
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+
cFYI(1, ("Full path: %s ", full_path));
cFYI(1, ("symname is %s", symname));
if (rc == 0) {
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&newinode, full_path,
- inode->i_sb);
+ inode->i_sb,xid);
else
rc = cifs_get_inode_info(&newinode, full_path, NULL,
- inode->i_sb);
+ inode->i_sb,xid);
if (rc != 0) {
cFYI(1,
("Create symlink worked but get_inode_info failed with rc = %d ",
rc));
} else {
- direntry->d_op = &cifs_dentry_ops;
+ if (pTcon->nocase)
+ direntry->d_op = &cifs_ci_dentry_ops;
+ else
+ direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode);
}
}
- if (full_path)
- kfree(full_path);
+ kfree(full_path);
FreeXid(xid);
return rc;
}
int
-cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
+cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
{
struct inode *inode = direntry->d_inode;
int rc = -EACCES;
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? */
+/* down(&inode->i_sb->s_vfs_rename_sem);*/
full_path = build_path_from_dentry(direntry);
+/* up(&inode->i_sb->s_vfs_rename_sem);*/
+
+ 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));
len = buflen;
tmpbuffer = kmalloc(len,GFP_KERNEL);
if(tmpbuffer == NULL) {
- if (full_path)
- kfree(full_path);
+ kfree(full_path);
FreeXid(xid);
return -ENOMEM;
}
cifs_sb->local_nls);
else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
- OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls);
+ 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,
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->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;
strncpy(tmpbuffer, referrals, len-1);
}
}
- if(referrals)
- kfree(referrals);
+ kfree(referrals);
kfree(tmp_path);
- if(referrals) {
- kfree(referrals);
- }
- }
+}
/* BB add code like else decode referrals then memcpy to
tmpbuffer and free referrals string array BB */
}
rc));
}
- if (tmpbuffer) {
- kfree(tmpbuffer);
- }
- if (full_path) {
- kfree(full_path);
- }
+ kfree(tmpbuffer);
+ kfree(full_path);
FreeXid(xid);
return rc;
}
+
+void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
+{
+ char *p = nd_get_link(nd);
+ if (!IS_ERR(p))
+ kfree(p);
+}