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