blob: 1cf43e1019438d839ea3b5ad35018c7713483424 [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:
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
Christoph Hellwig75f12982008-02-25 20:25:21 +000080static void cifs_unix_info_to_inode(struct inode *inode,
81 FILE_UNIX_BASIC_INFO *info, int force_uid_gid)
82{
83 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
84 struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
85 __u64 num_of_bytes = le64_to_cpu(info->NumOfBytes);
86 __u64 end_of_file = le64_to_cpu(info->EndOfFile);
87
88 inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(info->LastAccessTime));
89 inode->i_mtime =
90 cifs_NTtimeToUnix(le64_to_cpu(info->LastModificationTime));
91 inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(info->LastStatusChange));
92 inode->i_mode = le64_to_cpu(info->Permissions);
93
94 /*
95 * Since we set the inode type below we need to mask off
96 * to avoid strange results if bits set above.
97 */
98 inode->i_mode &= ~S_IFMT;
99 switch (le32_to_cpu(info->Type)) {
100 case UNIX_FILE:
101 inode->i_mode |= S_IFREG;
102 break;
103 case UNIX_SYMLINK:
104 inode->i_mode |= S_IFLNK;
105 break;
106 case UNIX_DIR:
107 inode->i_mode |= S_IFDIR;
108 break;
109 case UNIX_CHARDEV:
110 inode->i_mode |= S_IFCHR;
111 inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
112 le64_to_cpu(info->DevMinor) & MINORMASK);
113 break;
114 case UNIX_BLOCKDEV:
115 inode->i_mode |= S_IFBLK;
116 inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
117 le64_to_cpu(info->DevMinor) & MINORMASK);
118 break;
119 case UNIX_FIFO:
120 inode->i_mode |= S_IFIFO;
121 break;
122 case UNIX_SOCKET:
123 inode->i_mode |= S_IFSOCK;
124 break;
125 default:
126 /* safest to call it a file if we do not know */
127 inode->i_mode |= S_IFREG;
128 cFYI(1, ("unknown type %d", le32_to_cpu(info->Type)));
129 break;
130 }
131
132 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) &&
133 !force_uid_gid)
134 inode->i_uid = cifs_sb->mnt_uid;
135 else
136 inode->i_uid = le64_to_cpu(info->Uid);
137
138 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) &&
139 !force_uid_gid)
140 inode->i_gid = cifs_sb->mnt_gid;
141 else
142 inode->i_gid = le64_to_cpu(info->Gid);
143
144 inode->i_nlink = le64_to_cpu(info->Nlinks);
145
146 spin_lock(&inode->i_lock);
147 if (is_size_safe_to_change(cifsInfo, end_of_file)) {
148 /*
149 * We can not safely change the file size here if the client
150 * is writing to it due to potential races.
151 */
152 i_size_write(inode, end_of_file);
153
154 /*
155 * i_blocks is not related to (i_size / i_blksize),
156 * but instead 512 byte (2**9) size is required for
157 * calculating num blocks.
158 */
159 inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
160 }
161 spin_unlock(&inode->i_lock);
162}
163
Steve Frenchb9a32602008-05-20 21:52:32 +0000164
165/*
166 * Needed to setup inode data for the directory which is the
167 * junction to the new submount (ie to setup the fake directory
168 * which represents a DFS referral)
169 */
Steve French0e4bbde2008-05-20 19:50:46 +0000170static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
171 struct super_block *sb)
172{
173 struct inode *pinode = NULL;
174
175 memset(pfnd_dat, sizeof(FILE_UNIX_BASIC_INFO), 0);
176
177/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
178 __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
179 __u64 UniqueId = 0; */
180 pfnd_dat->LastStatusChange =
181 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
182 pfnd_dat->LastAccessTime =
183 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
184 pfnd_dat->LastModificationTime =
185 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
186 pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
187 pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
188 pfnd_dat->Nlinks = cpu_to_le64(2);
189 if (sb->s_root)
190 pinode = sb->s_root->d_inode;
191 if (pinode == NULL)
192 return;
193
194 /* fill in default values for the remaining based on root
195 inode since we can not query the server for this inode info */
196 pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
197 pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
198 pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
199 pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
200}
201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202int cifs_get_inode_info_unix(struct inode **pinode,
Steve French646dd532008-05-15 01:50:56 +0000203 const unsigned char *full_path, struct super_block *sb, int xid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
205 int rc = 0;
Steve French0e4bbde2008-05-20 19:50:46 +0000206 FILE_UNIX_BASIC_INFO find_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 struct cifsTconInfo *pTcon;
208 struct inode *inode;
209 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Igor Mammedov79626702008-03-09 03:44:18 +0000210 bool is_dfs_referral = false;
Steve French0e4bbde2008-05-20 19:50:46 +0000211 struct cifsInodeInfo *cifsInfo;
212 __u64 num_of_bytes;
213 __u64 end_of_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 pTcon = cifs_sb->tcon;
Steve French646dd532008-05-15 01:50:56 +0000216 cFYI(1, ("Getting info on %s", full_path));
Igor Mammedov79626702008-03-09 03:44:18 +0000217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 /* could have done a find first instead but this returns more info */
Steve French0e4bbde2008-05-20 19:50:46 +0000219 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
Steve French737b7582005-04-28 22:41:06 -0700220 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
221 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 if (rc) {
Igor Mammedov79626702008-03-09 03:44:18 +0000223 if (rc == -EREMOTE && !is_dfs_referral) {
224 is_dfs_referral = true;
Steve French0e4bbde2008-05-20 19:50:46 +0000225 cERROR(1, ("DFS ref")); /* BB removeme BB */
226 /* for DFS, server does not give us real inode data */
227 fill_fake_finddataunix(&find_data, sb);
228 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 }
Steve French0e4bbde2008-05-20 19:50:46 +0000231 num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
232 end_of_file = le64_to_cpu(find_data.EndOfFile);
233
234 /* get new inode */
235 if (*pinode == NULL) {
236 *pinode = new_inode(sb);
237 if (*pinode == NULL) {
238 rc = -ENOMEM;
239 goto cgiiu_exit;
240 }
241 /* Is an i_ino of zero legal? */
242 /* note ino incremented to unique num in new_inode */
243 /* Are there sanity checks we can use to ensure that
244 the server is really filling in that field? */
245 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
246 (*pinode)->i_ino = (unsigned long)find_data.UniqueId;
247
248 if (sb->s_flags & MS_NOATIME)
249 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
250
251 insert_inode_hash(*pinode);
252 }
253
254 inode = *pinode;
255 cifsInfo = CIFS_I(inode);
256
257 cFYI(1, ("Old time %ld", cifsInfo->time));
258 cifsInfo->time = jiffies;
259 cFYI(1, ("New time %ld", cifsInfo->time));
260 /* this is ok to set on every inode revalidate */
261 atomic_set(&cifsInfo->inUse, 1);
262
263 cifs_unix_info_to_inode(inode, &find_data, 0);
264
265 if (num_of_bytes < end_of_file)
266 cFYI(1, ("allocation size less than end of file"));
267 cFYI(1, ("Size %ld and blocks %llu",
268 (unsigned long) inode->i_size,
269 (unsigned long long)inode->i_blocks));
270
271 cifs_set_ops(inode, is_dfs_referral);
Igor Mammedov79626702008-03-09 03:44:18 +0000272cgiiu_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return rc;
274}
275
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000276static int decode_sfu_inode(struct inode *inode, __u64 size,
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800277 const unsigned char *path,
278 struct cifs_sb_info *cifs_sb, int xid)
279{
280 int rc;
Steve French4b18f2a2008-04-29 00:06:05 +0000281 int oplock = 0;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800282 __u16 netfid;
283 struct cifsTconInfo *pTcon = cifs_sb->tcon;
Steve French86c96b42005-11-18 20:25:31 -0800284 char buf[24];
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800285 unsigned int bytes_read;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000286 char *pbuf;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800287
288 pbuf = buf;
289
Steve French4523cc32007-04-30 20:13:06 +0000290 if (size == 0) {
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800291 inode->i_mode |= S_IFIFO;
292 return 0;
293 } else if (size < 8) {
294 return -EINVAL; /* EOPNOTSUPP? */
295 }
Steve French50c2f752007-07-13 00:33:32 +0000296
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800297 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
298 CREATE_NOT_DIR, &netfid, &oplock, NULL,
299 cifs_sb->local_nls,
300 cifs_sb->mnt_cifs_flags &
301 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000302 if (rc == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -0800303 int buf_type = CIFS_NO_BUFFER;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800304 /* Read header */
305 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000306 netfid,
Steve French86c96b42005-11-18 20:25:31 -0800307 24 /* length */, 0 /* offset */,
Steve Frenchec637e32005-12-12 20:53:18 -0800308 &bytes_read, &pbuf, &buf_type);
Steve French4523cc32007-04-30 20:13:06 +0000309 if ((rc == 0) && (bytes_read >= 8)) {
310 if (memcmp("IntxBLK", pbuf, 8) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000311 cFYI(1, ("Block device"));
Steve French3020a1f2005-11-18 11:31:10 -0800312 inode->i_mode |= S_IFBLK;
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);
320 }
Steve French4523cc32007-04-30 20:13:06 +0000321 } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000322 cFYI(1, ("Char device"));
Steve French3020a1f2005-11-18 11:31:10 -0800323 inode->i_mode |= S_IFCHR;
Steve French4523cc32007-04-30 20:13:06 +0000324 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800325 /* we have enough to decode dev num */
326 __u64 mjr; /* major */
327 __u64 mnr; /* minor */
328 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
329 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
330 inode->i_rdev = MKDEV(mjr, mnr);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000331 }
Steve French4523cc32007-04-30 20:13:06 +0000332 } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000333 cFYI(1, ("Symlink"));
Steve French3020a1f2005-11-18 11:31:10 -0800334 inode->i_mode |= S_IFLNK;
Steve French86c96b42005-11-18 20:25:31 -0800335 } else {
336 inode->i_mode |= S_IFREG; /* file? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000337 rc = -EOPNOTSUPP;
Steve French86c96b42005-11-18 20:25:31 -0800338 }
Steve French3020a1f2005-11-18 11:31:10 -0800339 } else {
340 inode->i_mode |= S_IFREG; /* then it is a file */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000341 rc = -EOPNOTSUPP; /* or some unknown SFU type */
342 }
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800343 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800344 }
345 return rc;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800346}
347
Steve French9e294f12005-11-17 16:59:21 -0800348#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
349
Steve French953f8682007-10-31 04:54:42 +0000350static int get_sfu_mode(struct inode *inode,
Steve French9e294f12005-11-17 16:59:21 -0800351 const unsigned char *path,
352 struct cifs_sb_info *cifs_sb, int xid)
353{
Steve French3020a1f2005-11-18 11:31:10 -0800354#ifdef CONFIG_CIFS_XATTR
Steve French9e294f12005-11-17 16:59:21 -0800355 ssize_t rc;
356 char ea_value[4];
357 __u32 mode;
358
359 rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
360 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000361 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4523cc32007-04-30 20:13:06 +0000362 if (rc < 0)
Steve French9e294f12005-11-17 16:59:21 -0800363 return (int)rc;
364 else if (rc > 3) {
365 mode = le32_to_cpu(*((__le32 *)ea_value));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000366 inode->i_mode &= ~SFBITS_MASK;
367 cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
Steve French9e294f12005-11-17 16:59:21 -0800368 inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000369 cFYI(1, ("special mode bits 0%o", mode));
Steve French9e294f12005-11-17 16:59:21 -0800370 return 0;
371 } else {
372 return 0;
373 }
Steve French3020a1f2005-11-18 11:31:10 -0800374#else
375 return -EOPNOTSUPP;
376#endif
Steve French9e294f12005-11-17 16:59:21 -0800377}
378
Steve Frenchb9a32602008-05-20 21:52:32 +0000379/*
380 * Needed to setup inode data for the directory which is the
381 * junction to the new submount (ie to setup the fake directory
382 * which represents a DFS referral)
383 */
384static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
385 struct super_block *sb)
386{
387 memset(pfnd_dat, sizeof(FILE_ALL_INFO), 0);
388
389/* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
390 __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
391 __u8 pfnd_dat->DeletePending = 0;
392 __u8 pfnd_data->Directory = 0;
393 __le32 pfnd_dat->EASize = 0;
394 __u64 pfnd_dat->IndexNumber = 0;
395 __u64 pfnd_dat->IndexNumber1 = 0; */
396 pfnd_dat->CreationTime =
397 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
398 pfnd_dat->LastAccessTime =
399 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
400 pfnd_dat->LastWriteTime =
401 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
402 pfnd_dat->ChangeTime =
403 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
404 pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
405 pfnd_dat->NumberOfLinks = cpu_to_le32(2);
406}
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408int cifs_get_inode_info(struct inode **pinode,
Steve French646dd532008-05-15 01:50:56 +0000409 const unsigned char *full_path, FILE_ALL_INFO *pfindData,
Steve French8b1327f2008-03-14 22:37:16 +0000410 struct super_block *sb, int xid, const __u16 *pfid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 int rc = 0;
Steve Frenchb9a32602008-05-20 21:52:32 +0000413 __u32 attr;
414 struct cifsInodeInfo *cifsInfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 struct cifsTconInfo *pTcon;
416 struct inode *inode;
417 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 char *buf = NULL;
Steve French5ade9de2008-05-02 20:56:23 +0000419 bool adjustTZ = false;
Igor Mammedov79626702008-03-09 03:44:18 +0000420 bool is_dfs_referral = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
422 pTcon = cifs_sb->tcon;
Steve French646dd532008-05-15 01:50:56 +0000423 cFYI(1, ("Getting info on %s", full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700425 if ((pfindData == NULL) && (*pinode != NULL)) {
426 if (CIFS_I(*pinode)->clientCanCacheRead) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000427 cFYI(1, ("No need to revalidate cached inode sizes"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 return rc;
429 }
430 }
431
432 /* if file info not passed in then get it from server */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700433 if (pfindData == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700435 if (buf == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 return -ENOMEM;
437 pfindData = (FILE_ALL_INFO *)buf;
Igor Mammedov79626702008-03-09 03:44:18 +0000438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 /* could do find first instead but this returns more info */
Igor Mammedov79626702008-03-09 03:44:18 +0000440 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +0000441 0 /* not legacy */,
Steve French6b8edfe2005-08-23 20:26:03 -0700442 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700443 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French6b8edfe2005-08-23 20:26:03 -0700444 /* BB optimize code so we do not make the above call
445 when server claims no NT SMB support and the above call
446 failed at least once - set flag in tcon or mount */
Steve French4523cc32007-04-30 20:13:06 +0000447 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
Igor Mammedov79626702008-03-09 03:44:18 +0000448 rc = SMBQueryInformation(xid, pTcon, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000449 pfindData, cifs_sb->local_nls,
Steve French6b8edfe2005-08-23 20:26:03 -0700450 cifs_sb->mnt_cifs_flags &
451 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French4b18f2a2008-04-29 00:06:05 +0000452 adjustTZ = true;
Steve French6b8edfe2005-08-23 20:26:03 -0700453 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 }
455 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
Steve Frenchb9a32602008-05-20 21:52:32 +0000456 if (rc == -EREMOTE) {
457 is_dfs_referral = true;
458 fill_fake_finddata(pfindData, sb);
459 rc = 0;
460 } else if (rc)
Igor Mammedov79626702008-03-09 03:44:18 +0000461 goto cgii_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
Steve Frenchb9a32602008-05-20 21:52:32 +0000463 attr = le32_to_cpu(pfindData->Attributes);
464
465 /* get new inode */
466 if (*pinode == NULL) {
467 *pinode = new_inode(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 if (*pinode == NULL) {
Steve Frenchb9a32602008-05-20 21:52:32 +0000469 rc = -ENOMEM;
470 goto cgii_exit;
471 }
472 /* Is an i_ino of zero legal? Can we use that to check
473 if the server supports returning inode numbers? Are
474 there other sanity checks we can use to ensure that
475 the server is really filling in that field? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Steve Frenchb9a32602008-05-20 21:52:32 +0000477 /* We can not use the IndexNumber field by default from
478 Windows or Samba (in ALL_INFO buf) but we can request
479 it explicitly. It may not be unique presumably if
480 the server has multiple devices mounted under one share */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Steve Frenchb9a32602008-05-20 21:52:32 +0000482 /* There may be higher info levels that work but are
483 there Windows server or network appliances for which
484 IndexNumber field is not guaranteed unique? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
Steve Frenchb9a32602008-05-20 21:52:32 +0000486 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
487 int rc1 = 0;
488 __u64 inode_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Steve Frenchb9a32602008-05-20 21:52:32 +0000490 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
Steve French646dd532008-05-15 01:50:56 +0000491 full_path, &inode_num,
Steve French737b7582005-04-28 22:41:06 -0700492 cifs_sb->local_nls,
493 cifs_sb->mnt_cifs_flags &
494 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchb9a32602008-05-20 21:52:32 +0000495 if (rc1) {
496 cFYI(1, ("GetSrvInodeNum rc %d", rc1));
497 /* BB EOPNOSUPP disable SERVER_INUM? */
498 } else /* do we need cast or hash to ino? */
499 (*pinode)->i_ino = inode_num;
500 } /* else ino incremented to unique num in new_inode*/
501 if (sb->s_flags & MS_NOATIME)
502 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
503 insert_inode_hash(*pinode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000505 inode = *pinode;
506 cifsInfo = CIFS_I(inode);
507 cifsInfo->cifsAttrs = attr;
508 cFYI(1, ("Old time %ld", cifsInfo->time));
509 cifsInfo->time = jiffies;
510 cFYI(1, ("New time %ld", cifsInfo->time));
511
512 /* blksize needs to be multiple of two. So safer to default to
513 blksize and blkbits set in superblock so 2**blkbits and blksize
514 will match rather than setting to:
515 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
516
517 /* Linux can not store file creation time so ignore it */
518 if (pfindData->LastAccessTime)
519 inode->i_atime = cifs_NTtimeToUnix
520 (le64_to_cpu(pfindData->LastAccessTime));
521 else /* do not need to use current_fs_time - time not stored */
522 inode->i_atime = CURRENT_TIME;
523 inode->i_mtime =
524 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
525 inode->i_ctime =
526 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
527 cFYI(DBG2, ("Attributes came in as 0x%x", attr));
528 if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
529 inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
530 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
531 }
532
533 /* set default mode. will override for dirs below */
534 if (atomic_read(&cifsInfo->inUse) == 0)
535 /* new inode, can safely set these fields */
536 inode->i_mode = cifs_sb->mnt_file_mode;
537 else /* since we set the inode type below we need to mask off
538 to avoid strange results if type changes and both
539 get orred in */
540 inode->i_mode &= ~S_IFMT;
541/* if (attr & ATTR_REPARSE) */
542 /* We no longer handle these as symlinks because we could not
543 follow them due to the absolute path with drive letter */
544 if (attr & ATTR_DIRECTORY) {
545 /* override default perms since we do not do byte range locking
546 on dirs */
547 inode->i_mode = cifs_sb->mnt_dir_mode;
548 inode->i_mode |= S_IFDIR;
549 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
550 (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
551 /* No need to le64 convert size of zero */
552 (pfindData->EndOfFile == 0)) {
553 inode->i_mode = cifs_sb->mnt_file_mode;
554 inode->i_mode |= S_IFIFO;
555/* BB Finish for SFU style symlinks and devices */
556 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
557 (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
558 if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile),
559 full_path, cifs_sb, xid))
560 cFYI(1, ("Unrecognized sfu inode type"));
561
562 cFYI(1, ("sfu mode 0%o", inode->i_mode));
563 } else {
564 inode->i_mode |= S_IFREG;
565 /* treat dos attribute of read-only as read-only mode eg 555 */
566 if (cifsInfo->cifsAttrs & ATTR_READONLY)
567 inode->i_mode &= ~(S_IWUGO);
568 else if ((inode->i_mode & S_IWUGO) == 0)
569 /* the ATTR_READONLY flag may have been */
570 /* changed on server -- set any w bits */
571 /* allowed by mnt_file_mode */
572 inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
573 /* BB add code to validate if device or weird share or device type? */
574 }
575
576 spin_lock(&inode->i_lock);
577 if (is_size_safe_to_change(cifsInfo,
578 le64_to_cpu(pfindData->EndOfFile))) {
579 /* can not safely shrink the file size here if the
580 client is writing to it due to potential races */
581 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
582
583 /* 512 bytes (2**9) is the fake blocksize that must be
584 used for this calculation */
585 inode->i_blocks = (512 - 1 + le64_to_cpu(
586 pfindData->AllocationSize)) >> 9;
587 }
588 spin_unlock(&inode->i_lock);
589
590 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
591
592 /* BB fill in uid and gid here? with help from winbind?
593 or retrieve from NTFS stream extended attribute */
594#ifdef CONFIG_CIFS_EXPERIMENTAL
595 /* fill in 0777 bits from ACL */
596 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
597 cFYI(1, ("Getting mode bits from ACL"));
598 acl_to_uid_mode(inode, full_path, pfid);
599 }
600#endif
601 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
602 /* fill in remaining high mode bits e.g. SUID, VTX */
603 get_sfu_mode(inode, full_path, cifs_sb, xid);
604 } else if (atomic_read(&cifsInfo->inUse) == 0) {
605 inode->i_uid = cifs_sb->mnt_uid;
606 inode->i_gid = cifs_sb->mnt_gid;
607 /* set so we do not keep refreshing these fields with
608 bad data after user has changed them in memory */
609 atomic_set(&cifsInfo->inUse, 1);
610 }
611
612 cifs_set_ops(inode, is_dfs_referral);
613
614
615
616
Igor Mammedov79626702008-03-09 03:44:18 +0000617cgii_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 kfree(buf);
619 return rc;
620}
621
Steve French7f8ed422007-09-28 22:28:55 +0000622static const struct inode_operations cifs_ipc_inode_ops = {
623 .lookup = cifs_lookup,
624};
625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626/* gets root inode */
David Howellsce634ab2008-02-07 00:15:33 -0800627struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
David Howellsce634ab2008-02-07 00:15:33 -0800629 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 struct cifs_sb_info *cifs_sb;
David Howellsce634ab2008-02-07 00:15:33 -0800631 struct inode *inode;
632 long rc;
633
634 inode = iget_locked(sb, ino);
635 if (!inode)
636 return ERR_PTR(-ENOMEM);
637 if (!(inode->i_state & I_NEW))
638 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 cifs_sb = CIFS_SB(inode->i_sb);
641 xid = GetXid();
Steve Frenchc18c8422007-07-18 23:21:09 +0000642
643 if (cifs_sb->tcon->unix_ext)
Steve French7f8ed422007-09-28 22:28:55 +0000644 rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 else
Steve French8b1327f2008-03-14 22:37:16 +0000646 rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
647 NULL);
Steve French7f8ed422007-09-28 22:28:55 +0000648 if (rc && cifs_sb->tcon->ipc) {
649 cFYI(1, ("ipc connection - fake read inode"));
650 inode->i_mode |= S_IFDIR;
651 inode->i_nlink = 2;
652 inode->i_op = &cifs_ipc_inode_ops;
653 inode->i_fop = &simple_dir_operations;
654 inode->i_uid = cifs_sb->mnt_uid;
655 inode->i_gid = cifs_sb->mnt_gid;
David Howellsce634ab2008-02-07 00:15:33 -0800656 _FreeXid(xid);
657 iget_failed(inode);
658 return ERR_PTR(rc);
Steve French7f8ed422007-09-28 22:28:55 +0000659 }
660
David Howellsce634ab2008-02-07 00:15:33 -0800661 unlock_new_inode(inode);
662
663 /* can not call macro FreeXid here since in a void func
664 * TODO: This is no longer true
665 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 _FreeXid(xid);
David Howellsce634ab2008-02-07 00:15:33 -0800667 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668}
669
670int cifs_unlink(struct inode *inode, struct dentry *direntry)
671{
672 int rc = 0;
673 int xid;
674 struct cifs_sb_info *cifs_sb;
675 struct cifsTconInfo *pTcon;
676 char *full_path = NULL;
677 struct cifsInodeInfo *cifsInode;
678 FILE_BASIC_INFO *pinfo_buf;
679
Steve French06bcfed2006-03-31 22:43:50 +0000680 cFYI(1, ("cifs_unlink, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 xid = GetXid();
683
Steve French4523cc32007-04-30 20:13:06 +0000684 if (inode)
Steve French6910ab32006-03-31 03:37:08 +0000685 cifs_sb = CIFS_SB(inode->i_sb);
686 else
Steve French06bcfed2006-03-31 22:43:50 +0000687 cifs_sb = CIFS_SB(direntry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 pTcon = cifs_sb->tcon;
689
690 /* Unlink can be called from rename so we can not grab the sem here
691 since we deadlock otherwise */
Arjan van de Vena11f3a02006-03-23 03:00:33 -0800692/* mutex_lock(&direntry->d_sb->s_vfs_rename_mutex);*/
Steve French7f573562005-08-30 11:32:14 -0700693 full_path = build_path_from_dentry(direntry);
Arjan van de Vena11f3a02006-03-23 03:00:33 -0800694/* mutex_unlock(&direntry->d_sb->s_vfs_rename_mutex);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (full_path == NULL) {
696 FreeXid(xid);
697 return -ENOMEM;
698 }
Steve French2d785a52007-07-15 01:48:57 +0000699
700 if ((pTcon->ses->capabilities & CAP_UNIX) &&
701 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
702 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
703 rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
704 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
705 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
706 cFYI(1, ("posix del rc %d", rc));
707 if ((rc == 0) || (rc == -ENOENT))
708 goto psx_del_no_retry;
709 }
710
Steve French737b7582005-04-28 22:41:06 -0700711 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
712 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French2d785a52007-07-15 01:48:57 +0000713psx_del_no_retry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 if (!rc) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700715 if (direntry->d_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700716 drop_nlink(direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 } else if (rc == -ENOENT) {
718 d_drop(direntry);
719 } else if (rc == -ETXTBSY) {
Steve French4b18f2a2008-04-29 00:06:05 +0000720 int oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 __u16 netfid;
722
723 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
724 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
Steve French737b7582005-04-28 22:41:06 -0700725 &netfid, &oplock, NULL, cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000726 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700727 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000728 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000730 cifs_sb->local_nls,
731 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700732 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700734 if (direntry->d_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700735 drop_nlink(direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737 } else if (rc == -EACCES) {
738 /* try only if r/o attribute set in local lookup data? */
Eric Sesterhenna048d7a2006-02-21 22:33:09 +0000739 pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if (pinfo_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 /* ATTRS set to normal clears r/o bit */
742 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
743 if (!(pTcon->ses->flags & CIFS_SES_NT4))
744 rc = CIFSSMBSetTimes(xid, pTcon, full_path,
745 pinfo_buf,
Steve French737b7582005-04-28 22:41:06 -0700746 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000747 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700748 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 else
750 rc = -EOPNOTSUPP;
751
752 if (rc == -EOPNOTSUPP) {
Steve French4b18f2a2008-04-29 00:06:05 +0000753 int oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 __u16 netfid;
755 /* rc = CIFSSMBSetAttrLegacy(xid, pTcon,
756 full_path,
757 (__u16)ATTR_NORMAL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000758 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 For some strange reason it seems that NT4 eats the
760 old setattr call without actually setting the
761 attributes so on to the third attempted workaround
762 */
763
764 /* BB could scan to see if we already have it open
765 and pass in pid of opener to function */
766 rc = CIFSSMBOpen(xid, pTcon, full_path,
767 FILE_OPEN, SYNCHRONIZE |
768 FILE_WRITE_ATTRIBUTES, 0,
769 &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700770 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000771 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700772 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000773 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 rc = CIFSSMBSetFileTimes(xid, pTcon,
775 pinfo_buf,
776 netfid);
777 CIFSSMBClose(xid, pTcon, netfid);
778 }
779 }
780 kfree(pinfo_buf);
781 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000782 if (rc == 0) {
783 rc = CIFSSMBDelFile(xid, pTcon, full_path,
784 cifs_sb->local_nls,
785 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700786 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 if (!rc) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700788 if (direntry->d_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700789 drop_nlink(direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 } else if (rc == -ETXTBSY) {
Steve French4b18f2a2008-04-29 00:06:05 +0000791 int oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 __u16 netfid;
793
794 rc = CIFSSMBOpen(xid, pTcon, full_path,
795 FILE_OPEN, DELETE,
796 CREATE_NOT_DIR |
797 CREATE_DELETE_ON_CLOSE,
798 &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000799 cifs_sb->local_nls,
800 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700801 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000802 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 CIFSSMBRenameOpenFile(xid, pTcon,
804 netfid, NULL,
Steve French737b7582005-04-28 22:41:06 -0700805 cifs_sb->local_nls,
806 cifs_sb->mnt_cifs_flags &
807 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700809 if (direntry->d_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700810 drop_nlink(direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 }
812 /* BB if rc = -ETXTBUSY goto the rename logic BB */
813 }
814 }
815 }
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700816 if (direntry->d_inode) {
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500817 cifsInode = CIFS_I(direntry->d_inode);
818 cifsInode->time = 0; /* will force revalidate to get info
819 when needed */
820 direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
821 }
Steve French4523cc32007-04-30 20:13:06 +0000822 if (inode) {
Steve French06bcfed2006-03-31 22:43:50 +0000823 inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
824 cifsInode = CIFS_I(inode);
825 cifsInode->time = 0; /* force revalidate of dir as well */
826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
828 kfree(full_path);
829 FreeXid(xid);
830 return rc;
831}
832
Steve French2dd29d32007-04-23 22:07:35 +0000833static void posix_fill_in_inode(struct inode *tmp_inode,
Steve French0b442d22008-02-26 03:44:02 +0000834 FILE_UNIX_BASIC_INFO *pData, int isNewInode)
Steve French2dd29d32007-04-23 22:07:35 +0000835{
Christoph Hellwig75f12982008-02-25 20:25:21 +0000836 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
Steve French2dd29d32007-04-23 22:07:35 +0000837 loff_t local_size;
838 struct timespec local_mtime;
839
Steve French2dd29d32007-04-23 22:07:35 +0000840 cifsInfo->time = jiffies;
841 atomic_inc(&cifsInfo->inUse);
842
843 /* save mtime and size */
844 local_mtime = tmp_inode->i_mtime;
845 local_size = tmp_inode->i_size;
846
Christoph Hellwig75f12982008-02-25 20:25:21 +0000847 cifs_unix_info_to_inode(tmp_inode, pData, 1);
Igor Mammedov79626702008-03-09 03:44:18 +0000848 cifs_set_ops(tmp_inode, false);
Steve French2dd29d32007-04-23 22:07:35 +0000849
Christoph Hellwig75f12982008-02-25 20:25:21 +0000850 if (!S_ISREG(tmp_inode->i_mode))
851 return;
852
853 /*
854 * No sense invalidating pages for new inode
855 * since we we have not started caching
856 * readahead file data yet.
857 */
858 if (isNewInode)
859 return;
860
861 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
862 (local_size == tmp_inode->i_size)) {
863 cFYI(1, ("inode exists but unchanged"));
Steve French2dd29d32007-04-23 22:07:35 +0000864 } else {
Christoph Hellwig75f12982008-02-25 20:25:21 +0000865 /* file may have changed on server */
866 cFYI(1, ("invalidate inode, readdir detected change"));
867 invalidate_remote_inode(tmp_inode);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000868 }
Steve French2dd29d32007-04-23 22:07:35 +0000869}
870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
872{
873 int rc = 0;
874 int xid;
875 struct cifs_sb_info *cifs_sb;
876 struct cifsTconInfo *pTcon;
877 char *full_path = NULL;
878 struct inode *newinode = NULL;
879
Steve French6473a552005-11-29 20:20:10 -0800880 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 xid = GetXid();
883
884 cifs_sb = CIFS_SB(inode->i_sb);
885 pTcon = cifs_sb->tcon;
886
Steve French7f573562005-08-30 11:32:14 -0700887 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if (full_path == NULL) {
889 FreeXid(xid);
890 return -ENOMEM;
891 }
Steve French50c2f752007-07-13 00:33:32 +0000892
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000893 if ((pTcon->ses->capabilities & CAP_UNIX) &&
894 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
Steve French2dd29d32007-04-23 22:07:35 +0000895 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
896 u32 oplock = 0;
Steve Frenchf6d09982008-01-08 23:18:22 +0000897 FILE_UNIX_BASIC_INFO *pInfo =
Steve French2dd29d32007-04-23 22:07:35 +0000898 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000899 if (pInfo == NULL) {
Steve French2dd29d32007-04-23 22:07:35 +0000900 rc = -ENOMEM;
901 goto mkdir_out;
902 }
Steve French50c2f752007-07-13 00:33:32 +0000903
Jeffa8cd9252007-09-13 18:38:50 +0000904 mode &= ~current->fs->umask;
Steve French2dd29d32007-04-23 22:07:35 +0000905 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
906 mode, NULL /* netfid */, pInfo, &oplock,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000907 full_path, cifs_sb->local_nls,
908 cifs_sb->mnt_cifs_flags &
Steve French2dd29d32007-04-23 22:07:35 +0000909 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc45d7072007-09-17 02:04:21 +0000910 if (rc == -EOPNOTSUPP) {
911 kfree(pInfo);
912 goto mkdir_retry_old;
913 } else if (rc) {
Steve French2dd29d32007-04-23 22:07:35 +0000914 cFYI(1, ("posix mkdir returned 0x%x", rc));
915 d_drop(direntry);
916 } else {
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000917 if (pInfo->Type == cpu_to_le32(-1)) {
918 /* no return info, go query for it */
Steve French5a07cdf2007-09-16 23:12:47 +0000919 kfree(pInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000920 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +0000921 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000922/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
923 to set uid/gid */
Steve French2dd29d32007-04-23 22:07:35 +0000924 inc_nlink(inode);
925 if (pTcon->nocase)
926 direntry->d_op = &cifs_ci_dentry_ops;
927 else
928 direntry->d_op = &cifs_dentry_ops;
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000929
930 newinode = new_inode(inode->i_sb);
Steve French5a07cdf2007-09-16 23:12:47 +0000931 if (newinode == NULL) {
932 kfree(pInfo);
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000933 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +0000934 }
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000935 /* Is an i_ino of zero legal? */
936 /* Are there sanity checks we can use to ensure that
937 the server is really filling in that field? */
938 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
939 newinode->i_ino =
940 (unsigned long)pInfo->UniqueId;
941 } /* note ino incremented to unique num in new_inode */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000942 if (inode->i_sb->s_flags & MS_NOATIME)
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000943 newinode->i_flags |= S_NOATIME | S_NOCMTIME;
944 newinode->i_nlink = 2;
945
946 insert_inode_hash(newinode);
Steve French2dd29d32007-04-23 22:07:35 +0000947 d_instantiate(direntry, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000948
949 /* we already checked in POSIXCreate whether
950 frame was long enough */
951 posix_fill_in_inode(direntry->d_inode,
Steve French0b442d22008-02-26 03:44:02 +0000952 pInfo, 1 /* NewInode */);
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000953#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000954 cFYI(1, ("instantiated dentry %p %s to inode %p",
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000955 direntry, direntry->d_name.name, newinode));
956
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000957 if (newinode->i_nlink != 2)
958 cFYI(1, ("unexpected number of links %d",
Steve Frenchcbac3cb2007-04-25 11:46:06 +0000959 newinode->i_nlink));
960#endif
Steve French2dd29d32007-04-23 22:07:35 +0000961 }
962 kfree(pInfo);
963 goto mkdir_out;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000964 }
Steve Frenchc45d7072007-09-17 02:04:21 +0000965mkdir_retry_old:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -0700967 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
968 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000970 cFYI(1, ("cifs_mkdir returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 d_drop(direntry);
972 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000973mkdir_get_info:
Dave Hansend8c76e62006-09-30 23:29:04 -0700974 inc_nlink(inode);
Steve Frenchc18c8422007-07-18 23:21:09 +0000975 if (pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000977 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 else
979 rc = cifs_get_inode_info(&newinode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +0000980 inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Steve Frenchb92327f2005-08-22 20:09:43 -0700982 if (pTcon->nocase)
983 direntry->d_op = &cifs_ci_dentry_ops;
984 else
985 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 d_instantiate(direntry, newinode);
Steve French2dd29d32007-04-23 22:07:35 +0000987 /* setting nlink not necessary except in cases where we
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000988 * failed to get it from the server or was set bogus */
Steve French2dd29d32007-04-23 22:07:35 +0000989 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000990 direntry->d_inode->i_nlink = 2;
Jeff Layton67750fb2008-05-09 22:28:02 +0000991 mode &= ~current->fs->umask;
Steve Frenchc18c8422007-07-18 23:21:09 +0000992 if (pTcon->unix_ext) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700993 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
995 mode,
Steve French83451872005-12-01 17:12:59 -0800996 (__u64)current->fsuid,
997 (__u64)current->fsgid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 0 /* dev_t */,
Steve French737b7582005-04-28 22:41:06 -0700999 cifs_sb->local_nls,
1000 cifs_sb->mnt_cifs_flags &
1001 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 } else {
1003 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
1004 mode, (__u64)-1,
1005 (__u64)-1, 0 /* dev_t */,
Steve French737b7582005-04-28 22:41:06 -07001006 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001007 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -07001008 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 }
Steve French3ce53fc2007-06-08 14:55:14 +00001010 } else {
Jeff Layton67750fb2008-05-09 22:28:02 +00001011 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1012 (mode & S_IWUGO) == 0) {
1013 FILE_BASIC_INFO pInfo;
1014 memset(&pInfo, 0, sizeof(pInfo));
1015 pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
1016 CIFSSMBSetTimes(xid, pTcon, full_path,
1017 &pInfo, cifs_sb->local_nls,
1018 cifs_sb->mnt_cifs_flags &
1019 CIFS_MOUNT_MAP_SPECIAL_CHR);
1020 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001021 if (direntry->d_inode) {
Steve French6473a552005-11-29 20:20:10 -08001022 direntry->d_inode->i_mode = mode;
Steve French25741b32005-11-29 22:38:43 -08001023 direntry->d_inode->i_mode |= S_IFDIR;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001024 if (cifs_sb->mnt_cifs_flags &
Steve French6473a552005-11-29 20:20:10 -08001025 CIFS_MOUNT_SET_UID) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001026 direntry->d_inode->i_uid =
Steve French6473a552005-11-29 20:20:10 -08001027 current->fsuid;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001028 direntry->d_inode->i_gid =
Steve French6473a552005-11-29 20:20:10 -08001029 current->fsgid;
1030 }
1031 }
Steve French2a138ebb2005-11-29 21:22:19 -08001032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001034mkdir_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 kfree(full_path);
1036 FreeXid(xid);
1037 return rc;
1038}
1039
1040int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1041{
1042 int rc = 0;
1043 int xid;
1044 struct cifs_sb_info *cifs_sb;
1045 struct cifsTconInfo *pTcon;
1046 char *full_path = NULL;
1047 struct cifsInodeInfo *cifsInode;
1048
Steve French26a21b92006-05-31 18:05:34 +00001049 cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
1051 xid = GetXid();
1052
1053 cifs_sb = CIFS_SB(inode->i_sb);
1054 pTcon = cifs_sb->tcon;
1055
Steve French7f573562005-08-30 11:32:14 -07001056 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 if (full_path == NULL) {
1058 FreeXid(xid);
1059 return -ENOMEM;
1060 }
1061
Steve French737b7582005-04-28 22:41:06 -07001062 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1063 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065 if (!rc) {
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001066 drop_nlink(inode);
Steve French3677db12007-02-26 16:46:11 +00001067 spin_lock(&direntry->d_inode->i_lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001068 i_size_write(direntry->d_inode, 0);
Dave Hansence71ec32006-09-30 23:29:06 -07001069 clear_nlink(direntry->d_inode);
Steve French3677db12007-02-26 16:46:11 +00001070 spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
1072
1073 cifsInode = CIFS_I(direntry->d_inode);
1074 cifsInode->time = 0; /* force revalidate to go get info when
1075 needed */
1076 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1077 current_fs_time(inode->i_sb);
1078
1079 kfree(full_path);
1080 FreeXid(xid);
1081 return rc;
1082}
1083
1084int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
1085 struct inode *target_inode, struct dentry *target_direntry)
1086{
1087 char *fromName;
1088 char *toName;
1089 struct cifs_sb_info *cifs_sb_source;
1090 struct cifs_sb_info *cifs_sb_target;
1091 struct cifsTconInfo *pTcon;
1092 int xid;
1093 int rc = 0;
1094
1095 xid = GetXid();
1096
1097 cifs_sb_target = CIFS_SB(target_inode->i_sb);
1098 cifs_sb_source = CIFS_SB(source_inode->i_sb);
1099 pTcon = cifs_sb_source->tcon;
1100
1101 if (pTcon != cifs_sb_target->tcon) {
1102 FreeXid(xid);
1103 return -EXDEV; /* BB actually could be allowed if same server,
1104 but different share.
1105 Might eventually add support for this */
1106 }
1107
1108 /* we already have the rename sem so we do not need to grab it again
1109 here to protect the path integrity */
Steve French7f573562005-08-30 11:32:14 -07001110 fromName = build_path_from_dentry(source_direntry);
1111 toName = build_path_from_dentry(target_direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if ((fromName == NULL) || (toName == NULL)) {
1113 rc = -ENOMEM;
1114 goto cifs_rename_exit;
1115 }
1116
1117 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
Steve French737b7582005-04-28 22:41:06 -07001118 cifs_sb_source->local_nls,
1119 cifs_sb_source->mnt_cifs_flags &
1120 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (rc == -EEXIST) {
1122 /* check if they are the same file because rename of hardlinked
1123 files is a noop */
1124 FILE_UNIX_BASIC_INFO *info_buf_source;
1125 FILE_UNIX_BASIC_INFO *info_buf_target;
1126
1127 info_buf_source =
1128 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
1129 if (info_buf_source != NULL) {
1130 info_buf_target = info_buf_source + 1;
Steve Frenchc18c8422007-07-18 23:21:09 +00001131 if (pTcon->unix_ext)
Steve French8e87d4d2006-11-02 03:45:24 +00001132 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001133 info_buf_source,
Steve French8e87d4d2006-11-02 03:45:24 +00001134 cifs_sb_source->local_nls,
1135 cifs_sb_source->mnt_cifs_flags &
1136 CIFS_MOUNT_MAP_SPECIAL_CHR);
1137 /* else rc is still EEXIST so will fall through to
1138 unlink the target and retry rename */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 if (rc == 0) {
1140 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
1141 info_buf_target,
Steve French737b7582005-04-28 22:41:06 -07001142 cifs_sb_target->local_nls,
1143 /* remap based on source sb */
1144 cifs_sb_source->mnt_cifs_flags &
1145 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 }
1147 if ((rc == 0) &&
1148 (info_buf_source->UniqueId ==
1149 info_buf_target->UniqueId)) {
1150 /* do not rename since the files are hardlinked which
1151 is a noop */
1152 } else {
1153 /* we either can not tell the files are hardlinked
1154 (as with Windows servers) or files are not
1155 hardlinked so delete the target manually before
1156 renaming to follow POSIX rather than Windows
1157 semantics */
1158 cifs_unlink(target_inode, target_direntry);
1159 rc = CIFSSMBRename(xid, pTcon, fromName,
1160 toName,
Steve French737b7582005-04-28 22:41:06 -07001161 cifs_sb_source->local_nls,
1162 cifs_sb_source->mnt_cifs_flags
1163 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 }
1165 kfree(info_buf_source);
1166 } /* if we can not get memory just leave rc as EEXIST */
1167 }
1168
Steve Frenchad7a2922008-02-07 23:25:02 +00001169 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 cFYI(1, ("rename rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172 if ((rc == -EIO) || (rc == -EEXIST)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001173 int oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 __u16 netfid;
1175
1176 /* BB FIXME Is Generic Read correct for rename? */
1177 /* if renaming directory - we should not say CREATE_NOT_DIR,
1178 need to test renaming open directory, also GENERIC_READ
1179 might not right be right access to request */
1180 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
1181 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001182 cifs_sb_source->local_nls,
1183 cifs_sb_source->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -07001184 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001185 if (rc == 0) {
Steve French8e87d4d2006-11-02 03:45:24 +00001186 rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001187 cifs_sb_source->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001188 cifs_sb_source->mnt_cifs_flags &
1189 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 CIFSSMBClose(xid, pTcon, netfid);
1191 }
1192 }
1193
1194cifs_rename_exit:
1195 kfree(fromName);
1196 kfree(toName);
1197 FreeXid(xid);
1198 return rc;
1199}
1200
1201int cifs_revalidate(struct dentry *direntry)
1202{
1203 int xid;
Jeff Laytoncea21802007-11-20 23:19:03 +00001204 int rc = 0, wbrc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 char *full_path;
1206 struct cifs_sb_info *cifs_sb;
1207 struct cifsInodeInfo *cifsInode;
1208 loff_t local_size;
1209 struct timespec local_mtime;
Steve French4b18f2a2008-04-29 00:06:05 +00001210 bool invalidate_inode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
1212 if (direntry->d_inode == NULL)
1213 return -ENOENT;
1214
1215 cifsInode = CIFS_I(direntry->d_inode);
1216
1217 if (cifsInode == NULL)
1218 return -ENOENT;
1219
1220 /* no sense revalidating inode info on file that no one can write */
1221 if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
1222 return rc;
1223
1224 xid = GetXid();
1225
1226 cifs_sb = CIFS_SB(direntry->d_sb);
1227
1228 /* can not safely grab the rename sem here if rename calls revalidate
1229 since that would deadlock */
Steve French7f573562005-08-30 11:32:14 -07001230 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 if (full_path == NULL) {
1232 FreeXid(xid);
1233 return -ENOMEM;
1234 }
1235 cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
1236 "jiffies %ld", full_path, direntry->d_inode,
1237 direntry->d_inode->i_count.counter, direntry,
1238 direntry->d_time, jiffies));
1239
1240 if (cifsInode->time == 0) {
1241 /* was set to zero previously to force revalidate */
1242 } else if (time_before(jiffies, cifsInode->time + HZ) &&
1243 lookupCacheEnabled) {
1244 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
1245 (direntry->d_inode->i_nlink == 1)) {
1246 kfree(full_path);
1247 FreeXid(xid);
1248 return rc;
1249 } else {
1250 cFYI(1, ("Have to revalidate file due to hardlinks"));
1251 }
1252 }
1253
1254 /* save mtime and size */
1255 local_mtime = direntry->d_inode->i_mtime;
1256 local_size = direntry->d_inode->i_size;
1257
Steve Frenchc18c8422007-07-18 23:21:09 +00001258 if (cifs_sb->tcon->unix_ext) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001260 direntry->d_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 if (rc) {
1262 cFYI(1, ("error on getting revalidate info %d", rc));
1263/* if (rc != -ENOENT)
1264 rc = 0; */ /* BB should we cache info on
1265 certain errors? */
1266 }
1267 } else {
1268 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +00001269 direntry->d_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 if (rc) {
1271 cFYI(1, ("error on getting revalidate info %d", rc));
1272/* if (rc != -ENOENT)
1273 rc = 0; */ /* BB should we cache info on
1274 certain errors? */
1275 }
1276 }
1277 /* should we remap certain errors, access denied?, to zero */
1278
1279 /* if not oplocked, we invalidate inode pages if mtime or file size
1280 had changed on server */
1281
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001282 if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 (local_size == direntry->d_inode->i_size)) {
1284 cFYI(1, ("cifs_revalidate - inode unchanged"));
1285 } else {
1286 /* file may have changed on server */
1287 if (cifsInode->clientCanCacheRead) {
1288 /* no need to invalidate inode pages since we were the
1289 only ones who could have modified the file and the
1290 server copy is staler than ours */
1291 } else {
Steve French4b18f2a2008-04-29 00:06:05 +00001292 invalidate_inode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 }
1294 }
1295
1296 /* can not grab this sem since kernel filesys locking documentation
Jes Sorensen1b1dcc12006-01-09 15:59:24 -08001297 indicates i_mutex may be taken by the kernel on lookup and rename
1298 which could deadlock if we grab the i_mutex here as well */
1299/* mutex_lock(&direntry->d_inode->i_mutex);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 /* need to write out dirty pages here */
1301 if (direntry->d_inode->i_mapping) {
1302 /* do we need to lock inode until after invalidate completes
1303 below? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001304 wbrc = filemap_fdatawrite(direntry->d_inode->i_mapping);
1305 if (wbrc)
1306 CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 }
1308 if (invalidate_inode) {
Steve French3abb9272005-11-28 08:16:13 -08001309 /* shrink_dcache not necessary now that cifs dentry ops
1310 are exported for negative dentries */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001311/* if (S_ISDIR(direntry->d_inode->i_mode))
Steve French3abb9272005-11-28 08:16:13 -08001312 shrink_dcache_parent(direntry); */
1313 if (S_ISREG(direntry->d_inode->i_mode)) {
1314 if (direntry->d_inode->i_mapping)
Jeff Laytoncea21802007-11-20 23:19:03 +00001315 wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
1316 if (wbrc)
1317 CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
Steve French3abb9272005-11-28 08:16:13 -08001318 /* may eventually have to do this for open files too */
1319 if (list_empty(&(cifsInode->openFileList))) {
1320 /* changed on server - flush read ahead pages */
1321 cFYI(1, ("Invalidating read ahead data on "
1322 "closed file"));
1323 invalidate_remote_inode(direntry->d_inode);
1324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 }
1326 }
Jes Sorensen1b1dcc12006-01-09 15:59:24 -08001327/* mutex_unlock(&direntry->d_inode->i_mutex); */
Steve French50c2f752007-07-13 00:33:32 +00001328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 kfree(full_path);
1330 FreeXid(xid);
1331 return rc;
1332}
1333
1334int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1335 struct kstat *stat)
1336{
1337 int err = cifs_revalidate(dentry);
Steve French5fe14c82006-11-07 19:26:33 +00001338 if (!err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 generic_fillattr(dentry->d_inode, stat);
Steve French5fe14c82006-11-07 19:26:33 +00001340 stat->blksize = CIFS_MAX_MSGSIZE;
1341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 return err;
1343}
1344
1345static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1346{
1347 pgoff_t index = from >> PAGE_CACHE_SHIFT;
1348 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1349 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 int rc = 0;
1351
1352 page = grab_cache_page(mapping, index);
1353 if (!page)
1354 return -ENOMEM;
1355
Christoph Lametereebd2aa2008-02-04 22:28:29 -08001356 zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 unlock_page(page);
1358 page_cache_release(page);
1359 return rc;
1360}
1361
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001362static int cifs_vmtruncate(struct inode *inode, loff_t offset)
Steve French3677db12007-02-26 16:46:11 +00001363{
1364 struct address_space *mapping = inode->i_mapping;
1365 unsigned long limit;
1366
Steve Frenchba6a46a2007-02-26 20:06:29 +00001367 spin_lock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001368 if (inode->i_size < offset)
1369 goto do_expand;
1370 /*
1371 * truncation of in-use swapfiles is disallowed - it would cause
1372 * subsequent swapout to scribble on the now-freed blocks.
1373 */
Steve Frenchba6a46a2007-02-26 20:06:29 +00001374 if (IS_SWAPFILE(inode)) {
1375 spin_unlock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001376 goto out_busy;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001377 }
Steve French3677db12007-02-26 16:46:11 +00001378 i_size_write(inode, offset);
1379 spin_unlock(&inode->i_lock);
Steve French8064ab42007-08-22 22:12:07 +00001380 /*
1381 * unmap_mapping_range is called twice, first simply for efficiency
1382 * so that truncate_inode_pages does fewer single-page unmaps. However
1383 * after this first call, and before truncate_inode_pages finishes,
1384 * it is possible for private pages to be COWed, which remain after
1385 * truncate_inode_pages finishes, hence the second unmap_mapping_range
1386 * call must be made for correctness.
1387 */
Steve French3677db12007-02-26 16:46:11 +00001388 unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
1389 truncate_inode_pages(mapping, offset);
Steve French8064ab42007-08-22 22:12:07 +00001390 unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
Steve French3677db12007-02-26 16:46:11 +00001391 goto out_truncate;
1392
1393do_expand:
1394 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001395 if (limit != RLIM_INFINITY && offset > limit) {
1396 spin_unlock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001397 goto out_sig;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001398 }
1399 if (offset > inode->i_sb->s_maxbytes) {
1400 spin_unlock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001401 goto out_big;
Steve Frenchba6a46a2007-02-26 20:06:29 +00001402 }
Steve French3677db12007-02-26 16:46:11 +00001403 i_size_write(inode, offset);
Steve Frenchba6a46a2007-02-26 20:06:29 +00001404 spin_unlock(&inode->i_lock);
Steve French3677db12007-02-26 16:46:11 +00001405out_truncate:
1406 if (inode->i_op && inode->i_op->truncate)
1407 inode->i_op->truncate(inode);
1408 return 0;
1409out_sig:
1410 send_sig(SIGXFSZ, current, 0);
1411out_big:
1412 return -EFBIG;
1413out_busy:
1414 return -ETXTBSY;
1415}
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1418{
1419 int xid;
1420 struct cifs_sb_info *cifs_sb;
1421 struct cifsTconInfo *pTcon;
1422 char *full_path = NULL;
1423 int rc = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 struct cifsFileInfo *open_file = NULL;
1425 FILE_BASIC_INFO time_buf;
Steve French4b18f2a2008-04-29 00:06:05 +00001426 bool set_time = false;
1427 bool set_dosattr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
1429 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
1430 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
1431 struct cifsInodeInfo *cifsInode;
Jeff Layton02eadef2008-05-09 21:26:11 +00001432 struct inode *inode = direntry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
1434 xid = GetXid();
1435
Steve French39798772006-05-31 22:40:51 +00001436 cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 direntry->d_name.name, attrs->ia_valid));
Steve French6473a552005-11-29 20:20:10 -08001438
Jeff Layton02eadef2008-05-09 21:26:11 +00001439 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 pTcon = cifs_sb->tcon;
1441
Steve French2a138ebb2005-11-29 21:22:19 -08001442 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
Steve French6473a552005-11-29 20:20:10 -08001443 /* check if we have permission to change attrs */
Jeff Layton02eadef2008-05-09 21:26:11 +00001444 rc = inode_change_ok(inode, attrs);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001445 if (rc < 0) {
Steve French6473a552005-11-29 20:20:10 -08001446 FreeXid(xid);
1447 return rc;
1448 } else
1449 rc = 0;
1450 }
Steve French50c2f752007-07-13 00:33:32 +00001451
Steve French7f573562005-08-30 11:32:14 -07001452 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (full_path == NULL) {
1454 FreeXid(xid);
1455 return -ENOMEM;
1456 }
Jeff Layton02eadef2008-05-09 21:26:11 +00001457 cifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Steve French50531442008-03-14 19:21:31 +00001459 if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
Jeff Laytoncea21802007-11-20 23:19:03 +00001460 /*
Steve French50531442008-03-14 19:21:31 +00001461 Flush data before changing file size or changing the last
1462 write time of the file on the server. If the
Jeff Laytoncea21802007-11-20 23:19:03 +00001463 flush returns error, store it to report later and continue.
1464 BB: This should be smarter. Why bother flushing pages that
1465 will be truncated anyway? Also, should we error out here if
1466 the flush returns error?
1467 */
Jeff Layton02eadef2008-05-09 21:26:11 +00001468 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001469 if (rc != 0) {
Jeff Layton02eadef2008-05-09 21:26:11 +00001470 cifsInode->write_behind_rc = rc;
Jeff Laytoncea21802007-11-20 23:19:03 +00001471 rc = 0;
1472 }
Steve French50531442008-03-14 19:21:31 +00001473 }
Jeff Laytoncea21802007-11-20 23:19:03 +00001474
Steve French50531442008-03-14 19:21:31 +00001475 if (attrs->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 /* To avoid spurious oplock breaks from server, in the case of
1477 inodes that we already have open, avoid doing path based
1478 setting of file size if we can do it by handle.
1479 This keeps our caching token (oplock) and avoids timeouts
1480 when the local oplock break takes longer to flush
1481 writebehind data than the SMB timeout for the SetPathInfo
1482 request would allow */
Steve French39798772006-05-31 22:40:51 +00001483
Steve French6148a742005-10-05 12:23:19 -07001484 open_file = find_writable_file(cifsInode);
1485 if (open_file) {
1486 __u16 nfid = open_file->netfid;
1487 __u32 npid = open_file->pid;
1488 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
Steve French4b18f2a2008-04-29 00:06:05 +00001489 nfid, npid, false);
Steve French23e7dd72005-10-20 13:44:56 -07001490 atomic_dec(&open_file->wrtPending);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001491 cFYI(1, ("SetFSize for attrs rc = %d", rc));
1492 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
Steve French77159b42007-08-31 01:10:17 +00001493 unsigned int bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001494 rc = CIFSSMBWrite(xid, pTcon,
1495 nfid, 0, attrs->ia_size,
1496 &bytes_written, NULL, NULL,
1497 1 /* 45 seconds */);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001498 cFYI(1, ("Wrt seteof rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001500 } else
Steve French6473a552005-11-29 20:20:10 -08001501 rc = -EINVAL;
1502
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if (rc != 0) {
1504 /* Set file size by pathname rather than by handle
1505 either because no valid, writeable file handle for
1506 it was found or because there was an error setting
1507 it by handle */
1508 rc = CIFSSMBSetEOF(xid, pTcon, full_path,
Steve French4b18f2a2008-04-29 00:06:05 +00001509 attrs->ia_size, false,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001510 cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001511 cifs_sb->mnt_cifs_flags &
1512 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenche30dcf32005-09-20 20:49:16 -07001513 cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001514 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
Steve Frenche30dcf32005-09-20 20:49:16 -07001515 __u16 netfid;
Steve French4b18f2a2008-04-29 00:06:05 +00001516 int oplock = 0;
Steve Frenche30dcf32005-09-20 20:49:16 -07001517
1518 rc = SMBLegacyOpen(xid, pTcon, full_path,
Jeff Layton35fc37d2008-05-14 10:22:03 -07001519 FILE_OPEN, GENERIC_WRITE,
Steve Frenche30dcf32005-09-20 20:49:16 -07001520 CREATE_NOT_DIR, &netfid, &oplock,
1521 NULL, cifs_sb->local_nls,
1522 cifs_sb->mnt_cifs_flags &
1523 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001524 if (rc == 0) {
Steve French77159b42007-08-31 01:10:17 +00001525 unsigned int bytes_written;
Steve Frenche30dcf32005-09-20 20:49:16 -07001526 rc = CIFSSMBWrite(xid, pTcon,
1527 netfid, 0,
1528 attrs->ia_size,
1529 &bytes_written, NULL,
1530 NULL, 1 /* 45 sec */);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001531 cFYI(1, ("wrt seteof rc %d", rc));
Steve Frenche30dcf32005-09-20 20:49:16 -07001532 CIFSSMBClose(xid, pTcon, netfid);
1533 }
1534
1535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 }
1537
1538 /* Server is ok setting allocation size implicitly - no need
1539 to call:
Steve French4b18f2a2008-04-29 00:06:05 +00001540 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, true,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 cifs_sb->local_nls);
1542 */
1543
1544 if (rc == 0) {
Jeff Layton02eadef2008-05-09 21:26:11 +00001545 rc = cifs_vmtruncate(inode, attrs->ia_size);
1546 cifs_truncate_page(inode->i_mapping, inode->i_size);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001547 } else
Steve Frenche30dcf32005-09-20 20:49:16 -07001548 goto cifs_setattr_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 }
1550 if (attrs->ia_valid & ATTR_UID) {
Steve Frenche30dcf32005-09-20 20:49:16 -07001551 cFYI(1, ("UID changed to %d", attrs->ia_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 uid = attrs->ia_uid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 }
1554 if (attrs->ia_valid & ATTR_GID) {
Steve Frenche30dcf32005-09-20 20:49:16 -07001555 cFYI(1, ("GID changed to %d", attrs->ia_gid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 gid = attrs->ia_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
1558
1559 time_buf.Attributes = 0;
Jeff Laytond32c4f22007-10-18 03:05:22 -07001560
1561 /* skip mode change if it's just for clearing setuid/setgid */
1562 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1563 attrs->ia_valid &= ~ATTR_MODE;
1564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 if (attrs->ia_valid & ATTR_MODE) {
Steve Frenche30dcf32005-09-20 20:49:16 -07001566 cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 mode = attrs->ia_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 }
1569
Steve Frenchc18c8422007-07-18 23:21:09 +00001570 if ((pTcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1572 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
Steve French737b7582005-04-28 22:41:06 -07001573 0 /* dev_t */, cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001574 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -07001575 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 else if (attrs->ia_valid & ATTR_MODE) {
Steve Frenchcdbce9c2005-11-19 21:04:52 -08001577 rc = 0;
Steve French97837582007-12-31 07:47:21 +00001578#ifdef CONFIG_CIFS_EXPERIMENTAL
1579 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
Jeff Layton02eadef2008-05-09 21:26:11 +00001580 rc = mode_to_acl(inode, full_path, mode);
Steve Frenchf6d09982008-01-08 23:18:22 +00001581 else if ((mode & S_IWUGO) == 0) {
Steve French97837582007-12-31 07:47:21 +00001582#else
Steve Frenchf6d09982008-01-08 23:18:22 +00001583 if ((mode & S_IWUGO) == 0) {
Steve French97837582007-12-31 07:47:21 +00001584#endif
Steve Frenchf6d09982008-01-08 23:18:22 +00001585 /* not writeable */
Steve French066fcb02007-03-23 00:45:08 +00001586 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001587 set_dosattr = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 time_buf.Attributes =
1589 cpu_to_le32(cifsInode->cifsAttrs |
1590 ATTR_READONLY);
Steve French066fcb02007-03-23 00:45:08 +00001591 }
Steve French5268df22007-04-06 19:28:16 +00001592 } else if (cifsInode->cifsAttrs & ATTR_READONLY) {
1593 /* If file is readonly on server, we would
1594 not be able to write to it - so if any write
1595 bit is enabled for user or group or other we
1596 need to at least try to remove r/o dos attr */
Steve French4b18f2a2008-04-29 00:06:05 +00001597 set_dosattr = true;
Steve French5268df22007-04-06 19:28:16 +00001598 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
1599 (~ATTR_READONLY));
1600 /* Windows ignores set to zero */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001601 if (time_buf.Attributes == 0)
Steve French5268df22007-04-06 19:28:16 +00001602 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 }
1605
1606 if (attrs->ia_valid & ATTR_ATIME) {
Steve French4b18f2a2008-04-29 00:06:05 +00001607 set_time = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 time_buf.LastAccessTime =
1609 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1610 } else
1611 time_buf.LastAccessTime = 0;
1612
1613 if (attrs->ia_valid & ATTR_MTIME) {
Steve French4b18f2a2008-04-29 00:06:05 +00001614 set_time = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 time_buf.LastWriteTime =
1616 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1617 } else
1618 time_buf.LastWriteTime = 0;
Steve Frenche30dcf32005-09-20 20:49:16 -07001619 /* Do not set ctime explicitly unless other time
1620 stamps are changed explicitly (i.e. by utime()
1621 since we would then have a mix of client and
1622 server times */
Steve French50c2f752007-07-13 00:33:32 +00001623
Steve Frenche30dcf32005-09-20 20:49:16 -07001624 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001625 set_time = true;
Steve Frenche30dcf32005-09-20 20:49:16 -07001626 /* Although Samba throws this field away
1627 it may be useful to Windows - but we do
1628 not want to set ctime unless some other
1629 timestamp is changing */
Steve French26a21b92006-05-31 18:05:34 +00001630 cFYI(1, ("CIFS - CTIME changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 time_buf.ChangeTime =
1632 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1633 } else
1634 time_buf.ChangeTime = 0;
1635
Steve French066fcb02007-03-23 00:45:08 +00001636 if (set_time || set_dosattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 time_buf.CreationTime = 0; /* do not change */
1638 /* In the future we should experiment - try setting timestamps
1639 via Handle (SetFileInfo) instead of by path */
1640 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1641 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
Steve French737b7582005-04-28 22:41:06 -07001642 cifs_sb->local_nls,
1643 cifs_sb->mnt_cifs_flags &
1644 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 else
1646 rc = -EOPNOTSUPP;
1647
1648 if (rc == -EOPNOTSUPP) {
Steve French4b18f2a2008-04-29 00:06:05 +00001649 int oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 __u16 netfid;
1651
1652 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1653 "times not supported by this server"));
1654 /* BB we could scan to see if we already have it open
1655 and pass in pid of opener to function */
1656 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1657 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1658 CREATE_NOT_DIR, &netfid, &oplock,
Steve French737b7582005-04-28 22:41:06 -07001659 NULL, cifs_sb->local_nls,
1660 cifs_sb->mnt_cifs_flags &
1661 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001662 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1664 netfid);
1665 CIFSSMBClose(xid, pTcon, netfid);
1666 } else {
1667 /* BB For even older servers we could convert time_buf
1668 into old DOS style which uses two second
1669 granularity */
1670
1671 /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001672 &time_buf, cifs_sb->local_nls); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 }
1674 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001675 /* Even if error on time set, no sense failing the call if
1676 the server would set the time to a reasonable value anyway,
1677 and this check ensures that we are not being called from
1678 sys_utimes in which case we ought to fail the call back to
1679 the user when the server rejects the call */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001680 if ((rc) && (attrs->ia_valid &
Steve Frenche30dcf32005-09-20 20:49:16 -07001681 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
1682 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 }
1684
1685 /* do not need local check to inode_check_ok since the server does
1686 that */
1687 if (!rc)
Jeff Layton02eadef2008-05-09 21:26:11 +00001688 rc = inode_setattr(inode, attrs);
Steve Frenche30dcf32005-09-20 20:49:16 -07001689cifs_setattr_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 kfree(full_path);
1691 FreeXid(xid);
1692 return rc;
1693}
1694
Steve French99ee4db2007-02-27 05:35:17 +00001695#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696void cifs_delete_inode(struct inode *inode)
1697{
Steve French26a21b92006-05-31 18:05:34 +00001698 cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 /* may have to add back in if and when safe distributed caching of
1700 directories added e.g. via FindNotify */
1701}
Steve French99ee4db2007-02-27 05:35:17 +00001702#endif