]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/cifs/link.c
Staging: usb-ip: vhci_hdc:Fix the returned error value
[net-next-2.6.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;
8b6427a2 110 int rc = -ENOMEM;
1da177e4
LT
111 int xid;
112 char *full_path = NULL;
8b6427a2
JL
113 char *target_path = NULL;
114 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
115 struct cifsTconInfo *tcon = cifs_sb->tcon;
1da177e4
LT
116
117 xid = GetXid();
118
8b6427a2
JL
119 /*
120 * For now, we just handle symlinks with unix extensions enabled.
121 * Eventually we should handle NTFS reparse points, and MacOS
122 * symlink support. For instance...
123 *
124 * rc = CIFSSMBQueryReparseLinkInfo(...)
125 *
126 * For now, just return -EACCES when the server doesn't support posix
127 * extensions. Note that we still allow querying symlinks when posix
128 * extensions are manually disabled. We could disable these as well
129 * but there doesn't seem to be any harm in allowing the client to
130 * read them.
131 */
132 if (!(tcon->ses->capabilities & CAP_UNIX)) {
133 rc = -EACCES;
134 goto out;
135 }
1da177e4 136
8b6427a2 137 full_path = build_path_from_dentry(direntry);
1da177e4 138 if (!full_path)
460b9696 139 goto out;
1da177e4
LT
140
141 cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
1da177e4 142
8b6427a2
JL
143 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
144 cifs_sb->local_nls);
145 kfree(full_path);
146out:
460b9696 147 if (rc != 0) {
1da177e4
LT
148 kfree(target_path);
149 target_path = ERR_PTR(rc);
150 }
151
1da177e4
LT
152 FreeXid(xid);
153 nd_set_link(nd, target_path);
460b9696 154 return NULL;
1da177e4
LT
155}
156
157int
158cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
159{
160 int rc = -EOPNOTSUPP;
161 int xid;
162 struct cifs_sb_info *cifs_sb;
163 struct cifsTconInfo *pTcon;
164 char *full_path = NULL;
165 struct inode *newinode = NULL;
166
167 xid = GetXid();
168
169 cifs_sb = CIFS_SB(inode->i_sb);
170 pTcon = cifs_sb->tcon;
171
7f57356b 172 full_path = build_path_from_dentry(direntry);
1da177e4 173
fb8c4b14 174 if (full_path == NULL) {
0f3bc09e 175 rc = -ENOMEM;
1da177e4 176 FreeXid(xid);
0f3bc09e 177 return rc;
1da177e4
LT
178 }
179
26a21b98 180 cFYI(1, ("Full path: %s", full_path));
1da177e4
LT
181 cFYI(1, ("symname is %s", symname));
182
183 /* BB what if DFS and this volume is on different share? BB */
c18c842b 184 if (pTcon->unix_ext)
1da177e4
LT
185 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
186 cifs_sb->local_nls);
187 /* else
fb8c4b14
SF
188 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
189 cifs_sb_target->local_nls); */
1da177e4
LT
190
191 if (rc == 0) {
c18c842b 192 if (pTcon->unix_ext)
1da177e4 193 rc = cifs_get_inode_info_unix(&newinode, full_path,
fb8c4b14 194 inode->i_sb, xid);
1da177e4
LT
195 else
196 rc = cifs_get_inode_info(&newinode, full_path, NULL,
8b1327f6 197 inode->i_sb, xid, NULL);
1da177e4
LT
198
199 if (rc != 0) {
26a21b98 200 cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
1da177e4
LT
201 rc));
202 } else {
b92327fe
SF
203 if (pTcon->nocase)
204 direntry->d_op = &cifs_ci_dentry_ops;
205 else
206 direntry->d_op = &cifs_dentry_ops;
1da177e4
LT
207 d_instantiate(direntry, newinode);
208 }
209 }
210
f99d49ad 211 kfree(full_path);
1da177e4
LT
212 FreeXid(xid);
213 return rc;
214}
215
cc314eef 216void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
1da177e4
LT
217{
218 char *p = nd_get_link(nd);
219 if (!IS_ERR(p))
220 kfree(p);
221}