blob: 8bdbc818164cbc87df5455c92b1d61ac2f915c90 [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 Laytoncc0bad72009-06-25 00:56:52 -040080/* populate an inode with info from a cifs_fattr struct */
81void
82cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
Christoph Hellwig75f12982008-02-25 20:25:21 +000083{
Jeff Laytoncc0bad72009-06-25 00:56:52 -040084 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -040085 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
86 unsigned long oldtime = cifs_i->time;
Christoph Hellwig75f12982008-02-25 20:25:21 +000087
Jeff Laytoncc0bad72009-06-25 00:56:52 -040088 inode->i_atime = fattr->cf_atime;
89 inode->i_mtime = fattr->cf_mtime;
90 inode->i_ctime = fattr->cf_ctime;
Jeff Laytoncc0bad72009-06-25 00:56:52 -040091 inode->i_rdev = fattr->cf_rdev;
92 inode->i_nlink = fattr->cf_nlink;
93 inode->i_uid = fattr->cf_uid;
94 inode->i_gid = fattr->cf_gid;
95
Jeff Layton0b8f18e2009-07-09 01:46:37 -040096 /* if dynperm is set, don't clobber existing mode */
97 if (inode->i_state & I_NEW ||
98 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
99 inode->i_mode = fattr->cf_mode;
100
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400101 cifs_i->cifsAttrs = fattr->cf_cifsattrs;
102 cifs_i->uniqueid = fattr->cf_uniqueid;
103
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400104 if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
105 cifs_i->time = 0;
106 else
107 cifs_i->time = jiffies;
108
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400109 cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400110 oldtime, cifs_i->time));
111
112 cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000113
Jeff Layton835a36c2010-02-10 16:21:33 -0500114 cifs_i->server_eof = fattr->cf_eof;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000115 /*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400116 * Can't safely change the file size here if the client is writing to
117 * it due to potential races.
Christoph Hellwig75f12982008-02-25 20:25:21 +0000118 */
Christoph Hellwig75f12982008-02-25 20:25:21 +0000119 spin_lock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400120 if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
121 i_size_write(inode, fattr->cf_eof);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000122
123 /*
124 * i_blocks is not related to (i_size / i_blksize),
125 * but instead 512 byte (2**9) size is required for
126 * calculating num blocks.
127 */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400128 inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000129 }
130 spin_unlock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400131
132 cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000133}
134
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400135/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
136void
137cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
138 struct cifs_sb_info *cifs_sb)
139{
140 memset(fattr, 0, sizeof(*fattr));
141 fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
142 fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
143 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
144
145 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
146 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
147 fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
148 fattr->cf_mode = le64_to_cpu(info->Permissions);
149
150 /*
151 * Since we set the inode type below we need to mask off
152 * to avoid strange results if bits set above.
153 */
154 fattr->cf_mode &= ~S_IFMT;
155 switch (le32_to_cpu(info->Type)) {
156 case UNIX_FILE:
157 fattr->cf_mode |= S_IFREG;
158 fattr->cf_dtype = DT_REG;
159 break;
160 case UNIX_SYMLINK:
161 fattr->cf_mode |= S_IFLNK;
162 fattr->cf_dtype = DT_LNK;
163 break;
164 case UNIX_DIR:
165 fattr->cf_mode |= S_IFDIR;
166 fattr->cf_dtype = DT_DIR;
167 break;
168 case UNIX_CHARDEV:
169 fattr->cf_mode |= S_IFCHR;
170 fattr->cf_dtype = DT_CHR;
171 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
172 le64_to_cpu(info->DevMinor) & MINORMASK);
173 break;
174 case UNIX_BLOCKDEV:
175 fattr->cf_mode |= S_IFBLK;
176 fattr->cf_dtype = DT_BLK;
177 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
178 le64_to_cpu(info->DevMinor) & MINORMASK);
179 break;
180 case UNIX_FIFO:
181 fattr->cf_mode |= S_IFIFO;
182 fattr->cf_dtype = DT_FIFO;
183 break;
184 case UNIX_SOCKET:
185 fattr->cf_mode |= S_IFSOCK;
186 fattr->cf_dtype = DT_SOCK;
187 break;
188 default:
189 /* safest to call it a file if we do not know */
190 fattr->cf_mode |= S_IFREG;
191 fattr->cf_dtype = DT_REG;
192 cFYI(1, ("unknown type %d", le32_to_cpu(info->Type)));
193 break;
194 }
195
196 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
197 fattr->cf_uid = cifs_sb->mnt_uid;
198 else
199 fattr->cf_uid = le64_to_cpu(info->Uid);
200
201 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
202 fattr->cf_gid = cifs_sb->mnt_gid;
203 else
204 fattr->cf_gid = le64_to_cpu(info->Gid);
205
206 fattr->cf_nlink = le64_to_cpu(info->Nlinks);
207}
Steve Frenchb9a32602008-05-20 21:52:32 +0000208
209/*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400210 * Fill a cifs_fattr struct with fake inode info.
211 *
212 * Needed to setup cifs_fattr data for the directory which is the
213 * junction to the new submount (ie to setup the fake directory
214 * which represents a DFS referral).
Steve Frenchb9a32602008-05-20 21:52:32 +0000215 */
Steve Frenchf1230c92009-07-22 23:13:01 +0000216static void
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400217cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
Steve French0e4bbde2008-05-20 19:50:46 +0000218{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400219 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Steve French0e4bbde2008-05-20 19:50:46 +0000220
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400221 cFYI(1, ("creating fake fattr for DFS referral"));
Steve French0e4bbde2008-05-20 19:50:46 +0000222
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400223 memset(fattr, 0, sizeof(*fattr));
224 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
225 fattr->cf_uid = cifs_sb->mnt_uid;
226 fattr->cf_gid = cifs_sb->mnt_gid;
227 fattr->cf_atime = CURRENT_TIME;
228 fattr->cf_ctime = CURRENT_TIME;
229 fattr->cf_mtime = CURRENT_TIME;
230 fattr->cf_nlink = 2;
231 fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
Steve French0e4bbde2008-05-20 19:50:46 +0000232}
233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234int cifs_get_inode_info_unix(struct inode **pinode,
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400235 const unsigned char *full_path,
236 struct super_block *sb, int xid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400238 int rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000239 FILE_UNIX_BASIC_INFO find_data;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400240 struct cifs_fattr fattr;
241 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400244 tcon = cifs_sb->tcon;
Steve French646dd532008-05-15 01:50:56 +0000245 cFYI(1, ("Getting info on %s", full_path));
Igor Mammedov79626702008-03-09 03:44:18 +0000246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 /* could have done a find first instead but this returns more info */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400248 rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
Steve French737b7582005-04-28 22:41:06 -0700249 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
250 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400251
252 if (!rc) {
253 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
254 } else if (rc == -EREMOTE) {
255 cifs_create_dfs_fattr(&fattr, sb);
Jeff Laytone911d0c2008-07-12 13:47:59 -0700256 rc = 0;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400257 } else {
258 return rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000259 }
260
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400261 if (*pinode == NULL) {
262 /* get new inode */
263 *pinode = cifs_iget(sb, &fattr);
264 if (!*pinode)
265 rc = -ENOMEM;
266 } else {
267 /* we already have inode, update it */
268 cifs_fattr_to_inode(*pinode, &fattr);
269 }
Steve French0e4bbde2008-05-20 19:50:46 +0000270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 return rc;
272}
273
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400274static int
275cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
276 struct cifs_sb_info *cifs_sb, int xid)
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800277{
278 int rc;
Steve French4b18f2a2008-04-29 00:06:05 +0000279 int oplock = 0;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800280 __u16 netfid;
281 struct cifsTconInfo *pTcon = cifs_sb->tcon;
Steve French86c96b42005-11-18 20:25:31 -0800282 char buf[24];
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800283 unsigned int bytes_read;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000284 char *pbuf;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800285
286 pbuf = buf;
287
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400288 fattr->cf_mode &= ~S_IFMT;
289
290 if (fattr->cf_eof == 0) {
291 fattr->cf_mode |= S_IFIFO;
292 fattr->cf_dtype = DT_FIFO;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800293 return 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400294 } else if (fattr->cf_eof < 8) {
295 fattr->cf_mode |= S_IFREG;
296 fattr->cf_dtype = DT_REG;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800297 return -EINVAL; /* EOPNOTSUPP? */
298 }
Steve French50c2f752007-07-13 00:33:32 +0000299
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800300 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
301 CREATE_NOT_DIR, &netfid, &oplock, NULL,
302 cifs_sb->local_nls,
303 cifs_sb->mnt_cifs_flags &
304 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000305 if (rc == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -0800306 int buf_type = CIFS_NO_BUFFER;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800307 /* Read header */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400308 rc = CIFSSMBRead(xid, pTcon, netfid,
Steve French86c96b42005-11-18 20:25:31 -0800309 24 /* length */, 0 /* offset */,
Steve Frenchec637e32005-12-12 20:53:18 -0800310 &bytes_read, &pbuf, &buf_type);
Steve French4523cc32007-04-30 20:13:06 +0000311 if ((rc == 0) && (bytes_read >= 8)) {
312 if (memcmp("IntxBLK", pbuf, 8) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000313 cFYI(1, ("Block device"));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400314 fattr->cf_mode |= S_IFBLK;
315 fattr->cf_dtype = DT_BLK;
Steve French4523cc32007-04-30 20:13:06 +0000316 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800317 /* we have enough to decode dev num */
318 __u64 mjr; /* major */
319 __u64 mnr; /* minor */
320 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
321 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400322 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve French86c96b42005-11-18 20:25:31 -0800323 }
Steve French4523cc32007-04-30 20:13:06 +0000324 } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000325 cFYI(1, ("Char device"));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400326 fattr->cf_mode |= S_IFCHR;
327 fattr->cf_dtype = DT_CHR;
Steve French4523cc32007-04-30 20:13:06 +0000328 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800329 /* we have enough to decode dev num */
330 __u64 mjr; /* major */
331 __u64 mnr; /* minor */
332 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
333 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400334 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000335 }
Steve French4523cc32007-04-30 20:13:06 +0000336 } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000337 cFYI(1, ("Symlink"));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400338 fattr->cf_mode |= S_IFLNK;
339 fattr->cf_dtype = DT_LNK;
Steve French86c96b42005-11-18 20:25:31 -0800340 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400341 fattr->cf_mode |= S_IFREG; /* file? */
342 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000343 rc = -EOPNOTSUPP;
Steve French86c96b42005-11-18 20:25:31 -0800344 }
Steve French3020a1f2005-11-18 11:31:10 -0800345 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400346 fattr->cf_mode |= S_IFREG; /* then it is a file */
347 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000348 rc = -EOPNOTSUPP; /* or some unknown SFU type */
349 }
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800350 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800351 }
352 return rc;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800353}
354
Steve French9e294f12005-11-17 16:59:21 -0800355#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
356
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400357/*
358 * Fetch mode bits as provided by SFU.
359 *
360 * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
361 */
362static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
363 struct cifs_sb_info *cifs_sb, int xid)
Steve French9e294f12005-11-17 16:59:21 -0800364{
Steve French3020a1f2005-11-18 11:31:10 -0800365#ifdef CONFIG_CIFS_XATTR
Steve French9e294f12005-11-17 16:59:21 -0800366 ssize_t rc;
367 char ea_value[4];
368 __u32 mode;
369
Jeff Layton31c05192010-02-10 16:18:26 -0500370 rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS",
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400371 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
372 cifs_sb->mnt_cifs_flags &
373 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4523cc32007-04-30 20:13:06 +0000374 if (rc < 0)
Steve French9e294f12005-11-17 16:59:21 -0800375 return (int)rc;
376 else if (rc > 3) {
377 mode = le32_to_cpu(*((__le32 *)ea_value));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400378 fattr->cf_mode &= ~SFBITS_MASK;
379 cFYI(1, ("special bits 0%o org mode 0%o", mode,
380 fattr->cf_mode));
381 fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000382 cFYI(1, ("special mode bits 0%o", mode));
Steve French9e294f12005-11-17 16:59:21 -0800383 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400384
385 return 0;
Steve French3020a1f2005-11-18 11:31:10 -0800386#else
387 return -EOPNOTSUPP;
388#endif
Steve French9e294f12005-11-17 16:59:21 -0800389}
390
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400391/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
Steve Frenchf1230c92009-07-22 23:13:01 +0000392static void
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400393cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
394 struct cifs_sb_info *cifs_sb, bool adjust_tz)
Steve Frenchb9a32602008-05-20 21:52:32 +0000395{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400396 memset(fattr, 0, sizeof(*fattr));
397 fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
398 if (info->DeletePending)
399 fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
Steve Frenchb9a32602008-05-20 21:52:32 +0000400
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400401 if (info->LastAccessTime)
402 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
403 else
404 fattr->cf_atime = CURRENT_TIME;
405
406 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
407 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
408
409 if (adjust_tz) {
410 fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
411 fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
412 }
413
414 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
415 fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
416
417 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
418 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
419 fattr->cf_dtype = DT_DIR;
420 } else {
421 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
422 fattr->cf_dtype = DT_REG;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400423
Jeff Laytond0c280d2009-07-09 01:46:44 -0400424 /* clear write bits if ATTR_READONLY is set */
425 if (fattr->cf_cifsattrs & ATTR_READONLY)
426 fattr->cf_mode &= ~(S_IWUGO);
427 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400428
429 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
430
431 fattr->cf_uid = cifs_sb->mnt_uid;
432 fattr->cf_gid = cifs_sb->mnt_gid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000433}
434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435int cifs_get_inode_info(struct inode **pinode,
Steve French646dd532008-05-15 01:50:56 +0000436 const unsigned char *full_path, FILE_ALL_INFO *pfindData,
Steve French8b1327f2008-03-14 22:37:16 +0000437 struct super_block *sb, int xid, const __u16 *pfid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400439 int rc = 0, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 struct cifsTconInfo *pTcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 char *buf = NULL;
Steve French5ade9de2008-05-02 20:56:23 +0000443 bool adjustTZ = false;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400444 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446 pTcon = cifs_sb->tcon;
Steve French646dd532008-05-15 01:50:56 +0000447 cFYI(1, ("Getting info on %s", full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700449 if ((pfindData == NULL) && (*pinode != NULL)) {
450 if (CIFS_I(*pinode)->clientCanCacheRead) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000451 cFYI(1, ("No need to revalidate cached inode sizes"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 return rc;
453 }
454 }
455
456 /* if file info not passed in then get it from server */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700457 if (pfindData == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700459 if (buf == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 return -ENOMEM;
461 pfindData = (FILE_ALL_INFO *)buf;
Igor Mammedov79626702008-03-09 03:44:18 +0000462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 /* could do find first instead but this returns more info */
Igor Mammedov79626702008-03-09 03:44:18 +0000464 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +0000465 0 /* not legacy */,
Steve French6b8edfe2005-08-23 20:26:03 -0700466 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700467 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French6b8edfe2005-08-23 20:26:03 -0700468 /* BB optimize code so we do not make the above call
469 when server claims no NT SMB support and the above call
470 failed at least once - set flag in tcon or mount */
Steve French4523cc32007-04-30 20:13:06 +0000471 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
Igor Mammedov79626702008-03-09 03:44:18 +0000472 rc = SMBQueryInformation(xid, pTcon, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 pfindData, cifs_sb->local_nls,
Steve French6b8edfe2005-08-23 20:26:03 -0700474 cifs_sb->mnt_cifs_flags &
475 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4b18f2a2008-04-29 00:06:05 +0000476 adjustTZ = true;
Steve French6b8edfe2005-08-23 20:26:03 -0700477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400479
480 if (!rc) {
481 cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
482 cifs_sb, adjustTZ);
483 } else if (rc == -EREMOTE) {
484 cifs_create_dfs_fattr(&fattr, sb);
Steve Frenchb9a32602008-05-20 21:52:32 +0000485 rc = 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400486 } else {
Igor Mammedov79626702008-03-09 03:44:18 +0000487 goto cgii_exit;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400490 /*
491 * If an inode wasn't passed in, then get the inode number
492 *
493 * Is an i_ino of zero legal? Can we use that to check if the server
494 * supports returning inode numbers? Are there other sanity checks we
495 * can use to ensure that the server is really filling in that field?
496 *
497 * We can not use the IndexNumber field by default from Windows or
498 * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
499 * CIFS spec claims that this value is unique within the scope of a
500 * share, and the windows docs hint that it's actually unique
501 * per-machine.
502 *
503 * There may be higher info levels that work but are there Windows
504 * server or network appliances for which IndexNumber field is not
505 * guaranteed unique?
506 */
Steve Frenchb9a32602008-05-20 21:52:32 +0000507 if (*pinode == NULL) {
Steve Frenchb9a32602008-05-20 21:52:32 +0000508 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
509 int rc1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Steve Frenchb9a32602008-05-20 21:52:32 +0000511 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400512 full_path, &fattr.cf_uniqueid,
Steve French737b7582005-04-28 22:41:06 -0700513 cifs_sb->local_nls,
514 cifs_sb->mnt_cifs_flags &
515 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500516 if (rc1 || !fattr.cf_uniqueid) {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400517 cFYI(1, ("GetSrvInodeNum rc %d", rc1));
518 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500519 cifs_autodisable_serverino(cifs_sb);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500520 }
Jeff Layton132ac7b2009-02-10 07:33:57 -0500521 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400522 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500523 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000524 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400525 fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000526 }
527
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400528 /* query for SFU type info if supported and needed */
529 if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
530 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
531 tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
532 if (tmprc)
533 cFYI(1, ("cifs_sfu_type failed: %d", tmprc));
Steve Frenchb9a32602008-05-20 21:52:32 +0000534 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000535
Steve Frenchb9a32602008-05-20 21:52:32 +0000536#ifdef CONFIG_CIFS_EXPERIMENTAL
537 /* fill in 0777 bits from ACL */
538 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
539 cFYI(1, ("Getting mode bits from ACL"));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400540 cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
Steve Frenchb9a32602008-05-20 21:52:32 +0000541 }
542#endif
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400543
544 /* fill in remaining high mode bits e.g. SUID, VTX */
545 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
546 cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
547
548 if (!*pinode) {
549 *pinode = cifs_iget(sb, &fattr);
550 if (!*pinode)
551 rc = -ENOMEM;
552 } else {
553 cifs_fattr_to_inode(*pinode, &fattr);
Steve Frenchb9a32602008-05-20 21:52:32 +0000554 }
555
Igor Mammedov79626702008-03-09 03:44:18 +0000556cgii_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 kfree(buf);
558 return rc;
559}
560
Steve French7f8ed422007-09-28 22:28:55 +0000561static const struct inode_operations cifs_ipc_inode_ops = {
562 .lookup = cifs_lookup,
563};
564
Igor Mammedove4cce942009-02-10 14:10:26 +0300565char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
Steve French8be0ed42008-12-05 19:14:12 +0000566{
567 int pplen = cifs_sb->prepathlen;
568 int dfsplen;
569 char *full_path = NULL;
570
571 /* if no prefix path, simply set path to the root of share to "" */
572 if (pplen == 0) {
573 full_path = kmalloc(1, GFP_KERNEL);
574 if (full_path)
575 full_path[0] = 0;
576 return full_path;
577 }
578
579 if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
580 dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
581 else
582 dfsplen = 0;
583
584 full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
585 if (full_path == NULL)
586 return full_path;
587
588 if (dfsplen) {
589 strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
590 /* switch slash direction in prepath depending on whether
591 * windows or posix style path names
592 */
593 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
594 int i;
595 for (i = 0; i < dfsplen; i++) {
596 if (full_path[i] == '\\')
597 full_path[i] = '/';
598 }
599 }
600 }
601 strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
602 full_path[dfsplen + pplen] = 0; /* add trailing null */
603 return full_path;
604}
605
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400606static int
607cifs_find_inode(struct inode *inode, void *opaque)
608{
609 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
610
611 if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
612 return 0;
613
614 return 1;
615}
616
617static int
618cifs_init_inode(struct inode *inode, void *opaque)
619{
620 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
621
622 CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
623 return 0;
624}
625
626/* Given fattrs, get a corresponding inode */
627struct inode *
628cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
629{
630 unsigned long hash;
631 struct inode *inode;
632
633 cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid));
634
635 /* hash down to 32-bits on 32-bit arch */
636 hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
637
638 inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
639
640 /* we have fattrs in hand, update the inode */
641 if (inode) {
642 cifs_fattr_to_inode(inode, fattr);
643 if (sb->s_flags & MS_NOATIME)
644 inode->i_flags |= S_NOATIME | S_NOCMTIME;
645 if (inode->i_state & I_NEW) {
646 inode->i_ino = hash;
647 unlock_new_inode(inode);
648 }
649 }
650
651 return inode;
652}
653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654/* gets root inode */
Jeff Laytonbd433d42009-05-27 09:37:34 -0400655struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
David Howellsce634ab2008-02-07 00:15:33 -0800657 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 struct cifs_sb_info *cifs_sb;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400659 struct inode *inode = NULL;
David Howellsce634ab2008-02-07 00:15:33 -0800660 long rc;
Steve French8be0ed42008-12-05 19:14:12 +0000661 char *full_path;
David Howellsce634ab2008-02-07 00:15:33 -0800662
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400663 cifs_sb = CIFS_SB(sb);
Igor Mammedove4cce942009-02-10 14:10:26 +0300664 full_path = cifs_build_path_to_root(cifs_sb);
Steve French8be0ed42008-12-05 19:14:12 +0000665 if (full_path == NULL)
666 return ERR_PTR(-ENOMEM);
Steve Frenchc18c8422007-07-18 23:21:09 +0000667
Steve French8be0ed42008-12-05 19:14:12 +0000668 xid = GetXid();
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400669 if (cifs_sb->tcon->unix_ext)
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400670 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400671 else
672 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
Steve French8be0ed42008-12-05 19:14:12 +0000673 xid, NULL);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400674
675 if (!inode)
676 return ERR_PTR(-ENOMEM);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400677
Steve French7f8ed422007-09-28 22:28:55 +0000678 if (rc && cifs_sb->tcon->ipc) {
679 cFYI(1, ("ipc connection - fake read inode"));
680 inode->i_mode |= S_IFDIR;
681 inode->i_nlink = 2;
682 inode->i_op = &cifs_ipc_inode_ops;
683 inode->i_fop = &simple_dir_operations;
684 inode->i_uid = cifs_sb->mnt_uid;
685 inode->i_gid = cifs_sb->mnt_gid;
Steve Frenchad661332008-08-12 14:14:40 +0000686 } else if (rc) {
Steve French8be0ed42008-12-05 19:14:12 +0000687 kfree(full_path);
David Howellsce634ab2008-02-07 00:15:33 -0800688 _FreeXid(xid);
689 iget_failed(inode);
690 return ERR_PTR(rc);
Steve French7f8ed422007-09-28 22:28:55 +0000691 }
692
David Howellsce634ab2008-02-07 00:15:33 -0800693
Steve French8be0ed42008-12-05 19:14:12 +0000694 kfree(full_path);
David Howellsce634ab2008-02-07 00:15:33 -0800695 /* can not call macro FreeXid here since in a void func
696 * TODO: This is no longer true
697 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 _FreeXid(xid);
David Howellsce634ab2008-02-07 00:15:33 -0800699 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
Steve French388e57b2008-09-16 23:50:58 +0000702static int
703cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
704 char *full_path, __u32 dosattr)
705{
706 int rc;
707 int oplock = 0;
708 __u16 netfid;
709 __u32 netpid;
710 bool set_time = false;
711 struct cifsFileInfo *open_file;
712 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
713 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
714 struct cifsTconInfo *pTcon = cifs_sb->tcon;
715 FILE_BASIC_INFO info_buf;
716
Steve French1adcb712009-02-25 14:19:56 +0000717 if (attrs == NULL)
718 return -EINVAL;
719
Steve French388e57b2008-09-16 23:50:58 +0000720 if (attrs->ia_valid & ATTR_ATIME) {
721 set_time = true;
722 info_buf.LastAccessTime =
723 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
724 } else
725 info_buf.LastAccessTime = 0;
726
727 if (attrs->ia_valid & ATTR_MTIME) {
728 set_time = true;
729 info_buf.LastWriteTime =
730 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
731 } else
732 info_buf.LastWriteTime = 0;
733
734 /*
735 * Samba throws this field away, but windows may actually use it.
736 * Do not set ctime unless other time stamps are changed explicitly
737 * (i.e. by utimes()) since we would then have a mix of client and
738 * server times.
739 */
740 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
741 cFYI(1, ("CIFS - CTIME changed"));
742 info_buf.ChangeTime =
743 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
744 } else
745 info_buf.ChangeTime = 0;
746
747 info_buf.CreationTime = 0; /* don't change */
748 info_buf.Attributes = cpu_to_le32(dosattr);
749
750 /*
751 * If the file is already open for write, just use that fileid
752 */
753 open_file = find_writable_file(cifsInode);
754 if (open_file) {
755 netfid = open_file->netfid;
756 netpid = open_file->pid;
757 goto set_via_filehandle;
758 }
759
760 /*
761 * NT4 apparently returns success on this call, but it doesn't
762 * really work.
763 */
764 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
765 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
766 &info_buf, cifs_sb->local_nls,
767 cifs_sb->mnt_cifs_flags &
768 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +0000769 if (rc == 0) {
770 cifsInode->cifsAttrs = dosattr;
771 goto out;
772 } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
Steve French388e57b2008-09-16 23:50:58 +0000773 goto out;
774 }
775
776 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
777 "times not supported by this server"));
778 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
779 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
780 CREATE_NOT_DIR, &netfid, &oplock,
781 NULL, cifs_sb->local_nls,
782 cifs_sb->mnt_cifs_flags &
783 CIFS_MOUNT_MAP_SPECIAL_CHR);
784
785 if (rc != 0) {
786 if (rc == -EIO)
787 rc = -EINVAL;
788 goto out;
789 }
790
791 netpid = current->tgid;
792
793set_via_filehandle:
794 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
Steve Frenchd3889082008-09-24 19:22:52 +0000795 if (!rc)
796 cifsInode->cifsAttrs = dosattr;
797
Steve French388e57b2008-09-16 23:50:58 +0000798 if (open_file == NULL)
799 CIFSSMBClose(xid, pTcon, netfid);
800 else
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400801 cifsFileInfo_put(open_file);
Steve French388e57b2008-09-16 23:50:58 +0000802out:
803 return rc;
804}
805
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400806/*
807 * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
808 * and rename it to a random name that hopefully won't conflict with
809 * anything else.
810 */
811static int
Steve French32709582008-10-20 00:44:19 +0000812cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400813{
814 int oplock = 0;
815 int rc;
816 __u16 netfid;
Steve French32709582008-10-20 00:44:19 +0000817 struct inode *inode = dentry->d_inode;
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400818 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
819 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
820 struct cifsTconInfo *tcon = cifs_sb->tcon;
Steve French32709582008-10-20 00:44:19 +0000821 __u32 dosattr, origattr;
822 FILE_BASIC_INFO *info_buf = NULL;
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400823
824 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
Jeff Laytondd1db2d2008-10-16 19:27:12 -0400825 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400826 &netfid, &oplock, NULL, cifs_sb->local_nls,
827 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
828 if (rc != 0)
829 goto out;
830
Steve French32709582008-10-20 00:44:19 +0000831 origattr = cifsInode->cifsAttrs;
832 if (origattr == 0)
833 origattr |= ATTR_NORMAL;
834
835 dosattr = origattr & ~ATTR_READONLY;
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400836 if (dosattr == 0)
837 dosattr |= ATTR_NORMAL;
838 dosattr |= ATTR_HIDDEN;
839
Steve French32709582008-10-20 00:44:19 +0000840 /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
841 if (dosattr != origattr) {
842 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
843 if (info_buf == NULL) {
844 rc = -ENOMEM;
845 goto out_close;
846 }
847 info_buf->Attributes = cpu_to_le32(dosattr);
848 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
849 current->tgid);
850 /* although we would like to mark the file hidden
851 if that fails we will still try to rename it */
Steve French41346092008-10-20 18:24:42 +0000852 if (rc != 0)
Steve French32709582008-10-20 00:44:19 +0000853 cifsInode->cifsAttrs = dosattr;
854 else
855 dosattr = origattr; /* since not able to change them */
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400856 }
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400857
Jeff Laytondd1db2d2008-10-16 19:27:12 -0400858 /* rename the file */
859 rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400860 cifs_sb->mnt_cifs_flags &
861 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French32709582008-10-20 00:44:19 +0000862 if (rc != 0) {
863 rc = -ETXTBSY;
864 goto undo_setattr;
865 }
Jeff Layton6d22f092008-09-23 11:48:35 -0400866
Steve French32709582008-10-20 00:44:19 +0000867 /* try to set DELETE_ON_CLOSE */
868 if (!cifsInode->delete_pending) {
869 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
870 current->tgid);
871 /*
872 * some samba versions return -ENOENT when we try to set the
873 * file disposition here. Likely a samba bug, but work around
874 * it for now. This means that some cifsXXX files may hang
875 * around after they shouldn't.
876 *
877 * BB: remove this hack after more servers have the fix
878 */
879 if (rc == -ENOENT)
880 rc = 0;
881 else if (rc != 0) {
882 rc = -ETXTBSY;
883 goto undo_rename;
884 }
885 cifsInode->delete_pending = true;
886 }
Jeff Layton7ce86d52008-09-24 11:32:59 -0400887
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400888out_close:
889 CIFSSMBClose(xid, tcon, netfid);
890out:
Steve French32709582008-10-20 00:44:19 +0000891 kfree(info_buf);
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400892 return rc;
Steve French32709582008-10-20 00:44:19 +0000893
894 /*
895 * reset everything back to the original state. Don't bother
896 * dealing with errors here since we can't do anything about
897 * them anyway.
898 */
899undo_rename:
900 CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
901 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
902 CIFS_MOUNT_MAP_SPECIAL_CHR);
903undo_setattr:
904 if (dosattr != origattr) {
905 info_buf->Attributes = cpu_to_le32(origattr);
906 if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
907 current->tgid))
908 cifsInode->cifsAttrs = origattr;
909 }
910
911 goto out_close;
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400912}
913
Steve Frenchff694522009-04-20 19:45:13 +0000914
915/*
916 * If dentry->d_inode is null (usually meaning the cached dentry
917 * is a negative dentry) then we would attempt a standard SMB delete, but
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200918 * if that fails we can not attempt the fall back mechanisms on EACCESS
919 * but will return the EACCESS to the caller. Note that the VFS does not call
Steve Frenchff694522009-04-20 19:45:13 +0000920 * unlink on negative dentries currently.
921 */
Jeff Layton5f0319a2008-09-16 14:05:16 -0400922int cifs_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
924 int rc = 0;
925 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 char *full_path = NULL;
Jeff Layton5f0319a2008-09-16 14:05:16 -0400927 struct inode *inode = dentry->d_inode;
Steve Frenchff694522009-04-20 19:45:13 +0000928 struct cifsInodeInfo *cifs_inode;
Jeff Layton5f0319a2008-09-16 14:05:16 -0400929 struct super_block *sb = dir->i_sb;
930 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
931 struct cifsTconInfo *tcon = cifs_sb->tcon;
Steve French60502472008-10-07 18:42:52 +0000932 struct iattr *attrs = NULL;
933 __u32 dosattr = 0, origattr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Jeff Layton5f0319a2008-09-16 14:05:16 -0400935 cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 xid = GetXid();
938
Jeff Layton5f0319a2008-09-16 14:05:16 -0400939 /* Unlink can be called from rename so we can not take the
940 * sb->s_vfs_rename_mutex here */
941 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530943 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530945 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 }
Steve French2d785a52007-07-15 01:48:57 +0000947
Jeff Layton5f0319a2008-09-16 14:05:16 -0400948 if ((tcon->ses->capabilities & CAP_UNIX) &&
Steve French2d785a52007-07-15 01:48:57 +0000949 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Jeff Layton5f0319a2008-09-16 14:05:16 -0400950 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
951 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
Steve French2d785a52007-07-15 01:48:57 +0000952 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
953 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
954 cFYI(1, ("posix del rc %d", rc));
955 if ((rc == 0) || (rc == -ENOENT))
956 goto psx_del_no_retry;
957 }
958
Steve French60502472008-10-07 18:42:52 +0000959retry_std_delete:
Jeff Layton5f0319a2008-09-16 14:05:16 -0400960 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -0700961 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French60502472008-10-07 18:42:52 +0000962
Steve French2d785a52007-07-15 01:48:57 +0000963psx_del_no_retry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 if (!rc) {
Jeff Layton5f0319a2008-09-16 14:05:16 -0400965 if (inode)
966 drop_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 } else if (rc == -ENOENT) {
Jeff Layton5f0319a2008-09-16 14:05:16 -0400968 d_drop(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 } else if (rc == -ETXTBSY) {
Steve French32709582008-10-20 00:44:19 +0000970 rc = cifs_rename_pending_delete(full_path, dentry, xid);
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400971 if (rc == 0)
972 drop_nlink(inode);
Steve Frenchff694522009-04-20 19:45:13 +0000973 } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
Steve French388e57b2008-09-16 23:50:58 +0000974 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
975 if (attrs == NULL) {
976 rc = -ENOMEM;
977 goto out_reval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
Steve French388e57b2008-09-16 23:50:58 +0000979
980 /* try to reset dos attributes */
Steve Frenchff694522009-04-20 19:45:13 +0000981 cifs_inode = CIFS_I(inode);
982 origattr = cifs_inode->cifsAttrs;
Steve French60502472008-10-07 18:42:52 +0000983 if (origattr == 0)
984 origattr |= ATTR_NORMAL;
985 dosattr = origattr & ~ATTR_READONLY;
Steve French388e57b2008-09-16 23:50:58 +0000986 if (dosattr == 0)
987 dosattr |= ATTR_NORMAL;
988 dosattr |= ATTR_HIDDEN;
989
990 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
Steve French388e57b2008-09-16 23:50:58 +0000991 if (rc != 0)
992 goto out_reval;
Steve French60502472008-10-07 18:42:52 +0000993
994 goto retry_std_delete;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 }
Steve French60502472008-10-07 18:42:52 +0000996
997 /* undo the setattr if we errored out and it's needed */
998 if (rc != 0 && dosattr != 0)
999 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
1000
Steve French388e57b2008-09-16 23:50:58 +00001001out_reval:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001002 if (inode) {
Steve Frenchff694522009-04-20 19:45:13 +00001003 cifs_inode = CIFS_I(inode);
1004 cifs_inode->time = 0; /* will force revalidate to get info
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001005 when needed */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001006 inode->i_ctime = current_fs_time(sb);
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001007 }
Jeff Layton5f0319a2008-09-16 14:05:16 -04001008 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
Steve Frenchff694522009-04-20 19:45:13 +00001009 cifs_inode = CIFS_I(dir);
Steve French60502472008-10-07 18:42:52 +00001010 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 kfree(full_path);
Steve French60502472008-10-07 18:42:52 +00001013 kfree(attrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 FreeXid(xid);
1015 return rc;
1016}
1017
1018int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
1019{
Jeff Layton6b37faa2008-10-06 21:54:41 +00001020 int rc = 0, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 int xid;
1022 struct cifs_sb_info *cifs_sb;
1023 struct cifsTconInfo *pTcon;
1024 char *full_path = NULL;
1025 struct inode *newinode = NULL;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001026 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Steve French6473a552005-11-29 20:20:10 -08001028 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030 xid = GetXid();
1031
1032 cifs_sb = CIFS_SB(inode->i_sb);
1033 pTcon = cifs_sb->tcon;
1034
Steve French7f573562005-08-30 11:32:14 -07001035 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301037 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301039 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 }
Steve French50c2f752007-07-13 00:33:32 +00001041
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001042 if ((pTcon->ses->capabilities & CAP_UNIX) &&
1043 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Steve French2dd29d32007-04-23 22:07:35 +00001044 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
1045 u32 oplock = 0;
Steve Frenchf6d09982008-01-08 23:18:22 +00001046 FILE_UNIX_BASIC_INFO *pInfo =
Steve French2dd29d32007-04-23 22:07:35 +00001047 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001048 if (pInfo == NULL) {
Steve French2dd29d32007-04-23 22:07:35 +00001049 rc = -ENOMEM;
1050 goto mkdir_out;
1051 }
Steve French50c2f752007-07-13 00:33:32 +00001052
Al Viroce3b0f82009-03-29 19:08:22 -04001053 mode &= ~current_umask();
Steve French2dd29d32007-04-23 22:07:35 +00001054 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
1055 mode, NULL /* netfid */, pInfo, &oplock,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001056 full_path, cifs_sb->local_nls,
1057 cifs_sb->mnt_cifs_flags &
Steve French2dd29d32007-04-23 22:07:35 +00001058 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc45d7072007-09-17 02:04:21 +00001059 if (rc == -EOPNOTSUPP) {
1060 kfree(pInfo);
1061 goto mkdir_retry_old;
1062 } else if (rc) {
Steve French2dd29d32007-04-23 22:07:35 +00001063 cFYI(1, ("posix mkdir returned 0x%x", rc));
1064 d_drop(direntry);
1065 } else {
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001066 if (pInfo->Type == cpu_to_le32(-1)) {
1067 /* no return info, go query for it */
Steve French5a07cdf2007-09-16 23:12:47 +00001068 kfree(pInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001069 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001070 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001071/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
1072 to set uid/gid */
Steve French2dd29d32007-04-23 22:07:35 +00001073 inc_nlink(inode);
1074 if (pTcon->nocase)
1075 direntry->d_op = &cifs_ci_dentry_ops;
1076 else
1077 direntry->d_op = &cifs_dentry_ops;
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001078
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001079 cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
1080 newinode = cifs_iget(inode->i_sb, &fattr);
1081 if (!newinode) {
Steve French5a07cdf2007-09-16 23:12:47 +00001082 kfree(pInfo);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001083 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001084 }
Jeff Layton6b37faa2008-10-06 21:54:41 +00001085
Steve French2dd29d32007-04-23 22:07:35 +00001086 d_instantiate(direntry, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001087
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001088#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001089 cFYI(1, ("instantiated dentry %p %s to inode %p",
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001090 direntry, direntry->d_name.name, newinode));
1091
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001092 if (newinode->i_nlink != 2)
1093 cFYI(1, ("unexpected number of links %d",
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001094 newinode->i_nlink));
1095#endif
Steve French2dd29d32007-04-23 22:07:35 +00001096 }
1097 kfree(pInfo);
1098 goto mkdir_out;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001099 }
Steve Frenchc45d7072007-09-17 02:04:21 +00001100mkdir_retry_old:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -07001102 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
1103 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +00001105 cFYI(1, ("cifs_mkdir returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 d_drop(direntry);
1107 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001108mkdir_get_info:
Dave Hansend8c76e62006-09-30 23:29:04 -07001109 inc_nlink(inode);
Steve Frenchc18c8422007-07-18 23:21:09 +00001110 if (pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001112 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 else
1114 rc = cifs_get_inode_info(&newinode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +00001115 inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Steve Frenchb92327f2005-08-22 20:09:43 -07001117 if (pTcon->nocase)
1118 direntry->d_op = &cifs_ci_dentry_ops;
1119 else
1120 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 d_instantiate(direntry, newinode);
Steve French2dd29d32007-04-23 22:07:35 +00001122 /* setting nlink not necessary except in cases where we
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001123 * failed to get it from the server or was set bogus */
Steve French2dd29d32007-04-23 22:07:35 +00001124 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001125 direntry->d_inode->i_nlink = 2;
Jeff Layton95089912008-08-06 04:39:02 +00001126
Al Viroce3b0f82009-03-29 19:08:22 -04001127 mode &= ~current_umask();
Jeff Layton95089912008-08-06 04:39:02 +00001128 /* must turn on setgid bit if parent dir has it */
1129 if (inode->i_mode & S_ISGID)
1130 mode |= S_ISGID;
1131
Steve Frenchc18c8422007-07-18 23:21:09 +00001132 if (pTcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001133 struct cifs_unix_set_info_args args = {
1134 .mode = mode,
1135 .ctime = NO_CHANGE_64,
1136 .atime = NO_CHANGE_64,
1137 .mtime = NO_CHANGE_64,
1138 .device = 0,
1139 };
Steve Frenchd0d2f2d2005-06-02 15:12:36 -07001140 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
David Howellsa001e5b2008-11-14 10:38:47 +11001141 args.uid = (__u64)current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001142 if (inode->i_mode & S_ISGID)
1143 args.gid = (__u64)inode->i_gid;
1144 else
David Howellsa001e5b2008-11-14 10:38:47 +11001145 args.gid = (__u64)current_fsgid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 } else {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001147 args.uid = NO_CHANGE_64;
1148 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 }
Jeff Layton01ea95e2009-07-09 20:02:49 -04001150 CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
1151 cifs_sb->local_nls,
1152 cifs_sb->mnt_cifs_flags &
1153 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French3ce53fc2007-06-08 14:55:14 +00001154 } else {
Jeff Layton67750fb2008-05-09 22:28:02 +00001155 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1156 (mode & S_IWUGO) == 0) {
1157 FILE_BASIC_INFO pInfo;
Jeff Layton6b37faa2008-10-06 21:54:41 +00001158 struct cifsInodeInfo *cifsInode;
1159 u32 dosattrs;
1160
Jeff Layton67750fb2008-05-09 22:28:02 +00001161 memset(&pInfo, 0, sizeof(pInfo));
Jeff Layton6b37faa2008-10-06 21:54:41 +00001162 cifsInode = CIFS_I(newinode);
1163 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1164 pInfo.Attributes = cpu_to_le32(dosattrs);
1165 tmprc = CIFSSMBSetPathInfo(xid, pTcon,
1166 full_path, &pInfo,
1167 cifs_sb->local_nls,
Jeff Layton67750fb2008-05-09 22:28:02 +00001168 cifs_sb->mnt_cifs_flags &
1169 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +00001170 if (tmprc == 0)
1171 cifsInode->cifsAttrs = dosattrs;
Jeff Layton67750fb2008-05-09 22:28:02 +00001172 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001173 if (direntry->d_inode) {
Jeff Laytonb0fd30d2008-05-22 09:33:34 -04001174 if (cifs_sb->mnt_cifs_flags &
1175 CIFS_MOUNT_DYNPERM)
1176 direntry->d_inode->i_mode =
1177 (mode | S_IFDIR);
Steve French4e94a102008-05-23 18:22:46 +00001178
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001179 if (cifs_sb->mnt_cifs_flags &
Steve French6473a552005-11-29 20:20:10 -08001180 CIFS_MOUNT_SET_UID) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001181 direntry->d_inode->i_uid =
David Howellsa001e5b2008-11-14 10:38:47 +11001182 current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001183 if (inode->i_mode & S_ISGID)
1184 direntry->d_inode->i_gid =
1185 inode->i_gid;
1186 else
1187 direntry->d_inode->i_gid =
David Howellsa001e5b2008-11-14 10:38:47 +11001188 current_fsgid();
Steve French6473a552005-11-29 20:20:10 -08001189 }
1190 }
Steve French2a138ebb2005-11-29 21:22:19 -08001191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001193mkdir_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 kfree(full_path);
1195 FreeXid(xid);
1196 return rc;
1197}
1198
1199int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1200{
1201 int rc = 0;
1202 int xid;
1203 struct cifs_sb_info *cifs_sb;
1204 struct cifsTconInfo *pTcon;
1205 char *full_path = NULL;
1206 struct cifsInodeInfo *cifsInode;
1207
Steve French26a21b92006-05-31 18:05:34 +00001208 cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
1210 xid = GetXid();
1211
1212 cifs_sb = CIFS_SB(inode->i_sb);
1213 pTcon = cifs_sb->tcon;
1214
Steve French7f573562005-08-30 11:32:14 -07001215 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301217 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301219 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 }
1221
Steve French737b7582005-04-28 22:41:06 -07001222 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1223 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225 if (!rc) {
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001226 drop_nlink(inode);
Steve French3677db12007-02-26 16:46:11 +00001227 spin_lock(&direntry->d_inode->i_lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001228 i_size_write(direntry->d_inode, 0);
Dave Hansence71ec32006-09-30 23:29:06 -07001229 clear_nlink(direntry->d_inode);
Steve French3677db12007-02-26 16:46:11 +00001230 spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 }
1232
1233 cifsInode = CIFS_I(direntry->d_inode);
1234 cifsInode->time = 0; /* force revalidate to go get info when
1235 needed */
Steve French42c24542009-01-13 22:03:55 +00001236
1237 cifsInode = CIFS_I(inode);
1238 cifsInode->time = 0; /* force revalidate to get parent dir info
1239 since cached search results now invalid */
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1242 current_fs_time(inode->i_sb);
1243
1244 kfree(full_path);
1245 FreeXid(xid);
1246 return rc;
1247}
1248
Steve Frenchee2fd962008-09-23 18:23:33 +00001249static int
1250cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
1251 struct dentry *to_dentry, const char *toPath)
1252{
1253 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
1254 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1255 __u16 srcfid;
1256 int oplock, rc;
1257
1258 /* try path-based rename first */
1259 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
1260 cifs_sb->mnt_cifs_flags &
1261 CIFS_MOUNT_MAP_SPECIAL_CHR);
1262
1263 /*
1264 * don't bother with rename by filehandle unless file is busy and
1265 * source Note that cross directory moves do not work with
1266 * rename by filehandle to various Windows servers.
1267 */
1268 if (rc == 0 || rc != -ETXTBSY)
1269 return rc;
1270
1271 /* open the file to be renamed -- we need DELETE perms */
1272 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
1273 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1274 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1275 CIFS_MOUNT_MAP_SPECIAL_CHR);
1276
1277 if (rc == 0) {
1278 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
1279 (const char *) to_dentry->d_name.name,
1280 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1281 CIFS_MOUNT_MAP_SPECIAL_CHR);
1282
1283 CIFSSMBClose(xid, pTcon, srcfid);
1284 }
1285
1286 return rc;
1287}
1288
Jeff Layton14121bd2008-10-20 14:45:22 -04001289int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1290 struct inode *target_dir, struct dentry *target_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291{
Steve Frenchee2fd962008-09-23 18:23:33 +00001292 char *fromName = NULL;
1293 char *toName = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 struct cifs_sb_info *cifs_sb_source;
1295 struct cifs_sb_info *cifs_sb_target;
Jeff Layton14121bd2008-10-20 14:45:22 -04001296 struct cifsTconInfo *tcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001297 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1298 FILE_UNIX_BASIC_INFO *info_buf_target;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001299 int xid, rc, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Jeff Layton14121bd2008-10-20 14:45:22 -04001301 cifs_sb_target = CIFS_SB(target_dir->i_sb);
1302 cifs_sb_source = CIFS_SB(source_dir->i_sb);
1303 tcon = cifs_sb_source->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
Steve Frenchee2fd962008-09-23 18:23:33 +00001305 xid = GetXid();
1306
1307 /*
1308 * BB: this might be allowed if same server, but different share.
1309 * Consider adding support for this
1310 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001311 if (tcon != cifs_sb_target->tcon) {
Steve Frenchee2fd962008-09-23 18:23:33 +00001312 rc = -EXDEV;
1313 goto cifs_rename_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
1315
Steve Frenchee2fd962008-09-23 18:23:33 +00001316 /*
1317 * we already have the rename sem so we do not need to
1318 * grab it again here to protect the path integrity
1319 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001320 fromName = build_path_from_dentry(source_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001321 if (fromName == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 rc = -ENOMEM;
1323 goto cifs_rename_exit;
1324 }
1325
Jeff Layton14121bd2008-10-20 14:45:22 -04001326 toName = build_path_from_dentry(target_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001327 if (toName == NULL) {
1328 rc = -ENOMEM;
1329 goto cifs_rename_exit;
1330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Jeff Layton14121bd2008-10-20 14:45:22 -04001332 rc = cifs_do_rename(xid, source_dentry, fromName,
1333 target_dentry, toName);
Steve Frenchee2fd962008-09-23 18:23:33 +00001334
Jeff Layton14121bd2008-10-20 14:45:22 -04001335 if (rc == -EEXIST && tcon->unix_ext) {
Steve Frenchee2fd962008-09-23 18:23:33 +00001336 /*
Jeff Layton14121bd2008-10-20 14:45:22 -04001337 * Are src and dst hardlinks of same inode? We can
1338 * only tell with unix extensions enabled
Steve Frenchee2fd962008-09-23 18:23:33 +00001339 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001340 info_buf_source =
1341 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1342 GFP_KERNEL);
1343 if (info_buf_source == NULL) {
1344 rc = -ENOMEM;
1345 goto cifs_rename_exit;
1346 }
1347
1348 info_buf_target = info_buf_source + 1;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001349 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
Jeff Layton14121bd2008-10-20 14:45:22 -04001350 info_buf_source,
1351 cifs_sb_source->local_nls,
1352 cifs_sb_source->mnt_cifs_flags &
1353 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton8d281ef2008-10-22 13:57:01 -04001354 if (tmprc != 0)
Jeff Layton14121bd2008-10-20 14:45:22 -04001355 goto unlink_target;
1356
Jeff Layton8d281ef2008-10-22 13:57:01 -04001357 tmprc = CIFSSMBUnixQPathInfo(xid, tcon,
Jeff Layton14121bd2008-10-20 14:45:22 -04001358 toName, info_buf_target,
1359 cifs_sb_target->local_nls,
1360 /* remap based on source sb */
1361 cifs_sb_source->mnt_cifs_flags &
1362 CIFS_MOUNT_MAP_SPECIAL_CHR);
1363
Jeff Layton8d281ef2008-10-22 13:57:01 -04001364 if (tmprc == 0 && (info_buf_source->UniqueId ==
Jeff Laytonae6884a2008-11-03 14:05:08 -05001365 info_buf_target->UniqueId)) {
Jeff Layton14121bd2008-10-20 14:45:22 -04001366 /* same file, POSIX says that this is a noop */
Jeff Laytonae6884a2008-11-03 14:05:08 -05001367 rc = 0;
Jeff Layton14121bd2008-10-20 14:45:22 -04001368 goto cifs_rename_exit;
Jeff Laytonae6884a2008-11-03 14:05:08 -05001369 }
Jeff Layton14121bd2008-10-20 14:45:22 -04001370 } /* else ... BB we could add the same check for Windows by
1371 checking the UniqueId via FILE_INTERNAL_INFO */
1372
Jeff Layton14121bd2008-10-20 14:45:22 -04001373unlink_target:
Jeff Laytonfc6f3942009-04-17 11:45:30 -04001374 /* Try unlinking the target dentry if it's not negative */
1375 if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
Jeff Layton8d281ef2008-10-22 13:57:01 -04001376 tmprc = cifs_unlink(target_dir, target_dentry);
Jeff Layton14121bd2008-10-20 14:45:22 -04001377 if (tmprc)
1378 goto cifs_rename_exit;
1379
Jeff Layton14121bd2008-10-20 14:45:22 -04001380 rc = cifs_do_rename(xid, source_dentry, fromName,
1381 target_dentry, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 }
1383
1384cifs_rename_exit:
Steve Frenchee2fd962008-09-23 18:23:33 +00001385 kfree(info_buf_source);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 kfree(fromName);
1387 kfree(toName);
1388 FreeXid(xid);
1389 return rc;
1390}
1391
1392int cifs_revalidate(struct dentry *direntry)
1393{
1394 int xid;
Jeff Laytoncea21802007-11-20 23:19:03 +00001395 int rc = 0, wbrc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 char *full_path;
1397 struct cifs_sb_info *cifs_sb;
1398 struct cifsInodeInfo *cifsInode;
1399 loff_t local_size;
1400 struct timespec local_mtime;
Steve French4b18f2a2008-04-29 00:06:05 +00001401 bool invalidate_inode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 if (direntry->d_inode == NULL)
1404 return -ENOENT;
1405
1406 cifsInode = CIFS_I(direntry->d_inode);
1407
1408 if (cifsInode == NULL)
1409 return -ENOENT;
1410
1411 /* no sense revalidating inode info on file that no one can write */
1412 if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
1413 return rc;
1414
1415 xid = GetXid();
1416
1417 cifs_sb = CIFS_SB(direntry->d_sb);
1418
1419 /* can not safely grab the rename sem here if rename calls revalidate
1420 since that would deadlock */
Steve French7f573562005-08-30 11:32:14 -07001421 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301423 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301425 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 }
1427 cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
1428 "jiffies %ld", full_path, direntry->d_inode,
1429 direntry->d_inode->i_count.counter, direntry,
1430 direntry->d_time, jiffies));
1431
1432 if (cifsInode->time == 0) {
1433 /* was set to zero previously to force revalidate */
1434 } else if (time_before(jiffies, cifsInode->time + HZ) &&
1435 lookupCacheEnabled) {
1436 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
1437 (direntry->d_inode->i_nlink == 1)) {
1438 kfree(full_path);
1439 FreeXid(xid);
1440 return rc;
1441 } else {
1442 cFYI(1, ("Have to revalidate file due to hardlinks"));
1443 }
1444 }
1445
1446 /* save mtime and size */
1447 local_mtime = direntry->d_inode->i_mtime;
1448 local_size = direntry->d_inode->i_size;
1449
Steve Frenchc18c8422007-07-18 23:21:09 +00001450 if (cifs_sb->tcon->unix_ext) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001452 direntry->d_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (rc) {
1454 cFYI(1, ("error on getting revalidate info %d", rc));
1455/* if (rc != -ENOENT)
1456 rc = 0; */ /* BB should we cache info on
1457 certain errors? */
1458 }
1459 } else {
1460 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +00001461 direntry->d_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 if (rc) {
1463 cFYI(1, ("error on getting revalidate info %d", rc));
1464/* if (rc != -ENOENT)
1465 rc = 0; */ /* BB should we cache info on
1466 certain errors? */
1467 }
1468 }
1469 /* should we remap certain errors, access denied?, to zero */
1470
1471 /* if not oplocked, we invalidate inode pages if mtime or file size
1472 had changed on server */
1473
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001474 if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 (local_size == direntry->d_inode->i_size)) {
1476 cFYI(1, ("cifs_revalidate - inode unchanged"));
1477 } else {
1478 /* file may have changed on server */
1479 if (cifsInode->clientCanCacheRead) {
1480 /* no need to invalidate inode pages since we were the
1481 only ones who could have modified the file and the
1482 server copy is staler than ours */
1483 } else {
Steve French4b18f2a2008-04-29 00:06:05 +00001484 invalidate_inode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 }
1486 }
1487
1488 /* can not grab this sem since kernel filesys locking documentation
Jes Sorensen1b1dcc12006-01-09 15:59:24 -08001489 indicates i_mutex may be taken by the kernel on lookup and rename
1490 which could deadlock if we grab the i_mutex here as well */
1491/* mutex_lock(&direntry->d_inode->i_mutex);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 /* need to write out dirty pages here */
1493 if (direntry->d_inode->i_mapping) {
1494 /* do we need to lock inode until after invalidate completes
1495 below? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001496 wbrc = filemap_fdatawrite(direntry->d_inode->i_mapping);
1497 if (wbrc)
1498 CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 }
1500 if (invalidate_inode) {
Steve French3abb9272005-11-28 08:16:13 -08001501 /* shrink_dcache not necessary now that cifs dentry ops
1502 are exported for negative dentries */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001503/* if (S_ISDIR(direntry->d_inode->i_mode))
Steve French3abb9272005-11-28 08:16:13 -08001504 shrink_dcache_parent(direntry); */
1505 if (S_ISREG(direntry->d_inode->i_mode)) {
Suresh Jayaraman9e96af82008-08-05 14:38:40 +05301506 if (direntry->d_inode->i_mapping) {
Jeff Laytoncea21802007-11-20 23:19:03 +00001507 wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
1508 if (wbrc)
1509 CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
Suresh Jayaraman9e96af82008-08-05 14:38:40 +05301510 }
Steve French3abb9272005-11-28 08:16:13 -08001511 /* may eventually have to do this for open files too */
1512 if (list_empty(&(cifsInode->openFileList))) {
1513 /* changed on server - flush read ahead pages */
1514 cFYI(1, ("Invalidating read ahead data on "
1515 "closed file"));
1516 invalidate_remote_inode(direntry->d_inode);
1517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 }
1519 }
Jes Sorensen1b1dcc12006-01-09 15:59:24 -08001520/* mutex_unlock(&direntry->d_inode->i_mutex); */
Steve French50c2f752007-07-13 00:33:32 +00001521
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 kfree(full_path);
1523 FreeXid(xid);
1524 return rc;
1525}
1526
1527int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1528 struct kstat *stat)
1529{
1530 int err = cifs_revalidate(dentry);
Steve French5fe14c82006-11-07 19:26:33 +00001531 if (!err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 generic_fillattr(dentry->d_inode, stat);
Steve French5fe14c82006-11-07 19:26:33 +00001533 stat->blksize = CIFS_MAX_MSGSIZE;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001534 stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
Steve French5fe14c82006-11-07 19:26:33 +00001535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 return err;
1537}
1538
1539static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1540{
1541 pgoff_t index = from >> PAGE_CACHE_SHIFT;
1542 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1543 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 int rc = 0;
1545
1546 page = grab_cache_page(mapping, index);
1547 if (!page)
1548 return -ENOMEM;
1549
Christoph Lametereebd2aa2008-02-04 22:28:29 -08001550 zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 unlock_page(page);
1552 page_cache_release(page);
1553 return rc;
1554}
1555
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001556static int cifs_vmtruncate(struct inode *inode, loff_t offset)
Steve French3677db12007-02-26 16:46:11 +00001557{
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001558 loff_t oldsize;
1559 int err;
Steve French3677db12007-02-26 16:46:11 +00001560
Steve Frenchba6a46a2007-02-26 20:06:29 +00001561 spin_lock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001562 err = inode_newsize_ok(inode, offset);
1563 if (err) {
Steve Frenchba6a46a2007-02-26 20:06:29 +00001564 spin_unlock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001565 goto out;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001566 }
Steve French3677db12007-02-26 16:46:11 +00001567
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001568 oldsize = inode->i_size;
Steve French3677db12007-02-26 16:46:11 +00001569 i_size_write(inode, offset);
Steve Frenchba6a46a2007-02-26 20:06:29 +00001570 spin_unlock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001571 truncate_pagecache(inode, oldsize, offset);
Al Viroacfa4382008-12-04 10:06:33 -05001572 if (inode->i_op->truncate)
Steve French3677db12007-02-26 16:46:11 +00001573 inode->i_op->truncate(inode);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001574out:
1575 return err;
Steve French3677db12007-02-26 16:46:11 +00001576}
1577
Jeff Layton8efdbde2008-07-23 21:28:12 +00001578static int
1579cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1580 int xid, char *full_path)
1581{
1582 int rc;
1583 struct cifsFileInfo *open_file;
1584 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1585 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1586 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1587
1588 /*
1589 * To avoid spurious oplock breaks from server, in the case of
1590 * inodes that we already have open, avoid doing path based
1591 * setting of file size if we can do it by handle.
1592 * This keeps our caching token (oplock) and avoids timeouts
1593 * when the local oplock break takes longer to flush
1594 * writebehind data than the SMB timeout for the SetPathInfo
1595 * request would allow
1596 */
1597 open_file = find_writable_file(cifsInode);
1598 if (open_file) {
1599 __u16 nfid = open_file->netfid;
1600 __u32 npid = open_file->pid;
1601 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
1602 npid, false);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001603 cifsFileInfo_put(open_file);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001604 cFYI(1, ("SetFSize for attrs rc = %d", rc));
1605 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1606 unsigned int bytes_written;
1607 rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size,
1608 &bytes_written, NULL, NULL, 1);
1609 cFYI(1, ("Wrt seteof rc %d", rc));
1610 }
1611 } else
1612 rc = -EINVAL;
1613
1614 if (rc != 0) {
1615 /* Set file size by pathname rather than by handle
1616 either because no valid, writeable file handle for
1617 it was found or because there was an error setting
1618 it by handle */
1619 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
1620 false, cifs_sb->local_nls,
1621 cifs_sb->mnt_cifs_flags &
1622 CIFS_MOUNT_MAP_SPECIAL_CHR);
1623 cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
1624 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1625 __u16 netfid;
1626 int oplock = 0;
1627
1628 rc = SMBLegacyOpen(xid, pTcon, full_path,
1629 FILE_OPEN, GENERIC_WRITE,
1630 CREATE_NOT_DIR, &netfid, &oplock, NULL,
1631 cifs_sb->local_nls,
1632 cifs_sb->mnt_cifs_flags &
1633 CIFS_MOUNT_MAP_SPECIAL_CHR);
1634 if (rc == 0) {
1635 unsigned int bytes_written;
1636 rc = CIFSSMBWrite(xid, pTcon, netfid, 0,
1637 attrs->ia_size,
1638 &bytes_written, NULL,
1639 NULL, 1);
1640 cFYI(1, ("wrt seteof rc %d", rc));
1641 CIFSSMBClose(xid, pTcon, netfid);
1642 }
1643 }
1644 }
1645
1646 if (rc == 0) {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001647 cifsInode->server_eof = attrs->ia_size;
Jeff Layton8efdbde2008-07-23 21:28:12 +00001648 rc = cifs_vmtruncate(inode, attrs->ia_size);
1649 cifs_truncate_page(inode->i_mapping, inode->i_size);
1650 }
1651
1652 return rc;
1653}
1654
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001655static int
1656cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1657{
1658 int rc;
1659 int xid;
1660 char *full_path = NULL;
1661 struct inode *inode = direntry->d_inode;
1662 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1663 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1664 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1665 struct cifs_unix_set_info_args *args = NULL;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001666 struct cifsFileInfo *open_file;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001667
1668 cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x",
1669 direntry->d_name.name, attrs->ia_valid));
1670
1671 xid = GetXid();
1672
1673 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
1674 /* check if we have permission to change attrs */
1675 rc = inode_change_ok(inode, attrs);
1676 if (rc < 0)
1677 goto out;
1678 else
1679 rc = 0;
1680 }
1681
1682 full_path = build_path_from_dentry(direntry);
1683 if (full_path == NULL) {
1684 rc = -ENOMEM;
1685 goto out;
1686 }
1687
Jeff Layton0f4d6342009-03-26 13:35:37 -04001688 /*
1689 * Attempt to flush data before changing attributes. We need to do
1690 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
1691 * ownership or mode then we may also need to do this. Here, we take
1692 * the safe way out and just do the flush on all setattr requests. If
1693 * the flush returns error, store it to report later and continue.
1694 *
1695 * BB: This should be smarter. Why bother flushing pages that
1696 * will be truncated anyway? Also, should we error out here if
1697 * the flush returns error?
1698 */
1699 rc = filemap_write_and_wait(inode->i_mapping);
1700 if (rc != 0) {
1701 cifsInode->write_behind_rc = rc;
1702 rc = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001703 }
1704
1705 if (attrs->ia_valid & ATTR_SIZE) {
1706 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1707 if (rc != 0)
1708 goto out;
1709 }
1710
1711 /* skip mode change if it's just for clearing setuid/setgid */
1712 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1713 attrs->ia_valid &= ~ATTR_MODE;
1714
1715 args = kmalloc(sizeof(*args), GFP_KERNEL);
1716 if (args == NULL) {
1717 rc = -ENOMEM;
1718 goto out;
1719 }
1720
1721 /* set up the struct */
1722 if (attrs->ia_valid & ATTR_MODE)
1723 args->mode = attrs->ia_mode;
1724 else
1725 args->mode = NO_CHANGE_64;
1726
1727 if (attrs->ia_valid & ATTR_UID)
1728 args->uid = attrs->ia_uid;
1729 else
1730 args->uid = NO_CHANGE_64;
1731
1732 if (attrs->ia_valid & ATTR_GID)
1733 args->gid = attrs->ia_gid;
1734 else
1735 args->gid = NO_CHANGE_64;
1736
1737 if (attrs->ia_valid & ATTR_ATIME)
1738 args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
1739 else
1740 args->atime = NO_CHANGE_64;
1741
1742 if (attrs->ia_valid & ATTR_MTIME)
1743 args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
1744 else
1745 args->mtime = NO_CHANGE_64;
1746
1747 if (attrs->ia_valid & ATTR_CTIME)
1748 args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
1749 else
1750 args->ctime = NO_CHANGE_64;
1751
1752 args->device = 0;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001753 open_file = find_writable_file(cifsInode);
1754 if (open_file) {
1755 u16 nfid = open_file->netfid;
1756 u32 npid = open_file->pid;
1757 rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001758 cifsFileInfo_put(open_file);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001759 } else {
1760 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
Jeff Layton01ea95e2009-07-09 20:02:49 -04001761 cifs_sb->local_nls,
1762 cifs_sb->mnt_cifs_flags &
1763 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001764 }
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001765
Steve Frenchccd4bb12010-02-08 17:39:58 +00001766 if (!rc) {
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001767 rc = inode_setattr(inode, attrs);
Steve Frenchccd4bb12010-02-08 17:39:58 +00001768
1769 /* force revalidate when any of these times are set since some
1770 of the fs types (eg ext3, fat) do not have fine enough
1771 time granularity to match protocol, and we do not have a
1772 a way (yet) to query the server fs's time granularity (and
1773 whether it rounds times down).
1774 */
1775 if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)))
1776 cifsInode->time = 0;
1777 }
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001778out:
1779 kfree(args);
1780 kfree(full_path);
1781 FreeXid(xid);
1782 return rc;
1783}
1784
Jeff Layton0510eeb2008-08-02 07:26:12 -04001785static int
1786cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787{
1788 int xid;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001789 struct inode *inode = direntry->d_inode;
1790 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001791 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 char *full_path = NULL;
1793 int rc = -EACCES;
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001794 __u32 dosattr = 0;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001795 __u64 mode = NO_CHANGE_64;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001796
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 xid = GetXid();
1798
Steve French39798772006-05-31 22:40:51 +00001799 cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 direntry->d_name.name, attrs->ia_valid));
Steve French6473a552005-11-29 20:20:10 -08001801
Steve French2a138ebb2005-11-29 21:22:19 -08001802 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
Steve French6473a552005-11-29 20:20:10 -08001803 /* check if we have permission to change attrs */
Jeff Layton02eadef2008-05-09 21:26:11 +00001804 rc = inode_change_ok(inode, attrs);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001805 if (rc < 0) {
Steve French6473a552005-11-29 20:20:10 -08001806 FreeXid(xid);
1807 return rc;
1808 } else
1809 rc = 0;
1810 }
Steve French50c2f752007-07-13 00:33:32 +00001811
Steve French7f573562005-08-30 11:32:14 -07001812 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301814 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301816 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818
Jeff Layton0f4d6342009-03-26 13:35:37 -04001819 /*
1820 * Attempt to flush data before changing attributes. We need to do
1821 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
1822 * ownership or mode then we may also need to do this. Here, we take
1823 * the safe way out and just do the flush on all setattr requests. If
1824 * the flush returns error, store it to report later and continue.
1825 *
1826 * BB: This should be smarter. Why bother flushing pages that
1827 * will be truncated anyway? Also, should we error out here if
1828 * the flush returns error?
1829 */
1830 rc = filemap_write_and_wait(inode->i_mapping);
1831 if (rc != 0) {
1832 cifsInode->write_behind_rc = rc;
1833 rc = 0;
Steve French50531442008-03-14 19:21:31 +00001834 }
Jeff Laytoncea21802007-11-20 23:19:03 +00001835
Steve French50531442008-03-14 19:21:31 +00001836 if (attrs->ia_valid & ATTR_SIZE) {
Jeff Layton8efdbde2008-07-23 21:28:12 +00001837 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1838 if (rc != 0)
Steve Frenche30dcf32005-09-20 20:49:16 -07001839 goto cifs_setattr_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 }
Jeff Layton4ca691a2008-05-22 09:33:34 -04001841
1842 /*
1843 * Without unix extensions we can't send ownership changes to the
1844 * server, so silently ignore them. This is consistent with how
1845 * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With
1846 * CIFSACL support + proper Windows to Unix idmapping, we may be
1847 * able to support this in the future.
1848 */
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001849 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
Jeff Layton4ca691a2008-05-22 09:33:34 -04001850 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
Jeff Laytond32c4f22007-10-18 03:05:22 -07001852 /* skip mode change if it's just for clearing setuid/setgid */
1853 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1854 attrs->ia_valid &= ~ATTR_MODE;
1855
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 if (attrs->ia_valid & ATTR_MODE) {
Jeff Layton51328612008-05-22 09:33:34 -04001857 cFYI(1, ("Mode changed to 0%o", attrs->ia_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 mode = attrs->ia_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 }
1860
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001861 if (attrs->ia_valid & ATTR_MODE) {
Steve Frenchcdbce9c2005-11-19 21:04:52 -08001862 rc = 0;
Steve French97837582007-12-31 07:47:21 +00001863#ifdef CONFIG_CIFS_EXPERIMENTAL
1864 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
Jeff Layton02eadef2008-05-09 21:26:11 +00001865 rc = mode_to_acl(inode, full_path, mode);
Jeff Layton51328612008-05-22 09:33:34 -04001866 else
Steve French97837582007-12-31 07:47:21 +00001867#endif
Jeff Layton51328612008-05-22 09:33:34 -04001868 if (((mode & S_IWUGO) == 0) &&
1869 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001870
1871 dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
1872
Jeff Layton51328612008-05-22 09:33:34 -04001873 /* fix up mode if we're not using dynperm */
1874 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
1875 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
1876 } else if ((mode & S_IWUGO) &&
1877 (cifsInode->cifsAttrs & ATTR_READONLY)) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001878
1879 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
1880 /* Attributes of 0 are ignored */
1881 if (dosattr == 0)
1882 dosattr |= ATTR_NORMAL;
Jeff Layton51328612008-05-22 09:33:34 -04001883
1884 /* reset local inode permissions to normal */
1885 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1886 attrs->ia_mode &= ~(S_IALLUGO);
1887 if (S_ISDIR(inode->i_mode))
1888 attrs->ia_mode |=
1889 cifs_sb->mnt_dir_mode;
1890 else
1891 attrs->ia_mode |=
1892 cifs_sb->mnt_file_mode;
1893 }
1894 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1895 /* ignore mode change - ATTR_READONLY hasn't changed */
1896 attrs->ia_valid &= ~ATTR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
1899
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001900 if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
1901 ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
1902 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
1903 /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
Steve Frenche30dcf32005-09-20 20:49:16 -07001905 /* Even if error on time set, no sense failing the call if
1906 the server would set the time to a reasonable value anyway,
1907 and this check ensures that we are not being called from
1908 sys_utimes in which case we ought to fail the call back to
1909 the user when the server rejects the call */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001910 if ((rc) && (attrs->ia_valid &
Jeff Laytonfeb3e202008-08-02 07:26:12 -04001911 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
Steve Frenche30dcf32005-09-20 20:49:16 -07001912 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 }
1914
1915 /* do not need local check to inode_check_ok since the server does
1916 that */
1917 if (!rc)
Jeff Layton02eadef2008-05-09 21:26:11 +00001918 rc = inode_setattr(inode, attrs);
Steve Frenche30dcf32005-09-20 20:49:16 -07001919cifs_setattr_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 kfree(full_path);
1921 FreeXid(xid);
1922 return rc;
1923}
1924
Jeff Layton0510eeb2008-08-02 07:26:12 -04001925int
1926cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1927{
1928 struct inode *inode = direntry->d_inode;
1929 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1930 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1931
1932 if (pTcon->unix_ext)
1933 return cifs_setattr_unix(direntry, attrs);
1934
1935 return cifs_setattr_nounix(direntry, attrs);
1936
1937 /* BB: add cifs_setattr_legacy for really old servers */
1938}
1939
Steve French99ee4db2007-02-27 05:35:17 +00001940#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941void cifs_delete_inode(struct inode *inode)
1942{
Steve French26a21b92006-05-31 18:05:34 +00001943 cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 /* may have to add back in if and when safe distributed caching of
1945 directories added e.g. via FindNotify */
1946}
Steve French99ee4db2007-02-27 05:35:17 +00001947#endif