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