]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/cifs/link.c
[CIFS] More whitespace/formatting fixes (noticed by checkpatch)
[net-next-2.6.git] / fs / cifs / link.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/link.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002,2003
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
58 if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
59 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
fb8c4b14 60 cifs_sb_target->local_nls,
737b758c
SF
61 cifs_sb_target->mnt_cifs_flags &
62 CIFS_MOUNT_MAP_SPECIAL_CHR);
1da177e4
LT
63 else {
64 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
fb8c4b14 65 cifs_sb_target->local_nls,
737b758c
SF
66 cifs_sb_target->mnt_cifs_flags &
67 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14
SF
68 if ((rc == -EIO) || (rc == -EINVAL))
69 rc = -EOPNOTSUPP;
1da177e4
LT
70 }
71
31ec35d6
SF
72 d_drop(direntry); /* force new lookup from server of target */
73
74 /* if source file is cached (oplocked) revalidate will not go to server
75 until the file is closed or oplock broken so update nlinks locally */
fb8c4b14 76 if (old_file->d_inode) {
31ec35d6 77 cifsInode = CIFS_I(old_file->d_inode);
fb8c4b14 78 if (rc == 0) {
31ec35d6 79 old_file->d_inode->i_nlink++;
1b2b2126
SF
80/* BB should we make this contingent on superblock flag NOATIME? */
81/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
31ec35d6
SF
82 /* parent dir timestamps will update from srv
83 within a second, would it really be worth it
84 to set the parent dir cifs inode time to zero
85 to force revalidate (faster) for it too? */
86 }
fb8c4b14 87 /* if not oplocked will force revalidate to get info
31ec35d6
SF
88 on source file from srv */
89 cifsInode->time = 0;
90
fb8c4b14 91 /* Will update parent dir timestamps from srv within a second.
31ec35d6
SF
92 Would it really be worth it to set the parent dir (cifs
93 inode) time field to zero to force revalidate on parent
fb8c4b14 94 directory faster ie
31ec35d6 95 CIFS_I(inode)->time = 0; */
1da177e4 96 }
1da177e4
LT
97
98cifs_hl_exit:
f99d49ad
JJ
99 kfree(fromName);
100 kfree(toName);
1da177e4
LT
101 FreeXid(xid);
102 return rc;
103}
104
cc314eef 105void *
1da177e4
LT
106cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
107{
108 struct inode *inode = direntry->d_inode;
109 int rc = -EACCES;
110 int xid;
111 char *full_path = NULL;
fb8c4b14 112 char *target_path = ERR_PTR(-ENOMEM);
1da177e4
LT
113 struct cifs_sb_info *cifs_sb;
114 struct cifsTconInfo *pTcon;
115
116 xid = GetXid();
117
7f57356b 118 full_path = build_path_from_dentry(direntry);
1da177e4
LT
119
120 if (!full_path)
121 goto out_no_free;
122
123 cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
7f57356b
SF
124 cifs_sb = CIFS_SB(inode->i_sb);
125 pTcon = cifs_sb->tcon;
1da177e4
LT
126 target_path = kmalloc(PATH_MAX, GFP_KERNEL);
127 if (!target_path) {
128 target_path = ERR_PTR(-ENOMEM);
129 goto out;
130 }
131
fb8c4b14
SF
132 /* BB add read reparse point symlink code and Unix extensions
133 symlink code here BB */
1da177e4
LT
134 if (pTcon->ses->capabilities & CAP_UNIX)
135 rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
136 target_path,
137 PATH_MAX-1,
138 cifs_sb->local_nls);
139 else {
140 /* rc = CIFSSMBQueryReparseLinkInfo */
141 /* BB Add code to Query ReparsePoint info */
142 /* BB Add MAC style xsymlink check here if enabled */
143 }
144
145 if (rc == 0) {
146
147/* BB Add special case check for Samba DFS symlinks */
148
149 target_path[PATH_MAX-1] = 0;
150 } else {
151 kfree(target_path);
152 target_path = ERR_PTR(rc);
153 }
154
155out:
156 kfree(full_path);
157out_no_free:
158 FreeXid(xid);
159 nd_set_link(nd, target_path);
cc314eef 160 return NULL; /* No cookie */
1da177e4
LT
161}
162
163int
164cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
165{
166 int rc = -EOPNOTSUPP;
167 int xid;
168 struct cifs_sb_info *cifs_sb;
169 struct cifsTconInfo *pTcon;
170 char *full_path = NULL;
171 struct inode *newinode = NULL;
172
173 xid = GetXid();
174
175 cifs_sb = CIFS_SB(inode->i_sb);
176 pTcon = cifs_sb->tcon;
177
7f57356b 178 full_path = build_path_from_dentry(direntry);
1da177e4 179
fb8c4b14 180 if (full_path == NULL) {
1da177e4
LT
181 FreeXid(xid);
182 return -ENOMEM;
183 }
184
26a21b98 185 cFYI(1, ("Full path: %s", full_path));
1da177e4
LT
186 cFYI(1, ("symname is %s", symname));
187
188 /* BB what if DFS and this volume is on different share? BB */
189 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
190 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
191 cifs_sb->local_nls);
192 /* else
fb8c4b14
SF
193 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
194 cifs_sb_target->local_nls); */
1da177e4
LT
195
196 if (rc == 0) {
197 if (pTcon->ses->capabilities & CAP_UNIX)
198 rc = cifs_get_inode_info_unix(&newinode, full_path,
fb8c4b14 199 inode->i_sb, xid);
1da177e4
LT
200 else
201 rc = cifs_get_inode_info(&newinode, full_path, NULL,
fb8c4b14 202 inode->i_sb, xid);
1da177e4
LT
203
204 if (rc != 0) {
26a21b98 205 cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
1da177e4
LT
206 rc));
207 } else {
b92327fe
SF
208 if (pTcon->nocase)
209 direntry->d_op = &cifs_ci_dentry_ops;
210 else
211 direntry->d_op = &cifs_dentry_ops;
1da177e4
LT
212 d_instantiate(direntry, newinode);
213 }
214 }
215
f99d49ad 216 kfree(full_path);
1da177e4
LT
217 FreeXid(xid);
218 return rc;
219}
220
221int
222cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
223{
224 struct inode *inode = direntry->d_inode;
225 int rc = -EACCES;
226 int xid;
227 int oplock = FALSE;
228 struct cifs_sb_info *cifs_sb;
229 struct cifsTconInfo *pTcon;
230 char *full_path = NULL;
fb8c4b14
SF
231 char *tmp_path = NULL;
232 char *tmpbuffer;
233 unsigned char *referrals = NULL;
1da177e4
LT
234 int num_referrals = 0;
235 int len;
236 __u16 fid;
237
238 xid = GetXid();
239 cifs_sb = CIFS_SB(inode->i_sb);
240 pTcon = cifs_sb->tcon;
241
fb8c4b14 242/* BB would it be safe against deadlock to grab this sem
1da177e4 243 even though rename itself grabs the sem and calls lookup? */
a11f3a05 244/* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/
7f57356b 245 full_path = build_path_from_dentry(direntry);
a11f3a05 246/* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/
1da177e4 247
fb8c4b14 248 if (full_path == NULL) {
1da177e4
LT
249 FreeXid(xid);
250 return -ENOMEM;
251 }
252
253 cFYI(1,
254 ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
255 full_path, inode, pBuffer, buflen));
fb8c4b14 256 if (buflen > PATH_MAX)
1da177e4
LT
257 len = PATH_MAX;
258 else
259 len = buflen;
fb8c4b14
SF
260 tmpbuffer = kmalloc(len, GFP_KERNEL);
261 if (tmpbuffer == NULL) {
f99d49ad 262 kfree(full_path);
1da177e4
LT
263 FreeXid(xid);
264 return -ENOMEM;
265 }
266
fb8c4b14
SF
267/* BB add read reparse point symlink code and
268 Unix extensions symlink code here BB */
1da177e4
LT
269 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
270 rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
271 tmpbuffer,
272 len - 1,
273 cifs_sb->local_nls);
1bd5bbcb 274 else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
fb8c4b14 275 cERROR(1, ("SFU style symlinks not implemented yet"));
1bd5bbcb 276 /* add open and read as in fs/cifs/inode.c */
1bd5bbcb 277 } else {
1da177e4 278 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
fb8c4b14
SF
279 OPEN_REPARSE_POINT, &fid, &oplock, NULL,
280 cifs_sb->local_nls,
281 cifs_sb->mnt_cifs_flags &
737b758c 282 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14 283 if (!rc) {
1da177e4
LT
284 rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
285 tmpbuffer,
fb8c4b14 286 len - 1,
1da177e4
LT
287 fid,
288 cifs_sb->local_nls);
fb8c4b14 289 if (CIFSSMBClose(xid, pTcon, fid)) {
63135e08
SF
290 cFYI(1, ("Error closing junction point "
291 "(open for ioctl)"));
1da177e4 292 }
fb8c4b14 293 if (rc == -EIO) {
1da177e4
LT
294 /* Query if DFS Junction */
295 tmp_path =
296 kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
297 GFP_KERNEL);
298 if (tmp_path) {
fb8c4b14
SF
299 strncpy(tmp_path, pTcon->treeName,
300 MAX_TREE_SIZE);
301 strncat(tmp_path, full_path,
302 MAX_PATHCONF);
303 rc = get_dfs_path(xid, pTcon->ses,
304 tmp_path,
737b758c
SF
305 cifs_sb->local_nls,
306 &num_referrals, &referrals,
307 cifs_sb->mnt_cifs_flags &
308 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14
SF
309 cFYI(1, ("Get DFS for %s rc = %d ",
310 tmp_path, rc));
311 if ((num_referrals == 0) && (rc == 0))
1da177e4
LT
312 rc = -EACCES;
313 else {
fb8c4b14
SF
314 cFYI(1, ("num referral: %d",
315 num_referrals));
316 if (referrals) {
317 cFYI(1,("referral string: %s", referrals));
50c2f753
SF
318 strncpy(tmpbuffer,
319 referrals,
320 len-1);
1da177e4
LT
321 }
322 }
f99d49ad 323 kfree(referrals);
1da177e4
LT
324 kfree(tmp_path);
325}
fb8c4b14
SF
326 /* BB add code like else decode referrals
327 then memcpy to tmpbuffer and free referrals
328 string array BB */
1da177e4
LT
329 }
330 }
331 }
332 /* BB Anything else to do to handle recursive links? */
333 /* BB Should we be using page ops here? */
334
335 /* BB null terminate returned string in pBuffer? BB */
336 if (rc == 0) {
337 rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer);
338 cFYI(1,
339 ("vfs_readlink called from cifs_readlink returned %d",
340 rc));
341 }
342
f99d49ad
JJ
343 kfree(tmpbuffer);
344 kfree(full_path);
1da177e4
LT
345 FreeXid(xid);
346 return rc;
347}
348
cc314eef 349void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
1da177e4
LT
350{
351 char *p = nd_get_link(nd);
352 if (!IS_ERR(p))
353 kfree(p);
354}