blob: df071fb2567fbfa0a64bea19d6de85f3a5ed83d4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/inode.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * 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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/stat.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/pagemap.h>
25#include <asm/div64.h>
26#include "cifsfs.h"
27#include "cifspdu.h"
28#include "cifsglob.h"
29#include "cifsproto.h"
30#include "cifs_debug.h"
31#include "cifs_fs_sb.h"
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +053032#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Christoph Hellwig70eff552008-02-15 20:55:05 +000034
David Howells01c64fe2011-01-14 18:45:47 +000035static void cifs_set_ops(struct inode *inode)
Christoph Hellwig70eff552008-02-15 20:55:05 +000036{
37 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
38
39 switch (inode->i_mode & S_IFMT) {
40 case S_IFREG:
41 inode->i_op = &cifs_file_inode_ops;
42 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
43 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
44 inode->i_fop = &cifs_file_direct_nobrl_ops;
45 else
46 inode->i_fop = &cifs_file_direct_ops;
Pavel Shilovsky8be7e6b2010-12-12 13:11:13 +030047 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
48 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
49 inode->i_fop = &cifs_file_strict_nobrl_ops;
50 else
51 inode->i_fop = &cifs_file_strict_ops;
Christoph Hellwig70eff552008-02-15 20:55:05 +000052 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
53 inode->i_fop = &cifs_file_nobrl_ops;
54 else { /* not direct, send byte range locks */
55 inode->i_fop = &cifs_file_ops;
56 }
57
Christoph Hellwig70eff552008-02-15 20:55:05 +000058 /* check if server can support readpages */
Jeff Layton0d424ad2010-09-20 16:01:35 -070059 if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
Christoph Hellwig70eff552008-02-15 20:55:05 +000060 PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
61 inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
62 else
63 inode->i_data.a_ops = &cifs_addr_ops;
64 break;
65 case S_IFDIR:
Steve Frenchbc5b6e22008-03-11 21:07:48 +000066#ifdef CONFIG_CIFS_DFS_UPCALL
David Howells01c64fe2011-01-14 18:45:47 +000067 if (IS_AUTOMOUNT(inode)) {
Igor Mammedov79626702008-03-09 03:44:18 +000068 inode->i_op = &cifs_dfs_referral_inode_operations;
69 } else {
Steve Frenchbc5b6e22008-03-11 21:07:48 +000070#else /* NO DFS support, treat as a directory */
71 {
72#endif
Igor Mammedov79626702008-03-09 03:44:18 +000073 inode->i_op = &cifs_dir_inode_ops;
74 inode->i_fop = &cifs_dir_ops;
75 }
Christoph Hellwig70eff552008-02-15 20:55:05 +000076 break;
77 case S_IFLNK:
78 inode->i_op = &cifs_symlink_inode_ops;
79 break;
80 default:
81 init_special_inode(inode, inode->i_mode, inode->i_rdev);
82 break;
83 }
84}
85
Jeff Laytondf2cf172010-02-12 07:44:16 -050086/* check inode attributes against fattr. If they don't match, tag the
87 * inode for cache invalidation
88 */
89static void
90cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
91{
92 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
93
Steve Frenchf19159d2010-04-21 04:12:10 +000094 cFYI(1, "%s: revalidating inode %llu", __func__, cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -050095
96 if (inode->i_state & I_NEW) {
Steve Frenchf19159d2010-04-21 04:12:10 +000097 cFYI(1, "%s: inode %llu is new", __func__, cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -050098 return;
99 }
100
101 /* don't bother with revalidation if we have an oplock */
102 if (cifs_i->clientCanCacheRead) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000103 cFYI(1, "%s: inode %llu is oplocked", __func__,
104 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500105 return;
106 }
107
108 /* revalidate if mtime or size have changed */
109 if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) &&
110 cifs_i->server_eof == fattr->cf_eof) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000111 cFYI(1, "%s: inode %llu is unchanged", __func__,
112 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500113 return;
114 }
115
Steve Frenchf19159d2010-04-21 04:12:10 +0000116 cFYI(1, "%s: invalidating inode %llu mapping", __func__,
117 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500118 cifs_i->invalid_mapping = true;
119}
120
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400121/* populate an inode with info from a cifs_fattr struct */
122void
123cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
Christoph Hellwig75f12982008-02-25 20:25:21 +0000124{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400125 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400126 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
127 unsigned long oldtime = cifs_i->time;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000128
Jeff Laytondf2cf172010-02-12 07:44:16 -0500129 cifs_revalidate_cache(inode, fattr);
130
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400131 inode->i_atime = fattr->cf_atime;
132 inode->i_mtime = fattr->cf_mtime;
133 inode->i_ctime = fattr->cf_ctime;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400134 inode->i_rdev = fattr->cf_rdev;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200135 set_nlink(inode, fattr->cf_nlink);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400136 inode->i_uid = fattr->cf_uid;
137 inode->i_gid = fattr->cf_gid;
138
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400139 /* if dynperm is set, don't clobber existing mode */
140 if (inode->i_state & I_NEW ||
141 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
142 inode->i_mode = fattr->cf_mode;
143
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400144 cifs_i->cifsAttrs = fattr->cf_cifsattrs;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400145
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400146 if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
147 cifs_i->time = 0;
148 else
149 cifs_i->time = jiffies;
150
Joe Perchesb6b38f72010-04-21 03:50:45 +0000151 cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode,
152 oldtime, cifs_i->time);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400153
154 cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000155
Jeff Layton835a36c2010-02-10 16:21:33 -0500156 cifs_i->server_eof = fattr->cf_eof;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000157 /*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400158 * Can't safely change the file size here if the client is writing to
159 * it due to potential races.
Christoph Hellwig75f12982008-02-25 20:25:21 +0000160 */
Christoph Hellwig75f12982008-02-25 20:25:21 +0000161 spin_lock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400162 if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
163 i_size_write(inode, fattr->cf_eof);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000164
165 /*
166 * i_blocks is not related to (i_size / i_blksize),
167 * but instead 512 byte (2**9) size is required for
168 * calculating num blocks.
169 */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400170 inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000171 }
172 spin_unlock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400173
David Howells01c64fe2011-01-14 18:45:47 +0000174 if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
175 inode->i_flags |= S_AUTOMOUNT;
176 cifs_set_ops(inode);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000177}
178
Jeff Layton4065c802010-05-17 07:18:58 -0400179void
180cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr)
181{
182 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
183
184 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
185 return;
186
187 fattr->cf_uniqueid = iunique(sb, ROOT_I);
188}
189
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400190/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
191void
192cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
193 struct cifs_sb_info *cifs_sb)
194{
195 memset(fattr, 0, sizeof(*fattr));
196 fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
197 fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
198 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
199
200 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
201 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
202 fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
203 fattr->cf_mode = le64_to_cpu(info->Permissions);
204
205 /*
206 * Since we set the inode type below we need to mask off
207 * to avoid strange results if bits set above.
208 */
209 fattr->cf_mode &= ~S_IFMT;
210 switch (le32_to_cpu(info->Type)) {
211 case UNIX_FILE:
212 fattr->cf_mode |= S_IFREG;
213 fattr->cf_dtype = DT_REG;
214 break;
215 case UNIX_SYMLINK:
216 fattr->cf_mode |= S_IFLNK;
217 fattr->cf_dtype = DT_LNK;
218 break;
219 case UNIX_DIR:
220 fattr->cf_mode |= S_IFDIR;
221 fattr->cf_dtype = DT_DIR;
222 break;
223 case UNIX_CHARDEV:
224 fattr->cf_mode |= S_IFCHR;
225 fattr->cf_dtype = DT_CHR;
226 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
227 le64_to_cpu(info->DevMinor) & MINORMASK);
228 break;
229 case UNIX_BLOCKDEV:
230 fattr->cf_mode |= S_IFBLK;
231 fattr->cf_dtype = DT_BLK;
232 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
233 le64_to_cpu(info->DevMinor) & MINORMASK);
234 break;
235 case UNIX_FIFO:
236 fattr->cf_mode |= S_IFIFO;
237 fattr->cf_dtype = DT_FIFO;
238 break;
239 case UNIX_SOCKET:
240 fattr->cf_mode |= S_IFSOCK;
241 fattr->cf_dtype = DT_SOCK;
242 break;
243 default:
244 /* safest to call it a file if we do not know */
245 fattr->cf_mode |= S_IFREG;
246 fattr->cf_dtype = DT_REG;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000247 cFYI(1, "unknown type %d", le32_to_cpu(info->Type));
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400248 break;
249 }
250
251 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
252 fattr->cf_uid = cifs_sb->mnt_uid;
253 else
254 fattr->cf_uid = le64_to_cpu(info->Uid);
255
256 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
257 fattr->cf_gid = cifs_sb->mnt_gid;
258 else
259 fattr->cf_gid = le64_to_cpu(info->Gid);
260
261 fattr->cf_nlink = le64_to_cpu(info->Nlinks);
262}
Steve Frenchb9a32602008-05-20 21:52:32 +0000263
264/*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400265 * Fill a cifs_fattr struct with fake inode info.
266 *
267 * Needed to setup cifs_fattr data for the directory which is the
268 * junction to the new submount (ie to setup the fake directory
269 * which represents a DFS referral).
Steve Frenchb9a32602008-05-20 21:52:32 +0000270 */
Steve Frenchf1230c92009-07-22 23:13:01 +0000271static void
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400272cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
Steve French0e4bbde2008-05-20 19:50:46 +0000273{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400274 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Steve French0e4bbde2008-05-20 19:50:46 +0000275
Joe Perchesb6b38f72010-04-21 03:50:45 +0000276 cFYI(1, "creating fake fattr for DFS referral");
Steve French0e4bbde2008-05-20 19:50:46 +0000277
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400278 memset(fattr, 0, sizeof(*fattr));
279 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
280 fattr->cf_uid = cifs_sb->mnt_uid;
281 fattr->cf_gid = cifs_sb->mnt_gid;
282 fattr->cf_atime = CURRENT_TIME;
283 fattr->cf_ctime = CURRENT_TIME;
284 fattr->cf_mtime = CURRENT_TIME;
285 fattr->cf_nlink = 2;
286 fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
Steve French0e4bbde2008-05-20 19:50:46 +0000287}
288
Jeff Laytonabab0952010-02-12 07:44:18 -0500289int cifs_get_file_info_unix(struct file *filp)
290{
291 int rc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400292 unsigned int xid;
Jeff Laytonabab0952010-02-12 07:44:18 -0500293 FILE_UNIX_BASIC_INFO find_data;
294 struct cifs_fattr fattr;
295 struct inode *inode = filp->f_path.dentry->d_inode;
296 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Joe Perchesc21dfb62010-07-12 13:50:14 -0700297 struct cifsFileInfo *cfile = filp->private_data;
Steve French96daf2b2011-05-27 04:34:02 +0000298 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Jeff Laytonabab0952010-02-12 07:44:18 -0500299
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400300 xid = get_xid();
Jeff Laytonabab0952010-02-12 07:44:18 -0500301 rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
302 if (!rc) {
303 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
304 } else if (rc == -EREMOTE) {
305 cifs_create_dfs_fattr(&fattr, inode->i_sb);
306 rc = 0;
307 }
308
309 cifs_fattr_to_inode(inode, &fattr);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400310 free_xid(xid);
Jeff Laytonabab0952010-02-12 07:44:18 -0500311 return rc;
312}
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314int cifs_get_inode_info_unix(struct inode **pinode,
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400315 const unsigned char *full_path,
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400316 struct super_block *sb, unsigned int xid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400318 int rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000319 FILE_UNIX_BASIC_INFO find_data;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400320 struct cifs_fattr fattr;
Steve French96daf2b2011-05-27 04:34:02 +0000321 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400322 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Joe Perchesb6b38f72010-04-21 03:50:45 +0000325 cFYI(1, "Getting info on %s", full_path);
Igor Mammedov79626702008-03-09 03:44:18 +0000326
Jeff Layton7ffec372010-09-29 19:51:11 -0400327 tlink = cifs_sb_tlink(cifs_sb);
328 if (IS_ERR(tlink))
329 return PTR_ERR(tlink);
330 tcon = tlink_tcon(tlink);
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /* could have done a find first instead but this returns more info */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400333 rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
Steve French737b7582005-04-28 22:41:06 -0700334 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
335 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -0400336 cifs_put_tlink(tlink);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400337
338 if (!rc) {
339 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
340 } else if (rc == -EREMOTE) {
341 cifs_create_dfs_fattr(&fattr, sb);
Jeff Laytone911d0c2008-07-12 13:47:59 -0700342 rc = 0;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400343 } else {
344 return rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000345 }
346
Stefan Metzmacher1b12b9c2010-08-05 21:19:56 +0200347 /* check for Minshall+French symlinks */
348 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
349 int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
350 if (tmprc)
351 cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
352 }
353
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400354 if (*pinode == NULL) {
355 /* get new inode */
Jeff Layton4065c802010-05-17 07:18:58 -0400356 cifs_fill_uniqueid(sb, &fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400357 *pinode = cifs_iget(sb, &fattr);
358 if (!*pinode)
359 rc = -ENOMEM;
360 } else {
361 /* we already have inode, update it */
362 cifs_fattr_to_inode(*pinode, &fattr);
363 }
Steve French0e4bbde2008-05-20 19:50:46 +0000364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 return rc;
366}
367
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400368static int
369cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400370 struct cifs_sb_info *cifs_sb, unsigned int xid)
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800371{
372 int rc;
Steve French4b18f2a2008-04-29 00:06:05 +0000373 int oplock = 0;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800374 __u16 netfid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400375 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +0000376 struct cifs_tcon *tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +0000377 struct cifs_io_parms io_parms;
Steve French86c96b42005-11-18 20:25:31 -0800378 char buf[24];
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800379 unsigned int bytes_read;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000380 char *pbuf;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800381
382 pbuf = buf;
383
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400384 fattr->cf_mode &= ~S_IFMT;
385
386 if (fattr->cf_eof == 0) {
387 fattr->cf_mode |= S_IFIFO;
388 fattr->cf_dtype = DT_FIFO;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800389 return 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400390 } else if (fattr->cf_eof < 8) {
391 fattr->cf_mode |= S_IFREG;
392 fattr->cf_dtype = DT_REG;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800393 return -EINVAL; /* EOPNOTSUPP? */
394 }
Steve French50c2f752007-07-13 00:33:32 +0000395
Jeff Layton7ffec372010-09-29 19:51:11 -0400396 tlink = cifs_sb_tlink(cifs_sb);
397 if (IS_ERR(tlink))
398 return PTR_ERR(tlink);
399 tcon = tlink_tcon(tlink);
400
401 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ,
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800402 CREATE_NOT_DIR, &netfid, &oplock, NULL,
403 cifs_sb->local_nls,
404 cifs_sb->mnt_cifs_flags &
405 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000406 if (rc == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -0800407 int buf_type = CIFS_NO_BUFFER;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800408 /* Read header */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +0000409 io_parms.netfid = netfid;
410 io_parms.pid = current->tgid;
411 io_parms.tcon = tcon;
412 io_parms.offset = 0;
413 io_parms.length = 24;
414 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf,
415 &buf_type);
Steve French4523cc32007-04-30 20:13:06 +0000416 if ((rc == 0) && (bytes_read >= 8)) {
417 if (memcmp("IntxBLK", pbuf, 8) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000418 cFYI(1, "Block device");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400419 fattr->cf_mode |= S_IFBLK;
420 fattr->cf_dtype = DT_BLK;
Steve French4523cc32007-04-30 20:13:06 +0000421 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800422 /* we have enough to decode dev num */
423 __u64 mjr; /* major */
424 __u64 mnr; /* minor */
425 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
426 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400427 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve French86c96b42005-11-18 20:25:31 -0800428 }
Steve French4523cc32007-04-30 20:13:06 +0000429 } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000430 cFYI(1, "Char device");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400431 fattr->cf_mode |= S_IFCHR;
432 fattr->cf_dtype = DT_CHR;
Steve French4523cc32007-04-30 20:13:06 +0000433 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800434 /* we have enough to decode dev num */
435 __u64 mjr; /* major */
436 __u64 mnr; /* minor */
437 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
438 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400439 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000440 }
Steve French4523cc32007-04-30 20:13:06 +0000441 } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000442 cFYI(1, "Symlink");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400443 fattr->cf_mode |= S_IFLNK;
444 fattr->cf_dtype = DT_LNK;
Steve French86c96b42005-11-18 20:25:31 -0800445 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400446 fattr->cf_mode |= S_IFREG; /* file? */
447 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000448 rc = -EOPNOTSUPP;
Steve French86c96b42005-11-18 20:25:31 -0800449 }
Steve French3020a1f2005-11-18 11:31:10 -0800450 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400451 fattr->cf_mode |= S_IFREG; /* then it is a file */
452 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000453 rc = -EOPNOTSUPP; /* or some unknown SFU type */
454 }
Jeff Layton7ffec372010-09-29 19:51:11 -0400455 CIFSSMBClose(xid, tcon, netfid);
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800456 }
Jeff Layton7ffec372010-09-29 19:51:11 -0400457 cifs_put_tlink(tlink);
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800458 return rc;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800459}
460
Steve French9e294f12005-11-17 16:59:21 -0800461#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
462
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400463/*
464 * Fetch mode bits as provided by SFU.
465 *
466 * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
467 */
468static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400469 struct cifs_sb_info *cifs_sb, unsigned int xid)
Steve French9e294f12005-11-17 16:59:21 -0800470{
Steve French3020a1f2005-11-18 11:31:10 -0800471#ifdef CONFIG_CIFS_XATTR
Steve French9e294f12005-11-17 16:59:21 -0800472 ssize_t rc;
473 char ea_value[4];
474 __u32 mode;
Jeff Layton7ffec372010-09-29 19:51:11 -0400475 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +0000476 struct cifs_tcon *tcon;
Steve French9e294f12005-11-17 16:59:21 -0800477
Jeff Layton7ffec372010-09-29 19:51:11 -0400478 tlink = cifs_sb_tlink(cifs_sb);
479 if (IS_ERR(tlink))
480 return PTR_ERR(tlink);
481 tcon = tlink_tcon(tlink);
482
483 rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS",
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400484 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
485 cifs_sb->mnt_cifs_flags &
486 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -0400487 cifs_put_tlink(tlink);
Steve French4523cc32007-04-30 20:13:06 +0000488 if (rc < 0)
Steve French9e294f12005-11-17 16:59:21 -0800489 return (int)rc;
490 else if (rc > 3) {
491 mode = le32_to_cpu(*((__le32 *)ea_value));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400492 fattr->cf_mode &= ~SFBITS_MASK;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000493 cFYI(1, "special bits 0%o org mode 0%o", mode,
494 fattr->cf_mode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400495 fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000496 cFYI(1, "special mode bits 0%o", mode);
Steve French9e294f12005-11-17 16:59:21 -0800497 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400498
499 return 0;
Steve French3020a1f2005-11-18 11:31:10 -0800500#else
501 return -EOPNOTSUPP;
502#endif
Steve French9e294f12005-11-17 16:59:21 -0800503}
504
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400505/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
Steve Frenchf1230c92009-07-22 23:13:01 +0000506static void
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400507cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
508 struct cifs_sb_info *cifs_sb, bool adjust_tz)
Steve Frenchb9a32602008-05-20 21:52:32 +0000509{
Steve French96daf2b2011-05-27 04:34:02 +0000510 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
Jeff Layton0d424ad2010-09-20 16:01:35 -0700511
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400512 memset(fattr, 0, sizeof(*fattr));
513 fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
514 if (info->DeletePending)
515 fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
Steve Frenchb9a32602008-05-20 21:52:32 +0000516
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400517 if (info->LastAccessTime)
518 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
519 else
520 fattr->cf_atime = CURRENT_TIME;
521
522 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
523 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
524
525 if (adjust_tz) {
Jeff Layton0d424ad2010-09-20 16:01:35 -0700526 fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
527 fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400528 }
529
530 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
531 fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
Jeff Layton20054bd2011-01-07 11:30:27 -0500532 fattr->cf_createtime = le64_to_cpu(info->CreationTime);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400533
534 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
535 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
536 fattr->cf_dtype = DT_DIR;
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +0300537 /*
538 * Server can return wrong NumberOfLinks value for directories
539 * when Unix extensions are disabled - fake it.
540 */
541 fattr->cf_nlink = 2;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400542 } else {
543 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
544 fattr->cf_dtype = DT_REG;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400545
Jeff Laytond0c280d2009-07-09 01:46:44 -0400546 /* clear write bits if ATTR_READONLY is set */
547 if (fattr->cf_cifsattrs & ATTR_READONLY)
548 fattr->cf_mode &= ~(S_IWUGO);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400549
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +0300550 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
551 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400552
553 fattr->cf_uid = cifs_sb->mnt_uid;
554 fattr->cf_gid = cifs_sb->mnt_gid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000555}
556
Jeff Laytonabab0952010-02-12 07:44:18 -0500557int cifs_get_file_info(struct file *filp)
558{
559 int rc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400560 unsigned int xid;
Jeff Laytonabab0952010-02-12 07:44:18 -0500561 FILE_ALL_INFO find_data;
562 struct cifs_fattr fattr;
563 struct inode *inode = filp->f_path.dentry->d_inode;
564 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Joe Perchesc21dfb62010-07-12 13:50:14 -0700565 struct cifsFileInfo *cfile = filp->private_data;
Steve French96daf2b2011-05-27 04:34:02 +0000566 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Jeff Laytonabab0952010-02-12 07:44:18 -0500567
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400568 xid = get_xid();
Jeff Laytonabab0952010-02-12 07:44:18 -0500569 rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400570 switch (rc) {
571 case 0:
572 cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
573 break;
574 case -EREMOTE:
575 cifs_create_dfs_fattr(&fattr, inode->i_sb);
576 rc = 0;
577 break;
578 case -EOPNOTSUPP:
579 case -EINVAL:
Jeff Laytonabab0952010-02-12 07:44:18 -0500580 /*
581 * FIXME: legacy server -- fall back to path-based call?
Steve Frenchff2157132010-03-09 20:30:42 +0000582 * for now, just skip revalidating and mark inode for
583 * immediate reval.
584 */
Jeff Laytonabab0952010-02-12 07:44:18 -0500585 rc = 0;
586 CIFS_I(inode)->time = 0;
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400587 default:
Jeff Laytonabab0952010-02-12 07:44:18 -0500588 goto cgfi_exit;
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400589 }
Jeff Laytonabab0952010-02-12 07:44:18 -0500590
591 /*
592 * don't bother with SFU junk here -- just mark inode as needing
593 * revalidation.
594 */
Jeff Laytonabab0952010-02-12 07:44:18 -0500595 fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
596 fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
597 cifs_fattr_to_inode(inode, &fattr);
598cgfi_exit:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400599 free_xid(xid);
Jeff Laytonabab0952010-02-12 07:44:18 -0500600 return rc;
601}
602
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400603int
604cifs_get_inode_info(struct inode **inode, const char *full_path,
605 FILE_ALL_INFO *data, struct super_block *sb, int xid,
606 const __u16 *fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400608 int rc = 0, tmprc;
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400609 struct cifs_tcon *tcon;
610 struct TCP_Server_Info *server;
Jeff Layton7ffec372010-09-29 19:51:11 -0400611 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 char *buf = NULL;
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400614 bool adjust_tz = false;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400615 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
Jeff Layton7ffec372010-09-29 19:51:11 -0400617 tlink = cifs_sb_tlink(cifs_sb);
618 if (IS_ERR(tlink))
619 return PTR_ERR(tlink);
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400620 tcon = tlink_tcon(tlink);
621 server = tcon->ses->server;
Jeff Layton7ffec372010-09-29 19:51:11 -0400622
Joe Perchesb6b38f72010-04-21 03:50:45 +0000623 cFYI(1, "Getting info on %s", full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400625 if ((data == NULL) && (*inode != NULL)) {
626 if (CIFS_I(*inode)->clientCanCacheRead) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000627 cFYI(1, "No need to revalidate cached inode sizes");
Jeff Layton7ffec372010-09-29 19:51:11 -0400628 goto cgii_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
630 }
631
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400632 /* if inode info is not passed, get it from server */
633 if (data == NULL) {
634 if (!server->ops->query_path_info) {
635 rc = -ENOSYS;
636 goto cgii_exit;
637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Jeff Layton7ffec372010-09-29 19:51:11 -0400639 if (buf == NULL) {
640 rc = -ENOMEM;
641 goto cgii_exit;
642 }
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400643 data = (FILE_ALL_INFO *)buf;
644 rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path,
645 data, &adjust_tz);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400647
648 if (!rc) {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400649 cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *)data, cifs_sb,
650 adjust_tz);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400651 } else if (rc == -EREMOTE) {
652 cifs_create_dfs_fattr(&fattr, sb);
Steve Frenchb9a32602008-05-20 21:52:32 +0000653 rc = 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400654 } else {
Igor Mammedov79626702008-03-09 03:44:18 +0000655 goto cgii_exit;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400658 /*
659 * If an inode wasn't passed in, then get the inode number
660 *
661 * Is an i_ino of zero legal? Can we use that to check if the server
662 * supports returning inode numbers? Are there other sanity checks we
663 * can use to ensure that the server is really filling in that field?
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400664 */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400665 if (*inode == NULL) {
Steve Frenchb9a32602008-05-20 21:52:32 +0000666 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400667 if (server->ops->get_srv_inum)
668 tmprc = server->ops->get_srv_inum(xid, tcon,
669 cifs_sb, full_path, &fattr.cf_uniqueid,
670 data);
671 else
672 tmprc = -ENOSYS;
673 if (tmprc || !fattr.cf_uniqueid) {
674 cFYI(1, "GetSrvInodeNum rc %d", tmprc);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400675 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500676 cifs_autodisable_serverino(cifs_sb);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500677 }
Jeff Layton132ac7b2009-02-10 07:33:57 -0500678 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400679 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500680 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000681 } else {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400682 fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000683 }
684
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400685 /* query for SFU type info if supported and needed */
686 if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
687 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
688 tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
689 if (tmprc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000690 cFYI(1, "cifs_sfu_type failed: %d", tmprc);
Steve Frenchb9a32602008-05-20 21:52:32 +0000691 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000692
Jeff Layton79df1ba2010-12-06 12:52:08 -0500693#ifdef CONFIG_CIFS_ACL
Steve Frenchb9a32602008-05-20 21:52:32 +0000694 /* fill in 0777 bits from ACL */
695 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400696 rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid);
Shirish Pargaonkar78415d22010-11-27 11:37:26 -0600697 if (rc) {
698 cFYI(1, "%s: Getting ACL failed with error: %d",
699 __func__, rc);
700 goto cgii_exit;
701 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000702 }
Jeff Layton79df1ba2010-12-06 12:52:08 -0500703#endif /* CONFIG_CIFS_ACL */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400704
705 /* fill in remaining high mode bits e.g. SUID, VTX */
706 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
707 cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
708
Stefan Metzmacher1b12b9c2010-08-05 21:19:56 +0200709 /* check for Minshall+French symlinks */
710 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
711 tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
712 if (tmprc)
713 cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
714 }
715
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400716 if (!*inode) {
717 *inode = cifs_iget(sb, &fattr);
718 if (!*inode)
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400719 rc = -ENOMEM;
720 } else {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400721 cifs_fattr_to_inode(*inode, &fattr);
Steve Frenchb9a32602008-05-20 21:52:32 +0000722 }
723
Igor Mammedov79626702008-03-09 03:44:18 +0000724cgii_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 kfree(buf);
Jeff Layton7ffec372010-09-29 19:51:11 -0400726 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return rc;
728}
729
Steve French7f8ed422007-09-28 22:28:55 +0000730static const struct inode_operations cifs_ipc_inode_ops = {
731 .lookup = cifs_lookup,
732};
733
Steve Frenchf87d39d2011-05-27 03:50:55 +0000734char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
Steve French96daf2b2011-05-27 04:34:02 +0000735 struct cifs_tcon *tcon)
Steve French8be0ed42008-12-05 19:14:12 +0000736{
Steve Frenchf87d39d2011-05-27 03:50:55 +0000737 int pplen = vol->prepath ? strlen(vol->prepath) : 0;
Steve French8be0ed42008-12-05 19:14:12 +0000738 int dfsplen;
739 char *full_path = NULL;
740
741 /* if no prefix path, simply set path to the root of share to "" */
742 if (pplen == 0) {
743 full_path = kmalloc(1, GFP_KERNEL);
744 if (full_path)
745 full_path[0] = 0;
746 return full_path;
747 }
748
Jeff Layton0d424ad2010-09-20 16:01:35 -0700749 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
750 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
Steve French8be0ed42008-12-05 19:14:12 +0000751 else
752 dfsplen = 0;
753
754 full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
755 if (full_path == NULL)
756 return full_path;
757
Jeff Laytonf9e8c452011-08-05 10:28:01 -0400758 if (dfsplen)
Jeff Layton0d424ad2010-09-20 16:01:35 -0700759 strncpy(full_path, tcon->treeName, dfsplen);
Steve Frenchf87d39d2011-05-27 03:50:55 +0000760 strncpy(full_path + dfsplen, vol->prepath, pplen);
Jeff Laytonf9e8c452011-08-05 10:28:01 -0400761 convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
Steve French8be0ed42008-12-05 19:14:12 +0000762 full_path[dfsplen + pplen] = 0; /* add trailing null */
763 return full_path;
764}
765
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400766static int
767cifs_find_inode(struct inode *inode, void *opaque)
768{
769 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
770
Jeff Laytonf30b9c12010-07-19 18:00:17 -0400771 /* don't match inode with different uniqueid */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400772 if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
773 return 0;
774
Jeff Layton20054bd2011-01-07 11:30:27 -0500775 /* use createtime like an i_generation field */
776 if (CIFS_I(inode)->createtime != fattr->cf_createtime)
777 return 0;
778
Jeff Laytonf30b9c12010-07-19 18:00:17 -0400779 /* don't match inode of different type */
780 if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
781 return 0;
782
Jeff Layton5acfec22010-08-02 17:43:54 -0400783 /* if it's not a directory or has no dentries, then flag it */
Al Virob3d9b7a2012-06-09 13:51:19 -0400784 if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
Jeff Layton3d694382010-05-11 14:59:55 -0400785 fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
Jeff Layton3d694382010-05-11 14:59:55 -0400786
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400787 return 1;
788}
789
790static int
791cifs_init_inode(struct inode *inode, void *opaque)
792{
793 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
794
795 CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
Jeff Layton20054bd2011-01-07 11:30:27 -0500796 CIFS_I(inode)->createtime = fattr->cf_createtime;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400797 return 0;
798}
799
Jeff Layton5acfec22010-08-02 17:43:54 -0400800/*
801 * walk dentry list for an inode and report whether it has aliases that
802 * are hashed. We use this to determine if a directory inode can actually
803 * be used.
804 */
805static bool
806inode_has_hashed_dentries(struct inode *inode)
807{
808 struct dentry *dentry;
Al Virob3d9b7a2012-06-09 13:51:19 -0400809 struct hlist_node *p;
Jeff Layton5acfec22010-08-02 17:43:54 -0400810
Nick Piggin873feea2011-01-07 17:50:06 +1100811 spin_lock(&inode->i_lock);
Al Virob3d9b7a2012-06-09 13:51:19 -0400812 hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
Jeff Layton5acfec22010-08-02 17:43:54 -0400813 if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
Nick Piggin873feea2011-01-07 17:50:06 +1100814 spin_unlock(&inode->i_lock);
Jeff Layton5acfec22010-08-02 17:43:54 -0400815 return true;
816 }
817 }
Nick Piggin873feea2011-01-07 17:50:06 +1100818 spin_unlock(&inode->i_lock);
Jeff Layton5acfec22010-08-02 17:43:54 -0400819 return false;
820}
821
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400822/* Given fattrs, get a corresponding inode */
823struct inode *
824cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
825{
826 unsigned long hash;
827 struct inode *inode;
828
Jeff Layton3d694382010-05-11 14:59:55 -0400829retry_iget5_locked:
Joe Perchesb6b38f72010-04-21 03:50:45 +0000830 cFYI(1, "looking for uniqueid=%llu", fattr->cf_uniqueid);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400831
832 /* hash down to 32-bits on 32-bit arch */
833 hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
834
835 inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400836 if (inode) {
Jeff Layton5acfec22010-08-02 17:43:54 -0400837 /* was there a potentially problematic inode collision? */
Jeff Layton3d694382010-05-11 14:59:55 -0400838 if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
Jeff Layton3d694382010-05-11 14:59:55 -0400839 fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
Jeff Layton5acfec22010-08-02 17:43:54 -0400840
841 if (inode_has_hashed_dentries(inode)) {
842 cifs_autodisable_serverino(CIFS_SB(sb));
843 iput(inode);
844 fattr->cf_uniqueid = iunique(sb, ROOT_I);
845 goto retry_iget5_locked;
846 }
Jeff Layton3d694382010-05-11 14:59:55 -0400847 }
848
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400849 cifs_fattr_to_inode(inode, fattr);
850 if (sb->s_flags & MS_NOATIME)
851 inode->i_flags |= S_NOATIME | S_NOCMTIME;
852 if (inode->i_state & I_NEW) {
853 inode->i_ino = hash;
Jeff Layton522440e2010-09-29 09:49:54 -0400854 if (S_ISREG(inode->i_mode))
855 inode->i_data.backing_dev_info = sb->s_bdi;
Steve French0ccd4802010-07-16 04:31:02 +0000856#ifdef CONFIG_CIFS_FSCACHE
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530857 /* initialize per-inode cache cookie pointer */
858 CIFS_I(inode)->fscache = NULL;
Steve French0ccd4802010-07-16 04:31:02 +0000859#endif
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400860 unlock_new_inode(inode);
861 }
862 }
863
864 return inode;
865}
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867/* gets root inode */
Shirish Pargaonkar9b6763e2011-02-21 23:56:59 -0600868struct inode *cifs_root_iget(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869{
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400870 unsigned int xid;
Jeff Layton0d424ad2010-09-20 16:01:35 -0700871 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400872 struct inode *inode = NULL;
David Howellsce634ab2008-02-07 00:15:33 -0800873 long rc;
Steve French96daf2b2011-05-27 04:34:02 +0000874 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
David Howellsce634ab2008-02-07 00:15:33 -0800875
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400876 xid = get_xid();
Jeff Layton0d424ad2010-09-20 16:01:35 -0700877 if (tcon->unix_ext)
Steve Frenchf87d39d2011-05-27 03:50:55 +0000878 rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400879 else
Steve Frenchf87d39d2011-05-27 03:50:55 +0000880 rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400881
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000882 if (!inode) {
883 inode = ERR_PTR(rc);
884 goto out;
885 }
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400886
Steve French0ccd4802010-07-16 04:31:02 +0000887#ifdef CONFIG_CIFS_FSCACHE
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530888 /* populate tcon->resource_id */
Jeff Layton0d424ad2010-09-20 16:01:35 -0700889 tcon->resource_id = CIFS_I(inode)->uniqueid;
Steve French0ccd4802010-07-16 04:31:02 +0000890#endif
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530891
Jeff Layton0d424ad2010-09-20 16:01:35 -0700892 if (rc && tcon->ipc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000893 cFYI(1, "ipc connection - fake read inode");
Steve French7f8ed422007-09-28 22:28:55 +0000894 inode->i_mode |= S_IFDIR;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200895 set_nlink(inode, 2);
Steve French7f8ed422007-09-28 22:28:55 +0000896 inode->i_op = &cifs_ipc_inode_ops;
897 inode->i_fop = &simple_dir_operations;
898 inode->i_uid = cifs_sb->mnt_uid;
899 inode->i_gid = cifs_sb->mnt_gid;
Steve Frenchad661332008-08-12 14:14:40 +0000900 } else if (rc) {
David Howellsce634ab2008-02-07 00:15:33 -0800901 iget_failed(inode);
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000902 inode = ERR_PTR(rc);
Steve French7f8ed422007-09-28 22:28:55 +0000903 }
904
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000905out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400906 /* can not call macro free_xid here since in a void func
David Howellsce634ab2008-02-07 00:15:33 -0800907 * TODO: This is no longer true
908 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400909 _free_xid(xid);
David Howellsce634ab2008-02-07 00:15:33 -0800910 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911}
912
Steve French388e57b2008-09-16 23:50:58 +0000913static int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400914cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
Steve French388e57b2008-09-16 23:50:58 +0000915 char *full_path, __u32 dosattr)
916{
917 int rc;
918 int oplock = 0;
919 __u16 netfid;
920 __u32 netpid;
921 bool set_time = false;
922 struct cifsFileInfo *open_file;
923 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
924 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400925 struct tcon_link *tlink = NULL;
Steve French96daf2b2011-05-27 04:34:02 +0000926 struct cifs_tcon *pTcon;
Steve French388e57b2008-09-16 23:50:58 +0000927 FILE_BASIC_INFO info_buf;
928
Steve French1adcb712009-02-25 14:19:56 +0000929 if (attrs == NULL)
930 return -EINVAL;
931
Steve French388e57b2008-09-16 23:50:58 +0000932 if (attrs->ia_valid & ATTR_ATIME) {
933 set_time = true;
934 info_buf.LastAccessTime =
935 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
936 } else
937 info_buf.LastAccessTime = 0;
938
939 if (attrs->ia_valid & ATTR_MTIME) {
940 set_time = true;
941 info_buf.LastWriteTime =
942 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
943 } else
944 info_buf.LastWriteTime = 0;
945
946 /*
947 * Samba throws this field away, but windows may actually use it.
948 * Do not set ctime unless other time stamps are changed explicitly
949 * (i.e. by utimes()) since we would then have a mix of client and
950 * server times.
951 */
952 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000953 cFYI(1, "CIFS - CTIME changed");
Steve French388e57b2008-09-16 23:50:58 +0000954 info_buf.ChangeTime =
955 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
956 } else
957 info_buf.ChangeTime = 0;
958
959 info_buf.CreationTime = 0; /* don't change */
960 info_buf.Attributes = cpu_to_le32(dosattr);
961
962 /*
963 * If the file is already open for write, just use that fileid
964 */
Jeff Layton6508d902010-09-29 19:51:11 -0400965 open_file = find_writable_file(cifsInode, true);
Steve French388e57b2008-09-16 23:50:58 +0000966 if (open_file) {
967 netfid = open_file->netfid;
968 netpid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -0400969 pTcon = tlink_tcon(open_file->tlink);
Steve French388e57b2008-09-16 23:50:58 +0000970 goto set_via_filehandle;
971 }
972
Jeff Layton7ffec372010-09-29 19:51:11 -0400973 tlink = cifs_sb_tlink(cifs_sb);
974 if (IS_ERR(tlink)) {
975 rc = PTR_ERR(tlink);
976 tlink = NULL;
977 goto out;
978 }
979 pTcon = tlink_tcon(tlink);
Jeff Laytonba00ba62010-09-20 16:01:31 -0700980
Steve French388e57b2008-09-16 23:50:58 +0000981 /*
982 * NT4 apparently returns success on this call, but it doesn't
983 * really work.
984 */
985 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
986 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
987 &info_buf, cifs_sb->local_nls,
988 cifs_sb->mnt_cifs_flags &
989 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +0000990 if (rc == 0) {
991 cifsInode->cifsAttrs = dosattr;
992 goto out;
993 } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
Steve French388e57b2008-09-16 23:50:58 +0000994 goto out;
995 }
996
Joe Perchesb6b38f72010-04-21 03:50:45 +0000997 cFYI(1, "calling SetFileInfo since SetPathInfo for "
998 "times not supported by this server");
Steve French388e57b2008-09-16 23:50:58 +0000999 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1000 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1001 CREATE_NOT_DIR, &netfid, &oplock,
1002 NULL, cifs_sb->local_nls,
1003 cifs_sb->mnt_cifs_flags &
1004 CIFS_MOUNT_MAP_SPECIAL_CHR);
1005
1006 if (rc != 0) {
1007 if (rc == -EIO)
1008 rc = -EINVAL;
1009 goto out;
1010 }
1011
1012 netpid = current->tgid;
1013
1014set_via_filehandle:
1015 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
Steve Frenchd3889082008-09-24 19:22:52 +00001016 if (!rc)
1017 cifsInode->cifsAttrs = dosattr;
1018
Steve French388e57b2008-09-16 23:50:58 +00001019 if (open_file == NULL)
1020 CIFSSMBClose(xid, pTcon, netfid);
1021 else
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001022 cifsFileInfo_put(open_file);
Steve French388e57b2008-09-16 23:50:58 +00001023out:
Jeff Layton7ffec372010-09-29 19:51:11 -04001024 if (tlink != NULL)
1025 cifs_put_tlink(tlink);
Steve French388e57b2008-09-16 23:50:58 +00001026 return rc;
1027}
1028
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001029/*
1030 * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
1031 * and rename it to a random name that hopefully won't conflict with
1032 * anything else.
1033 */
1034static int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001035cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
1036 unsigned int xid)
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001037{
1038 int oplock = 0;
1039 int rc;
1040 __u16 netfid;
Steve French32709582008-10-20 00:44:19 +00001041 struct inode *inode = dentry->d_inode;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001042 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1043 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001044 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001045 struct cifs_tcon *tcon;
Steve French32709582008-10-20 00:44:19 +00001046 __u32 dosattr, origattr;
1047 FILE_BASIC_INFO *info_buf = NULL;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001048
Jeff Layton7ffec372010-09-29 19:51:11 -04001049 tlink = cifs_sb_tlink(cifs_sb);
1050 if (IS_ERR(tlink))
1051 return PTR_ERR(tlink);
1052 tcon = tlink_tcon(tlink);
1053
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001054 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
Jeff Laytondd1db2d2008-10-16 19:27:12 -04001055 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001056 &netfid, &oplock, NULL, cifs_sb->local_nls,
1057 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1058 if (rc != 0)
1059 goto out;
1060
Steve French32709582008-10-20 00:44:19 +00001061 origattr = cifsInode->cifsAttrs;
1062 if (origattr == 0)
1063 origattr |= ATTR_NORMAL;
1064
1065 dosattr = origattr & ~ATTR_READONLY;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001066 if (dosattr == 0)
1067 dosattr |= ATTR_NORMAL;
1068 dosattr |= ATTR_HIDDEN;
1069
Steve French32709582008-10-20 00:44:19 +00001070 /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
1071 if (dosattr != origattr) {
1072 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
1073 if (info_buf == NULL) {
1074 rc = -ENOMEM;
1075 goto out_close;
1076 }
1077 info_buf->Attributes = cpu_to_le32(dosattr);
1078 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1079 current->tgid);
1080 /* although we would like to mark the file hidden
1081 if that fails we will still try to rename it */
Steve French41346092008-10-20 18:24:42 +00001082 if (rc != 0)
Steve French32709582008-10-20 00:44:19 +00001083 cifsInode->cifsAttrs = dosattr;
1084 else
1085 dosattr = origattr; /* since not able to change them */
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001086 }
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001087
Jeff Laytondd1db2d2008-10-16 19:27:12 -04001088 /* rename the file */
1089 rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001090 cifs_sb->mnt_cifs_flags &
1091 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French32709582008-10-20 00:44:19 +00001092 if (rc != 0) {
1093 rc = -ETXTBSY;
1094 goto undo_setattr;
1095 }
Jeff Layton6d22f092008-09-23 11:48:35 -04001096
Steve French32709582008-10-20 00:44:19 +00001097 /* try to set DELETE_ON_CLOSE */
1098 if (!cifsInode->delete_pending) {
1099 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
1100 current->tgid);
1101 /*
1102 * some samba versions return -ENOENT when we try to set the
1103 * file disposition here. Likely a samba bug, but work around
1104 * it for now. This means that some cifsXXX files may hang
1105 * around after they shouldn't.
1106 *
1107 * BB: remove this hack after more servers have the fix
1108 */
1109 if (rc == -ENOENT)
1110 rc = 0;
1111 else if (rc != 0) {
1112 rc = -ETXTBSY;
1113 goto undo_rename;
1114 }
1115 cifsInode->delete_pending = true;
1116 }
Jeff Layton7ce86d52008-09-24 11:32:59 -04001117
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001118out_close:
1119 CIFSSMBClose(xid, tcon, netfid);
1120out:
Steve French32709582008-10-20 00:44:19 +00001121 kfree(info_buf);
Jeff Layton7ffec372010-09-29 19:51:11 -04001122 cifs_put_tlink(tlink);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001123 return rc;
Steve French32709582008-10-20 00:44:19 +00001124
1125 /*
1126 * reset everything back to the original state. Don't bother
1127 * dealing with errors here since we can't do anything about
1128 * them anyway.
1129 */
1130undo_rename:
1131 CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
1132 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1133 CIFS_MOUNT_MAP_SPECIAL_CHR);
1134undo_setattr:
1135 if (dosattr != origattr) {
1136 info_buf->Attributes = cpu_to_le32(origattr);
1137 if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1138 current->tgid))
1139 cifsInode->cifsAttrs = origattr;
1140 }
1141
1142 goto out_close;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001143}
1144
Steve Frenchff694522009-04-20 19:45:13 +00001145
1146/*
1147 * If dentry->d_inode is null (usually meaning the cached dentry
1148 * is a negative dentry) then we would attempt a standard SMB delete, but
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001149 * if that fails we can not attempt the fall back mechanisms on EACCESS
1150 * but will return the EACCESS to the caller. Note that the VFS does not call
Steve Frenchff694522009-04-20 19:45:13 +00001151 * unlink on negative dentries currently.
1152 */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001153int cifs_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
1155 int rc = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001156 unsigned int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 char *full_path = NULL;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001158 struct inode *inode = dentry->d_inode;
Steve Frenchff694522009-04-20 19:45:13 +00001159 struct cifsInodeInfo *cifs_inode;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001160 struct super_block *sb = dir->i_sb;
1161 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001162 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001163 struct cifs_tcon *tcon;
Steve French60502472008-10-07 18:42:52 +00001164 struct iattr *attrs = NULL;
1165 __u32 dosattr = 0, origattr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Joe Perchesb6b38f72010-04-21 03:50:45 +00001167 cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
Jeff Layton7ffec372010-09-29 19:51:11 -04001169 tlink = cifs_sb_tlink(cifs_sb);
1170 if (IS_ERR(tlink))
1171 return PTR_ERR(tlink);
1172 tcon = tlink_tcon(tlink);
1173
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001174 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
Jeff Layton5f0319a2008-09-16 14:05:16 -04001176 /* Unlink can be called from rename so we can not take the
1177 * sb->s_vfs_rename_mutex here */
1178 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301180 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001181 goto unlink_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 }
Steve French2d785a52007-07-15 01:48:57 +00001183
Jeff Layton5f0319a2008-09-16 14:05:16 -04001184 if ((tcon->ses->capabilities & CAP_UNIX) &&
Steve French2d785a52007-07-15 01:48:57 +00001185 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Jeff Layton5f0319a2008-09-16 14:05:16 -04001186 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1187 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
Steve French2d785a52007-07-15 01:48:57 +00001188 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
1189 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001190 cFYI(1, "posix del rc %d", rc);
Steve French2d785a52007-07-15 01:48:57 +00001191 if ((rc == 0) || (rc == -ENOENT))
1192 goto psx_del_no_retry;
1193 }
1194
Steve French60502472008-10-07 18:42:52 +00001195retry_std_delete:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001196 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001197 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French60502472008-10-07 18:42:52 +00001198
Steve French2d785a52007-07-15 01:48:57 +00001199psx_del_no_retry:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 if (!rc) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001201 if (inode)
1202 drop_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 } else if (rc == -ENOENT) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001204 d_drop(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 } else if (rc == -ETXTBSY) {
Steve French32709582008-10-20 00:44:19 +00001206 rc = cifs_rename_pending_delete(full_path, dentry, xid);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001207 if (rc == 0)
1208 drop_nlink(inode);
Steve Frenchff694522009-04-20 19:45:13 +00001209 } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
Steve French388e57b2008-09-16 23:50:58 +00001210 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
1211 if (attrs == NULL) {
1212 rc = -ENOMEM;
1213 goto out_reval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 }
Steve French388e57b2008-09-16 23:50:58 +00001215
1216 /* try to reset dos attributes */
Steve Frenchff694522009-04-20 19:45:13 +00001217 cifs_inode = CIFS_I(inode);
1218 origattr = cifs_inode->cifsAttrs;
Steve French60502472008-10-07 18:42:52 +00001219 if (origattr == 0)
1220 origattr |= ATTR_NORMAL;
1221 dosattr = origattr & ~ATTR_READONLY;
Steve French388e57b2008-09-16 23:50:58 +00001222 if (dosattr == 0)
1223 dosattr |= ATTR_NORMAL;
1224 dosattr |= ATTR_HIDDEN;
1225
1226 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
Steve French388e57b2008-09-16 23:50:58 +00001227 if (rc != 0)
1228 goto out_reval;
Steve French60502472008-10-07 18:42:52 +00001229
1230 goto retry_std_delete;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 }
Steve French60502472008-10-07 18:42:52 +00001232
1233 /* undo the setattr if we errored out and it's needed */
1234 if (rc != 0 && dosattr != 0)
1235 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
1236
Steve French388e57b2008-09-16 23:50:58 +00001237out_reval:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001238 if (inode) {
Steve Frenchff694522009-04-20 19:45:13 +00001239 cifs_inode = CIFS_I(inode);
1240 cifs_inode->time = 0; /* will force revalidate to get info
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001241 when needed */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001242 inode->i_ctime = current_fs_time(sb);
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001243 }
Jeff Layton5f0319a2008-09-16 14:05:16 -04001244 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
Steve Frenchff694522009-04-20 19:45:13 +00001245 cifs_inode = CIFS_I(dir);
Steve French60502472008-10-07 18:42:52 +00001246 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
Jeff Layton7ffec372010-09-29 19:51:11 -04001247unlink_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 kfree(full_path);
Steve French60502472008-10-07 18:42:52 +00001249 kfree(attrs);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001250 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001251 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 return rc;
1253}
1254
Al Viro18bb1db2011-07-26 01:41:39 -04001255int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256{
Jeff Layton6b37faa2008-10-06 21:54:41 +00001257 int rc = 0, tmprc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001258 unsigned int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001260 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001261 struct cifs_tcon *pTcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 char *full_path = NULL;
1263 struct inode *newinode = NULL;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001264 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Al Viro18bb1db2011-07-26 01:41:39 -04001266 cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001269 tlink = cifs_sb_tlink(cifs_sb);
1270 if (IS_ERR(tlink))
1271 return PTR_ERR(tlink);
1272 pTcon = tlink_tcon(tlink);
1273
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001274 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
Steve French7f573562005-08-30 11:32:14 -07001276 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301278 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001279 goto mkdir_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 }
Steve French50c2f752007-07-13 00:33:32 +00001281
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001282 if ((pTcon->ses->capabilities & CAP_UNIX) &&
1283 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Steve French2dd29d32007-04-23 22:07:35 +00001284 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
1285 u32 oplock = 0;
Steve Frenchf6d09982008-01-08 23:18:22 +00001286 FILE_UNIX_BASIC_INFO *pInfo =
Steve French2dd29d32007-04-23 22:07:35 +00001287 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001288 if (pInfo == NULL) {
Steve French2dd29d32007-04-23 22:07:35 +00001289 rc = -ENOMEM;
1290 goto mkdir_out;
1291 }
Steve French50c2f752007-07-13 00:33:32 +00001292
Al Viroce3b0f82009-03-29 19:08:22 -04001293 mode &= ~current_umask();
Steve French2dd29d32007-04-23 22:07:35 +00001294 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
1295 mode, NULL /* netfid */, pInfo, &oplock,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001296 full_path, cifs_sb->local_nls,
1297 cifs_sb->mnt_cifs_flags &
Steve French2dd29d32007-04-23 22:07:35 +00001298 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc45d7072007-09-17 02:04:21 +00001299 if (rc == -EOPNOTSUPP) {
1300 kfree(pInfo);
1301 goto mkdir_retry_old;
1302 } else if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001303 cFYI(1, "posix mkdir returned 0x%x", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001304 d_drop(direntry);
1305 } else {
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001306 if (pInfo->Type == cpu_to_le32(-1)) {
1307 /* no return info, go query for it */
Steve French5a07cdf2007-09-16 23:12:47 +00001308 kfree(pInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001309 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001310 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001311/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
1312 to set uid/gid */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001313
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001314 cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
Jeff Layton4065c802010-05-17 07:18:58 -04001315 cifs_fill_uniqueid(inode->i_sb, &fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001316 newinode = cifs_iget(inode->i_sb, &fattr);
1317 if (!newinode) {
Steve French5a07cdf2007-09-16 23:12:47 +00001318 kfree(pInfo);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001319 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001320 }
Jeff Layton6b37faa2008-10-06 21:54:41 +00001321
Steve French2dd29d32007-04-23 22:07:35 +00001322 d_instantiate(direntry, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001323
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001324#ifdef CONFIG_CIFS_DEBUG2
Joe Perchesb6b38f72010-04-21 03:50:45 +00001325 cFYI(1, "instantiated dentry %p %s to inode %p",
1326 direntry, direntry->d_name.name, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001327
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001328 if (newinode->i_nlink != 2)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001329 cFYI(1, "unexpected number of links %d",
1330 newinode->i_nlink);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001331#endif
Steve French2dd29d32007-04-23 22:07:35 +00001332 }
1333 kfree(pInfo);
1334 goto mkdir_out;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001335 }
Steve Frenchc45d7072007-09-17 02:04:21 +00001336mkdir_retry_old:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -07001338 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
1339 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001341 cFYI(1, "cifs_mkdir returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 d_drop(direntry);
1343 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001344mkdir_get_info:
Steve Frenchc18c8422007-07-18 23:21:09 +00001345 if (pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001347 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 else
1349 rc = cifs_get_inode_info(&newinode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +00001350 inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 d_instantiate(direntry, newinode);
Steve French2dd29d32007-04-23 22:07:35 +00001353 /* setting nlink not necessary except in cases where we
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001354 * failed to get it from the server or was set bogus */
Steve French2dd29d32007-04-23 22:07:35 +00001355 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
Miklos Szeredibfe86842011-10-28 14:13:29 +02001356 set_nlink(direntry->d_inode, 2);
Jeff Layton95089912008-08-06 04:39:02 +00001357
Al Viroce3b0f82009-03-29 19:08:22 -04001358 mode &= ~current_umask();
Jeff Layton95089912008-08-06 04:39:02 +00001359 /* must turn on setgid bit if parent dir has it */
1360 if (inode->i_mode & S_ISGID)
1361 mode |= S_ISGID;
1362
Steve Frenchc18c8422007-07-18 23:21:09 +00001363 if (pTcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001364 struct cifs_unix_set_info_args args = {
1365 .mode = mode,
1366 .ctime = NO_CHANGE_64,
1367 .atime = NO_CHANGE_64,
1368 .mtime = NO_CHANGE_64,
1369 .device = 0,
1370 };
Steve Frenchd0d2f2d2005-06-02 15:12:36 -07001371 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
David Howellsa001e5b2008-11-14 10:38:47 +11001372 args.uid = (__u64)current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001373 if (inode->i_mode & S_ISGID)
1374 args.gid = (__u64)inode->i_gid;
1375 else
David Howellsa001e5b2008-11-14 10:38:47 +11001376 args.gid = (__u64)current_fsgid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 } else {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001378 args.uid = NO_CHANGE_64;
1379 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
Jeff Layton01ea95e2009-07-09 20:02:49 -04001381 CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
1382 cifs_sb->local_nls,
1383 cifs_sb->mnt_cifs_flags &
1384 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French3ce53fc2007-06-08 14:55:14 +00001385 } else {
Jeff Layton67750fb2008-05-09 22:28:02 +00001386 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1387 (mode & S_IWUGO) == 0) {
1388 FILE_BASIC_INFO pInfo;
Jeff Layton6b37faa2008-10-06 21:54:41 +00001389 struct cifsInodeInfo *cifsInode;
1390 u32 dosattrs;
1391
Jeff Layton67750fb2008-05-09 22:28:02 +00001392 memset(&pInfo, 0, sizeof(pInfo));
Jeff Layton6b37faa2008-10-06 21:54:41 +00001393 cifsInode = CIFS_I(newinode);
1394 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1395 pInfo.Attributes = cpu_to_le32(dosattrs);
1396 tmprc = CIFSSMBSetPathInfo(xid, pTcon,
1397 full_path, &pInfo,
1398 cifs_sb->local_nls,
Jeff Layton67750fb2008-05-09 22:28:02 +00001399 cifs_sb->mnt_cifs_flags &
1400 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +00001401 if (tmprc == 0)
1402 cifsInode->cifsAttrs = dosattrs;
Jeff Layton67750fb2008-05-09 22:28:02 +00001403 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001404 if (direntry->d_inode) {
Jeff Laytonb0fd30d2008-05-22 09:33:34 -04001405 if (cifs_sb->mnt_cifs_flags &
1406 CIFS_MOUNT_DYNPERM)
1407 direntry->d_inode->i_mode =
1408 (mode | S_IFDIR);
Steve French4e94a102008-05-23 18:22:46 +00001409
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001410 if (cifs_sb->mnt_cifs_flags &
Steve French6473a552005-11-29 20:20:10 -08001411 CIFS_MOUNT_SET_UID) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001412 direntry->d_inode->i_uid =
David Howellsa001e5b2008-11-14 10:38:47 +11001413 current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001414 if (inode->i_mode & S_ISGID)
1415 direntry->d_inode->i_gid =
1416 inode->i_gid;
1417 else
1418 direntry->d_inode->i_gid =
David Howellsa001e5b2008-11-14 10:38:47 +11001419 current_fsgid();
Steve French6473a552005-11-29 20:20:10 -08001420 }
1421 }
Steve French2a138ebb2005-11-29 21:22:19 -08001422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001424mkdir_out:
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001425 /*
1426 * Force revalidate to get parent dir info when needed since cached
1427 * attributes are invalid now.
1428 */
1429 CIFS_I(inode)->time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001431 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001432 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 return rc;
1434}
1435
1436int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1437{
1438 int rc = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001439 unsigned int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001441 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001442 struct cifs_tcon *pTcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 char *full_path = NULL;
1444 struct cifsInodeInfo *cifsInode;
1445
Joe Perchesb6b38f72010-04-21 03:50:45 +00001446 cFYI(1, "cifs_rmdir, inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001448 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
Steve French7f573562005-08-30 11:32:14 -07001450 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301452 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001453 goto rmdir_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 }
1455
Jeff Layton7ffec372010-09-29 19:51:11 -04001456 cifs_sb = CIFS_SB(inode->i_sb);
1457 tlink = cifs_sb_tlink(cifs_sb);
1458 if (IS_ERR(tlink)) {
1459 rc = PTR_ERR(tlink);
1460 goto rmdir_exit;
1461 }
1462 pTcon = tlink_tcon(tlink);
1463
Steve French737b7582005-04-28 22:41:06 -07001464 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1465 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -04001466 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
1468 if (!rc) {
Steve French3677db12007-02-26 16:46:11 +00001469 spin_lock(&direntry->d_inode->i_lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001470 i_size_write(direntry->d_inode, 0);
Dave Hansence71ec32006-09-30 23:29:06 -07001471 clear_nlink(direntry->d_inode);
Steve French3677db12007-02-26 16:46:11 +00001472 spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
1474
1475 cifsInode = CIFS_I(direntry->d_inode);
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001476 /* force revalidate to go get info when needed */
1477 cifsInode->time = 0;
Steve French42c24542009-01-13 22:03:55 +00001478
1479 cifsInode = CIFS_I(inode);
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001480 /*
1481 * Force revalidate to get parent dir info when needed since cached
1482 * attributes are invalid now.
1483 */
1484 cifsInode->time = 0;
Steve French42c24542009-01-13 22:03:55 +00001485
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1487 current_fs_time(inode->i_sb);
1488
Jeff Layton7ffec372010-09-29 19:51:11 -04001489rmdir_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001491 free_xid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 return rc;
1493}
1494
Steve Frenchee2fd962008-09-23 18:23:33 +00001495static int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001496cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
1497 const char *fromPath, struct dentry *to_dentry,
1498 const char *toPath)
Steve Frenchee2fd962008-09-23 18:23:33 +00001499{
1500 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001501 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001502 struct cifs_tcon *pTcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001503 __u16 srcfid;
1504 int oplock, rc;
1505
Jeff Layton7ffec372010-09-29 19:51:11 -04001506 tlink = cifs_sb_tlink(cifs_sb);
1507 if (IS_ERR(tlink))
1508 return PTR_ERR(tlink);
1509 pTcon = tlink_tcon(tlink);
1510
Steve Frenchee2fd962008-09-23 18:23:33 +00001511 /* try path-based rename first */
1512 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
1513 cifs_sb->mnt_cifs_flags &
1514 CIFS_MOUNT_MAP_SPECIAL_CHR);
1515
1516 /*
1517 * don't bother with rename by filehandle unless file is busy and
1518 * source Note that cross directory moves do not work with
1519 * rename by filehandle to various Windows servers.
1520 */
1521 if (rc == 0 || rc != -ETXTBSY)
Jeff Layton7ffec372010-09-29 19:51:11 -04001522 goto do_rename_exit;
Steve Frenchee2fd962008-09-23 18:23:33 +00001523
Jeff Laytoned0e3ac2010-06-01 16:21:01 -04001524 /* open-file renames don't work across directories */
1525 if (to_dentry->d_parent != from_dentry->d_parent)
Jeff Layton7ffec372010-09-29 19:51:11 -04001526 goto do_rename_exit;
Jeff Laytoned0e3ac2010-06-01 16:21:01 -04001527
Steve Frenchee2fd962008-09-23 18:23:33 +00001528 /* open the file to be renamed -- we need DELETE perms */
1529 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
1530 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1531 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1532 CIFS_MOUNT_MAP_SPECIAL_CHR);
1533
1534 if (rc == 0) {
1535 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
1536 (const char *) to_dentry->d_name.name,
1537 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1538 CIFS_MOUNT_MAP_SPECIAL_CHR);
1539
1540 CIFSSMBClose(xid, pTcon, srcfid);
1541 }
Jeff Layton7ffec372010-09-29 19:51:11 -04001542do_rename_exit:
1543 cifs_put_tlink(tlink);
Steve Frenchee2fd962008-09-23 18:23:33 +00001544 return rc;
1545}
1546
Jeff Layton14121bd2008-10-20 14:45:22 -04001547int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1548 struct inode *target_dir, struct dentry *target_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549{
Steve Frenchee2fd962008-09-23 18:23:33 +00001550 char *fromName = NULL;
1551 char *toName = NULL;
Jeff Layton639e7a92010-09-03 11:50:09 -04001552 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001553 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001554 struct cifs_tcon *tcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001555 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1556 FILE_UNIX_BASIC_INFO *info_buf_target;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001557 unsigned int xid;
1558 int rc, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Jeff Layton639e7a92010-09-03 11:50:09 -04001560 cifs_sb = CIFS_SB(source_dir->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001561 tlink = cifs_sb_tlink(cifs_sb);
1562 if (IS_ERR(tlink))
1563 return PTR_ERR(tlink);
1564 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001566 xid = get_xid();
Steve Frenchee2fd962008-09-23 18:23:33 +00001567
1568 /*
Steve Frenchee2fd962008-09-23 18:23:33 +00001569 * we already have the rename sem so we do not need to
1570 * grab it again here to protect the path integrity
1571 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001572 fromName = build_path_from_dentry(source_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001573 if (fromName == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 rc = -ENOMEM;
1575 goto cifs_rename_exit;
1576 }
1577
Jeff Layton14121bd2008-10-20 14:45:22 -04001578 toName = build_path_from_dentry(target_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001579 if (toName == NULL) {
1580 rc = -ENOMEM;
1581 goto cifs_rename_exit;
1582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Jeff Layton14121bd2008-10-20 14:45:22 -04001584 rc = cifs_do_rename(xid, source_dentry, fromName,
1585 target_dentry, toName);
Steve Frenchee2fd962008-09-23 18:23:33 +00001586
Jeff Layton14121bd2008-10-20 14:45:22 -04001587 if (rc == -EEXIST && tcon->unix_ext) {
Steve Frenchee2fd962008-09-23 18:23:33 +00001588 /*
Jeff Layton14121bd2008-10-20 14:45:22 -04001589 * Are src and dst hardlinks of same inode? We can
1590 * only tell with unix extensions enabled
Steve Frenchee2fd962008-09-23 18:23:33 +00001591 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001592 info_buf_source =
1593 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1594 GFP_KERNEL);
1595 if (info_buf_source == NULL) {
1596 rc = -ENOMEM;
1597 goto cifs_rename_exit;
1598 }
1599
1600 info_buf_target = info_buf_source + 1;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001601 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
Jeff Layton14121bd2008-10-20 14:45:22 -04001602 info_buf_source,
Jeff Layton639e7a92010-09-03 11:50:09 -04001603 cifs_sb->local_nls,
1604 cifs_sb->mnt_cifs_flags &
Jeff Layton14121bd2008-10-20 14:45:22 -04001605 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton8d281ef2008-10-22 13:57:01 -04001606 if (tmprc != 0)
Jeff Layton14121bd2008-10-20 14:45:22 -04001607 goto unlink_target;
1608
Jeff Layton639e7a92010-09-03 11:50:09 -04001609 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
1610 info_buf_target,
1611 cifs_sb->local_nls,
1612 cifs_sb->mnt_cifs_flags &
Jeff Layton14121bd2008-10-20 14:45:22 -04001613 CIFS_MOUNT_MAP_SPECIAL_CHR);
1614
Jeff Layton8d281ef2008-10-22 13:57:01 -04001615 if (tmprc == 0 && (info_buf_source->UniqueId ==
Jeff Laytonae6884a2008-11-03 14:05:08 -05001616 info_buf_target->UniqueId)) {
Jeff Layton14121bd2008-10-20 14:45:22 -04001617 /* same file, POSIX says that this is a noop */
Jeff Laytonae6884a2008-11-03 14:05:08 -05001618 rc = 0;
Jeff Layton14121bd2008-10-20 14:45:22 -04001619 goto cifs_rename_exit;
Jeff Laytonae6884a2008-11-03 14:05:08 -05001620 }
Jeff Layton14121bd2008-10-20 14:45:22 -04001621 } /* else ... BB we could add the same check for Windows by
1622 checking the UniqueId via FILE_INTERNAL_INFO */
1623
Jeff Layton14121bd2008-10-20 14:45:22 -04001624unlink_target:
Jeff Laytonfc6f3942009-04-17 11:45:30 -04001625 /* Try unlinking the target dentry if it's not negative */
1626 if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
Jeff Layton8d281ef2008-10-22 13:57:01 -04001627 tmprc = cifs_unlink(target_dir, target_dentry);
Jeff Layton14121bd2008-10-20 14:45:22 -04001628 if (tmprc)
1629 goto cifs_rename_exit;
1630
Jeff Layton14121bd2008-10-20 14:45:22 -04001631 rc = cifs_do_rename(xid, source_dentry, fromName,
1632 target_dentry, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 }
1634
1635cifs_rename_exit:
Steve Frenchee2fd962008-09-23 18:23:33 +00001636 kfree(info_buf_source);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 kfree(fromName);
1638 kfree(toName);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001639 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001640 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 return rc;
1642}
1643
Jeff Laytondf2cf172010-02-12 07:44:16 -05001644static bool
1645cifs_inode_needs_reval(struct inode *inode)
1646{
1647 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301648 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytondf2cf172010-02-12 07:44:16 -05001649
1650 if (cifs_i->clientCanCacheRead)
1651 return false;
1652
1653 if (!lookupCacheEnabled)
1654 return true;
1655
1656 if (cifs_i->time == 0)
1657 return true;
1658
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301659 if (!time_in_range(jiffies, cifs_i->time,
1660 cifs_i->time + cifs_sb->actimeo))
Jeff Laytondf2cf172010-02-12 07:44:16 -05001661 return true;
1662
Jeff Laytondb192722010-05-17 14:51:49 -04001663 /* hardlinked files w/ noserverino get "special" treatment */
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301664 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
Jeff Laytondb192722010-05-17 14:51:49 -04001665 S_ISREG(inode->i_mode) && inode->i_nlink != 1)
1666 return true;
1667
Jeff Laytondf2cf172010-02-12 07:44:16 -05001668 return false;
1669}
1670
Suresh Jayaraman523fb8c2010-11-29 22:39:47 +05301671/*
1672 * Zap the cache. Called when invalid_mapping flag is set.
1673 */
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001674int
Jeff Laytondf2cf172010-02-12 07:44:16 -05001675cifs_invalidate_mapping(struct inode *inode)
1676{
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001677 int rc = 0;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001678 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1679
1680 cifs_i->invalid_mapping = false;
1681
Jeff Laytondf2cf172010-02-12 07:44:16 -05001682 if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
Pavel Shilovsky257fb1f2011-03-16 01:55:32 +03001683 rc = invalidate_inode_pages2(inode->i_mapping);
1684 if (rc) {
1685 cERROR(1, "%s: could not invalidate inode %p", __func__,
1686 inode);
1687 cifs_i->invalid_mapping = true;
1688 }
Jeff Laytondf2cf172010-02-12 07:44:16 -05001689 }
Pavel Shilovsky257fb1f2011-03-16 01:55:32 +03001690
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +05301691 cifs_fscache_reset_inode_cookie(inode);
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001692 return rc;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001693}
1694
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001695int cifs_revalidate_file_attr(struct file *filp)
Jeff Laytonabab0952010-02-12 07:44:18 -05001696{
1697 int rc = 0;
1698 struct inode *inode = filp->f_path.dentry->d_inode;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001699 struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
Jeff Laytonabab0952010-02-12 07:44:18 -05001700
1701 if (!cifs_inode_needs_reval(inode))
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001702 return rc;
Jeff Laytonabab0952010-02-12 07:44:18 -05001703
Jeff Layton13cfb732010-09-29 19:51:11 -04001704 if (tlink_tcon(cfile->tlink)->unix_ext)
Jeff Laytonabab0952010-02-12 07:44:18 -05001705 rc = cifs_get_file_info_unix(filp);
1706 else
1707 rc = cifs_get_file_info(filp);
1708
Jeff Laytonabab0952010-02-12 07:44:18 -05001709 return rc;
1710}
1711
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001712int cifs_revalidate_dentry_attr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713{
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001714 unsigned int xid;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001715 int rc = 0;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001716 struct inode *inode = dentry->d_inode;
1717 struct super_block *sb = dentry->d_sb;
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001718 char *full_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
Jeff Laytondf2cf172010-02-12 07:44:16 -05001720 if (inode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 return -ENOENT;
1722
Jeff Laytondf2cf172010-02-12 07:44:16 -05001723 if (!cifs_inode_needs_reval(inode))
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001724 return rc;
1725
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001726 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 /* can not safely grab the rename sem here if rename calls revalidate
1729 since that would deadlock */
Jeff Laytondf2cf172010-02-12 07:44:16 -05001730 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301732 rc = -ENOMEM;
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001733 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 }
Jeff Laytondf2cf172010-02-12 07:44:16 -05001735
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001736 cFYI(1, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time "
1737 "%ld jiffies %ld", full_path, inode, inode->i_count.counter,
Steve Frenchf19159d2010-04-21 04:12:10 +00001738 dentry, dentry->d_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
Jeff Layton0d424ad2010-09-20 16:01:35 -07001740 if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
Jeff Laytondf2cf172010-02-12 07:44:16 -05001741 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
1742 else
1743 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
1744 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001746out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001748 free_xid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 return rc;
1750}
1751
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001752int cifs_revalidate_file(struct file *filp)
1753{
1754 int rc;
1755 struct inode *inode = filp->f_path.dentry->d_inode;
1756
1757 rc = cifs_revalidate_file_attr(filp);
1758 if (rc)
1759 return rc;
1760
1761 if (CIFS_I(inode)->invalid_mapping)
1762 rc = cifs_invalidate_mapping(inode);
1763 return rc;
1764}
1765
1766/* revalidate a dentry's inode attributes */
1767int cifs_revalidate_dentry(struct dentry *dentry)
1768{
1769 int rc;
1770 struct inode *inode = dentry->d_inode;
1771
1772 rc = cifs_revalidate_dentry_attr(dentry);
1773 if (rc)
1774 return rc;
1775
1776 if (CIFS_I(inode)->invalid_mapping)
1777 rc = cifs_invalidate_mapping(inode);
1778 return rc;
1779}
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
Jeff Layton1c456012010-10-12 11:32:42 -04001782 struct kstat *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783{
Jeff Layton3aa1c8c2010-10-07 14:46:28 -04001784 struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
Steve French96daf2b2011-05-27 04:34:02 +00001785 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001786 struct inode *inode = dentry->d_inode;
1787 int rc;
Jeff Layton3aa1c8c2010-10-07 14:46:28 -04001788
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001789 /*
1790 * We need to be sure that all dirty pages are written and the server
1791 * has actual ctime, mtime and file length.
1792 */
1793 if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
1794 inode->i_mapping->nrpages != 0) {
1795 rc = filemap_fdatawait(inode->i_mapping);
Steve French156ecb22011-05-20 17:00:01 +00001796 if (rc) {
1797 mapping_set_error(inode->i_mapping, rc);
1798 return rc;
1799 }
Steve French5fe14c82006-11-07 19:26:33 +00001800 }
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001801
1802 rc = cifs_revalidate_dentry_attr(dentry);
1803 if (rc)
1804 return rc;
1805
1806 generic_fillattr(inode, stat);
1807 stat->blksize = CIFS_MAX_MSGSIZE;
1808 stat->ino = CIFS_I(inode)->uniqueid;
1809
1810 /*
1811 * If on a multiuser mount without unix extensions, and the admin hasn't
1812 * overridden them, set the ownership to the fsuid/fsgid of the current
1813 * process.
1814 */
1815 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
1816 !tcon->unix_ext) {
1817 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
1818 stat->uid = current_fsuid();
1819 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
1820 stat->gid = current_fsgid();
1821 }
1822 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823}
1824
1825static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1826{
1827 pgoff_t index = from >> PAGE_CACHE_SHIFT;
1828 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1829 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 int rc = 0;
1831
1832 page = grab_cache_page(mapping, index);
1833 if (!page)
1834 return -ENOMEM;
1835
Christoph Lametereebd2aa2008-02-04 22:28:29 -08001836 zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 unlock_page(page);
1838 page_cache_release(page);
1839 return rc;
1840}
1841
Christoph Hellwig1b947462010-07-18 17:51:21 -04001842static void cifs_setsize(struct inode *inode, loff_t offset)
Steve French3677db12007-02-26 16:46:11 +00001843{
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001844 loff_t oldsize;
Steve French3677db12007-02-26 16:46:11 +00001845
Steve Frenchba6a46a2007-02-26 20:06:29 +00001846 spin_lock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001847 oldsize = inode->i_size;
Steve French3677db12007-02-26 16:46:11 +00001848 i_size_write(inode, offset);
Steve Frenchba6a46a2007-02-26 20:06:29 +00001849 spin_unlock(&inode->i_lock);
Christoph Hellwig1b947462010-07-18 17:51:21 -04001850
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001851 truncate_pagecache(inode, oldsize, offset);
Steve French3677db12007-02-26 16:46:11 +00001852}
1853
Jeff Layton8efdbde2008-07-23 21:28:12 +00001854static int
1855cifs_set_file_size(struct inode *inode, struct iattr *attrs,
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001856 unsigned int xid, char *full_path)
Jeff Layton8efdbde2008-07-23 21:28:12 +00001857{
1858 int rc;
1859 struct cifsFileInfo *open_file;
1860 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1861 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001862 struct tcon_link *tlink = NULL;
Steve French96daf2b2011-05-27 04:34:02 +00001863 struct cifs_tcon *pTcon = NULL;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001864 struct cifs_io_parms io_parms;
Jeff Layton8efdbde2008-07-23 21:28:12 +00001865
1866 /*
1867 * To avoid spurious oplock breaks from server, in the case of
1868 * inodes that we already have open, avoid doing path based
1869 * setting of file size if we can do it by handle.
1870 * This keeps our caching token (oplock) and avoids timeouts
1871 * when the local oplock break takes longer to flush
1872 * writebehind data than the SMB timeout for the SetPathInfo
1873 * request would allow
1874 */
Jeff Layton6508d902010-09-29 19:51:11 -04001875 open_file = find_writable_file(cifsInode, true);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001876 if (open_file) {
1877 __u16 nfid = open_file->netfid;
1878 __u32 npid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -04001879 pTcon = tlink_tcon(open_file->tlink);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001880 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
1881 npid, false);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001882 cifsFileInfo_put(open_file);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001883 cFYI(1, "SetFSize for attrs rc = %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001884 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1885 unsigned int bytes_written;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001886
1887 io_parms.netfid = nfid;
1888 io_parms.pid = npid;
1889 io_parms.tcon = pTcon;
1890 io_parms.offset = 0;
1891 io_parms.length = attrs->ia_size;
1892 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
1893 NULL, NULL, 1);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001894 cFYI(1, "Wrt seteof rc %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001895 }
1896 } else
1897 rc = -EINVAL;
1898
1899 if (rc != 0) {
Jeff Layton7ffec372010-09-29 19:51:11 -04001900 if (pTcon == NULL) {
1901 tlink = cifs_sb_tlink(cifs_sb);
1902 if (IS_ERR(tlink))
1903 return PTR_ERR(tlink);
1904 pTcon = tlink_tcon(tlink);
1905 }
Jeff Laytonba00ba62010-09-20 16:01:31 -07001906
Jeff Layton8efdbde2008-07-23 21:28:12 +00001907 /* Set file size by pathname rather than by handle
1908 either because no valid, writeable file handle for
1909 it was found or because there was an error setting
1910 it by handle */
1911 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
1912 false, cifs_sb->local_nls,
1913 cifs_sb->mnt_cifs_flags &
1914 CIFS_MOUNT_MAP_SPECIAL_CHR);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001915 cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001916 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1917 __u16 netfid;
1918 int oplock = 0;
1919
1920 rc = SMBLegacyOpen(xid, pTcon, full_path,
1921 FILE_OPEN, GENERIC_WRITE,
1922 CREATE_NOT_DIR, &netfid, &oplock, NULL,
1923 cifs_sb->local_nls,
1924 cifs_sb->mnt_cifs_flags &
1925 CIFS_MOUNT_MAP_SPECIAL_CHR);
1926 if (rc == 0) {
1927 unsigned int bytes_written;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001928
1929 io_parms.netfid = netfid;
1930 io_parms.pid = current->tgid;
1931 io_parms.tcon = pTcon;
1932 io_parms.offset = 0;
1933 io_parms.length = attrs->ia_size;
1934 rc = CIFSSMBWrite(xid, &io_parms,
1935 &bytes_written,
1936 NULL, NULL, 1);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001937 cFYI(1, "wrt seteof rc %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001938 CIFSSMBClose(xid, pTcon, netfid);
1939 }
1940 }
Jeff Layton7ffec372010-09-29 19:51:11 -04001941 if (tlink)
1942 cifs_put_tlink(tlink);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001943 }
1944
1945 if (rc == 0) {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001946 cifsInode->server_eof = attrs->ia_size;
Christoph Hellwig1b947462010-07-18 17:51:21 -04001947 cifs_setsize(inode, attrs->ia_size);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001948 cifs_truncate_page(inode->i_mapping, inode->i_size);
1949 }
1950
1951 return rc;
1952}
1953
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001954static int
1955cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1956{
1957 int rc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001958 unsigned int xid;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001959 char *full_path = NULL;
1960 struct inode *inode = direntry->d_inode;
1961 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1962 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001963 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001964 struct cifs_tcon *pTcon;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001965 struct cifs_unix_set_info_args *args = NULL;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001966 struct cifsFileInfo *open_file;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001967
Joe Perchesb6b38f72010-04-21 03:50:45 +00001968 cFYI(1, "setattr_unix on file %s attrs->ia_valid=0x%x",
1969 direntry->d_name.name, attrs->ia_valid);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001970
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001971 xid = get_xid();
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001972
Christoph Hellwigdb78b872010-06-04 11:30:03 +02001973 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
1974 attrs->ia_valid |= ATTR_FORCE;
1975
1976 rc = inode_change_ok(inode, attrs);
1977 if (rc < 0)
1978 goto out;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001979
1980 full_path = build_path_from_dentry(direntry);
1981 if (full_path == NULL) {
1982 rc = -ENOMEM;
1983 goto out;
1984 }
1985
Jeff Layton0f4d6342009-03-26 13:35:37 -04001986 /*
1987 * Attempt to flush data before changing attributes. We need to do
1988 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
1989 * ownership or mode then we may also need to do this. Here, we take
1990 * the safe way out and just do the flush on all setattr requests. If
1991 * the flush returns error, store it to report later and continue.
1992 *
1993 * BB: This should be smarter. Why bother flushing pages that
1994 * will be truncated anyway? Also, should we error out here if
1995 * the flush returns error?
1996 */
1997 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001998 mapping_set_error(inode->i_mapping, rc);
1999 rc = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002000
2001 if (attrs->ia_valid & ATTR_SIZE) {
2002 rc = cifs_set_file_size(inode, attrs, xid, full_path);
2003 if (rc != 0)
2004 goto out;
2005 }
2006
2007 /* skip mode change if it's just for clearing setuid/setgid */
2008 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
2009 attrs->ia_valid &= ~ATTR_MODE;
2010
2011 args = kmalloc(sizeof(*args), GFP_KERNEL);
2012 if (args == NULL) {
2013 rc = -ENOMEM;
2014 goto out;
2015 }
2016
2017 /* set up the struct */
2018 if (attrs->ia_valid & ATTR_MODE)
2019 args->mode = attrs->ia_mode;
2020 else
2021 args->mode = NO_CHANGE_64;
2022
2023 if (attrs->ia_valid & ATTR_UID)
2024 args->uid = attrs->ia_uid;
2025 else
2026 args->uid = NO_CHANGE_64;
2027
2028 if (attrs->ia_valid & ATTR_GID)
2029 args->gid = attrs->ia_gid;
2030 else
2031 args->gid = NO_CHANGE_64;
2032
2033 if (attrs->ia_valid & ATTR_ATIME)
2034 args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
2035 else
2036 args->atime = NO_CHANGE_64;
2037
2038 if (attrs->ia_valid & ATTR_MTIME)
2039 args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
2040 else
2041 args->mtime = NO_CHANGE_64;
2042
2043 if (attrs->ia_valid & ATTR_CTIME)
2044 args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
2045 else
2046 args->ctime = NO_CHANGE_64;
2047
2048 args->device = 0;
Jeff Layton6508d902010-09-29 19:51:11 -04002049 open_file = find_writable_file(cifsInode, true);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002050 if (open_file) {
2051 u16 nfid = open_file->netfid;
2052 u32 npid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -04002053 pTcon = tlink_tcon(open_file->tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002054 rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04002055 cifsFileInfo_put(open_file);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002056 } else {
Jeff Layton7ffec372010-09-29 19:51:11 -04002057 tlink = cifs_sb_tlink(cifs_sb);
2058 if (IS_ERR(tlink)) {
2059 rc = PTR_ERR(tlink);
2060 goto out;
2061 }
2062 pTcon = tlink_tcon(tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002063 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
Jeff Layton01ea95e2009-07-09 20:02:49 -04002064 cifs_sb->local_nls,
2065 cifs_sb->mnt_cifs_flags &
2066 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -04002067 cifs_put_tlink(tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002068 }
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002069
Christoph Hellwig10257742010-06-04 11:30:02 +02002070 if (rc)
2071 goto out;
Steve Frenchccd4bb12010-02-08 17:39:58 +00002072
Christoph Hellwig10257742010-06-04 11:30:02 +02002073 if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig1b947462010-07-18 17:51:21 -04002074 attrs->ia_size != i_size_read(inode))
2075 truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02002076
2077 setattr_copy(inode, attrs);
2078 mark_inode_dirty(inode);
2079
2080 /* force revalidate when any of these times are set since some
2081 of the fs types (eg ext3, fat) do not have fine enough
2082 time granularity to match protocol, and we do not have a
2083 a way (yet) to query the server fs's time granularity (and
2084 whether it rounds times down).
2085 */
2086 if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
2087 cifsInode->time = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002088out:
2089 kfree(args);
2090 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002091 free_xid(xid);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002092 return rc;
2093}
2094
Jeff Layton0510eeb2008-08-02 07:26:12 -04002095static int
2096cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097{
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002098 unsigned int xid;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002099 uid_t uid = NO_CHANGE_32;
2100 gid_t gid = NO_CHANGE_32;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002101 struct inode *inode = direntry->d_inode;
2102 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002103 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 char *full_path = NULL;
2105 int rc = -EACCES;
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002106 __u32 dosattr = 0;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04002107 __u64 mode = NO_CHANGE_64;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002108
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002109 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Joe Perchesb6b38f72010-04-21 03:50:45 +00002111 cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
2112 direntry->d_name.name, attrs->ia_valid);
Steve French6473a552005-11-29 20:20:10 -08002113
Christoph Hellwigdb78b872010-06-04 11:30:03 +02002114 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
2115 attrs->ia_valid |= ATTR_FORCE;
2116
2117 rc = inode_change_ok(inode, attrs);
2118 if (rc < 0) {
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002119 free_xid(xid);
Christoph Hellwigdb78b872010-06-04 11:30:03 +02002120 return rc;
Steve French6473a552005-11-29 20:20:10 -08002121 }
Steve French50c2f752007-07-13 00:33:32 +00002122
Steve French7f573562005-08-30 11:32:14 -07002123 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302125 rc = -ENOMEM;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002126 free_xid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302127 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
Jeff Layton0f4d6342009-03-26 13:35:37 -04002130 /*
2131 * Attempt to flush data before changing attributes. We need to do
2132 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
2133 * ownership or mode then we may also need to do this. Here, we take
2134 * the safe way out and just do the flush on all setattr requests. If
2135 * the flush returns error, store it to report later and continue.
2136 *
2137 * BB: This should be smarter. Why bother flushing pages that
2138 * will be truncated anyway? Also, should we error out here if
2139 * the flush returns error?
2140 */
2141 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002142 mapping_set_error(inode->i_mapping, rc);
2143 rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00002144
Steve French50531442008-03-14 19:21:31 +00002145 if (attrs->ia_valid & ATTR_SIZE) {
Jeff Layton8efdbde2008-07-23 21:28:12 +00002146 rc = cifs_set_file_size(inode, attrs, xid, full_path);
2147 if (rc != 0)
Steve Frenche30dcf32005-09-20 20:49:16 -07002148 goto cifs_setattr_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 }
Jeff Layton4ca691a2008-05-22 09:33:34 -04002150
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002151 if (attrs->ia_valid & ATTR_UID)
2152 uid = attrs->ia_uid;
2153
2154 if (attrs->ia_valid & ATTR_GID)
2155 gid = attrs->ia_gid;
2156
2157#ifdef CONFIG_CIFS_ACL
2158 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2159 if (uid != NO_CHANGE_32 || gid != NO_CHANGE_32) {
2160 rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
2161 uid, gid);
2162 if (rc) {
2163 cFYI(1, "%s: Setting id failed with error: %d",
2164 __func__, rc);
2165 goto cifs_setattr_exit;
2166 }
2167 }
2168 } else
2169#endif /* CONFIG_CIFS_ACL */
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002170 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
Jeff Layton4ca691a2008-05-22 09:33:34 -04002171 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
Jeff Laytond32c4f22007-10-18 03:05:22 -07002173 /* skip mode change if it's just for clearing setuid/setgid */
2174 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
2175 attrs->ia_valid &= ~ATTR_MODE;
2176
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 if (attrs->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 mode = attrs->ia_mode;
Steve Frenchcdbce9c2005-11-19 21:04:52 -08002179 rc = 0;
Jeff Layton79df1ba2010-12-06 12:52:08 -05002180#ifdef CONFIG_CIFS_ACL
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06002181 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002182 rc = id_mode_to_cifs_acl(inode, full_path, mode,
2183 NO_CHANGE_32, NO_CHANGE_32);
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06002184 if (rc) {
2185 cFYI(1, "%s: Setting ACL failed with error: %d",
2186 __func__, rc);
2187 goto cifs_setattr_exit;
2188 }
2189 } else
Jeff Layton79df1ba2010-12-06 12:52:08 -05002190#endif /* CONFIG_CIFS_ACL */
Jeff Layton51328612008-05-22 09:33:34 -04002191 if (((mode & S_IWUGO) == 0) &&
2192 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002193
2194 dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
2195
Jeff Layton51328612008-05-22 09:33:34 -04002196 /* fix up mode if we're not using dynperm */
2197 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
2198 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
2199 } else if ((mode & S_IWUGO) &&
2200 (cifsInode->cifsAttrs & ATTR_READONLY)) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002201
2202 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
2203 /* Attributes of 0 are ignored */
2204 if (dosattr == 0)
2205 dosattr |= ATTR_NORMAL;
Jeff Layton51328612008-05-22 09:33:34 -04002206
2207 /* reset local inode permissions to normal */
2208 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
2209 attrs->ia_mode &= ~(S_IALLUGO);
2210 if (S_ISDIR(inode->i_mode))
2211 attrs->ia_mode |=
2212 cifs_sb->mnt_dir_mode;
2213 else
2214 attrs->ia_mode |=
2215 cifs_sb->mnt_file_mode;
2216 }
2217 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
2218 /* ignore mode change - ATTR_READONLY hasn't changed */
2219 attrs->ia_valid &= ~ATTR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
2222
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002223 if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
2224 ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
2225 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
2226 /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
Steve Frenche30dcf32005-09-20 20:49:16 -07002228 /* Even if error on time set, no sense failing the call if
2229 the server would set the time to a reasonable value anyway,
2230 and this check ensures that we are not being called from
2231 sys_utimes in which case we ought to fail the call back to
2232 the user when the server rejects the call */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002233 if ((rc) && (attrs->ia_valid &
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002234 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
Steve Frenche30dcf32005-09-20 20:49:16 -07002235 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 }
2237
2238 /* do not need local check to inode_check_ok since the server does
2239 that */
Christoph Hellwig10257742010-06-04 11:30:02 +02002240 if (rc)
2241 goto cifs_setattr_exit;
2242
2243 if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig1b947462010-07-18 17:51:21 -04002244 attrs->ia_size != i_size_read(inode))
2245 truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02002246
2247 setattr_copy(inode, attrs);
2248 mark_inode_dirty(inode);
Christoph Hellwig10257742010-06-04 11:30:02 +02002249
Steve Frenche30dcf32005-09-20 20:49:16 -07002250cifs_setattr_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002252 free_xid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 return rc;
2254}
2255
Jeff Layton0510eeb2008-08-02 07:26:12 -04002256int
2257cifs_setattr(struct dentry *direntry, struct iattr *attrs)
2258{
2259 struct inode *inode = direntry->d_inode;
2260 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Steve French96daf2b2011-05-27 04:34:02 +00002261 struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
Jeff Layton0510eeb2008-08-02 07:26:12 -04002262
2263 if (pTcon->unix_ext)
2264 return cifs_setattr_unix(direntry, attrs);
2265
2266 return cifs_setattr_nounix(direntry, attrs);
2267
2268 /* BB: add cifs_setattr_legacy for really old servers */
2269}
2270
Steve French99ee4db2007-02-27 05:35:17 +00002271#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272void cifs_delete_inode(struct inode *inode)
2273{
Joe Perchesb6b38f72010-04-21 03:50:45 +00002274 cFYI(1, "In cifs_delete_inode, inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 /* may have to add back in if and when safe distributed caching of
2276 directories added e.g. via FindNotify */
2277}
Steve French99ee4db2007-02-27 05:35:17 +00002278#endif