VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[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                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
485                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
486                                                 (__u64)current->euid,  
487                                                 (__u64)current->egid,
488                                                 0 /* dev_t */,
489                                                 cifs_sb->local_nls);
490                         } else {
491                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
492                                                 (__u64)-1,  
493                                                 (__u64)-1,
494                                                 0 /* dev_t */,
495                                                 cifs_sb->local_nls);
496                         }
497                 else { /* BB to be implemented via Windows secrty descriptors*/
498                 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
499                 }
500         }
501         if (full_path)
502                 kfree(full_path);
503         FreeXid(xid);
504
505         return rc;
506 }
507
508 int
509 cifs_rmdir(struct inode *inode, struct dentry *direntry)
510 {
511         int rc = 0;
512         int xid;
513         struct cifs_sb_info *cifs_sb;
514         struct cifsTconInfo *pTcon;
515         char *full_path = NULL;
516         struct cifsInodeInfo *cifsInode;
517
518         cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
519
520         xid = GetXid();
521
522         cifs_sb = CIFS_SB(inode->i_sb);
523         pTcon = cifs_sb->tcon;
524
525         down(&inode->i_sb->s_vfs_rename_sem);
526         full_path = build_path_from_dentry(direntry);
527         up(&inode->i_sb->s_vfs_rename_sem);
528         if(full_path == NULL) {
529                 FreeXid(xid);
530                 return -ENOMEM;
531         }
532
533         rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
534
535         if (!rc) {
536                 inode->i_nlink--;
537                 i_size_write(direntry->d_inode,0);
538                 direntry->d_inode->i_nlink = 0;
539         }
540
541         cifsInode = CIFS_I(direntry->d_inode);
542         cifsInode->time = 0;    /* force revalidate to go get info when needed */
543         direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
544             CURRENT_TIME;
545
546         if (full_path)
547                 kfree(full_path);
548         FreeXid(xid);
549         return rc;
550 }
551
552 int
553 cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
554             struct inode *target_inode, struct dentry *target_direntry)
555 {
556         char *fromName;
557         char *toName;
558         struct cifs_sb_info *cifs_sb_source;
559         struct cifs_sb_info *cifs_sb_target;
560         struct cifsTconInfo *pTcon;
561         int xid;
562         int rc = 0;
563
564         xid = GetXid();
565
566         cifs_sb_target = CIFS_SB(target_inode->i_sb);
567         cifs_sb_source = CIFS_SB(source_inode->i_sb);
568         pTcon = cifs_sb_source->tcon;
569
570         if (pTcon != cifs_sb_target->tcon) {
571                 FreeXid(xid);    
572                 return -EXDEV;  /* BB actually could be allowed if same server, but
573                      different share. Might eventually add support for this */
574         }
575
576         /* we already  have the rename sem so we do not need
577         to grab it again here to protect the path integrity */
578         fromName = build_path_from_dentry(source_direntry);
579         toName = build_path_from_dentry(target_direntry);
580         if((fromName == NULL) || (toName == NULL)) {
581                 rc = -ENOMEM;
582                 goto cifs_rename_exit;
583         }
584
585         rc = CIFSSMBRename(xid, pTcon, fromName, toName,
586                            cifs_sb_source->local_nls);
587         if(rc == -EEXIST) {
588                 /* check if they are the same file 
589                 because rename of hardlinked files is a noop */
590                 FILE_UNIX_BASIC_INFO * info_buf_source;
591                 FILE_UNIX_BASIC_INFO * info_buf_target;
592
593                 info_buf_source = 
594                         kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
595                 if(info_buf_source != NULL) {
596                         info_buf_target = info_buf_source+1;
597                         rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, 
598                                 info_buf_source, cifs_sb_source->local_nls);
599                         if(rc == 0) {
600                                 rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
601                                                 info_buf_target,
602                                                 cifs_sb_target->local_nls);
603                         }
604                         if((rc == 0) && 
605                                 (info_buf_source->UniqueId == 
606                                  info_buf_target->UniqueId)) {
607                         /* do not rename since the files are hardlinked 
608                            which is a noop */
609                         } else {
610                         /* we either can not tell the files are hardlinked
611                         (as with Windows servers) or files are not hardlinked 
612                         so delete the target manually before renaming to
613                         follow POSIX rather than Windows semantics */
614                                 cifs_unlink(target_inode, target_direntry);
615                                 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
616                                         cifs_sb_source->local_nls);
617                         }
618                         kfree(info_buf_source);
619                 } /* if we can not get memory just leave rc as EEXIST */
620         }
621
622         if((rc == -EIO)||(rc == -EEXIST)) {
623                 int oplock = FALSE;
624                 __u16 netfid;
625
626                 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
627                                         CREATE_NOT_DIR,
628                                         &netfid, &oplock, NULL, cifs_sb_source->local_nls);
629                 if(rc==0) {
630                         CIFSSMBRenameOpenFile(xid,pTcon,netfid,
631                                         toName, cifs_sb_source->local_nls);
632                         CIFSSMBClose(xid, pTcon, netfid);
633                 }
634         }
635
636 cifs_rename_exit:
637         if (fromName)
638                 kfree(fromName);
639         if (toName)
640                 kfree(toName);
641
642         FreeXid(xid);
643         return rc;
644 }
645
646 int
647 cifs_revalidate(struct dentry *direntry)
648 {
649         int xid;
650         int rc = 0;
651         char *full_path;
652         struct cifs_sb_info *cifs_sb;
653         struct cifsInodeInfo *cifsInode;
654         loff_t local_size;
655         struct timespec local_mtime;
656         int invalidate_inode = FALSE;
657
658         if(direntry->d_inode == NULL)
659                 return -ENOENT;
660
661         cifsInode = CIFS_I(direntry->d_inode);
662
663         if(cifsInode == NULL)
664                 return -ENOENT;
665
666         /* no sense revalidating inode info on file that no one can write */
667         if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
668                 return rc;
669
670         xid = GetXid();
671
672         cifs_sb = CIFS_SB(direntry->d_sb);
673
674         /* can not safely grab the rename sem here if
675         rename calls revalidate since that would deadlock */
676         full_path = build_path_from_dentry(direntry);
677         if(full_path == NULL) {
678                 FreeXid(xid);
679                 return -ENOMEM;
680         }
681         cFYI(1,
682              ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
683               full_path, direntry->d_inode,
684               direntry->d_inode->i_count.counter, direntry,
685               direntry->d_time, jiffies));
686
687         if (cifsInode->time == 0){
688                 /* was set to zero previously to force revalidate */
689         } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
690             if((S_ISREG(direntry->d_inode->i_mode) == 0) || 
691                         (direntry->d_inode->i_nlink == 1)) {  
692                         if (full_path)
693                                 kfree(full_path);
694                         FreeXid(xid);
695                         return rc;
696                 } else {
697                         cFYI(1,("Have to revalidate file due to hardlinks"));
698                 }            
699         }
700         
701         /* save mtime and size */
702         local_mtime = direntry->d_inode->i_mtime;
703         local_size  = direntry->d_inode->i_size;
704
705         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
706                 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
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         } else {
714                 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
715                                     direntry->d_sb,xid);
716                 if(rc) {
717                         cFYI(1,("error on getting revalidate info %d",rc));
718 /*                      if(rc != -ENOENT)
719                                 rc = 0; */  /* BB should we cache info on certain errors? */
720                 }
721         }
722         /* should we remap certain errors, access denied?, to zero */
723
724         /* if not oplocked, we invalidate inode pages if mtime 
725            or file size had changed on server */
726
727         if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
728                 (local_size == direntry->d_inode->i_size)) {
729                 cFYI(1,("cifs_revalidate - inode unchanged"));
730         } else {
731                 /* file may have changed on server */
732                 if(cifsInode->clientCanCacheRead) {
733                         /* no need to invalidate inode pages since we were
734                            the only ones who could have modified the file and
735                            the server copy is staler than ours */
736                 } else {
737                         invalidate_inode = TRUE;
738                 }
739         }
740
741         /* can not grab this sem since kernel filesys locking
742                 documentation indicates i_sem may be taken by the kernel 
743                 on lookup and rename which could deadlock if we grab
744                 the i_sem here as well */
745 /*      down(&direntry->d_inode->i_sem);*/
746         /* need to write out dirty pages here  */
747         if(direntry->d_inode->i_mapping) {
748                 /* do we need to lock inode until after invalidate completes below? */
749                 filemap_fdatawrite(direntry->d_inode->i_mapping);
750         }
751         if(invalidate_inode) {
752                 filemap_fdatawait(direntry->d_inode->i_mapping);
753                 /* may eventually have to do this for open files too */
754                 if(list_empty(&(cifsInode->openFileList))) {
755                         /* Has changed on server - flush read ahead pages */
756                         cFYI(1,("Invalidating read ahead data on closed file"));
757                         invalidate_remote_inode(direntry->d_inode);
758                 }
759         }
760 /*      up(&direntry->d_inode->i_sem);*/
761         
762         if (full_path)
763                 kfree(full_path);
764         FreeXid(xid);
765
766         return rc;
767 }
768
769 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
770 {
771         int err = cifs_revalidate(dentry);
772         if (!err)
773                 generic_fillattr(dentry->d_inode, stat);
774         return err;
775 }
776
777 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
778 {
779         pgoff_t index = from >> PAGE_CACHE_SHIFT;
780         unsigned offset = from & (PAGE_CACHE_SIZE-1);
781         struct page *page;
782         char *kaddr;
783         int rc = 0;
784
785         page = grab_cache_page(mapping, index);
786         if (!page)
787                 return -ENOMEM;
788
789         kaddr = kmap_atomic(page, KM_USER0);
790         memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
791         flush_dcache_page(page);
792         kunmap_atomic(kaddr, KM_USER0);
793         unlock_page(page);
794         page_cache_release(page);
795         return rc;
796 }
797
798 int
799 cifs_setattr(struct dentry *direntry, struct iattr *attrs)
800 {
801         int xid;
802         struct cifs_sb_info *cifs_sb;
803         struct cifsTconInfo *pTcon;
804         char *full_path = NULL;
805         int rc = -EACCES;
806         int found = FALSE;
807         struct cifsFileInfo *open_file = NULL;
808         FILE_BASIC_INFO time_buf;
809         int set_time = FALSE;
810         __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
811         __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
812         __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
813         struct cifsInodeInfo *cifsInode;
814         struct list_head * tmp;
815
816         xid = GetXid();
817
818         cFYI(1,
819              (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
820               direntry->d_name.name, attrs->ia_valid));
821         cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
822         pTcon = cifs_sb->tcon;
823
824         down(&direntry->d_sb->s_vfs_rename_sem);
825         full_path = build_path_from_dentry(direntry);
826         up(&direntry->d_sb->s_vfs_rename_sem);
827         if(full_path == NULL) {
828                 FreeXid(xid);
829                 return -ENOMEM;
830         }
831         cifsInode = CIFS_I(direntry->d_inode);
832
833         /* BB check if we need to refresh inode from server now ? BB */
834
835         /* need to flush data before changing file size on server */
836         filemap_fdatawrite(direntry->d_inode->i_mapping); 
837         filemap_fdatawait(direntry->d_inode->i_mapping);
838
839         if (attrs->ia_valid & ATTR_SIZE) {
840                 read_lock(&GlobalSMBSeslock); 
841                 /* To avoid spurious oplock breaks from server, in the case
842                         of inodes that we already have open, avoid doing path
843                         based setting of file size if we can do it by handle.
844                         This keeps our caching token (oplock) and avoids
845                         timeouts when the local oplock break takes longer to flush
846                         writebehind data than the SMB timeout for the SetPathInfo 
847                         request would allow */
848                 list_for_each(tmp, &cifsInode->openFileList) {            
849                         open_file = list_entry(tmp,struct cifsFileInfo, flist);
850                         /* We check if file is open for writing first */
851                         if((open_file->pfile) &&
852                                 ((open_file->pfile->f_flags & O_RDWR) || 
853                                  (open_file->pfile->f_flags & O_WRONLY))) {
854                                 if(open_file->invalidHandle == FALSE) {
855                                         /* we found a valid, writeable network file 
856                                         handle to use to try to set the file size */
857                                         __u16 nfid = open_file->netfid;
858                                         __u32 npid = open_file->pid;
859                                         read_unlock(&GlobalSMBSeslock);
860                                         found = TRUE;
861                                         rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
862                                            nfid,npid,FALSE);
863                                         cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
864                                 /* Do not need reopen and retry on EAGAIN since we will
865                                         retry by pathname below */
866
867                                         break;  /* now that we found one valid file handle no
868                                                 sense continuing to loop trying others */
869                                 }
870                         }
871                 }
872                 if(found == FALSE) {
873                         read_unlock(&GlobalSMBSeslock);
874                 }
875
876
877                 if(rc != 0) {
878                         /* Set file size by pathname rather than by handle either
879                         because no valid, writeable file handle for it was found or
880                         because there was an error setting it by handle */
881                         rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
882                                    cifs_sb->local_nls);
883                         cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
884                 }
885         
886         /*  Server is ok setting allocation size implicitly - no need to call: */
887         /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
888
889                 if (rc == 0) {
890                         rc = vmtruncate(direntry->d_inode, attrs->ia_size);
891                         cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
892                 }
893         }
894         if (attrs->ia_valid & ATTR_UID) {
895                 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
896                 uid = attrs->ia_uid;
897                 /*        entry->uid = cpu_to_le16(attr->ia_uid); */
898         }
899         if (attrs->ia_valid & ATTR_GID) {
900                 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
901                 gid = attrs->ia_gid;
902                 /*      entry->gid = cpu_to_le16(attr->ia_gid); */
903         }
904
905         time_buf.Attributes = 0;
906         if (attrs->ia_valid & ATTR_MODE) {
907                 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
908                 mode = attrs->ia_mode;
909                 /* entry->mode = cpu_to_le16(attr->ia_mode); */
910         }
911
912         if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
913             && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
914                 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
915                                 0 /* dev_t */, cifs_sb->local_nls);
916         else if (attrs->ia_valid & ATTR_MODE) {
917                 if((mode & S_IWUGO) == 0) /* not writeable */ {
918                         if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
919                                 time_buf.Attributes = 
920                                         cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
921                 } else if((mode & S_IWUGO) == S_IWUGO) {
922                         if(cifsInode->cifsAttrs & ATTR_READONLY)
923                                 time_buf.Attributes = 
924                                         cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
925                 }
926                 /* BB to be implemented - via Windows security descriptors or streams */
927                 /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
928         }
929
930         if (attrs->ia_valid & ATTR_ATIME) {
931                 set_time = TRUE;
932                 time_buf.LastAccessTime =
933                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
934         } else
935                 time_buf.LastAccessTime = 0;
936
937         if (attrs->ia_valid & ATTR_MTIME) {
938                 set_time = TRUE;
939                 time_buf.LastWriteTime =
940                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
941         } else
942                 time_buf.LastWriteTime = 0;
943
944         if (attrs->ia_valid & ATTR_CTIME) {
945                 set_time = TRUE;
946                 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
947                 time_buf.ChangeTime =
948                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
949         } else
950                 time_buf.ChangeTime = 0;
951
952         if (set_time | time_buf.Attributes) {
953                 /* BB what if setting one attribute fails  
954                         (such as size) but time setting works */
955                 time_buf.CreationTime = 0;      /* do not change */
956                 /* In the future we should experiment - try setting timestamps
957                          via Handle (SetFileInfo) instead of by path */
958                 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
959                                 cifs_sb->local_nls);
960         }
961
962         /* do not  need local check to inode_check_ok since the server does that */
963         if (!rc)
964                 rc = inode_setattr(direntry->d_inode, attrs);
965         if (full_path)
966                 kfree(full_path);
967         FreeXid(xid);
968         return rc;
969 }
970
971 void
972 cifs_delete_inode(struct inode *inode)
973 {
974         cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
975         /* may have to add back in if and when safe distributed caching of
976                 directories added e.g. via FindNotify */
977 }