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