blob: 2d50b3507d13d20c85f57c70ecbb412d52b8600f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/inode.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002,2005
5 * 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>
22#include <linux/buffer_head.h>
23#include <linux/stat.h>
24#include <linux/pagemap.h>
25#include <asm/div64.h>
26#include "cifsfs.h"
27#include "cifspdu.h"
28#include "cifsglob.h"
29#include "cifsproto.h"
30#include "cifs_debug.h"
31#include "cifs_fs_sb.h"
32
33int cifs_get_inode_info_unix(struct inode **pinode,
34 const unsigned char *search_path, struct super_block *sb, int xid)
35{
36 int rc = 0;
37 FILE_UNIX_BASIC_INFO findData;
38 struct cifsTconInfo *pTcon;
39 struct inode *inode;
40 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
41 char *tmp_path;
42
43 pTcon = cifs_sb->tcon;
44 cFYI(1, (" Getting info on %s ", search_path));
45 /* could have done a find first instead but this returns more info */
46 rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
Steve French737b7582005-04-28 22:41:06 -070047 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
48 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049/* dump_mem("\nUnixQPathInfo return data", &findData,
50 sizeof(findData)); */
51 if (rc) {
52 if (rc == -EREMOTE) {
53 tmp_path =
54 kmalloc(strnlen(pTcon->treeName,
55 MAX_TREE_SIZE + 1) +
56 strnlen(search_path, MAX_PATHCONF) + 1,
57 GFP_KERNEL);
58 if (tmp_path == NULL) {
59 return -ENOMEM;
60 }
61 /* have to skip first of the double backslash of
62 UNC name */
63 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
64 strncat(tmp_path, search_path, MAX_PATHCONF);
65 rc = connect_to_dfs_path(xid, pTcon->ses,
66 /* treename + */ tmp_path,
Steve French737b7582005-04-28 22:41:06 -070067 cifs_sb->local_nls,
68 cifs_sb->mnt_cifs_flags &
69 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 kfree(tmp_path);
71
72 /* BB fix up inode etc. */
73 } else if (rc) {
74 return rc;
75 }
76 } else {
77 struct cifsInodeInfo *cifsInfo;
78 __u32 type = le32_to_cpu(findData.Type);
79 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
80 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
81
82 /* get new inode */
83 if (*pinode == NULL) {
84 *pinode = new_inode(sb);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -070085 if (*pinode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 return -ENOMEM;
87 /* Is an i_ino of zero legal? */
88 /* Are there sanity checks we can use to ensure that
89 the server is really filling in that field? */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -070090 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 (*pinode)->i_ino =
92 (unsigned long)findData.UniqueId;
93 } /* note ino incremented to unique num in new_inode */
94 insert_inode_hash(*pinode);
95 }
96
97 inode = *pinode;
98 cifsInfo = CIFS_I(inode);
99
100 cFYI(1, (" Old time %ld ", cifsInfo->time));
101 cifsInfo->time = jiffies;
102 cFYI(1, (" New time %ld ", cifsInfo->time));
103 /* this is ok to set on every inode revalidate */
104 atomic_set(&cifsInfo->inUse,1);
105
106 inode->i_atime =
107 cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
108 inode->i_mtime =
109 cifs_NTtimeToUnix(le64_to_cpu
110 (findData.LastModificationTime));
111 inode->i_ctime =
112 cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
113 inode->i_mode = le64_to_cpu(findData.Permissions);
114 if (type == UNIX_FILE) {
115 inode->i_mode |= S_IFREG;
116 } else if (type == UNIX_SYMLINK) {
117 inode->i_mode |= S_IFLNK;
118 } else if (type == UNIX_DIR) {
119 inode->i_mode |= S_IFDIR;
120 } else if (type == UNIX_CHARDEV) {
121 inode->i_mode |= S_IFCHR;
122 inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
123 le64_to_cpu(findData.DevMinor) & MINORMASK);
124 } else if (type == UNIX_BLOCKDEV) {
125 inode->i_mode |= S_IFBLK;
126 inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
127 le64_to_cpu(findData.DevMinor) & MINORMASK);
128 } else if (type == UNIX_FIFO) {
129 inode->i_mode |= S_IFIFO;
130 } else if (type == UNIX_SOCKET) {
131 inode->i_mode |= S_IFSOCK;
132 }
133 inode->i_uid = le64_to_cpu(findData.Uid);
134 inode->i_gid = le64_to_cpu(findData.Gid);
135 inode->i_nlink = le64_to_cpu(findData.Nlinks);
136
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700137 if (is_size_safe_to_change(cifsInfo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 /* can not safely change the file size here if the
139 client is writing to it due to potential races */
140
141 i_size_write(inode, end_of_file);
142
143 /* blksize needs to be multiple of two. So safer to default to
144 blksize and blkbits set in superblock so 2**blkbits and blksize
145 will match rather than setting to:
146 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
147
148 /* This seems incredibly stupid but it turns out that i_blocks
149 is not related to (i_size / i_blksize), instead 512 byte size
150 is required for calculating num blocks */
151
152 /* 512 bytes (2**9) is the fake blocksize that must be used */
153 /* for this calculation */
154 inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
155 }
156
157 if (num_of_bytes < end_of_file)
158 cFYI(1, ("allocation size less than end of file "));
159 cFYI(1,
160 ("Size %ld and blocks %ld",
161 (unsigned long) inode->i_size, inode->i_blocks));
162 if (S_ISREG(inode->i_mode)) {
163 cFYI(1, (" File inode "));
164 inode->i_op = &cifs_file_inode_ops;
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700165 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 inode->i_fop = &cifs_file_direct_ops;
167 else
168 inode->i_fop = &cifs_file_ops;
Steve Frenchc46fa8a2005-08-18 20:49:57 -0700169 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
170 inode->i_fop->lock = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 inode->i_data.a_ops = &cifs_addr_ops;
172 } else if (S_ISDIR(inode->i_mode)) {
173 cFYI(1, (" Directory inode"));
174 inode->i_op = &cifs_dir_inode_ops;
175 inode->i_fop = &cifs_dir_ops;
176 } else if (S_ISLNK(inode->i_mode)) {
177 cFYI(1, (" Symbolic Link inode "));
178 inode->i_op = &cifs_symlink_inode_ops;
179 /* tmp_inode->i_fop = */ /* do not need to set to anything */
180 } else {
181 cFYI(1, (" Init special inode "));
182 init_special_inode(inode, inode->i_mode,
183 inode->i_rdev);
184 }
185 }
186 return rc;
187}
188
189int cifs_get_inode_info(struct inode **pinode,
190 const unsigned char *search_path, FILE_ALL_INFO *pfindData,
191 struct super_block *sb, int xid)
192{
193 int rc = 0;
194 struct cifsTconInfo *pTcon;
195 struct inode *inode;
196 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
197 char *tmp_path;
198 char *buf = NULL;
199
200 pTcon = cifs_sb->tcon;
201 cFYI(1,("Getting info on %s ", search_path));
202
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700203 if ((pfindData == NULL) && (*pinode != NULL)) {
204 if (CIFS_I(*pinode)->clientCanCacheRead) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 cFYI(1,("No need to revalidate cached inode sizes"));
206 return rc;
207 }
208 }
209
210 /* if file info not passed in then get it from server */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700211 if (pfindData == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700213 if (buf == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 return -ENOMEM;
215 pfindData = (FILE_ALL_INFO *)buf;
216 /* could do find first instead but this returns more info */
217 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
Steve French737b7582005-04-28 22:41:06 -0700218 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
219 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 }
221 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
222 if (rc) {
223 if (rc == -EREMOTE) {
224 tmp_path =
225 kmalloc(strnlen
226 (pTcon->treeName,
227 MAX_TREE_SIZE + 1) +
228 strnlen(search_path, MAX_PATHCONF) + 1,
229 GFP_KERNEL);
230 if (tmp_path == NULL) {
231 kfree(buf);
232 return -ENOMEM;
233 }
234
235 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
236 strncat(tmp_path, search_path, MAX_PATHCONF);
237 rc = connect_to_dfs_path(xid, pTcon->ses,
238 /* treename + */ tmp_path,
Steve French737b7582005-04-28 22:41:06 -0700239 cifs_sb->local_nls,
240 cifs_sb->mnt_cifs_flags &
241 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 kfree(tmp_path);
243 /* BB fix up inode etc. */
244 } else if (rc) {
245 kfree(buf);
246 return rc;
247 }
248 } else {
249 struct cifsInodeInfo *cifsInfo;
250 __u32 attr = le32_to_cpu(pfindData->Attributes);
251
252 /* get new inode */
253 if (*pinode == NULL) {
254 *pinode = new_inode(sb);
255 if (*pinode == NULL)
256 return -ENOMEM;
257 /* Is an i_ino of zero legal? Can we use that to check
258 if the server supports returning inode numbers? Are
259 there other sanity checks we can use to ensure that
260 the server is really filling in that field? */
261
262 /* We can not use the IndexNumber field by default from
263 Windows or Samba (in ALL_INFO buf) but we can request
264 it explicitly. It may not be unique presumably if
265 the server has multiple devices mounted under one
266 share */
267
268 /* There may be higher info levels that work but are
269 there Windows server or network appliances for which
270 IndexNumber field is not guaranteed unique? */
271
272#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700273 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 int rc1 = 0;
275 __u64 inode_num;
276
277 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
278 search_path, &inode_num,
Steve French737b7582005-04-28 22:41:06 -0700279 cifs_sb->local_nls,
280 cifs_sb->mnt_cifs_flags &
281 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700282 if (rc1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 cFYI(1,("GetSrvInodeNum rc %d", rc1));
284 /* BB EOPNOSUPP disable SERVER_INUM? */
285 } else /* do we need cast or hash to ino? */
286 (*pinode)->i_ino = inode_num;
287 } /* else ino incremented to unique num in new_inode*/
288#endif /* CIFS_EXPERIMENTAL */
289 insert_inode_hash(*pinode);
290 }
291 inode = *pinode;
292 cifsInfo = CIFS_I(inode);
293 cifsInfo->cifsAttrs = attr;
294 cFYI(1, (" Old time %ld ", cifsInfo->time));
295 cifsInfo->time = jiffies;
296 cFYI(1, (" New time %ld ", cifsInfo->time));
297
298 /* blksize needs to be multiple of two. So safer to default to
299 blksize and blkbits set in superblock so 2**blkbits and blksize
300 will match rather than setting to:
301 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
302
303 /* Linux can not store file creation time unfortunately so we ignore it */
304 inode->i_atime =
305 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
306 inode->i_mtime =
307 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
308 inode->i_ctime =
309 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
310 cFYI(0, (" Attributes came in as 0x%x ", attr));
311
312 /* set default mode. will override for dirs below */
313 if (atomic_read(&cifsInfo->inUse) == 0)
314 /* new inode, can safely set these fields */
315 inode->i_mode = cifs_sb->mnt_file_mode;
316
317/* if (attr & ATTR_REPARSE) */
318 /* We no longer handle these as symlinks because we could not
319 follow them due to the absolute path with drive letter */
320 if (attr & ATTR_DIRECTORY) {
321 /* override default perms since we do not do byte range locking
322 on dirs */
323 inode->i_mode = cifs_sb->mnt_dir_mode;
324 inode->i_mode |= S_IFDIR;
Steve Frencheda3c0292005-07-21 15:20:28 -0700325 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
326 (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
327 /* No need to le64 convert size of zero */
328 (pfindData->EndOfFile == 0)) {
329 inode->i_mode = cifs_sb->mnt_file_mode;
330 inode->i_mode |= S_IFIFO;
331/* BB Finish for SFU style symlinks and devies */
332/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
333 (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */
334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 } else {
336 inode->i_mode |= S_IFREG;
337 /* treat the dos attribute of read-only as read-only
338 mode e.g. 555 */
339 if (cifsInfo->cifsAttrs & ATTR_READONLY)
340 inode->i_mode &= ~(S_IWUGO);
341 /* BB add code here -
342 validate if device or weird share or device type? */
343 }
344 if (is_size_safe_to_change(cifsInfo)) {
345 /* can not safely change the file size here if the
346 client is writing to it due to potential races */
347 i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
348
349 /* 512 bytes (2**9) is the fake blocksize that must be
350 used for this calculation */
351 inode->i_blocks = (512 - 1 + le64_to_cpu(
352 pfindData->AllocationSize)) >> 9;
353 }
354
355 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
356
357 /* BB fill in uid and gid here? with help from winbind?
358 or retrieve from NTFS stream extended attribute */
359 if (atomic_read(&cifsInfo->inUse) == 0) {
360 inode->i_uid = cifs_sb->mnt_uid;
361 inode->i_gid = cifs_sb->mnt_gid;
362 /* set so we do not keep refreshing these fields with
363 bad data after user has changed them in memory */
364 atomic_set(&cifsInfo->inUse,1);
365 }
366
367 if (S_ISREG(inode->i_mode)) {
368 cFYI(1, (" File inode "));
369 inode->i_op = &cifs_file_inode_ops;
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700370 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 inode->i_fop = &cifs_file_direct_ops;
372 else
373 inode->i_fop = &cifs_file_ops;
Steve Frenchc46fa8a2005-08-18 20:49:57 -0700374 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
375 inode->i_fop->lock = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 inode->i_data.a_ops = &cifs_addr_ops;
377 } else if (S_ISDIR(inode->i_mode)) {
378 cFYI(1, (" Directory inode "));
379 inode->i_op = &cifs_dir_inode_ops;
380 inode->i_fop = &cifs_dir_ops;
381 } else if (S_ISLNK(inode->i_mode)) {
382 cFYI(1, (" Symbolic Link inode "));
383 inode->i_op = &cifs_symlink_inode_ops;
384 } else {
385 init_special_inode(inode, inode->i_mode,
386 inode->i_rdev);
387 }
388 }
389 kfree(buf);
390 return rc;
391}
392
393/* gets root inode */
394void cifs_read_inode(struct inode *inode)
395{
396 int xid;
397 struct cifs_sb_info *cifs_sb;
398
399 cifs_sb = CIFS_SB(inode->i_sb);
400 xid = GetXid();
401 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
402 cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
403 else
404 cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
405 /* can not call macro FreeXid here since in a void func */
406 _FreeXid(xid);
407}
408
409int cifs_unlink(struct inode *inode, struct dentry *direntry)
410{
411 int rc = 0;
412 int xid;
413 struct cifs_sb_info *cifs_sb;
414 struct cifsTconInfo *pTcon;
415 char *full_path = NULL;
416 struct cifsInodeInfo *cifsInode;
417 FILE_BASIC_INFO *pinfo_buf;
418
419 cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
420
421 xid = GetXid();
422
423 cifs_sb = CIFS_SB(inode->i_sb);
424 pTcon = cifs_sb->tcon;
425
426 /* Unlink can be called from rename so we can not grab the sem here
427 since we deadlock otherwise */
428/* down(&direntry->d_sb->s_vfs_rename_sem);*/
Jeremy Allisonac670552005-06-22 17:26:35 -0700429 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430/* up(&direntry->d_sb->s_vfs_rename_sem);*/
431 if (full_path == NULL) {
432 FreeXid(xid);
433 return -ENOMEM;
434 }
Steve French737b7582005-04-28 22:41:06 -0700435 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
436 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 if (!rc) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700439 if (direntry->d_inode)
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500440 direntry->d_inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 } else if (rc == -ENOENT) {
442 d_drop(direntry);
443 } else if (rc == -ETXTBSY) {
444 int oplock = FALSE;
445 __u16 netfid;
446
447 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
448 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
Steve French737b7582005-04-28 22:41:06 -0700449 &netfid, &oplock, NULL, cifs_sb->local_nls,
450 cifs_sb->mnt_cifs_flags &
451 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (rc==0) {
453 CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
Steve French737b7582005-04-28 22:41:06 -0700454 cifs_sb->local_nls,
455 cifs_sb->mnt_cifs_flags &
456 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700458 if (direntry->d_inode)
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500459 direntry->d_inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 }
461 } else if (rc == -EACCES) {
462 /* try only if r/o attribute set in local lookup data? */
463 pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
464 if (pinfo_buf) {
465 memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
466 /* ATTRS set to normal clears r/o bit */
467 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
468 if (!(pTcon->ses->flags & CIFS_SES_NT4))
469 rc = CIFSSMBSetTimes(xid, pTcon, full_path,
470 pinfo_buf,
Steve French737b7582005-04-28 22:41:06 -0700471 cifs_sb->local_nls,
472 cifs_sb->mnt_cifs_flags &
473 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 else
475 rc = -EOPNOTSUPP;
476
477 if (rc == -EOPNOTSUPP) {
478 int oplock = FALSE;
479 __u16 netfid;
480 /* rc = CIFSSMBSetAttrLegacy(xid, pTcon,
481 full_path,
482 (__u16)ATTR_NORMAL,
483 cifs_sb->local_nls);
484 For some strange reason it seems that NT4 eats the
485 old setattr call without actually setting the
486 attributes so on to the third attempted workaround
487 */
488
489 /* BB could scan to see if we already have it open
490 and pass in pid of opener to function */
491 rc = CIFSSMBOpen(xid, pTcon, full_path,
492 FILE_OPEN, SYNCHRONIZE |
493 FILE_WRITE_ATTRIBUTES, 0,
494 &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700495 cifs_sb->local_nls,
496 cifs_sb->mnt_cifs_flags &
497 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 if (rc==0) {
499 rc = CIFSSMBSetFileTimes(xid, pTcon,
500 pinfo_buf,
501 netfid);
502 CIFSSMBClose(xid, pTcon, netfid);
503 }
504 }
505 kfree(pinfo_buf);
506 }
507 if (rc==0) {
Steve French737b7582005-04-28 22:41:06 -0700508 rc = CIFSSMBDelFile(xid, pTcon, full_path,
509 cifs_sb->local_nls,
510 cifs_sb->mnt_cifs_flags &
511 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (!rc) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700513 if (direntry->d_inode)
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500514 direntry->d_inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 } else if (rc == -ETXTBSY) {
516 int oplock = FALSE;
517 __u16 netfid;
518
519 rc = CIFSSMBOpen(xid, pTcon, full_path,
520 FILE_OPEN, DELETE,
521 CREATE_NOT_DIR |
522 CREATE_DELETE_ON_CLOSE,
523 &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700524 cifs_sb->local_nls,
525 cifs_sb->mnt_cifs_flags &
526 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 if (rc==0) {
528 CIFSSMBRenameOpenFile(xid, pTcon,
529 netfid, NULL,
Steve French737b7582005-04-28 22:41:06 -0700530 cifs_sb->local_nls,
531 cifs_sb->mnt_cifs_flags &
532 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700534 if (direntry->d_inode)
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500535 direntry->d_inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
537 /* BB if rc = -ETXTBUSY goto the rename logic BB */
538 }
539 }
540 }
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700541 if (direntry->d_inode) {
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500542 cifsInode = CIFS_I(direntry->d_inode);
543 cifsInode->time = 0; /* will force revalidate to get info
544 when needed */
545 direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
546 }
547 inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 cifsInode = CIFS_I(inode);
549 cifsInode->time = 0; /* force revalidate of dir as well */
550
551 kfree(full_path);
552 FreeXid(xid);
553 return rc;
554}
555
556int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
557{
558 int rc = 0;
559 int xid;
560 struct cifs_sb_info *cifs_sb;
561 struct cifsTconInfo *pTcon;
562 char *full_path = NULL;
563 struct inode *newinode = NULL;
564
565 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
566
567 xid = GetXid();
568
569 cifs_sb = CIFS_SB(inode->i_sb);
570 pTcon = cifs_sb->tcon;
571
572 down(&inode->i_sb->s_vfs_rename_sem);
Jeremy Allisonac670552005-06-22 17:26:35 -0700573 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 up(&inode->i_sb->s_vfs_rename_sem);
575 if (full_path == NULL) {
576 FreeXid(xid);
577 return -ENOMEM;
578 }
579 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -0700580 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
581 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 if (rc) {
583 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
584 d_drop(direntry);
585 } else {
586 inode->i_nlink++;
587 if (pTcon->ses->capabilities & CAP_UNIX)
588 rc = cifs_get_inode_info_unix(&newinode, full_path,
589 inode->i_sb,xid);
590 else
591 rc = cifs_get_inode_info(&newinode, full_path, NULL,
592 inode->i_sb,xid);
593
Steve Frenchb92327f2005-08-22 20:09:43 -0700594 if (pTcon->nocase)
595 direntry->d_op = &cifs_ci_dentry_ops;
596 else
597 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 d_instantiate(direntry, newinode);
599 if (direntry->d_inode)
600 direntry->d_inode->i_nlink = 2;
601 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700602 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
604 mode,
605 (__u64)current->euid,
606 (__u64)current->egid,
607 0 /* dev_t */,
Steve French737b7582005-04-28 22:41:06 -0700608 cifs_sb->local_nls,
609 cifs_sb->mnt_cifs_flags &
610 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 } else {
612 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
613 mode, (__u64)-1,
614 (__u64)-1, 0 /* dev_t */,
Steve French737b7582005-04-28 22:41:06 -0700615 cifs_sb->local_nls,
616 cifs_sb->mnt_cifs_flags &
617 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 }
619 else {
620 /* BB to be implemented via Windows secrty descriptors
621 eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
622 -1, -1, local_nls); */
623 }
624 }
625 kfree(full_path);
626 FreeXid(xid);
627 return rc;
628}
629
630int cifs_rmdir(struct inode *inode, struct dentry *direntry)
631{
632 int rc = 0;
633 int xid;
634 struct cifs_sb_info *cifs_sb;
635 struct cifsTconInfo *pTcon;
636 char *full_path = NULL;
637 struct cifsInodeInfo *cifsInode;
638
639 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
640
641 xid = GetXid();
642
643 cifs_sb = CIFS_SB(inode->i_sb);
644 pTcon = cifs_sb->tcon;
645
646 down(&inode->i_sb->s_vfs_rename_sem);
Jeremy Allisonac670552005-06-22 17:26:35 -0700647 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 up(&inode->i_sb->s_vfs_rename_sem);
649 if (full_path == NULL) {
650 FreeXid(xid);
651 return -ENOMEM;
652 }
653
Steve French737b7582005-04-28 22:41:06 -0700654 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
655 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 if (!rc) {
658 inode->i_nlink--;
659 i_size_write(direntry->d_inode,0);
660 direntry->d_inode->i_nlink = 0;
661 }
662
663 cifsInode = CIFS_I(direntry->d_inode);
664 cifsInode->time = 0; /* force revalidate to go get info when
665 needed */
666 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
667 current_fs_time(inode->i_sb);
668
669 kfree(full_path);
670 FreeXid(xid);
671 return rc;
672}
673
674int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
675 struct inode *target_inode, struct dentry *target_direntry)
676{
677 char *fromName;
678 char *toName;
679 struct cifs_sb_info *cifs_sb_source;
680 struct cifs_sb_info *cifs_sb_target;
681 struct cifsTconInfo *pTcon;
682 int xid;
683 int rc = 0;
684
685 xid = GetXid();
686
687 cifs_sb_target = CIFS_SB(target_inode->i_sb);
688 cifs_sb_source = CIFS_SB(source_inode->i_sb);
689 pTcon = cifs_sb_source->tcon;
690
691 if (pTcon != cifs_sb_target->tcon) {
692 FreeXid(xid);
693 return -EXDEV; /* BB actually could be allowed if same server,
694 but different share.
695 Might eventually add support for this */
696 }
697
698 /* we already have the rename sem so we do not need to grab it again
699 here to protect the path integrity */
Jeremy Allisonac670552005-06-22 17:26:35 -0700700 fromName = build_path_from_dentry(source_direntry, cifs_sb_source);
701 toName = build_path_from_dentry(target_direntry, cifs_sb_target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 if ((fromName == NULL) || (toName == NULL)) {
703 rc = -ENOMEM;
704 goto cifs_rename_exit;
705 }
706
707 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
Steve French737b7582005-04-28 22:41:06 -0700708 cifs_sb_source->local_nls,
709 cifs_sb_source->mnt_cifs_flags &
710 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 if (rc == -EEXIST) {
712 /* check if they are the same file because rename of hardlinked
713 files is a noop */
714 FILE_UNIX_BASIC_INFO *info_buf_source;
715 FILE_UNIX_BASIC_INFO *info_buf_target;
716
717 info_buf_source =
718 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
719 if (info_buf_source != NULL) {
720 info_buf_target = info_buf_source + 1;
721 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
Steve French737b7582005-04-28 22:41:06 -0700722 info_buf_source, cifs_sb_source->local_nls,
723 cifs_sb_source->mnt_cifs_flags &
724 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 if (rc == 0) {
726 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
727 info_buf_target,
Steve French737b7582005-04-28 22:41:06 -0700728 cifs_sb_target->local_nls,
729 /* remap based on source sb */
730 cifs_sb_source->mnt_cifs_flags &
731 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 }
733 if ((rc == 0) &&
734 (info_buf_source->UniqueId ==
735 info_buf_target->UniqueId)) {
736 /* do not rename since the files are hardlinked which
737 is a noop */
738 } else {
739 /* we either can not tell the files are hardlinked
740 (as with Windows servers) or files are not
741 hardlinked so delete the target manually before
742 renaming to follow POSIX rather than Windows
743 semantics */
744 cifs_unlink(target_inode, target_direntry);
745 rc = CIFSSMBRename(xid, pTcon, fromName,
746 toName,
Steve French737b7582005-04-28 22:41:06 -0700747 cifs_sb_source->local_nls,
748 cifs_sb_source->mnt_cifs_flags
749 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
751 kfree(info_buf_source);
752 } /* if we can not get memory just leave rc as EEXIST */
753 }
754
755 if (rc) {
756 cFYI(1, ("rename rc %d", rc));
757 }
758
759 if ((rc == -EIO) || (rc == -EEXIST)) {
760 int oplock = FALSE;
761 __u16 netfid;
762
763 /* BB FIXME Is Generic Read correct for rename? */
764 /* if renaming directory - we should not say CREATE_NOT_DIR,
765 need to test renaming open directory, also GENERIC_READ
766 might not right be right access to request */
767 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
768 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700769 cifs_sb_source->local_nls,
770 cifs_sb_source->mnt_cifs_flags &
771 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 if (rc==0) {
773 CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
Steve French737b7582005-04-28 22:41:06 -0700774 cifs_sb_source->local_nls,
775 cifs_sb_source->mnt_cifs_flags &
776 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 CIFSSMBClose(xid, pTcon, netfid);
778 }
779 }
780
781cifs_rename_exit:
782 kfree(fromName);
783 kfree(toName);
784 FreeXid(xid);
785 return rc;
786}
787
788int cifs_revalidate(struct dentry *direntry)
789{
790 int xid;
791 int rc = 0;
792 char *full_path;
793 struct cifs_sb_info *cifs_sb;
794 struct cifsInodeInfo *cifsInode;
795 loff_t local_size;
796 struct timespec local_mtime;
797 int invalidate_inode = FALSE;
798
799 if (direntry->d_inode == NULL)
800 return -ENOENT;
801
802 cifsInode = CIFS_I(direntry->d_inode);
803
804 if (cifsInode == NULL)
805 return -ENOENT;
806
807 /* no sense revalidating inode info on file that no one can write */
808 if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
809 return rc;
810
811 xid = GetXid();
812
813 cifs_sb = CIFS_SB(direntry->d_sb);
814
815 /* can not safely grab the rename sem here if rename calls revalidate
816 since that would deadlock */
Jeremy Allisonac670552005-06-22 17:26:35 -0700817 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 if (full_path == NULL) {
819 FreeXid(xid);
820 return -ENOMEM;
821 }
822 cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
823 "jiffies %ld", full_path, direntry->d_inode,
824 direntry->d_inode->i_count.counter, direntry,
825 direntry->d_time, jiffies));
826
827 if (cifsInode->time == 0) {
828 /* was set to zero previously to force revalidate */
829 } else if (time_before(jiffies, cifsInode->time + HZ) &&
830 lookupCacheEnabled) {
831 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
832 (direntry->d_inode->i_nlink == 1)) {
833 kfree(full_path);
834 FreeXid(xid);
835 return rc;
836 } else {
837 cFYI(1, ("Have to revalidate file due to hardlinks"));
838 }
839 }
840
841 /* save mtime and size */
842 local_mtime = direntry->d_inode->i_mtime;
843 local_size = direntry->d_inode->i_size;
844
845 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
846 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
847 direntry->d_sb,xid);
848 if (rc) {
849 cFYI(1, ("error on getting revalidate info %d", rc));
850/* if (rc != -ENOENT)
851 rc = 0; */ /* BB should we cache info on
852 certain errors? */
853 }
854 } else {
855 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
856 direntry->d_sb,xid);
857 if (rc) {
858 cFYI(1, ("error on getting revalidate info %d", rc));
859/* if (rc != -ENOENT)
860 rc = 0; */ /* BB should we cache info on
861 certain errors? */
862 }
863 }
864 /* should we remap certain errors, access denied?, to zero */
865
866 /* if not oplocked, we invalidate inode pages if mtime or file size
867 had changed on server */
868
869 if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
870 (local_size == direntry->d_inode->i_size)) {
871 cFYI(1, ("cifs_revalidate - inode unchanged"));
872 } else {
873 /* file may have changed on server */
874 if (cifsInode->clientCanCacheRead) {
875 /* no need to invalidate inode pages since we were the
876 only ones who could have modified the file and the
877 server copy is staler than ours */
878 } else {
879 invalidate_inode = TRUE;
880 }
881 }
882
883 /* can not grab this sem since kernel filesys locking documentation
884 indicates i_sem may be taken by the kernel on lookup and rename
885 which could deadlock if we grab the i_sem here as well */
886/* down(&direntry->d_inode->i_sem);*/
887 /* need to write out dirty pages here */
888 if (direntry->d_inode->i_mapping) {
889 /* do we need to lock inode until after invalidate completes
890 below? */
891 filemap_fdatawrite(direntry->d_inode->i_mapping);
892 }
893 if (invalidate_inode) {
894 if (direntry->d_inode->i_mapping)
895 filemap_fdatawait(direntry->d_inode->i_mapping);
896 /* may eventually have to do this for open files too */
897 if (list_empty(&(cifsInode->openFileList))) {
898 /* Has changed on server - flush read ahead pages */
899 cFYI(1, ("Invalidating read ahead data on "
900 "closed file"));
901 invalidate_remote_inode(direntry->d_inode);
902 }
903 }
904/* up(&direntry->d_inode->i_sem); */
905
906 kfree(full_path);
907 FreeXid(xid);
908 return rc;
909}
910
911int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
912 struct kstat *stat)
913{
914 int err = cifs_revalidate(dentry);
915 if (!err)
916 generic_fillattr(dentry->d_inode, stat);
917 return err;
918}
919
920static int cifs_truncate_page(struct address_space *mapping, loff_t from)
921{
922 pgoff_t index = from >> PAGE_CACHE_SHIFT;
923 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
924 struct page *page;
925 char *kaddr;
926 int rc = 0;
927
928 page = grab_cache_page(mapping, index);
929 if (!page)
930 return -ENOMEM;
931
932 kaddr = kmap_atomic(page, KM_USER0);
933 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
934 flush_dcache_page(page);
935 kunmap_atomic(kaddr, KM_USER0);
936 unlock_page(page);
937 page_cache_release(page);
938 return rc;
939}
940
941int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
942{
943 int xid;
944 struct cifs_sb_info *cifs_sb;
945 struct cifsTconInfo *pTcon;
946 char *full_path = NULL;
947 int rc = -EACCES;
948 int found = FALSE;
949 struct cifsFileInfo *open_file = NULL;
950 FILE_BASIC_INFO time_buf;
951 int set_time = FALSE;
952 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
953 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
954 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
955 struct cifsInodeInfo *cifsInode;
956 struct list_head *tmp;
957
958 xid = GetXid();
959
960 cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
961 direntry->d_name.name, attrs->ia_valid));
962 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
963 pTcon = cifs_sb->tcon;
964
965 down(&direntry->d_sb->s_vfs_rename_sem);
Jeremy Allisonac670552005-06-22 17:26:35 -0700966 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 up(&direntry->d_sb->s_vfs_rename_sem);
968 if (full_path == NULL) {
969 FreeXid(xid);
970 return -ENOMEM;
971 }
972 cifsInode = CIFS_I(direntry->d_inode);
973
974 /* BB check if we need to refresh inode from server now ? BB */
975
976 /* need to flush data before changing file size on server */
977 filemap_fdatawrite(direntry->d_inode->i_mapping);
978 filemap_fdatawait(direntry->d_inode->i_mapping);
979
980 if (attrs->ia_valid & ATTR_SIZE) {
981 read_lock(&GlobalSMBSeslock);
982 /* To avoid spurious oplock breaks from server, in the case of
983 inodes that we already have open, avoid doing path based
984 setting of file size if we can do it by handle.
985 This keeps our caching token (oplock) and avoids timeouts
986 when the local oplock break takes longer to flush
987 writebehind data than the SMB timeout for the SetPathInfo
988 request would allow */
989 list_for_each(tmp, &cifsInode->openFileList) {
990 open_file = list_entry(tmp, struct cifsFileInfo,
991 flist);
992 /* We check if file is open for writing first */
993 if ((open_file->pfile) &&
994 ((open_file->pfile->f_flags & O_RDWR) ||
995 (open_file->pfile->f_flags & O_WRONLY))) {
996 if (open_file->invalidHandle == FALSE) {
997 /* we found a valid, writeable network
998 file handle to use to try to set the
999 file size */
1000 __u16 nfid = open_file->netfid;
1001 __u32 npid = open_file->pid;
1002 read_unlock(&GlobalSMBSeslock);
1003 found = TRUE;
1004 rc = CIFSSMBSetFileSize(xid, pTcon,
1005 attrs->ia_size, nfid, npid,
1006 FALSE);
1007 cFYI(1, ("SetFileSize by handle "
1008 "(setattrs) rc = %d", rc));
1009 /* Do not need reopen and retry on
1010 EAGAIN since we will retry by
1011 pathname below */
1012
1013 /* now that we found one valid file
1014 handle no sense continuing to loop
1015 trying others, so break here */
1016 break;
1017 }
1018 }
1019 }
1020 if (found == FALSE)
1021 read_unlock(&GlobalSMBSeslock);
1022
1023 if (rc != 0) {
1024 /* Set file size by pathname rather than by handle
1025 either because no valid, writeable file handle for
1026 it was found or because there was an error setting
1027 it by handle */
1028 rc = CIFSSMBSetEOF(xid, pTcon, full_path,
1029 attrs->ia_size, FALSE,
Steve French737b7582005-04-28 22:41:06 -07001030 cifs_sb->local_nls,
1031 cifs_sb->mnt_cifs_flags &
1032 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
1034 }
1035
1036 /* Server is ok setting allocation size implicitly - no need
1037 to call:
1038 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
1039 cifs_sb->local_nls);
1040 */
1041
1042 if (rc == 0) {
1043 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
1044 cifs_truncate_page(direntry->d_inode->i_mapping,
1045 direntry->d_inode->i_size);
1046 }
1047 }
1048 if (attrs->ia_valid & ATTR_UID) {
1049 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
1050 uid = attrs->ia_uid;
1051 /* entry->uid = cpu_to_le16(attr->ia_uid); */
1052 }
1053 if (attrs->ia_valid & ATTR_GID) {
1054 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
1055 gid = attrs->ia_gid;
1056 /* entry->gid = cpu_to_le16(attr->ia_gid); */
1057 }
1058
1059 time_buf.Attributes = 0;
1060 if (attrs->ia_valid & ATTR_MODE) {
1061 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
1062 mode = attrs->ia_mode;
1063 /* entry->mode = cpu_to_le16(attr->ia_mode); */
1064 }
1065
1066 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
1067 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1068 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
Steve French737b7582005-04-28 22:41:06 -07001069 0 /* dev_t */, cifs_sb->local_nls,
1070 cifs_sb->mnt_cifs_flags &
1071 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 else if (attrs->ia_valid & ATTR_MODE) {
1073 if ((mode & S_IWUGO) == 0) /* not writeable */ {
1074 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
1075 time_buf.Attributes =
1076 cpu_to_le32(cifsInode->cifsAttrs |
1077 ATTR_READONLY);
1078 } else if ((mode & S_IWUGO) == S_IWUGO) {
1079 if (cifsInode->cifsAttrs & ATTR_READONLY)
1080 time_buf.Attributes =
1081 cpu_to_le32(cifsInode->cifsAttrs &
1082 (~ATTR_READONLY));
1083 }
1084 /* BB to be implemented -
1085 via Windows security descriptors or streams */
1086 /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
1087 cifs_sb->local_nls); */
1088 }
1089
1090 if (attrs->ia_valid & ATTR_ATIME) {
1091 set_time = TRUE;
1092 time_buf.LastAccessTime =
1093 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1094 } else
1095 time_buf.LastAccessTime = 0;
1096
1097 if (attrs->ia_valid & ATTR_MTIME) {
1098 set_time = TRUE;
1099 time_buf.LastWriteTime =
1100 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1101 } else
1102 time_buf.LastWriteTime = 0;
1103
1104 if (attrs->ia_valid & ATTR_CTIME) {
1105 set_time = TRUE;
1106 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
1107 time_buf.ChangeTime =
1108 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1109 } else
1110 time_buf.ChangeTime = 0;
1111
1112 if (set_time || time_buf.Attributes) {
1113 /* BB what if setting one attribute fails (such as size) but
1114 time setting works? */
1115 time_buf.CreationTime = 0; /* do not change */
1116 /* In the future we should experiment - try setting timestamps
1117 via Handle (SetFileInfo) instead of by path */
1118 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1119 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
Steve French737b7582005-04-28 22:41:06 -07001120 cifs_sb->local_nls,
1121 cifs_sb->mnt_cifs_flags &
1122 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 else
1124 rc = -EOPNOTSUPP;
1125
1126 if (rc == -EOPNOTSUPP) {
1127 int oplock = FALSE;
1128 __u16 netfid;
1129
1130 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1131 "times not supported by this server"));
1132 /* BB we could scan to see if we already have it open
1133 and pass in pid of opener to function */
1134 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1135 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1136 CREATE_NOT_DIR, &netfid, &oplock,
Steve French737b7582005-04-28 22:41:06 -07001137 NULL, cifs_sb->local_nls,
1138 cifs_sb->mnt_cifs_flags &
1139 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 if (rc==0) {
1141 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1142 netfid);
1143 CIFSSMBClose(xid, pTcon, netfid);
1144 } else {
1145 /* BB For even older servers we could convert time_buf
1146 into old DOS style which uses two second
1147 granularity */
1148
1149 /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1150 &time_buf, cifs_sb->local_nls); */
1151 }
1152 }
1153 }
1154
1155 /* do not need local check to inode_check_ok since the server does
1156 that */
1157 if (!rc)
1158 rc = inode_setattr(direntry->d_inode, attrs);
1159 kfree(full_path);
1160 FreeXid(xid);
1161 return rc;
1162}
1163
1164void cifs_delete_inode(struct inode *inode)
1165{
1166 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
1167 /* may have to add back in if and when safe distributed caching of
1168 directories added e.g. via FindNotify */
1169}