blob: 8d6ac6bec9e9b36f1c012b51bd481582362935c9 [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;
Jeff Laytonf6b6c152013-05-07 11:28:31 -0400176 if (inode->i_state & I_NEW)
177 cifs_set_ops(inode);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000178}
179
Jeff Layton4065c802010-05-17 07:18:58 -0400180void
181cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr)
182{
183 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
184
185 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
186 return;
187
188 fattr->cf_uniqueid = iunique(sb, ROOT_I);
189}
190
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400191/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
192void
193cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
194 struct cifs_sb_info *cifs_sb)
195{
196 memset(fattr, 0, sizeof(*fattr));
197 fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
198 fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
199 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
200
201 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
202 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
203 fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
204 fattr->cf_mode = le64_to_cpu(info->Permissions);
205
206 /*
207 * Since we set the inode type below we need to mask off
208 * to avoid strange results if bits set above.
209 */
210 fattr->cf_mode &= ~S_IFMT;
211 switch (le32_to_cpu(info->Type)) {
212 case UNIX_FILE:
213 fattr->cf_mode |= S_IFREG;
214 fattr->cf_dtype = DT_REG;
215 break;
216 case UNIX_SYMLINK:
217 fattr->cf_mode |= S_IFLNK;
218 fattr->cf_dtype = DT_LNK;
219 break;
220 case UNIX_DIR:
221 fattr->cf_mode |= S_IFDIR;
222 fattr->cf_dtype = DT_DIR;
223 break;
224 case UNIX_CHARDEV:
225 fattr->cf_mode |= S_IFCHR;
226 fattr->cf_dtype = DT_CHR;
227 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
228 le64_to_cpu(info->DevMinor) & MINORMASK);
229 break;
230 case UNIX_BLOCKDEV:
231 fattr->cf_mode |= S_IFBLK;
232 fattr->cf_dtype = DT_BLK;
233 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
234 le64_to_cpu(info->DevMinor) & MINORMASK);
235 break;
236 case UNIX_FIFO:
237 fattr->cf_mode |= S_IFIFO;
238 fattr->cf_dtype = DT_FIFO;
239 break;
240 case UNIX_SOCKET:
241 fattr->cf_mode |= S_IFSOCK;
242 fattr->cf_dtype = DT_SOCK;
243 break;
244 default:
245 /* safest to call it a file if we do not know */
246 fattr->cf_mode |= S_IFREG;
247 fattr->cf_dtype = DT_REG;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000248 cFYI(1, "unknown type %d", le32_to_cpu(info->Type));
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400249 break;
250 }
251
252 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
253 fattr->cf_uid = cifs_sb->mnt_uid;
254 else
255 fattr->cf_uid = le64_to_cpu(info->Uid);
256
257 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
258 fattr->cf_gid = cifs_sb->mnt_gid;
259 else
260 fattr->cf_gid = le64_to_cpu(info->Gid);
261
262 fattr->cf_nlink = le64_to_cpu(info->Nlinks);
263}
Steve Frenchb9a32602008-05-20 21:52:32 +0000264
265/*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400266 * Fill a cifs_fattr struct with fake inode info.
267 *
268 * Needed to setup cifs_fattr data for the directory which is the
269 * junction to the new submount (ie to setup the fake directory
270 * which represents a DFS referral).
Steve Frenchb9a32602008-05-20 21:52:32 +0000271 */
Steve Frenchf1230c92009-07-22 23:13:01 +0000272static void
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400273cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
Steve French0e4bbde2008-05-20 19:50:46 +0000274{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400275 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Steve French0e4bbde2008-05-20 19:50:46 +0000276
Joe Perchesb6b38f72010-04-21 03:50:45 +0000277 cFYI(1, "creating fake fattr for DFS referral");
Steve French0e4bbde2008-05-20 19:50:46 +0000278
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400279 memset(fattr, 0, sizeof(*fattr));
280 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
281 fattr->cf_uid = cifs_sb->mnt_uid;
282 fattr->cf_gid = cifs_sb->mnt_gid;
283 fattr->cf_atime = CURRENT_TIME;
284 fattr->cf_ctime = CURRENT_TIME;
285 fattr->cf_mtime = CURRENT_TIME;
286 fattr->cf_nlink = 2;
287 fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
Steve French0e4bbde2008-05-20 19:50:46 +0000288}
289
Jeff Laytonabab0952010-02-12 07:44:18 -0500290int cifs_get_file_info_unix(struct file *filp)
291{
292 int rc;
293 int xid;
294 FILE_UNIX_BASIC_INFO find_data;
295 struct cifs_fattr fattr;
296 struct inode *inode = filp->f_path.dentry->d_inode;
297 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Joe Perchesc21dfb62010-07-12 13:50:14 -0700298 struct cifsFileInfo *cfile = filp->private_data;
Steve French96daf2b2011-05-27 04:34:02 +0000299 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Jeff Laytonabab0952010-02-12 07:44:18 -0500300
301 xid = GetXid();
302 rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
303 if (!rc) {
304 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
305 } else if (rc == -EREMOTE) {
306 cifs_create_dfs_fattr(&fattr, inode->i_sb);
307 rc = 0;
308 }
309
310 cifs_fattr_to_inode(inode, &fattr);
311 FreeXid(xid);
312 return rc;
313}
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315int cifs_get_inode_info_unix(struct inode **pinode,
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400316 const unsigned char *full_path,
317 struct super_block *sb, int xid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400319 int rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000320 FILE_UNIX_BASIC_INFO find_data;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400321 struct cifs_fattr fattr;
Steve French96daf2b2011-05-27 04:34:02 +0000322 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400323 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Joe Perchesb6b38f72010-04-21 03:50:45 +0000326 cFYI(1, "Getting info on %s", full_path);
Igor Mammedov79626702008-03-09 03:44:18 +0000327
Jeff Layton7ffec372010-09-29 19:51:11 -0400328 tlink = cifs_sb_tlink(cifs_sb);
329 if (IS_ERR(tlink))
330 return PTR_ERR(tlink);
331 tcon = tlink_tcon(tlink);
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 /* could have done a find first instead but this returns more info */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400334 rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
Steve French737b7582005-04-28 22:41:06 -0700335 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
336 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -0400337 cifs_put_tlink(tlink);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400338
339 if (!rc) {
340 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
341 } else if (rc == -EREMOTE) {
342 cifs_create_dfs_fattr(&fattr, sb);
Jeff Laytone911d0c2008-07-12 13:47:59 -0700343 rc = 0;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400344 } else {
345 return rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000346 }
347
Stefan Metzmacher1b12b9c2010-08-05 21:19:56 +0200348 /* check for Minshall+French symlinks */
349 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
350 int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
351 if (tmprc)
352 cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
353 }
354
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400355 if (*pinode == NULL) {
356 /* get new inode */
Jeff Layton4065c802010-05-17 07:18:58 -0400357 cifs_fill_uniqueid(sb, &fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400358 *pinode = cifs_iget(sb, &fattr);
359 if (!*pinode)
360 rc = -ENOMEM;
361 } else {
362 /* we already have inode, update it */
363 cifs_fattr_to_inode(*pinode, &fattr);
364 }
Steve French0e4bbde2008-05-20 19:50:46 +0000365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 return rc;
367}
368
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400369static int
370cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
371 struct cifs_sb_info *cifs_sb, int xid)
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800372{
373 int rc;
Steve French4b18f2a2008-04-29 00:06:05 +0000374 int oplock = 0;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800375 __u16 netfid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400376 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +0000377 struct cifs_tcon *tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +0000378 struct cifs_io_parms io_parms;
Steve French86c96b42005-11-18 20:25:31 -0800379 char buf[24];
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800380 unsigned int bytes_read;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000381 char *pbuf;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800382
383 pbuf = buf;
384
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400385 fattr->cf_mode &= ~S_IFMT;
386
387 if (fattr->cf_eof == 0) {
388 fattr->cf_mode |= S_IFIFO;
389 fattr->cf_dtype = DT_FIFO;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800390 return 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400391 } else if (fattr->cf_eof < 8) {
392 fattr->cf_mode |= S_IFREG;
393 fattr->cf_dtype = DT_REG;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800394 return -EINVAL; /* EOPNOTSUPP? */
395 }
Steve French50c2f752007-07-13 00:33:32 +0000396
Jeff Layton7ffec372010-09-29 19:51:11 -0400397 tlink = cifs_sb_tlink(cifs_sb);
398 if (IS_ERR(tlink))
399 return PTR_ERR(tlink);
400 tcon = tlink_tcon(tlink);
401
402 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ,
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800403 CREATE_NOT_DIR, &netfid, &oplock, NULL,
404 cifs_sb->local_nls,
405 cifs_sb->mnt_cifs_flags &
406 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000407 if (rc == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -0800408 int buf_type = CIFS_NO_BUFFER;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800409 /* Read header */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +0000410 io_parms.netfid = netfid;
411 io_parms.pid = current->tgid;
412 io_parms.tcon = tcon;
413 io_parms.offset = 0;
414 io_parms.length = 24;
415 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf,
416 &buf_type);
Steve French4523cc32007-04-30 20:13:06 +0000417 if ((rc == 0) && (bytes_read >= 8)) {
418 if (memcmp("IntxBLK", pbuf, 8) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000419 cFYI(1, "Block device");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400420 fattr->cf_mode |= S_IFBLK;
421 fattr->cf_dtype = DT_BLK;
Steve French4523cc32007-04-30 20:13:06 +0000422 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800423 /* we have enough to decode dev num */
424 __u64 mjr; /* major */
425 __u64 mnr; /* minor */
426 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
427 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400428 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve French86c96b42005-11-18 20:25:31 -0800429 }
Steve French4523cc32007-04-30 20:13:06 +0000430 } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000431 cFYI(1, "Char device");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400432 fattr->cf_mode |= S_IFCHR;
433 fattr->cf_dtype = DT_CHR;
Steve French4523cc32007-04-30 20:13:06 +0000434 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800435 /* we have enough to decode dev num */
436 __u64 mjr; /* major */
437 __u64 mnr; /* minor */
438 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
439 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400440 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000441 }
Steve French4523cc32007-04-30 20:13:06 +0000442 } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000443 cFYI(1, "Symlink");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400444 fattr->cf_mode |= S_IFLNK;
445 fattr->cf_dtype = DT_LNK;
Steve French86c96b42005-11-18 20:25:31 -0800446 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400447 fattr->cf_mode |= S_IFREG; /* file? */
448 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000449 rc = -EOPNOTSUPP;
Steve French86c96b42005-11-18 20:25:31 -0800450 }
Steve French3020a1f2005-11-18 11:31:10 -0800451 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400452 fattr->cf_mode |= S_IFREG; /* then it is a file */
453 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000454 rc = -EOPNOTSUPP; /* or some unknown SFU type */
455 }
Jeff Layton7ffec372010-09-29 19:51:11 -0400456 CIFSSMBClose(xid, tcon, netfid);
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800457 }
Jeff Layton7ffec372010-09-29 19:51:11 -0400458 cifs_put_tlink(tlink);
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800459 return rc;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800460}
461
Steve French9e294f12005-11-17 16:59:21 -0800462#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
463
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400464/*
465 * Fetch mode bits as provided by SFU.
466 *
467 * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
468 */
469static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
470 struct cifs_sb_info *cifs_sb, int xid)
Steve French9e294f12005-11-17 16:59:21 -0800471{
Steve French3020a1f2005-11-18 11:31:10 -0800472#ifdef CONFIG_CIFS_XATTR
Steve French9e294f12005-11-17 16:59:21 -0800473 ssize_t rc;
474 char ea_value[4];
475 __u32 mode;
Jeff Layton7ffec372010-09-29 19:51:11 -0400476 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +0000477 struct cifs_tcon *tcon;
Steve French9e294f12005-11-17 16:59:21 -0800478
Jeff Layton7ffec372010-09-29 19:51:11 -0400479 tlink = cifs_sb_tlink(cifs_sb);
480 if (IS_ERR(tlink))
481 return PTR_ERR(tlink);
482 tcon = tlink_tcon(tlink);
483
484 rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS",
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400485 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
486 cifs_sb->mnt_cifs_flags &
487 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -0400488 cifs_put_tlink(tlink);
Steve French4523cc32007-04-30 20:13:06 +0000489 if (rc < 0)
Steve French9e294f12005-11-17 16:59:21 -0800490 return (int)rc;
491 else if (rc > 3) {
492 mode = le32_to_cpu(*((__le32 *)ea_value));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400493 fattr->cf_mode &= ~SFBITS_MASK;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000494 cFYI(1, "special bits 0%o org mode 0%o", mode,
495 fattr->cf_mode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400496 fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000497 cFYI(1, "special mode bits 0%o", mode);
Steve French9e294f12005-11-17 16:59:21 -0800498 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400499
500 return 0;
Steve French3020a1f2005-11-18 11:31:10 -0800501#else
502 return -EOPNOTSUPP;
503#endif
Steve French9e294f12005-11-17 16:59:21 -0800504}
505
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400506/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
Steve Frenchf1230c92009-07-22 23:13:01 +0000507static void
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400508cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
509 struct cifs_sb_info *cifs_sb, bool adjust_tz)
Steve Frenchb9a32602008-05-20 21:52:32 +0000510{
Steve French96daf2b2011-05-27 04:34:02 +0000511 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
Jeff Layton0d424ad2010-09-20 16:01:35 -0700512
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400513 memset(fattr, 0, sizeof(*fattr));
514 fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
515 if (info->DeletePending)
516 fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
Steve Frenchb9a32602008-05-20 21:52:32 +0000517
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400518 if (info->LastAccessTime)
519 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
520 else
521 fattr->cf_atime = CURRENT_TIME;
522
523 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
524 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
525
526 if (adjust_tz) {
Jeff Layton0d424ad2010-09-20 16:01:35 -0700527 fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
528 fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400529 }
530
531 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
532 fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
Jeff Layton20054bd2011-01-07 11:30:27 -0500533 fattr->cf_createtime = le64_to_cpu(info->CreationTime);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400534
535 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
536 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
537 fattr->cf_dtype = DT_DIR;
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +0300538 /*
539 * Server can return wrong NumberOfLinks value for directories
540 * when Unix extensions are disabled - fake it.
541 */
542 fattr->cf_nlink = 2;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400543 } else {
544 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
545 fattr->cf_dtype = DT_REG;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400546
Jeff Laytond0c280d2009-07-09 01:46:44 -0400547 /* clear write bits if ATTR_READONLY is set */
548 if (fattr->cf_cifsattrs & ATTR_READONLY)
549 fattr->cf_mode &= ~(S_IWUGO);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400550
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +0300551 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
Steve Frenche2c411c2013-07-04 14:38:48 -0500552 if (fattr->cf_nlink < 1) {
553 cFYI(1, "replacing bogus file nlink value %u\n",
554 fattr->cf_nlink);
555 fattr->cf_nlink = 1;
556 }
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +0300557 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400558
559 fattr->cf_uid = cifs_sb->mnt_uid;
560 fattr->cf_gid = cifs_sb->mnt_gid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000561}
562
Jeff Laytonabab0952010-02-12 07:44:18 -0500563int cifs_get_file_info(struct file *filp)
564{
565 int rc;
566 int xid;
567 FILE_ALL_INFO find_data;
568 struct cifs_fattr fattr;
569 struct inode *inode = filp->f_path.dentry->d_inode;
570 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Joe Perchesc21dfb62010-07-12 13:50:14 -0700571 struct cifsFileInfo *cfile = filp->private_data;
Steve French96daf2b2011-05-27 04:34:02 +0000572 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Jeff Laytonabab0952010-02-12 07:44:18 -0500573
574 xid = GetXid();
575 rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400576 switch (rc) {
577 case 0:
578 cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
579 break;
580 case -EREMOTE:
581 cifs_create_dfs_fattr(&fattr, inode->i_sb);
582 rc = 0;
583 break;
584 case -EOPNOTSUPP:
585 case -EINVAL:
Jeff Laytonabab0952010-02-12 07:44:18 -0500586 /*
587 * FIXME: legacy server -- fall back to path-based call?
Steve Frenchff2157132010-03-09 20:30:42 +0000588 * for now, just skip revalidating and mark inode for
589 * immediate reval.
590 */
Jeff Laytonabab0952010-02-12 07:44:18 -0500591 rc = 0;
592 CIFS_I(inode)->time = 0;
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400593 default:
Jeff Laytonabab0952010-02-12 07:44:18 -0500594 goto cgfi_exit;
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400595 }
Jeff Laytonabab0952010-02-12 07:44:18 -0500596
597 /*
598 * don't bother with SFU junk here -- just mark inode as needing
599 * revalidation.
600 */
Jeff Laytonabab0952010-02-12 07:44:18 -0500601 fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
602 fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
603 cifs_fattr_to_inode(inode, &fattr);
604cgfi_exit:
605 FreeXid(xid);
606 return rc;
607}
608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609int cifs_get_inode_info(struct inode **pinode,
Steve French646dd532008-05-15 01:50:56 +0000610 const unsigned char *full_path, FILE_ALL_INFO *pfindData,
Steve French8b1327f2008-03-14 22:37:16 +0000611 struct super_block *sb, int xid, const __u16 *pfid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400613 int rc = 0, tmprc;
Steve French96daf2b2011-05-27 04:34:02 +0000614 struct cifs_tcon *pTcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400615 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 char *buf = NULL;
Steve French5ade9de2008-05-02 20:56:23 +0000618 bool adjustTZ = false;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400619 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Jeff Layton7ffec372010-09-29 19:51:11 -0400621 tlink = cifs_sb_tlink(cifs_sb);
622 if (IS_ERR(tlink))
623 return PTR_ERR(tlink);
624 pTcon = tlink_tcon(tlink);
625
Joe Perchesb6b38f72010-04-21 03:50:45 +0000626 cFYI(1, "Getting info on %s", full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700628 if ((pfindData == NULL) && (*pinode != NULL)) {
629 if (CIFS_I(*pinode)->clientCanCacheRead) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000630 cFYI(1, "No need to revalidate cached inode sizes");
Jeff Layton7ffec372010-09-29 19:51:11 -0400631 goto cgii_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
633 }
634
635 /* if file info not passed in then get it from server */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700636 if (pfindData == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Jeff Layton7ffec372010-09-29 19:51:11 -0400638 if (buf == NULL) {
639 rc = -ENOMEM;
640 goto cgii_exit;
641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 pfindData = (FILE_ALL_INFO *)buf;
Igor Mammedov79626702008-03-09 03:44:18 +0000643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 /* could do find first instead but this returns more info */
Igor Mammedov79626702008-03-09 03:44:18 +0000645 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +0000646 0 /* not legacy */,
Steve French6b8edfe2005-08-23 20:26:03 -0700647 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700648 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French6b8edfe2005-08-23 20:26:03 -0700649 /* BB optimize code so we do not make the above call
650 when server claims no NT SMB support and the above call
651 failed at least once - set flag in tcon or mount */
Steve French4523cc32007-04-30 20:13:06 +0000652 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
Igor Mammedov79626702008-03-09 03:44:18 +0000653 rc = SMBQueryInformation(xid, pTcon, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000654 pfindData, cifs_sb->local_nls,
Steve French6b8edfe2005-08-23 20:26:03 -0700655 cifs_sb->mnt_cifs_flags &
656 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4b18f2a2008-04-29 00:06:05 +0000657 adjustTZ = true;
Steve French6b8edfe2005-08-23 20:26:03 -0700658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400660
661 if (!rc) {
662 cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
663 cifs_sb, adjustTZ);
664 } else if (rc == -EREMOTE) {
665 cifs_create_dfs_fattr(&fattr, sb);
Steve Frenchb9a32602008-05-20 21:52:32 +0000666 rc = 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400667 } else {
Igor Mammedov79626702008-03-09 03:44:18 +0000668 goto cgii_exit;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400671 /*
672 * If an inode wasn't passed in, then get the inode number
673 *
674 * Is an i_ino of zero legal? Can we use that to check if the server
675 * supports returning inode numbers? Are there other sanity checks we
676 * can use to ensure that the server is really filling in that field?
677 *
678 * We can not use the IndexNumber field by default from Windows or
679 * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
680 * CIFS spec claims that this value is unique within the scope of a
681 * share, and the windows docs hint that it's actually unique
682 * per-machine.
683 *
684 * There may be higher info levels that work but are there Windows
685 * server or network appliances for which IndexNumber field is not
686 * guaranteed unique?
687 */
Steve Frenchb9a32602008-05-20 21:52:32 +0000688 if (*pinode == NULL) {
Steve Frenchb9a32602008-05-20 21:52:32 +0000689 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
690 int rc1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Steve Frenchb9a32602008-05-20 21:52:32 +0000692 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400693 full_path, &fattr.cf_uniqueid,
Steve French737b7582005-04-28 22:41:06 -0700694 cifs_sb->local_nls,
695 cifs_sb->mnt_cifs_flags &
696 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500697 if (rc1 || !fattr.cf_uniqueid) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000698 cFYI(1, "GetSrvInodeNum rc %d", rc1);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400699 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500700 cifs_autodisable_serverino(cifs_sb);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500701 }
Jeff Layton132ac7b2009-02-10 07:33:57 -0500702 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400703 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500704 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000705 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400706 fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000707 }
708
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400709 /* query for SFU type info if supported and needed */
710 if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
711 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
712 tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
713 if (tmprc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000714 cFYI(1, "cifs_sfu_type failed: %d", tmprc);
Steve Frenchb9a32602008-05-20 21:52:32 +0000715 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000716
Jeff Layton79df1ba2010-12-06 12:52:08 -0500717#ifdef CONFIG_CIFS_ACL
Steve Frenchb9a32602008-05-20 21:52:32 +0000718 /* fill in 0777 bits from ACL */
719 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
Shirish Pargaonkar78415d22010-11-27 11:37:26 -0600720 rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path,
721 pfid);
722 if (rc) {
723 cFYI(1, "%s: Getting ACL failed with error: %d",
724 __func__, rc);
725 goto cgii_exit;
726 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000727 }
Jeff Layton79df1ba2010-12-06 12:52:08 -0500728#endif /* CONFIG_CIFS_ACL */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400729
730 /* fill in remaining high mode bits e.g. SUID, VTX */
731 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
732 cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
733
Stefan Metzmacher1b12b9c2010-08-05 21:19:56 +0200734 /* check for Minshall+French symlinks */
735 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
736 tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
737 if (tmprc)
738 cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
739 }
740
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400741 if (!*pinode) {
742 *pinode = cifs_iget(sb, &fattr);
743 if (!*pinode)
744 rc = -ENOMEM;
745 } else {
746 cifs_fattr_to_inode(*pinode, &fattr);
Steve Frenchb9a32602008-05-20 21:52:32 +0000747 }
748
Igor Mammedov79626702008-03-09 03:44:18 +0000749cgii_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 kfree(buf);
Jeff Layton7ffec372010-09-29 19:51:11 -0400751 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return rc;
753}
754
Steve French7f8ed422007-09-28 22:28:55 +0000755static const struct inode_operations cifs_ipc_inode_ops = {
756 .lookup = cifs_lookup,
757};
758
Steve Frenchf87d39d2011-05-27 03:50:55 +0000759char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
Steve French96daf2b2011-05-27 04:34:02 +0000760 struct cifs_tcon *tcon)
Steve French8be0ed42008-12-05 19:14:12 +0000761{
Steve Frenchf87d39d2011-05-27 03:50:55 +0000762 int pplen = vol->prepath ? strlen(vol->prepath) : 0;
Steve French8be0ed42008-12-05 19:14:12 +0000763 int dfsplen;
764 char *full_path = NULL;
765
766 /* if no prefix path, simply set path to the root of share to "" */
767 if (pplen == 0) {
768 full_path = kmalloc(1, GFP_KERNEL);
769 if (full_path)
770 full_path[0] = 0;
771 return full_path;
772 }
773
Jeff Layton0d424ad2010-09-20 16:01:35 -0700774 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
775 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
Steve French8be0ed42008-12-05 19:14:12 +0000776 else
777 dfsplen = 0;
778
779 full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
780 if (full_path == NULL)
781 return full_path;
782
Jeff Laytonf9e8c452011-08-05 10:28:01 -0400783 if (dfsplen)
Jeff Layton0d424ad2010-09-20 16:01:35 -0700784 strncpy(full_path, tcon->treeName, dfsplen);
Steve Frenchf87d39d2011-05-27 03:50:55 +0000785 strncpy(full_path + dfsplen, vol->prepath, pplen);
Jeff Laytonf9e8c452011-08-05 10:28:01 -0400786 convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
Steve French8be0ed42008-12-05 19:14:12 +0000787 full_path[dfsplen + pplen] = 0; /* add trailing null */
788 return full_path;
789}
790
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400791static int
792cifs_find_inode(struct inode *inode, void *opaque)
793{
794 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
795
Jeff Laytonf30b9c12010-07-19 18:00:17 -0400796 /* don't match inode with different uniqueid */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400797 if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
798 return 0;
799
Jeff Layton20054bd2011-01-07 11:30:27 -0500800 /* use createtime like an i_generation field */
801 if (CIFS_I(inode)->createtime != fattr->cf_createtime)
802 return 0;
803
Jeff Laytonf30b9c12010-07-19 18:00:17 -0400804 /* don't match inode of different type */
805 if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
806 return 0;
807
Jeff Layton5acfec22010-08-02 17:43:54 -0400808 /* if it's not a directory or has no dentries, then flag it */
809 if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
Jeff Layton3d694382010-05-11 14:59:55 -0400810 fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
Jeff Layton3d694382010-05-11 14:59:55 -0400811
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400812 return 1;
813}
814
815static int
816cifs_init_inode(struct inode *inode, void *opaque)
817{
818 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
819
820 CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
Jeff Layton20054bd2011-01-07 11:30:27 -0500821 CIFS_I(inode)->createtime = fattr->cf_createtime;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400822 return 0;
823}
824
Jeff Layton5acfec22010-08-02 17:43:54 -0400825/*
826 * walk dentry list for an inode and report whether it has aliases that
827 * are hashed. We use this to determine if a directory inode can actually
828 * be used.
829 */
830static bool
831inode_has_hashed_dentries(struct inode *inode)
832{
833 struct dentry *dentry;
834
Nick Piggin873feea2011-01-07 17:50:06 +1100835 spin_lock(&inode->i_lock);
Jeff Layton5acfec22010-08-02 17:43:54 -0400836 list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
837 if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
Nick Piggin873feea2011-01-07 17:50:06 +1100838 spin_unlock(&inode->i_lock);
Jeff Layton5acfec22010-08-02 17:43:54 -0400839 return true;
840 }
841 }
Nick Piggin873feea2011-01-07 17:50:06 +1100842 spin_unlock(&inode->i_lock);
Jeff Layton5acfec22010-08-02 17:43:54 -0400843 return false;
844}
845
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400846/* Given fattrs, get a corresponding inode */
847struct inode *
848cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
849{
850 unsigned long hash;
851 struct inode *inode;
852
Jeff Layton3d694382010-05-11 14:59:55 -0400853retry_iget5_locked:
Joe Perchesb6b38f72010-04-21 03:50:45 +0000854 cFYI(1, "looking for uniqueid=%llu", fattr->cf_uniqueid);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400855
856 /* hash down to 32-bits on 32-bit arch */
857 hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
858
859 inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400860 if (inode) {
Jeff Layton5acfec22010-08-02 17:43:54 -0400861 /* was there a potentially problematic inode collision? */
Jeff Layton3d694382010-05-11 14:59:55 -0400862 if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
Jeff Layton3d694382010-05-11 14:59:55 -0400863 fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
Jeff Layton5acfec22010-08-02 17:43:54 -0400864
865 if (inode_has_hashed_dentries(inode)) {
866 cifs_autodisable_serverino(CIFS_SB(sb));
867 iput(inode);
868 fattr->cf_uniqueid = iunique(sb, ROOT_I);
869 goto retry_iget5_locked;
870 }
Jeff Layton3d694382010-05-11 14:59:55 -0400871 }
872
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400873 cifs_fattr_to_inode(inode, fattr);
874 if (sb->s_flags & MS_NOATIME)
875 inode->i_flags |= S_NOATIME | S_NOCMTIME;
876 if (inode->i_state & I_NEW) {
877 inode->i_ino = hash;
Jeff Layton522440e2010-09-29 09:49:54 -0400878 if (S_ISREG(inode->i_mode))
879 inode->i_data.backing_dev_info = sb->s_bdi;
Steve French0ccd4802010-07-16 04:31:02 +0000880#ifdef CONFIG_CIFS_FSCACHE
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530881 /* initialize per-inode cache cookie pointer */
882 CIFS_I(inode)->fscache = NULL;
Steve French0ccd4802010-07-16 04:31:02 +0000883#endif
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400884 unlock_new_inode(inode);
885 }
886 }
887
888 return inode;
889}
890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891/* gets root inode */
Shirish Pargaonkar9b6763e2011-02-21 23:56:59 -0600892struct inode *cifs_root_iget(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893{
David Howellsce634ab2008-02-07 00:15:33 -0800894 int xid;
Jeff Layton0d424ad2010-09-20 16:01:35 -0700895 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400896 struct inode *inode = NULL;
David Howellsce634ab2008-02-07 00:15:33 -0800897 long rc;
Steve French96daf2b2011-05-27 04:34:02 +0000898 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
David Howellsce634ab2008-02-07 00:15:33 -0800899
Steve French8be0ed42008-12-05 19:14:12 +0000900 xid = GetXid();
Jeff Layton0d424ad2010-09-20 16:01:35 -0700901 if (tcon->unix_ext)
Steve Frenchf87d39d2011-05-27 03:50:55 +0000902 rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400903 else
Steve Frenchf87d39d2011-05-27 03:50:55 +0000904 rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400905
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000906 if (!inode) {
907 inode = ERR_PTR(rc);
908 goto out;
909 }
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400910
Steve French0ccd4802010-07-16 04:31:02 +0000911#ifdef CONFIG_CIFS_FSCACHE
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530912 /* populate tcon->resource_id */
Jeff Layton0d424ad2010-09-20 16:01:35 -0700913 tcon->resource_id = CIFS_I(inode)->uniqueid;
Steve French0ccd4802010-07-16 04:31:02 +0000914#endif
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530915
Jeff Layton0d424ad2010-09-20 16:01:35 -0700916 if (rc && tcon->ipc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000917 cFYI(1, "ipc connection - fake read inode");
Steve French7f8ed422007-09-28 22:28:55 +0000918 inode->i_mode |= S_IFDIR;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200919 set_nlink(inode, 2);
Steve French7f8ed422007-09-28 22:28:55 +0000920 inode->i_op = &cifs_ipc_inode_ops;
921 inode->i_fop = &simple_dir_operations;
922 inode->i_uid = cifs_sb->mnt_uid;
923 inode->i_gid = cifs_sb->mnt_gid;
Steve Frenchad661332008-08-12 14:14:40 +0000924 } else if (rc) {
David Howellsce634ab2008-02-07 00:15:33 -0800925 iget_failed(inode);
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000926 inode = ERR_PTR(rc);
Steve French7f8ed422007-09-28 22:28:55 +0000927 }
928
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000929out:
David Howellsce634ab2008-02-07 00:15:33 -0800930 /* can not call macro FreeXid here since in a void func
931 * TODO: This is no longer true
932 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 _FreeXid(xid);
David Howellsce634ab2008-02-07 00:15:33 -0800934 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935}
936
Steve French388e57b2008-09-16 23:50:58 +0000937static int
938cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
939 char *full_path, __u32 dosattr)
940{
941 int rc;
942 int oplock = 0;
943 __u16 netfid;
944 __u32 netpid;
945 bool set_time = false;
946 struct cifsFileInfo *open_file;
947 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
948 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400949 struct tcon_link *tlink = NULL;
Steve French96daf2b2011-05-27 04:34:02 +0000950 struct cifs_tcon *pTcon;
Steve French388e57b2008-09-16 23:50:58 +0000951 FILE_BASIC_INFO info_buf;
952
Steve French1adcb712009-02-25 14:19:56 +0000953 if (attrs == NULL)
954 return -EINVAL;
955
Steve French388e57b2008-09-16 23:50:58 +0000956 if (attrs->ia_valid & ATTR_ATIME) {
957 set_time = true;
958 info_buf.LastAccessTime =
959 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
960 } else
961 info_buf.LastAccessTime = 0;
962
963 if (attrs->ia_valid & ATTR_MTIME) {
964 set_time = true;
965 info_buf.LastWriteTime =
966 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
967 } else
968 info_buf.LastWriteTime = 0;
969
970 /*
971 * Samba throws this field away, but windows may actually use it.
972 * Do not set ctime unless other time stamps are changed explicitly
973 * (i.e. by utimes()) since we would then have a mix of client and
974 * server times.
975 */
976 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000977 cFYI(1, "CIFS - CTIME changed");
Steve French388e57b2008-09-16 23:50:58 +0000978 info_buf.ChangeTime =
979 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
980 } else
981 info_buf.ChangeTime = 0;
982
983 info_buf.CreationTime = 0; /* don't change */
984 info_buf.Attributes = cpu_to_le32(dosattr);
985
986 /*
987 * If the file is already open for write, just use that fileid
988 */
Jeff Layton6508d902010-09-29 19:51:11 -0400989 open_file = find_writable_file(cifsInode, true);
Steve French388e57b2008-09-16 23:50:58 +0000990 if (open_file) {
991 netfid = open_file->netfid;
992 netpid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -0400993 pTcon = tlink_tcon(open_file->tlink);
Steve French388e57b2008-09-16 23:50:58 +0000994 goto set_via_filehandle;
995 }
996
Jeff Layton7ffec372010-09-29 19:51:11 -0400997 tlink = cifs_sb_tlink(cifs_sb);
998 if (IS_ERR(tlink)) {
999 rc = PTR_ERR(tlink);
1000 tlink = NULL;
1001 goto out;
1002 }
1003 pTcon = tlink_tcon(tlink);
Jeff Laytonba00ba62010-09-20 16:01:31 -07001004
Steve French388e57b2008-09-16 23:50:58 +00001005 /*
1006 * NT4 apparently returns success on this call, but it doesn't
1007 * really work.
1008 */
1009 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
1010 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
1011 &info_buf, cifs_sb->local_nls,
1012 cifs_sb->mnt_cifs_flags &
1013 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +00001014 if (rc == 0) {
1015 cifsInode->cifsAttrs = dosattr;
1016 goto out;
1017 } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
Steve French388e57b2008-09-16 23:50:58 +00001018 goto out;
1019 }
1020
Joe Perchesb6b38f72010-04-21 03:50:45 +00001021 cFYI(1, "calling SetFileInfo since SetPathInfo for "
1022 "times not supported by this server");
Steve French388e57b2008-09-16 23:50:58 +00001023 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1024 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1025 CREATE_NOT_DIR, &netfid, &oplock,
1026 NULL, cifs_sb->local_nls,
1027 cifs_sb->mnt_cifs_flags &
1028 CIFS_MOUNT_MAP_SPECIAL_CHR);
1029
1030 if (rc != 0) {
1031 if (rc == -EIO)
1032 rc = -EINVAL;
1033 goto out;
1034 }
1035
1036 netpid = current->tgid;
1037
1038set_via_filehandle:
1039 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
Steve Frenchd3889082008-09-24 19:22:52 +00001040 if (!rc)
1041 cifsInode->cifsAttrs = dosattr;
1042
Steve French388e57b2008-09-16 23:50:58 +00001043 if (open_file == NULL)
1044 CIFSSMBClose(xid, pTcon, netfid);
1045 else
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001046 cifsFileInfo_put(open_file);
Steve French388e57b2008-09-16 23:50:58 +00001047out:
Jeff Layton7ffec372010-09-29 19:51:11 -04001048 if (tlink != NULL)
1049 cifs_put_tlink(tlink);
Steve French388e57b2008-09-16 23:50:58 +00001050 return rc;
1051}
1052
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001053/*
1054 * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
1055 * and rename it to a random name that hopefully won't conflict with
1056 * anything else.
1057 */
1058static int
Steve French32709582008-10-20 00:44:19 +00001059cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001060{
1061 int oplock = 0;
1062 int rc;
1063 __u16 netfid;
Steve French32709582008-10-20 00:44:19 +00001064 struct inode *inode = dentry->d_inode;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001065 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1066 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001067 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001068 struct cifs_tcon *tcon;
Steve French32709582008-10-20 00:44:19 +00001069 __u32 dosattr, origattr;
1070 FILE_BASIC_INFO *info_buf = NULL;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001071
Jeff Layton7ffec372010-09-29 19:51:11 -04001072 tlink = cifs_sb_tlink(cifs_sb);
1073 if (IS_ERR(tlink))
1074 return PTR_ERR(tlink);
1075 tcon = tlink_tcon(tlink);
1076
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001077 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
Jeff Laytondd1db2d2008-10-16 19:27:12 -04001078 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001079 &netfid, &oplock, NULL, cifs_sb->local_nls,
1080 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1081 if (rc != 0)
1082 goto out;
1083
Steve French32709582008-10-20 00:44:19 +00001084 origattr = cifsInode->cifsAttrs;
1085 if (origattr == 0)
1086 origattr |= ATTR_NORMAL;
1087
1088 dosattr = origattr & ~ATTR_READONLY;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001089 if (dosattr == 0)
1090 dosattr |= ATTR_NORMAL;
1091 dosattr |= ATTR_HIDDEN;
1092
Steve French32709582008-10-20 00:44:19 +00001093 /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
1094 if (dosattr != origattr) {
1095 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
1096 if (info_buf == NULL) {
1097 rc = -ENOMEM;
1098 goto out_close;
1099 }
1100 info_buf->Attributes = cpu_to_le32(dosattr);
1101 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1102 current->tgid);
1103 /* although we would like to mark the file hidden
1104 if that fails we will still try to rename it */
Steve French41346092008-10-20 18:24:42 +00001105 if (rc != 0)
Steve French32709582008-10-20 00:44:19 +00001106 cifsInode->cifsAttrs = dosattr;
1107 else
1108 dosattr = origattr; /* since not able to change them */
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001109 }
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001110
Jeff Laytondd1db2d2008-10-16 19:27:12 -04001111 /* rename the file */
1112 rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001113 cifs_sb->mnt_cifs_flags &
1114 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French32709582008-10-20 00:44:19 +00001115 if (rc != 0) {
1116 rc = -ETXTBSY;
1117 goto undo_setattr;
1118 }
Jeff Layton6d22f092008-09-23 11:48:35 -04001119
Steve French32709582008-10-20 00:44:19 +00001120 /* try to set DELETE_ON_CLOSE */
1121 if (!cifsInode->delete_pending) {
1122 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
1123 current->tgid);
1124 /*
1125 * some samba versions return -ENOENT when we try to set the
1126 * file disposition here. Likely a samba bug, but work around
1127 * it for now. This means that some cifsXXX files may hang
1128 * around after they shouldn't.
1129 *
1130 * BB: remove this hack after more servers have the fix
1131 */
1132 if (rc == -ENOENT)
1133 rc = 0;
1134 else if (rc != 0) {
1135 rc = -ETXTBSY;
1136 goto undo_rename;
1137 }
1138 cifsInode->delete_pending = true;
1139 }
Jeff Layton7ce86d52008-09-24 11:32:59 -04001140
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001141out_close:
1142 CIFSSMBClose(xid, tcon, netfid);
1143out:
Steve French32709582008-10-20 00:44:19 +00001144 kfree(info_buf);
Jeff Layton7ffec372010-09-29 19:51:11 -04001145 cifs_put_tlink(tlink);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001146 return rc;
Steve French32709582008-10-20 00:44:19 +00001147
1148 /*
1149 * reset everything back to the original state. Don't bother
1150 * dealing with errors here since we can't do anything about
1151 * them anyway.
1152 */
1153undo_rename:
1154 CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
1155 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1156 CIFS_MOUNT_MAP_SPECIAL_CHR);
1157undo_setattr:
1158 if (dosattr != origattr) {
1159 info_buf->Attributes = cpu_to_le32(origattr);
1160 if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1161 current->tgid))
1162 cifsInode->cifsAttrs = origattr;
1163 }
1164
1165 goto out_close;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001166}
1167
Steve Frenchff694522009-04-20 19:45:13 +00001168
1169/*
1170 * If dentry->d_inode is null (usually meaning the cached dentry
1171 * is a negative dentry) then we would attempt a standard SMB delete, but
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001172 * if that fails we can not attempt the fall back mechanisms on EACCESS
1173 * but will return the EACCESS to the caller. Note that the VFS does not call
Steve Frenchff694522009-04-20 19:45:13 +00001174 * unlink on negative dentries currently.
1175 */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001176int cifs_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177{
1178 int rc = 0;
1179 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 char *full_path = NULL;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001181 struct inode *inode = dentry->d_inode;
Steve Frenchff694522009-04-20 19:45:13 +00001182 struct cifsInodeInfo *cifs_inode;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001183 struct super_block *sb = dir->i_sb;
1184 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001185 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001186 struct cifs_tcon *tcon;
Steve French60502472008-10-07 18:42:52 +00001187 struct iattr *attrs = NULL;
1188 __u32 dosattr = 0, origattr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
Joe Perchesb6b38f72010-04-21 03:50:45 +00001190 cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
Jeff Layton7ffec372010-09-29 19:51:11 -04001192 tlink = cifs_sb_tlink(cifs_sb);
1193 if (IS_ERR(tlink))
1194 return PTR_ERR(tlink);
1195 tcon = tlink_tcon(tlink);
1196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 xid = GetXid();
1198
Jeff Layton5f0319a2008-09-16 14:05:16 -04001199 /* Unlink can be called from rename so we can not take the
1200 * sb->s_vfs_rename_mutex here */
1201 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301203 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001204 goto unlink_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 }
Steve French2d785a52007-07-15 01:48:57 +00001206
Jeff Layton5f0319a2008-09-16 14:05:16 -04001207 if ((tcon->ses->capabilities & CAP_UNIX) &&
Steve French2d785a52007-07-15 01:48:57 +00001208 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Jeff Layton5f0319a2008-09-16 14:05:16 -04001209 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1210 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
Steve French2d785a52007-07-15 01:48:57 +00001211 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
1212 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001213 cFYI(1, "posix del rc %d", rc);
Steve French2d785a52007-07-15 01:48:57 +00001214 if ((rc == 0) || (rc == -ENOENT))
1215 goto psx_del_no_retry;
1216 }
1217
Steve French60502472008-10-07 18:42:52 +00001218retry_std_delete:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001219 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001220 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French60502472008-10-07 18:42:52 +00001221
Steve French2d785a52007-07-15 01:48:57 +00001222psx_del_no_retry:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 if (!rc) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001224 if (inode)
1225 drop_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 } else if (rc == -ENOENT) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001227 d_drop(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 } else if (rc == -ETXTBSY) {
Steve French32709582008-10-20 00:44:19 +00001229 rc = cifs_rename_pending_delete(full_path, dentry, xid);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001230 if (rc == 0)
1231 drop_nlink(inode);
Steve Frenchff694522009-04-20 19:45:13 +00001232 } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
Steve French388e57b2008-09-16 23:50:58 +00001233 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
1234 if (attrs == NULL) {
1235 rc = -ENOMEM;
1236 goto out_reval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 }
Steve French388e57b2008-09-16 23:50:58 +00001238
1239 /* try to reset dos attributes */
Steve Frenchff694522009-04-20 19:45:13 +00001240 cifs_inode = CIFS_I(inode);
1241 origattr = cifs_inode->cifsAttrs;
Steve French60502472008-10-07 18:42:52 +00001242 if (origattr == 0)
1243 origattr |= ATTR_NORMAL;
1244 dosattr = origattr & ~ATTR_READONLY;
Steve French388e57b2008-09-16 23:50:58 +00001245 if (dosattr == 0)
1246 dosattr |= ATTR_NORMAL;
1247 dosattr |= ATTR_HIDDEN;
1248
1249 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
Steve French388e57b2008-09-16 23:50:58 +00001250 if (rc != 0)
1251 goto out_reval;
Steve French60502472008-10-07 18:42:52 +00001252
1253 goto retry_std_delete;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
Steve French60502472008-10-07 18:42:52 +00001255
1256 /* undo the setattr if we errored out and it's needed */
1257 if (rc != 0 && dosattr != 0)
1258 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
1259
Steve French388e57b2008-09-16 23:50:58 +00001260out_reval:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001261 if (inode) {
Steve Frenchff694522009-04-20 19:45:13 +00001262 cifs_inode = CIFS_I(inode);
1263 cifs_inode->time = 0; /* will force revalidate to get info
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001264 when needed */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001265 inode->i_ctime = current_fs_time(sb);
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001266 }
Jeff Layton5f0319a2008-09-16 14:05:16 -04001267 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
Steve Frenchff694522009-04-20 19:45:13 +00001268 cifs_inode = CIFS_I(dir);
Steve French60502472008-10-07 18:42:52 +00001269 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
Jeff Layton7ffec372010-09-29 19:51:11 -04001270unlink_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 kfree(full_path);
Steve French60502472008-10-07 18:42:52 +00001272 kfree(attrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001274 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 return rc;
1276}
1277
Al Viro18bb1db2011-07-26 01:41:39 -04001278int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
Jeff Layton6b37faa2008-10-06 21:54:41 +00001280 int rc = 0, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 int xid;
1282 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001283 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001284 struct cifs_tcon *pTcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 char *full_path = NULL;
1286 struct inode *newinode = NULL;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001287 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
Al Viro18bb1db2011-07-26 01:41:39 -04001289 cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001292 tlink = cifs_sb_tlink(cifs_sb);
1293 if (IS_ERR(tlink))
1294 return PTR_ERR(tlink);
1295 pTcon = tlink_tcon(tlink);
1296
1297 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Steve French7f573562005-08-30 11:32:14 -07001299 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301301 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001302 goto mkdir_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 }
Steve French50c2f752007-07-13 00:33:32 +00001304
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001305 if ((pTcon->ses->capabilities & CAP_UNIX) &&
1306 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Steve French2dd29d32007-04-23 22:07:35 +00001307 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
1308 u32 oplock = 0;
Steve Frenchf6d09982008-01-08 23:18:22 +00001309 FILE_UNIX_BASIC_INFO *pInfo =
Steve French2dd29d32007-04-23 22:07:35 +00001310 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001311 if (pInfo == NULL) {
Steve French2dd29d32007-04-23 22:07:35 +00001312 rc = -ENOMEM;
1313 goto mkdir_out;
1314 }
Steve French50c2f752007-07-13 00:33:32 +00001315
Al Viroce3b0f82009-03-29 19:08:22 -04001316 mode &= ~current_umask();
Steve French2dd29d32007-04-23 22:07:35 +00001317 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
1318 mode, NULL /* netfid */, pInfo, &oplock,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001319 full_path, cifs_sb->local_nls,
1320 cifs_sb->mnt_cifs_flags &
Steve French2dd29d32007-04-23 22:07:35 +00001321 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc45d7072007-09-17 02:04:21 +00001322 if (rc == -EOPNOTSUPP) {
1323 kfree(pInfo);
1324 goto mkdir_retry_old;
1325 } else if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001326 cFYI(1, "posix mkdir returned 0x%x", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001327 d_drop(direntry);
1328 } else {
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001329 if (pInfo->Type == cpu_to_le32(-1)) {
1330 /* no return info, go query for it */
Steve French5a07cdf2007-09-16 23:12:47 +00001331 kfree(pInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001332 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001333 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001334/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
1335 to set uid/gid */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001336
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001337 cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
Jeff Layton4065c802010-05-17 07:18:58 -04001338 cifs_fill_uniqueid(inode->i_sb, &fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001339 newinode = cifs_iget(inode->i_sb, &fattr);
1340 if (!newinode) {
Steve French5a07cdf2007-09-16 23:12:47 +00001341 kfree(pInfo);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001342 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001343 }
Jeff Layton6b37faa2008-10-06 21:54:41 +00001344
Steve French2dd29d32007-04-23 22:07:35 +00001345 d_instantiate(direntry, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001346
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001347#ifdef CONFIG_CIFS_DEBUG2
Joe Perchesb6b38f72010-04-21 03:50:45 +00001348 cFYI(1, "instantiated dentry %p %s to inode %p",
1349 direntry, direntry->d_name.name, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001350
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001351 if (newinode->i_nlink != 2)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001352 cFYI(1, "unexpected number of links %d",
1353 newinode->i_nlink);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001354#endif
Steve French2dd29d32007-04-23 22:07:35 +00001355 }
1356 kfree(pInfo);
1357 goto mkdir_out;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001358 }
Steve Frenchc45d7072007-09-17 02:04:21 +00001359mkdir_retry_old:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -07001361 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
1362 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001364 cFYI(1, "cifs_mkdir returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 d_drop(direntry);
1366 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001367mkdir_get_info:
Steve Frenchc18c8422007-07-18 23:21:09 +00001368 if (pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001370 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 else
1372 rc = cifs_get_inode_info(&newinode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +00001373 inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 d_instantiate(direntry, newinode);
Steve French2dd29d32007-04-23 22:07:35 +00001376 /* setting nlink not necessary except in cases where we
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001377 * failed to get it from the server or was set bogus */
Steve French2dd29d32007-04-23 22:07:35 +00001378 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
Miklos Szeredibfe86842011-10-28 14:13:29 +02001379 set_nlink(direntry->d_inode, 2);
Jeff Layton95089912008-08-06 04:39:02 +00001380
Al Viroce3b0f82009-03-29 19:08:22 -04001381 mode &= ~current_umask();
Jeff Layton95089912008-08-06 04:39:02 +00001382 /* must turn on setgid bit if parent dir has it */
1383 if (inode->i_mode & S_ISGID)
1384 mode |= S_ISGID;
1385
Steve Frenchc18c8422007-07-18 23:21:09 +00001386 if (pTcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001387 struct cifs_unix_set_info_args args = {
1388 .mode = mode,
1389 .ctime = NO_CHANGE_64,
1390 .atime = NO_CHANGE_64,
1391 .mtime = NO_CHANGE_64,
1392 .device = 0,
1393 };
Steve Frenchd0d2f2d2005-06-02 15:12:36 -07001394 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
David Howellsa001e5b2008-11-14 10:38:47 +11001395 args.uid = (__u64)current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001396 if (inode->i_mode & S_ISGID)
1397 args.gid = (__u64)inode->i_gid;
1398 else
David Howellsa001e5b2008-11-14 10:38:47 +11001399 args.gid = (__u64)current_fsgid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 } else {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001401 args.uid = NO_CHANGE_64;
1402 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 }
Jeff Layton01ea95e2009-07-09 20:02:49 -04001404 CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
1405 cifs_sb->local_nls,
1406 cifs_sb->mnt_cifs_flags &
1407 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French3ce53fc2007-06-08 14:55:14 +00001408 } else {
Jeff Layton67750fb2008-05-09 22:28:02 +00001409 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1410 (mode & S_IWUGO) == 0) {
1411 FILE_BASIC_INFO pInfo;
Jeff Layton6b37faa2008-10-06 21:54:41 +00001412 struct cifsInodeInfo *cifsInode;
1413 u32 dosattrs;
1414
Jeff Layton67750fb2008-05-09 22:28:02 +00001415 memset(&pInfo, 0, sizeof(pInfo));
Jeff Layton6b37faa2008-10-06 21:54:41 +00001416 cifsInode = CIFS_I(newinode);
1417 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1418 pInfo.Attributes = cpu_to_le32(dosattrs);
1419 tmprc = CIFSSMBSetPathInfo(xid, pTcon,
1420 full_path, &pInfo,
1421 cifs_sb->local_nls,
Jeff Layton67750fb2008-05-09 22:28:02 +00001422 cifs_sb->mnt_cifs_flags &
1423 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +00001424 if (tmprc == 0)
1425 cifsInode->cifsAttrs = dosattrs;
Jeff Layton67750fb2008-05-09 22:28:02 +00001426 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001427 if (direntry->d_inode) {
Jeff Laytonb0fd30d2008-05-22 09:33:34 -04001428 if (cifs_sb->mnt_cifs_flags &
1429 CIFS_MOUNT_DYNPERM)
1430 direntry->d_inode->i_mode =
1431 (mode | S_IFDIR);
Steve French4e94a102008-05-23 18:22:46 +00001432
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001433 if (cifs_sb->mnt_cifs_flags &
Steve French6473a552005-11-29 20:20:10 -08001434 CIFS_MOUNT_SET_UID) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001435 direntry->d_inode->i_uid =
David Howellsa001e5b2008-11-14 10:38:47 +11001436 current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001437 if (inode->i_mode & S_ISGID)
1438 direntry->d_inode->i_gid =
1439 inode->i_gid;
1440 else
1441 direntry->d_inode->i_gid =
David Howellsa001e5b2008-11-14 10:38:47 +11001442 current_fsgid();
Steve French6473a552005-11-29 20:20:10 -08001443 }
1444 }
Steve French2a138ebb2005-11-29 21:22:19 -08001445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001447mkdir_out:
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001448 /*
1449 * Force revalidate to get parent dir info when needed since cached
1450 * attributes are invalid now.
1451 */
1452 CIFS_I(inode)->time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 kfree(full_path);
1454 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001455 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 return rc;
1457}
1458
1459int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1460{
1461 int rc = 0;
1462 int xid;
1463 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001464 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001465 struct cifs_tcon *pTcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 char *full_path = NULL;
1467 struct cifsInodeInfo *cifsInode;
1468
Joe Perchesb6b38f72010-04-21 03:50:45 +00001469 cFYI(1, "cifs_rmdir, inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
1471 xid = GetXid();
1472
Steve French7f573562005-08-30 11:32:14 -07001473 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301475 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001476 goto rmdir_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 }
1478
Jeff Layton7ffec372010-09-29 19:51:11 -04001479 cifs_sb = CIFS_SB(inode->i_sb);
1480 tlink = cifs_sb_tlink(cifs_sb);
1481 if (IS_ERR(tlink)) {
1482 rc = PTR_ERR(tlink);
1483 goto rmdir_exit;
1484 }
1485 pTcon = tlink_tcon(tlink);
1486
Steve French737b7582005-04-28 22:41:06 -07001487 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1488 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -04001489 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
1491 if (!rc) {
Steve French3677db12007-02-26 16:46:11 +00001492 spin_lock(&direntry->d_inode->i_lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001493 i_size_write(direntry->d_inode, 0);
Dave Hansence71ec32006-09-30 23:29:06 -07001494 clear_nlink(direntry->d_inode);
Steve French3677db12007-02-26 16:46:11 +00001495 spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 }
1497
1498 cifsInode = CIFS_I(direntry->d_inode);
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001499 /* force revalidate to go get info when needed */
1500 cifsInode->time = 0;
Steve French42c24542009-01-13 22:03:55 +00001501
1502 cifsInode = CIFS_I(inode);
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001503 /*
1504 * Force revalidate to get parent dir info when needed since cached
1505 * attributes are invalid now.
1506 */
1507 cifsInode->time = 0;
Steve French42c24542009-01-13 22:03:55 +00001508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1510 current_fs_time(inode->i_sb);
1511
Jeff Layton7ffec372010-09-29 19:51:11 -04001512rmdir_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 kfree(full_path);
1514 FreeXid(xid);
1515 return rc;
1516}
1517
Steve Frenchee2fd962008-09-23 18:23:33 +00001518static int
1519cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
1520 struct dentry *to_dentry, const char *toPath)
1521{
1522 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001523 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001524 struct cifs_tcon *pTcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001525 __u16 srcfid;
1526 int oplock, rc;
1527
Jeff Layton7ffec372010-09-29 19:51:11 -04001528 tlink = cifs_sb_tlink(cifs_sb);
1529 if (IS_ERR(tlink))
1530 return PTR_ERR(tlink);
1531 pTcon = tlink_tcon(tlink);
1532
Steve Frenchee2fd962008-09-23 18:23:33 +00001533 /* try path-based rename first */
1534 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
1535 cifs_sb->mnt_cifs_flags &
1536 CIFS_MOUNT_MAP_SPECIAL_CHR);
1537
1538 /*
1539 * don't bother with rename by filehandle unless file is busy and
1540 * source Note that cross directory moves do not work with
1541 * rename by filehandle to various Windows servers.
1542 */
1543 if (rc == 0 || rc != -ETXTBSY)
Jeff Layton7ffec372010-09-29 19:51:11 -04001544 goto do_rename_exit;
Steve Frenchee2fd962008-09-23 18:23:33 +00001545
Jeff Laytoned0e3ac2010-06-01 16:21:01 -04001546 /* open-file renames don't work across directories */
1547 if (to_dentry->d_parent != from_dentry->d_parent)
Jeff Layton7ffec372010-09-29 19:51:11 -04001548 goto do_rename_exit;
Jeff Laytoned0e3ac2010-06-01 16:21:01 -04001549
Steve Frenchee2fd962008-09-23 18:23:33 +00001550 /* open the file to be renamed -- we need DELETE perms */
1551 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
1552 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1553 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1554 CIFS_MOUNT_MAP_SPECIAL_CHR);
1555
1556 if (rc == 0) {
1557 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
1558 (const char *) to_dentry->d_name.name,
1559 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1560 CIFS_MOUNT_MAP_SPECIAL_CHR);
1561
1562 CIFSSMBClose(xid, pTcon, srcfid);
1563 }
Jeff Layton7ffec372010-09-29 19:51:11 -04001564do_rename_exit:
1565 cifs_put_tlink(tlink);
Steve Frenchee2fd962008-09-23 18:23:33 +00001566 return rc;
1567}
1568
Jeff Layton14121bd2008-10-20 14:45:22 -04001569int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1570 struct inode *target_dir, struct dentry *target_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571{
Steve Frenchee2fd962008-09-23 18:23:33 +00001572 char *fromName = NULL;
1573 char *toName = NULL;
Jeff Layton639e7a92010-09-03 11:50:09 -04001574 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001575 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001576 struct cifs_tcon *tcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001577 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1578 FILE_UNIX_BASIC_INFO *info_buf_target;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001579 int xid, rc, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
Jeff Layton639e7a92010-09-03 11:50:09 -04001581 cifs_sb = CIFS_SB(source_dir->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001582 tlink = cifs_sb_tlink(cifs_sb);
1583 if (IS_ERR(tlink))
1584 return PTR_ERR(tlink);
1585 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Steve Frenchee2fd962008-09-23 18:23:33 +00001587 xid = GetXid();
1588
1589 /*
Steve Frenchee2fd962008-09-23 18:23:33 +00001590 * we already have the rename sem so we do not need to
1591 * grab it again here to protect the path integrity
1592 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001593 fromName = build_path_from_dentry(source_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001594 if (fromName == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 rc = -ENOMEM;
1596 goto cifs_rename_exit;
1597 }
1598
Jeff Layton14121bd2008-10-20 14:45:22 -04001599 toName = build_path_from_dentry(target_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001600 if (toName == NULL) {
1601 rc = -ENOMEM;
1602 goto cifs_rename_exit;
1603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Jeff Layton14121bd2008-10-20 14:45:22 -04001605 rc = cifs_do_rename(xid, source_dentry, fromName,
1606 target_dentry, toName);
Steve Frenchee2fd962008-09-23 18:23:33 +00001607
Jeff Layton14121bd2008-10-20 14:45:22 -04001608 if (rc == -EEXIST && tcon->unix_ext) {
Steve Frenchee2fd962008-09-23 18:23:33 +00001609 /*
Jeff Layton14121bd2008-10-20 14:45:22 -04001610 * Are src and dst hardlinks of same inode? We can
1611 * only tell with unix extensions enabled
Steve Frenchee2fd962008-09-23 18:23:33 +00001612 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001613 info_buf_source =
1614 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1615 GFP_KERNEL);
1616 if (info_buf_source == NULL) {
1617 rc = -ENOMEM;
1618 goto cifs_rename_exit;
1619 }
1620
1621 info_buf_target = info_buf_source + 1;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001622 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
Jeff Layton14121bd2008-10-20 14:45:22 -04001623 info_buf_source,
Jeff Layton639e7a92010-09-03 11:50:09 -04001624 cifs_sb->local_nls,
1625 cifs_sb->mnt_cifs_flags &
Jeff Layton14121bd2008-10-20 14:45:22 -04001626 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton8d281ef2008-10-22 13:57:01 -04001627 if (tmprc != 0)
Jeff Layton14121bd2008-10-20 14:45:22 -04001628 goto unlink_target;
1629
Jeff Layton639e7a92010-09-03 11:50:09 -04001630 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
1631 info_buf_target,
1632 cifs_sb->local_nls,
1633 cifs_sb->mnt_cifs_flags &
Jeff Layton14121bd2008-10-20 14:45:22 -04001634 CIFS_MOUNT_MAP_SPECIAL_CHR);
1635
Jeff Layton8d281ef2008-10-22 13:57:01 -04001636 if (tmprc == 0 && (info_buf_source->UniqueId ==
Jeff Laytonae6884a2008-11-03 14:05:08 -05001637 info_buf_target->UniqueId)) {
Jeff Layton14121bd2008-10-20 14:45:22 -04001638 /* same file, POSIX says that this is a noop */
Jeff Laytonae6884a2008-11-03 14:05:08 -05001639 rc = 0;
Jeff Layton14121bd2008-10-20 14:45:22 -04001640 goto cifs_rename_exit;
Jeff Laytonae6884a2008-11-03 14:05:08 -05001641 }
Jeff Layton14121bd2008-10-20 14:45:22 -04001642 } /* else ... BB we could add the same check for Windows by
1643 checking the UniqueId via FILE_INTERNAL_INFO */
1644
Jeff Layton14121bd2008-10-20 14:45:22 -04001645unlink_target:
Jeff Laytonfc6f3942009-04-17 11:45:30 -04001646 /* Try unlinking the target dentry if it's not negative */
1647 if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
Jeff Layton8d281ef2008-10-22 13:57:01 -04001648 tmprc = cifs_unlink(target_dir, target_dentry);
Jeff Layton14121bd2008-10-20 14:45:22 -04001649 if (tmprc)
1650 goto cifs_rename_exit;
1651
Jeff Layton14121bd2008-10-20 14:45:22 -04001652 rc = cifs_do_rename(xid, source_dentry, fromName,
1653 target_dentry, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 }
1655
Pavel Shilovskyd06e4b02014-08-18 20:49:58 +04001656 /* force revalidate to go get info when needed */
1657 CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
1658
1659 source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime =
1660 target_dir->i_mtime = current_fs_time(source_dir->i_sb);
1661
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662cifs_rename_exit:
Steve Frenchee2fd962008-09-23 18:23:33 +00001663 kfree(info_buf_source);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 kfree(fromName);
1665 kfree(toName);
1666 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001667 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 return rc;
1669}
1670
Jeff Laytondf2cf172010-02-12 07:44:16 -05001671static bool
1672cifs_inode_needs_reval(struct inode *inode)
1673{
1674 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301675 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytondf2cf172010-02-12 07:44:16 -05001676
1677 if (cifs_i->clientCanCacheRead)
1678 return false;
1679
1680 if (!lookupCacheEnabled)
1681 return true;
1682
1683 if (cifs_i->time == 0)
1684 return true;
1685
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301686 if (!time_in_range(jiffies, cifs_i->time,
1687 cifs_i->time + cifs_sb->actimeo))
Jeff Laytondf2cf172010-02-12 07:44:16 -05001688 return true;
1689
Jeff Laytondb192722010-05-17 14:51:49 -04001690 /* hardlinked files w/ noserverino get "special" treatment */
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301691 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
Jeff Laytondb192722010-05-17 14:51:49 -04001692 S_ISREG(inode->i_mode) && inode->i_nlink != 1)
1693 return true;
1694
Jeff Laytondf2cf172010-02-12 07:44:16 -05001695 return false;
1696}
1697
Suresh Jayaraman523fb8c2010-11-29 22:39:47 +05301698/*
1699 * Zap the cache. Called when invalid_mapping flag is set.
1700 */
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001701int
Jeff Laytondf2cf172010-02-12 07:44:16 -05001702cifs_invalidate_mapping(struct inode *inode)
1703{
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001704 int rc = 0;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001705 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1706
1707 cifs_i->invalid_mapping = false;
1708
Jeff Laytondf2cf172010-02-12 07:44:16 -05001709 if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
Pavel Shilovsky257fb1f2011-03-16 01:55:32 +03001710 rc = invalidate_inode_pages2(inode->i_mapping);
1711 if (rc) {
1712 cERROR(1, "%s: could not invalidate inode %p", __func__,
1713 inode);
1714 cifs_i->invalid_mapping = true;
1715 }
Jeff Laytondf2cf172010-02-12 07:44:16 -05001716 }
Pavel Shilovsky257fb1f2011-03-16 01:55:32 +03001717
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +05301718 cifs_fscache_reset_inode_cookie(inode);
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001719 return rc;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001720}
1721
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001722int cifs_revalidate_file_attr(struct file *filp)
Jeff Laytonabab0952010-02-12 07:44:18 -05001723{
1724 int rc = 0;
1725 struct inode *inode = filp->f_path.dentry->d_inode;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001726 struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
Jeff Laytonabab0952010-02-12 07:44:18 -05001727
1728 if (!cifs_inode_needs_reval(inode))
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001729 return rc;
Jeff Laytonabab0952010-02-12 07:44:18 -05001730
Jeff Layton13cfb732010-09-29 19:51:11 -04001731 if (tlink_tcon(cfile->tlink)->unix_ext)
Jeff Laytonabab0952010-02-12 07:44:18 -05001732 rc = cifs_get_file_info_unix(filp);
1733 else
1734 rc = cifs_get_file_info(filp);
1735
Jeff Laytonabab0952010-02-12 07:44:18 -05001736 return rc;
1737}
1738
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001739int cifs_revalidate_dentry_attr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740{
1741 int xid;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001742 int rc = 0;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001743 struct inode *inode = dentry->d_inode;
1744 struct super_block *sb = dentry->d_sb;
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001745 char *full_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
Jeff Laytondf2cf172010-02-12 07:44:16 -05001747 if (inode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 return -ENOENT;
1749
Jeff Laytondf2cf172010-02-12 07:44:16 -05001750 if (!cifs_inode_needs_reval(inode))
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001751 return rc;
1752
1753 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
1755 /* can not safely grab the rename sem here if rename calls revalidate
1756 since that would deadlock */
Jeff Laytondf2cf172010-02-12 07:44:16 -05001757 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301759 rc = -ENOMEM;
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001760 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 }
Jeff Laytondf2cf172010-02-12 07:44:16 -05001762
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001763 cFYI(1, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time "
1764 "%ld jiffies %ld", full_path, inode, inode->i_count.counter,
Steve Frenchf19159d2010-04-21 04:12:10 +00001765 dentry, dentry->d_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
Jeff Layton0d424ad2010-09-20 16:01:35 -07001767 if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
Jeff Laytondf2cf172010-02-12 07:44:16 -05001768 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
1769 else
1770 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
1771 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001773out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 kfree(full_path);
1775 FreeXid(xid);
1776 return rc;
1777}
1778
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001779int cifs_revalidate_file(struct file *filp)
1780{
1781 int rc;
1782 struct inode *inode = filp->f_path.dentry->d_inode;
1783
1784 rc = cifs_revalidate_file_attr(filp);
1785 if (rc)
1786 return rc;
1787
1788 if (CIFS_I(inode)->invalid_mapping)
1789 rc = cifs_invalidate_mapping(inode);
1790 return rc;
1791}
1792
1793/* revalidate a dentry's inode attributes */
1794int cifs_revalidate_dentry(struct dentry *dentry)
1795{
1796 int rc;
1797 struct inode *inode = dentry->d_inode;
1798
1799 rc = cifs_revalidate_dentry_attr(dentry);
1800 if (rc)
1801 return rc;
1802
1803 if (CIFS_I(inode)->invalid_mapping)
1804 rc = cifs_invalidate_mapping(inode);
1805 return rc;
1806}
1807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
Jeff Layton1c456012010-10-12 11:32:42 -04001809 struct kstat *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810{
Jeff Layton3aa1c8c2010-10-07 14:46:28 -04001811 struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
Steve French96daf2b2011-05-27 04:34:02 +00001812 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001813 struct inode *inode = dentry->d_inode;
1814 int rc;
Jeff Layton3aa1c8c2010-10-07 14:46:28 -04001815
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001816 /*
1817 * We need to be sure that all dirty pages are written and the server
1818 * has actual ctime, mtime and file length.
1819 */
1820 if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
1821 inode->i_mapping->nrpages != 0) {
1822 rc = filemap_fdatawait(inode->i_mapping);
Steve French156ecb22011-05-20 17:00:01 +00001823 if (rc) {
1824 mapping_set_error(inode->i_mapping, rc);
1825 return rc;
1826 }
Steve French5fe14c82006-11-07 19:26:33 +00001827 }
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001828
1829 rc = cifs_revalidate_dentry_attr(dentry);
1830 if (rc)
1831 return rc;
1832
1833 generic_fillattr(inode, stat);
1834 stat->blksize = CIFS_MAX_MSGSIZE;
1835 stat->ino = CIFS_I(inode)->uniqueid;
1836
1837 /*
1838 * If on a multiuser mount without unix extensions, and the admin hasn't
1839 * overridden them, set the ownership to the fsuid/fsgid of the current
1840 * process.
1841 */
1842 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
1843 !tcon->unix_ext) {
1844 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
1845 stat->uid = current_fsuid();
1846 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
1847 stat->gid = current_fsgid();
1848 }
1849 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850}
1851
1852static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1853{
1854 pgoff_t index = from >> PAGE_CACHE_SHIFT;
1855 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1856 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 int rc = 0;
1858
1859 page = grab_cache_page(mapping, index);
1860 if (!page)
1861 return -ENOMEM;
1862
Christoph Lametereebd2aa2008-02-04 22:28:29 -08001863 zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 unlock_page(page);
1865 page_cache_release(page);
1866 return rc;
1867}
1868
Christoph Hellwig1b947462010-07-18 17:51:21 -04001869static void cifs_setsize(struct inode *inode, loff_t offset)
Steve French3677db12007-02-26 16:46:11 +00001870{
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001871 loff_t oldsize;
Steve French3677db12007-02-26 16:46:11 +00001872
Steve Frenchba6a46a2007-02-26 20:06:29 +00001873 spin_lock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001874 oldsize = inode->i_size;
Steve French3677db12007-02-26 16:46:11 +00001875 i_size_write(inode, offset);
Steve Frenchba6a46a2007-02-26 20:06:29 +00001876 spin_unlock(&inode->i_lock);
Christoph Hellwig1b947462010-07-18 17:51:21 -04001877
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001878 truncate_pagecache(inode, oldsize, offset);
Steve French3677db12007-02-26 16:46:11 +00001879}
1880
Jeff Layton8efdbde2008-07-23 21:28:12 +00001881static int
1882cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1883 int xid, char *full_path)
1884{
1885 int rc;
1886 struct cifsFileInfo *open_file;
1887 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1888 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001889 struct tcon_link *tlink = NULL;
Steve French96daf2b2011-05-27 04:34:02 +00001890 struct cifs_tcon *pTcon = NULL;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001891 struct cifs_io_parms io_parms;
Jeff Layton8efdbde2008-07-23 21:28:12 +00001892
1893 /*
1894 * To avoid spurious oplock breaks from server, in the case of
1895 * inodes that we already have open, avoid doing path based
1896 * setting of file size if we can do it by handle.
1897 * This keeps our caching token (oplock) and avoids timeouts
1898 * when the local oplock break takes longer to flush
1899 * writebehind data than the SMB timeout for the SetPathInfo
1900 * request would allow
1901 */
Jeff Layton6508d902010-09-29 19:51:11 -04001902 open_file = find_writable_file(cifsInode, true);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001903 if (open_file) {
1904 __u16 nfid = open_file->netfid;
1905 __u32 npid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -04001906 pTcon = tlink_tcon(open_file->tlink);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001907 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
1908 npid, false);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001909 cifsFileInfo_put(open_file);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001910 cFYI(1, "SetFSize for attrs rc = %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001911 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1912 unsigned int bytes_written;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001913
1914 io_parms.netfid = nfid;
1915 io_parms.pid = npid;
1916 io_parms.tcon = pTcon;
1917 io_parms.offset = 0;
1918 io_parms.length = attrs->ia_size;
1919 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
1920 NULL, NULL, 1);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001921 cFYI(1, "Wrt seteof rc %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001922 }
1923 } else
1924 rc = -EINVAL;
1925
1926 if (rc != 0) {
Jeff Layton7ffec372010-09-29 19:51:11 -04001927 if (pTcon == NULL) {
1928 tlink = cifs_sb_tlink(cifs_sb);
1929 if (IS_ERR(tlink))
1930 return PTR_ERR(tlink);
1931 pTcon = tlink_tcon(tlink);
1932 }
Jeff Laytonba00ba62010-09-20 16:01:31 -07001933
Jeff Layton8efdbde2008-07-23 21:28:12 +00001934 /* Set file size by pathname rather than by handle
1935 either because no valid, writeable file handle for
1936 it was found or because there was an error setting
1937 it by handle */
1938 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
1939 false, cifs_sb->local_nls,
1940 cifs_sb->mnt_cifs_flags &
1941 CIFS_MOUNT_MAP_SPECIAL_CHR);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001942 cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001943 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1944 __u16 netfid;
1945 int oplock = 0;
1946
1947 rc = SMBLegacyOpen(xid, pTcon, full_path,
1948 FILE_OPEN, GENERIC_WRITE,
1949 CREATE_NOT_DIR, &netfid, &oplock, NULL,
1950 cifs_sb->local_nls,
1951 cifs_sb->mnt_cifs_flags &
1952 CIFS_MOUNT_MAP_SPECIAL_CHR);
1953 if (rc == 0) {
1954 unsigned int bytes_written;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001955
1956 io_parms.netfid = netfid;
1957 io_parms.pid = current->tgid;
1958 io_parms.tcon = pTcon;
1959 io_parms.offset = 0;
1960 io_parms.length = attrs->ia_size;
1961 rc = CIFSSMBWrite(xid, &io_parms,
1962 &bytes_written,
1963 NULL, NULL, 1);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001964 cFYI(1, "wrt seteof rc %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001965 CIFSSMBClose(xid, pTcon, netfid);
1966 }
1967 }
Jeff Layton7ffec372010-09-29 19:51:11 -04001968 if (tlink)
1969 cifs_put_tlink(tlink);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001970 }
1971
1972 if (rc == 0) {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001973 cifsInode->server_eof = attrs->ia_size;
Christoph Hellwig1b947462010-07-18 17:51:21 -04001974 cifs_setsize(inode, attrs->ia_size);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001975 cifs_truncate_page(inode->i_mapping, inode->i_size);
1976 }
1977
1978 return rc;
1979}
1980
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001981static int
1982cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1983{
1984 int rc;
1985 int xid;
1986 char *full_path = NULL;
1987 struct inode *inode = direntry->d_inode;
1988 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1989 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001990 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001991 struct cifs_tcon *pTcon;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001992 struct cifs_unix_set_info_args *args = NULL;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001993 struct cifsFileInfo *open_file;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001994
Joe Perchesb6b38f72010-04-21 03:50:45 +00001995 cFYI(1, "setattr_unix on file %s attrs->ia_valid=0x%x",
1996 direntry->d_name.name, attrs->ia_valid);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001997
1998 xid = GetXid();
1999
Christoph Hellwigdb78b872010-06-04 11:30:03 +02002000 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
2001 attrs->ia_valid |= ATTR_FORCE;
2002
2003 rc = inode_change_ok(inode, attrs);
2004 if (rc < 0)
2005 goto out;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002006
2007 full_path = build_path_from_dentry(direntry);
2008 if (full_path == NULL) {
2009 rc = -ENOMEM;
2010 goto out;
2011 }
2012
Jeff Layton0f4d6342009-03-26 13:35:37 -04002013 /*
2014 * Attempt to flush data before changing attributes. We need to do
2015 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
2016 * ownership or mode then we may also need to do this. Here, we take
2017 * the safe way out and just do the flush on all setattr requests. If
2018 * the flush returns error, store it to report later and continue.
2019 *
2020 * BB: This should be smarter. Why bother flushing pages that
2021 * will be truncated anyway? Also, should we error out here if
2022 * the flush returns error?
2023 */
2024 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002025 mapping_set_error(inode->i_mapping, rc);
2026 rc = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002027
2028 if (attrs->ia_valid & ATTR_SIZE) {
2029 rc = cifs_set_file_size(inode, attrs, xid, full_path);
2030 if (rc != 0)
2031 goto out;
2032 }
2033
2034 /* skip mode change if it's just for clearing setuid/setgid */
2035 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
2036 attrs->ia_valid &= ~ATTR_MODE;
2037
2038 args = kmalloc(sizeof(*args), GFP_KERNEL);
2039 if (args == NULL) {
2040 rc = -ENOMEM;
2041 goto out;
2042 }
2043
2044 /* set up the struct */
2045 if (attrs->ia_valid & ATTR_MODE)
2046 args->mode = attrs->ia_mode;
2047 else
2048 args->mode = NO_CHANGE_64;
2049
2050 if (attrs->ia_valid & ATTR_UID)
2051 args->uid = attrs->ia_uid;
2052 else
2053 args->uid = NO_CHANGE_64;
2054
2055 if (attrs->ia_valid & ATTR_GID)
2056 args->gid = attrs->ia_gid;
2057 else
2058 args->gid = NO_CHANGE_64;
2059
2060 if (attrs->ia_valid & ATTR_ATIME)
2061 args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
2062 else
2063 args->atime = NO_CHANGE_64;
2064
2065 if (attrs->ia_valid & ATTR_MTIME)
2066 args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
2067 else
2068 args->mtime = NO_CHANGE_64;
2069
2070 if (attrs->ia_valid & ATTR_CTIME)
2071 args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
2072 else
2073 args->ctime = NO_CHANGE_64;
2074
2075 args->device = 0;
Jeff Layton6508d902010-09-29 19:51:11 -04002076 open_file = find_writable_file(cifsInode, true);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002077 if (open_file) {
2078 u16 nfid = open_file->netfid;
2079 u32 npid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -04002080 pTcon = tlink_tcon(open_file->tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002081 rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04002082 cifsFileInfo_put(open_file);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002083 } else {
Jeff Layton7ffec372010-09-29 19:51:11 -04002084 tlink = cifs_sb_tlink(cifs_sb);
2085 if (IS_ERR(tlink)) {
2086 rc = PTR_ERR(tlink);
2087 goto out;
2088 }
2089 pTcon = tlink_tcon(tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002090 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
Jeff Layton01ea95e2009-07-09 20:02:49 -04002091 cifs_sb->local_nls,
2092 cifs_sb->mnt_cifs_flags &
2093 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -04002094 cifs_put_tlink(tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002095 }
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002096
Christoph Hellwig10257742010-06-04 11:30:02 +02002097 if (rc)
2098 goto out;
Steve Frenchccd4bb12010-02-08 17:39:58 +00002099
Christoph Hellwig10257742010-06-04 11:30:02 +02002100 if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig1b947462010-07-18 17:51:21 -04002101 attrs->ia_size != i_size_read(inode))
2102 truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02002103
2104 setattr_copy(inode, attrs);
2105 mark_inode_dirty(inode);
2106
2107 /* force revalidate when any of these times are set since some
2108 of the fs types (eg ext3, fat) do not have fine enough
2109 time granularity to match protocol, and we do not have a
2110 a way (yet) to query the server fs's time granularity (and
2111 whether it rounds times down).
2112 */
2113 if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
2114 cifsInode->time = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002115out:
2116 kfree(args);
2117 kfree(full_path);
2118 FreeXid(xid);
2119 return rc;
2120}
2121
Jeff Layton0510eeb2008-08-02 07:26:12 -04002122static int
2123cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124{
2125 int xid;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002126 uid_t uid = NO_CHANGE_32;
2127 gid_t gid = NO_CHANGE_32;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002128 struct inode *inode = direntry->d_inode;
2129 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002130 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 char *full_path = NULL;
2132 int rc = -EACCES;
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002133 __u32 dosattr = 0;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04002134 __u64 mode = NO_CHANGE_64;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002135
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 xid = GetXid();
2137
Joe Perchesb6b38f72010-04-21 03:50:45 +00002138 cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
2139 direntry->d_name.name, attrs->ia_valid);
Steve French6473a552005-11-29 20:20:10 -08002140
Christoph Hellwigdb78b872010-06-04 11:30:03 +02002141 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
2142 attrs->ia_valid |= ATTR_FORCE;
2143
2144 rc = inode_change_ok(inode, attrs);
2145 if (rc < 0) {
2146 FreeXid(xid);
2147 return rc;
Steve French6473a552005-11-29 20:20:10 -08002148 }
Steve French50c2f752007-07-13 00:33:32 +00002149
Steve French7f573562005-08-30 11:32:14 -07002150 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302152 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302154 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
Jeff Layton0f4d6342009-03-26 13:35:37 -04002157 /*
2158 * Attempt to flush data before changing attributes. We need to do
2159 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
2160 * ownership or mode then we may also need to do this. Here, we take
2161 * the safe way out and just do the flush on all setattr requests. If
2162 * the flush returns error, store it to report later and continue.
2163 *
2164 * BB: This should be smarter. Why bother flushing pages that
2165 * will be truncated anyway? Also, should we error out here if
2166 * the flush returns error?
2167 */
2168 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002169 mapping_set_error(inode->i_mapping, rc);
2170 rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00002171
Steve French50531442008-03-14 19:21:31 +00002172 if (attrs->ia_valid & ATTR_SIZE) {
Jeff Layton8efdbde2008-07-23 21:28:12 +00002173 rc = cifs_set_file_size(inode, attrs, xid, full_path);
2174 if (rc != 0)
Steve Frenche30dcf32005-09-20 20:49:16 -07002175 goto cifs_setattr_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 }
Jeff Layton4ca691a2008-05-22 09:33:34 -04002177
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002178 if (attrs->ia_valid & ATTR_UID)
2179 uid = attrs->ia_uid;
2180
2181 if (attrs->ia_valid & ATTR_GID)
2182 gid = attrs->ia_gid;
2183
2184#ifdef CONFIG_CIFS_ACL
2185 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2186 if (uid != NO_CHANGE_32 || gid != NO_CHANGE_32) {
2187 rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
2188 uid, gid);
2189 if (rc) {
2190 cFYI(1, "%s: Setting id failed with error: %d",
2191 __func__, rc);
2192 goto cifs_setattr_exit;
2193 }
2194 }
2195 } else
2196#endif /* CONFIG_CIFS_ACL */
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002197 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
Jeff Layton4ca691a2008-05-22 09:33:34 -04002198 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Jeff Laytond32c4f22007-10-18 03:05:22 -07002200 /* skip mode change if it's just for clearing setuid/setgid */
2201 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
2202 attrs->ia_valid &= ~ATTR_MODE;
2203
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 if (attrs->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 mode = attrs->ia_mode;
Steve Frenchcdbce9c2005-11-19 21:04:52 -08002206 rc = 0;
Jeff Layton79df1ba2010-12-06 12:52:08 -05002207#ifdef CONFIG_CIFS_ACL
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06002208 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002209 rc = id_mode_to_cifs_acl(inode, full_path, mode,
2210 NO_CHANGE_32, NO_CHANGE_32);
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06002211 if (rc) {
2212 cFYI(1, "%s: Setting ACL failed with error: %d",
2213 __func__, rc);
2214 goto cifs_setattr_exit;
2215 }
2216 } else
Jeff Layton79df1ba2010-12-06 12:52:08 -05002217#endif /* CONFIG_CIFS_ACL */
Jeff Layton51328612008-05-22 09:33:34 -04002218 if (((mode & S_IWUGO) == 0) &&
2219 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002220
2221 dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
2222
Jeff Layton51328612008-05-22 09:33:34 -04002223 /* fix up mode if we're not using dynperm */
2224 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
2225 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
2226 } else if ((mode & S_IWUGO) &&
2227 (cifsInode->cifsAttrs & ATTR_READONLY)) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002228
2229 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
2230 /* Attributes of 0 are ignored */
2231 if (dosattr == 0)
2232 dosattr |= ATTR_NORMAL;
Jeff Layton51328612008-05-22 09:33:34 -04002233
2234 /* reset local inode permissions to normal */
2235 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
2236 attrs->ia_mode &= ~(S_IALLUGO);
2237 if (S_ISDIR(inode->i_mode))
2238 attrs->ia_mode |=
2239 cifs_sb->mnt_dir_mode;
2240 else
2241 attrs->ia_mode |=
2242 cifs_sb->mnt_file_mode;
2243 }
2244 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
2245 /* ignore mode change - ATTR_READONLY hasn't changed */
2246 attrs->ia_valid &= ~ATTR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 }
2249
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002250 if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
2251 ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
2252 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
2253 /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
Steve Frenche30dcf32005-09-20 20:49:16 -07002255 /* Even if error on time set, no sense failing the call if
2256 the server would set the time to a reasonable value anyway,
2257 and this check ensures that we are not being called from
2258 sys_utimes in which case we ought to fail the call back to
2259 the user when the server rejects the call */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002260 if ((rc) && (attrs->ia_valid &
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002261 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
Steve Frenche30dcf32005-09-20 20:49:16 -07002262 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 }
2264
2265 /* do not need local check to inode_check_ok since the server does
2266 that */
Christoph Hellwig10257742010-06-04 11:30:02 +02002267 if (rc)
2268 goto cifs_setattr_exit;
2269
2270 if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig1b947462010-07-18 17:51:21 -04002271 attrs->ia_size != i_size_read(inode))
2272 truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02002273
2274 setattr_copy(inode, attrs);
2275 mark_inode_dirty(inode);
Christoph Hellwig10257742010-06-04 11:30:02 +02002276
Steve Frenche30dcf32005-09-20 20:49:16 -07002277cifs_setattr_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 kfree(full_path);
2279 FreeXid(xid);
2280 return rc;
2281}
2282
Jeff Layton0510eeb2008-08-02 07:26:12 -04002283int
2284cifs_setattr(struct dentry *direntry, struct iattr *attrs)
2285{
2286 struct inode *inode = direntry->d_inode;
2287 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Steve French96daf2b2011-05-27 04:34:02 +00002288 struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
Jeff Layton0510eeb2008-08-02 07:26:12 -04002289
2290 if (pTcon->unix_ext)
2291 return cifs_setattr_unix(direntry, attrs);
2292
2293 return cifs_setattr_nounix(direntry, attrs);
2294
2295 /* BB: add cifs_setattr_legacy for really old servers */
2296}
2297
Steve French99ee4db2007-02-27 05:35:17 +00002298#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299void cifs_delete_inode(struct inode *inode)
2300{
Joe Perchesb6b38f72010-04-21 03:50:45 +00002301 cFYI(1, "In cifs_delete_inode, inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 /* may have to add back in if and when safe distributed caching of
2303 directories added e.g. via FindNotify */
2304}
Steve French99ee4db2007-02-27 05:35:17 +00002305#endif