blob: dce2d598927e815fd0d0aa61e313c3148a0964ac [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
Igor Mammedov79626702008-03-09 03:44:18 +000035static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
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;
47 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
48 inode->i_fop = &cifs_file_nobrl_ops;
49 else { /* not direct, send byte range locks */
50 inode->i_fop = &cifs_file_ops;
51 }
52
53
54 /* check if server can support readpages */
Jeff Laytona6e8a842010-09-20 16:01:33 -070055 if (cifs_sb_tcon(cifs_sb)->ses->server->maxBuf <
Christoph Hellwig70eff552008-02-15 20:55:05 +000056 PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
57 inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
58 else
59 inode->i_data.a_ops = &cifs_addr_ops;
60 break;
61 case S_IFDIR:
Steve Frenchbc5b6e22008-03-11 21:07:48 +000062#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov79626702008-03-09 03:44:18 +000063 if (is_dfs_referral) {
64 inode->i_op = &cifs_dfs_referral_inode_operations;
65 } else {
Steve Frenchbc5b6e22008-03-11 21:07:48 +000066#else /* NO DFS support, treat as a directory */
67 {
68#endif
Igor Mammedov79626702008-03-09 03:44:18 +000069 inode->i_op = &cifs_dir_inode_ops;
70 inode->i_fop = &cifs_dir_ops;
71 }
Christoph Hellwig70eff552008-02-15 20:55:05 +000072 break;
73 case S_IFLNK:
74 inode->i_op = &cifs_symlink_inode_ops;
75 break;
76 default:
77 init_special_inode(inode, inode->i_mode, inode->i_rdev);
78 break;
79 }
80}
81
Jeff Laytondf2cf172010-02-12 07:44:16 -050082/* check inode attributes against fattr. If they don't match, tag the
83 * inode for cache invalidation
84 */
85static void
86cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
87{
88 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
89
Steve Frenchf19159d2010-04-21 04:12:10 +000090 cFYI(1, "%s: revalidating inode %llu", __func__, cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -050091
92 if (inode->i_state & I_NEW) {
Steve Frenchf19159d2010-04-21 04:12:10 +000093 cFYI(1, "%s: inode %llu is new", __func__, cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -050094 return;
95 }
96
97 /* don't bother with revalidation if we have an oplock */
98 if (cifs_i->clientCanCacheRead) {
Steve Frenchf19159d2010-04-21 04:12:10 +000099 cFYI(1, "%s: inode %llu is oplocked", __func__,
100 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500101 return;
102 }
103
104 /* revalidate if mtime or size have changed */
105 if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) &&
106 cifs_i->server_eof == fattr->cf_eof) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000107 cFYI(1, "%s: inode %llu is unchanged", __func__,
108 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500109 return;
110 }
111
Steve Frenchf19159d2010-04-21 04:12:10 +0000112 cFYI(1, "%s: invalidating inode %llu mapping", __func__,
113 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500114 cifs_i->invalid_mapping = true;
115}
116
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400117/* populate an inode with info from a cifs_fattr struct */
118void
119cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
Christoph Hellwig75f12982008-02-25 20:25:21 +0000120{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400121 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400122 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
123 unsigned long oldtime = cifs_i->time;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000124
Jeff Laytondf2cf172010-02-12 07:44:16 -0500125 cifs_revalidate_cache(inode, fattr);
126
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400127 inode->i_atime = fattr->cf_atime;
128 inode->i_mtime = fattr->cf_mtime;
129 inode->i_ctime = fattr->cf_ctime;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400130 inode->i_rdev = fattr->cf_rdev;
131 inode->i_nlink = fattr->cf_nlink;
132 inode->i_uid = fattr->cf_uid;
133 inode->i_gid = fattr->cf_gid;
134
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400135 /* if dynperm is set, don't clobber existing mode */
136 if (inode->i_state & I_NEW ||
137 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
138 inode->i_mode = fattr->cf_mode;
139
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400140 cifs_i->cifsAttrs = fattr->cf_cifsattrs;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400141
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400142 if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
143 cifs_i->time = 0;
144 else
145 cifs_i->time = jiffies;
146
Joe Perchesb6b38f72010-04-21 03:50:45 +0000147 cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode,
148 oldtime, cifs_i->time);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400149
150 cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000151
Jeff Layton835a36c2010-02-10 16:21:33 -0500152 cifs_i->server_eof = fattr->cf_eof;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000153 /*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400154 * Can't safely change the file size here if the client is writing to
155 * it due to potential races.
Christoph Hellwig75f12982008-02-25 20:25:21 +0000156 */
Christoph Hellwig75f12982008-02-25 20:25:21 +0000157 spin_lock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400158 if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
159 i_size_write(inode, fattr->cf_eof);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000160
161 /*
162 * i_blocks is not related to (i_size / i_blksize),
163 * but instead 512 byte (2**9) size is required for
164 * calculating num blocks.
165 */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400166 inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000167 }
168 spin_unlock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400169
170 cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000171}
172
Jeff Layton4065c802010-05-17 07:18:58 -0400173void
174cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr)
175{
176 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
177
178 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
179 return;
180
181 fattr->cf_uniqueid = iunique(sb, ROOT_I);
182}
183
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400184/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
185void
186cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
187 struct cifs_sb_info *cifs_sb)
188{
189 memset(fattr, 0, sizeof(*fattr));
190 fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
191 fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
192 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
193
194 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
195 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
196 fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
197 fattr->cf_mode = le64_to_cpu(info->Permissions);
198
199 /*
200 * Since we set the inode type below we need to mask off
201 * to avoid strange results if bits set above.
202 */
203 fattr->cf_mode &= ~S_IFMT;
204 switch (le32_to_cpu(info->Type)) {
205 case UNIX_FILE:
206 fattr->cf_mode |= S_IFREG;
207 fattr->cf_dtype = DT_REG;
208 break;
209 case UNIX_SYMLINK:
210 fattr->cf_mode |= S_IFLNK;
211 fattr->cf_dtype = DT_LNK;
212 break;
213 case UNIX_DIR:
214 fattr->cf_mode |= S_IFDIR;
215 fattr->cf_dtype = DT_DIR;
216 break;
217 case UNIX_CHARDEV:
218 fattr->cf_mode |= S_IFCHR;
219 fattr->cf_dtype = DT_CHR;
220 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
221 le64_to_cpu(info->DevMinor) & MINORMASK);
222 break;
223 case UNIX_BLOCKDEV:
224 fattr->cf_mode |= S_IFBLK;
225 fattr->cf_dtype = DT_BLK;
226 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
227 le64_to_cpu(info->DevMinor) & MINORMASK);
228 break;
229 case UNIX_FIFO:
230 fattr->cf_mode |= S_IFIFO;
231 fattr->cf_dtype = DT_FIFO;
232 break;
233 case UNIX_SOCKET:
234 fattr->cf_mode |= S_IFSOCK;
235 fattr->cf_dtype = DT_SOCK;
236 break;
237 default:
238 /* safest to call it a file if we do not know */
239 fattr->cf_mode |= S_IFREG;
240 fattr->cf_dtype = DT_REG;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000241 cFYI(1, "unknown type %d", le32_to_cpu(info->Type));
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400242 break;
243 }
244
245 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
246 fattr->cf_uid = cifs_sb->mnt_uid;
247 else
248 fattr->cf_uid = le64_to_cpu(info->Uid);
249
250 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
251 fattr->cf_gid = cifs_sb->mnt_gid;
252 else
253 fattr->cf_gid = le64_to_cpu(info->Gid);
254
255 fattr->cf_nlink = le64_to_cpu(info->Nlinks);
256}
Steve Frenchb9a32602008-05-20 21:52:32 +0000257
258/*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400259 * Fill a cifs_fattr struct with fake inode info.
260 *
261 * Needed to setup cifs_fattr data for the directory which is the
262 * junction to the new submount (ie to setup the fake directory
263 * which represents a DFS referral).
Steve Frenchb9a32602008-05-20 21:52:32 +0000264 */
Steve Frenchf1230c92009-07-22 23:13:01 +0000265static void
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400266cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
Steve French0e4bbde2008-05-20 19:50:46 +0000267{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400268 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Steve French0e4bbde2008-05-20 19:50:46 +0000269
Joe Perchesb6b38f72010-04-21 03:50:45 +0000270 cFYI(1, "creating fake fattr for DFS referral");
Steve French0e4bbde2008-05-20 19:50:46 +0000271
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400272 memset(fattr, 0, sizeof(*fattr));
273 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
274 fattr->cf_uid = cifs_sb->mnt_uid;
275 fattr->cf_gid = cifs_sb->mnt_gid;
276 fattr->cf_atime = CURRENT_TIME;
277 fattr->cf_ctime = CURRENT_TIME;
278 fattr->cf_mtime = CURRENT_TIME;
279 fattr->cf_nlink = 2;
280 fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
Steve French0e4bbde2008-05-20 19:50:46 +0000281}
282
Jeff Laytonabab0952010-02-12 07:44:18 -0500283int cifs_get_file_info_unix(struct file *filp)
284{
285 int rc;
286 int xid;
287 FILE_UNIX_BASIC_INFO find_data;
288 struct cifs_fattr fattr;
289 struct inode *inode = filp->f_path.dentry->d_inode;
290 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Joe Perchesc21dfb62010-07-12 13:50:14 -0700291 struct cifsFileInfo *cfile = filp->private_data;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700292 struct cifsTconInfo *tcon = cfile->tcon;
Jeff Laytonabab0952010-02-12 07:44:18 -0500293
294 xid = GetXid();
295 rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
296 if (!rc) {
297 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
298 } else if (rc == -EREMOTE) {
299 cifs_create_dfs_fattr(&fattr, inode->i_sb);
300 rc = 0;
301 }
302
303 cifs_fattr_to_inode(inode, &fattr);
304 FreeXid(xid);
305 return rc;
306}
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308int cifs_get_inode_info_unix(struct inode **pinode,
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400309 const unsigned char *full_path,
310 struct super_block *sb, int xid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400312 int rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000313 FILE_UNIX_BASIC_INFO find_data;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400314 struct cifs_fattr fattr;
315 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Jeff Laytona6e8a842010-09-20 16:01:33 -0700318 tcon = cifs_sb_tcon(cifs_sb);
319
Joe Perchesb6b38f72010-04-21 03:50:45 +0000320 cFYI(1, "Getting info on %s", full_path);
Igor Mammedov79626702008-03-09 03:44:18 +0000321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 /* could have done a find first instead but this returns more info */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400323 rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
Steve French737b7582005-04-28 22:41:06 -0700324 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
325 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400326
327 if (!rc) {
328 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
329 } else if (rc == -EREMOTE) {
330 cifs_create_dfs_fattr(&fattr, sb);
Jeff Laytone911d0c2008-07-12 13:47:59 -0700331 rc = 0;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400332 } else {
333 return rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000334 }
335
Stefan Metzmacher1b12b9c2010-08-05 21:19:56 +0200336 /* check for Minshall+French symlinks */
337 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
338 int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
339 if (tmprc)
340 cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
341 }
342
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400343 if (*pinode == NULL) {
344 /* get new inode */
Jeff Layton4065c802010-05-17 07:18:58 -0400345 cifs_fill_uniqueid(sb, &fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400346 *pinode = cifs_iget(sb, &fattr);
347 if (!*pinode)
348 rc = -ENOMEM;
349 } else {
350 /* we already have inode, update it */
351 cifs_fattr_to_inode(*pinode, &fattr);
352 }
Steve French0e4bbde2008-05-20 19:50:46 +0000353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 return rc;
355}
356
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400357static int
358cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
359 struct cifs_sb_info *cifs_sb, int xid)
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800360{
361 int rc;
Steve French4b18f2a2008-04-29 00:06:05 +0000362 int oplock = 0;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800363 __u16 netfid;
Jeff Laytona6e8a842010-09-20 16:01:33 -0700364 struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
Steve French86c96b42005-11-18 20:25:31 -0800365 char buf[24];
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800366 unsigned int bytes_read;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000367 char *pbuf;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800368
369 pbuf = buf;
370
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400371 fattr->cf_mode &= ~S_IFMT;
372
373 if (fattr->cf_eof == 0) {
374 fattr->cf_mode |= S_IFIFO;
375 fattr->cf_dtype = DT_FIFO;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800376 return 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400377 } else if (fattr->cf_eof < 8) {
378 fattr->cf_mode |= S_IFREG;
379 fattr->cf_dtype = DT_REG;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800380 return -EINVAL; /* EOPNOTSUPP? */
381 }
Steve French50c2f752007-07-13 00:33:32 +0000382
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800383 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
384 CREATE_NOT_DIR, &netfid, &oplock, NULL,
385 cifs_sb->local_nls,
386 cifs_sb->mnt_cifs_flags &
387 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000388 if (rc == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -0800389 int buf_type = CIFS_NO_BUFFER;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800390 /* Read header */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400391 rc = CIFSSMBRead(xid, pTcon, netfid,
Steve French86c96b42005-11-18 20:25:31 -0800392 24 /* length */, 0 /* offset */,
Steve Frenchec637e32005-12-12 20:53:18 -0800393 &bytes_read, &pbuf, &buf_type);
Steve French4523cc32007-04-30 20:13:06 +0000394 if ((rc == 0) && (bytes_read >= 8)) {
395 if (memcmp("IntxBLK", pbuf, 8) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000396 cFYI(1, "Block device");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400397 fattr->cf_mode |= S_IFBLK;
398 fattr->cf_dtype = DT_BLK;
Steve French4523cc32007-04-30 20:13:06 +0000399 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800400 /* we have enough to decode dev num */
401 __u64 mjr; /* major */
402 __u64 mnr; /* minor */
403 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
404 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400405 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve French86c96b42005-11-18 20:25:31 -0800406 }
Steve French4523cc32007-04-30 20:13:06 +0000407 } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000408 cFYI(1, "Char device");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400409 fattr->cf_mode |= S_IFCHR;
410 fattr->cf_dtype = DT_CHR;
Steve French4523cc32007-04-30 20:13:06 +0000411 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800412 /* we have enough to decode dev num */
413 __u64 mjr; /* major */
414 __u64 mnr; /* minor */
415 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
416 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400417 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000418 }
Steve French4523cc32007-04-30 20:13:06 +0000419 } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000420 cFYI(1, "Symlink");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400421 fattr->cf_mode |= S_IFLNK;
422 fattr->cf_dtype = DT_LNK;
Steve French86c96b42005-11-18 20:25:31 -0800423 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400424 fattr->cf_mode |= S_IFREG; /* file? */
425 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000426 rc = -EOPNOTSUPP;
Steve French86c96b42005-11-18 20:25:31 -0800427 }
Steve French3020a1f2005-11-18 11:31:10 -0800428 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400429 fattr->cf_mode |= S_IFREG; /* then it is a file */
430 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000431 rc = -EOPNOTSUPP; /* or some unknown SFU type */
432 }
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800433 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800434 }
435 return rc;
Steve Frenchd6e2f2a2005-11-15 16:43:39 -0800436}
437
Steve French9e294f12005-11-17 16:59:21 -0800438#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
439
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400440/*
441 * Fetch mode bits as provided by SFU.
442 *
443 * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
444 */
445static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
446 struct cifs_sb_info *cifs_sb, int xid)
Steve French9e294f12005-11-17 16:59:21 -0800447{
Steve French3020a1f2005-11-18 11:31:10 -0800448#ifdef CONFIG_CIFS_XATTR
Steve French9e294f12005-11-17 16:59:21 -0800449 ssize_t rc;
450 char ea_value[4];
451 __u32 mode;
452
Jeff Laytona6e8a842010-09-20 16:01:33 -0700453 rc = CIFSSMBQAllEAs(xid, cifs_sb_tcon(cifs_sb), path, "SETFILEBITS",
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400454 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
455 cifs_sb->mnt_cifs_flags &
456 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4523cc32007-04-30 20:13:06 +0000457 if (rc < 0)
Steve French9e294f12005-11-17 16:59:21 -0800458 return (int)rc;
459 else if (rc > 3) {
460 mode = le32_to_cpu(*((__le32 *)ea_value));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400461 fattr->cf_mode &= ~SFBITS_MASK;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000462 cFYI(1, "special bits 0%o org mode 0%o", mode,
463 fattr->cf_mode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400464 fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000465 cFYI(1, "special mode bits 0%o", mode);
Steve French9e294f12005-11-17 16:59:21 -0800466 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400467
468 return 0;
Steve French3020a1f2005-11-18 11:31:10 -0800469#else
470 return -EOPNOTSUPP;
471#endif
Steve French9e294f12005-11-17 16:59:21 -0800472}
473
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400474/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
Steve Frenchf1230c92009-07-22 23:13:01 +0000475static void
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400476cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
477 struct cifs_sb_info *cifs_sb, bool adjust_tz)
Steve Frenchb9a32602008-05-20 21:52:32 +0000478{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400479 memset(fattr, 0, sizeof(*fattr));
480 fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
481 if (info->DeletePending)
482 fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
Steve Frenchb9a32602008-05-20 21:52:32 +0000483
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400484 if (info->LastAccessTime)
485 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
486 else
487 fattr->cf_atime = CURRENT_TIME;
488
489 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
490 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
491
492 if (adjust_tz) {
Jeff Laytona6e8a842010-09-20 16:01:33 -0700493 fattr->cf_ctime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj;
494 fattr->cf_mtime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400495 }
496
497 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
498 fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
499
500 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
501 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
502 fattr->cf_dtype = DT_DIR;
503 } else {
504 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
505 fattr->cf_dtype = DT_REG;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400506
Jeff Laytond0c280d2009-07-09 01:46:44 -0400507 /* clear write bits if ATTR_READONLY is set */
508 if (fattr->cf_cifsattrs & ATTR_READONLY)
509 fattr->cf_mode &= ~(S_IWUGO);
510 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400511
512 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
513
514 fattr->cf_uid = cifs_sb->mnt_uid;
515 fattr->cf_gid = cifs_sb->mnt_gid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000516}
517
Jeff Laytonabab0952010-02-12 07:44:18 -0500518int cifs_get_file_info(struct file *filp)
519{
520 int rc;
521 int xid;
522 FILE_ALL_INFO find_data;
523 struct cifs_fattr fattr;
524 struct inode *inode = filp->f_path.dentry->d_inode;
525 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Joe Perchesc21dfb62010-07-12 13:50:14 -0700526 struct cifsFileInfo *cfile = filp->private_data;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700527 struct cifsTconInfo *tcon = cfile->tcon;
Jeff Laytonabab0952010-02-12 07:44:18 -0500528
529 xid = GetXid();
530 rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
531 if (rc == -EOPNOTSUPP || rc == -EINVAL) {
532 /*
533 * FIXME: legacy server -- fall back to path-based call?
Steve Frenchff2157132010-03-09 20:30:42 +0000534 * for now, just skip revalidating and mark inode for
535 * immediate reval.
536 */
Jeff Laytonabab0952010-02-12 07:44:18 -0500537 rc = 0;
538 CIFS_I(inode)->time = 0;
539 goto cgfi_exit;
540 } else if (rc == -EREMOTE) {
541 cifs_create_dfs_fattr(&fattr, inode->i_sb);
542 rc = 0;
543 } else if (rc)
544 goto cgfi_exit;
545
546 /*
547 * don't bother with SFU junk here -- just mark inode as needing
548 * revalidation.
549 */
550 cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
551 fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
552 fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
553 cifs_fattr_to_inode(inode, &fattr);
554cgfi_exit:
555 FreeXid(xid);
556 return rc;
557}
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559int cifs_get_inode_info(struct inode **pinode,
Steve French646dd532008-05-15 01:50:56 +0000560 const unsigned char *full_path, FILE_ALL_INFO *pfindData,
Steve French8b1327f2008-03-14 22:37:16 +0000561 struct super_block *sb, int xid, const __u16 *pfid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400563 int rc = 0, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 struct cifsTconInfo *pTcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 char *buf = NULL;
Steve French5ade9de2008-05-02 20:56:23 +0000567 bool adjustTZ = false;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400568 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Jeff Laytona6e8a842010-09-20 16:01:33 -0700570 pTcon = cifs_sb_tcon(cifs_sb);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000571 cFYI(1, "Getting info on %s", full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700573 if ((pfindData == NULL) && (*pinode != NULL)) {
574 if (CIFS_I(*pinode)->clientCanCacheRead) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000575 cFYI(1, "No need to revalidate cached inode sizes");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return rc;
577 }
578 }
579
580 /* if file info not passed in then get it from server */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700581 if (pfindData == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700583 if (buf == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 return -ENOMEM;
585 pfindData = (FILE_ALL_INFO *)buf;
Igor Mammedov79626702008-03-09 03:44:18 +0000586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 /* could do find first instead but this returns more info */
Igor Mammedov79626702008-03-09 03:44:18 +0000588 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +0000589 0 /* not legacy */,
Steve French6b8edfe2005-08-23 20:26:03 -0700590 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700591 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French6b8edfe2005-08-23 20:26:03 -0700592 /* BB optimize code so we do not make the above call
593 when server claims no NT SMB support and the above call
594 failed at least once - set flag in tcon or mount */
Steve French4523cc32007-04-30 20:13:06 +0000595 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
Igor Mammedov79626702008-03-09 03:44:18 +0000596 rc = SMBQueryInformation(xid, pTcon, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000597 pfindData, cifs_sb->local_nls,
Steve French6b8edfe2005-08-23 20:26:03 -0700598 cifs_sb->mnt_cifs_flags &
599 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4b18f2a2008-04-29 00:06:05 +0000600 adjustTZ = true;
Steve French6b8edfe2005-08-23 20:26:03 -0700601 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400603
604 if (!rc) {
605 cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
606 cifs_sb, adjustTZ);
607 } else if (rc == -EREMOTE) {
608 cifs_create_dfs_fattr(&fattr, sb);
Steve Frenchb9a32602008-05-20 21:52:32 +0000609 rc = 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400610 } else {
Igor Mammedov79626702008-03-09 03:44:18 +0000611 goto cgii_exit;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400614 /*
615 * If an inode wasn't passed in, then get the inode number
616 *
617 * Is an i_ino of zero legal? Can we use that to check if the server
618 * supports returning inode numbers? Are there other sanity checks we
619 * can use to ensure that the server is really filling in that field?
620 *
621 * We can not use the IndexNumber field by default from Windows or
622 * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
623 * CIFS spec claims that this value is unique within the scope of a
624 * share, and the windows docs hint that it's actually unique
625 * per-machine.
626 *
627 * There may be higher info levels that work but are there Windows
628 * server or network appliances for which IndexNumber field is not
629 * guaranteed unique?
630 */
Steve Frenchb9a32602008-05-20 21:52:32 +0000631 if (*pinode == NULL) {
Steve Frenchb9a32602008-05-20 21:52:32 +0000632 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
633 int rc1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Steve Frenchb9a32602008-05-20 21:52:32 +0000635 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400636 full_path, &fattr.cf_uniqueid,
Steve French737b7582005-04-28 22:41:06 -0700637 cifs_sb->local_nls,
638 cifs_sb->mnt_cifs_flags &
639 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500640 if (rc1 || !fattr.cf_uniqueid) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 cFYI(1, "GetSrvInodeNum rc %d", rc1);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400642 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500643 cifs_autodisable_serverino(cifs_sb);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500644 }
Jeff Layton132ac7b2009-02-10 07:33:57 -0500645 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400646 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500647 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000648 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400649 fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000650 }
651
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400652 /* query for SFU type info if supported and needed */
653 if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
654 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
655 tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
656 if (tmprc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000657 cFYI(1, "cifs_sfu_type failed: %d", tmprc);
Steve Frenchb9a32602008-05-20 21:52:32 +0000658 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000659
Steve Frenchb9a32602008-05-20 21:52:32 +0000660#ifdef CONFIG_CIFS_EXPERIMENTAL
661 /* fill in 0777 bits from ACL */
662 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000663 cFYI(1, "Getting mode bits from ACL");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400664 cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
Steve Frenchb9a32602008-05-20 21:52:32 +0000665 }
666#endif
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400667
668 /* fill in remaining high mode bits e.g. SUID, VTX */
669 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
670 cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
671
Stefan Metzmacher1b12b9c2010-08-05 21:19:56 +0200672 /* check for Minshall+French symlinks */
673 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
674 tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
675 if (tmprc)
676 cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
677 }
678
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400679 if (!*pinode) {
680 *pinode = cifs_iget(sb, &fattr);
681 if (!*pinode)
682 rc = -ENOMEM;
683 } else {
684 cifs_fattr_to_inode(*pinode, &fattr);
Steve Frenchb9a32602008-05-20 21:52:32 +0000685 }
686
Igor Mammedov79626702008-03-09 03:44:18 +0000687cgii_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 kfree(buf);
689 return rc;
690}
691
Steve French7f8ed422007-09-28 22:28:55 +0000692static const struct inode_operations cifs_ipc_inode_ops = {
693 .lookup = cifs_lookup,
694};
695
Igor Mammedove4cce942009-02-10 14:10:26 +0300696char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
Steve French8be0ed42008-12-05 19:14:12 +0000697{
698 int pplen = cifs_sb->prepathlen;
699 int dfsplen;
700 char *full_path = NULL;
701
702 /* if no prefix path, simply set path to the root of share to "" */
703 if (pplen == 0) {
704 full_path = kmalloc(1, GFP_KERNEL);
705 if (full_path)
706 full_path[0] = 0;
707 return full_path;
708 }
709
Jeff Laytona6e8a842010-09-20 16:01:33 -0700710 if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS))
711 dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1);
Steve French8be0ed42008-12-05 19:14:12 +0000712 else
713 dfsplen = 0;
714
715 full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
716 if (full_path == NULL)
717 return full_path;
718
719 if (dfsplen) {
Jeff Laytona6e8a842010-09-20 16:01:33 -0700720 strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen);
Steve French8be0ed42008-12-05 19:14:12 +0000721 /* switch slash direction in prepath depending on whether
722 * windows or posix style path names
723 */
724 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
725 int i;
726 for (i = 0; i < dfsplen; i++) {
727 if (full_path[i] == '\\')
728 full_path[i] = '/';
729 }
730 }
731 }
732 strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
733 full_path[dfsplen + pplen] = 0; /* add trailing null */
734 return full_path;
735}
736
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400737static int
738cifs_find_inode(struct inode *inode, void *opaque)
739{
740 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
741
Jeff Laytonf30b9c12010-07-19 18:00:17 -0400742 /* don't match inode with different uniqueid */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400743 if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
744 return 0;
745
Jeff Laytonf30b9c12010-07-19 18:00:17 -0400746 /* don't match inode of different type */
747 if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
748 return 0;
749
Jeff Layton5acfec22010-08-02 17:43:54 -0400750 /* if it's not a directory or has no dentries, then flag it */
751 if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
Jeff Layton3d694382010-05-11 14:59:55 -0400752 fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
Jeff Layton3d694382010-05-11 14:59:55 -0400753
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400754 return 1;
755}
756
757static int
758cifs_init_inode(struct inode *inode, void *opaque)
759{
760 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
761
762 CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
763 return 0;
764}
765
Jeff Layton5acfec22010-08-02 17:43:54 -0400766/*
767 * walk dentry list for an inode and report whether it has aliases that
768 * are hashed. We use this to determine if a directory inode can actually
769 * be used.
770 */
771static bool
772inode_has_hashed_dentries(struct inode *inode)
773{
774 struct dentry *dentry;
775
776 spin_lock(&dcache_lock);
777 list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
778 if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
779 spin_unlock(&dcache_lock);
780 return true;
781 }
782 }
783 spin_unlock(&dcache_lock);
784 return false;
785}
786
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400787/* Given fattrs, get a corresponding inode */
788struct inode *
789cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
790{
791 unsigned long hash;
792 struct inode *inode;
793
Jeff Layton3d694382010-05-11 14:59:55 -0400794retry_iget5_locked:
Joe Perchesb6b38f72010-04-21 03:50:45 +0000795 cFYI(1, "looking for uniqueid=%llu", fattr->cf_uniqueid);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400796
797 /* hash down to 32-bits on 32-bit arch */
798 hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
799
800 inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400801 if (inode) {
Jeff Layton5acfec22010-08-02 17:43:54 -0400802 /* was there a potentially problematic inode collision? */
Jeff Layton3d694382010-05-11 14:59:55 -0400803 if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
Jeff Layton3d694382010-05-11 14:59:55 -0400804 fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
Jeff Layton5acfec22010-08-02 17:43:54 -0400805
806 if (inode_has_hashed_dentries(inode)) {
807 cifs_autodisable_serverino(CIFS_SB(sb));
808 iput(inode);
809 fattr->cf_uniqueid = iunique(sb, ROOT_I);
810 goto retry_iget5_locked;
811 }
Jeff Layton3d694382010-05-11 14:59:55 -0400812 }
813
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400814 cifs_fattr_to_inode(inode, fattr);
815 if (sb->s_flags & MS_NOATIME)
816 inode->i_flags |= S_NOATIME | S_NOCMTIME;
817 if (inode->i_state & I_NEW) {
818 inode->i_ino = hash;
Steve French0ccd4802010-07-16 04:31:02 +0000819#ifdef CONFIG_CIFS_FSCACHE
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530820 /* initialize per-inode cache cookie pointer */
821 CIFS_I(inode)->fscache = NULL;
Steve French0ccd4802010-07-16 04:31:02 +0000822#endif
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400823 unlock_new_inode(inode);
824 }
825 }
826
827 return inode;
828}
829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830/* gets root inode */
Jeff Laytonbd433d42009-05-27 09:37:34 -0400831struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
David Howellsce634ab2008-02-07 00:15:33 -0800833 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 struct cifs_sb_info *cifs_sb;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400835 struct inode *inode = NULL;
David Howellsce634ab2008-02-07 00:15:33 -0800836 long rc;
Steve French8be0ed42008-12-05 19:14:12 +0000837 char *full_path;
David Howellsce634ab2008-02-07 00:15:33 -0800838
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400839 cifs_sb = CIFS_SB(sb);
Igor Mammedove4cce942009-02-10 14:10:26 +0300840 full_path = cifs_build_path_to_root(cifs_sb);
Steve French8be0ed42008-12-05 19:14:12 +0000841 if (full_path == NULL)
842 return ERR_PTR(-ENOMEM);
Steve Frenchc18c8422007-07-18 23:21:09 +0000843
Steve French8be0ed42008-12-05 19:14:12 +0000844 xid = GetXid();
Jeff Laytona6e8a842010-09-20 16:01:33 -0700845 if (cifs_sb_tcon(cifs_sb)->unix_ext)
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400846 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400847 else
848 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
Steve French8be0ed42008-12-05 19:14:12 +0000849 xid, NULL);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400850
851 if (!inode)
Suresh Jayaramanf0138a72010-08-26 14:46:09 +0530852 return ERR_PTR(rc);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400853
Steve French0ccd4802010-07-16 04:31:02 +0000854#ifdef CONFIG_CIFS_FSCACHE
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530855 /* populate tcon->resource_id */
Jeff Laytona6e8a842010-09-20 16:01:33 -0700856 cifs_sb_tcon(cifs_sb)->resource_id = CIFS_I(inode)->uniqueid;
Steve French0ccd4802010-07-16 04:31:02 +0000857#endif
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530858
Jeff Laytona6e8a842010-09-20 16:01:33 -0700859 if (rc && cifs_sb_tcon(cifs_sb)->ipc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000860 cFYI(1, "ipc connection - fake read inode");
Steve French7f8ed422007-09-28 22:28:55 +0000861 inode->i_mode |= S_IFDIR;
862 inode->i_nlink = 2;
863 inode->i_op = &cifs_ipc_inode_ops;
864 inode->i_fop = &simple_dir_operations;
865 inode->i_uid = cifs_sb->mnt_uid;
866 inode->i_gid = cifs_sb->mnt_gid;
Steve Frenchad661332008-08-12 14:14:40 +0000867 } else if (rc) {
Steve French8be0ed42008-12-05 19:14:12 +0000868 kfree(full_path);
David Howellsce634ab2008-02-07 00:15:33 -0800869 _FreeXid(xid);
870 iget_failed(inode);
871 return ERR_PTR(rc);
Steve French7f8ed422007-09-28 22:28:55 +0000872 }
873
David Howellsce634ab2008-02-07 00:15:33 -0800874
Steve French8be0ed42008-12-05 19:14:12 +0000875 kfree(full_path);
David Howellsce634ab2008-02-07 00:15:33 -0800876 /* can not call macro FreeXid here since in a void func
877 * TODO: This is no longer true
878 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 _FreeXid(xid);
David Howellsce634ab2008-02-07 00:15:33 -0800880 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881}
882
Steve French388e57b2008-09-16 23:50:58 +0000883static int
884cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
885 char *full_path, __u32 dosattr)
886{
887 int rc;
888 int oplock = 0;
889 __u16 netfid;
890 __u32 netpid;
891 bool set_time = false;
892 struct cifsFileInfo *open_file;
893 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
894 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytonba00ba62010-09-20 16:01:31 -0700895 struct cifsTconInfo *pTcon;
Steve French388e57b2008-09-16 23:50:58 +0000896 FILE_BASIC_INFO info_buf;
897
Steve French1adcb712009-02-25 14:19:56 +0000898 if (attrs == NULL)
899 return -EINVAL;
900
Steve French388e57b2008-09-16 23:50:58 +0000901 if (attrs->ia_valid & ATTR_ATIME) {
902 set_time = true;
903 info_buf.LastAccessTime =
904 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
905 } else
906 info_buf.LastAccessTime = 0;
907
908 if (attrs->ia_valid & ATTR_MTIME) {
909 set_time = true;
910 info_buf.LastWriteTime =
911 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
912 } else
913 info_buf.LastWriteTime = 0;
914
915 /*
916 * Samba throws this field away, but windows may actually use it.
917 * Do not set ctime unless other time stamps are changed explicitly
918 * (i.e. by utimes()) since we would then have a mix of client and
919 * server times.
920 */
921 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000922 cFYI(1, "CIFS - CTIME changed");
Steve French388e57b2008-09-16 23:50:58 +0000923 info_buf.ChangeTime =
924 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
925 } else
926 info_buf.ChangeTime = 0;
927
928 info_buf.CreationTime = 0; /* don't change */
929 info_buf.Attributes = cpu_to_le32(dosattr);
930
931 /*
932 * If the file is already open for write, just use that fileid
933 */
934 open_file = find_writable_file(cifsInode);
935 if (open_file) {
936 netfid = open_file->netfid;
937 netpid = open_file->pid;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700938 pTcon = open_file->tcon;
Steve French388e57b2008-09-16 23:50:58 +0000939 goto set_via_filehandle;
940 }
941
Jeff Laytona6e8a842010-09-20 16:01:33 -0700942 pTcon = cifs_sb_tcon(cifs_sb);
Jeff Laytonba00ba62010-09-20 16:01:31 -0700943
Steve French388e57b2008-09-16 23:50:58 +0000944 /*
945 * NT4 apparently returns success on this call, but it doesn't
946 * really work.
947 */
948 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
949 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
950 &info_buf, cifs_sb->local_nls,
951 cifs_sb->mnt_cifs_flags &
952 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +0000953 if (rc == 0) {
954 cifsInode->cifsAttrs = dosattr;
955 goto out;
956 } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
Steve French388e57b2008-09-16 23:50:58 +0000957 goto out;
958 }
959
Joe Perchesb6b38f72010-04-21 03:50:45 +0000960 cFYI(1, "calling SetFileInfo since SetPathInfo for "
961 "times not supported by this server");
Steve French388e57b2008-09-16 23:50:58 +0000962 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
963 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
964 CREATE_NOT_DIR, &netfid, &oplock,
965 NULL, cifs_sb->local_nls,
966 cifs_sb->mnt_cifs_flags &
967 CIFS_MOUNT_MAP_SPECIAL_CHR);
968
969 if (rc != 0) {
970 if (rc == -EIO)
971 rc = -EINVAL;
972 goto out;
973 }
974
975 netpid = current->tgid;
976
977set_via_filehandle:
978 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
Steve Frenchd3889082008-09-24 19:22:52 +0000979 if (!rc)
980 cifsInode->cifsAttrs = dosattr;
981
Steve French388e57b2008-09-16 23:50:58 +0000982 if (open_file == NULL)
983 CIFSSMBClose(xid, pTcon, netfid);
984 else
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400985 cifsFileInfo_put(open_file);
Steve French388e57b2008-09-16 23:50:58 +0000986out:
987 return rc;
988}
989
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400990/*
991 * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
992 * and rename it to a random name that hopefully won't conflict with
993 * anything else.
994 */
995static int
Steve French32709582008-10-20 00:44:19 +0000996cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400997{
998 int oplock = 0;
999 int rc;
1000 __u16 netfid;
Steve French32709582008-10-20 00:44:19 +00001001 struct inode *inode = dentry->d_inode;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001002 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1003 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytona6e8a842010-09-20 16:01:33 -07001004 struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
Steve French32709582008-10-20 00:44:19 +00001005 __u32 dosattr, origattr;
1006 FILE_BASIC_INFO *info_buf = NULL;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001007
1008 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
Jeff Laytondd1db2d2008-10-16 19:27:12 -04001009 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001010 &netfid, &oplock, NULL, cifs_sb->local_nls,
1011 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1012 if (rc != 0)
1013 goto out;
1014
Steve French32709582008-10-20 00:44:19 +00001015 origattr = cifsInode->cifsAttrs;
1016 if (origattr == 0)
1017 origattr |= ATTR_NORMAL;
1018
1019 dosattr = origattr & ~ATTR_READONLY;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001020 if (dosattr == 0)
1021 dosattr |= ATTR_NORMAL;
1022 dosattr |= ATTR_HIDDEN;
1023
Steve French32709582008-10-20 00:44:19 +00001024 /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
1025 if (dosattr != origattr) {
1026 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
1027 if (info_buf == NULL) {
1028 rc = -ENOMEM;
1029 goto out_close;
1030 }
1031 info_buf->Attributes = cpu_to_le32(dosattr);
1032 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1033 current->tgid);
1034 /* although we would like to mark the file hidden
1035 if that fails we will still try to rename it */
Steve French41346092008-10-20 18:24:42 +00001036 if (rc != 0)
Steve French32709582008-10-20 00:44:19 +00001037 cifsInode->cifsAttrs = dosattr;
1038 else
1039 dosattr = origattr; /* since not able to change them */
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001040 }
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001041
Jeff Laytondd1db2d2008-10-16 19:27:12 -04001042 /* rename the file */
1043 rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001044 cifs_sb->mnt_cifs_flags &
1045 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French32709582008-10-20 00:44:19 +00001046 if (rc != 0) {
1047 rc = -ETXTBSY;
1048 goto undo_setattr;
1049 }
Jeff Layton6d22f092008-09-23 11:48:35 -04001050
Steve French32709582008-10-20 00:44:19 +00001051 /* try to set DELETE_ON_CLOSE */
1052 if (!cifsInode->delete_pending) {
1053 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
1054 current->tgid);
1055 /*
1056 * some samba versions return -ENOENT when we try to set the
1057 * file disposition here. Likely a samba bug, but work around
1058 * it for now. This means that some cifsXXX files may hang
1059 * around after they shouldn't.
1060 *
1061 * BB: remove this hack after more servers have the fix
1062 */
1063 if (rc == -ENOENT)
1064 rc = 0;
1065 else if (rc != 0) {
1066 rc = -ETXTBSY;
1067 goto undo_rename;
1068 }
1069 cifsInode->delete_pending = true;
1070 }
Jeff Layton7ce86d52008-09-24 11:32:59 -04001071
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001072out_close:
1073 CIFSSMBClose(xid, tcon, netfid);
1074out:
Steve French32709582008-10-20 00:44:19 +00001075 kfree(info_buf);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001076 return rc;
Steve French32709582008-10-20 00:44:19 +00001077
1078 /*
1079 * reset everything back to the original state. Don't bother
1080 * dealing with errors here since we can't do anything about
1081 * them anyway.
1082 */
1083undo_rename:
1084 CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
1085 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1086 CIFS_MOUNT_MAP_SPECIAL_CHR);
1087undo_setattr:
1088 if (dosattr != origattr) {
1089 info_buf->Attributes = cpu_to_le32(origattr);
1090 if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1091 current->tgid))
1092 cifsInode->cifsAttrs = origattr;
1093 }
1094
1095 goto out_close;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001096}
1097
Steve Frenchff694522009-04-20 19:45:13 +00001098
1099/*
1100 * If dentry->d_inode is null (usually meaning the cached dentry
1101 * is a negative dentry) then we would attempt a standard SMB delete, but
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001102 * if that fails we can not attempt the fall back mechanisms on EACCESS
1103 * but will return the EACCESS to the caller. Note that the VFS does not call
Steve Frenchff694522009-04-20 19:45:13 +00001104 * unlink on negative dentries currently.
1105 */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001106int cifs_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
1108 int rc = 0;
1109 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 char *full_path = NULL;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001111 struct inode *inode = dentry->d_inode;
Steve Frenchff694522009-04-20 19:45:13 +00001112 struct cifsInodeInfo *cifs_inode;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001113 struct super_block *sb = dir->i_sb;
1114 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Jeff Laytona6e8a842010-09-20 16:01:33 -07001115 struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb);
Steve French60502472008-10-07 18:42:52 +00001116 struct iattr *attrs = NULL;
1117 __u32 dosattr = 0, origattr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Joe Perchesb6b38f72010-04-21 03:50:45 +00001119 cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
1121 xid = GetXid();
1122
Jeff Layton5f0319a2008-09-16 14:05:16 -04001123 /* Unlink can be called from rename so we can not take the
1124 * sb->s_vfs_rename_mutex here */
1125 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301127 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301129 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 }
Steve French2d785a52007-07-15 01:48:57 +00001131
Jeff Layton5f0319a2008-09-16 14:05:16 -04001132 if ((tcon->ses->capabilities & CAP_UNIX) &&
Steve French2d785a52007-07-15 01:48:57 +00001133 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Jeff Layton5f0319a2008-09-16 14:05:16 -04001134 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1135 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
Steve French2d785a52007-07-15 01:48:57 +00001136 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
1137 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001138 cFYI(1, "posix del rc %d", rc);
Steve French2d785a52007-07-15 01:48:57 +00001139 if ((rc == 0) || (rc == -ENOENT))
1140 goto psx_del_no_retry;
1141 }
1142
Steve French60502472008-10-07 18:42:52 +00001143retry_std_delete:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001144 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001145 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French60502472008-10-07 18:42:52 +00001146
Steve French2d785a52007-07-15 01:48:57 +00001147psx_del_no_retry:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 if (!rc) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001149 if (inode)
1150 drop_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 } else if (rc == -ENOENT) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001152 d_drop(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 } else if (rc == -ETXTBSY) {
Steve French32709582008-10-20 00:44:19 +00001154 rc = cifs_rename_pending_delete(full_path, dentry, xid);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001155 if (rc == 0)
1156 drop_nlink(inode);
Steve Frenchff694522009-04-20 19:45:13 +00001157 } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
Steve French388e57b2008-09-16 23:50:58 +00001158 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
1159 if (attrs == NULL) {
1160 rc = -ENOMEM;
1161 goto out_reval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
Steve French388e57b2008-09-16 23:50:58 +00001163
1164 /* try to reset dos attributes */
Steve Frenchff694522009-04-20 19:45:13 +00001165 cifs_inode = CIFS_I(inode);
1166 origattr = cifs_inode->cifsAttrs;
Steve French60502472008-10-07 18:42:52 +00001167 if (origattr == 0)
1168 origattr |= ATTR_NORMAL;
1169 dosattr = origattr & ~ATTR_READONLY;
Steve French388e57b2008-09-16 23:50:58 +00001170 if (dosattr == 0)
1171 dosattr |= ATTR_NORMAL;
1172 dosattr |= ATTR_HIDDEN;
1173
1174 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
Steve French388e57b2008-09-16 23:50:58 +00001175 if (rc != 0)
1176 goto out_reval;
Steve French60502472008-10-07 18:42:52 +00001177
1178 goto retry_std_delete;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 }
Steve French60502472008-10-07 18:42:52 +00001180
1181 /* undo the setattr if we errored out and it's needed */
1182 if (rc != 0 && dosattr != 0)
1183 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
1184
Steve French388e57b2008-09-16 23:50:58 +00001185out_reval:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001186 if (inode) {
Steve Frenchff694522009-04-20 19:45:13 +00001187 cifs_inode = CIFS_I(inode);
1188 cifs_inode->time = 0; /* will force revalidate to get info
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001189 when needed */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001190 inode->i_ctime = current_fs_time(sb);
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001191 }
Jeff Layton5f0319a2008-09-16 14:05:16 -04001192 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
Steve Frenchff694522009-04-20 19:45:13 +00001193 cifs_inode = CIFS_I(dir);
Steve French60502472008-10-07 18:42:52 +00001194 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
1196 kfree(full_path);
Steve French60502472008-10-07 18:42:52 +00001197 kfree(attrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 FreeXid(xid);
1199 return rc;
1200}
1201
1202int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
1203{
Jeff Layton6b37faa2008-10-06 21:54:41 +00001204 int rc = 0, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 int xid;
1206 struct cifs_sb_info *cifs_sb;
1207 struct cifsTconInfo *pTcon;
1208 char *full_path = NULL;
1209 struct inode *newinode = NULL;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001210 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
Joe Perchesb6b38f72010-04-21 03:50:45 +00001212 cFYI(1, "In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 xid = GetXid();
1215
1216 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytona6e8a842010-09-20 16:01:33 -07001217 pTcon = cifs_sb_tcon(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Steve French7f573562005-08-30 11:32:14 -07001219 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301221 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301223 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 }
Steve French50c2f752007-07-13 00:33:32 +00001225
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001226 if ((pTcon->ses->capabilities & CAP_UNIX) &&
1227 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Steve French2dd29d32007-04-23 22:07:35 +00001228 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
1229 u32 oplock = 0;
Steve Frenchf6d09982008-01-08 23:18:22 +00001230 FILE_UNIX_BASIC_INFO *pInfo =
Steve French2dd29d32007-04-23 22:07:35 +00001231 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001232 if (pInfo == NULL) {
Steve French2dd29d32007-04-23 22:07:35 +00001233 rc = -ENOMEM;
1234 goto mkdir_out;
1235 }
Steve French50c2f752007-07-13 00:33:32 +00001236
Al Viroce3b0f82009-03-29 19:08:22 -04001237 mode &= ~current_umask();
Steve French2dd29d32007-04-23 22:07:35 +00001238 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
1239 mode, NULL /* netfid */, pInfo, &oplock,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001240 full_path, cifs_sb->local_nls,
1241 cifs_sb->mnt_cifs_flags &
Steve French2dd29d32007-04-23 22:07:35 +00001242 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc45d7072007-09-17 02:04:21 +00001243 if (rc == -EOPNOTSUPP) {
1244 kfree(pInfo);
1245 goto mkdir_retry_old;
1246 } else if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001247 cFYI(1, "posix mkdir returned 0x%x", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001248 d_drop(direntry);
1249 } else {
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001250 if (pInfo->Type == cpu_to_le32(-1)) {
1251 /* no return info, go query for it */
Steve French5a07cdf2007-09-16 23:12:47 +00001252 kfree(pInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001253 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001254 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001255/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
1256 to set uid/gid */
Steve French2dd29d32007-04-23 22:07:35 +00001257 inc_nlink(inode);
1258 if (pTcon->nocase)
1259 direntry->d_op = &cifs_ci_dentry_ops;
1260 else
1261 direntry->d_op = &cifs_dentry_ops;
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001262
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001263 cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
Jeff Layton4065c802010-05-17 07:18:58 -04001264 cifs_fill_uniqueid(inode->i_sb, &fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001265 newinode = cifs_iget(inode->i_sb, &fattr);
1266 if (!newinode) {
Steve French5a07cdf2007-09-16 23:12:47 +00001267 kfree(pInfo);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001268 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001269 }
Jeff Layton6b37faa2008-10-06 21:54:41 +00001270
Steve French2dd29d32007-04-23 22:07:35 +00001271 d_instantiate(direntry, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001272
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001273#ifdef CONFIG_CIFS_DEBUG2
Joe Perchesb6b38f72010-04-21 03:50:45 +00001274 cFYI(1, "instantiated dentry %p %s to inode %p",
1275 direntry, direntry->d_name.name, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001276
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001277 if (newinode->i_nlink != 2)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001278 cFYI(1, "unexpected number of links %d",
1279 newinode->i_nlink);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001280#endif
Steve French2dd29d32007-04-23 22:07:35 +00001281 }
1282 kfree(pInfo);
1283 goto mkdir_out;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001284 }
Steve Frenchc45d7072007-09-17 02:04:21 +00001285mkdir_retry_old:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -07001287 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
1288 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001290 cFYI(1, "cifs_mkdir returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 d_drop(direntry);
1292 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001293mkdir_get_info:
Dave Hansend8c76e62006-09-30 23:29:04 -07001294 inc_nlink(inode);
Steve Frenchc18c8422007-07-18 23:21:09 +00001295 if (pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001297 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 else
1299 rc = cifs_get_inode_info(&newinode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +00001300 inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Steve Frenchb92327f2005-08-22 20:09:43 -07001302 if (pTcon->nocase)
1303 direntry->d_op = &cifs_ci_dentry_ops;
1304 else
1305 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 d_instantiate(direntry, newinode);
Steve French2dd29d32007-04-23 22:07:35 +00001307 /* setting nlink not necessary except in cases where we
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001308 * failed to get it from the server or was set bogus */
Steve French2dd29d32007-04-23 22:07:35 +00001309 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001310 direntry->d_inode->i_nlink = 2;
Jeff Layton95089912008-08-06 04:39:02 +00001311
Al Viroce3b0f82009-03-29 19:08:22 -04001312 mode &= ~current_umask();
Jeff Layton95089912008-08-06 04:39:02 +00001313 /* must turn on setgid bit if parent dir has it */
1314 if (inode->i_mode & S_ISGID)
1315 mode |= S_ISGID;
1316
Steve Frenchc18c8422007-07-18 23:21:09 +00001317 if (pTcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001318 struct cifs_unix_set_info_args args = {
1319 .mode = mode,
1320 .ctime = NO_CHANGE_64,
1321 .atime = NO_CHANGE_64,
1322 .mtime = NO_CHANGE_64,
1323 .device = 0,
1324 };
Steve Frenchd0d2f2d2005-06-02 15:12:36 -07001325 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
David Howellsa001e5b2008-11-14 10:38:47 +11001326 args.uid = (__u64)current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001327 if (inode->i_mode & S_ISGID)
1328 args.gid = (__u64)inode->i_gid;
1329 else
David Howellsa001e5b2008-11-14 10:38:47 +11001330 args.gid = (__u64)current_fsgid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 } else {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001332 args.uid = NO_CHANGE_64;
1333 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
Jeff Layton01ea95e2009-07-09 20:02:49 -04001335 CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
1336 cifs_sb->local_nls,
1337 cifs_sb->mnt_cifs_flags &
1338 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French3ce53fc2007-06-08 14:55:14 +00001339 } else {
Jeff Layton67750fb2008-05-09 22:28:02 +00001340 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1341 (mode & S_IWUGO) == 0) {
1342 FILE_BASIC_INFO pInfo;
Jeff Layton6b37faa2008-10-06 21:54:41 +00001343 struct cifsInodeInfo *cifsInode;
1344 u32 dosattrs;
1345
Jeff Layton67750fb2008-05-09 22:28:02 +00001346 memset(&pInfo, 0, sizeof(pInfo));
Jeff Layton6b37faa2008-10-06 21:54:41 +00001347 cifsInode = CIFS_I(newinode);
1348 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1349 pInfo.Attributes = cpu_to_le32(dosattrs);
1350 tmprc = CIFSSMBSetPathInfo(xid, pTcon,
1351 full_path, &pInfo,
1352 cifs_sb->local_nls,
Jeff Layton67750fb2008-05-09 22:28:02 +00001353 cifs_sb->mnt_cifs_flags &
1354 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +00001355 if (tmprc == 0)
1356 cifsInode->cifsAttrs = dosattrs;
Jeff Layton67750fb2008-05-09 22:28:02 +00001357 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001358 if (direntry->d_inode) {
Jeff Laytonb0fd30d2008-05-22 09:33:34 -04001359 if (cifs_sb->mnt_cifs_flags &
1360 CIFS_MOUNT_DYNPERM)
1361 direntry->d_inode->i_mode =
1362 (mode | S_IFDIR);
Steve French4e94a102008-05-23 18:22:46 +00001363
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001364 if (cifs_sb->mnt_cifs_flags &
Steve French6473a552005-11-29 20:20:10 -08001365 CIFS_MOUNT_SET_UID) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001366 direntry->d_inode->i_uid =
David Howellsa001e5b2008-11-14 10:38:47 +11001367 current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001368 if (inode->i_mode & S_ISGID)
1369 direntry->d_inode->i_gid =
1370 inode->i_gid;
1371 else
1372 direntry->d_inode->i_gid =
David Howellsa001e5b2008-11-14 10:38:47 +11001373 current_fsgid();
Steve French6473a552005-11-29 20:20:10 -08001374 }
1375 }
Steve French2a138ebb2005-11-29 21:22:19 -08001376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001378mkdir_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 kfree(full_path);
1380 FreeXid(xid);
1381 return rc;
1382}
1383
1384int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1385{
1386 int rc = 0;
1387 int xid;
1388 struct cifs_sb_info *cifs_sb;
1389 struct cifsTconInfo *pTcon;
1390 char *full_path = NULL;
1391 struct cifsInodeInfo *cifsInode;
1392
Joe Perchesb6b38f72010-04-21 03:50:45 +00001393 cFYI(1, "cifs_rmdir, inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 xid = GetXid();
1396
1397 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytona6e8a842010-09-20 16:01:33 -07001398 pTcon = cifs_sb_tcon(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Steve French7f573562005-08-30 11:32:14 -07001400 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301402 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301404 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 }
1406
Steve French737b7582005-04-28 22:41:06 -07001407 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1408 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
1410 if (!rc) {
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001411 drop_nlink(inode);
Steve French3677db12007-02-26 16:46:11 +00001412 spin_lock(&direntry->d_inode->i_lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001413 i_size_write(direntry->d_inode, 0);
Dave Hansence71ec32006-09-30 23:29:06 -07001414 clear_nlink(direntry->d_inode);
Steve French3677db12007-02-26 16:46:11 +00001415 spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 }
1417
1418 cifsInode = CIFS_I(direntry->d_inode);
1419 cifsInode->time = 0; /* force revalidate to go get info when
1420 needed */
Steve French42c24542009-01-13 22:03:55 +00001421
1422 cifsInode = CIFS_I(inode);
1423 cifsInode->time = 0; /* force revalidate to get parent dir info
1424 since cached search results now invalid */
1425
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1427 current_fs_time(inode->i_sb);
1428
1429 kfree(full_path);
1430 FreeXid(xid);
1431 return rc;
1432}
1433
Steve Frenchee2fd962008-09-23 18:23:33 +00001434static int
1435cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
1436 struct dentry *to_dentry, const char *toPath)
1437{
1438 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
Jeff Laytona6e8a842010-09-20 16:01:33 -07001439 struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
Steve Frenchee2fd962008-09-23 18:23:33 +00001440 __u16 srcfid;
1441 int oplock, rc;
1442
1443 /* try path-based rename first */
1444 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
1445 cifs_sb->mnt_cifs_flags &
1446 CIFS_MOUNT_MAP_SPECIAL_CHR);
1447
1448 /*
1449 * don't bother with rename by filehandle unless file is busy and
1450 * source Note that cross directory moves do not work with
1451 * rename by filehandle to various Windows servers.
1452 */
1453 if (rc == 0 || rc != -ETXTBSY)
1454 return rc;
1455
Jeff Laytoned0e3ac2010-06-01 16:21:01 -04001456 /* open-file renames don't work across directories */
1457 if (to_dentry->d_parent != from_dentry->d_parent)
1458 return rc;
1459
Steve Frenchee2fd962008-09-23 18:23:33 +00001460 /* open the file to be renamed -- we need DELETE perms */
1461 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
1462 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1463 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1464 CIFS_MOUNT_MAP_SPECIAL_CHR);
1465
1466 if (rc == 0) {
1467 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
1468 (const char *) to_dentry->d_name.name,
1469 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1470 CIFS_MOUNT_MAP_SPECIAL_CHR);
1471
1472 CIFSSMBClose(xid, pTcon, srcfid);
1473 }
1474
1475 return rc;
1476}
1477
Jeff Layton14121bd2008-10-20 14:45:22 -04001478int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1479 struct inode *target_dir, struct dentry *target_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480{
Steve Frenchee2fd962008-09-23 18:23:33 +00001481 char *fromName = NULL;
1482 char *toName = NULL;
Jeff Layton639e7a92010-09-03 11:50:09 -04001483 struct cifs_sb_info *cifs_sb;
Jeff Layton14121bd2008-10-20 14:45:22 -04001484 struct cifsTconInfo *tcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001485 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1486 FILE_UNIX_BASIC_INFO *info_buf_target;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001487 int xid, rc, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
Jeff Layton639e7a92010-09-03 11:50:09 -04001489 cifs_sb = CIFS_SB(source_dir->i_sb);
Jeff Laytona6e8a842010-09-20 16:01:33 -07001490 tcon = cifs_sb_tcon(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Steve Frenchee2fd962008-09-23 18:23:33 +00001492 xid = GetXid();
1493
1494 /*
Steve Frenchee2fd962008-09-23 18:23:33 +00001495 * we already have the rename sem so we do not need to
1496 * grab it again here to protect the path integrity
1497 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001498 fromName = build_path_from_dentry(source_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001499 if (fromName == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 rc = -ENOMEM;
1501 goto cifs_rename_exit;
1502 }
1503
Jeff Layton14121bd2008-10-20 14:45:22 -04001504 toName = build_path_from_dentry(target_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001505 if (toName == NULL) {
1506 rc = -ENOMEM;
1507 goto cifs_rename_exit;
1508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
Jeff Layton14121bd2008-10-20 14:45:22 -04001510 rc = cifs_do_rename(xid, source_dentry, fromName,
1511 target_dentry, toName);
Steve Frenchee2fd962008-09-23 18:23:33 +00001512
Jeff Layton14121bd2008-10-20 14:45:22 -04001513 if (rc == -EEXIST && tcon->unix_ext) {
Steve Frenchee2fd962008-09-23 18:23:33 +00001514 /*
Jeff Layton14121bd2008-10-20 14:45:22 -04001515 * Are src and dst hardlinks of same inode? We can
1516 * only tell with unix extensions enabled
Steve Frenchee2fd962008-09-23 18:23:33 +00001517 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001518 info_buf_source =
1519 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1520 GFP_KERNEL);
1521 if (info_buf_source == NULL) {
1522 rc = -ENOMEM;
1523 goto cifs_rename_exit;
1524 }
1525
1526 info_buf_target = info_buf_source + 1;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001527 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
Jeff Layton14121bd2008-10-20 14:45:22 -04001528 info_buf_source,
Jeff Layton639e7a92010-09-03 11:50:09 -04001529 cifs_sb->local_nls,
1530 cifs_sb->mnt_cifs_flags &
Jeff Layton14121bd2008-10-20 14:45:22 -04001531 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton8d281ef2008-10-22 13:57:01 -04001532 if (tmprc != 0)
Jeff Layton14121bd2008-10-20 14:45:22 -04001533 goto unlink_target;
1534
Jeff Layton639e7a92010-09-03 11:50:09 -04001535 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
1536 info_buf_target,
1537 cifs_sb->local_nls,
1538 cifs_sb->mnt_cifs_flags &
Jeff Layton14121bd2008-10-20 14:45:22 -04001539 CIFS_MOUNT_MAP_SPECIAL_CHR);
1540
Jeff Layton8d281ef2008-10-22 13:57:01 -04001541 if (tmprc == 0 && (info_buf_source->UniqueId ==
Jeff Laytonae6884a2008-11-03 14:05:08 -05001542 info_buf_target->UniqueId)) {
Jeff Layton14121bd2008-10-20 14:45:22 -04001543 /* same file, POSIX says that this is a noop */
Jeff Laytonae6884a2008-11-03 14:05:08 -05001544 rc = 0;
Jeff Layton14121bd2008-10-20 14:45:22 -04001545 goto cifs_rename_exit;
Jeff Laytonae6884a2008-11-03 14:05:08 -05001546 }
Jeff Layton14121bd2008-10-20 14:45:22 -04001547 } /* else ... BB we could add the same check for Windows by
1548 checking the UniqueId via FILE_INTERNAL_INFO */
1549
Jeff Layton14121bd2008-10-20 14:45:22 -04001550unlink_target:
Jeff Laytonfc6f3942009-04-17 11:45:30 -04001551 /* Try unlinking the target dentry if it's not negative */
1552 if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
Jeff Layton8d281ef2008-10-22 13:57:01 -04001553 tmprc = cifs_unlink(target_dir, target_dentry);
Jeff Layton14121bd2008-10-20 14:45:22 -04001554 if (tmprc)
1555 goto cifs_rename_exit;
1556
Jeff Layton14121bd2008-10-20 14:45:22 -04001557 rc = cifs_do_rename(xid, source_dentry, fromName,
1558 target_dentry, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 }
1560
1561cifs_rename_exit:
Steve Frenchee2fd962008-09-23 18:23:33 +00001562 kfree(info_buf_source);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 kfree(fromName);
1564 kfree(toName);
1565 FreeXid(xid);
1566 return rc;
1567}
1568
Jeff Laytondf2cf172010-02-12 07:44:16 -05001569static bool
1570cifs_inode_needs_reval(struct inode *inode)
1571{
1572 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1573
1574 if (cifs_i->clientCanCacheRead)
1575 return false;
1576
1577 if (!lookupCacheEnabled)
1578 return true;
1579
1580 if (cifs_i->time == 0)
1581 return true;
1582
1583 /* FIXME: the actimeo should be tunable */
1584 if (time_after_eq(jiffies, cifs_i->time + HZ))
1585 return true;
1586
Jeff Laytondb192722010-05-17 14:51:49 -04001587 /* hardlinked files w/ noserverino get "special" treatment */
1588 if (!(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
1589 S_ISREG(inode->i_mode) && inode->i_nlink != 1)
1590 return true;
1591
Jeff Laytondf2cf172010-02-12 07:44:16 -05001592 return false;
1593}
1594
1595/* check invalid_mapping flag and zap the cache if it's set */
1596static void
1597cifs_invalidate_mapping(struct inode *inode)
1598{
1599 int rc;
1600 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1601
1602 cifs_i->invalid_mapping = false;
1603
1604 /* write back any cached data */
1605 if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
1606 rc = filemap_write_and_wait(inode->i_mapping);
1607 if (rc)
1608 cifs_i->write_behind_rc = rc;
1609 }
1610 invalidate_remote_inode(inode);
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +05301611 cifs_fscache_reset_inode_cookie(inode);
Jeff Laytondf2cf172010-02-12 07:44:16 -05001612}
1613
Jeff Laytonabab0952010-02-12 07:44:18 -05001614int cifs_revalidate_file(struct file *filp)
1615{
1616 int rc = 0;
1617 struct inode *inode = filp->f_path.dentry->d_inode;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001618 struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
Jeff Laytonabab0952010-02-12 07:44:18 -05001619
1620 if (!cifs_inode_needs_reval(inode))
1621 goto check_inval;
1622
Jeff Laytonba00ba62010-09-20 16:01:31 -07001623 if (cfile->tcon->unix_ext)
Jeff Laytonabab0952010-02-12 07:44:18 -05001624 rc = cifs_get_file_info_unix(filp);
1625 else
1626 rc = cifs_get_file_info(filp);
1627
1628check_inval:
1629 if (CIFS_I(inode)->invalid_mapping)
1630 cifs_invalidate_mapping(inode);
1631
1632 return rc;
1633}
1634
Jeff Laytondf2cf172010-02-12 07:44:16 -05001635/* revalidate a dentry's inode attributes */
1636int cifs_revalidate_dentry(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637{
1638 int xid;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001639 int rc = 0;
1640 char *full_path = NULL;
1641 struct inode *inode = dentry->d_inode;
1642 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Jeff Laytondf2cf172010-02-12 07:44:16 -05001644 if (inode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 return -ENOENT;
1646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 xid = GetXid();
1648
Jeff Laytondf2cf172010-02-12 07:44:16 -05001649 if (!cifs_inode_needs_reval(inode))
1650 goto check_inval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
1652 /* can not safely grab the rename sem here if rename calls revalidate
1653 since that would deadlock */
Jeff Laytondf2cf172010-02-12 07:44:16 -05001654 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301656 rc = -ENOMEM;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001657 goto check_inval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 }
Jeff Laytondf2cf172010-02-12 07:44:16 -05001659
Steve Frenchf19159d2010-04-21 04:12:10 +00001660 cFYI(1, "Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
Jeff Laytondf2cf172010-02-12 07:44:16 -05001661 "jiffies %ld", full_path, inode, inode->i_count.counter,
Steve Frenchf19159d2010-04-21 04:12:10 +00001662 dentry, dentry->d_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
Jeff Laytona6e8a842010-09-20 16:01:33 -07001664 if (cifs_sb_tcon(CIFS_SB(sb))->unix_ext)
Jeff Laytondf2cf172010-02-12 07:44:16 -05001665 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
1666 else
1667 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
1668 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Jeff Laytondf2cf172010-02-12 07:44:16 -05001670check_inval:
1671 if (CIFS_I(inode)->invalid_mapping)
1672 cifs_invalidate_mapping(inode);
Steve French50c2f752007-07-13 00:33:32 +00001673
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 kfree(full_path);
1675 FreeXid(xid);
1676 return rc;
1677}
1678
1679int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1680 struct kstat *stat)
1681{
Jeff Laytondf2cf172010-02-12 07:44:16 -05001682 int err = cifs_revalidate_dentry(dentry);
Steve French5fe14c82006-11-07 19:26:33 +00001683 if (!err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 generic_fillattr(dentry->d_inode, stat);
Steve French5fe14c82006-11-07 19:26:33 +00001685 stat->blksize = CIFS_MAX_MSGSIZE;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001686 stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
Steve French5fe14c82006-11-07 19:26:33 +00001687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 return err;
1689}
1690
1691static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1692{
1693 pgoff_t index = from >> PAGE_CACHE_SHIFT;
1694 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1695 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 int rc = 0;
1697
1698 page = grab_cache_page(mapping, index);
1699 if (!page)
1700 return -ENOMEM;
1701
Christoph Lametereebd2aa2008-02-04 22:28:29 -08001702 zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 unlock_page(page);
1704 page_cache_release(page);
1705 return rc;
1706}
1707
Christoph Hellwig1b947462010-07-18 17:51:21 -04001708static void cifs_setsize(struct inode *inode, loff_t offset)
Steve French3677db12007-02-26 16:46:11 +00001709{
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001710 loff_t oldsize;
Steve French3677db12007-02-26 16:46:11 +00001711
Steve Frenchba6a46a2007-02-26 20:06:29 +00001712 spin_lock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001713 oldsize = inode->i_size;
Steve French3677db12007-02-26 16:46:11 +00001714 i_size_write(inode, offset);
Steve Frenchba6a46a2007-02-26 20:06:29 +00001715 spin_unlock(&inode->i_lock);
Christoph Hellwig1b947462010-07-18 17:51:21 -04001716
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001717 truncate_pagecache(inode, oldsize, offset);
Steve French3677db12007-02-26 16:46:11 +00001718}
1719
Jeff Layton8efdbde2008-07-23 21:28:12 +00001720static int
1721cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1722 int xid, char *full_path)
1723{
1724 int rc;
1725 struct cifsFileInfo *open_file;
1726 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1727 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytonba00ba62010-09-20 16:01:31 -07001728 struct cifsTconInfo *pTcon = NULL;
Jeff Layton8efdbde2008-07-23 21:28:12 +00001729
1730 /*
1731 * To avoid spurious oplock breaks from server, in the case of
1732 * inodes that we already have open, avoid doing path based
1733 * setting of file size if we can do it by handle.
1734 * This keeps our caching token (oplock) and avoids timeouts
1735 * when the local oplock break takes longer to flush
1736 * writebehind data than the SMB timeout for the SetPathInfo
1737 * request would allow
1738 */
1739 open_file = find_writable_file(cifsInode);
1740 if (open_file) {
1741 __u16 nfid = open_file->netfid;
1742 __u32 npid = open_file->pid;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001743 pTcon = open_file->tcon;
Jeff Layton8efdbde2008-07-23 21:28:12 +00001744 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
1745 npid, false);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001746 cifsFileInfo_put(open_file);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001747 cFYI(1, "SetFSize for attrs rc = %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001748 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1749 unsigned int bytes_written;
1750 rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size,
1751 &bytes_written, NULL, NULL, 1);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001752 cFYI(1, "Wrt seteof rc %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001753 }
1754 } else
1755 rc = -EINVAL;
1756
1757 if (rc != 0) {
Jeff Laytonba00ba62010-09-20 16:01:31 -07001758 if (pTcon == NULL)
Jeff Laytona6e8a842010-09-20 16:01:33 -07001759 pTcon = cifs_sb_tcon(cifs_sb);
Jeff Laytonba00ba62010-09-20 16:01:31 -07001760
Jeff Layton8efdbde2008-07-23 21:28:12 +00001761 /* Set file size by pathname rather than by handle
1762 either because no valid, writeable file handle for
1763 it was found or because there was an error setting
1764 it by handle */
1765 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
1766 false, cifs_sb->local_nls,
1767 cifs_sb->mnt_cifs_flags &
1768 CIFS_MOUNT_MAP_SPECIAL_CHR);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001769 cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001770 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1771 __u16 netfid;
1772 int oplock = 0;
1773
1774 rc = SMBLegacyOpen(xid, pTcon, full_path,
1775 FILE_OPEN, GENERIC_WRITE,
1776 CREATE_NOT_DIR, &netfid, &oplock, NULL,
1777 cifs_sb->local_nls,
1778 cifs_sb->mnt_cifs_flags &
1779 CIFS_MOUNT_MAP_SPECIAL_CHR);
1780 if (rc == 0) {
1781 unsigned int bytes_written;
1782 rc = CIFSSMBWrite(xid, pTcon, netfid, 0,
1783 attrs->ia_size,
1784 &bytes_written, NULL,
1785 NULL, 1);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001786 cFYI(1, "wrt seteof rc %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001787 CIFSSMBClose(xid, pTcon, netfid);
1788 }
1789 }
1790 }
1791
1792 if (rc == 0) {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001793 cifsInode->server_eof = attrs->ia_size;
Christoph Hellwig1b947462010-07-18 17:51:21 -04001794 cifs_setsize(inode, attrs->ia_size);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001795 cifs_truncate_page(inode->i_mapping, inode->i_size);
1796 }
1797
1798 return rc;
1799}
1800
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001801static int
1802cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1803{
1804 int rc;
1805 int xid;
1806 char *full_path = NULL;
1807 struct inode *inode = direntry->d_inode;
1808 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1809 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytonba00ba62010-09-20 16:01:31 -07001810 struct cifsTconInfo *pTcon;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001811 struct cifs_unix_set_info_args *args = NULL;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001812 struct cifsFileInfo *open_file;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001813
Joe Perchesb6b38f72010-04-21 03:50:45 +00001814 cFYI(1, "setattr_unix on file %s attrs->ia_valid=0x%x",
1815 direntry->d_name.name, attrs->ia_valid);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001816
1817 xid = GetXid();
1818
Christoph Hellwigdb78b872010-06-04 11:30:03 +02001819 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
1820 attrs->ia_valid |= ATTR_FORCE;
1821
1822 rc = inode_change_ok(inode, attrs);
1823 if (rc < 0)
1824 goto out;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001825
1826 full_path = build_path_from_dentry(direntry);
1827 if (full_path == NULL) {
1828 rc = -ENOMEM;
1829 goto out;
1830 }
1831
Jeff Layton0f4d6342009-03-26 13:35:37 -04001832 /*
1833 * Attempt to flush data before changing attributes. We need to do
1834 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
1835 * ownership or mode then we may also need to do this. Here, we take
1836 * the safe way out and just do the flush on all setattr requests. If
1837 * the flush returns error, store it to report later and continue.
1838 *
1839 * BB: This should be smarter. Why bother flushing pages that
1840 * will be truncated anyway? Also, should we error out here if
1841 * the flush returns error?
1842 */
1843 rc = filemap_write_and_wait(inode->i_mapping);
1844 if (rc != 0) {
1845 cifsInode->write_behind_rc = rc;
1846 rc = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001847 }
1848
1849 if (attrs->ia_valid & ATTR_SIZE) {
1850 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1851 if (rc != 0)
1852 goto out;
1853 }
1854
1855 /* skip mode change if it's just for clearing setuid/setgid */
1856 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1857 attrs->ia_valid &= ~ATTR_MODE;
1858
1859 args = kmalloc(sizeof(*args), GFP_KERNEL);
1860 if (args == NULL) {
1861 rc = -ENOMEM;
1862 goto out;
1863 }
1864
1865 /* set up the struct */
1866 if (attrs->ia_valid & ATTR_MODE)
1867 args->mode = attrs->ia_mode;
1868 else
1869 args->mode = NO_CHANGE_64;
1870
1871 if (attrs->ia_valid & ATTR_UID)
1872 args->uid = attrs->ia_uid;
1873 else
1874 args->uid = NO_CHANGE_64;
1875
1876 if (attrs->ia_valid & ATTR_GID)
1877 args->gid = attrs->ia_gid;
1878 else
1879 args->gid = NO_CHANGE_64;
1880
1881 if (attrs->ia_valid & ATTR_ATIME)
1882 args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
1883 else
1884 args->atime = NO_CHANGE_64;
1885
1886 if (attrs->ia_valid & ATTR_MTIME)
1887 args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
1888 else
1889 args->mtime = NO_CHANGE_64;
1890
1891 if (attrs->ia_valid & ATTR_CTIME)
1892 args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
1893 else
1894 args->ctime = NO_CHANGE_64;
1895
1896 args->device = 0;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001897 open_file = find_writable_file(cifsInode);
1898 if (open_file) {
1899 u16 nfid = open_file->netfid;
1900 u32 npid = open_file->pid;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001901 pTcon = open_file->tcon;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001902 rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001903 cifsFileInfo_put(open_file);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001904 } else {
Jeff Laytona6e8a842010-09-20 16:01:33 -07001905 pTcon = cifs_sb_tcon(cifs_sb);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001906 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
Jeff Layton01ea95e2009-07-09 20:02:49 -04001907 cifs_sb->local_nls,
1908 cifs_sb->mnt_cifs_flags &
1909 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001910 }
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001911
Christoph Hellwig10257742010-06-04 11:30:02 +02001912 if (rc)
1913 goto out;
Steve Frenchccd4bb12010-02-08 17:39:58 +00001914
Christoph Hellwig10257742010-06-04 11:30:02 +02001915 if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig1b947462010-07-18 17:51:21 -04001916 attrs->ia_size != i_size_read(inode))
1917 truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02001918
1919 setattr_copy(inode, attrs);
1920 mark_inode_dirty(inode);
1921
1922 /* force revalidate when any of these times are set since some
1923 of the fs types (eg ext3, fat) do not have fine enough
1924 time granularity to match protocol, and we do not have a
1925 a way (yet) to query the server fs's time granularity (and
1926 whether it rounds times down).
1927 */
1928 if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
1929 cifsInode->time = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001930out:
1931 kfree(args);
1932 kfree(full_path);
1933 FreeXid(xid);
1934 return rc;
1935}
1936
Jeff Layton0510eeb2008-08-02 07:26:12 -04001937static int
1938cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939{
1940 int xid;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001941 struct inode *inode = direntry->d_inode;
1942 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001943 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 char *full_path = NULL;
1945 int rc = -EACCES;
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001946 __u32 dosattr = 0;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001947 __u64 mode = NO_CHANGE_64;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 xid = GetXid();
1950
Joe Perchesb6b38f72010-04-21 03:50:45 +00001951 cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
1952 direntry->d_name.name, attrs->ia_valid);
Steve French6473a552005-11-29 20:20:10 -08001953
Christoph Hellwigdb78b872010-06-04 11:30:03 +02001954 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
1955 attrs->ia_valid |= ATTR_FORCE;
1956
1957 rc = inode_change_ok(inode, attrs);
1958 if (rc < 0) {
1959 FreeXid(xid);
1960 return rc;
Steve French6473a552005-11-29 20:20:10 -08001961 }
Steve French50c2f752007-07-13 00:33:32 +00001962
Steve French7f573562005-08-30 11:32:14 -07001963 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301965 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301967 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969
Jeff Layton0f4d6342009-03-26 13:35:37 -04001970 /*
1971 * Attempt to flush data before changing attributes. We need to do
1972 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
1973 * ownership or mode then we may also need to do this. Here, we take
1974 * the safe way out and just do the flush on all setattr requests. If
1975 * the flush returns error, store it to report later and continue.
1976 *
1977 * BB: This should be smarter. Why bother flushing pages that
1978 * will be truncated anyway? Also, should we error out here if
1979 * the flush returns error?
1980 */
1981 rc = filemap_write_and_wait(inode->i_mapping);
1982 if (rc != 0) {
1983 cifsInode->write_behind_rc = rc;
1984 rc = 0;
Steve French50531442008-03-14 19:21:31 +00001985 }
Jeff Laytoncea21802007-11-20 23:19:03 +00001986
Steve French50531442008-03-14 19:21:31 +00001987 if (attrs->ia_valid & ATTR_SIZE) {
Jeff Layton8efdbde2008-07-23 21:28:12 +00001988 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1989 if (rc != 0)
Steve Frenche30dcf32005-09-20 20:49:16 -07001990 goto cifs_setattr_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 }
Jeff Layton4ca691a2008-05-22 09:33:34 -04001992
1993 /*
1994 * Without unix extensions we can't send ownership changes to the
1995 * server, so silently ignore them. This is consistent with how
1996 * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With
1997 * CIFSACL support + proper Windows to Unix idmapping, we may be
1998 * able to support this in the future.
1999 */
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002000 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
Jeff Layton4ca691a2008-05-22 09:33:34 -04002001 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
Jeff Laytond32c4f22007-10-18 03:05:22 -07002003 /* skip mode change if it's just for clearing setuid/setgid */
2004 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
2005 attrs->ia_valid &= ~ATTR_MODE;
2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 if (attrs->ia_valid & ATTR_MODE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002008 cFYI(1, "Mode changed to 0%o", attrs->ia_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 mode = attrs->ia_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 }
2011
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002012 if (attrs->ia_valid & ATTR_MODE) {
Steve Frenchcdbce9c2005-11-19 21:04:52 -08002013 rc = 0;
Steve French97837582007-12-31 07:47:21 +00002014#ifdef CONFIG_CIFS_EXPERIMENTAL
2015 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
Jeff Layton02eadef2008-05-09 21:26:11 +00002016 rc = mode_to_acl(inode, full_path, mode);
Jeff Layton51328612008-05-22 09:33:34 -04002017 else
Steve French97837582007-12-31 07:47:21 +00002018#endif
Jeff Layton51328612008-05-22 09:33:34 -04002019 if (((mode & S_IWUGO) == 0) &&
2020 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002021
2022 dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
2023
Jeff Layton51328612008-05-22 09:33:34 -04002024 /* fix up mode if we're not using dynperm */
2025 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
2026 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
2027 } else if ((mode & S_IWUGO) &&
2028 (cifsInode->cifsAttrs & ATTR_READONLY)) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002029
2030 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
2031 /* Attributes of 0 are ignored */
2032 if (dosattr == 0)
2033 dosattr |= ATTR_NORMAL;
Jeff Layton51328612008-05-22 09:33:34 -04002034
2035 /* reset local inode permissions to normal */
2036 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
2037 attrs->ia_mode &= ~(S_IALLUGO);
2038 if (S_ISDIR(inode->i_mode))
2039 attrs->ia_mode |=
2040 cifs_sb->mnt_dir_mode;
2041 else
2042 attrs->ia_mode |=
2043 cifs_sb->mnt_file_mode;
2044 }
2045 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
2046 /* ignore mode change - ATTR_READONLY hasn't changed */
2047 attrs->ia_valid &= ~ATTR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 }
2050
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002051 if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
2052 ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
2053 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
2054 /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055
Steve Frenche30dcf32005-09-20 20:49:16 -07002056 /* Even if error on time set, no sense failing the call if
2057 the server would set the time to a reasonable value anyway,
2058 and this check ensures that we are not being called from
2059 sys_utimes in which case we ought to fail the call back to
2060 the user when the server rejects the call */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002061 if ((rc) && (attrs->ia_valid &
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002062 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
Steve Frenche30dcf32005-09-20 20:49:16 -07002063 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 }
2065
2066 /* do not need local check to inode_check_ok since the server does
2067 that */
Christoph Hellwig10257742010-06-04 11:30:02 +02002068 if (rc)
2069 goto cifs_setattr_exit;
2070
2071 if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig1b947462010-07-18 17:51:21 -04002072 attrs->ia_size != i_size_read(inode))
2073 truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02002074
2075 setattr_copy(inode, attrs);
2076 mark_inode_dirty(inode);
2077 return 0;
2078
Steve Frenche30dcf32005-09-20 20:49:16 -07002079cifs_setattr_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 kfree(full_path);
2081 FreeXid(xid);
2082 return rc;
2083}
2084
Jeff Layton0510eeb2008-08-02 07:26:12 -04002085int
2086cifs_setattr(struct dentry *direntry, struct iattr *attrs)
2087{
2088 struct inode *inode = direntry->d_inode;
2089 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytona6e8a842010-09-20 16:01:33 -07002090 struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb);
Jeff Layton0510eeb2008-08-02 07:26:12 -04002091
2092 if (pTcon->unix_ext)
2093 return cifs_setattr_unix(direntry, attrs);
2094
2095 return cifs_setattr_nounix(direntry, attrs);
2096
2097 /* BB: add cifs_setattr_legacy for really old servers */
2098}
2099
Steve French99ee4db2007-02-27 05:35:17 +00002100#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101void cifs_delete_inode(struct inode *inode)
2102{
Joe Perchesb6b38f72010-04-21 03:50:45 +00002103 cFYI(1, "In cifs_delete_inode, inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 /* may have to add back in if and when safe distributed caching of
2105 directories added e.g. via FindNotify */
2106}
Steve French99ee4db2007-02-27 05:35:17 +00002107#endif