Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[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>
5a0e3ad6 23#include <linux/slab.h>
1da177e4
LT
24#include <linux/namei.h>
25#include "cifsfs.h"
26#include "cifspdu.h"
27#include "cifsglob.h"
28#include "cifsproto.h"
29#include "cifs_debug.h"
30#include "cifs_fs_sb.h"
31
32int
33cifs_hardlink(struct dentry *old_file, struct inode *inode,
34 struct dentry *direntry)
35{
36 int rc = -EACCES;
37 int xid;
38 char *fromName = NULL;
39 char *toName = NULL;
40 struct cifs_sb_info *cifs_sb_target;
41 struct cifsTconInfo *pTcon;
42 struct cifsInodeInfo *cifsInode;
43
44 xid = GetXid();
45
46 cifs_sb_target = CIFS_SB(inode->i_sb);
47 pTcon = cifs_sb_target->tcon;
48
49/* No need to check for cross device links since server will do that
50 BB note DFS case in future though (when we may have to check) */
51
7f57356b
SF
52 fromName = build_path_from_dentry(old_file);
53 toName = build_path_from_dentry(direntry);
fb8c4b14 54 if ((fromName == NULL) || (toName == NULL)) {
1da177e4
LT
55 rc = -ENOMEM;
56 goto cifs_hl_exit;
57 }
58
c18c842b
SF
59/* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
60 if (pTcon->unix_ext)
1da177e4 61 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
fb8c4b14 62 cifs_sb_target->local_nls,
737b758c
SF
63 cifs_sb_target->mnt_cifs_flags &
64 CIFS_MOUNT_MAP_SPECIAL_CHR);
1da177e4
LT
65 else {
66 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
fb8c4b14 67 cifs_sb_target->local_nls,
737b758c
SF
68 cifs_sb_target->mnt_cifs_flags &
69 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14
SF
70 if ((rc == -EIO) || (rc == -EINVAL))
71 rc = -EOPNOTSUPP;
1da177e4
LT
72 }
73
31ec35d6
SF
74 d_drop(direntry); /* force new lookup from server of target */
75
76 /* if source file is cached (oplocked) revalidate will not go to server
77 until the file is closed or oplock broken so update nlinks locally */
fb8c4b14 78 if (old_file->d_inode) {
31ec35d6 79 cifsInode = CIFS_I(old_file->d_inode);
fb8c4b14 80 if (rc == 0) {
31ec35d6 81 old_file->d_inode->i_nlink++;
1b2b2126
SF
82/* BB should we make this contingent on superblock flag NOATIME? */
83/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
31ec35d6
SF
84 /* parent dir timestamps will update from srv
85 within a second, would it really be worth it
86 to set the parent dir cifs inode time to zero
87 to force revalidate (faster) for it too? */
88 }
fb8c4b14 89 /* if not oplocked will force revalidate to get info
31ec35d6
SF
90 on source file from srv */
91 cifsInode->time = 0;
92
fb8c4b14 93 /* Will update parent dir timestamps from srv within a second.
31ec35d6
SF
94 Would it really be worth it to set the parent dir (cifs
95 inode) time field to zero to force revalidate on parent
fb8c4b14 96 directory faster ie
31ec35d6 97 CIFS_I(inode)->time = 0; */
1da177e4 98 }
1da177e4
LT
99
100cifs_hl_exit:
f99d49ad
JJ
101 kfree(fromName);
102 kfree(toName);
1da177e4
LT
103 FreeXid(xid);
104 return rc;
105}
106
cc314eef 107void *
1da177e4
LT
108cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
109{
110 struct inode *inode = direntry->d_inode;
8b6427a2 111 int rc = -ENOMEM;
1da177e4
LT
112 int xid;
113 char *full_path = NULL;
8b6427a2
JL
114 char *target_path = NULL;
115 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
116 struct cifsTconInfo *tcon = cifs_sb->tcon;
1da177e4
LT
117
118 xid = GetXid();
119
8b6427a2
JL
120 /*
121 * For now, we just handle symlinks with unix extensions enabled.
122 * Eventually we should handle NTFS reparse points, and MacOS
123 * symlink support. For instance...
124 *
125 * rc = CIFSSMBQueryReparseLinkInfo(...)
126 *
127 * For now, just return -EACCES when the server doesn't support posix
128 * extensions. Note that we still allow querying symlinks when posix
129 * extensions are manually disabled. We could disable these as well
130 * but there doesn't seem to be any harm in allowing the client to
131 * read them.
132 */
133 if (!(tcon->ses->capabilities & CAP_UNIX)) {
134 rc = -EACCES;
135 goto out;
136 }
1da177e4 137
8b6427a2 138 full_path = build_path_from_dentry(direntry);
1da177e4 139 if (!full_path)
460b9696 140 goto out;
1da177e4
LT
141
142 cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
1da177e4 143
8b6427a2
JL
144 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
145 cifs_sb->local_nls);
146 kfree(full_path);
147out:
460b9696 148 if (rc != 0) {
1da177e4
LT
149 kfree(target_path);
150 target_path = ERR_PTR(rc);
151 }
152
1da177e4
LT
153 FreeXid(xid);
154 nd_set_link(nd, target_path);
460b9696 155 return NULL;
1da177e4
LT
156}
157
158int
159cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
160{
161 int rc = -EOPNOTSUPP;
162 int xid;
163 struct cifs_sb_info *cifs_sb;
164 struct cifsTconInfo *pTcon;
165 char *full_path = NULL;
166 struct inode *newinode = NULL;
167
168 xid = GetXid();
169
170 cifs_sb = CIFS_SB(inode->i_sb);
171 pTcon = cifs_sb->tcon;
172
7f57356b 173 full_path = build_path_from_dentry(direntry);
1da177e4 174
fb8c4b14 175 if (full_path == NULL) {
0f3bc09e 176 rc = -ENOMEM;
1da177e4 177 FreeXid(xid);
0f3bc09e 178 return rc;
1da177e4
LT
179 }
180
26a21b98 181 cFYI(1, ("Full path: %s", full_path));
1da177e4
LT
182 cFYI(1, ("symname is %s", symname));
183
184 /* BB what if DFS and this volume is on different share? BB */
c18c842b 185 if (pTcon->unix_ext)
1da177e4
LT
186 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
187 cifs_sb->local_nls);
188 /* else
fb8c4b14
SF
189 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
190 cifs_sb_target->local_nls); */
1da177e4
LT
191
192 if (rc == 0) {
c18c842b 193 if (pTcon->unix_ext)
1da177e4 194 rc = cifs_get_inode_info_unix(&newinode, full_path,
fb8c4b14 195 inode->i_sb, xid);
1da177e4
LT
196 else
197 rc = cifs_get_inode_info(&newinode, full_path, NULL,
8b1327f6 198 inode->i_sb, xid, NULL);
1da177e4
LT
199
200 if (rc != 0) {
26a21b98 201 cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
1da177e4
LT
202 rc));
203 } else {
b92327fe
SF
204 if (pTcon->nocase)
205 direntry->d_op = &cifs_ci_dentry_ops;
206 else
207 direntry->d_op = &cifs_dentry_ops;
1da177e4
LT
208 d_instantiate(direntry, newinode);
209 }
210 }
211
f99d49ad 212 kfree(full_path);
1da177e4
LT
213 FreeXid(xid);
214 return rc;
215}
216
cc314eef 217void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
1da177e4
LT
218{
219 char *p = nd_get_link(nd);
220 if (!IS_ERR(p))
221 kfree(p);
222}