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