blob: 4f0ee67eb9540e51d2e980637595461827259758 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/inode.c
3 *
Steve French2dd29d32007-04-23 22:07:35 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
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:
Igor Mammedov79626702008-03-09 03:44:18 +000060 if (is_dfs_referral) {
61 inode->i_op = &cifs_dfs_referral_inode_operations;
62 } else {
63 inode->i_op = &cifs_dir_inode_ops;
64 inode->i_fop = &cifs_dir_ops;
65 }
Christoph Hellwig70eff552008-02-15 20:55:05 +000066 break;
67 case S_IFLNK:
68 inode->i_op = &cifs_symlink_inode_ops;
69 break;
70 default:
71 init_special_inode(inode, inode->i_mode, inode->i_rdev);
72 break;
73 }
74}
75
Christoph Hellwig75f12982008-02-25 20:25:21 +000076static void cifs_unix_info_to_inode(struct inode *inode,
77 FILE_UNIX_BASIC_INFO *info, int force_uid_gid)
78{
79 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
80 struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
81 __u64 num_of_bytes = le64_to_cpu(info->NumOfBytes);
82 __u64 end_of_file = le64_to_cpu(info->EndOfFile);
83
84 inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(info->LastAccessTime));
85 inode->i_mtime =
86 cifs_NTtimeToUnix(le64_to_cpu(info->LastModificationTime));
87 inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(info->LastStatusChange));
88 inode->i_mode = le64_to_cpu(info->Permissions);
89
90 /*
91 * Since we set the inode type below we need to mask off
92 * to avoid strange results if bits set above.
93 */
94 inode->i_mode &= ~S_IFMT;
95 switch (le32_to_cpu(info->Type)) {
96 case UNIX_FILE:
97 inode->i_mode |= S_IFREG;
98 break;
99 case UNIX_SYMLINK:
100 inode->i_mode |= S_IFLNK;
101 break;
102 case UNIX_DIR:
103 inode->i_mode |= S_IFDIR;
104 break;
105 case UNIX_CHARDEV:
106 inode->i_mode |= S_IFCHR;
107 inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
108 le64_to_cpu(info->DevMinor) & MINORMASK);
109 break;
110 case UNIX_BLOCKDEV:
111 inode->i_mode |= S_IFBLK;
112 inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
113 le64_to_cpu(info->DevMinor) & MINORMASK);
114 break;
115 case UNIX_FIFO:
116 inode->i_mode |= S_IFIFO;
117 break;
118 case UNIX_SOCKET:
119 inode->i_mode |= S_IFSOCK;
120 break;
121 default:
122 /* safest to call it a file if we do not know */
123 inode->i_mode |= S_IFREG;
124 cFYI(1, ("unknown type %d", le32_to_cpu(info->Type)));
125 break;
126 }
127
128 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) &&
129 !force_uid_gid)
130 inode->i_uid = cifs_sb->mnt_uid;
131 else
132 inode->i_uid = le64_to_cpu(info->Uid);
133
134 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) &&
135 !force_uid_gid)
136 inode->i_gid = cifs_sb->mnt_gid;
137 else
138 inode->i_gid = le64_to_cpu(info->Gid);
139
140 inode->i_nlink = le64_to_cpu(info->Nlinks);
141
142 spin_lock(&inode->i_lock);
143 if (is_size_safe_to_change(cifsInfo, end_of_file)) {
144 /*
145 * We can not safely change the file size here if the client
146 * is writing to it due to potential races.
147 */
148 i_size_write(inode, end_of_file);
149
150 /*
151 * i_blocks is not related to (i_size / i_blksize),
152 * but instead 512 byte (2**9) size is required for
153 * calculating num blocks.
154 */
155 inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
156 }
157 spin_unlock(&inode->i_lock);
158}
159
Igor Mammedov79626702008-03-09 03:44:18 +0000160static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon,
161 const char *search_path)
162{
163 int tree_len;
164 int path_len;
165 char *tmp_path;
166
167 if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
168 return search_path;
169
170 /* use full path name for working with DFS */
171 tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
172 path_len = strnlen(search_path, MAX_PATHCONF);
173
174 tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL);
175 if (tmp_path == NULL)
176 return search_path;
177
178 strncpy(tmp_path, pTcon->treeName, tree_len);
179 strncpy(tmp_path+tree_len, search_path, path_len);
180 tmp_path[tree_len+path_len] = 0;
181 return tmp_path;
182}
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184int cifs_get_inode_info_unix(struct inode **pinode,
185 const unsigned char *search_path, struct super_block *sb, int xid)
186{
187 int rc = 0;
188 FILE_UNIX_BASIC_INFO findData;
189 struct cifsTconInfo *pTcon;
190 struct inode *inode;
191 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Igor Mammedov79626702008-03-09 03:44:18 +0000192 const unsigned char *full_path;
193 bool is_dfs_referral = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 pTcon = cifs_sb->tcon;
Steve French26a21b92006-05-31 18:05:34 +0000196 cFYI(1, ("Getting info on %s", search_path));
Igor Mammedov79626702008-03-09 03:44:18 +0000197
198 full_path = cifs_get_search_path(pTcon, search_path);
199
200try_again_CIFSSMBUnixQPathInfo:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 /* could have done a find first instead but this returns more info */
Igor Mammedov79626702008-03-09 03:44:18 +0000202 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData,
Steve French737b7582005-04-28 22:41:06 -0700203 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
204 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205/* dump_mem("\nUnixQPathInfo return data", &findData,
206 sizeof(findData)); */
207 if (rc) {
Igor Mammedov79626702008-03-09 03:44:18 +0000208 if (rc == -EREMOTE && !is_dfs_referral) {
209 is_dfs_referral = true;
210 full_path = search_path;
211 goto try_again_CIFSSMBUnixQPathInfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 }
Igor Mammedov79626702008-03-09 03:44:18 +0000213 goto cgiiu_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 } else {
215 struct cifsInodeInfo *cifsInfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
217 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
218
219 /* get new inode */
220 if (*pinode == NULL) {
221 *pinode = new_inode(sb);
Igor Mammedov79626702008-03-09 03:44:18 +0000222 if (*pinode == NULL) {
223 rc = -ENOMEM;
224 goto cgiiu_exit;
225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 /* Is an i_ino of zero legal? */
227 /* Are there sanity checks we can use to ensure that
228 the server is really filling in that field? */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700229 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 (*pinode)->i_ino =
231 (unsigned long)findData.UniqueId;
232 } /* note ino incremented to unique num in new_inode */
Steve French4523cc32007-04-30 20:13:06 +0000233 if (sb->s_flags & MS_NOATIME)
Steve French1b2b2122007-02-17 04:30:54 +0000234 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
Steve French50c2f752007-07-13 00:33:32 +0000235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 insert_inode_hash(*pinode);
237 }
238
239 inode = *pinode;
240 cifsInfo = CIFS_I(inode);
241
Steve French26a21b92006-05-31 18:05:34 +0000242 cFYI(1, ("Old time %ld", cifsInfo->time));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 cifsInfo->time = jiffies;
Steve French26a21b92006-05-31 18:05:34 +0000244 cFYI(1, ("New time %ld", cifsInfo->time));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 /* this is ok to set on every inode revalidate */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000246 atomic_set(&cifsInfo->inUse, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Christoph Hellwig75f12982008-02-25 20:25:21 +0000248 cifs_unix_info_to_inode(inode, &findData, 0);
Steve French50c2f752007-07-13 00:33:32 +0000249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 if (num_of_bytes < end_of_file)
Steve French8b94bcb2005-11-11 11:41:00 -0800252 cFYI(1, ("allocation size less than end of file"));
Andrew Morton5515eff2006-03-26 01:37:53 -0800253 cFYI(1, ("Size %ld and blocks %llu",
254 (unsigned long) inode->i_size,
255 (unsigned long long)inode->i_blocks));
Steve French8b94bcb2005-11-11 11:41:00 -0800256
Igor Mammedov79626702008-03-09 03:44:18 +0000257 cifs_set_ops(inode, is_dfs_referral);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
Igor Mammedov79626702008-03-09 03:44:18 +0000259cgiiu_exit:
260 if (full_path != search_path)
261 kfree(full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 return rc;
263}
264
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000265static int decode_sfu_inode(struct inode *inode, __u64 size,
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800266 const unsigned char *path,
267 struct cifs_sb_info *cifs_sb, int xid)
268{
269 int rc;
270 int oplock = FALSE;
271 __u16 netfid;
272 struct cifsTconInfo *pTcon = cifs_sb->tcon;
Steve French86c96b42005-11-18 20:25:31 -0800273 char buf[24];
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800274 unsigned int bytes_read;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000275 char *pbuf;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800276
277 pbuf = buf;
278
Steve French4523cc32007-04-30 20:13:06 +0000279 if (size == 0) {
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800280 inode->i_mode |= S_IFIFO;
281 return 0;
282 } else if (size < 8) {
283 return -EINVAL; /* EOPNOTSUPP? */
284 }
Steve French50c2f752007-07-13 00:33:32 +0000285
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800286 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
287 CREATE_NOT_DIR, &netfid, &oplock, NULL,
288 cifs_sb->local_nls,
289 cifs_sb->mnt_cifs_flags &
290 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000291 if (rc == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -0800292 int buf_type = CIFS_NO_BUFFER;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800293 /* Read header */
294 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000295 netfid,
Steve French86c96b42005-11-18 20:25:31 -0800296 24 /* length */, 0 /* offset */,
Steve Frenchec637e32005-12-12 20:53:18 -0800297 &bytes_read, &pbuf, &buf_type);
Steve French4523cc32007-04-30 20:13:06 +0000298 if ((rc == 0) && (bytes_read >= 8)) {
299 if (memcmp("IntxBLK", pbuf, 8) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000300 cFYI(1, ("Block device"));
Steve French3020a1f2005-11-18 11:31:10 -0800301 inode->i_mode |= S_IFBLK;
Steve French4523cc32007-04-30 20:13:06 +0000302 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800303 /* we have enough to decode dev num */
304 __u64 mjr; /* major */
305 __u64 mnr; /* minor */
306 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
307 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
308 inode->i_rdev = MKDEV(mjr, mnr);
309 }
Steve French4523cc32007-04-30 20:13:06 +0000310 } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000311 cFYI(1, ("Char device"));
Steve French3020a1f2005-11-18 11:31:10 -0800312 inode->i_mode |= S_IFCHR;
Steve French4523cc32007-04-30 20:13:06 +0000313 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800314 /* we have enough to decode dev num */
315 __u64 mjr; /* major */
316 __u64 mnr; /* minor */
317 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
318 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
319 inode->i_rdev = MKDEV(mjr, mnr);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000320 }
Steve French4523cc32007-04-30 20:13:06 +0000321 } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000322 cFYI(1, ("Symlink"));
Steve French3020a1f2005-11-18 11:31:10 -0800323 inode->i_mode |= S_IFLNK;
Steve French86c96b42005-11-18 20:25:31 -0800324 } else {
325 inode->i_mode |= S_IFREG; /* file? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000326 rc = -EOPNOTSUPP;
Steve French86c96b42005-11-18 20:25:31 -0800327 }
Steve French3020a1f2005-11-18 11:31:10 -0800328 } else {
329 inode->i_mode |= S_IFREG; /* then it is a file */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000330 rc = -EOPNOTSUPP; /* or some unknown SFU type */
331 }
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800332 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800333 }
334 return rc;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800335}
336
Steve French9e294f12005-11-17 16:59:21 -0800337#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
338
Steve French953f8682007-10-31 04:54:42 +0000339static int get_sfu_mode(struct inode *inode,
Steve French9e294f12005-11-17 16:59:21 -0800340 const unsigned char *path,
341 struct cifs_sb_info *cifs_sb, int xid)
342{
Steve French3020a1f2005-11-18 11:31:10 -0800343#ifdef CONFIG_CIFS_XATTR
Steve French9e294f12005-11-17 16:59:21 -0800344 ssize_t rc;
345 char ea_value[4];
346 __u32 mode;
347
348 rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
349 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000350 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4523cc32007-04-30 20:13:06 +0000351 if (rc < 0)
Steve French9e294f12005-11-17 16:59:21 -0800352 return (int)rc;
353 else if (rc > 3) {
354 mode = le32_to_cpu(*((__le32 *)ea_value));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000355 inode->i_mode &= ~SFBITS_MASK;
356 cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
Steve French9e294f12005-11-17 16:59:21 -0800357 inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000358 cFYI(1, ("special mode bits 0%o", mode));
Steve French9e294f12005-11-17 16:59:21 -0800359 return 0;
360 } else {
361 return 0;
362 }
Steve French3020a1f2005-11-18 11:31:10 -0800363#else
364 return -EOPNOTSUPP;
365#endif
Steve French9e294f12005-11-17 16:59:21 -0800366}
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368int cifs_get_inode_info(struct inode **pinode,
369 const unsigned char *search_path, FILE_ALL_INFO *pfindData,
370 struct super_block *sb, int xid)
371{
372 int rc = 0;
373 struct cifsTconInfo *pTcon;
374 struct inode *inode;
375 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Igor Mammedov79626702008-03-09 03:44:18 +0000376 const unsigned char *full_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 char *buf = NULL;
Steve French8d6286f2006-11-16 22:48:25 +0000378 int adjustTZ = FALSE;
Igor Mammedov79626702008-03-09 03:44:18 +0000379 bool is_dfs_referral = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 pTcon = cifs_sb->tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000382 cFYI(1, ("Getting info on %s", search_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700384 if ((pfindData == NULL) && (*pinode != NULL)) {
385 if (CIFS_I(*pinode)->clientCanCacheRead) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000386 cFYI(1, ("No need to revalidate cached inode sizes"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 return rc;
388 }
389 }
390
391 /* if file info not passed in then get it from server */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700392 if (pfindData == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700394 if (buf == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return -ENOMEM;
396 pfindData = (FILE_ALL_INFO *)buf;
Igor Mammedov79626702008-03-09 03:44:18 +0000397
398 full_path = cifs_get_search_path(pTcon, search_path);
399
400try_again_CIFSSMBQPathInfo:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 /* could do find first instead but this returns more info */
Igor Mammedov79626702008-03-09 03:44:18 +0000402 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +0000403 0 /* not legacy */,
Steve French6b8edfe2005-08-23 20:26:03 -0700404 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700405 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French6b8edfe2005-08-23 20:26:03 -0700406 /* BB optimize code so we do not make the above call
407 when server claims no NT SMB support and the above call
408 failed at least once - set flag in tcon or mount */
Steve French4523cc32007-04-30 20:13:06 +0000409 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
Igor Mammedov79626702008-03-09 03:44:18 +0000410 rc = SMBQueryInformation(xid, pTcon, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000411 pfindData, cifs_sb->local_nls,
Steve French6b8edfe2005-08-23 20:26:03 -0700412 cifs_sb->mnt_cifs_flags &
413 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French8d6286f2006-11-16 22:48:25 +0000414 adjustTZ = TRUE;
Steve French6b8edfe2005-08-23 20:26:03 -0700415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 }
417 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
418 if (rc) {
Igor Mammedov79626702008-03-09 03:44:18 +0000419 if (rc == -EREMOTE && !is_dfs_referral) {
420 is_dfs_referral = true;
421 full_path = search_path;
422 goto try_again_CIFSSMBQPathInfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 }
Igor Mammedov79626702008-03-09 03:44:18 +0000424 goto cgii_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 } else {
426 struct cifsInodeInfo *cifsInfo;
427 __u32 attr = le32_to_cpu(pfindData->Attributes);
428
429 /* get new inode */
430 if (*pinode == NULL) {
431 *pinode = new_inode(sb);
Steve Frenchacf1a1b2006-10-12 03:28:28 +0000432 if (*pinode == NULL) {
Igor Mammedov79626702008-03-09 03:44:18 +0000433 rc = -ENOMEM;
434 goto cgii_exit;
Steve Frenchacf1a1b2006-10-12 03:28:28 +0000435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 /* Is an i_ino of zero legal? Can we use that to check
437 if the server supports returning inode numbers? Are
438 there other sanity checks we can use to ensure that
439 the server is really filling in that field? */
440
441 /* We can not use the IndexNumber field by default from
442 Windows or Samba (in ALL_INFO buf) but we can request
443 it explicitly. It may not be unique presumably if
444 the server has multiple devices mounted under one
445 share */
446
447 /* There may be higher info levels that work but are
448 there Windows server or network appliances for which
449 IndexNumber field is not guaranteed unique? */
450
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000451 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 int rc1 = 0;
453 __u64 inode_num;
454
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000455 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
456 search_path, &inode_num,
Steve French737b7582005-04-28 22:41:06 -0700457 cifs_sb->local_nls,
458 cifs_sb->mnt_cifs_flags &
459 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700460 if (rc1) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000461 cFYI(1, ("GetSrvInodeNum rc %d", rc1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 /* BB EOPNOSUPP disable SERVER_INUM? */
463 } else /* do we need cast or hash to ino? */
464 (*pinode)->i_ino = inode_num;
465 } /* else ino incremented to unique num in new_inode*/
Steve French4523cc32007-04-30 20:13:06 +0000466 if (sb->s_flags & MS_NOATIME)
Steve French1b2b2122007-02-17 04:30:54 +0000467 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 insert_inode_hash(*pinode);
469 }
470 inode = *pinode;
471 cifsInfo = CIFS_I(inode);
472 cifsInfo->cifsAttrs = attr;
Steve French26a21b92006-05-31 18:05:34 +0000473 cFYI(1, ("Old time %ld", cifsInfo->time));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 cifsInfo->time = jiffies;
Steve French26a21b92006-05-31 18:05:34 +0000475 cFYI(1, ("New time %ld", cifsInfo->time));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477 /* blksize needs to be multiple of two. So safer to default to
478 blksize and blkbits set in superblock so 2**blkbits and blksize
479 will match rather than setting to:
480 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
481
Steve French26a21b92006-05-31 18:05:34 +0000482 /* Linux can not store file creation time so ignore it */
Steve French4523cc32007-04-30 20:13:06 +0000483 if (pfindData->LastAccessTime)
Steve French1bd5bbc2006-09-28 03:35:57 +0000484 inode->i_atime = cifs_NTtimeToUnix
485 (le64_to_cpu(pfindData->LastAccessTime));
486 else /* do not need to use current_fs_time - time not stored */
487 inode->i_atime = CURRENT_TIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 inode->i_mtime =
489 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
490 inode->i_ctime =
491 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
Steve French26a21b92006-05-31 18:05:34 +0000492 cFYI(0, ("Attributes came in as 0x%x", attr));
Steve French4523cc32007-04-30 20:13:06 +0000493 if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
Steve French8d6286f2006-11-16 22:48:25 +0000494 inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000495 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
Steve French8d6286f2006-11-16 22:48:25 +0000496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
498 /* set default mode. will override for dirs below */
499 if (atomic_read(&cifsInfo->inUse) == 0)
500 /* new inode, can safely set these fields */
501 inode->i_mode = cifs_sb->mnt_file_mode;
Steve French3020a1f2005-11-18 11:31:10 -0800502 else /* since we set the inode type below we need to mask off
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000503 to avoid strange results if type changes and both
504 get orred in */
505 inode->i_mode &= ~S_IFMT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506/* if (attr & ATTR_REPARSE) */
507 /* We no longer handle these as symlinks because we could not
508 follow them due to the absolute path with drive letter */
509 if (attr & ATTR_DIRECTORY) {
510 /* override default perms since we do not do byte range locking
511 on dirs */
512 inode->i_mode = cifs_sb->mnt_dir_mode;
513 inode->i_mode |= S_IFDIR;
Steve Frencheda3c0292005-07-21 15:20:28 -0700514 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
515 (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
516 /* No need to le64 convert size of zero */
517 (pfindData->EndOfFile == 0)) {
518 inode->i_mode = cifs_sb->mnt_file_mode;
519 inode->i_mode |= S_IFIFO;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800520/* BB Finish for SFU style symlinks and devices */
521 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
522 (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000523 if (decode_sfu_inode(inode,
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800524 le64_to_cpu(pfindData->EndOfFile),
525 search_path,
Steve Frenchad7a2922008-02-07 23:25:02 +0000526 cifs_sb, xid))
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000527 cFYI(1, ("Unrecognized sfu inode type"));
Steve Frenchad7a2922008-02-07 23:25:02 +0000528
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000529 cFYI(1, ("sfu mode 0%o", inode->i_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 } else {
531 inode->i_mode |= S_IFREG;
532 /* treat the dos attribute of read-only as read-only
533 mode e.g. 555 */
534 if (cifsInfo->cifsAttrs & ATTR_READONLY)
535 inode->i_mode &= ~(S_IWUGO);
Alan Tysonf5c1e2e2007-03-10 06:05:14 +0000536 else if ((inode->i_mode & S_IWUGO) == 0)
537 /* the ATTR_READONLY flag may have been */
538 /* changed on server -- set any w bits */
539 /* allowed by mnt_file_mode */
540 inode->i_mode |= (S_IWUGO &
541 cifs_sb->mnt_file_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 /* BB add code here -
543 validate if device or weird share or device type? */
544 }
Steve French50c2f752007-07-13 00:33:32 +0000545
Steve French3677db12007-02-26 16:46:11 +0000546 spin_lock(&inode->i_lock);
Steve Frenchf6d09982008-01-08 23:18:22 +0000547 if (is_size_safe_to_change(cifsInfo,
548 le64_to_cpu(pfindData->EndOfFile))) {
Steve French7ba52632007-02-08 18:14:13 +0000549 /* can not safely shrink the file size here if the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 client is writing to it due to potential races */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000551 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 /* 512 bytes (2**9) is the fake blocksize that must be
554 used for this calculation */
555 inode->i_blocks = (512 - 1 + le64_to_cpu(
556 pfindData->AllocationSize)) >> 9;
557 }
Steve French3677db12007-02-26 16:46:11 +0000558 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
560 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
561
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000562 /* BB fill in uid and gid here? with help from winbind?
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 or retrieve from NTFS stream extended attribute */
Steve French4879b442007-10-19 21:57:39 +0000564#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French953f8682007-10-31 04:54:42 +0000565 /* fill in 0777 bits from ACL */
Steve French4879b442007-10-19 21:57:39 +0000566 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
567 cFYI(1, ("Getting mode bits from ACL"));
Steve French630f3f0c2007-10-25 21:17:17 +0000568 acl_to_uid_mode(inode, search_path);
Steve French4879b442007-10-19 21:57:39 +0000569 }
570#endif
Steve French4523cc32007-04-30 20:13:06 +0000571 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
Steve French953f8682007-10-31 04:54:42 +0000572 /* fill in remaining high mode bits e.g. SUID, VTX */
573 get_sfu_mode(inode, search_path, cifs_sb, xid);
Steve French9e294f12005-11-17 16:59:21 -0800574 } else if (atomic_read(&cifsInfo->inUse) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 inode->i_uid = cifs_sb->mnt_uid;
576 inode->i_gid = cifs_sb->mnt_gid;
577 /* set so we do not keep refreshing these fields with
578 bad data after user has changed them in memory */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000579 atomic_set(&cifsInfo->inUse, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 }
581
Igor Mammedov79626702008-03-09 03:44:18 +0000582 cifs_set_ops(inode, is_dfs_referral);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 }
Igor Mammedov79626702008-03-09 03:44:18 +0000584cgii_exit:
585 if (full_path != search_path)
586 kfree(full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 kfree(buf);
588 return rc;
589}
590
Steve French7f8ed422007-09-28 22:28:55 +0000591static const struct inode_operations cifs_ipc_inode_ops = {
592 .lookup = cifs_lookup,
593};
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595/* gets root inode */
David Howellsce634ab2008-02-07 00:15:33 -0800596struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
David Howellsce634ab2008-02-07 00:15:33 -0800598 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 struct cifs_sb_info *cifs_sb;
David Howellsce634ab2008-02-07 00:15:33 -0800600 struct inode *inode;
601 long rc;
602
603 inode = iget_locked(sb, ino);
604 if (!inode)
605 return ERR_PTR(-ENOMEM);
606 if (!(inode->i_state & I_NEW))
607 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
609 cifs_sb = CIFS_SB(inode->i_sb);
610 xid = GetXid();
Steve Frenchc18c8422007-07-18 23:21:09 +0000611
612 if (cifs_sb->tcon->unix_ext)
Steve French7f8ed422007-09-28 22:28:55 +0000613 rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 else
Steve French7f8ed422007-09-28 22:28:55 +0000615 rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid);
616 if (rc && cifs_sb->tcon->ipc) {
617 cFYI(1, ("ipc connection - fake read inode"));
618 inode->i_mode |= S_IFDIR;
619 inode->i_nlink = 2;
620 inode->i_op = &cifs_ipc_inode_ops;
621 inode->i_fop = &simple_dir_operations;
622 inode->i_uid = cifs_sb->mnt_uid;
623 inode->i_gid = cifs_sb->mnt_gid;
David Howellsce634ab2008-02-07 00:15:33 -0800624 _FreeXid(xid);
625 iget_failed(inode);
626 return ERR_PTR(rc);
Steve French7f8ed422007-09-28 22:28:55 +0000627 }
628
David Howellsce634ab2008-02-07 00:15:33 -0800629 unlock_new_inode(inode);
630
631 /* can not call macro FreeXid here since in a void func
632 * TODO: This is no longer true
633 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 _FreeXid(xid);
David Howellsce634ab2008-02-07 00:15:33 -0800635 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636}
637
638int cifs_unlink(struct inode *inode, struct dentry *direntry)
639{
640 int rc = 0;
641 int xid;
642 struct cifs_sb_info *cifs_sb;
643 struct cifsTconInfo *pTcon;
644 char *full_path = NULL;
645 struct cifsInodeInfo *cifsInode;
646 FILE_BASIC_INFO *pinfo_buf;
647
Steve French06bcfed2006-03-31 22:43:50 +0000648 cFYI(1, ("cifs_unlink, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 xid = GetXid();
651
Steve French4523cc32007-04-30 20:13:06 +0000652 if (inode)
Steve French6910ab32006-03-31 03:37:08 +0000653 cifs_sb = CIFS_SB(inode->i_sb);
654 else
Steve French06bcfed2006-03-31 22:43:50 +0000655 cifs_sb = CIFS_SB(direntry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 pTcon = cifs_sb->tcon;
657
658 /* Unlink can be called from rename so we can not grab the sem here
659 since we deadlock otherwise */
Arjan van de Vena11f3a02006-03-23 03:00:33 -0800660/* mutex_lock(&direntry->d_sb->s_vfs_rename_mutex);*/
Steve French7f573562005-08-30 11:32:14 -0700661 full_path = build_path_from_dentry(direntry);
Arjan van de Vena11f3a02006-03-23 03:00:33 -0800662/* mutex_unlock(&direntry->d_sb->s_vfs_rename_mutex);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 if (full_path == NULL) {
664 FreeXid(xid);
665 return -ENOMEM;
666 }
Steve French2d785a52007-07-15 01:48:57 +0000667
668 if ((pTcon->ses->capabilities & CAP_UNIX) &&
669 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
670 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
671 rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
672 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
673 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
674 cFYI(1, ("posix del rc %d", rc));
675 if ((rc == 0) || (rc == -ENOENT))
676 goto psx_del_no_retry;
677 }
678
Steve French737b7582005-04-28 22:41:06 -0700679 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
680 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French2d785a52007-07-15 01:48:57 +0000681psx_del_no_retry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (!rc) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700683 if (direntry->d_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700684 drop_nlink(direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 } else if (rc == -ENOENT) {
686 d_drop(direntry);
687 } else if (rc == -ETXTBSY) {
688 int oplock = FALSE;
689 __u16 netfid;
690
691 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
692 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
Steve French737b7582005-04-28 22:41:06 -0700693 &netfid, &oplock, NULL, cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000694 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700695 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000696 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000698 cifs_sb->local_nls,
699 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700700 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700702 if (direntry->d_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700703 drop_nlink(direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 }
705 } else if (rc == -EACCES) {
706 /* try only if r/o attribute set in local lookup data? */
Eric Sesterhenna048d7a2006-02-21 22:33:09 +0000707 pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 if (pinfo_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 /* ATTRS set to normal clears r/o bit */
710 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
711 if (!(pTcon->ses->flags & CIFS_SES_NT4))
712 rc = CIFSSMBSetTimes(xid, pTcon, full_path,
713 pinfo_buf,
Steve French737b7582005-04-28 22:41:06 -0700714 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000715 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700716 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 else
718 rc = -EOPNOTSUPP;
719
720 if (rc == -EOPNOTSUPP) {
721 int oplock = FALSE;
722 __u16 netfid;
723 /* rc = CIFSSMBSetAttrLegacy(xid, pTcon,
724 full_path,
725 (__u16)ATTR_NORMAL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000726 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 For some strange reason it seems that NT4 eats the
728 old setattr call without actually setting the
729 attributes so on to the third attempted workaround
730 */
731
732 /* BB could scan to see if we already have it open
733 and pass in pid of opener to function */
734 rc = CIFSSMBOpen(xid, pTcon, full_path,
735 FILE_OPEN, SYNCHRONIZE |
736 FILE_WRITE_ATTRIBUTES, 0,
737 &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700738 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000739 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700740 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000741 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 rc = CIFSSMBSetFileTimes(xid, pTcon,
743 pinfo_buf,
744 netfid);
745 CIFSSMBClose(xid, pTcon, netfid);
746 }
747 }
748 kfree(pinfo_buf);
749 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000750 if (rc == 0) {
751 rc = CIFSSMBDelFile(xid, pTcon, full_path,
752 cifs_sb->local_nls,
753 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700754 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (!rc) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700756 if (direntry->d_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700757 drop_nlink(direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 } else if (rc == -ETXTBSY) {
759 int oplock = FALSE;
760 __u16 netfid;
761
762 rc = CIFSSMBOpen(xid, pTcon, full_path,
763 FILE_OPEN, DELETE,
764 CREATE_NOT_DIR |
765 CREATE_DELETE_ON_CLOSE,
766 &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000767 cifs_sb->local_nls,
768 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700769 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000770 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 CIFSSMBRenameOpenFile(xid, pTcon,
772 netfid, NULL,
Steve French737b7582005-04-28 22:41:06 -0700773 cifs_sb->local_nls,
774 cifs_sb->mnt_cifs_flags &
775 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700777 if (direntry->d_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700778 drop_nlink(direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780 /* BB if rc = -ETXTBUSY goto the rename logic BB */
781 }
782 }
783 }
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700784 if (direntry->d_inode) {
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500785 cifsInode = CIFS_I(direntry->d_inode);
786 cifsInode->time = 0; /* will force revalidate to get info
787 when needed */
788 direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
789 }
Steve French4523cc32007-04-30 20:13:06 +0000790 if (inode) {
Steve French06bcfed2006-03-31 22:43:50 +0000791 inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
792 cifsInode = CIFS_I(inode);
793 cifsInode->time = 0; /* force revalidate of dir as well */
794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 kfree(full_path);
797 FreeXid(xid);
798 return rc;
799}
800
Steve French2dd29d32007-04-23 22:07:35 +0000801static void posix_fill_in_inode(struct inode *tmp_inode,
Steve French0b442d22008-02-26 03:44:02 +0000802 FILE_UNIX_BASIC_INFO *pData, int isNewInode)
Steve French2dd29d32007-04-23 22:07:35 +0000803{
Christoph Hellwig75f12982008-02-25 20:25:21 +0000804 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
Steve French2dd29d32007-04-23 22:07:35 +0000805 loff_t local_size;
806 struct timespec local_mtime;
807
Steve French2dd29d32007-04-23 22:07:35 +0000808 cifsInfo->time = jiffies;
809 atomic_inc(&cifsInfo->inUse);
810
811 /* save mtime and size */
812 local_mtime = tmp_inode->i_mtime;
813 local_size = tmp_inode->i_size;
814
Christoph Hellwig75f12982008-02-25 20:25:21 +0000815 cifs_unix_info_to_inode(tmp_inode, pData, 1);
Igor Mammedov79626702008-03-09 03:44:18 +0000816 cifs_set_ops(tmp_inode, false);
Steve French2dd29d32007-04-23 22:07:35 +0000817
Christoph Hellwig75f12982008-02-25 20:25:21 +0000818 if (!S_ISREG(tmp_inode->i_mode))
819 return;
820
821 /*
822 * No sense invalidating pages for new inode
823 * since we we have not started caching
824 * readahead file data yet.
825 */
826 if (isNewInode)
827 return;
828
829 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
830 (local_size == tmp_inode->i_size)) {
831 cFYI(1, ("inode exists but unchanged"));
Steve French2dd29d32007-04-23 22:07:35 +0000832 } else {
Christoph Hellwig75f12982008-02-25 20:25:21 +0000833 /* file may have changed on server */
834 cFYI(1, ("invalidate inode, readdir detected change"));
835 invalidate_remote_inode(tmp_inode);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000836 }
Steve French2dd29d32007-04-23 22:07:35 +0000837}
838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
840{
841 int rc = 0;
842 int xid;
843 struct cifs_sb_info *cifs_sb;
844 struct cifsTconInfo *pTcon;
845 char *full_path = NULL;
846 struct inode *newinode = NULL;
847
Steve French6473a552005-11-29 20:20:10 -0800848 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850 xid = GetXid();
851
852 cifs_sb = CIFS_SB(inode->i_sb);
853 pTcon = cifs_sb->tcon;
854
Steve French7f573562005-08-30 11:32:14 -0700855 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 if (full_path == NULL) {
857 FreeXid(xid);
858 return -ENOMEM;
859 }
Steve French50c2f752007-07-13 00:33:32 +0000860
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000861 if ((pTcon->ses->capabilities & CAP_UNIX) &&
862 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Steve French2dd29d32007-04-23 22:07:35 +0000863 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
864 u32 oplock = 0;
Steve Frenchf6d09982008-01-08 23:18:22 +0000865 FILE_UNIX_BASIC_INFO *pInfo =
Steve French2dd29d32007-04-23 22:07:35 +0000866 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000867 if (pInfo == NULL) {
Steve French2dd29d32007-04-23 22:07:35 +0000868 rc = -ENOMEM;
869 goto mkdir_out;
870 }
Steve French50c2f752007-07-13 00:33:32 +0000871
Jeffa8cd9252007-09-13 18:38:50 +0000872 mode &= ~current->fs->umask;
Steve French2dd29d32007-04-23 22:07:35 +0000873 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
874 mode, NULL /* netfid */, pInfo, &oplock,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000875 full_path, cifs_sb->local_nls,
876 cifs_sb->mnt_cifs_flags &
Steve French2dd29d32007-04-23 22:07:35 +0000877 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc45d7072007-09-17 02:04:21 +0000878 if (rc == -EOPNOTSUPP) {
879 kfree(pInfo);
880 goto mkdir_retry_old;
881 } else if (rc) {
Steve French2dd29d32007-04-23 22:07:35 +0000882 cFYI(1, ("posix mkdir returned 0x%x", rc));
883 d_drop(direntry);
884 } else {
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000885 if (pInfo->Type == cpu_to_le32(-1)) {
886 /* no return info, go query for it */
Steve French5a07cdf2007-09-16 23:12:47 +0000887 kfree(pInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000888 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +0000889 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000890/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
891 to set uid/gid */
Steve French2dd29d32007-04-23 22:07:35 +0000892 inc_nlink(inode);
893 if (pTcon->nocase)
894 direntry->d_op = &cifs_ci_dentry_ops;
895 else
896 direntry->d_op = &cifs_dentry_ops;
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000897
898 newinode = new_inode(inode->i_sb);
Steve French5a07cdf2007-09-16 23:12:47 +0000899 if (newinode == NULL) {
900 kfree(pInfo);
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000901 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +0000902 }
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000903 /* Is an i_ino of zero legal? */
904 /* Are there sanity checks we can use to ensure that
905 the server is really filling in that field? */
906 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
907 newinode->i_ino =
908 (unsigned long)pInfo->UniqueId;
909 } /* note ino incremented to unique num in new_inode */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000910 if (inode->i_sb->s_flags & MS_NOATIME)
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000911 newinode->i_flags |= S_NOATIME | S_NOCMTIME;
912 newinode->i_nlink = 2;
913
914 insert_inode_hash(newinode);
Steve French2dd29d32007-04-23 22:07:35 +0000915 d_instantiate(direntry, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000916
917 /* we already checked in POSIXCreate whether
918 frame was long enough */
919 posix_fill_in_inode(direntry->d_inode,
Steve French0b442d22008-02-26 03:44:02 +0000920 pInfo, 1 /* NewInode */);
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000921#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000922 cFYI(1, ("instantiated dentry %p %s to inode %p",
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000923 direntry, direntry->d_name.name, newinode));
924
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000925 if (newinode->i_nlink != 2)
926 cFYI(1, ("unexpected number of links %d",
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000927 newinode->i_nlink));
928#endif
Steve French2dd29d32007-04-23 22:07:35 +0000929 }
930 kfree(pInfo);
931 goto mkdir_out;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000932 }
Steve Frenchc45d7072007-09-17 02:04:21 +0000933mkdir_retry_old:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -0700935 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
936 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000938 cFYI(1, ("cifs_mkdir returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 d_drop(direntry);
940 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000941mkdir_get_info:
Dave Hansend8c76e62006-09-30 23:29:04 -0700942 inc_nlink(inode);
Steve Frenchc18c8422007-07-18 23:21:09 +0000943 if (pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000945 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 else
947 rc = cifs_get_inode_info(&newinode, full_path, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000948 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Steve Frenchb92327f2005-08-22 20:09:43 -0700950 if (pTcon->nocase)
951 direntry->d_op = &cifs_ci_dentry_ops;
952 else
953 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 d_instantiate(direntry, newinode);
Steve French2dd29d32007-04-23 22:07:35 +0000955 /* setting nlink not necessary except in cases where we
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000956 * failed to get it from the server or was set bogus */
Steve French2dd29d32007-04-23 22:07:35 +0000957 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000958 direntry->d_inode->i_nlink = 2;
Steve Frenchc18c8422007-07-18 23:21:09 +0000959 if (pTcon->unix_ext) {
Steve French3ce53fc2007-06-08 14:55:14 +0000960 mode &= ~current->fs->umask;
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700961 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
963 mode,
Steve French83451872005-12-01 17:12:59 -0800964 (__u64)current->fsuid,
965 (__u64)current->fsgid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 0 /* dev_t */,
Steve French737b7582005-04-28 22:41:06 -0700967 cifs_sb->local_nls,
968 cifs_sb->mnt_cifs_flags &
969 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 } else {
971 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
972 mode, (__u64)-1,
973 (__u64)-1, 0 /* dev_t */,
Steve French737b7582005-04-28 22:41:06 -0700974 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000975 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700976 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
Steve French3ce53fc2007-06-08 14:55:14 +0000978 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 /* BB to be implemented via Windows secrty descriptors
980 eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
981 -1, -1, local_nls); */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000982 if (direntry->d_inode) {
Steve French6473a552005-11-29 20:20:10 -0800983 direntry->d_inode->i_mode = mode;
Steve French25741b32005-11-29 22:38:43 -0800984 direntry->d_inode->i_mode |= S_IFDIR;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000985 if (cifs_sb->mnt_cifs_flags &
Steve French6473a552005-11-29 20:20:10 -0800986 CIFS_MOUNT_SET_UID) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000987 direntry->d_inode->i_uid =
Steve French6473a552005-11-29 20:20:10 -0800988 current->fsuid;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000989 direntry->d_inode->i_gid =
Steve French6473a552005-11-29 20:20:10 -0800990 current->fsgid;
991 }
992 }
Steve French2a138ebb2005-11-29 21:22:19 -0800993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000995mkdir_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 kfree(full_path);
997 FreeXid(xid);
998 return rc;
999}
1000
1001int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1002{
1003 int rc = 0;
1004 int xid;
1005 struct cifs_sb_info *cifs_sb;
1006 struct cifsTconInfo *pTcon;
1007 char *full_path = NULL;
1008 struct cifsInodeInfo *cifsInode;
1009
Steve French26a21b92006-05-31 18:05:34 +00001010 cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 xid = GetXid();
1013
1014 cifs_sb = CIFS_SB(inode->i_sb);
1015 pTcon = cifs_sb->tcon;
1016
Steve French7f573562005-08-30 11:32:14 -07001017 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (full_path == NULL) {
1019 FreeXid(xid);
1020 return -ENOMEM;
1021 }
1022
Steve French737b7582005-04-28 22:41:06 -07001023 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1024 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 if (!rc) {
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001027 drop_nlink(inode);
Steve French3677db12007-02-26 16:46:11 +00001028 spin_lock(&direntry->d_inode->i_lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001029 i_size_write(direntry->d_inode, 0);
Dave Hansence71ec32006-09-30 23:29:06 -07001030 clear_nlink(direntry->d_inode);
Steve French3677db12007-02-26 16:46:11 +00001031 spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 }
1033
1034 cifsInode = CIFS_I(direntry->d_inode);
1035 cifsInode->time = 0; /* force revalidate to go get info when
1036 needed */
1037 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1038 current_fs_time(inode->i_sb);
1039
1040 kfree(full_path);
1041 FreeXid(xid);
1042 return rc;
1043}
1044
1045int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
1046 struct inode *target_inode, struct dentry *target_direntry)
1047{
1048 char *fromName;
1049 char *toName;
1050 struct cifs_sb_info *cifs_sb_source;
1051 struct cifs_sb_info *cifs_sb_target;
1052 struct cifsTconInfo *pTcon;
1053 int xid;
1054 int rc = 0;
1055
1056 xid = GetXid();
1057
1058 cifs_sb_target = CIFS_SB(target_inode->i_sb);
1059 cifs_sb_source = CIFS_SB(source_inode->i_sb);
1060 pTcon = cifs_sb_source->tcon;
1061
1062 if (pTcon != cifs_sb_target->tcon) {
1063 FreeXid(xid);
1064 return -EXDEV; /* BB actually could be allowed if same server,
1065 but different share.
1066 Might eventually add support for this */
1067 }
1068
1069 /* we already have the rename sem so we do not need to grab it again
1070 here to protect the path integrity */
Steve French7f573562005-08-30 11:32:14 -07001071 fromName = build_path_from_dentry(source_direntry);
1072 toName = build_path_from_dentry(target_direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 if ((fromName == NULL) || (toName == NULL)) {
1074 rc = -ENOMEM;
1075 goto cifs_rename_exit;
1076 }
1077
1078 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
Steve French737b7582005-04-28 22:41:06 -07001079 cifs_sb_source->local_nls,
1080 cifs_sb_source->mnt_cifs_flags &
1081 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 if (rc == -EEXIST) {
1083 /* check if they are the same file because rename of hardlinked
1084 files is a noop */
1085 FILE_UNIX_BASIC_INFO *info_buf_source;
1086 FILE_UNIX_BASIC_INFO *info_buf_target;
1087
1088 info_buf_source =
1089 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
1090 if (info_buf_source != NULL) {
1091 info_buf_target = info_buf_source + 1;
Steve Frenchc18c8422007-07-18 23:21:09 +00001092 if (pTcon->unix_ext)
Steve French8e87d4d2006-11-02 03:45:24 +00001093 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001094 info_buf_source,
Steve French8e87d4d2006-11-02 03:45:24 +00001095 cifs_sb_source->local_nls,
1096 cifs_sb_source->mnt_cifs_flags &
1097 CIFS_MOUNT_MAP_SPECIAL_CHR);
1098 /* else rc is still EEXIST so will fall through to
1099 unlink the target and retry rename */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 if (rc == 0) {
1101 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
1102 info_buf_target,
Steve French737b7582005-04-28 22:41:06 -07001103 cifs_sb_target->local_nls,
1104 /* remap based on source sb */
1105 cifs_sb_source->mnt_cifs_flags &
1106 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 }
1108 if ((rc == 0) &&
1109 (info_buf_source->UniqueId ==
1110 info_buf_target->UniqueId)) {
1111 /* do not rename since the files are hardlinked which
1112 is a noop */
1113 } else {
1114 /* we either can not tell the files are hardlinked
1115 (as with Windows servers) or files are not
1116 hardlinked so delete the target manually before
1117 renaming to follow POSIX rather than Windows
1118 semantics */
1119 cifs_unlink(target_inode, target_direntry);
1120 rc = CIFSSMBRename(xid, pTcon, fromName,
1121 toName,
Steve French737b7582005-04-28 22:41:06 -07001122 cifs_sb_source->local_nls,
1123 cifs_sb_source->mnt_cifs_flags
1124 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
1126 kfree(info_buf_source);
1127 } /* if we can not get memory just leave rc as EEXIST */
1128 }
1129
Steve Frenchad7a2922008-02-07 23:25:02 +00001130 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 cFYI(1, ("rename rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 if ((rc == -EIO) || (rc == -EEXIST)) {
1134 int oplock = FALSE;
1135 __u16 netfid;
1136
1137 /* BB FIXME Is Generic Read correct for rename? */
1138 /* if renaming directory - we should not say CREATE_NOT_DIR,
1139 need to test renaming open directory, also GENERIC_READ
1140 might not right be right access to request */
1141 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
1142 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001143 cifs_sb_source->local_nls,
1144 cifs_sb_source->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -07001145 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001146 if (rc == 0) {
Steve French8e87d4d2006-11-02 03:45:24 +00001147 rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001148 cifs_sb_source->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001149 cifs_sb_source->mnt_cifs_flags &
1150 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 CIFSSMBClose(xid, pTcon, netfid);
1152 }
1153 }
1154
1155cifs_rename_exit:
1156 kfree(fromName);
1157 kfree(toName);
1158 FreeXid(xid);
1159 return rc;
1160}
1161
1162int cifs_revalidate(struct dentry *direntry)
1163{
1164 int xid;
Jeff Laytoncea21802007-11-20 23:19:03 +00001165 int rc = 0, wbrc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 char *full_path;
1167 struct cifs_sb_info *cifs_sb;
1168 struct cifsInodeInfo *cifsInode;
1169 loff_t local_size;
1170 struct timespec local_mtime;
1171 int invalidate_inode = FALSE;
1172
1173 if (direntry->d_inode == NULL)
1174 return -ENOENT;
1175
1176 cifsInode = CIFS_I(direntry->d_inode);
1177
1178 if (cifsInode == NULL)
1179 return -ENOENT;
1180
1181 /* no sense revalidating inode info on file that no one can write */
1182 if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
1183 return rc;
1184
1185 xid = GetXid();
1186
1187 cifs_sb = CIFS_SB(direntry->d_sb);
1188
1189 /* can not safely grab the rename sem here if rename calls revalidate
1190 since that would deadlock */
Steve French7f573562005-08-30 11:32:14 -07001191 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 if (full_path == NULL) {
1193 FreeXid(xid);
1194 return -ENOMEM;
1195 }
1196 cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
1197 "jiffies %ld", full_path, direntry->d_inode,
1198 direntry->d_inode->i_count.counter, direntry,
1199 direntry->d_time, jiffies));
1200
1201 if (cifsInode->time == 0) {
1202 /* was set to zero previously to force revalidate */
1203 } else if (time_before(jiffies, cifsInode->time + HZ) &&
1204 lookupCacheEnabled) {
1205 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
1206 (direntry->d_inode->i_nlink == 1)) {
1207 kfree(full_path);
1208 FreeXid(xid);
1209 return rc;
1210 } else {
1211 cFYI(1, ("Have to revalidate file due to hardlinks"));
1212 }
1213 }
1214
1215 /* save mtime and size */
1216 local_mtime = direntry->d_inode->i_mtime;
1217 local_size = direntry->d_inode->i_size;
1218
Steve Frenchc18c8422007-07-18 23:21:09 +00001219 if (cifs_sb->tcon->unix_ext) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001221 direntry->d_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 if (rc) {
1223 cFYI(1, ("error on getting revalidate info %d", rc));
1224/* if (rc != -ENOENT)
1225 rc = 0; */ /* BB should we cache info on
1226 certain errors? */
1227 }
1228 } else {
1229 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001230 direntry->d_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 if (rc) {
1232 cFYI(1, ("error on getting revalidate info %d", rc));
1233/* if (rc != -ENOENT)
1234 rc = 0; */ /* BB should we cache info on
1235 certain errors? */
1236 }
1237 }
1238 /* should we remap certain errors, access denied?, to zero */
1239
1240 /* if not oplocked, we invalidate inode pages if mtime or file size
1241 had changed on server */
1242
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001243 if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 (local_size == direntry->d_inode->i_size)) {
1245 cFYI(1, ("cifs_revalidate - inode unchanged"));
1246 } else {
1247 /* file may have changed on server */
1248 if (cifsInode->clientCanCacheRead) {
1249 /* no need to invalidate inode pages since we were the
1250 only ones who could have modified the file and the
1251 server copy is staler than ours */
1252 } else {
1253 invalidate_inode = TRUE;
1254 }
1255 }
1256
1257 /* can not grab this sem since kernel filesys locking documentation
Jes Sorensen1b1dcc12006-01-09 15:59:24 -08001258 indicates i_mutex may be taken by the kernel on lookup and rename
1259 which could deadlock if we grab the i_mutex here as well */
1260/* mutex_lock(&direntry->d_inode->i_mutex);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 /* need to write out dirty pages here */
1262 if (direntry->d_inode->i_mapping) {
1263 /* do we need to lock inode until after invalidate completes
1264 below? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001265 wbrc = filemap_fdatawrite(direntry->d_inode->i_mapping);
1266 if (wbrc)
1267 CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 }
1269 if (invalidate_inode) {
Steve French3abb9272005-11-28 08:16:13 -08001270 /* shrink_dcache not necessary now that cifs dentry ops
1271 are exported for negative dentries */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001272/* if (S_ISDIR(direntry->d_inode->i_mode))
Steve French3abb9272005-11-28 08:16:13 -08001273 shrink_dcache_parent(direntry); */
1274 if (S_ISREG(direntry->d_inode->i_mode)) {
1275 if (direntry->d_inode->i_mapping)
Jeff Laytoncea21802007-11-20 23:19:03 +00001276 wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
1277 if (wbrc)
1278 CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
Steve French3abb9272005-11-28 08:16:13 -08001279 /* may eventually have to do this for open files too */
1280 if (list_empty(&(cifsInode->openFileList))) {
1281 /* changed on server - flush read ahead pages */
1282 cFYI(1, ("Invalidating read ahead data on "
1283 "closed file"));
1284 invalidate_remote_inode(direntry->d_inode);
1285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 }
1287 }
Jes Sorensen1b1dcc12006-01-09 15:59:24 -08001288/* mutex_unlock(&direntry->d_inode->i_mutex); */
Steve French50c2f752007-07-13 00:33:32 +00001289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 kfree(full_path);
1291 FreeXid(xid);
1292 return rc;
1293}
1294
1295int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1296 struct kstat *stat)
1297{
1298 int err = cifs_revalidate(dentry);
Steve French5fe14c82006-11-07 19:26:33 +00001299 if (!err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 generic_fillattr(dentry->d_inode, stat);
Steve French5fe14c82006-11-07 19:26:33 +00001301 stat->blksize = CIFS_MAX_MSGSIZE;
1302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 return err;
1304}
1305
1306static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1307{
1308 pgoff_t index = from >> PAGE_CACHE_SHIFT;
1309 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1310 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 int rc = 0;
1312
1313 page = grab_cache_page(mapping, index);
1314 if (!page)
1315 return -ENOMEM;
1316
Christoph Lametereebd2aa2008-02-04 22:28:29 -08001317 zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 unlock_page(page);
1319 page_cache_release(page);
1320 return rc;
1321}
1322
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001323static int cifs_vmtruncate(struct inode *inode, loff_t offset)
Steve French3677db12007-02-26 16:46:11 +00001324{
1325 struct address_space *mapping = inode->i_mapping;
1326 unsigned long limit;
1327
Steve Frenchba6a46a2007-02-26 20:06:29 +00001328 spin_lock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001329 if (inode->i_size < offset)
1330 goto do_expand;
1331 /*
1332 * truncation of in-use swapfiles is disallowed - it would cause
1333 * subsequent swapout to scribble on the now-freed blocks.
1334 */
Steve Frenchba6a46a2007-02-26 20:06:29 +00001335 if (IS_SWAPFILE(inode)) {
1336 spin_unlock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001337 goto out_busy;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001338 }
Steve French3677db12007-02-26 16:46:11 +00001339 i_size_write(inode, offset);
1340 spin_unlock(&inode->i_lock);
Steve French8064ab42007-08-22 22:12:07 +00001341 /*
1342 * unmap_mapping_range is called twice, first simply for efficiency
1343 * so that truncate_inode_pages does fewer single-page unmaps. However
1344 * after this first call, and before truncate_inode_pages finishes,
1345 * it is possible for private pages to be COWed, which remain after
1346 * truncate_inode_pages finishes, hence the second unmap_mapping_range
1347 * call must be made for correctness.
1348 */
Steve French3677db12007-02-26 16:46:11 +00001349 unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
1350 truncate_inode_pages(mapping, offset);
Steve French8064ab42007-08-22 22:12:07 +00001351 unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
Steve French3677db12007-02-26 16:46:11 +00001352 goto out_truncate;
1353
1354do_expand:
1355 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001356 if (limit != RLIM_INFINITY && offset > limit) {
1357 spin_unlock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001358 goto out_sig;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001359 }
1360 if (offset > inode->i_sb->s_maxbytes) {
1361 spin_unlock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001362 goto out_big;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001363 }
Steve French3677db12007-02-26 16:46:11 +00001364 i_size_write(inode, offset);
Steve Frenchba6a46a2007-02-26 20:06:29 +00001365 spin_unlock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001366out_truncate:
1367 if (inode->i_op && inode->i_op->truncate)
1368 inode->i_op->truncate(inode);
1369 return 0;
1370out_sig:
1371 send_sig(SIGXFSZ, current, 0);
1372out_big:
1373 return -EFBIG;
1374out_busy:
1375 return -ETXTBSY;
1376}
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1379{
1380 int xid;
1381 struct cifs_sb_info *cifs_sb;
1382 struct cifsTconInfo *pTcon;
1383 char *full_path = NULL;
1384 int rc = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 struct cifsFileInfo *open_file = NULL;
1386 FILE_BASIC_INFO time_buf;
1387 int set_time = FALSE;
Steve French066fcb02007-03-23 00:45:08 +00001388 int set_dosattr = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
1390 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
1391 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
1392 struct cifsInodeInfo *cifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 xid = GetXid();
1395
Steve French39798772006-05-31 22:40:51 +00001396 cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 direntry->d_name.name, attrs->ia_valid));
Steve French6473a552005-11-29 20:20:10 -08001398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
1400 pTcon = cifs_sb->tcon;
1401
Steve French2a138ebb2005-11-29 21:22:19 -08001402 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
Steve French6473a552005-11-29 20:20:10 -08001403 /* check if we have permission to change attrs */
1404 rc = inode_change_ok(direntry->d_inode, attrs);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001405 if (rc < 0) {
Steve French6473a552005-11-29 20:20:10 -08001406 FreeXid(xid);
1407 return rc;
1408 } else
1409 rc = 0;
1410 }
Steve French50c2f752007-07-13 00:33:32 +00001411
Steve French7f573562005-08-30 11:32:14 -07001412 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 if (full_path == NULL) {
1414 FreeXid(xid);
1415 return -ENOMEM;
1416 }
1417 cifsInode = CIFS_I(direntry->d_inode);
1418
1419 /* BB check if we need to refresh inode from server now ? BB */
1420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 if (attrs->ia_valid & ATTR_SIZE) {
Jeff Laytoncea21802007-11-20 23:19:03 +00001422 /*
1423 Flush data before changing file size on server. If the
1424 flush returns error, store it to report later and continue.
1425 BB: This should be smarter. Why bother flushing pages that
1426 will be truncated anyway? Also, should we error out here if
1427 the flush returns error?
1428 */
1429 rc = filemap_write_and_wait(direntry->d_inode->i_mapping);
1430 if (rc != 0) {
1431 CIFS_I(direntry->d_inode)->write_behind_rc = rc;
1432 rc = 0;
1433 }
1434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 /* To avoid spurious oplock breaks from server, in the case of
1436 inodes that we already have open, avoid doing path based
1437 setting of file size if we can do it by handle.
1438 This keeps our caching token (oplock) and avoids timeouts
1439 when the local oplock break takes longer to flush
1440 writebehind data than the SMB timeout for the SetPathInfo
1441 request would allow */
Steve French39798772006-05-31 22:40:51 +00001442
Steve French6148a742005-10-05 12:23:19 -07001443 open_file = find_writable_file(cifsInode);
1444 if (open_file) {
1445 __u16 nfid = open_file->netfid;
1446 __u32 npid = open_file->pid;
1447 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
1448 nfid, npid, FALSE);
Steve French23e7dd72005-10-20 13:44:56 -07001449 atomic_dec(&open_file->wrtPending);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001450 cFYI(1, ("SetFSize for attrs rc = %d", rc));
1451 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
Steve French77159b42007-08-31 01:10:17 +00001452 unsigned int bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001453 rc = CIFSSMBWrite(xid, pTcon,
1454 nfid, 0, attrs->ia_size,
1455 &bytes_written, NULL, NULL,
1456 1 /* 45 seconds */);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001457 cFYI(1, ("Wrt seteof rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001459 } else
Steve French6473a552005-11-29 20:20:10 -08001460 rc = -EINVAL;
1461
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 if (rc != 0) {
1463 /* Set file size by pathname rather than by handle
1464 either because no valid, writeable file handle for
1465 it was found or because there was an error setting
1466 it by handle */
1467 rc = CIFSSMBSetEOF(xid, pTcon, full_path,
1468 attrs->ia_size, FALSE,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001469 cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001470 cifs_sb->mnt_cifs_flags &
1471 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenche30dcf32005-09-20 20:49:16 -07001472 cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001473 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
Steve Frenche30dcf32005-09-20 20:49:16 -07001474 __u16 netfid;
1475 int oplock = FALSE;
1476
1477 rc = SMBLegacyOpen(xid, pTcon, full_path,
1478 FILE_OPEN,
1479 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1480 CREATE_NOT_DIR, &netfid, &oplock,
1481 NULL, cifs_sb->local_nls,
1482 cifs_sb->mnt_cifs_flags &
1483 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001484 if (rc == 0) {
Steve French77159b42007-08-31 01:10:17 +00001485 unsigned int bytes_written;
Steve Frenche30dcf32005-09-20 20:49:16 -07001486 rc = CIFSSMBWrite(xid, pTcon,
1487 netfid, 0,
1488 attrs->ia_size,
1489 &bytes_written, NULL,
1490 NULL, 1 /* 45 sec */);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001491 cFYI(1, ("wrt seteof rc %d", rc));
Steve Frenche30dcf32005-09-20 20:49:16 -07001492 CIFSSMBClose(xid, pTcon, netfid);
1493 }
1494
1495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 }
1497
1498 /* Server is ok setting allocation size implicitly - no need
1499 to call:
1500 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
1501 cifs_sb->local_nls);
1502 */
1503
1504 if (rc == 0) {
Steve French3677db12007-02-26 16:46:11 +00001505 rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 cifs_truncate_page(direntry->d_inode->i_mapping,
1507 direntry->d_inode->i_size);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001508 } else
Steve Frenche30dcf32005-09-20 20:49:16 -07001509 goto cifs_setattr_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 }
1511 if (attrs->ia_valid & ATTR_UID) {
Steve Frenche30dcf32005-09-20 20:49:16 -07001512 cFYI(1, ("UID changed to %d", attrs->ia_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 uid = attrs->ia_uid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 }
1515 if (attrs->ia_valid & ATTR_GID) {
Steve Frenche30dcf32005-09-20 20:49:16 -07001516 cFYI(1, ("GID changed to %d", attrs->ia_gid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 gid = attrs->ia_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 }
1519
1520 time_buf.Attributes = 0;
Jeff Laytond32c4f22007-10-18 03:05:22 -07001521
1522 /* skip mode change if it's just for clearing setuid/setgid */
1523 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1524 attrs->ia_valid &= ~ATTR_MODE;
1525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 if (attrs->ia_valid & ATTR_MODE) {
Steve Frenche30dcf32005-09-20 20:49:16 -07001527 cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 mode = attrs->ia_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 }
1530
Steve Frenchc18c8422007-07-18 23:21:09 +00001531 if ((pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1533 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
Steve French737b7582005-04-28 22:41:06 -07001534 0 /* dev_t */, cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001535 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -07001536 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 else if (attrs->ia_valid & ATTR_MODE) {
Steve Frenchcdbce9c2005-11-19 21:04:52 -08001538 rc = 0;
Steve French97837582007-12-31 07:47:21 +00001539#ifdef CONFIG_CIFS_EXPERIMENTAL
1540 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
1541 rc = mode_to_acl(direntry->d_inode, full_path, mode);
Steve Frenchf6d09982008-01-08 23:18:22 +00001542 else if ((mode & S_IWUGO) == 0) {
Steve French97837582007-12-31 07:47:21 +00001543#else
Steve Frenchf6d09982008-01-08 23:18:22 +00001544 if ((mode & S_IWUGO) == 0) {
Steve French97837582007-12-31 07:47:21 +00001545#endif
Steve Frenchf6d09982008-01-08 23:18:22 +00001546 /* not writeable */
Steve French066fcb02007-03-23 00:45:08 +00001547 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
1548 set_dosattr = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 time_buf.Attributes =
1550 cpu_to_le32(cifsInode->cifsAttrs |
1551 ATTR_READONLY);
Steve French066fcb02007-03-23 00:45:08 +00001552 }
Steve French5268df22007-04-06 19:28:16 +00001553 } else if (cifsInode->cifsAttrs & ATTR_READONLY) {
1554 /* If file is readonly on server, we would
1555 not be able to write to it - so if any write
1556 bit is enabled for user or group or other we
1557 need to at least try to remove r/o dos attr */
1558 set_dosattr = TRUE;
1559 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
1560 (~ATTR_READONLY));
1561 /* Windows ignores set to zero */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001562 if (time_buf.Attributes == 0)
Steve French5268df22007-04-06 19:28:16 +00001563 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
Steve French97837582007-12-31 07:47:21 +00001565#ifdef CONFIG_CIFS_EXPERIMENTAL
1566 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
1567 mode_to_acl(direntry->d_inode, full_path, mode);
1568#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 }
1570
1571 if (attrs->ia_valid & ATTR_ATIME) {
1572 set_time = TRUE;
1573 time_buf.LastAccessTime =
1574 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1575 } else
1576 time_buf.LastAccessTime = 0;
1577
1578 if (attrs->ia_valid & ATTR_MTIME) {
1579 set_time = TRUE;
1580 time_buf.LastWriteTime =
1581 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1582 } else
1583 time_buf.LastWriteTime = 0;
Steve Frenche30dcf32005-09-20 20:49:16 -07001584 /* Do not set ctime explicitly unless other time
1585 stamps are changed explicitly (i.e. by utime()
1586 since we would then have a mix of client and
1587 server times */
Steve French50c2f752007-07-13 00:33:32 +00001588
Steve Frenche30dcf32005-09-20 20:49:16 -07001589 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 set_time = TRUE;
Steve Frenche30dcf32005-09-20 20:49:16 -07001591 /* Although Samba throws this field away
1592 it may be useful to Windows - but we do
1593 not want to set ctime unless some other
1594 timestamp is changing */
Steve French26a21b92006-05-31 18:05:34 +00001595 cFYI(1, ("CIFS - CTIME changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 time_buf.ChangeTime =
1597 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1598 } else
1599 time_buf.ChangeTime = 0;
1600
Steve French066fcb02007-03-23 00:45:08 +00001601 if (set_time || set_dosattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 time_buf.CreationTime = 0; /* do not change */
1603 /* In the future we should experiment - try setting timestamps
1604 via Handle (SetFileInfo) instead of by path */
1605 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1606 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
Steve French737b7582005-04-28 22:41:06 -07001607 cifs_sb->local_nls,
1608 cifs_sb->mnt_cifs_flags &
1609 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 else
1611 rc = -EOPNOTSUPP;
1612
1613 if (rc == -EOPNOTSUPP) {
1614 int oplock = FALSE;
1615 __u16 netfid;
1616
1617 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1618 "times not supported by this server"));
1619 /* BB we could scan to see if we already have it open
1620 and pass in pid of opener to function */
1621 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1622 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1623 CREATE_NOT_DIR, &netfid, &oplock,
Steve French737b7582005-04-28 22:41:06 -07001624 NULL, cifs_sb->local_nls,
1625 cifs_sb->mnt_cifs_flags &
1626 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001627 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1629 netfid);
1630 CIFSSMBClose(xid, pTcon, netfid);
1631 } else {
1632 /* BB For even older servers we could convert time_buf
1633 into old DOS style which uses two second
1634 granularity */
1635
1636 /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001637 &time_buf, cifs_sb->local_nls); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 }
1639 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001640 /* Even if error on time set, no sense failing the call if
1641 the server would set the time to a reasonable value anyway,
1642 and this check ensures that we are not being called from
1643 sys_utimes in which case we ought to fail the call back to
1644 the user when the server rejects the call */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001645 if ((rc) && (attrs->ia_valid &
Steve Frenche30dcf32005-09-20 20:49:16 -07001646 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
1647 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 }
1649
1650 /* do not need local check to inode_check_ok since the server does
1651 that */
1652 if (!rc)
1653 rc = inode_setattr(direntry->d_inode, attrs);
Steve Frenche30dcf32005-09-20 20:49:16 -07001654cifs_setattr_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 kfree(full_path);
1656 FreeXid(xid);
1657 return rc;
1658}
1659
Steve French99ee4db2007-02-27 05:35:17 +00001660#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661void cifs_delete_inode(struct inode *inode)
1662{
Steve French26a21b92006-05-31 18:05:34 +00001663 cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 /* may have to add back in if and when safe distributed caching of
1665 directories added e.g. via FindNotify */
1666}
Steve French99ee4db2007-02-27 05:35:17 +00001667#endif