blob: 723daaccbd0e75b87e10169485de124f504d5fd2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/inode.c
3 *
Steve French8be0ed42008-12-05 19:14:12 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
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>
23#include <linux/pagemap.h>
24#include <asm/div64.h>
25#include "cifsfs.h"
26#include "cifspdu.h"
27#include "cifsglob.h"
28#include "cifsproto.h"
29#include "cifs_debug.h"
30#include "cifs_fs_sb.h"
31
Christoph Hellwig70eff552008-02-15 20:55:05 +000032
Igor Mammedov79626702008-03-09 03:44:18 +000033static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
Christoph Hellwig70eff552008-02-15 20:55:05 +000034{
35 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
36
37 switch (inode->i_mode & S_IFMT) {
38 case S_IFREG:
39 inode->i_op = &cifs_file_inode_ops;
40 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
41 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
42 inode->i_fop = &cifs_file_direct_nobrl_ops;
43 else
44 inode->i_fop = &cifs_file_direct_ops;
45 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
46 inode->i_fop = &cifs_file_nobrl_ops;
47 else { /* not direct, send byte range locks */
48 inode->i_fop = &cifs_file_ops;
49 }
50
51
52 /* check if server can support readpages */
53 if (cifs_sb->tcon->ses->server->maxBuf <
54 PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
55 inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
56 else
57 inode->i_data.a_ops = &cifs_addr_ops;
58 break;
59 case S_IFDIR:
Steve Frenchbc5b6e22008-03-11 21:07:48 +000060#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov79626702008-03-09 03:44:18 +000061 if (is_dfs_referral) {
62 inode->i_op = &cifs_dfs_referral_inode_operations;
63 } else {
Steve Frenchbc5b6e22008-03-11 21:07:48 +000064#else /* NO DFS support, treat as a directory */
65 {
66#endif
Igor Mammedov79626702008-03-09 03:44:18 +000067 inode->i_op = &cifs_dir_inode_ops;
68 inode->i_fop = &cifs_dir_ops;
69 }
Christoph Hellwig70eff552008-02-15 20:55:05 +000070 break;
71 case S_IFLNK:
72 inode->i_op = &cifs_symlink_inode_ops;
73 break;
74 default:
75 init_special_inode(inode, inode->i_mode, inode->i_rdev);
76 break;
77 }
78}
79
Jeff Laytondf2cf172010-02-12 07:44:16 -050080/* check inode attributes against fattr. If they don't match, tag the
81 * inode for cache invalidation
82 */
83static void
84cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
85{
86 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
87
88 cFYI(1, ("%s: revalidating inode %llu", __func__, cifs_i->uniqueid));
89
90 if (inode->i_state & I_NEW) {
91 cFYI(1, ("%s: inode %llu is new", __func__, cifs_i->uniqueid));
92 return;
93 }
94
95 /* don't bother with revalidation if we have an oplock */
96 if (cifs_i->clientCanCacheRead) {
97 cFYI(1, ("%s: inode %llu is oplocked", __func__,
98 cifs_i->uniqueid));
99 return;
100 }
101
102 /* revalidate if mtime or size have changed */
103 if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) &&
104 cifs_i->server_eof == fattr->cf_eof) {
105 cFYI(1, ("%s: inode %llu is unchanged", __func__,
106 cifs_i->uniqueid));
107 return;
108 }
109
110 cFYI(1, ("%s: invalidating inode %llu mapping", __func__,
111 cifs_i->uniqueid));
112 cifs_i->invalid_mapping = true;
113}
114
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400115/* populate an inode with info from a cifs_fattr struct */
116void
117cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
Christoph Hellwig75f12982008-02-25 20:25:21 +0000118{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400119 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400120 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
121 unsigned long oldtime = cifs_i->time;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000122
Jeff Laytondf2cf172010-02-12 07:44:16 -0500123 cifs_revalidate_cache(inode, fattr);
124
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400125 inode->i_atime = fattr->cf_atime;
126 inode->i_mtime = fattr->cf_mtime;
127 inode->i_ctime = fattr->cf_ctime;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400128 inode->i_rdev = fattr->cf_rdev;
129 inode->i_nlink = fattr->cf_nlink;
130 inode->i_uid = fattr->cf_uid;
131 inode->i_gid = fattr->cf_gid;
132
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400133 /* if dynperm is set, don't clobber existing mode */
134 if (inode->i_state & I_NEW ||
135 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
136 inode->i_mode = fattr->cf_mode;
137
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400138 cifs_i->cifsAttrs = fattr->cf_cifsattrs;
139 cifs_i->uniqueid = fattr->cf_uniqueid;
140
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400141 if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
142 cifs_i->time = 0;
143 else
144 cifs_i->time = jiffies;
145
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400146 cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400147 oldtime, cifs_i->time));
148
149 cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000150
Jeff Layton835a36c2010-02-10 16:21:33 -0500151 cifs_i->server_eof = fattr->cf_eof;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000152 /*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400153 * Can't safely change the file size here if the client is writing to
154 * it due to potential races.
Christoph Hellwig75f12982008-02-25 20:25:21 +0000155 */
Christoph Hellwig75f12982008-02-25 20:25:21 +0000156 spin_lock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400157 if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
158 i_size_write(inode, fattr->cf_eof);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000159
160 /*
161 * i_blocks is not related to (i_size / i_blksize),
162 * but instead 512 byte (2**9) size is required for
163 * calculating num blocks.
164 */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400165 inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000166 }
167 spin_unlock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400168
169 cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000170}
171
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400172/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
173void
174cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
175 struct cifs_sb_info *cifs_sb)
176{
177 memset(fattr, 0, sizeof(*fattr));
178 fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
179 fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
180 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
181
182 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
183 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
184 fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
185 fattr->cf_mode = le64_to_cpu(info->Permissions);
186
187 /*
188 * Since we set the inode type below we need to mask off
189 * to avoid strange results if bits set above.
190 */
191 fattr->cf_mode &= ~S_IFMT;
192 switch (le32_to_cpu(info->Type)) {
193 case UNIX_FILE:
194 fattr->cf_mode |= S_IFREG;
195 fattr->cf_dtype = DT_REG;
196 break;
197 case UNIX_SYMLINK:
198 fattr->cf_mode |= S_IFLNK;
199 fattr->cf_dtype = DT_LNK;
200 break;
201 case UNIX_DIR:
202 fattr->cf_mode |= S_IFDIR;
203 fattr->cf_dtype = DT_DIR;
204 break;
205 case UNIX_CHARDEV:
206 fattr->cf_mode |= S_IFCHR;
207 fattr->cf_dtype = DT_CHR;
208 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
209 le64_to_cpu(info->DevMinor) & MINORMASK);
210 break;
211 case UNIX_BLOCKDEV:
212 fattr->cf_mode |= S_IFBLK;
213 fattr->cf_dtype = DT_BLK;
214 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
215 le64_to_cpu(info->DevMinor) & MINORMASK);
216 break;
217 case UNIX_FIFO:
218 fattr->cf_mode |= S_IFIFO;
219 fattr->cf_dtype = DT_FIFO;
220 break;
221 case UNIX_SOCKET:
222 fattr->cf_mode |= S_IFSOCK;
223 fattr->cf_dtype = DT_SOCK;
224 break;
225 default:
226 /* safest to call it a file if we do not know */
227 fattr->cf_mode |= S_IFREG;
228 fattr->cf_dtype = DT_REG;
229 cFYI(1, ("unknown type %d", le32_to_cpu(info->Type)));
230 break;
231 }
232
233 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
234 fattr->cf_uid = cifs_sb->mnt_uid;
235 else
236 fattr->cf_uid = le64_to_cpu(info->Uid);
237
238 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
239 fattr->cf_gid = cifs_sb->mnt_gid;
240 else
241 fattr->cf_gid = le64_to_cpu(info->Gid);
242
243 fattr->cf_nlink = le64_to_cpu(info->Nlinks);
244}
Steve Frenchb9a32602008-05-20 21:52:32 +0000245
246/*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400247 * Fill a cifs_fattr struct with fake inode info.
248 *
249 * Needed to setup cifs_fattr data for the directory which is the
250 * junction to the new submount (ie to setup the fake directory
251 * which represents a DFS referral).
Steve Frenchb9a32602008-05-20 21:52:32 +0000252 */
Steve Frenchf1230c92009-07-22 23:13:01 +0000253static void
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400254cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
Steve French0e4bbde2008-05-20 19:50:46 +0000255{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400256 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Steve French0e4bbde2008-05-20 19:50:46 +0000257
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400258 cFYI(1, ("creating fake fattr for DFS referral"));
Steve French0e4bbde2008-05-20 19:50:46 +0000259
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400260 memset(fattr, 0, sizeof(*fattr));
261 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
262 fattr->cf_uid = cifs_sb->mnt_uid;
263 fattr->cf_gid = cifs_sb->mnt_gid;
264 fattr->cf_atime = CURRENT_TIME;
265 fattr->cf_ctime = CURRENT_TIME;
266 fattr->cf_mtime = CURRENT_TIME;
267 fattr->cf_nlink = 2;
268 fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
Steve French0e4bbde2008-05-20 19:50:46 +0000269}
270
Jeff Laytonabab0952010-02-12 07:44:18 -0500271int cifs_get_file_info_unix(struct file *filp)
272{
273 int rc;
274 int xid;
275 FILE_UNIX_BASIC_INFO find_data;
276 struct cifs_fattr fattr;
277 struct inode *inode = filp->f_path.dentry->d_inode;
278 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
279 struct cifsTconInfo *tcon = cifs_sb->tcon;
280 struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
281
282 xid = GetXid();
283 rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
284 if (!rc) {
285 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
286 } else if (rc == -EREMOTE) {
287 cifs_create_dfs_fattr(&fattr, inode->i_sb);
288 rc = 0;
289 }
290
291 cifs_fattr_to_inode(inode, &fattr);
292 FreeXid(xid);
293 return rc;
294}
295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296int cifs_get_inode_info_unix(struct inode **pinode,
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400297 const unsigned char *full_path,
298 struct super_block *sb, int xid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400300 int rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000301 FILE_UNIX_BASIC_INFO find_data;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400302 struct cifs_fattr fattr;
303 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400306 tcon = cifs_sb->tcon;
Steve French646dd532008-05-15 01:50:56 +0000307 cFYI(1, ("Getting info on %s", full_path));
Igor Mammedov79626702008-03-09 03:44:18 +0000308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 /* could have done a find first instead but this returns more info */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400310 rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
Steve French737b7582005-04-28 22:41:06 -0700311 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
312 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400313
314 if (!rc) {
315 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
316 } else if (rc == -EREMOTE) {
317 cifs_create_dfs_fattr(&fattr, sb);
Jeff Laytone911d0c2008-07-12 13:47:59 -0700318 rc = 0;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400319 } else {
320 return rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000321 }
322
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400323 if (*pinode == NULL) {
324 /* get new inode */
325 *pinode = cifs_iget(sb, &fattr);
326 if (!*pinode)
327 rc = -ENOMEM;
328 } else {
329 /* we already have inode, update it */
330 cifs_fattr_to_inode(*pinode, &fattr);
331 }
Steve French0e4bbde2008-05-20 19:50:46 +0000332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 return rc;
334}
335
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400336static int
337cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
338 struct cifs_sb_info *cifs_sb, int xid)
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800339{
340 int rc;
Steve French4b18f2a2008-04-29 00:06:05 +0000341 int oplock = 0;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800342 __u16 netfid;
343 struct cifsTconInfo *pTcon = cifs_sb->tcon;
Steve French86c96b42005-11-18 20:25:31 -0800344 char buf[24];
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800345 unsigned int bytes_read;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000346 char *pbuf;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800347
348 pbuf = buf;
349
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400350 fattr->cf_mode &= ~S_IFMT;
351
352 if (fattr->cf_eof == 0) {
353 fattr->cf_mode |= S_IFIFO;
354 fattr->cf_dtype = DT_FIFO;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800355 return 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400356 } else if (fattr->cf_eof < 8) {
357 fattr->cf_mode |= S_IFREG;
358 fattr->cf_dtype = DT_REG;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800359 return -EINVAL; /* EOPNOTSUPP? */
360 }
Steve French50c2f752007-07-13 00:33:32 +0000361
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800362 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
363 CREATE_NOT_DIR, &netfid, &oplock, NULL,
364 cifs_sb->local_nls,
365 cifs_sb->mnt_cifs_flags &
366 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000367 if (rc == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -0800368 int buf_type = CIFS_NO_BUFFER;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800369 /* Read header */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400370 rc = CIFSSMBRead(xid, pTcon, netfid,
Steve French86c96b42005-11-18 20:25:31 -0800371 24 /* length */, 0 /* offset */,
Steve Frenchec637e32005-12-12 20:53:18 -0800372 &bytes_read, &pbuf, &buf_type);
Steve French4523cc32007-04-30 20:13:06 +0000373 if ((rc == 0) && (bytes_read >= 8)) {
374 if (memcmp("IntxBLK", pbuf, 8) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000375 cFYI(1, ("Block device"));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400376 fattr->cf_mode |= S_IFBLK;
377 fattr->cf_dtype = DT_BLK;
Steve French4523cc32007-04-30 20:13:06 +0000378 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800379 /* we have enough to decode dev num */
380 __u64 mjr; /* major */
381 __u64 mnr; /* minor */
382 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
383 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400384 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve French86c96b42005-11-18 20:25:31 -0800385 }
Steve French4523cc32007-04-30 20:13:06 +0000386 } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000387 cFYI(1, ("Char device"));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400388 fattr->cf_mode |= S_IFCHR;
389 fattr->cf_dtype = DT_CHR;
Steve French4523cc32007-04-30 20:13:06 +0000390 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800391 /* we have enough to decode dev num */
392 __u64 mjr; /* major */
393 __u64 mnr; /* minor */
394 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
395 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400396 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000397 }
Steve French4523cc32007-04-30 20:13:06 +0000398 } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000399 cFYI(1, ("Symlink"));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400400 fattr->cf_mode |= S_IFLNK;
401 fattr->cf_dtype = DT_LNK;
Steve French86c96b42005-11-18 20:25:31 -0800402 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400403 fattr->cf_mode |= S_IFREG; /* file? */
404 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000405 rc = -EOPNOTSUPP;
Steve French86c96b42005-11-18 20:25:31 -0800406 }
Steve French3020a1f2005-11-18 11:31:10 -0800407 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400408 fattr->cf_mode |= S_IFREG; /* then it is a file */
409 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000410 rc = -EOPNOTSUPP; /* or some unknown SFU type */
411 }
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800412 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800413 }
414 return rc;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800415}
416
Steve French9e294f12005-11-17 16:59:21 -0800417#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
418
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400419/*
420 * Fetch mode bits as provided by SFU.
421 *
422 * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
423 */
424static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
425 struct cifs_sb_info *cifs_sb, int xid)
Steve French9e294f12005-11-17 16:59:21 -0800426{
Steve French3020a1f2005-11-18 11:31:10 -0800427#ifdef CONFIG_CIFS_XATTR
Steve French9e294f12005-11-17 16:59:21 -0800428 ssize_t rc;
429 char ea_value[4];
430 __u32 mode;
431
Jeff Layton31c05192010-02-10 16:18:26 -0500432 rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS",
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400433 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
434 cifs_sb->mnt_cifs_flags &
435 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4523cc32007-04-30 20:13:06 +0000436 if (rc < 0)
Steve French9e294f12005-11-17 16:59:21 -0800437 return (int)rc;
438 else if (rc > 3) {
439 mode = le32_to_cpu(*((__le32 *)ea_value));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400440 fattr->cf_mode &= ~SFBITS_MASK;
441 cFYI(1, ("special bits 0%o org mode 0%o", mode,
442 fattr->cf_mode));
443 fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000444 cFYI(1, ("special mode bits 0%o", mode));
Steve French9e294f12005-11-17 16:59:21 -0800445 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400446
447 return 0;
Steve French3020a1f2005-11-18 11:31:10 -0800448#else
449 return -EOPNOTSUPP;
450#endif
Steve French9e294f12005-11-17 16:59:21 -0800451}
452
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400453/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
Steve Frenchf1230c92009-07-22 23:13:01 +0000454static void
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400455cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
456 struct cifs_sb_info *cifs_sb, bool adjust_tz)
Steve Frenchb9a32602008-05-20 21:52:32 +0000457{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400458 memset(fattr, 0, sizeof(*fattr));
459 fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
460 if (info->DeletePending)
461 fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
Steve Frenchb9a32602008-05-20 21:52:32 +0000462
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400463 if (info->LastAccessTime)
464 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
465 else
466 fattr->cf_atime = CURRENT_TIME;
467
468 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
469 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
470
471 if (adjust_tz) {
472 fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
473 fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
474 }
475
476 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
477 fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
478
479 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
480 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
481 fattr->cf_dtype = DT_DIR;
482 } else {
483 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
484 fattr->cf_dtype = DT_REG;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400485
Jeff Laytond0c280d2009-07-09 01:46:44 -0400486 /* clear write bits if ATTR_READONLY is set */
487 if (fattr->cf_cifsattrs & ATTR_READONLY)
488 fattr->cf_mode &= ~(S_IWUGO);
489 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400490
491 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
492
493 fattr->cf_uid = cifs_sb->mnt_uid;
494 fattr->cf_gid = cifs_sb->mnt_gid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000495}
496
Jeff Laytonabab0952010-02-12 07:44:18 -0500497int cifs_get_file_info(struct file *filp)
498{
499 int rc;
500 int xid;
501 FILE_ALL_INFO find_data;
502 struct cifs_fattr fattr;
503 struct inode *inode = filp->f_path.dentry->d_inode;
504 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
505 struct cifsTconInfo *tcon = cifs_sb->tcon;
506 struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
507
508 xid = GetXid();
509 rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
510 if (rc == -EOPNOTSUPP || rc == -EINVAL) {
511 /*
512 * FIXME: legacy server -- fall back to path-based call?
Steve Frenchff2157132010-03-09 20:30:42 +0000513 * for now, just skip revalidating and mark inode for
514 * immediate reval.
515 */
Jeff Laytonabab0952010-02-12 07:44:18 -0500516 rc = 0;
517 CIFS_I(inode)->time = 0;
518 goto cgfi_exit;
519 } else if (rc == -EREMOTE) {
520 cifs_create_dfs_fattr(&fattr, inode->i_sb);
521 rc = 0;
522 } else if (rc)
523 goto cgfi_exit;
524
525 /*
526 * don't bother with SFU junk here -- just mark inode as needing
527 * revalidation.
528 */
529 cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
530 fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
531 fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
532 cifs_fattr_to_inode(inode, &fattr);
533cgfi_exit:
534 FreeXid(xid);
535 return rc;
536}
537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538int cifs_get_inode_info(struct inode **pinode,
Steve French646dd532008-05-15 01:50:56 +0000539 const unsigned char *full_path, FILE_ALL_INFO *pfindData,
Steve French8b1327f2008-03-14 22:37:16 +0000540 struct super_block *sb, int xid, const __u16 *pfid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400542 int rc = 0, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 struct cifsTconInfo *pTcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 char *buf = NULL;
Steve French5ade9de2008-05-02 20:56:23 +0000546 bool adjustTZ = false;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400547 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 pTcon = cifs_sb->tcon;
Steve French646dd532008-05-15 01:50:56 +0000550 cFYI(1, ("Getting info on %s", full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700552 if ((pfindData == NULL) && (*pinode != NULL)) {
553 if (CIFS_I(*pinode)->clientCanCacheRead) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000554 cFYI(1, ("No need to revalidate cached inode sizes"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 return rc;
556 }
557 }
558
559 /* if file info not passed in then get it from server */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700560 if (pfindData == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700562 if (buf == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 return -ENOMEM;
564 pfindData = (FILE_ALL_INFO *)buf;
Igor Mammedov79626702008-03-09 03:44:18 +0000565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 /* could do find first instead but this returns more info */
Igor Mammedov79626702008-03-09 03:44:18 +0000567 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +0000568 0 /* not legacy */,
Steve French6b8edfe2005-08-23 20:26:03 -0700569 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700570 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French6b8edfe2005-08-23 20:26:03 -0700571 /* BB optimize code so we do not make the above call
572 when server claims no NT SMB support and the above call
573 failed at least once - set flag in tcon or mount */
Steve French4523cc32007-04-30 20:13:06 +0000574 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
Igor Mammedov79626702008-03-09 03:44:18 +0000575 rc = SMBQueryInformation(xid, pTcon, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000576 pfindData, cifs_sb->local_nls,
Steve French6b8edfe2005-08-23 20:26:03 -0700577 cifs_sb->mnt_cifs_flags &
578 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4b18f2a2008-04-29 00:06:05 +0000579 adjustTZ = true;
Steve French6b8edfe2005-08-23 20:26:03 -0700580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400582
583 if (!rc) {
584 cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
585 cifs_sb, adjustTZ);
586 } else if (rc == -EREMOTE) {
587 cifs_create_dfs_fattr(&fattr, sb);
Steve Frenchb9a32602008-05-20 21:52:32 +0000588 rc = 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400589 } else {
Igor Mammedov79626702008-03-09 03:44:18 +0000590 goto cgii_exit;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400593 /*
594 * If an inode wasn't passed in, then get the inode number
595 *
596 * Is an i_ino of zero legal? Can we use that to check if the server
597 * supports returning inode numbers? Are there other sanity checks we
598 * can use to ensure that the server is really filling in that field?
599 *
600 * We can not use the IndexNumber field by default from Windows or
601 * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
602 * CIFS spec claims that this value is unique within the scope of a
603 * share, and the windows docs hint that it's actually unique
604 * per-machine.
605 *
606 * There may be higher info levels that work but are there Windows
607 * server or network appliances for which IndexNumber field is not
608 * guaranteed unique?
609 */
Steve Frenchb9a32602008-05-20 21:52:32 +0000610 if (*pinode == NULL) {
Steve Frenchb9a32602008-05-20 21:52:32 +0000611 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
612 int rc1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Steve Frenchb9a32602008-05-20 21:52:32 +0000614 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400615 full_path, &fattr.cf_uniqueid,
Steve French737b7582005-04-28 22:41:06 -0700616 cifs_sb->local_nls,
617 cifs_sb->mnt_cifs_flags &
618 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500619 if (rc1 || !fattr.cf_uniqueid) {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400620 cFYI(1, ("GetSrvInodeNum rc %d", rc1));
621 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500622 cifs_autodisable_serverino(cifs_sb);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500623 }
Jeff Layton132ac7b2009-02-10 07:33:57 -0500624 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400625 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500626 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000627 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400628 fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000629 }
630
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400631 /* query for SFU type info if supported and needed */
632 if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
633 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
634 tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
635 if (tmprc)
636 cFYI(1, ("cifs_sfu_type failed: %d", tmprc));
Steve Frenchb9a32602008-05-20 21:52:32 +0000637 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000638
Steve Frenchb9a32602008-05-20 21:52:32 +0000639#ifdef CONFIG_CIFS_EXPERIMENTAL
640 /* fill in 0777 bits from ACL */
641 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
642 cFYI(1, ("Getting mode bits from ACL"));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400643 cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
Steve Frenchb9a32602008-05-20 21:52:32 +0000644 }
645#endif
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400646
647 /* fill in remaining high mode bits e.g. SUID, VTX */
648 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
649 cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
650
651 if (!*pinode) {
652 *pinode = cifs_iget(sb, &fattr);
653 if (!*pinode)
654 rc = -ENOMEM;
655 } else {
656 cifs_fattr_to_inode(*pinode, &fattr);
Steve Frenchb9a32602008-05-20 21:52:32 +0000657 }
658
Igor Mammedov79626702008-03-09 03:44:18 +0000659cgii_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 kfree(buf);
661 return rc;
662}
663
Steve French7f8ed422007-09-28 22:28:55 +0000664static const struct inode_operations cifs_ipc_inode_ops = {
665 .lookup = cifs_lookup,
666};
667
Igor Mammedove4cce942009-02-10 14:10:26 +0300668char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
Steve French8be0ed42008-12-05 19:14:12 +0000669{
670 int pplen = cifs_sb->prepathlen;
671 int dfsplen;
672 char *full_path = NULL;
673
674 /* if no prefix path, simply set path to the root of share to "" */
675 if (pplen == 0) {
676 full_path = kmalloc(1, GFP_KERNEL);
677 if (full_path)
678 full_path[0] = 0;
679 return full_path;
680 }
681
682 if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
683 dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
684 else
685 dfsplen = 0;
686
687 full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
688 if (full_path == NULL)
689 return full_path;
690
691 if (dfsplen) {
692 strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
693 /* switch slash direction in prepath depending on whether
694 * windows or posix style path names
695 */
696 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
697 int i;
698 for (i = 0; i < dfsplen; i++) {
699 if (full_path[i] == '\\')
700 full_path[i] = '/';
701 }
702 }
703 }
704 strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
705 full_path[dfsplen + pplen] = 0; /* add trailing null */
706 return full_path;
707}
708
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400709static int
710cifs_find_inode(struct inode *inode, void *opaque)
711{
712 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
713
714 if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
715 return 0;
716
717 return 1;
718}
719
720static int
721cifs_init_inode(struct inode *inode, void *opaque)
722{
723 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
724
725 CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
726 return 0;
727}
728
729/* Given fattrs, get a corresponding inode */
730struct inode *
731cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
732{
733 unsigned long hash;
734 struct inode *inode;
735
736 cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid));
737
738 /* hash down to 32-bits on 32-bit arch */
739 hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
740
741 inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
742
743 /* we have fattrs in hand, update the inode */
744 if (inode) {
745 cifs_fattr_to_inode(inode, fattr);
746 if (sb->s_flags & MS_NOATIME)
747 inode->i_flags |= S_NOATIME | S_NOCMTIME;
748 if (inode->i_state & I_NEW) {
749 inode->i_ino = hash;
750 unlock_new_inode(inode);
751 }
752 }
753
754 return inode;
755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757/* gets root inode */
Jeff Laytonbd433d42009-05-27 09:37:34 -0400758struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
David Howellsce634ab2008-02-07 00:15:33 -0800760 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 struct cifs_sb_info *cifs_sb;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400762 struct inode *inode = NULL;
David Howellsce634ab2008-02-07 00:15:33 -0800763 long rc;
Steve French8be0ed42008-12-05 19:14:12 +0000764 char *full_path;
David Howellsce634ab2008-02-07 00:15:33 -0800765
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400766 cifs_sb = CIFS_SB(sb);
Igor Mammedove4cce942009-02-10 14:10:26 +0300767 full_path = cifs_build_path_to_root(cifs_sb);
Steve French8be0ed42008-12-05 19:14:12 +0000768 if (full_path == NULL)
769 return ERR_PTR(-ENOMEM);
Steve Frenchc18c8422007-07-18 23:21:09 +0000770
Steve French8be0ed42008-12-05 19:14:12 +0000771 xid = GetXid();
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400772 if (cifs_sb->tcon->unix_ext)
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400773 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400774 else
775 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
Steve French8be0ed42008-12-05 19:14:12 +0000776 xid, NULL);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400777
778 if (!inode)
779 return ERR_PTR(-ENOMEM);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400780
Steve French7f8ed422007-09-28 22:28:55 +0000781 if (rc && cifs_sb->tcon->ipc) {
782 cFYI(1, ("ipc connection - fake read inode"));
783 inode->i_mode |= S_IFDIR;
784 inode->i_nlink = 2;
785 inode->i_op = &cifs_ipc_inode_ops;
786 inode->i_fop = &simple_dir_operations;
787 inode->i_uid = cifs_sb->mnt_uid;
788 inode->i_gid = cifs_sb->mnt_gid;
Steve Frenchad661332008-08-12 14:14:40 +0000789 } else if (rc) {
Steve French8be0ed42008-12-05 19:14:12 +0000790 kfree(full_path);
David Howellsce634ab2008-02-07 00:15:33 -0800791 _FreeXid(xid);
792 iget_failed(inode);
793 return ERR_PTR(rc);
Steve French7f8ed422007-09-28 22:28:55 +0000794 }
795
David Howellsce634ab2008-02-07 00:15:33 -0800796
Steve French8be0ed42008-12-05 19:14:12 +0000797 kfree(full_path);
David Howellsce634ab2008-02-07 00:15:33 -0800798 /* can not call macro FreeXid here since in a void func
799 * TODO: This is no longer true
800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 _FreeXid(xid);
David Howellsce634ab2008-02-07 00:15:33 -0800802 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803}
804
Steve French388e57b2008-09-16 23:50:58 +0000805static int
806cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
807 char *full_path, __u32 dosattr)
808{
809 int rc;
810 int oplock = 0;
811 __u16 netfid;
812 __u32 netpid;
813 bool set_time = false;
814 struct cifsFileInfo *open_file;
815 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
816 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
817 struct cifsTconInfo *pTcon = cifs_sb->tcon;
818 FILE_BASIC_INFO info_buf;
819
Steve French1adcb712009-02-25 14:19:56 +0000820 if (attrs == NULL)
821 return -EINVAL;
822
Steve French388e57b2008-09-16 23:50:58 +0000823 if (attrs->ia_valid & ATTR_ATIME) {
824 set_time = true;
825 info_buf.LastAccessTime =
826 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
827 } else
828 info_buf.LastAccessTime = 0;
829
830 if (attrs->ia_valid & ATTR_MTIME) {
831 set_time = true;
832 info_buf.LastWriteTime =
833 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
834 } else
835 info_buf.LastWriteTime = 0;
836
837 /*
838 * Samba throws this field away, but windows may actually use it.
839 * Do not set ctime unless other time stamps are changed explicitly
840 * (i.e. by utimes()) since we would then have a mix of client and
841 * server times.
842 */
843 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
844 cFYI(1, ("CIFS - CTIME changed"));
845 info_buf.ChangeTime =
846 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
847 } else
848 info_buf.ChangeTime = 0;
849
850 info_buf.CreationTime = 0; /* don't change */
851 info_buf.Attributes = cpu_to_le32(dosattr);
852
853 /*
854 * If the file is already open for write, just use that fileid
855 */
856 open_file = find_writable_file(cifsInode);
857 if (open_file) {
858 netfid = open_file->netfid;
859 netpid = open_file->pid;
860 goto set_via_filehandle;
861 }
862
863 /*
864 * NT4 apparently returns success on this call, but it doesn't
865 * really work.
866 */
867 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
868 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
869 &info_buf, cifs_sb->local_nls,
870 cifs_sb->mnt_cifs_flags &
871 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +0000872 if (rc == 0) {
873 cifsInode->cifsAttrs = dosattr;
874 goto out;
875 } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
Steve French388e57b2008-09-16 23:50:58 +0000876 goto out;
877 }
878
879 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
880 "times not supported by this server"));
881 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
882 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
883 CREATE_NOT_DIR, &netfid, &oplock,
884 NULL, cifs_sb->local_nls,
885 cifs_sb->mnt_cifs_flags &
886 CIFS_MOUNT_MAP_SPECIAL_CHR);
887
888 if (rc != 0) {
889 if (rc == -EIO)
890 rc = -EINVAL;
891 goto out;
892 }
893
894 netpid = current->tgid;
895
896set_via_filehandle:
897 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
Steve Frenchd3889082008-09-24 19:22:52 +0000898 if (!rc)
899 cifsInode->cifsAttrs = dosattr;
900
Steve French388e57b2008-09-16 23:50:58 +0000901 if (open_file == NULL)
902 CIFSSMBClose(xid, pTcon, netfid);
903 else
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400904 cifsFileInfo_put(open_file);
Steve French388e57b2008-09-16 23:50:58 +0000905out:
906 return rc;
907}
908
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400909/*
910 * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
911 * and rename it to a random name that hopefully won't conflict with
912 * anything else.
913 */
914static int
Steve French32709582008-10-20 00:44:19 +0000915cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400916{
917 int oplock = 0;
918 int rc;
919 __u16 netfid;
Steve French32709582008-10-20 00:44:19 +0000920 struct inode *inode = dentry->d_inode;
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400921 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
922 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
923 struct cifsTconInfo *tcon = cifs_sb->tcon;
Steve French32709582008-10-20 00:44:19 +0000924 __u32 dosattr, origattr;
925 FILE_BASIC_INFO *info_buf = NULL;
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400926
927 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
Jeff Laytondd1db2d2008-10-16 19:27:12 -0400928 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400929 &netfid, &oplock, NULL, cifs_sb->local_nls,
930 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
931 if (rc != 0)
932 goto out;
933
Steve French32709582008-10-20 00:44:19 +0000934 origattr = cifsInode->cifsAttrs;
935 if (origattr == 0)
936 origattr |= ATTR_NORMAL;
937
938 dosattr = origattr & ~ATTR_READONLY;
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400939 if (dosattr == 0)
940 dosattr |= ATTR_NORMAL;
941 dosattr |= ATTR_HIDDEN;
942
Steve French32709582008-10-20 00:44:19 +0000943 /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
944 if (dosattr != origattr) {
945 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
946 if (info_buf == NULL) {
947 rc = -ENOMEM;
948 goto out_close;
949 }
950 info_buf->Attributes = cpu_to_le32(dosattr);
951 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
952 current->tgid);
953 /* although we would like to mark the file hidden
954 if that fails we will still try to rename it */
Steve French41346092008-10-20 18:24:42 +0000955 if (rc != 0)
Steve French32709582008-10-20 00:44:19 +0000956 cifsInode->cifsAttrs = dosattr;
957 else
958 dosattr = origattr; /* since not able to change them */
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400959 }
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400960
Jeff Laytondd1db2d2008-10-16 19:27:12 -0400961 /* rename the file */
962 rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400963 cifs_sb->mnt_cifs_flags &
964 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French32709582008-10-20 00:44:19 +0000965 if (rc != 0) {
966 rc = -ETXTBSY;
967 goto undo_setattr;
968 }
Jeff Layton6d22f092008-09-23 11:48:35 -0400969
Steve French32709582008-10-20 00:44:19 +0000970 /* try to set DELETE_ON_CLOSE */
971 if (!cifsInode->delete_pending) {
972 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
973 current->tgid);
974 /*
975 * some samba versions return -ENOENT when we try to set the
976 * file disposition here. Likely a samba bug, but work around
977 * it for now. This means that some cifsXXX files may hang
978 * around after they shouldn't.
979 *
980 * BB: remove this hack after more servers have the fix
981 */
982 if (rc == -ENOENT)
983 rc = 0;
984 else if (rc != 0) {
985 rc = -ETXTBSY;
986 goto undo_rename;
987 }
988 cifsInode->delete_pending = true;
989 }
Jeff Layton7ce86d52008-09-24 11:32:59 -0400990
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400991out_close:
992 CIFSSMBClose(xid, tcon, netfid);
993out:
Steve French32709582008-10-20 00:44:19 +0000994 kfree(info_buf);
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400995 return rc;
Steve French32709582008-10-20 00:44:19 +0000996
997 /*
998 * reset everything back to the original state. Don't bother
999 * dealing with errors here since we can't do anything about
1000 * them anyway.
1001 */
1002undo_rename:
1003 CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
1004 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1005 CIFS_MOUNT_MAP_SPECIAL_CHR);
1006undo_setattr:
1007 if (dosattr != origattr) {
1008 info_buf->Attributes = cpu_to_le32(origattr);
1009 if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1010 current->tgid))
1011 cifsInode->cifsAttrs = origattr;
1012 }
1013
1014 goto out_close;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001015}
1016
Steve Frenchff694522009-04-20 19:45:13 +00001017
1018/*
1019 * If dentry->d_inode is null (usually meaning the cached dentry
1020 * is a negative dentry) then we would attempt a standard SMB delete, but
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001021 * if that fails we can not attempt the fall back mechanisms on EACCESS
1022 * but will return the EACCESS to the caller. Note that the VFS does not call
Steve Frenchff694522009-04-20 19:45:13 +00001023 * unlink on negative dentries currently.
1024 */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001025int cifs_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026{
1027 int rc = 0;
1028 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 char *full_path = NULL;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001030 struct inode *inode = dentry->d_inode;
Steve Frenchff694522009-04-20 19:45:13 +00001031 struct cifsInodeInfo *cifs_inode;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001032 struct super_block *sb = dir->i_sb;
1033 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1034 struct cifsTconInfo *tcon = cifs_sb->tcon;
Steve French60502472008-10-07 18:42:52 +00001035 struct iattr *attrs = NULL;
1036 __u32 dosattr = 0, origattr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
Jeff Layton5f0319a2008-09-16 14:05:16 -04001038 cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
1040 xid = GetXid();
1041
Jeff Layton5f0319a2008-09-16 14:05:16 -04001042 /* Unlink can be called from rename so we can not take the
1043 * sb->s_vfs_rename_mutex here */
1044 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301046 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301048 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 }
Steve French2d785a52007-07-15 01:48:57 +00001050
Jeff Layton5f0319a2008-09-16 14:05:16 -04001051 if ((tcon->ses->capabilities & CAP_UNIX) &&
Steve French2d785a52007-07-15 01:48:57 +00001052 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Jeff Layton5f0319a2008-09-16 14:05:16 -04001053 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1054 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
Steve French2d785a52007-07-15 01:48:57 +00001055 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
1056 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1057 cFYI(1, ("posix del rc %d", rc));
1058 if ((rc == 0) || (rc == -ENOENT))
1059 goto psx_del_no_retry;
1060 }
1061
Steve French60502472008-10-07 18:42:52 +00001062retry_std_delete:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001063 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001064 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French60502472008-10-07 18:42:52 +00001065
Steve French2d785a52007-07-15 01:48:57 +00001066psx_del_no_retry:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 if (!rc) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001068 if (inode)
1069 drop_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 } else if (rc == -ENOENT) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001071 d_drop(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 } else if (rc == -ETXTBSY) {
Steve French32709582008-10-20 00:44:19 +00001073 rc = cifs_rename_pending_delete(full_path, dentry, xid);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001074 if (rc == 0)
1075 drop_nlink(inode);
Steve Frenchff694522009-04-20 19:45:13 +00001076 } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
Steve French388e57b2008-09-16 23:50:58 +00001077 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
1078 if (attrs == NULL) {
1079 rc = -ENOMEM;
1080 goto out_reval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 }
Steve French388e57b2008-09-16 23:50:58 +00001082
1083 /* try to reset dos attributes */
Steve Frenchff694522009-04-20 19:45:13 +00001084 cifs_inode = CIFS_I(inode);
1085 origattr = cifs_inode->cifsAttrs;
Steve French60502472008-10-07 18:42:52 +00001086 if (origattr == 0)
1087 origattr |= ATTR_NORMAL;
1088 dosattr = origattr & ~ATTR_READONLY;
Steve French388e57b2008-09-16 23:50:58 +00001089 if (dosattr == 0)
1090 dosattr |= ATTR_NORMAL;
1091 dosattr |= ATTR_HIDDEN;
1092
1093 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
Steve French388e57b2008-09-16 23:50:58 +00001094 if (rc != 0)
1095 goto out_reval;
Steve French60502472008-10-07 18:42:52 +00001096
1097 goto retry_std_delete;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 }
Steve French60502472008-10-07 18:42:52 +00001099
1100 /* undo the setattr if we errored out and it's needed */
1101 if (rc != 0 && dosattr != 0)
1102 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
1103
Steve French388e57b2008-09-16 23:50:58 +00001104out_reval:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001105 if (inode) {
Steve Frenchff694522009-04-20 19:45:13 +00001106 cifs_inode = CIFS_I(inode);
1107 cifs_inode->time = 0; /* will force revalidate to get info
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001108 when needed */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001109 inode->i_ctime = current_fs_time(sb);
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001110 }
Jeff Layton5f0319a2008-09-16 14:05:16 -04001111 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
Steve Frenchff694522009-04-20 19:45:13 +00001112 cifs_inode = CIFS_I(dir);
Steve French60502472008-10-07 18:42:52 +00001113 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
1115 kfree(full_path);
Steve French60502472008-10-07 18:42:52 +00001116 kfree(attrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 FreeXid(xid);
1118 return rc;
1119}
1120
1121int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
1122{
Jeff Layton6b37faa2008-10-06 21:54:41 +00001123 int rc = 0, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 int xid;
1125 struct cifs_sb_info *cifs_sb;
1126 struct cifsTconInfo *pTcon;
1127 char *full_path = NULL;
1128 struct inode *newinode = NULL;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001129 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Steve French6473a552005-11-29 20:20:10 -08001131 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 xid = GetXid();
1134
1135 cifs_sb = CIFS_SB(inode->i_sb);
1136 pTcon = cifs_sb->tcon;
1137
Steve French7f573562005-08-30 11:32:14 -07001138 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301140 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301142 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 }
Steve French50c2f752007-07-13 00:33:32 +00001144
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001145 if ((pTcon->ses->capabilities & CAP_UNIX) &&
1146 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Steve French2dd29d32007-04-23 22:07:35 +00001147 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
1148 u32 oplock = 0;
Steve Frenchf6d09982008-01-08 23:18:22 +00001149 FILE_UNIX_BASIC_INFO *pInfo =
Steve French2dd29d32007-04-23 22:07:35 +00001150 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001151 if (pInfo == NULL) {
Steve French2dd29d32007-04-23 22:07:35 +00001152 rc = -ENOMEM;
1153 goto mkdir_out;
1154 }
Steve French50c2f752007-07-13 00:33:32 +00001155
Al Viroce3b0f82009-03-29 19:08:22 -04001156 mode &= ~current_umask();
Steve French2dd29d32007-04-23 22:07:35 +00001157 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
1158 mode, NULL /* netfid */, pInfo, &oplock,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001159 full_path, cifs_sb->local_nls,
1160 cifs_sb->mnt_cifs_flags &
Steve French2dd29d32007-04-23 22:07:35 +00001161 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc45d7072007-09-17 02:04:21 +00001162 if (rc == -EOPNOTSUPP) {
1163 kfree(pInfo);
1164 goto mkdir_retry_old;
1165 } else if (rc) {
Steve French2dd29d32007-04-23 22:07:35 +00001166 cFYI(1, ("posix mkdir returned 0x%x", rc));
1167 d_drop(direntry);
1168 } else {
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001169 if (pInfo->Type == cpu_to_le32(-1)) {
1170 /* no return info, go query for it */
Steve French5a07cdf2007-09-16 23:12:47 +00001171 kfree(pInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001172 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001173 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001174/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
1175 to set uid/gid */
Steve French2dd29d32007-04-23 22:07:35 +00001176 inc_nlink(inode);
1177 if (pTcon->nocase)
1178 direntry->d_op = &cifs_ci_dentry_ops;
1179 else
1180 direntry->d_op = &cifs_dentry_ops;
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001181
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001182 cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
1183 newinode = cifs_iget(inode->i_sb, &fattr);
1184 if (!newinode) {
Steve French5a07cdf2007-09-16 23:12:47 +00001185 kfree(pInfo);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001186 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001187 }
Jeff Layton6b37faa2008-10-06 21:54:41 +00001188
Steve French2dd29d32007-04-23 22:07:35 +00001189 d_instantiate(direntry, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001190
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001191#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001192 cFYI(1, ("instantiated dentry %p %s to inode %p",
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001193 direntry, direntry->d_name.name, newinode));
1194
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001195 if (newinode->i_nlink != 2)
1196 cFYI(1, ("unexpected number of links %d",
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001197 newinode->i_nlink));
1198#endif
Steve French2dd29d32007-04-23 22:07:35 +00001199 }
1200 kfree(pInfo);
1201 goto mkdir_out;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001202 }
Steve Frenchc45d7072007-09-17 02:04:21 +00001203mkdir_retry_old:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -07001205 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
1206 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +00001208 cFYI(1, ("cifs_mkdir returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 d_drop(direntry);
1210 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001211mkdir_get_info:
Dave Hansend8c76e62006-09-30 23:29:04 -07001212 inc_nlink(inode);
Steve Frenchc18c8422007-07-18 23:21:09 +00001213 if (pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001215 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 else
1217 rc = cifs_get_inode_info(&newinode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +00001218 inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Steve Frenchb92327f2005-08-22 20:09:43 -07001220 if (pTcon->nocase)
1221 direntry->d_op = &cifs_ci_dentry_ops;
1222 else
1223 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 d_instantiate(direntry, newinode);
Steve French2dd29d32007-04-23 22:07:35 +00001225 /* setting nlink not necessary except in cases where we
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001226 * failed to get it from the server or was set bogus */
Steve French2dd29d32007-04-23 22:07:35 +00001227 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001228 direntry->d_inode->i_nlink = 2;
Jeff Layton95089912008-08-06 04:39:02 +00001229
Al Viroce3b0f82009-03-29 19:08:22 -04001230 mode &= ~current_umask();
Jeff Layton95089912008-08-06 04:39:02 +00001231 /* must turn on setgid bit if parent dir has it */
1232 if (inode->i_mode & S_ISGID)
1233 mode |= S_ISGID;
1234
Steve Frenchc18c8422007-07-18 23:21:09 +00001235 if (pTcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001236 struct cifs_unix_set_info_args args = {
1237 .mode = mode,
1238 .ctime = NO_CHANGE_64,
1239 .atime = NO_CHANGE_64,
1240 .mtime = NO_CHANGE_64,
1241 .device = 0,
1242 };
Steve Frenchd0d2f2d2005-06-02 15:12:36 -07001243 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
David Howellsa001e5b2008-11-14 10:38:47 +11001244 args.uid = (__u64)current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001245 if (inode->i_mode & S_ISGID)
1246 args.gid = (__u64)inode->i_gid;
1247 else
David Howellsa001e5b2008-11-14 10:38:47 +11001248 args.gid = (__u64)current_fsgid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 } else {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001250 args.uid = NO_CHANGE_64;
1251 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 }
Jeff Layton01ea95e2009-07-09 20:02:49 -04001253 CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
1254 cifs_sb->local_nls,
1255 cifs_sb->mnt_cifs_flags &
1256 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French3ce53fc2007-06-08 14:55:14 +00001257 } else {
Jeff Layton67750fb2008-05-09 22:28:02 +00001258 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1259 (mode & S_IWUGO) == 0) {
1260 FILE_BASIC_INFO pInfo;
Jeff Layton6b37faa2008-10-06 21:54:41 +00001261 struct cifsInodeInfo *cifsInode;
1262 u32 dosattrs;
1263
Jeff Layton67750fb2008-05-09 22:28:02 +00001264 memset(&pInfo, 0, sizeof(pInfo));
Jeff Layton6b37faa2008-10-06 21:54:41 +00001265 cifsInode = CIFS_I(newinode);
1266 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1267 pInfo.Attributes = cpu_to_le32(dosattrs);
1268 tmprc = CIFSSMBSetPathInfo(xid, pTcon,
1269 full_path, &pInfo,
1270 cifs_sb->local_nls,
Jeff Layton67750fb2008-05-09 22:28:02 +00001271 cifs_sb->mnt_cifs_flags &
1272 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +00001273 if (tmprc == 0)
1274 cifsInode->cifsAttrs = dosattrs;
Jeff Layton67750fb2008-05-09 22:28:02 +00001275 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001276 if (direntry->d_inode) {
Jeff Laytonb0fd30d2008-05-22 09:33:34 -04001277 if (cifs_sb->mnt_cifs_flags &
1278 CIFS_MOUNT_DYNPERM)
1279 direntry->d_inode->i_mode =
1280 (mode | S_IFDIR);
Steve French4e94a102008-05-23 18:22:46 +00001281
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001282 if (cifs_sb->mnt_cifs_flags &
Steve French6473a552005-11-29 20:20:10 -08001283 CIFS_MOUNT_SET_UID) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001284 direntry->d_inode->i_uid =
David Howellsa001e5b2008-11-14 10:38:47 +11001285 current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001286 if (inode->i_mode & S_ISGID)
1287 direntry->d_inode->i_gid =
1288 inode->i_gid;
1289 else
1290 direntry->d_inode->i_gid =
David Howellsa001e5b2008-11-14 10:38:47 +11001291 current_fsgid();
Steve French6473a552005-11-29 20:20:10 -08001292 }
1293 }
Steve French2a138ebb2005-11-29 21:22:19 -08001294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001296mkdir_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 kfree(full_path);
1298 FreeXid(xid);
1299 return rc;
1300}
1301
1302int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1303{
1304 int rc = 0;
1305 int xid;
1306 struct cifs_sb_info *cifs_sb;
1307 struct cifsTconInfo *pTcon;
1308 char *full_path = NULL;
1309 struct cifsInodeInfo *cifsInode;
1310
Steve French26a21b92006-05-31 18:05:34 +00001311 cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 xid = GetXid();
1314
1315 cifs_sb = CIFS_SB(inode->i_sb);
1316 pTcon = cifs_sb->tcon;
1317
Steve French7f573562005-08-30 11:32:14 -07001318 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301320 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301322 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 }
1324
Steve French737b7582005-04-28 22:41:06 -07001325 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1326 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
1328 if (!rc) {
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001329 drop_nlink(inode);
Steve French3677db12007-02-26 16:46:11 +00001330 spin_lock(&direntry->d_inode->i_lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001331 i_size_write(direntry->d_inode, 0);
Dave Hansence71ec32006-09-30 23:29:06 -07001332 clear_nlink(direntry->d_inode);
Steve French3677db12007-02-26 16:46:11 +00001333 spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
1335
1336 cifsInode = CIFS_I(direntry->d_inode);
1337 cifsInode->time = 0; /* force revalidate to go get info when
1338 needed */
Steve French42c24542009-01-13 22:03:55 +00001339
1340 cifsInode = CIFS_I(inode);
1341 cifsInode->time = 0; /* force revalidate to get parent dir info
1342 since cached search results now invalid */
1343
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1345 current_fs_time(inode->i_sb);
1346
1347 kfree(full_path);
1348 FreeXid(xid);
1349 return rc;
1350}
1351
Steve Frenchee2fd962008-09-23 18:23:33 +00001352static int
1353cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
1354 struct dentry *to_dentry, const char *toPath)
1355{
1356 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
1357 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1358 __u16 srcfid;
1359 int oplock, rc;
1360
1361 /* try path-based rename first */
1362 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
1363 cifs_sb->mnt_cifs_flags &
1364 CIFS_MOUNT_MAP_SPECIAL_CHR);
1365
1366 /*
1367 * don't bother with rename by filehandle unless file is busy and
1368 * source Note that cross directory moves do not work with
1369 * rename by filehandle to various Windows servers.
1370 */
1371 if (rc == 0 || rc != -ETXTBSY)
1372 return rc;
1373
1374 /* open the file to be renamed -- we need DELETE perms */
1375 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
1376 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1377 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1378 CIFS_MOUNT_MAP_SPECIAL_CHR);
1379
1380 if (rc == 0) {
1381 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
1382 (const char *) to_dentry->d_name.name,
1383 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1384 CIFS_MOUNT_MAP_SPECIAL_CHR);
1385
1386 CIFSSMBClose(xid, pTcon, srcfid);
1387 }
1388
1389 return rc;
1390}
1391
Jeff Layton14121bd2008-10-20 14:45:22 -04001392int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1393 struct inode *target_dir, struct dentry *target_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
Steve Frenchee2fd962008-09-23 18:23:33 +00001395 char *fromName = NULL;
1396 char *toName = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 struct cifs_sb_info *cifs_sb_source;
1398 struct cifs_sb_info *cifs_sb_target;
Jeff Layton14121bd2008-10-20 14:45:22 -04001399 struct cifsTconInfo *tcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001400 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1401 FILE_UNIX_BASIC_INFO *info_buf_target;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001402 int xid, rc, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Jeff Layton14121bd2008-10-20 14:45:22 -04001404 cifs_sb_target = CIFS_SB(target_dir->i_sb);
1405 cifs_sb_source = CIFS_SB(source_dir->i_sb);
1406 tcon = cifs_sb_source->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Steve Frenchee2fd962008-09-23 18:23:33 +00001408 xid = GetXid();
1409
1410 /*
1411 * BB: this might be allowed if same server, but different share.
1412 * Consider adding support for this
1413 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001414 if (tcon != cifs_sb_target->tcon) {
Steve Frenchee2fd962008-09-23 18:23:33 +00001415 rc = -EXDEV;
1416 goto cifs_rename_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 }
1418
Steve Frenchee2fd962008-09-23 18:23:33 +00001419 /*
1420 * we already have the rename sem so we do not need to
1421 * grab it again here to protect the path integrity
1422 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001423 fromName = build_path_from_dentry(source_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001424 if (fromName == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 rc = -ENOMEM;
1426 goto cifs_rename_exit;
1427 }
1428
Jeff Layton14121bd2008-10-20 14:45:22 -04001429 toName = build_path_from_dentry(target_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001430 if (toName == NULL) {
1431 rc = -ENOMEM;
1432 goto cifs_rename_exit;
1433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Jeff Layton14121bd2008-10-20 14:45:22 -04001435 rc = cifs_do_rename(xid, source_dentry, fromName,
1436 target_dentry, toName);
Steve Frenchee2fd962008-09-23 18:23:33 +00001437
Jeff Layton14121bd2008-10-20 14:45:22 -04001438 if (rc == -EEXIST && tcon->unix_ext) {
Steve Frenchee2fd962008-09-23 18:23:33 +00001439 /*
Jeff Layton14121bd2008-10-20 14:45:22 -04001440 * Are src and dst hardlinks of same inode? We can
1441 * only tell with unix extensions enabled
Steve Frenchee2fd962008-09-23 18:23:33 +00001442 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001443 info_buf_source =
1444 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1445 GFP_KERNEL);
1446 if (info_buf_source == NULL) {
1447 rc = -ENOMEM;
1448 goto cifs_rename_exit;
1449 }
1450
1451 info_buf_target = info_buf_source + 1;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001452 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
Jeff Layton14121bd2008-10-20 14:45:22 -04001453 info_buf_source,
1454 cifs_sb_source->local_nls,
1455 cifs_sb_source->mnt_cifs_flags &
1456 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton8d281ef2008-10-22 13:57:01 -04001457 if (tmprc != 0)
Jeff Layton14121bd2008-10-20 14:45:22 -04001458 goto unlink_target;
1459
Jeff Layton8d281ef2008-10-22 13:57:01 -04001460 tmprc = CIFSSMBUnixQPathInfo(xid, tcon,
Jeff Layton14121bd2008-10-20 14:45:22 -04001461 toName, info_buf_target,
1462 cifs_sb_target->local_nls,
1463 /* remap based on source sb */
1464 cifs_sb_source->mnt_cifs_flags &
1465 CIFS_MOUNT_MAP_SPECIAL_CHR);
1466
Jeff Layton8d281ef2008-10-22 13:57:01 -04001467 if (tmprc == 0 && (info_buf_source->UniqueId ==
Jeff Laytonae6884a2008-11-03 14:05:08 -05001468 info_buf_target->UniqueId)) {
Jeff Layton14121bd2008-10-20 14:45:22 -04001469 /* same file, POSIX says that this is a noop */
Jeff Laytonae6884a2008-11-03 14:05:08 -05001470 rc = 0;
Jeff Layton14121bd2008-10-20 14:45:22 -04001471 goto cifs_rename_exit;
Jeff Laytonae6884a2008-11-03 14:05:08 -05001472 }
Jeff Layton14121bd2008-10-20 14:45:22 -04001473 } /* else ... BB we could add the same check for Windows by
1474 checking the UniqueId via FILE_INTERNAL_INFO */
1475
Jeff Layton14121bd2008-10-20 14:45:22 -04001476unlink_target:
Jeff Laytonfc6f3942009-04-17 11:45:30 -04001477 /* Try unlinking the target dentry if it's not negative */
1478 if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
Jeff Layton8d281ef2008-10-22 13:57:01 -04001479 tmprc = cifs_unlink(target_dir, target_dentry);
Jeff Layton14121bd2008-10-20 14:45:22 -04001480 if (tmprc)
1481 goto cifs_rename_exit;
1482
Jeff Layton14121bd2008-10-20 14:45:22 -04001483 rc = cifs_do_rename(xid, source_dentry, fromName,
1484 target_dentry, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 }
1486
1487cifs_rename_exit:
Steve Frenchee2fd962008-09-23 18:23:33 +00001488 kfree(info_buf_source);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 kfree(fromName);
1490 kfree(toName);
1491 FreeXid(xid);
1492 return rc;
1493}
1494
Jeff Laytondf2cf172010-02-12 07:44:16 -05001495static bool
1496cifs_inode_needs_reval(struct inode *inode)
1497{
1498 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1499
1500 if (cifs_i->clientCanCacheRead)
1501 return false;
1502
1503 if (!lookupCacheEnabled)
1504 return true;
1505
1506 if (cifs_i->time == 0)
1507 return true;
1508
1509 /* FIXME: the actimeo should be tunable */
1510 if (time_after_eq(jiffies, cifs_i->time + HZ))
1511 return true;
1512
1513 return false;
1514}
1515
1516/* check invalid_mapping flag and zap the cache if it's set */
1517static void
1518cifs_invalidate_mapping(struct inode *inode)
1519{
1520 int rc;
1521 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1522
1523 cifs_i->invalid_mapping = false;
1524
1525 /* write back any cached data */
1526 if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
1527 rc = filemap_write_and_wait(inode->i_mapping);
1528 if (rc)
1529 cifs_i->write_behind_rc = rc;
1530 }
1531 invalidate_remote_inode(inode);
1532}
1533
Jeff Laytonabab0952010-02-12 07:44:18 -05001534int cifs_revalidate_file(struct file *filp)
1535{
1536 int rc = 0;
1537 struct inode *inode = filp->f_path.dentry->d_inode;
1538
1539 if (!cifs_inode_needs_reval(inode))
1540 goto check_inval;
1541
1542 if (CIFS_SB(inode->i_sb)->tcon->unix_ext)
1543 rc = cifs_get_file_info_unix(filp);
1544 else
1545 rc = cifs_get_file_info(filp);
1546
1547check_inval:
1548 if (CIFS_I(inode)->invalid_mapping)
1549 cifs_invalidate_mapping(inode);
1550
1551 return rc;
1552}
1553
Jeff Laytondf2cf172010-02-12 07:44:16 -05001554/* revalidate a dentry's inode attributes */
1555int cifs_revalidate_dentry(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556{
1557 int xid;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001558 int rc = 0;
1559 char *full_path = NULL;
1560 struct inode *inode = dentry->d_inode;
1561 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Jeff Laytondf2cf172010-02-12 07:44:16 -05001563 if (inode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 return -ENOENT;
1565
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 xid = GetXid();
1567
Jeff Laytondf2cf172010-02-12 07:44:16 -05001568 if (!cifs_inode_needs_reval(inode))
1569 goto check_inval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
1571 /* can not safely grab the rename sem here if rename calls revalidate
1572 since that would deadlock */
Jeff Laytondf2cf172010-02-12 07:44:16 -05001573 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301575 rc = -ENOMEM;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001576 goto check_inval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
Jeff Laytondf2cf172010-02-12 07:44:16 -05001578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
Jeff Laytondf2cf172010-02-12 07:44:16 -05001580 "jiffies %ld", full_path, inode, inode->i_count.counter,
1581 dentry, dentry->d_time, jiffies));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Jeff Laytondf2cf172010-02-12 07:44:16 -05001583 if (CIFS_SB(sb)->tcon->unix_ext)
1584 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
1585 else
1586 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
1587 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
Jeff Laytondf2cf172010-02-12 07:44:16 -05001589check_inval:
1590 if (CIFS_I(inode)->invalid_mapping)
1591 cifs_invalidate_mapping(inode);
Steve French50c2f752007-07-13 00:33:32 +00001592
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 kfree(full_path);
1594 FreeXid(xid);
1595 return rc;
1596}
1597
1598int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1599 struct kstat *stat)
1600{
Jeff Laytondf2cf172010-02-12 07:44:16 -05001601 int err = cifs_revalidate_dentry(dentry);
Steve French5fe14c82006-11-07 19:26:33 +00001602 if (!err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 generic_fillattr(dentry->d_inode, stat);
Steve French5fe14c82006-11-07 19:26:33 +00001604 stat->blksize = CIFS_MAX_MSGSIZE;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001605 stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
Steve French5fe14c82006-11-07 19:26:33 +00001606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 return err;
1608}
1609
1610static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1611{
1612 pgoff_t index = from >> PAGE_CACHE_SHIFT;
1613 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1614 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 int rc = 0;
1616
1617 page = grab_cache_page(mapping, index);
1618 if (!page)
1619 return -ENOMEM;
1620
Christoph Lametereebd2aa2008-02-04 22:28:29 -08001621 zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 unlock_page(page);
1623 page_cache_release(page);
1624 return rc;
1625}
1626
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001627static int cifs_vmtruncate(struct inode *inode, loff_t offset)
Steve French3677db12007-02-26 16:46:11 +00001628{
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001629 loff_t oldsize;
1630 int err;
Steve French3677db12007-02-26 16:46:11 +00001631
Steve Frenchba6a46a2007-02-26 20:06:29 +00001632 spin_lock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001633 err = inode_newsize_ok(inode, offset);
1634 if (err) {
Steve Frenchba6a46a2007-02-26 20:06:29 +00001635 spin_unlock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001636 goto out;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001637 }
Steve French3677db12007-02-26 16:46:11 +00001638
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001639 oldsize = inode->i_size;
Steve French3677db12007-02-26 16:46:11 +00001640 i_size_write(inode, offset);
Steve Frenchba6a46a2007-02-26 20:06:29 +00001641 spin_unlock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001642 truncate_pagecache(inode, oldsize, offset);
Al Viroacfa4382008-12-04 10:06:33 -05001643 if (inode->i_op->truncate)
Steve French3677db12007-02-26 16:46:11 +00001644 inode->i_op->truncate(inode);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001645out:
1646 return err;
Steve French3677db12007-02-26 16:46:11 +00001647}
1648
Jeff Layton8efdbde2008-07-23 21:28:12 +00001649static int
1650cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1651 int xid, char *full_path)
1652{
1653 int rc;
1654 struct cifsFileInfo *open_file;
1655 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1656 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1657 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1658
1659 /*
1660 * To avoid spurious oplock breaks from server, in the case of
1661 * inodes that we already have open, avoid doing path based
1662 * setting of file size if we can do it by handle.
1663 * This keeps our caching token (oplock) and avoids timeouts
1664 * when the local oplock break takes longer to flush
1665 * writebehind data than the SMB timeout for the SetPathInfo
1666 * request would allow
1667 */
1668 open_file = find_writable_file(cifsInode);
1669 if (open_file) {
1670 __u16 nfid = open_file->netfid;
1671 __u32 npid = open_file->pid;
1672 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
1673 npid, false);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001674 cifsFileInfo_put(open_file);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001675 cFYI(1, ("SetFSize for attrs rc = %d", rc));
1676 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1677 unsigned int bytes_written;
1678 rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size,
1679 &bytes_written, NULL, NULL, 1);
1680 cFYI(1, ("Wrt seteof rc %d", rc));
1681 }
1682 } else
1683 rc = -EINVAL;
1684
1685 if (rc != 0) {
1686 /* Set file size by pathname rather than by handle
1687 either because no valid, writeable file handle for
1688 it was found or because there was an error setting
1689 it by handle */
1690 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
1691 false, cifs_sb->local_nls,
1692 cifs_sb->mnt_cifs_flags &
1693 CIFS_MOUNT_MAP_SPECIAL_CHR);
1694 cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
1695 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1696 __u16 netfid;
1697 int oplock = 0;
1698
1699 rc = SMBLegacyOpen(xid, pTcon, full_path,
1700 FILE_OPEN, GENERIC_WRITE,
1701 CREATE_NOT_DIR, &netfid, &oplock, NULL,
1702 cifs_sb->local_nls,
1703 cifs_sb->mnt_cifs_flags &
1704 CIFS_MOUNT_MAP_SPECIAL_CHR);
1705 if (rc == 0) {
1706 unsigned int bytes_written;
1707 rc = CIFSSMBWrite(xid, pTcon, netfid, 0,
1708 attrs->ia_size,
1709 &bytes_written, NULL,
1710 NULL, 1);
1711 cFYI(1, ("wrt seteof rc %d", rc));
1712 CIFSSMBClose(xid, pTcon, netfid);
1713 }
1714 }
1715 }
1716
1717 if (rc == 0) {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001718 cifsInode->server_eof = attrs->ia_size;
Jeff Layton8efdbde2008-07-23 21:28:12 +00001719 rc = cifs_vmtruncate(inode, attrs->ia_size);
1720 cifs_truncate_page(inode->i_mapping, inode->i_size);
1721 }
1722
1723 return rc;
1724}
1725
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001726static int
1727cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1728{
1729 int rc;
1730 int xid;
1731 char *full_path = NULL;
1732 struct inode *inode = direntry->d_inode;
1733 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1734 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1735 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1736 struct cifs_unix_set_info_args *args = NULL;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001737 struct cifsFileInfo *open_file;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001738
1739 cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x",
1740 direntry->d_name.name, attrs->ia_valid));
1741
1742 xid = GetXid();
1743
1744 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
1745 /* check if we have permission to change attrs */
1746 rc = inode_change_ok(inode, attrs);
1747 if (rc < 0)
1748 goto out;
1749 else
1750 rc = 0;
1751 }
1752
1753 full_path = build_path_from_dentry(direntry);
1754 if (full_path == NULL) {
1755 rc = -ENOMEM;
1756 goto out;
1757 }
1758
Jeff Layton0f4d6342009-03-26 13:35:37 -04001759 /*
1760 * Attempt to flush data before changing attributes. We need to do
1761 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
1762 * ownership or mode then we may also need to do this. Here, we take
1763 * the safe way out and just do the flush on all setattr requests. If
1764 * the flush returns error, store it to report later and continue.
1765 *
1766 * BB: This should be smarter. Why bother flushing pages that
1767 * will be truncated anyway? Also, should we error out here if
1768 * the flush returns error?
1769 */
1770 rc = filemap_write_and_wait(inode->i_mapping);
1771 if (rc != 0) {
1772 cifsInode->write_behind_rc = rc;
1773 rc = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001774 }
1775
1776 if (attrs->ia_valid & ATTR_SIZE) {
1777 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1778 if (rc != 0)
1779 goto out;
1780 }
1781
1782 /* skip mode change if it's just for clearing setuid/setgid */
1783 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1784 attrs->ia_valid &= ~ATTR_MODE;
1785
1786 args = kmalloc(sizeof(*args), GFP_KERNEL);
1787 if (args == NULL) {
1788 rc = -ENOMEM;
1789 goto out;
1790 }
1791
1792 /* set up the struct */
1793 if (attrs->ia_valid & ATTR_MODE)
1794 args->mode = attrs->ia_mode;
1795 else
1796 args->mode = NO_CHANGE_64;
1797
1798 if (attrs->ia_valid & ATTR_UID)
1799 args->uid = attrs->ia_uid;
1800 else
1801 args->uid = NO_CHANGE_64;
1802
1803 if (attrs->ia_valid & ATTR_GID)
1804 args->gid = attrs->ia_gid;
1805 else
1806 args->gid = NO_CHANGE_64;
1807
1808 if (attrs->ia_valid & ATTR_ATIME)
1809 args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
1810 else
1811 args->atime = NO_CHANGE_64;
1812
1813 if (attrs->ia_valid & ATTR_MTIME)
1814 args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
1815 else
1816 args->mtime = NO_CHANGE_64;
1817
1818 if (attrs->ia_valid & ATTR_CTIME)
1819 args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
1820 else
1821 args->ctime = NO_CHANGE_64;
1822
1823 args->device = 0;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001824 open_file = find_writable_file(cifsInode);
1825 if (open_file) {
1826 u16 nfid = open_file->netfid;
1827 u32 npid = open_file->pid;
1828 rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001829 cifsFileInfo_put(open_file);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001830 } else {
1831 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
Jeff Layton01ea95e2009-07-09 20:02:49 -04001832 cifs_sb->local_nls,
1833 cifs_sb->mnt_cifs_flags &
1834 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001835 }
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001836
Steve Frenchccd4bb12010-02-08 17:39:58 +00001837 if (!rc) {
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001838 rc = inode_setattr(inode, attrs);
Steve Frenchccd4bb12010-02-08 17:39:58 +00001839
1840 /* force revalidate when any of these times are set since some
1841 of the fs types (eg ext3, fat) do not have fine enough
1842 time granularity to match protocol, and we do not have a
1843 a way (yet) to query the server fs's time granularity (and
1844 whether it rounds times down).
1845 */
1846 if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)))
1847 cifsInode->time = 0;
1848 }
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001849out:
1850 kfree(args);
1851 kfree(full_path);
1852 FreeXid(xid);
1853 return rc;
1854}
1855
Jeff Layton0510eeb2008-08-02 07:26:12 -04001856static int
1857cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858{
1859 int xid;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001860 struct inode *inode = direntry->d_inode;
1861 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001862 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 char *full_path = NULL;
1864 int rc = -EACCES;
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001865 __u32 dosattr = 0;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001866 __u64 mode = NO_CHANGE_64;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001867
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 xid = GetXid();
1869
Steve French39798772006-05-31 22:40:51 +00001870 cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 direntry->d_name.name, attrs->ia_valid));
Steve French6473a552005-11-29 20:20:10 -08001872
Steve French2a138ebb2005-11-29 21:22:19 -08001873 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
Steve French6473a552005-11-29 20:20:10 -08001874 /* check if we have permission to change attrs */
Jeff Layton02eadef2008-05-09 21:26:11 +00001875 rc = inode_change_ok(inode, attrs);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001876 if (rc < 0) {
Steve French6473a552005-11-29 20:20:10 -08001877 FreeXid(xid);
1878 return rc;
1879 } else
1880 rc = 0;
1881 }
Steve French50c2f752007-07-13 00:33:32 +00001882
Steve French7f573562005-08-30 11:32:14 -07001883 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301885 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301887 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
Jeff Layton0f4d6342009-03-26 13:35:37 -04001890 /*
1891 * Attempt to flush data before changing attributes. We need to do
1892 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
1893 * ownership or mode then we may also need to do this. Here, we take
1894 * the safe way out and just do the flush on all setattr requests. If
1895 * the flush returns error, store it to report later and continue.
1896 *
1897 * BB: This should be smarter. Why bother flushing pages that
1898 * will be truncated anyway? Also, should we error out here if
1899 * the flush returns error?
1900 */
1901 rc = filemap_write_and_wait(inode->i_mapping);
1902 if (rc != 0) {
1903 cifsInode->write_behind_rc = rc;
1904 rc = 0;
Steve French50531442008-03-14 19:21:31 +00001905 }
Jeff Laytoncea21802007-11-20 23:19:03 +00001906
Steve French50531442008-03-14 19:21:31 +00001907 if (attrs->ia_valid & ATTR_SIZE) {
Jeff Layton8efdbde2008-07-23 21:28:12 +00001908 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1909 if (rc != 0)
Steve Frenche30dcf32005-09-20 20:49:16 -07001910 goto cifs_setattr_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 }
Jeff Layton4ca691a2008-05-22 09:33:34 -04001912
1913 /*
1914 * Without unix extensions we can't send ownership changes to the
1915 * server, so silently ignore them. This is consistent with how
1916 * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With
1917 * CIFSACL support + proper Windows to Unix idmapping, we may be
1918 * able to support this in the future.
1919 */
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001920 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
Jeff Layton4ca691a2008-05-22 09:33:34 -04001921 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
Jeff Laytond32c4f22007-10-18 03:05:22 -07001923 /* skip mode change if it's just for clearing setuid/setgid */
1924 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1925 attrs->ia_valid &= ~ATTR_MODE;
1926
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 if (attrs->ia_valid & ATTR_MODE) {
Jeff Layton51328612008-05-22 09:33:34 -04001928 cFYI(1, ("Mode changed to 0%o", attrs->ia_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 mode = attrs->ia_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 }
1931
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001932 if (attrs->ia_valid & ATTR_MODE) {
Steve Frenchcdbce9c2005-11-19 21:04:52 -08001933 rc = 0;
Steve French97837582007-12-31 07:47:21 +00001934#ifdef CONFIG_CIFS_EXPERIMENTAL
1935 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
Jeff Layton02eadef2008-05-09 21:26:11 +00001936 rc = mode_to_acl(inode, full_path, mode);
Jeff Layton51328612008-05-22 09:33:34 -04001937 else
Steve French97837582007-12-31 07:47:21 +00001938#endif
Jeff Layton51328612008-05-22 09:33:34 -04001939 if (((mode & S_IWUGO) == 0) &&
1940 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001941
1942 dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
1943
Jeff Layton51328612008-05-22 09:33:34 -04001944 /* fix up mode if we're not using dynperm */
1945 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
1946 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
1947 } else if ((mode & S_IWUGO) &&
1948 (cifsInode->cifsAttrs & ATTR_READONLY)) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001949
1950 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
1951 /* Attributes of 0 are ignored */
1952 if (dosattr == 0)
1953 dosattr |= ATTR_NORMAL;
Jeff Layton51328612008-05-22 09:33:34 -04001954
1955 /* reset local inode permissions to normal */
1956 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1957 attrs->ia_mode &= ~(S_IALLUGO);
1958 if (S_ISDIR(inode->i_mode))
1959 attrs->ia_mode |=
1960 cifs_sb->mnt_dir_mode;
1961 else
1962 attrs->ia_mode |=
1963 cifs_sb->mnt_file_mode;
1964 }
1965 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1966 /* ignore mode change - ATTR_READONLY hasn't changed */
1967 attrs->ia_valid &= ~ATTR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 }
1970
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001971 if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
1972 ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
1973 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
1974 /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975
Steve Frenche30dcf32005-09-20 20:49:16 -07001976 /* Even if error on time set, no sense failing the call if
1977 the server would set the time to a reasonable value anyway,
1978 and this check ensures that we are not being called from
1979 sys_utimes in which case we ought to fail the call back to
1980 the user when the server rejects the call */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001981 if ((rc) && (attrs->ia_valid &
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001982 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
Steve Frenche30dcf32005-09-20 20:49:16 -07001983 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 }
1985
1986 /* do not need local check to inode_check_ok since the server does
1987 that */
1988 if (!rc)
Jeff Layton02eadef2008-05-09 21:26:11 +00001989 rc = inode_setattr(inode, attrs);
Steve Frenche30dcf32005-09-20 20:49:16 -07001990cifs_setattr_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 kfree(full_path);
1992 FreeXid(xid);
1993 return rc;
1994}
1995
Jeff Layton0510eeb2008-08-02 07:26:12 -04001996int
1997cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1998{
1999 struct inode *inode = direntry->d_inode;
2000 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
2001 struct cifsTconInfo *pTcon = cifs_sb->tcon;
2002
2003 if (pTcon->unix_ext)
2004 return cifs_setattr_unix(direntry, attrs);
2005
2006 return cifs_setattr_nounix(direntry, attrs);
2007
2008 /* BB: add cifs_setattr_legacy for really old servers */
2009}
2010
Steve French99ee4db2007-02-27 05:35:17 +00002011#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012void cifs_delete_inode(struct inode *inode)
2013{
Steve French26a21b92006-05-31 18:05:34 +00002014 cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 /* may have to add back in if and when safe distributed caching of
2016 directories added e.g. via FindNotify */
2017}
Steve French99ee4db2007-02-27 05:35:17 +00002018#endif