]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/cifs/link.c
cifs: fix error handling in parse_DFS_referrals
[mirror_ubuntu-artful-kernel.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)
460b9696 122 goto out;
1da177e4
LT
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 127
c18c842b
SF
128 /* We could change this to:
129 if (pTcon->unix_ext)
130 but there does not seem any point in refusing to
131 get symlink info if we can, even if unix extensions
132 turned off for this mount */
133
1da177e4
LT
134 if (pTcon->ses->capabilities & CAP_UNIX)
135 rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
460b9696 136 &target_path,
1da177e4
LT
137 cifs_sb->local_nls);
138 else {
c18c842b 139 /* BB add read reparse point symlink code here */
1da177e4
LT
140 /* rc = CIFSSMBQueryReparseLinkInfo */
141 /* BB Add code to Query ReparsePoint info */
142 /* BB Add MAC style xsymlink check here if enabled */
143 }
144
460b9696 145 if (rc != 0) {
1da177e4
LT
146 kfree(target_path);
147 target_path = ERR_PTR(rc);
148 }
149
1da177e4 150 kfree(full_path);
460b9696 151out:
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) {
1da177e4
LT
175 FreeXid(xid);
176 return -ENOMEM;
177 }
178
26a21b98 179 cFYI(1, ("Full path: %s", full_path));
1da177e4
LT
180 cFYI(1, ("symname is %s", symname));
181
182 /* BB what if DFS and this volume is on different share? BB */
c18c842b 183 if (pTcon->unix_ext)
1da177e4
LT
184 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
185 cifs_sb->local_nls);
186 /* else
fb8c4b14
SF
187 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
188 cifs_sb_target->local_nls); */
1da177e4
LT
189
190 if (rc == 0) {
c18c842b 191 if (pTcon->unix_ext)
1da177e4 192 rc = cifs_get_inode_info_unix(&newinode, full_path,
fb8c4b14 193 inode->i_sb, xid);
1da177e4
LT
194 else
195 rc = cifs_get_inode_info(&newinode, full_path, NULL,
8b1327f6 196 inode->i_sb, xid, NULL);
1da177e4
LT
197
198 if (rc != 0) {
26a21b98 199 cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
1da177e4
LT
200 rc));
201 } else {
b92327fe
SF
202 if (pTcon->nocase)
203 direntry->d_op = &cifs_ci_dentry_ops;
204 else
205 direntry->d_op = &cifs_dentry_ops;
1da177e4
LT
206 d_instantiate(direntry, newinode);
207 }
208 }
209
f99d49ad 210 kfree(full_path);
1da177e4
LT
211 FreeXid(xid);
212 return rc;
213}
214
cc314eef 215void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
1da177e4
LT
216{
217 char *p = nd_get_link(nd);
218 if (!IS_ERR(p))
219 kfree(p);
220}