Merge git://git.infradead.org/mtd-2.6
[linux-2.6-block.git] / fs / cifs / link.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/link.c
3 *
366781c1 4 * Copyright (C) International Business Machines Corp., 2002,2008
1da177e4
LT
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/fs.h>
22#include <linux/stat.h>
23#include <linux/namei.h>
24#include "cifsfs.h"
25#include "cifspdu.h"
26#include "cifsglob.h"
27#include "cifsproto.h"
28#include "cifs_debug.h"
29#include "cifs_fs_sb.h"
30
31int
32cifs_hardlink(struct dentry *old_file, struct inode *inode,
33 struct dentry *direntry)
34{
35 int rc = -EACCES;
36 int xid;
37 char *fromName = NULL;
38 char *toName = NULL;
39 struct cifs_sb_info *cifs_sb_target;
40 struct cifsTconInfo *pTcon;
41 struct cifsInodeInfo *cifsInode;
42
43 xid = GetXid();
44
45 cifs_sb_target = CIFS_SB(inode->i_sb);
46 pTcon = cifs_sb_target->tcon;
47
48/* No need to check for cross device links since server will do that
49 BB note DFS case in future though (when we may have to check) */
50
7f57356b
SF
51 fromName = build_path_from_dentry(old_file);
52 toName = build_path_from_dentry(direntry);
fb8c4b14 53 if ((fromName == NULL) || (toName == NULL)) {
1da177e4
LT
54 rc = -ENOMEM;
55 goto cifs_hl_exit;
56 }
57
c18c842b
SF
58/* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
59 if (pTcon->unix_ext)
1da177e4 60 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
fb8c4b14 61 cifs_sb_target->local_nls,
737b758c
SF
62 cifs_sb_target->mnt_cifs_flags &
63 CIFS_MOUNT_MAP_SPECIAL_CHR);
1da177e4
LT
64 else {
65 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
fb8c4b14 66 cifs_sb_target->local_nls,
737b758c
SF
67 cifs_sb_target->mnt_cifs_flags &
68 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14
SF
69 if ((rc == -EIO) || (rc == -EINVAL))
70 rc = -EOPNOTSUPP;
1da177e4
LT
71 }
72
31ec35d6
SF
73 d_drop(direntry); /* force new lookup from server of target */
74
75 /* if source file is cached (oplocked) revalidate will not go to server
76 until the file is closed or oplock broken so update nlinks locally */
fb8c4b14 77 if (old_file->d_inode) {
31ec35d6 78 cifsInode = CIFS_I(old_file->d_inode);
fb8c4b14 79 if (rc == 0) {
31ec35d6 80 old_file->d_inode->i_nlink++;
1b2b2126
SF
81/* BB should we make this contingent on superblock flag NOATIME? */
82/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
31ec35d6
SF
83 /* parent dir timestamps will update from srv
84 within a second, would it really be worth it
85 to set the parent dir cifs inode time to zero
86 to force revalidate (faster) for it too? */
87 }
fb8c4b14 88 /* if not oplocked will force revalidate to get info
31ec35d6
SF
89 on source file from srv */
90 cifsInode->time = 0;
91
fb8c4b14 92 /* Will update parent dir timestamps from srv within a second.
31ec35d6
SF
93 Would it really be worth it to set the parent dir (cifs
94 inode) time field to zero to force revalidate on parent
fb8c4b14 95 directory faster ie
31ec35d6 96 CIFS_I(inode)->time = 0; */
1da177e4 97 }
1da177e4
LT
98
99cifs_hl_exit:
f99d49ad
JJ
100 kfree(fromName);
101 kfree(toName);
1da177e4
LT
102 FreeXid(xid);
103 return rc;
104}
105
cc314eef 106void *
1da177e4
LT
107cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
108{
109 struct inode *inode = direntry->d_inode;
110 int rc = -EACCES;
111 int xid;
112 char *full_path = NULL;
fb8c4b14 113 char *target_path = ERR_PTR(-ENOMEM);
1da177e4
LT
114 struct cifs_sb_info *cifs_sb;
115 struct cifsTconInfo *pTcon;
116
117 xid = GetXid();
118
7f57356b 119 full_path = build_path_from_dentry(direntry);
1da177e4
LT
120
121 if (!full_path)
122 goto out_no_free;
123
124 cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
7f57356b
SF
125 cifs_sb = CIFS_SB(inode->i_sb);
126 pTcon = cifs_sb->tcon;
1da177e4
LT
127 target_path = kmalloc(PATH_MAX, GFP_KERNEL);
128 if (!target_path) {
129 target_path = ERR_PTR(-ENOMEM);
130 goto out;
131 }
132
c18c842b
SF
133 /* We could change this to:
134 if (pTcon->unix_ext)
135 but there does not seem any point in refusing to
136 get symlink info if we can, even if unix extensions
137 turned off for this mount */
138
1da177e4
LT
139 if (pTcon->ses->capabilities & CAP_UNIX)
140 rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
141 target_path,
142 PATH_MAX-1,
143 cifs_sb->local_nls);
144 else {
c18c842b 145 /* BB add read reparse point symlink code here */
1da177e4
LT
146 /* rc = CIFSSMBQueryReparseLinkInfo */
147 /* BB Add code to Query ReparsePoint info */
148 /* BB Add MAC style xsymlink check here if enabled */
149 }
150
151 if (rc == 0) {
152
153/* BB Add special case check for Samba DFS symlinks */
154
155 target_path[PATH_MAX-1] = 0;
156 } else {
157 kfree(target_path);
158 target_path = ERR_PTR(rc);
159 }
160
161out:
162 kfree(full_path);
163out_no_free:
164 FreeXid(xid);
165 nd_set_link(nd, target_path);
cc314eef 166 return NULL; /* No cookie */
1da177e4
LT
167}
168
169int
170cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
171{
172 int rc = -EOPNOTSUPP;
173 int xid;
174 struct cifs_sb_info *cifs_sb;
175 struct cifsTconInfo *pTcon;
176 char *full_path = NULL;
177 struct inode *newinode = NULL;
178
179 xid = GetXid();
180
181 cifs_sb = CIFS_SB(inode->i_sb);
182 pTcon = cifs_sb->tcon;
183
7f57356b 184 full_path = build_path_from_dentry(direntry);
1da177e4 185
fb8c4b14 186 if (full_path == NULL) {
1da177e4
LT
187 FreeXid(xid);
188 return -ENOMEM;
189 }
190
26a21b98 191 cFYI(1, ("Full path: %s", full_path));
1da177e4
LT
192 cFYI(1, ("symname is %s", symname));
193
194 /* BB what if DFS and this volume is on different share? BB */
c18c842b 195 if (pTcon->unix_ext)
1da177e4
LT
196 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
197 cifs_sb->local_nls);
198 /* else
fb8c4b14
SF
199 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
200 cifs_sb_target->local_nls); */
1da177e4
LT
201
202 if (rc == 0) {
c18c842b 203 if (pTcon->unix_ext)
1da177e4 204 rc = cifs_get_inode_info_unix(&newinode, full_path,
fb8c4b14 205 inode->i_sb, xid);
1da177e4
LT
206 else
207 rc = cifs_get_inode_info(&newinode, full_path, NULL,
8b1327f6 208 inode->i_sb, xid, NULL);
1da177e4
LT
209
210 if (rc != 0) {
26a21b98 211 cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
1da177e4
LT
212 rc));
213 } else {
b92327fe
SF
214 if (pTcon->nocase)
215 direntry->d_op = &cifs_ci_dentry_ops;
216 else
217 direntry->d_op = &cifs_dentry_ops;
1da177e4
LT
218 d_instantiate(direntry, newinode);
219 }
220 }
221
f99d49ad 222 kfree(full_path);
1da177e4
LT
223 FreeXid(xid);
224 return rc;
225}
226
227int
228cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
229{
230 struct inode *inode = direntry->d_inode;
231 int rc = -EACCES;
232 int xid;
4b18f2a9 233 int oplock = 0;
1da177e4
LT
234 struct cifs_sb_info *cifs_sb;
235 struct cifsTconInfo *pTcon;
236 char *full_path = NULL;
fb8c4b14 237 char *tmpbuffer;
1da177e4
LT
238 int len;
239 __u16 fid;
240
241 xid = GetXid();
242 cifs_sb = CIFS_SB(inode->i_sb);
243 pTcon = cifs_sb->tcon;
244
fb8c4b14 245/* BB would it be safe against deadlock to grab this sem
1da177e4 246 even though rename itself grabs the sem and calls lookup? */
a11f3a05 247/* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/
7f57356b 248 full_path = build_path_from_dentry(direntry);
a11f3a05 249/* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/
1da177e4 250
fb8c4b14 251 if (full_path == NULL) {
1da177e4
LT
252 FreeXid(xid);
253 return -ENOMEM;
254 }
255
256 cFYI(1,
257 ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
258 full_path, inode, pBuffer, buflen));
fb8c4b14 259 if (buflen > PATH_MAX)
1da177e4
LT
260 len = PATH_MAX;
261 else
262 len = buflen;
fb8c4b14
SF
263 tmpbuffer = kmalloc(len, GFP_KERNEL);
264 if (tmpbuffer == NULL) {
f99d49ad 265 kfree(full_path);
1da177e4
LT
266 FreeXid(xid);
267 return -ENOMEM;
268 }
269
fb8c4b14
SF
270/* BB add read reparse point symlink code and
271 Unix extensions symlink code here BB */
c18c842b 272/* We could disable this based on pTcon->unix_ext flag instead ... but why? */
1da177e4
LT
273 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
274 rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
275 tmpbuffer,
276 len - 1,
277 cifs_sb->local_nls);
1bd5bbcb 278 else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
fb8c4b14 279 cERROR(1, ("SFU style symlinks not implemented yet"));
1bd5bbcb 280 /* add open and read as in fs/cifs/inode.c */
1bd5bbcb 281 } else {
1da177e4 282 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
fb8c4b14
SF
283 OPEN_REPARSE_POINT, &fid, &oplock, NULL,
284 cifs_sb->local_nls,
285 cifs_sb->mnt_cifs_flags &
737b758c 286 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14 287 if (!rc) {
1da177e4
LT
288 rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
289 tmpbuffer,
fb8c4b14 290 len - 1,
1da177e4
LT
291 fid,
292 cifs_sb->local_nls);
fb8c4b14 293 if (CIFSSMBClose(xid, pTcon, fid)) {
63135e08
SF
294 cFYI(1, ("Error closing junction point "
295 "(open for ioctl)"));
1da177e4 296 }
646dd539
SF
297 /* If it is a DFS junction earlier we would have gotten
298 PATH_NOT_COVERED returned from server so we do
299 not need to request the DFS info here */
1da177e4
LT
300 }
301 }
302 /* BB Anything else to do to handle recursive links? */
303 /* BB Should we be using page ops here? */
304
305 /* BB null terminate returned string in pBuffer? BB */
306 if (rc == 0) {
307 rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer);
308 cFYI(1,
309 ("vfs_readlink called from cifs_readlink returned %d",
310 rc));
311 }
312
f99d49ad
JJ
313 kfree(tmpbuffer);
314 kfree(full_path);
1da177e4
LT
315 FreeXid(xid);
316 return rc;
317}
318
cc314eef 319void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
1da177e4
LT
320{
321 char *p = nd_get_link(nd);
322 if (!IS_ERR(p))
323 kfree(p);
324}