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; }