1 /*
2 * fs/cifs/inode.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002,2003
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
33 extern int is_size_safe_to_change(struct cifsInodeInfo *);
34
35 int
36 cifs_get_inode_info_unix(struct inode **pinode,
37 const unsigned char *search_path,
38 struct super_block *sb,int xid)
39 {
40 int rc = 0;
41 FILE_UNIX_BASIC_INFO findData;
42 struct cifsTconInfo *pTcon;
43 struct inode *inode;
44 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
45 char *tmp_path;
46
47 pTcon = cifs_sb->tcon;
48 cFYI(1, (" Getting info on %s ", search_path));
49 /* we could have done a find first instead but this returns more info */
50 rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
51 cifs_sb->local_nls);
52 /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
53 if (rc) {
54 if (rc == -EREMOTE) {
55 tmp_path =
56 kmalloc(strnlen
57 (pTcon->treeName,
58 MAX_TREE_SIZE + 1) +
59 strnlen(search_path, MAX_PATHCONF) + 1,
60 GFP_KERNEL);
61 if (tmp_path == NULL) {
62 return -ENOMEM;
63 }
64 /* have to skip first of the double backslash of UNC name */
65 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
66 strncat(tmp_path, search_path, MAX_PATHCONF);
67 rc = connect_to_dfs_path(xid, pTcon->ses,
68 /* treename + */ tmp_path,
69 cifs_sb->local_nls);
70 kfree(tmp_path);
71
72 /* BB fix up inode etc. */
73 } else if (rc) {
74 return rc;
75 }
76
77 } else {
78 struct cifsInodeInfo *cifsInfo;
79 __u32 type = le32_to_cpu(findData.Type);
80 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
81 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
82
83 /* get new inode */
84 if (*pinode == NULL) {
85 *pinode = new_inode(sb);
86 if(*pinode == NULL)
87 return -ENOMEM;
88 /* Is an i_ino of zero legal? */
89 /* Are there sanity checks we can use to ensure that
90 the server is really filling in that field? */
91 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
92 (*pinode)->i_ino =
93 (unsigned long)findData.UniqueId;
94 } /* note ino incremented to unique num in new_inode */
95 insert_inode_hash(*pinode);
96 }
97
98 inode = *pinode;
99 cifsInfo = CIFS_I(inode);
100
101 cFYI(1, (" Old time %ld ", cifsInfo->time));
102 cifsInfo->time = jiffies;
103 cFYI(1, (" New time %ld ", cifsInfo->time));
104 atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */
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
137 if(is_size_safe_to_change(cifsInfo)) {
138 /* 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 /* blksize needs to be multiple of two. So safer to default to blksize
143 and blkbits set in superblock so 2**blkbits and blksize will match */
144 /* inode->i_blksize =
145 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
146
147 /* This seems incredibly stupid but it turns out that
148 i_blocks is not related to (i_size / i_blksize), instead a
149 size of 512 is required to be used for calculating num blocks */
150
151
152 /* inode->i_blocks =
153 (inode->i_blksize - 1 + num_of_bytes) >> inode->i_blkbits;*/
154
155 /* 512 bytes (2**9) is the fake blocksize that must be used */
156 /* for this calculation */
157 inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
158 }
159
160 if (num_of_bytes < end_of_file)
161 cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
162 cFYI(1,
163 ("Size %ld and blocks %ld ",
164 (unsigned long) inode->i_size, inode->i_blocks));
165 if (S_ISREG(inode->i_mode)) {
166 cFYI(1, (" File inode "));
167 inode->i_op = &cifs_file_inode_ops;
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
187 int
188 cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
189 FILE_ALL_INFO * pfindData, 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
201 if((pfindData == NULL) && (*pinode != NULL)) {
202 if(CIFS_I(*pinode)->clientCanCacheRead) {
203 cFYI(1,("No need to revalidate inode sizes on cached file "));
204 return rc;
205 }
206 }
207
208 /* if file info not passed in then get it from server */
209 if(pfindData == NULL) {
210 buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
211 if(buf == NULL)
212 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,
216 cifs_sb->local_nls);
217 }
218 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
219 if (rc) {
220 if (rc == -EREMOTE) {
221 tmp_path =
222 kmalloc(strnlen
223 (pTcon->treeName,
224 MAX_TREE_SIZE + 1) +
225 strnlen(search_path, MAX_PATHCONF) + 1,
226 GFP_KERNEL);
227 if (tmp_path == NULL) {
228 if(buf)
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,
237 cifs_sb->local_nls);
238 kfree(tmp_path);
239 /* BB fix up inode etc. */
240 } else if (rc) {
241 if(buf)
242 kfree(buf);
243 return rc;
244 }
245 } else {
246 struct cifsInodeInfo *cifsInfo;
247 __u32 attr = le32_to_cpu(pfindData->Attributes);
248
249 /* get new inode */
250 if (*pinode == NULL) {
251 *pinode = new_inode(sb);
252 if(*pinode == NULL)
253 return -ENOMEM;
254 /* Is an i_ino of zero legal? */
255 /* Are there sanity checks we can use to ensure that
256 the server is really filling in that field? */
257
258 /* We can not use the IndexNumber from either
259 Windows or Samba as it is frequently set to zero */
260 /* There may be higher info levels that work but
261 Are there Windows server or network appliances
262 for which IndexNumber field is not guaranteed unique? */
263
264 /* if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
265 (*pinode)->i_ino =
266 (unsigned long)pfindData->IndexNumber;
267 } */ /*NB: ino incremented to unique num in new_inode*/
268
269 insert_inode_hash(*pinode);
270 }
271 inode = *pinode;
272 cifsInfo = CIFS_I(inode);
273 cifsInfo->cifsAttrs = attr;
274 cFYI(1, (" Old time %ld ", cifsInfo->time));
275 cifsInfo->time = jiffies;
276 cFYI(1, (" New time %ld ", cifsInfo->time));
277
278 /* blksize needs to be multiple of two. So safer to default to blksize
279 and blkbits set in superblock so 2**blkbits and blksize will match */
280 /* inode->i_blksize =
281 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
282
283 /* Linux can not store file creation time unfortunately so we ignore it */
284 inode->i_atime =
285 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
286 inode->i_mtime =
287 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
288 inode->i_ctime =
289 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
290 cFYI(0,
291 (" Attributes came in as 0x%x ", attr));
292
293 /* set default mode. will override for dirs below */
294 if(atomic_read(&cifsInfo->inUse) == 0)
295 /* new inode, can safely set these fields */
296 inode->i_mode = cifs_sb->mnt_file_mode;
297
298 /* if (attr & ATTR_REPARSE) */
299 /* We no longer handle these as symlinks because we could not */
300 /* follow them due to the absolute path with drive letter */
301 if (attr & ATTR_DIRECTORY) {
302 /* override default perms since we do not do byte range locking on dirs */
303 inode->i_mode = cifs_sb->mnt_dir_mode;
304 inode->i_mode |= S_IFDIR;
305 } else {
306 inode->i_mode |= S_IFREG;
307 /* treat the dos attribute of read-only as read-only mode e.g. 555 */
308 if(cifsInfo->cifsAttrs & ATTR_READONLY)
309 inode->i_mode &= ~(S_IWUGO);
310 /* BB add code here - validate if device or weird share or device type? */
311 }
312 if(is_size_safe_to_change(cifsInfo)) {
313 /* can not safely change the file size here if the
314 client is writing to it due to potential races */
315
316 i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
317
318 /* 512 bytes (2**9) is the fake blocksize that must be used */
319 /* for this calculation */
320 inode->i_blocks = (512 - 1 + le64_to_cpu(pfindData->AllocationSize))
321 >> 9;
322 }
323
324 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
325
326 /* BB fill in uid and gid here? with help from winbind?
327 or retrieve from NTFS stream extended attribute */
328 if(atomic_read(&cifsInfo->inUse) == 0) {
329 inode->i_uid = cifs_sb->mnt_uid;
330 inode->i_gid = cifs_sb->mnt_gid;
331 /* set so we do not keep refreshing these fields with
332 bad data after user has changed them in memory */
333 atomic_set(&cifsInfo->inUse,1);
334 }
335
336 if (S_ISREG(inode->i_mode)) {
337 cFYI(1, (" File inode "));
338 inode->i_op = &cifs_file_inode_ops;
339 inode->i_fop = &cifs_file_ops;
340 inode->i_data.a_ops = &cifs_addr_ops;
341 } else if (S_ISDIR(inode->i_mode)) {
342 cFYI(1, (" Directory inode "));
343 inode->i_op = &cifs_dir_inode_ops;
344 inode->i_fop = &cifs_dir_ops;
345 } else if (S_ISLNK(inode->i_mode)) {
346 cFYI(1, (" Symbolic Link inode "));
347 inode->i_op = &cifs_symlink_inode_ops;
348 } else {
349 init_special_inode(inode, inode->i_mode,
350 inode->i_rdev);
351 }
352 }
353 if(buf)
354 kfree(buf);
355 return rc;
356 }
357
358 void
359 cifs_read_inode(struct inode *inode)
360 { /* gets root inode */
361 int xid;
362 struct cifs_sb_info *cifs_sb;
363
364 cifs_sb = CIFS_SB(inode->i_sb);
365 xid = GetXid();
366 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
367 cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
368 else
369 cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
370 /* can not call macro FreeXid here since in a void func */
371 _FreeXid(xid);
372 }
373
374 int
375 cifs_unlink(struct inode *inode, struct dentry *direntry)
376 {
377 int rc = 0;
378 int xid;
379 struct cifs_sb_info *cifs_sb;
380 struct cifsTconInfo *pTcon;
381 char *full_path = NULL;
382 struct cifsInodeInfo *cifsInode;
383 FILE_BASIC_INFO * pinfo_buf;
384
385 cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
386
387 xid = GetXid();
388
389 cifs_sb = CIFS_SB(inode->i_sb);
390 pTcon = cifs_sb->tcon;
391
392 /* Unlink can be called from rename so we can not grab
393 the sem here since we deadlock otherwise */
394 /* down(&direntry->d_sb->s_vfs_rename_sem);*/
395 full_path = build_path_from_dentry(direntry);
396 /* up(&direntry->d_sb->s_vfs_rename_sem);*/
397 if(full_path == NULL) {
398 FreeXid(xid);
399 return -ENOMEM;
400 }
401 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
402
403 if (!rc) {
404 direntry->d_inode->i_nlink--;
405 } else if (rc == -ENOENT) {
406 d_drop(direntry);
407 } else if (rc == -ETXTBSY) {
408 int oplock = FALSE;
409 __u16 netfid;
410
411 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
412 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
413 &netfid, &oplock, NULL, cifs_sb->local_nls);
414 if(rc==0) {
415 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
416 NULL, cifs_sb->local_nls);
417 CIFSSMBClose(xid, pTcon, netfid);
418 direntry->d_inode->i_nlink--;
419 }
420 } else if (rc == -EACCES) {
421 /* try only if r/o attribute set in local lookup data? */
422 pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
423 if(pinfo_buf) {
424 memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
425 /* ATTRS set to normal clears r/o bit */
426 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
427 rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
428 cifs_sb->local_nls);
429 kfree(pinfo_buf);
430 }
431 if(rc==0) {
432 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
433 if (!rc) {
434 direntry->d_inode->i_nlink--;
435 } else if (rc == -ETXTBSY) {
436 int oplock = FALSE;
437 __u16 netfid;
438
439 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
440 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
441 &netfid, &oplock, NULL, cifs_sb->local_nls);
442 if(rc==0) {
443 CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
444 CIFSSMBClose(xid, pTcon, netfid);
445 direntry->d_inode->i_nlink--;
446 }
447 /* BB if rc = -ETXTBUSY goto the rename logic BB */
448 }
449 }
450 }
451 cifsInode = CIFS_I(direntry->d_inode);
452 cifsInode->time = 0; /* will force revalidate to get info when needed */
453 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
454 current_fs_time(inode->i_sb);
455 cifsInode = CIFS_I(inode);
456 cifsInode->time = 0; /* force revalidate of dir as well */
457
458 if (full_path)
459 kfree(full_path);
460 FreeXid(xid);
461 return rc;
462 }
463
464 int
465 cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
466 {
467 int rc = 0;
468 int xid;
469 struct cifs_sb_info *cifs_sb;
470 struct cifsTconInfo *pTcon;
471 char *full_path = NULL;
472 struct inode *newinode = NULL;
473
474 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
475
476 xid = GetXid();
477
478 cifs_sb = CIFS_SB(inode->i_sb);
479 pTcon = cifs_sb->tcon;
480
481 down(&inode->i_sb->s_vfs_rename_sem);
482 full_path = build_path_from_dentry(direntry);
483 up(&inode->i_sb->s_vfs_rename_sem);
484 if(full_path == NULL) {
485 FreeXid(xid);
486 return -ENOMEM;
487 }
488 /* BB add setting the equivalent of mode via CreateX w/ACLs */
489 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
490 if (rc) {
491 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
492 d_drop(direntry);
493 } else {
494 inode->i_nlink++;
495 if (pTcon->ses->capabilities & CAP_UNIX)
496 rc = cifs_get_inode_info_unix(&newinode, full_path,
497 inode->i_sb,xid);
498 else
499 rc = cifs_get_inode_info(&newinode, full_path,NULL,
500 inode->i_sb,xid);
501
502 direntry->d_op = &cifs_dentry_ops;
503 d_instantiate(direntry, newinode);
504 if(direntry->d_inode)
505 direntry->d_inode->i_nlink = 2;
506 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
507 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
508 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
509 (__u64)current->euid,
510 (__u64)current->egid,
511 0 /* dev_t */,
512 cifs_sb->local_nls);
513 } else {
514 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
515 (__u64)-1,
516 (__u64)-1,
517 0 /* dev_t */,
518 cifs_sb->local_nls);
519 }
520 else { /* BB to be implemented via Windows secrty descriptors*/
521 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
522 }
523 }
524 if (full_path)
525 kfree(full_path);
526 FreeXid(xid);
527
528 return rc;
529 }
530
531 int
532 cifs_rmdir(struct inode *inode, struct dentry *direntry)
533 {
534 int rc = 0;
535 int xid;
536 struct cifs_sb_info *cifs_sb;
537 struct cifsTconInfo *pTcon;
538 char *full_path = NULL;
539 struct cifsInodeInfo *cifsInode;
540
541 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
542
543 xid = GetXid();
544
545 cifs_sb = CIFS_SB(inode->i_sb);
546 pTcon = cifs_sb->tcon;
547
548 down(&inode->i_sb->s_vfs_rename_sem);
549 full_path = build_path_from_dentry(direntry);
550 up(&inode->i_sb->s_vfs_rename_sem);
551 if(full_path == NULL) {
552 FreeXid(xid);
553 return -ENOMEM;
554 }
555
556 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
557
558 if (!rc) {
559 inode->i_nlink--;
560 i_size_write(direntry->d_inode,0);
561 direntry->d_inode->i_nlink = 0;
562 }
563
564 cifsInode = CIFS_I(direntry->d_inode);
565 cifsInode->time = 0; /* force revalidate to go get info when needed */
566 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
567 current_fs_time(inode->i_sb);
568
569 if (full_path)
570 kfree(full_path);
571 FreeXid(xid);
572 return rc;
573 }
574
575 int
576 cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
577 struct inode *target_inode, struct dentry *target_direntry)
578 {
579 char *fromName;
580 char *toName;
581 struct cifs_sb_info *cifs_sb_source;
582 struct cifs_sb_info *cifs_sb_target;
583 struct cifsTconInfo *pTcon;
584 int xid;
585 int rc = 0;
586
587 xid = GetXid();
588
589 cifs_sb_target = CIFS_SB(target_inode->i_sb);
590 cifs_sb_source = CIFS_SB(source_inode->i_sb);
591 pTcon = cifs_sb_source->tcon;
592
593 if (pTcon != cifs_sb_target->tcon) {
594 FreeXid(xid);
595 return -EXDEV; /* BB actually could be allowed if same server, but
596 different share. Might eventually add support for this */
597 }
598
599 /* we already have the rename sem so we do not need
600 to grab it again here to protect the path integrity */
601 fromName = build_path_from_dentry(source_direntry);
602 toName = build_path_from_dentry(target_direntry);
603 if((fromName == NULL) || (toName == NULL)) {
604 rc = -ENOMEM;
605 goto cifs_rename_exit;
606 }
607
608 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
609 cifs_sb_source->local_nls);
610 if(rc == -EEXIST) {
611 /* check if they are the same file
612 because rename of hardlinked files is a noop */
613 FILE_UNIX_BASIC_INFO * info_buf_source;
614 FILE_UNIX_BASIC_INFO * info_buf_target;
615
616 info_buf_source =
617 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
618 if(info_buf_source != NULL) {
619 info_buf_target = info_buf_source+1;
620 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
621 info_buf_source, cifs_sb_source->local_nls);
622 if(rc == 0) {
623 rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
624 info_buf_target,
625 cifs_sb_target->local_nls);
626 }
627 if((rc == 0) &&
628 (info_buf_source->UniqueId ==
629 info_buf_target->UniqueId)) {
630 /* do not rename since the files are hardlinked
631 which is a noop */
632 } else {
633 /* we either can not tell the files are hardlinked
634 (as with Windows servers) or files are not hardlinked
635 so delete the target manually before renaming to
636 follow POSIX rather than Windows semantics */
637 cifs_unlink(target_inode, target_direntry);
638 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
639 cifs_sb_source->local_nls);
640 }
641 kfree(info_buf_source);
642 } /* if we can not get memory just leave rc as EEXIST */
643 }
644
645 if((rc == -EIO)||(rc == -EEXIST)) {
646 int oplock = FALSE;
647 __u16 netfid;
648
649 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
650 CREATE_NOT_DIR,
651 &netfid, &oplock, NULL, cifs_sb_source->local_nls);
652 if(rc==0) {
653 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
654 toName, cifs_sb_source->local_nls);
655 CIFSSMBClose(xid, pTcon, netfid);
656 }
657 }
658
659 cifs_rename_exit:
660 if (fromName)
661 kfree(fromName);
662 if (toName)
663 kfree(toName);
664
665 FreeXid(xid);
666 return rc;
667 }
668
669 int
670 cifs_revalidate(struct dentry *direntry)
671 {
672 int xid;
673 int rc = 0;
674 char *full_path;
675 struct cifs_sb_info *cifs_sb;
676 struct cifsInodeInfo *cifsInode;
677 loff_t local_size;
678 struct timespec local_mtime;
679 int invalidate_inode = FALSE;
680
681 if(direntry->d_inode == NULL)
682 return -ENOENT;
683
684 cifsInode = CIFS_I(direntry->d_inode);
685
686 if(cifsInode == NULL)
687 return -ENOENT;
688
689 /* no sense revalidating inode info on file that no one can write */
690 if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
691 return rc;
692
693 xid = GetXid();
694
695 cifs_sb = CIFS_SB(direntry->d_sb);
696
697 /* can not safely grab the rename sem here if
698 rename calls revalidate since that would deadlock */
699 full_path = build_path_from_dentry(direntry);
700 if(full_path == NULL) {
701 FreeXid(xid);
702 return -ENOMEM;
703 }
704 cFYI(1,
705 ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
706 full_path, direntry->d_inode,
707 direntry->d_inode->i_count.counter, direntry,
708 direntry->d_time, jiffies));
709
710 if (cifsInode->time == 0){
711 /* was set to zero previously to force revalidate */
712 } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
713 if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
714 (direntry->d_inode->i_nlink == 1)) {
715 if (full_path)
716 kfree(full_path);
717 FreeXid(xid);
718 return rc;
719 } else {
720 cFYI(1,("Have to revalidate file due to hardlinks"));
721 }
722 }
723
724 /* save mtime and size */
725 local_mtime = direntry->d_inode->i_mtime;
726 local_size = direntry->d_inode->i_size;
727
728 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
729 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
730 direntry->d_sb,xid);
731 if(rc) {
732 cFYI(1,("error on getting revalidate info %d",rc));
733 /* if(rc != -ENOENT)
734 rc = 0; */ /* BB should we cache info on certain errors? */
735 }
736 } else {
737 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
738 direntry->d_sb,xid);
739 if(rc) {
740 cFYI(1,("error on getting revalidate info %d",rc));
741 /* if(rc != -ENOENT)
742 rc = 0; */ /* BB should we cache info on certain errors? */
743 }
744 }
745 /* should we remap certain errors, access denied?, to zero */
746
747 /* if not oplocked, we invalidate inode pages if mtime
748 or file size had changed on server */
749
750 if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
751 (local_size == direntry->d_inode->i_size)) {
752 cFYI(1,("cifs_revalidate - inode unchanged"));
753 } else {
754 /* file may have changed on server */
755 if(cifsInode->clientCanCacheRead) {
756 /* no need to invalidate inode pages since we were
757 the only ones who could have modified the file and
758 the server copy is staler than ours */
759 } else {
760 invalidate_inode = TRUE;
761 }
762 }
763
764 /* can not grab this sem since kernel filesys locking
765 documentation indicates i_sem may be taken by the kernel
766 on lookup and rename which could deadlock if we grab
767 the i_sem here as well */
768 /* down(&direntry->d_inode->i_sem);*/
769 /* need to write out dirty pages here */
770 if(direntry->d_inode->i_mapping) {
771 /* do we need to lock inode until after invalidate completes below? */
772 filemap_fdatawrite(direntry->d_inode->i_mapping);
773 }
774 if(invalidate_inode) {
775 filemap_fdatawait(direntry->d_inode->i_mapping);
776 /* may eventually have to do this for open files too */
777 if(list_empty(&(cifsInode->openFileList))) {
778 /* Has changed on server - flush read ahead pages */
779 cFYI(1,("Invalidating read ahead data on closed file"));
780 invalidate_remote_inode(direntry->d_inode);
781 }
782 }
783 /* up(&direntry->d_inode->i_sem);*/
784
785 if (full_path)
786 kfree(full_path);
787 FreeXid(xid);
788
789 return rc;
790 }
791
792 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
793 {
794 int err = cifs_revalidate(dentry);
795 if (!err)
796 generic_fillattr(dentry->d_inode, stat);
797 return err;
798 }
799
800 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
801 {
802 pgoff_t index = from >> PAGE_CACHE_SHIFT;
803 unsigned offset = from & (PAGE_CACHE_SIZE-1);
804 struct page *page;
805 char *kaddr;
806 int rc = 0;
807
808 page = grab_cache_page(mapping, index);
809 if (!page)
810 return -ENOMEM;
811
812 kaddr = kmap_atomic(page, KM_USER0);
813 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
814 flush_dcache_page(page);
815 kunmap_atomic(kaddr, KM_USER0);
816 unlock_page(page);
817 page_cache_release(page);
818 return rc;
819 }
820
821 int
822 cifs_setattr(struct dentry *direntry, struct iattr *attrs)
823 {
824 int xid;
825 struct cifs_sb_info *cifs_sb;
826 struct cifsTconInfo *pTcon;
827 char *full_path = NULL;
828 int rc = -EACCES;
829 int found = FALSE;
830 struct cifsFileInfo *open_file = NULL;
831 FILE_BASIC_INFO time_buf;
832 int set_time = FALSE;
833 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
834 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
835 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
836 struct cifsInodeInfo *cifsInode;
837 struct list_head * tmp;
838
839 xid = GetXid();
840
841 cFYI(1,
842 (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
843 direntry->d_name.name, attrs->ia_valid));
844 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
845 pTcon = cifs_sb->tcon;
846
847 down(&direntry->d_sb->s_vfs_rename_sem);
848 full_path = build_path_from_dentry(direntry);
849 up(&direntry->d_sb->s_vfs_rename_sem);
850 if(full_path == NULL) {
851 FreeXid(xid);
852 return -ENOMEM;
853 }
854 cifsInode = CIFS_I(direntry->d_inode);
855
856 /* BB check if we need to refresh inode from server now ? BB */
857
858 /* need to flush data before changing file size on server */
859 filemap_fdatawrite(direntry->d_inode->i_mapping);
860 filemap_fdatawait(direntry->d_inode->i_mapping);
861
862 if (attrs->ia_valid & ATTR_SIZE) {
863 read_lock(&GlobalSMBSeslock);
864 /* To avoid spurious oplock breaks from server, in the case
865 of inodes that we already have open, avoid doing path
866 based setting of file size if we can do it by handle.
867 This keeps our caching token (oplock) and avoids
868 timeouts when the local oplock break takes longer to flush
869 writebehind data than the SMB timeout for the SetPathInfo
870 request would allow */
871 list_for_each(tmp, &cifsInode->openFileList) {
872 open_file = list_entry(tmp,struct cifsFileInfo, flist);
873 /* We check if file is open for writing first */
874 if((open_file->pfile) &&
875 ((open_file->pfile->f_flags & O_RDWR) ||
876 (open_file->pfile->f_flags & O_WRONLY))) {
877 if(open_file->invalidHandle == FALSE) {
878 /* we found a valid, writeable network file
879 handle to use to try to set the file size */
880 __u16 nfid = open_file->netfid;
881 __u32 npid = open_file->pid;
882 read_unlock(&GlobalSMBSeslock);
883 found = TRUE;
884 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
885 nfid,npid,FALSE);
886 cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
887 /* Do not need reopen and retry on EAGAIN since we will
888 retry by pathname below */
889
890 break; /* now that we found one valid file handle no
891 sense continuing to loop trying others */
892 }
893 }
894 }
895 if(found == FALSE) {
896 read_unlock(&GlobalSMBSeslock);
897 }
898
899
900 if(rc != 0) {
901 /* Set file size by pathname rather than by handle either
902 because no valid, writeable file handle for it was found or
903 because there was an error setting it by handle */
904 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
905 cifs_sb->local_nls);
906 cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
907 }
908
909 /* Server is ok setting allocation size implicitly - no need to call: */
910 /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
911
912 if (rc == 0) {
913 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
914 cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
915 }
916 }
917 if (attrs->ia_valid & ATTR_UID) {
918 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
919 uid = attrs->ia_uid;
920 /* entry->uid = cpu_to_le16(attr->ia_uid); */
921 }
922 if (attrs->ia_valid & ATTR_GID) {
923 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
924 gid = attrs->ia_gid;
925 /* entry->gid = cpu_to_le16(attr->ia_gid); */
926 }
927
928 time_buf.Attributes = 0;
929 if (attrs->ia_valid & ATTR_MODE) {
930 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
931 mode = attrs->ia_mode;
932 /* entry->mode = cpu_to_le16(attr->ia_mode); */
933 }
934
935 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
936 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
937 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
938 0 /* dev_t */, cifs_sb->local_nls);
939 else if (attrs->ia_valid & ATTR_MODE) {
940 if((mode & S_IWUGO) == 0) /* not writeable */ {
941 if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
942 time_buf.Attributes =
943 cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
944 } else if((mode & S_IWUGO) == S_IWUGO) {
945 if(cifsInode->cifsAttrs & ATTR_READONLY)
946 time_buf.Attributes =
947 cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
948 }
949 /* BB to be implemented - via Windows security descriptors or streams */
950 /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
951 }
952
953 if (attrs->ia_valid & ATTR_ATIME) {
954 set_time = TRUE;
955 time_buf.LastAccessTime =
956 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
957 } else
958 time_buf.LastAccessTime = 0;
959
960 if (attrs->ia_valid & ATTR_MTIME) {
961 set_time = TRUE;
962 time_buf.LastWriteTime =
963 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
964 } else
965 time_buf.LastWriteTime = 0;
966
967 if (attrs->ia_valid & ATTR_CTIME) {
968 set_time = TRUE;
969 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
970 time_buf.ChangeTime =
971 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
972 } else
973 time_buf.ChangeTime = 0;
974
975 if (set_time || time_buf.Attributes) {
976 /* BB what if setting one attribute fails
977 (such as size) but time setting works */
978 time_buf.CreationTime = 0; /* do not change */
979 /* In the future we should experiment - try setting timestamps
980 via Handle (SetFileInfo) instead of by path */
981 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
982 cifs_sb->local_nls);
983 if(rc == -EOPNOTSUPP) {
984 cFYI(1,("OS2 level of SetPathInfo not implemented"));
985 /* Need to convert time_buf into old format,
986 but probably better to do that inside the function
987 below rather than here */
988 /* Better to return EOPNOTSUPP until function
989 below is ready */
990 /* CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
991 FILE_INFO_STANDARD * data, cifs_sb->local_nls); */
992 }
993 }
994
995 /* do not need local check to inode_check_ok since the server does that */
996 if (!rc)
997 rc = inode_setattr(direntry->d_inode, attrs);
998 if (full_path)
999 kfree(full_path);
1000 FreeXid(xid);
1001 return rc;
1002 }
1003
1004 void
1005 cifs_delete_inode(struct inode *inode)
1006 {
1007 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
1008 /* may have to add back in if and when safe distributed caching of
1009 directories added e.g. via FindNotify */
1010 }
1011
|
This page was automatically generated by the
LXR engine.
|