blob: 628aa1a9fe64396e89f6c968fd043404d54c7133 [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;
169 inode->i_data.a_ops = &cifs_addr_ops;
170 } else if (S_ISDIR(inode->i_mode)) {
171 cFYI(1, (" Directory inode"));
172 inode->i_op = &cifs_dir_inode_ops;
173 inode->i_fop = &cifs_dir_ops;
174 } else if (S_ISLNK(inode->i_mode)) {
175 cFYI(1, (" Symbolic Link inode "));
176 inode->i_op = &cifs_symlink_inode_ops;
177 /* tmp_inode->i_fop = */ /* do not need to set to anything */
178 } else {
179 cFYI(1, (" Init special inode "));
180 init_special_inode(inode, inode->i_mode,
181 inode->i_rdev);
182 }
183 }
184 return rc;
185}
186
187int cifs_get_inode_info(struct inode **pinode,
188 const unsigned char *search_path, FILE_ALL_INFO *pfindData,
189 struct super_block *sb, int xid)
190{
191 int rc = 0;
192 struct cifsTconInfo *pTcon;
193 struct inode *inode;
194 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
195 char *tmp_path;
196 char *buf = NULL;
197
198 pTcon = cifs_sb->tcon;
199 cFYI(1,("Getting info on %s ", search_path));
200
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700201 if ((pfindData == NULL) && (*pinode != NULL)) {
202 if (CIFS_I(*pinode)->clientCanCacheRead) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 cFYI(1,("No need to revalidate cached inode sizes"));
204 return rc;
205 }
206 }
207
208 /* if file info not passed in then get it from server */
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700209 if (pfindData == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700211 if (buf == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 return -ENOMEM;
213 pfindData = (FILE_ALL_INFO *)buf;
214 /* could do find first instead but this returns more info */
215 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
Steve French737b7582005-04-28 22:41:06 -0700216 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
217 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 }
219 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
220 if (rc) {
221 if (rc == -EREMOTE) {
222 tmp_path =
223 kmalloc(strnlen
224 (pTcon->treeName,
225 MAX_TREE_SIZE + 1) +
226 strnlen(search_path, MAX_PATHCONF) + 1,
227 GFP_KERNEL);
228 if (tmp_path == NULL) {
229 kfree(buf);
230 return -ENOMEM;
231 }
232
233 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
234 strncat(tmp_path, search_path, MAX_PATHCONF);
235 rc = connect_to_dfs_path(xid, pTcon->ses,
236 /* treename + */ tmp_path,
Steve French737b7582005-04-28 22:41:06 -0700237 cifs_sb->local_nls,
238 cifs_sb->mnt_cifs_flags &
239 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 kfree(tmp_path);
241 /* BB fix up inode etc. */
242 } else if (rc) {
243 kfree(buf);
244 return rc;
245 }
246 } else {
247 struct cifsInodeInfo *cifsInfo;
248 __u32 attr = le32_to_cpu(pfindData->Attributes);
249
250 /* get new inode */
251 if (*pinode == NULL) {
252 *pinode = new_inode(sb);
253 if (*pinode == NULL)
254 return -ENOMEM;
255 /* Is an i_ino of zero legal? Can we use that to check
256 if the server supports returning inode numbers? Are
257 there other sanity checks we can use to ensure that
258 the server is really filling in that field? */
259
260 /* We can not use the IndexNumber field by default from
261 Windows or Samba (in ALL_INFO buf) but we can request
262 it explicitly. It may not be unique presumably if
263 the server has multiple devices mounted under one
264 share */
265
266 /* There may be higher info levels that work but are
267 there Windows server or network appliances for which
268 IndexNumber field is not guaranteed unique? */
269
270#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700271 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 int rc1 = 0;
273 __u64 inode_num;
274
275 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
276 search_path, &inode_num,
Steve French737b7582005-04-28 22:41:06 -0700277 cifs_sb->local_nls,
278 cifs_sb->mnt_cifs_flags &
279 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700280 if (rc1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 cFYI(1,("GetSrvInodeNum rc %d", rc1));
282 /* BB EOPNOSUPP disable SERVER_INUM? */
283 } else /* do we need cast or hash to ino? */
284 (*pinode)->i_ino = inode_num;
285 } /* else ino incremented to unique num in new_inode*/
286#endif /* CIFS_EXPERIMENTAL */
287 insert_inode_hash(*pinode);
288 }
289 inode = *pinode;
290 cifsInfo = CIFS_I(inode);
291 cifsInfo->cifsAttrs = attr;
292 cFYI(1, (" Old time %ld ", cifsInfo->time));
293 cifsInfo->time = jiffies;
294 cFYI(1, (" New time %ld ", cifsInfo->time));
295
296 /* blksize needs to be multiple of two. So safer to default to
297 blksize and blkbits set in superblock so 2**blkbits and blksize
298 will match rather than setting to:
299 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
300
301 /* Linux can not store file creation time unfortunately so we ignore it */
302 inode->i_atime =
303 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
304 inode->i_mtime =
305 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
306 inode->i_ctime =
307 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
308 cFYI(0, (" Attributes came in as 0x%x ", attr));
309
310 /* set default mode. will override for dirs below */
311 if (atomic_read(&cifsInfo->inUse) == 0)
312 /* new inode, can safely set these fields */
313 inode->i_mode = cifs_sb->mnt_file_mode;
314
315/* if (attr & ATTR_REPARSE) */
316 /* We no longer handle these as symlinks because we could not
317 follow them due to the absolute path with drive letter */
318 if (attr & ATTR_DIRECTORY) {
319 /* override default perms since we do not do byte range locking
320 on dirs */
321 inode->i_mode = cifs_sb->mnt_dir_mode;
322 inode->i_mode |= S_IFDIR;
Steve Frencheda3c0292005-07-21 15:20:28 -0700323 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
324 (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
325 /* No need to le64 convert size of zero */
326 (pfindData->EndOfFile == 0)) {
327 inode->i_mode = cifs_sb->mnt_file_mode;
328 inode->i_mode |= S_IFIFO;
329/* BB Finish for SFU style symlinks and devies */
330/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
331 (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 } else {
334 inode->i_mode |= S_IFREG;
335 /* treat the dos attribute of read-only as read-only
336 mode e.g. 555 */
337 if (cifsInfo->cifsAttrs & ATTR_READONLY)
338 inode->i_mode &= ~(S_IWUGO);
339 /* BB add code here -
340 validate if device or weird share or device type? */
341 }
342 if (is_size_safe_to_change(cifsInfo)) {
343 /* can not safely change the file size here if the
344 client is writing to it due to potential races */
345 i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
346
347 /* 512 bytes (2**9) is the fake blocksize that must be
348 used for this calculation */
349 inode->i_blocks = (512 - 1 + le64_to_cpu(
350 pfindData->AllocationSize)) >> 9;
351 }
352
353 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
354
355 /* BB fill in uid and gid here? with help from winbind?
356 or retrieve from NTFS stream extended attribute */
357 if (atomic_read(&cifsInfo->inUse) == 0) {
358 inode->i_uid = cifs_sb->mnt_uid;
359 inode->i_gid = cifs_sb->mnt_gid;
360 /* set so we do not keep refreshing these fields with
361 bad data after user has changed them in memory */
362 atomic_set(&cifsInfo->inUse,1);
363 }
364
365 if (S_ISREG(inode->i_mode)) {
366 cFYI(1, (" File inode "));
367 inode->i_op = &cifs_file_inode_ops;
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700368 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 inode->i_fop = &cifs_file_direct_ops;
370 else
371 inode->i_fop = &cifs_file_ops;
372 inode->i_data.a_ops = &cifs_addr_ops;
373 } else if (S_ISDIR(inode->i_mode)) {
374 cFYI(1, (" Directory inode "));
375 inode->i_op = &cifs_dir_inode_ops;
376 inode->i_fop = &cifs_dir_ops;
377 } else if (S_ISLNK(inode->i_mode)) {
378 cFYI(1, (" Symbolic Link inode "));
379 inode->i_op = &cifs_symlink_inode_ops;
380 } else {
381 init_special_inode(inode, inode->i_mode,
382 inode->i_rdev);
383 }
384 }
385 kfree(buf);
386 return rc;
387}
388
389/* gets root inode */
390void cifs_read_inode(struct inode *inode)
391{
392 int xid;
393 struct cifs_sb_info *cifs_sb;
394
395 cifs_sb = CIFS_SB(inode->i_sb);
396 xid = GetXid();
397 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
398 cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
399 else
400 cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
401 /* can not call macro FreeXid here since in a void func */
402 _FreeXid(xid);
403}
404
405int cifs_unlink(struct inode *inode, struct dentry *direntry)
406{
407 int rc = 0;
408 int xid;
409 struct cifs_sb_info *cifs_sb;
410 struct cifsTconInfo *pTcon;
411 char *full_path = NULL;
412 struct cifsInodeInfo *cifsInode;
413 FILE_BASIC_INFO *pinfo_buf;
414
415 cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
416
417 xid = GetXid();
418
419 cifs_sb = CIFS_SB(inode->i_sb);
420 pTcon = cifs_sb->tcon;
421
422 /* Unlink can be called from rename so we can not grab the sem here
423 since we deadlock otherwise */
424/* down(&direntry->d_sb->s_vfs_rename_sem);*/
Jeremy Allisonac670552005-06-22 17:26:35 -0700425 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426/* up(&direntry->d_sb->s_vfs_rename_sem);*/
427 if (full_path == NULL) {
428 FreeXid(xid);
429 return -ENOMEM;
430 }
Steve French737b7582005-04-28 22:41:06 -0700431 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
432 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
434 if (!rc) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700435 if (direntry->d_inode)
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500436 direntry->d_inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 } else if (rc == -ENOENT) {
438 d_drop(direntry);
439 } else if (rc == -ETXTBSY) {
440 int oplock = FALSE;
441 __u16 netfid;
442
443 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
444 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
Steve French737b7582005-04-28 22:41:06 -0700445 &netfid, &oplock, NULL, cifs_sb->local_nls,
446 cifs_sb->mnt_cifs_flags &
447 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (rc==0) {
449 CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
Steve French737b7582005-04-28 22:41:06 -0700450 cifs_sb->local_nls,
451 cifs_sb->mnt_cifs_flags &
452 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700454 if (direntry->d_inode)
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500455 direntry->d_inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
457 } else if (rc == -EACCES) {
458 /* try only if r/o attribute set in local lookup data? */
459 pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
460 if (pinfo_buf) {
461 memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
462 /* ATTRS set to normal clears r/o bit */
463 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
464 if (!(pTcon->ses->flags & CIFS_SES_NT4))
465 rc = CIFSSMBSetTimes(xid, pTcon, full_path,
466 pinfo_buf,
Steve French737b7582005-04-28 22:41:06 -0700467 cifs_sb->local_nls,
468 cifs_sb->mnt_cifs_flags &
469 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 else
471 rc = -EOPNOTSUPP;
472
473 if (rc == -EOPNOTSUPP) {
474 int oplock = FALSE;
475 __u16 netfid;
476 /* rc = CIFSSMBSetAttrLegacy(xid, pTcon,
477 full_path,
478 (__u16)ATTR_NORMAL,
479 cifs_sb->local_nls);
480 For some strange reason it seems that NT4 eats the
481 old setattr call without actually setting the
482 attributes so on to the third attempted workaround
483 */
484
485 /* BB could scan to see if we already have it open
486 and pass in pid of opener to function */
487 rc = CIFSSMBOpen(xid, pTcon, full_path,
488 FILE_OPEN, SYNCHRONIZE |
489 FILE_WRITE_ATTRIBUTES, 0,
490 &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700491 cifs_sb->local_nls,
492 cifs_sb->mnt_cifs_flags &
493 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (rc==0) {
495 rc = CIFSSMBSetFileTimes(xid, pTcon,
496 pinfo_buf,
497 netfid);
498 CIFSSMBClose(xid, pTcon, netfid);
499 }
500 }
501 kfree(pinfo_buf);
502 }
503 if (rc==0) {
Steve French737b7582005-04-28 22:41:06 -0700504 rc = CIFSSMBDelFile(xid, pTcon, full_path,
505 cifs_sb->local_nls,
506 cifs_sb->mnt_cifs_flags &
507 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 if (!rc) {
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700509 if (direntry->d_inode)
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500510 direntry->d_inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 } else if (rc == -ETXTBSY) {
512 int oplock = FALSE;
513 __u16 netfid;
514
515 rc = CIFSSMBOpen(xid, pTcon, full_path,
516 FILE_OPEN, DELETE,
517 CREATE_NOT_DIR |
518 CREATE_DELETE_ON_CLOSE,
519 &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700520 cifs_sb->local_nls,
521 cifs_sb->mnt_cifs_flags &
522 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (rc==0) {
524 CIFSSMBRenameOpenFile(xid, pTcon,
525 netfid, NULL,
Steve French737b7582005-04-28 22:41:06 -0700526 cifs_sb->local_nls,
527 cifs_sb->mnt_cifs_flags &
528 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 CIFSSMBClose(xid, pTcon, netfid);
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700530 if (direntry->d_inode)
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500531 direntry->d_inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 }
533 /* BB if rc = -ETXTBUSY goto the rename logic BB */
534 }
535 }
536 }
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700537 if (direntry->d_inode) {
Steve Frenchb2aeb9d2005-05-17 13:16:18 -0500538 cifsInode = CIFS_I(direntry->d_inode);
539 cifsInode->time = 0; /* will force revalidate to get info
540 when needed */
541 direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
542 }
543 inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 cifsInode = CIFS_I(inode);
545 cifsInode->time = 0; /* force revalidate of dir as well */
546
547 kfree(full_path);
548 FreeXid(xid);
549 return rc;
550}
551
552int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
553{
554 int rc = 0;
555 int xid;
556 struct cifs_sb_info *cifs_sb;
557 struct cifsTconInfo *pTcon;
558 char *full_path = NULL;
559 struct inode *newinode = NULL;
560
561 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
562
563 xid = GetXid();
564
565 cifs_sb = CIFS_SB(inode->i_sb);
566 pTcon = cifs_sb->tcon;
567
568 down(&inode->i_sb->s_vfs_rename_sem);
Jeremy Allisonac670552005-06-22 17:26:35 -0700569 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 up(&inode->i_sb->s_vfs_rename_sem);
571 if (full_path == NULL) {
572 FreeXid(xid);
573 return -ENOMEM;
574 }
575 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Steve French737b7582005-04-28 22:41:06 -0700576 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
577 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 if (rc) {
579 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
580 d_drop(direntry);
581 } else {
582 inode->i_nlink++;
583 if (pTcon->ses->capabilities & CAP_UNIX)
584 rc = cifs_get_inode_info_unix(&newinode, full_path,
585 inode->i_sb,xid);
586 else
587 rc = cifs_get_inode_info(&newinode, full_path, NULL,
588 inode->i_sb,xid);
589
590 direntry->d_op = &cifs_dentry_ops;
591 d_instantiate(direntry, newinode);
592 if (direntry->d_inode)
593 direntry->d_inode->i_nlink = 2;
594 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
Steve Frenchd0d2f2d2005-06-02 15:12:36 -0700595 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
597 mode,
598 (__u64)current->euid,
599 (__u64)current->egid,
600 0 /* dev_t */,
Steve French737b7582005-04-28 22:41:06 -0700601 cifs_sb->local_nls,
602 cifs_sb->mnt_cifs_flags &
603 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 } else {
605 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
606 mode, (__u64)-1,
607 (__u64)-1, 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 }
612 else {
613 /* BB to be implemented via Windows secrty descriptors
614 eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
615 -1, -1, local_nls); */
616 }
617 }
618 kfree(full_path);
619 FreeXid(xid);
620 return rc;
621}
622
623int cifs_rmdir(struct inode *inode, struct dentry *direntry)
624{
625 int rc = 0;
626 int xid;
627 struct cifs_sb_info *cifs_sb;
628 struct cifsTconInfo *pTcon;
629 char *full_path = NULL;
630 struct cifsInodeInfo *cifsInode;
631
632 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
633
634 xid = GetXid();
635
636 cifs_sb = CIFS_SB(inode->i_sb);
637 pTcon = cifs_sb->tcon;
638
639 down(&inode->i_sb->s_vfs_rename_sem);
Jeremy Allisonac670552005-06-22 17:26:35 -0700640 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 up(&inode->i_sb->s_vfs_rename_sem);
642 if (full_path == NULL) {
643 FreeXid(xid);
644 return -ENOMEM;
645 }
646
Steve French737b7582005-04-28 22:41:06 -0700647 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
648 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 if (!rc) {
651 inode->i_nlink--;
652 i_size_write(direntry->d_inode,0);
653 direntry->d_inode->i_nlink = 0;
654 }
655
656 cifsInode = CIFS_I(direntry->d_inode);
657 cifsInode->time = 0; /* force revalidate to go get info when
658 needed */
659 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
660 current_fs_time(inode->i_sb);
661
662 kfree(full_path);
663 FreeXid(xid);
664 return rc;
665}
666
667int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
668 struct inode *target_inode, struct dentry *target_direntry)
669{
670 char *fromName;
671 char *toName;
672 struct cifs_sb_info *cifs_sb_source;
673 struct cifs_sb_info *cifs_sb_target;
674 struct cifsTconInfo *pTcon;
675 int xid;
676 int rc = 0;
677
678 xid = GetXid();
679
680 cifs_sb_target = CIFS_SB(target_inode->i_sb);
681 cifs_sb_source = CIFS_SB(source_inode->i_sb);
682 pTcon = cifs_sb_source->tcon;
683
684 if (pTcon != cifs_sb_target->tcon) {
685 FreeXid(xid);
686 return -EXDEV; /* BB actually could be allowed if same server,
687 but different share.
688 Might eventually add support for this */
689 }
690
691 /* we already have the rename sem so we do not need to grab it again
692 here to protect the path integrity */
Jeremy Allisonac670552005-06-22 17:26:35 -0700693 fromName = build_path_from_dentry(source_direntry, cifs_sb_source);
694 toName = build_path_from_dentry(target_direntry, cifs_sb_target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if ((fromName == NULL) || (toName == NULL)) {
696 rc = -ENOMEM;
697 goto cifs_rename_exit;
698 }
699
700 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
Steve French737b7582005-04-28 22:41:06 -0700701 cifs_sb_source->local_nls,
702 cifs_sb_source->mnt_cifs_flags &
703 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (rc == -EEXIST) {
705 /* check if they are the same file because rename of hardlinked
706 files is a noop */
707 FILE_UNIX_BASIC_INFO *info_buf_source;
708 FILE_UNIX_BASIC_INFO *info_buf_target;
709
710 info_buf_source =
711 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
712 if (info_buf_source != NULL) {
713 info_buf_target = info_buf_source + 1;
714 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
Steve French737b7582005-04-28 22:41:06 -0700715 info_buf_source, cifs_sb_source->local_nls,
716 cifs_sb_source->mnt_cifs_flags &
717 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 if (rc == 0) {
719 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
720 info_buf_target,
Steve French737b7582005-04-28 22:41:06 -0700721 cifs_sb_target->local_nls,
722 /* remap based on source sb */
723 cifs_sb_source->mnt_cifs_flags &
724 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
726 if ((rc == 0) &&
727 (info_buf_source->UniqueId ==
728 info_buf_target->UniqueId)) {
729 /* do not rename since the files are hardlinked which
730 is a noop */
731 } else {
732 /* we either can not tell the files are hardlinked
733 (as with Windows servers) or files are not
734 hardlinked so delete the target manually before
735 renaming to follow POSIX rather than Windows
736 semantics */
737 cifs_unlink(target_inode, target_direntry);
738 rc = CIFSSMBRename(xid, pTcon, fromName,
739 toName,
Steve French737b7582005-04-28 22:41:06 -0700740 cifs_sb_source->local_nls,
741 cifs_sb_source->mnt_cifs_flags
742 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 }
744 kfree(info_buf_source);
745 } /* if we can not get memory just leave rc as EEXIST */
746 }
747
748 if (rc) {
749 cFYI(1, ("rename rc %d", rc));
750 }
751
752 if ((rc == -EIO) || (rc == -EEXIST)) {
753 int oplock = FALSE;
754 __u16 netfid;
755
756 /* BB FIXME Is Generic Read correct for rename? */
757 /* if renaming directory - we should not say CREATE_NOT_DIR,
758 need to test renaming open directory, also GENERIC_READ
759 might not right be right access to request */
760 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
761 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700762 cifs_sb_source->local_nls,
763 cifs_sb_source->mnt_cifs_flags &
764 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (rc==0) {
766 CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
Steve French737b7582005-04-28 22:41:06 -0700767 cifs_sb_source->local_nls,
768 cifs_sb_source->mnt_cifs_flags &
769 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 CIFSSMBClose(xid, pTcon, netfid);
771 }
772 }
773
774cifs_rename_exit:
775 kfree(fromName);
776 kfree(toName);
777 FreeXid(xid);
778 return rc;
779}
780
781int cifs_revalidate(struct dentry *direntry)
782{
783 int xid;
784 int rc = 0;
785 char *full_path;
786 struct cifs_sb_info *cifs_sb;
787 struct cifsInodeInfo *cifsInode;
788 loff_t local_size;
789 struct timespec local_mtime;
790 int invalidate_inode = FALSE;
791
792 if (direntry->d_inode == NULL)
793 return -ENOENT;
794
795 cifsInode = CIFS_I(direntry->d_inode);
796
797 if (cifsInode == NULL)
798 return -ENOENT;
799
800 /* no sense revalidating inode info on file that no one can write */
801 if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
802 return rc;
803
804 xid = GetXid();
805
806 cifs_sb = CIFS_SB(direntry->d_sb);
807
808 /* can not safely grab the rename sem here if rename calls revalidate
809 since that would deadlock */
Jeremy Allisonac670552005-06-22 17:26:35 -0700810 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (full_path == NULL) {
812 FreeXid(xid);
813 return -ENOMEM;
814 }
815 cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
816 "jiffies %ld", full_path, direntry->d_inode,
817 direntry->d_inode->i_count.counter, direntry,
818 direntry->d_time, jiffies));
819
820 if (cifsInode->time == 0) {
821 /* was set to zero previously to force revalidate */
822 } else if (time_before(jiffies, cifsInode->time + HZ) &&
823 lookupCacheEnabled) {
824 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
825 (direntry->d_inode->i_nlink == 1)) {
826 kfree(full_path);
827 FreeXid(xid);
828 return rc;
829 } else {
830 cFYI(1, ("Have to revalidate file due to hardlinks"));
831 }
832 }
833
834 /* save mtime and size */
835 local_mtime = direntry->d_inode->i_mtime;
836 local_size = direntry->d_inode->i_size;
837
838 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
839 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
840 direntry->d_sb,xid);
841 if (rc) {
842 cFYI(1, ("error on getting revalidate info %d", rc));
843/* if (rc != -ENOENT)
844 rc = 0; */ /* BB should we cache info on
845 certain errors? */
846 }
847 } else {
848 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
849 direntry->d_sb,xid);
850 if (rc) {
851 cFYI(1, ("error on getting revalidate info %d", rc));
852/* if (rc != -ENOENT)
853 rc = 0; */ /* BB should we cache info on
854 certain errors? */
855 }
856 }
857 /* should we remap certain errors, access denied?, to zero */
858
859 /* if not oplocked, we invalidate inode pages if mtime or file size
860 had changed on server */
861
862 if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
863 (local_size == direntry->d_inode->i_size)) {
864 cFYI(1, ("cifs_revalidate - inode unchanged"));
865 } else {
866 /* file may have changed on server */
867 if (cifsInode->clientCanCacheRead) {
868 /* no need to invalidate inode pages since we were the
869 only ones who could have modified the file and the
870 server copy is staler than ours */
871 } else {
872 invalidate_inode = TRUE;
873 }
874 }
875
876 /* can not grab this sem since kernel filesys locking documentation
877 indicates i_sem may be taken by the kernel on lookup and rename
878 which could deadlock if we grab the i_sem here as well */
879/* down(&direntry->d_inode->i_sem);*/
880 /* need to write out dirty pages here */
881 if (direntry->d_inode->i_mapping) {
882 /* do we need to lock inode until after invalidate completes
883 below? */
884 filemap_fdatawrite(direntry->d_inode->i_mapping);
885 }
886 if (invalidate_inode) {
887 if (direntry->d_inode->i_mapping)
888 filemap_fdatawait(direntry->d_inode->i_mapping);
889 /* may eventually have to do this for open files too */
890 if (list_empty(&(cifsInode->openFileList))) {
891 /* Has changed on server - flush read ahead pages */
892 cFYI(1, ("Invalidating read ahead data on "
893 "closed file"));
894 invalidate_remote_inode(direntry->d_inode);
895 }
896 }
897/* up(&direntry->d_inode->i_sem); */
898
899 kfree(full_path);
900 FreeXid(xid);
901 return rc;
902}
903
904int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
905 struct kstat *stat)
906{
907 int err = cifs_revalidate(dentry);
908 if (!err)
909 generic_fillattr(dentry->d_inode, stat);
910 return err;
911}
912
913static int cifs_truncate_page(struct address_space *mapping, loff_t from)
914{
915 pgoff_t index = from >> PAGE_CACHE_SHIFT;
916 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
917 struct page *page;
918 char *kaddr;
919 int rc = 0;
920
921 page = grab_cache_page(mapping, index);
922 if (!page)
923 return -ENOMEM;
924
925 kaddr = kmap_atomic(page, KM_USER0);
926 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
927 flush_dcache_page(page);
928 kunmap_atomic(kaddr, KM_USER0);
929 unlock_page(page);
930 page_cache_release(page);
931 return rc;
932}
933
934int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
935{
936 int xid;
937 struct cifs_sb_info *cifs_sb;
938 struct cifsTconInfo *pTcon;
939 char *full_path = NULL;
940 int rc = -EACCES;
941 int found = FALSE;
942 struct cifsFileInfo *open_file = NULL;
943 FILE_BASIC_INFO time_buf;
944 int set_time = FALSE;
945 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
946 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
947 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
948 struct cifsInodeInfo *cifsInode;
949 struct list_head *tmp;
950
951 xid = GetXid();
952
953 cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
954 direntry->d_name.name, attrs->ia_valid));
955 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
956 pTcon = cifs_sb->tcon;
957
958 down(&direntry->d_sb->s_vfs_rename_sem);
Jeremy Allisonac670552005-06-22 17:26:35 -0700959 full_path = build_path_from_dentry(direntry, cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 up(&direntry->d_sb->s_vfs_rename_sem);
961 if (full_path == NULL) {
962 FreeXid(xid);
963 return -ENOMEM;
964 }
965 cifsInode = CIFS_I(direntry->d_inode);
966
967 /* BB check if we need to refresh inode from server now ? BB */
968
969 /* need to flush data before changing file size on server */
970 filemap_fdatawrite(direntry->d_inode->i_mapping);
971 filemap_fdatawait(direntry->d_inode->i_mapping);
972
973 if (attrs->ia_valid & ATTR_SIZE) {
974 read_lock(&GlobalSMBSeslock);
975 /* To avoid spurious oplock breaks from server, in the case of
976 inodes that we already have open, avoid doing path based
977 setting of file size if we can do it by handle.
978 This keeps our caching token (oplock) and avoids timeouts
979 when the local oplock break takes longer to flush
980 writebehind data than the SMB timeout for the SetPathInfo
981 request would allow */
982 list_for_each(tmp, &cifsInode->openFileList) {
983 open_file = list_entry(tmp, struct cifsFileInfo,
984 flist);
985 /* We check if file is open for writing first */
986 if ((open_file->pfile) &&
987 ((open_file->pfile->f_flags & O_RDWR) ||
988 (open_file->pfile->f_flags & O_WRONLY))) {
989 if (open_file->invalidHandle == FALSE) {
990 /* we found a valid, writeable network
991 file handle to use to try to set the
992 file size */
993 __u16 nfid = open_file->netfid;
994 __u32 npid = open_file->pid;
995 read_unlock(&GlobalSMBSeslock);
996 found = TRUE;
997 rc = CIFSSMBSetFileSize(xid, pTcon,
998 attrs->ia_size, nfid, npid,
999 FALSE);
1000 cFYI(1, ("SetFileSize by handle "
1001 "(setattrs) rc = %d", rc));
1002 /* Do not need reopen and retry on
1003 EAGAIN since we will retry by
1004 pathname below */
1005
1006 /* now that we found one valid file
1007 handle no sense continuing to loop
1008 trying others, so break here */
1009 break;
1010 }
1011 }
1012 }
1013 if (found == FALSE)
1014 read_unlock(&GlobalSMBSeslock);
1015
1016 if (rc != 0) {
1017 /* Set file size by pathname rather than by handle
1018 either because no valid, writeable file handle for
1019 it was found or because there was an error setting
1020 it by handle */
1021 rc = CIFSSMBSetEOF(xid, pTcon, full_path,
1022 attrs->ia_size, FALSE,
Steve French737b7582005-04-28 22:41:06 -07001023 cifs_sb->local_nls,
1024 cifs_sb->mnt_cifs_flags &
1025 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
1027 }
1028
1029 /* Server is ok setting allocation size implicitly - no need
1030 to call:
1031 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
1032 cifs_sb->local_nls);
1033 */
1034
1035 if (rc == 0) {
1036 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
1037 cifs_truncate_page(direntry->d_inode->i_mapping,
1038 direntry->d_inode->i_size);
1039 }
1040 }
1041 if (attrs->ia_valid & ATTR_UID) {
1042 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
1043 uid = attrs->ia_uid;
1044 /* entry->uid = cpu_to_le16(attr->ia_uid); */
1045 }
1046 if (attrs->ia_valid & ATTR_GID) {
1047 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
1048 gid = attrs->ia_gid;
1049 /* entry->gid = cpu_to_le16(attr->ia_gid); */
1050 }
1051
1052 time_buf.Attributes = 0;
1053 if (attrs->ia_valid & ATTR_MODE) {
1054 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
1055 mode = attrs->ia_mode;
1056 /* entry->mode = cpu_to_le16(attr->ia_mode); */
1057 }
1058
1059 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
1060 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1061 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
Steve French737b7582005-04-28 22:41:06 -07001062 0 /* dev_t */, cifs_sb->local_nls,
1063 cifs_sb->mnt_cifs_flags &
1064 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 else if (attrs->ia_valid & ATTR_MODE) {
1066 if ((mode & S_IWUGO) == 0) /* not writeable */ {
1067 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
1068 time_buf.Attributes =
1069 cpu_to_le32(cifsInode->cifsAttrs |
1070 ATTR_READONLY);
1071 } else if ((mode & S_IWUGO) == S_IWUGO) {
1072 if (cifsInode->cifsAttrs & ATTR_READONLY)
1073 time_buf.Attributes =
1074 cpu_to_le32(cifsInode->cifsAttrs &
1075 (~ATTR_READONLY));
1076 }
1077 /* BB to be implemented -
1078 via Windows security descriptors or streams */
1079 /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
1080 cifs_sb->local_nls); */
1081 }
1082
1083 if (attrs->ia_valid & ATTR_ATIME) {
1084 set_time = TRUE;
1085 time_buf.LastAccessTime =
1086 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1087 } else
1088 time_buf.LastAccessTime = 0;
1089
1090 if (attrs->ia_valid & ATTR_MTIME) {
1091 set_time = TRUE;
1092 time_buf.LastWriteTime =
1093 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1094 } else
1095 time_buf.LastWriteTime = 0;
1096
1097 if (attrs->ia_valid & ATTR_CTIME) {
1098 set_time = TRUE;
1099 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
1100 time_buf.ChangeTime =
1101 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1102 } else
1103 time_buf.ChangeTime = 0;
1104
1105 if (set_time || time_buf.Attributes) {
1106 /* BB what if setting one attribute fails (such as size) but
1107 time setting works? */
1108 time_buf.CreationTime = 0; /* do not change */
1109 /* In the future we should experiment - try setting timestamps
1110 via Handle (SetFileInfo) instead of by path */
1111 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1112 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
Steve French737b7582005-04-28 22:41:06 -07001113 cifs_sb->local_nls,
1114 cifs_sb->mnt_cifs_flags &
1115 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 else
1117 rc = -EOPNOTSUPP;
1118
1119 if (rc == -EOPNOTSUPP) {
1120 int oplock = FALSE;
1121 __u16 netfid;
1122
1123 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1124 "times not supported by this server"));
1125 /* BB we could scan to see if we already have it open
1126 and pass in pid of opener to function */
1127 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1128 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1129 CREATE_NOT_DIR, &netfid, &oplock,
Steve French737b7582005-04-28 22:41:06 -07001130 NULL, cifs_sb->local_nls,
1131 cifs_sb->mnt_cifs_flags &
1132 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (rc==0) {
1134 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1135 netfid);
1136 CIFSSMBClose(xid, pTcon, netfid);
1137 } else {
1138 /* BB For even older servers we could convert time_buf
1139 into old DOS style which uses two second
1140 granularity */
1141
1142 /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1143 &time_buf, cifs_sb->local_nls); */
1144 }
1145 }
1146 }
1147
1148 /* do not need local check to inode_check_ok since the server does
1149 that */
1150 if (!rc)
1151 rc = inode_setattr(direntry->d_inode, attrs);
1152 kfree(full_path);
1153 FreeXid(xid);
1154 return rc;
1155}
1156
1157void cifs_delete_inode(struct inode *inode)
1158{
1159 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
1160 /* may have to add back in if and when safe distributed caching of
1161 directories added e.g. via FindNotify */
1162}