[CIFS] Finish up of case-insensitive dentry handling for cifs. This
[safe/jmp/linux-2.6] / fs / cifs / inode.c
1 /*
2  *   fs/cifs/inode.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2005
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   This library is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU Lesser General Public License as published
9  *   by the Free Software Foundation; either version 2.1 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This library is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15  *   the GNU Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public License
18  *   along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 #include <linux/fs.h>
22 #include <linux/buffer_head.h>
23 #include <linux/stat.h>
24 #include <linux/pagemap.h>
25 #include <asm/div64.h>
26 #include "cifsfs.h"
27 #include "cifspdu.h"
28 #include "cifsglob.h"
29 #include "cifsproto.h"
30 #include "cifs_debug.h"
31 #include "cifs_fs_sb.h"
32
33 int cifs_get_inode_info_unix(struct inode **pinode,
34         const unsigned char *search_path, struct super_block *sb, int xid)
35 {
36         int rc = 0;
37         FILE_UNIX_BASIC_INFO findData;
38         struct cifsTconInfo *pTcon;
39         struct inode *inode;
40         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
41         char *tmp_path;
42
43         pTcon = cifs_sb->tcon;
44         cFYI(1, (" Getting info on %s ", search_path));
45         /* could have done a find first instead but this returns more info */
46         rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
47                                   cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
48                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
49 /*      dump_mem("\nUnixQPathInfo return data", &findData,
50                  sizeof(findData)); */
51         if (rc) {
52                 if (rc == -EREMOTE) {
53                         tmp_path =
54                             kmalloc(strnlen(pTcon->treeName,
55                                             MAX_TREE_SIZE + 1) +
56                                     strnlen(search_path, MAX_PATHCONF) + 1,
57                                     GFP_KERNEL);
58                         if (tmp_path == NULL) {
59                                 return -ENOMEM;
60                         }
61                         /* have to skip first of the double backslash of
62                            UNC name */
63                         strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
64                         strncat(tmp_path, search_path, MAX_PATHCONF);
65                         rc = connect_to_dfs_path(xid, pTcon->ses,
66                                                  /* treename + */ tmp_path,
67                                                  cifs_sb->local_nls, 
68                                                  cifs_sb->mnt_cifs_flags & 
69                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
70                         kfree(tmp_path);
71
72                         /* BB fix up inode etc. */
73                 } else if (rc) {
74                         return rc;
75                 }
76         } else {
77                 struct cifsInodeInfo *cifsInfo;
78                 __u32 type = le32_to_cpu(findData.Type);
79                 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
80                 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
81
82                 /* get new inode */
83                 if (*pinode == NULL) {
84                         *pinode = new_inode(sb);
85                         if (*pinode == NULL) 
86                                 return -ENOMEM;
87                         /* Is an i_ino of zero legal? */
88                         /* Are there sanity checks we can use to ensure that
89                            the server is really filling in that field? */
90                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
91                                 (*pinode)->i_ino =
92                                         (unsigned long)findData.UniqueId;
93                         } /* note ino incremented to unique num in new_inode */
94                         insert_inode_hash(*pinode);
95                 }
96
97                 inode = *pinode;
98                 cifsInfo = CIFS_I(inode);
99
100                 cFYI(1, (" Old time %ld ", cifsInfo->time));
101                 cifsInfo->time = jiffies;
102                 cFYI(1, (" New time %ld ", cifsInfo->time));
103                 /* this is ok to set on every inode revalidate */
104                 atomic_set(&cifsInfo->inUse,1);
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
143                 /* blksize needs to be multiple of two. So safer to default to
144                 blksize and blkbits set in superblock so 2**blkbits and blksize
145                 will match rather than setting to:
146                 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
147
148                 /* This seems incredibly stupid but it turns out that i_blocks
149                    is not related to (i_size / i_blksize), instead 512 byte size
150                    is required for calculating num blocks */
151
152                 /* 512 bytes (2**9) is the fake blocksize that must be used */
153                 /* for this calculation */
154                         inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
155                 }
156
157                 if (num_of_bytes < end_of_file)
158                         cFYI(1, ("allocation size less than end of file "));
159                 cFYI(1,
160                      ("Size %ld and blocks %ld",
161                       (unsigned long) inode->i_size, inode->i_blocks));
162                 if (S_ISREG(inode->i_mode)) {
163                         cFYI(1, (" File inode "));
164                         inode->i_op = &cifs_file_inode_ops;
165                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
166                                 inode->i_fop = &cifs_file_direct_ops;
167                         else
168                                 inode->i_fop = &cifs_file_ops;
169                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
170                                 inode->i_fop->lock = NULL;
171                         inode->i_data.a_ops = &cifs_addr_ops;
172                 } else if (S_ISDIR(inode->i_mode)) {
173                         cFYI(1, (" Directory inode"));
174                         inode->i_op = &cifs_dir_inode_ops;
175                         inode->i_fop = &cifs_dir_ops;
176                 } else if (S_ISLNK(inode->i_mode)) {
177                         cFYI(1, (" Symbolic Link inode "));
178                         inode->i_op = &cifs_symlink_inode_ops;
179                 /* tmp_inode->i_fop = */ /* do not need to set to anything */
180                 } else {
181                         cFYI(1, (" Init special inode "));
182                         init_special_inode(inode, inode->i_mode,
183                                            inode->i_rdev);
184                 }
185         }
186         return rc;
187 }
188
189 int cifs_get_inode_info(struct inode **pinode,
190         const unsigned char *search_path, FILE_ALL_INFO *pfindData,
191         struct super_block *sb, int xid)
192 {
193         int rc = 0;
194         struct cifsTconInfo *pTcon;
195         struct inode *inode;
196         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
197         char *tmp_path;
198         char *buf = NULL;
199
200         pTcon = cifs_sb->tcon;
201         cFYI(1,("Getting info on %s ", search_path));
202
203         if ((pfindData == NULL) && (*pinode != NULL)) {
204                 if (CIFS_I(*pinode)->clientCanCacheRead) {
205                         cFYI(1,("No need to revalidate cached inode sizes"));
206                         return rc;
207                 }
208         }
209
210         /* if file info not passed in then get it from server */
211         if (pfindData == NULL) {
212                 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
213                 if (buf == NULL)
214                         return -ENOMEM;
215                 pfindData = (FILE_ALL_INFO *)buf;
216                 /* could do find first instead but this returns more info */
217                 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
218                               cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 
219                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
220         }
221         /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
222         if (rc) {
223                 if (rc == -EREMOTE) {
224                         tmp_path =
225                             kmalloc(strnlen
226                                     (pTcon->treeName,
227                                      MAX_TREE_SIZE + 1) +
228                                     strnlen(search_path, MAX_PATHCONF) + 1,
229                                     GFP_KERNEL);
230                         if (tmp_path == NULL) {
231                                 kfree(buf);
232                                 return -ENOMEM;
233                         }
234
235                         strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
236                         strncat(tmp_path, search_path, MAX_PATHCONF);
237                         rc = connect_to_dfs_path(xid, pTcon->ses,
238                                                  /* treename + */ tmp_path,
239                                                  cifs_sb->local_nls, 
240                                                  cifs_sb->mnt_cifs_flags & 
241                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
242                         kfree(tmp_path);
243                         /* BB fix up inode etc. */
244                 } else if (rc) {
245                         kfree(buf);
246                         return rc;
247                 }
248         } else {
249                 struct cifsInodeInfo *cifsInfo;
250                 __u32 attr = le32_to_cpu(pfindData->Attributes);
251
252                 /* get new inode */
253                 if (*pinode == NULL) {
254                         *pinode = new_inode(sb);
255                         if (*pinode == NULL)
256                                 return -ENOMEM;
257                         /* Is an i_ino of zero legal? Can we use that to check
258                            if the server supports returning inode numbers?  Are
259                            there other sanity checks we can use to ensure that
260                            the server is really filling in that field? */
261
262                         /* We can not use the IndexNumber field by default from
263                            Windows or Samba (in ALL_INFO buf) but we can request
264                            it explicitly.  It may not be unique presumably if
265                            the server has multiple devices mounted under one
266                            share */
267
268                         /* There may be higher info levels that work but are
269                            there Windows server or network appliances for which
270                            IndexNumber field is not guaranteed unique? */
271
272 #ifdef CONFIG_CIFS_EXPERIMENTAL         
273                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
274                                 int rc1 = 0;
275                                 __u64 inode_num;
276
277                                 rc1 = CIFSGetSrvInodeNumber(xid, pTcon, 
278                                         search_path, &inode_num, 
279                                         cifs_sb->local_nls,
280                                         cifs_sb->mnt_cifs_flags &
281                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
282                                 if (rc1) {
283                                         cFYI(1,("GetSrvInodeNum rc %d", rc1));
284                                         /* BB EOPNOSUPP disable SERVER_INUM? */
285                                 } else /* do we need cast or hash to ino? */
286                                         (*pinode)->i_ino = inode_num;
287                         } /* else ino incremented to unique num in new_inode*/
288 #endif /* CIFS_EXPERIMENTAL */
289                         insert_inode_hash(*pinode);
290                 }
291                 inode = *pinode;
292                 cifsInfo = CIFS_I(inode);
293                 cifsInfo->cifsAttrs = attr;
294                 cFYI(1, (" Old time %ld ", cifsInfo->time));
295                 cifsInfo->time = jiffies;
296                 cFYI(1, (" New time %ld ", cifsInfo->time));
297
298                 /* blksize needs to be multiple of two. So safer to default to
299                 blksize and blkbits set in superblock so 2**blkbits and blksize
300                 will match rather than setting to:
301                 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
302
303                 /* Linux can not store file creation time unfortunately so we ignore it */
304                 inode->i_atime =
305                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
306                 inode->i_mtime =
307                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
308                 inode->i_ctime =
309                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
310                 cFYI(0, (" Attributes came in as 0x%x ", attr));
311
312                 /* set default mode. will override for dirs below */
313                 if (atomic_read(&cifsInfo->inUse) == 0)
314                         /* new inode, can safely set these fields */
315                         inode->i_mode = cifs_sb->mnt_file_mode;
316
317 /*              if (attr & ATTR_REPARSE)  */
318                 /* We no longer handle these as symlinks because we could not
319                    follow them due to the absolute path with drive letter */
320                 if (attr & ATTR_DIRECTORY) {
321                 /* override default perms since we do not do byte range locking
322                    on dirs */
323                         inode->i_mode = cifs_sb->mnt_dir_mode;
324                         inode->i_mode |= S_IFDIR;
325                 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
326                            (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
327                            /* No need to le64 convert size of zero */
328                            (pfindData->EndOfFile == 0)) {
329                         inode->i_mode = cifs_sb->mnt_file_mode;
330                         inode->i_mode |= S_IFIFO;
331 /* BB Finish for SFU style symlinks and devies */
332 /*              } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
333                            (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */
334
335                 } else {
336                         inode->i_mode |= S_IFREG;
337                         /* treat the dos attribute of read-only as read-only
338                            mode e.g. 555 */
339                         if (cifsInfo->cifsAttrs & ATTR_READONLY)
340                                 inode->i_mode &= ~(S_IWUGO);
341                 /* BB add code here -
342                    validate if device or weird share or device type? */
343                 }
344                 if (is_size_safe_to_change(cifsInfo)) {
345                         /* can not safely change the file size here if the
346                            client is writing to it due to potential races */
347                         i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
348
349                         /* 512 bytes (2**9) is the fake blocksize that must be
350                            used for this calculation */
351                         inode->i_blocks = (512 - 1 + le64_to_cpu(
352                                            pfindData->AllocationSize)) >> 9;
353                 }
354
355                 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
356
357                 /* BB fill in uid and gid here? with help from winbind? 
358                    or retrieve from NTFS stream extended attribute */
359                 if (atomic_read(&cifsInfo->inUse) == 0) {
360                         inode->i_uid = cifs_sb->mnt_uid;
361                         inode->i_gid = cifs_sb->mnt_gid;
362                         /* set so we do not keep refreshing these fields with
363                            bad data after user has changed them in memory */
364                         atomic_set(&cifsInfo->inUse,1);
365                 }
366
367                 if (S_ISREG(inode->i_mode)) {
368                         cFYI(1, (" File inode "));
369                         inode->i_op = &cifs_file_inode_ops;
370                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
371                                 inode->i_fop = &cifs_file_direct_ops;
372                         else
373                                 inode->i_fop = &cifs_file_ops;
374                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
375                                 inode->i_fop->lock = NULL;
376                         inode->i_data.a_ops = &cifs_addr_ops;
377                 } else if (S_ISDIR(inode->i_mode)) {
378                         cFYI(1, (" Directory inode "));
379                         inode->i_op = &cifs_dir_inode_ops;
380                         inode->i_fop = &cifs_dir_ops;
381                 } else if (S_ISLNK(inode->i_mode)) {
382                         cFYI(1, (" Symbolic Link inode "));
383                         inode->i_op = &cifs_symlink_inode_ops;
384                 } else {
385                         init_special_inode(inode, inode->i_mode,
386                                            inode->i_rdev);
387                 }
388         }
389         kfree(buf);
390         return rc;
391 }
392
393 /* gets root inode */
394 void cifs_read_inode(struct inode *inode)
395 {
396         int xid;
397         struct cifs_sb_info *cifs_sb;
398
399         cifs_sb = CIFS_SB(inode->i_sb);
400         xid = GetXid();
401         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
402                 cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
403         else
404                 cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
405         /* can not call macro FreeXid here since in a void func */
406         _FreeXid(xid);
407 }
408
409 int cifs_unlink(struct inode *inode, struct dentry *direntry)
410 {
411         int rc = 0;
412         int xid;
413         struct cifs_sb_info *cifs_sb;
414         struct cifsTconInfo *pTcon;
415         char *full_path = NULL;
416         struct cifsInodeInfo *cifsInode;
417         FILE_BASIC_INFO *pinfo_buf;
418
419         cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
420
421         xid = GetXid();
422
423         cifs_sb = CIFS_SB(inode->i_sb);
424         pTcon = cifs_sb->tcon;
425
426         /* Unlink can be called from rename so we can not grab the sem here
427            since we deadlock otherwise */
428 /*      down(&direntry->d_sb->s_vfs_rename_sem);*/
429         full_path = build_path_from_dentry(direntry, cifs_sb);
430 /*      up(&direntry->d_sb->s_vfs_rename_sem);*/
431         if (full_path == NULL) {
432                 FreeXid(xid);
433                 return -ENOMEM;
434         }
435         rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
436                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
437
438         if (!rc) {
439                 if (direntry->d_inode)
440                         direntry->d_inode->i_nlink--;
441         } else if (rc == -ENOENT) {
442                 d_drop(direntry);
443         } else if (rc == -ETXTBSY) {
444                 int oplock = FALSE;
445                 __u16 netfid;
446
447                 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
448                                  CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
449                                  &netfid, &oplock, NULL, cifs_sb->local_nls,
450                                  cifs_sb->mnt_cifs_flags & 
451                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
452                 if (rc==0) {
453                         CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
454                                               cifs_sb->local_nls, 
455                                               cifs_sb->mnt_cifs_flags & 
456                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
457                         CIFSSMBClose(xid, pTcon, netfid);
458                         if (direntry->d_inode)
459                                 direntry->d_inode->i_nlink--;
460                 }
461         } else if (rc == -EACCES) {
462                 /* try only if r/o attribute set in local lookup data? */
463                 pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
464                 if (pinfo_buf) {
465                         memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
466                         /* ATTRS set to normal clears r/o bit */
467                         pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
468                         if (!(pTcon->ses->flags & CIFS_SES_NT4))
469                                 rc = CIFSSMBSetTimes(xid, pTcon, full_path,
470                                                      pinfo_buf,
471                                                      cifs_sb->local_nls,
472                                                      cifs_sb->mnt_cifs_flags & 
473                                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
474                         else
475                                 rc = -EOPNOTSUPP;
476
477                         if (rc == -EOPNOTSUPP) {
478                                 int oplock = FALSE;
479                                 __u16 netfid;
480                         /*      rc = CIFSSMBSetAttrLegacy(xid, pTcon,
481                                                           full_path,
482                                                           (__u16)ATTR_NORMAL,
483                                                           cifs_sb->local_nls); 
484                            For some strange reason it seems that NT4 eats the
485                            old setattr call without actually setting the
486                            attributes so on to the third attempted workaround
487                            */
488
489                         /* BB could scan to see if we already have it open
490                            and pass in pid of opener to function */
491                                 rc = CIFSSMBOpen(xid, pTcon, full_path,
492                                                  FILE_OPEN, SYNCHRONIZE |
493                                                  FILE_WRITE_ATTRIBUTES, 0,
494                                                  &netfid, &oplock, NULL,
495                                                  cifs_sb->local_nls,
496                                                  cifs_sb->mnt_cifs_flags & 
497                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
498                                 if (rc==0) {
499                                         rc = CIFSSMBSetFileTimes(xid, pTcon,
500                                                                  pinfo_buf,
501                                                                  netfid);
502                                         CIFSSMBClose(xid, pTcon, netfid);
503                                 }
504                         }
505                         kfree(pinfo_buf);
506                 }
507                 if (rc==0) {
508                         rc = CIFSSMBDelFile(xid, pTcon, full_path, 
509                                             cifs_sb->local_nls, 
510                                             cifs_sb->mnt_cifs_flags & 
511                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
512                         if (!rc) {
513                                 if (direntry->d_inode)
514                                         direntry->d_inode->i_nlink--;
515                         } else if (rc == -ETXTBSY) {
516                                 int oplock = FALSE;
517                                 __u16 netfid;
518
519                                 rc = CIFSSMBOpen(xid, pTcon, full_path,
520                                                  FILE_OPEN, DELETE,
521                                                  CREATE_NOT_DIR |
522                                                  CREATE_DELETE_ON_CLOSE,
523                                                  &netfid, &oplock, NULL,
524                                                  cifs_sb->local_nls, 
525                                                  cifs_sb->mnt_cifs_flags & 
526                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
527                                 if (rc==0) {
528                                         CIFSSMBRenameOpenFile(xid, pTcon,
529                                                 netfid, NULL,
530                                                 cifs_sb->local_nls,
531                                                 cifs_sb->mnt_cifs_flags &
532                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
533                                         CIFSSMBClose(xid, pTcon, netfid);
534                                         if (direntry->d_inode)
535                                                 direntry->d_inode->i_nlink--;
536                                 }
537                         /* BB if rc = -ETXTBUSY goto the rename logic BB */
538                         }
539                 }
540         }
541         if (direntry->d_inode) {
542                 cifsInode = CIFS_I(direntry->d_inode);
543                 cifsInode->time = 0;    /* will force revalidate to get info
544                                            when needed */
545                 direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
546         }
547         inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
548         cifsInode = CIFS_I(inode);
549         cifsInode->time = 0;    /* force revalidate of dir as well */
550
551         kfree(full_path);
552         FreeXid(xid);
553         return rc;
554 }
555
556 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
557 {
558         int rc = 0;
559         int xid;
560         struct cifs_sb_info *cifs_sb;
561         struct cifsTconInfo *pTcon;
562         char *full_path = NULL;
563         struct inode *newinode = NULL;
564
565         cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
566
567         xid = GetXid();
568
569         cifs_sb = CIFS_SB(inode->i_sb);
570         pTcon = cifs_sb->tcon;
571
572         down(&inode->i_sb->s_vfs_rename_sem);
573         full_path = build_path_from_dentry(direntry, cifs_sb);
574         up(&inode->i_sb->s_vfs_rename_sem);
575         if (full_path == NULL) {
576                 FreeXid(xid);
577                 return -ENOMEM;
578         }
579         /* BB add setting the equivalent of mode via CreateX w/ACLs */
580         rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
581                           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
582         if (rc) {
583                 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
584                 d_drop(direntry);
585         } else {
586                 inode->i_nlink++;
587                 if (pTcon->ses->capabilities & CAP_UNIX)
588                         rc = cifs_get_inode_info_unix(&newinode, full_path,
589                                                       inode->i_sb,xid);
590                 else
591                         rc = cifs_get_inode_info(&newinode, full_path, NULL,
592                                                  inode->i_sb,xid);
593
594                 if (pTcon->nocase)
595                         direntry->d_op = &cifs_ci_dentry_ops;
596                 else
597                         direntry->d_op = &cifs_dentry_ops;
598                 d_instantiate(direntry, newinode);
599                 if (direntry->d_inode)
600                         direntry->d_inode->i_nlink = 2;
601                 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
602                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
603                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
604                                                     mode,
605                                                     (__u64)current->euid,
606                                                     (__u64)current->egid,
607                                                     0 /* dev_t */,
608                                                     cifs_sb->local_nls,
609                                                     cifs_sb->mnt_cifs_flags &
610                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
611                         } else {
612                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
613                                                     mode, (__u64)-1,
614                                                     (__u64)-1, 0 /* dev_t */,
615                                                     cifs_sb->local_nls,
616                                                     cifs_sb->mnt_cifs_flags & 
617                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
618                         }
619                 else {
620                         /* BB to be implemented via Windows secrty descriptors
621                            eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
622                                                  -1, -1, local_nls); */
623                 }
624         }
625         kfree(full_path);
626         FreeXid(xid);
627         return rc;
628 }
629
630 int cifs_rmdir(struct inode *inode, struct dentry *direntry)
631 {
632         int rc = 0;
633         int xid;
634         struct cifs_sb_info *cifs_sb;
635         struct cifsTconInfo *pTcon;
636         char *full_path = NULL;
637         struct cifsInodeInfo *cifsInode;
638
639         cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
640
641         xid = GetXid();
642
643         cifs_sb = CIFS_SB(inode->i_sb);
644         pTcon = cifs_sb->tcon;
645
646         down(&inode->i_sb->s_vfs_rename_sem);
647         full_path = build_path_from_dentry(direntry, cifs_sb);
648         up(&inode->i_sb->s_vfs_rename_sem);
649         if (full_path == NULL) {
650                 FreeXid(xid);
651                 return -ENOMEM;
652         }
653
654         rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
655                           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
656
657         if (!rc) {
658                 inode->i_nlink--;
659                 i_size_write(direntry->d_inode,0);
660                 direntry->d_inode->i_nlink = 0;
661         }
662
663         cifsInode = CIFS_I(direntry->d_inode);
664         cifsInode->time = 0;    /* force revalidate to go get info when
665                                    needed */
666         direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
667                 current_fs_time(inode->i_sb);
668
669         kfree(full_path);
670         FreeXid(xid);
671         return rc;
672 }
673
674 int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
675         struct inode *target_inode, struct dentry *target_direntry)
676 {
677         char *fromName;
678         char *toName;
679         struct cifs_sb_info *cifs_sb_source;
680         struct cifs_sb_info *cifs_sb_target;
681         struct cifsTconInfo *pTcon;
682         int xid;
683         int rc = 0;
684
685         xid = GetXid();
686
687         cifs_sb_target = CIFS_SB(target_inode->i_sb);
688         cifs_sb_source = CIFS_SB(source_inode->i_sb);
689         pTcon = cifs_sb_source->tcon;
690
691         if (pTcon != cifs_sb_target->tcon) {
692                 FreeXid(xid);
693                 return -EXDEV;  /* BB actually could be allowed if same server,
694                                    but different share.
695                                    Might eventually add support for this */
696         }
697
698         /* we already  have the rename sem so we do not need to grab it again
699            here to protect the path integrity */
700         fromName = build_path_from_dentry(source_direntry, cifs_sb_source);
701         toName = build_path_from_dentry(target_direntry, cifs_sb_target);
702         if ((fromName == NULL) || (toName == NULL)) {
703                 rc = -ENOMEM;
704                 goto cifs_rename_exit;
705         }
706
707         rc = CIFSSMBRename(xid, pTcon, fromName, toName,
708                            cifs_sb_source->local_nls,
709                            cifs_sb_source->mnt_cifs_flags &
710                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
711         if (rc == -EEXIST) {
712                 /* check if they are the same file because rename of hardlinked
713                    files is a noop */
714                 FILE_UNIX_BASIC_INFO *info_buf_source;
715                 FILE_UNIX_BASIC_INFO *info_buf_target;
716
717                 info_buf_source =
718                         kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
719                 if (info_buf_source != NULL) {
720                         info_buf_target = info_buf_source + 1;
721                         rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
722                                 info_buf_source, cifs_sb_source->local_nls, 
723                                 cifs_sb_source->mnt_cifs_flags &
724                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
725                         if (rc == 0) {
726                                 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
727                                                 info_buf_target,
728                                                 cifs_sb_target->local_nls,
729                                                 /* remap based on source sb */
730                                                 cifs_sb_source->mnt_cifs_flags &
731                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
732                         }
733                         if ((rc == 0) &&
734                             (info_buf_source->UniqueId ==
735                              info_buf_target->UniqueId)) {
736                         /* do not rename since the files are hardlinked which
737                            is a noop */
738                         } else {
739                         /* we either can not tell the files are hardlinked
740                            (as with Windows servers) or files are not
741                            hardlinked so delete the target manually before
742                            renaming to follow POSIX rather than Windows
743                            semantics */
744                                 cifs_unlink(target_inode, target_direntry);
745                                 rc = CIFSSMBRename(xid, pTcon, fromName,
746                                                    toName,
747                                                    cifs_sb_source->local_nls,
748                                                    cifs_sb_source->mnt_cifs_flags
749                                                    & CIFS_MOUNT_MAP_SPECIAL_CHR);
750                         }
751                         kfree(info_buf_source);
752                 } /* if we can not get memory just leave rc as EEXIST */
753         }
754
755         if (rc) {
756                 cFYI(1, ("rename rc %d", rc));
757         }
758
759         if ((rc == -EIO) || (rc == -EEXIST)) {
760                 int oplock = FALSE;
761                 __u16 netfid;
762
763                 /* BB FIXME Is Generic Read correct for rename? */
764                 /* if renaming directory - we should not say CREATE_NOT_DIR,
765                    need to test renaming open directory, also GENERIC_READ
766                    might not right be right access to request */
767                 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
768                                  CREATE_NOT_DIR, &netfid, &oplock, NULL,
769                                  cifs_sb_source->local_nls, 
770                                  cifs_sb_source->mnt_cifs_flags & 
771                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
772                 if (rc==0) {
773                         CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
774                                               cifs_sb_source->local_nls, 
775                                               cifs_sb_source->mnt_cifs_flags &
776                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
777                         CIFSSMBClose(xid, pTcon, netfid);
778                 }
779         }
780
781 cifs_rename_exit:
782         kfree(fromName);
783         kfree(toName);
784         FreeXid(xid);
785         return rc;
786 }
787
788 int cifs_revalidate(struct dentry *direntry)
789 {
790         int xid;
791         int rc = 0;
792         char *full_path;
793         struct cifs_sb_info *cifs_sb;
794         struct cifsInodeInfo *cifsInode;
795         loff_t local_size;
796         struct timespec local_mtime;
797         int invalidate_inode = FALSE;
798
799         if (direntry->d_inode == NULL)
800                 return -ENOENT;
801
802         cifsInode = CIFS_I(direntry->d_inode);
803
804         if (cifsInode == NULL)
805                 return -ENOENT;
806
807         /* no sense revalidating inode info on file that no one can write */
808         if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
809                 return rc;
810
811         xid = GetXid();
812
813         cifs_sb = CIFS_SB(direntry->d_sb);
814
815         /* can not safely grab the rename sem here if rename calls revalidate
816            since that would deadlock */
817         full_path = build_path_from_dentry(direntry, cifs_sb);
818         if (full_path == NULL) {
819                 FreeXid(xid);
820                 return -ENOMEM;
821         }
822         cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
823                  "jiffies %ld", full_path, direntry->d_inode,
824                  direntry->d_inode->i_count.counter, direntry,
825                  direntry->d_time, jiffies));
826
827         if (cifsInode->time == 0) {
828                 /* was set to zero previously to force revalidate */
829         } else if (time_before(jiffies, cifsInode->time + HZ) &&
830                    lookupCacheEnabled) {
831                 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
832                     (direntry->d_inode->i_nlink == 1)) {
833                         kfree(full_path);
834                         FreeXid(xid);
835                         return rc;
836                 } else {
837                         cFYI(1, ("Have to revalidate file due to hardlinks"));
838                 }
839         }
840
841         /* save mtime and size */
842         local_mtime = direntry->d_inode->i_mtime;
843         local_size = direntry->d_inode->i_size;
844
845         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
846                 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
847                                               direntry->d_sb,xid);
848                 if (rc) {
849                         cFYI(1, ("error on getting revalidate info %d", rc));
850 /*                      if (rc != -ENOENT)
851                                 rc = 0; */      /* BB should we cache info on
852                                                    certain errors? */
853                 }
854         } else {
855                 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
856                                          direntry->d_sb,xid);
857                 if (rc) {
858                         cFYI(1, ("error on getting revalidate info %d", rc));
859 /*                      if (rc != -ENOENT)
860                                 rc = 0; */      /* BB should we cache info on
861                                                    certain errors? */
862                 }
863         }
864         /* should we remap certain errors, access denied?, to zero */
865
866         /* if not oplocked, we invalidate inode pages if mtime or file size
867            had changed on server */
868
869         if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
870             (local_size == direntry->d_inode->i_size)) {
871                 cFYI(1, ("cifs_revalidate - inode unchanged"));
872         } else {
873                 /* file may have changed on server */
874                 if (cifsInode->clientCanCacheRead) {
875                         /* no need to invalidate inode pages since we were the
876                            only ones who could have modified the file and the
877                            server copy is staler than ours */
878                 } else {
879                         invalidate_inode = TRUE;
880                 }
881         }
882
883         /* can not grab this sem since kernel filesys locking documentation
884            indicates i_sem may be taken by the kernel on lookup and rename
885            which could deadlock if we grab the i_sem here as well */
886 /*      down(&direntry->d_inode->i_sem);*/
887         /* need to write out dirty pages here  */
888         if (direntry->d_inode->i_mapping) {
889                 /* do we need to lock inode until after invalidate completes
890                    below? */
891                 filemap_fdatawrite(direntry->d_inode->i_mapping);
892         }
893         if (invalidate_inode) {
894                 if (direntry->d_inode->i_mapping)
895                         filemap_fdatawait(direntry->d_inode->i_mapping);
896                 /* may eventually have to do this for open files too */
897                 if (list_empty(&(cifsInode->openFileList))) {
898                         /* Has changed on server - flush read ahead pages */
899                         cFYI(1, ("Invalidating read ahead data on "
900                                  "closed file"));
901                         invalidate_remote_inode(direntry->d_inode);
902                 }
903         }
904 /*      up(&direntry->d_inode->i_sem); */
905         
906         kfree(full_path);
907         FreeXid(xid);
908         return rc;
909 }
910
911 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
912         struct kstat *stat)
913 {
914         int err = cifs_revalidate(dentry);
915         if (!err)
916                 generic_fillattr(dentry->d_inode, stat);
917         return err;
918 }
919
920 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
921 {
922         pgoff_t index = from >> PAGE_CACHE_SHIFT;
923         unsigned offset = from & (PAGE_CACHE_SIZE - 1);
924         struct page *page;
925         char *kaddr;
926         int rc = 0;
927
928         page = grab_cache_page(mapping, index);
929         if (!page)
930                 return -ENOMEM;
931
932         kaddr = kmap_atomic(page, KM_USER0);
933         memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
934         flush_dcache_page(page);
935         kunmap_atomic(kaddr, KM_USER0);
936         unlock_page(page);
937         page_cache_release(page);
938         return rc;
939 }
940
941 int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
942 {
943         int xid;
944         struct cifs_sb_info *cifs_sb;
945         struct cifsTconInfo *pTcon;
946         char *full_path = NULL;
947         int rc = -EACCES;
948         int found = FALSE;
949         struct cifsFileInfo *open_file = NULL;
950         FILE_BASIC_INFO time_buf;
951         int set_time = FALSE;
952         __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
953         __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
954         __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
955         struct cifsInodeInfo *cifsInode;
956         struct list_head *tmp;
957
958         xid = GetXid();
959
960         cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
961                  direntry->d_name.name, attrs->ia_valid));
962         cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
963         pTcon = cifs_sb->tcon;
964
965         down(&direntry->d_sb->s_vfs_rename_sem);
966         full_path = build_path_from_dentry(direntry, cifs_sb);
967         up(&direntry->d_sb->s_vfs_rename_sem);
968         if (full_path == NULL) {
969                 FreeXid(xid);
970                 return -ENOMEM;
971         }
972         cifsInode = CIFS_I(direntry->d_inode);
973
974         /* BB check if we need to refresh inode from server now ? BB */
975
976         /* need to flush data before changing file size on server */
977         filemap_fdatawrite(direntry->d_inode->i_mapping);
978         filemap_fdatawait(direntry->d_inode->i_mapping);
979
980         if (attrs->ia_valid & ATTR_SIZE) {
981                 read_lock(&GlobalSMBSeslock);
982                 /* To avoid spurious oplock breaks from server, in the case of
983                    inodes that we already have open, avoid doing path based
984                    setting of file size if we can do it by handle.
985                    This keeps our caching token (oplock) and avoids timeouts
986                    when the local oplock break takes longer to flush
987                    writebehind data than the SMB timeout for the SetPathInfo
988                    request would allow */
989                 list_for_each(tmp, &cifsInode->openFileList) {
990                         open_file = list_entry(tmp, struct cifsFileInfo,
991                                                flist);
992                         /* We check if file is open for writing first */
993                         if ((open_file->pfile) &&
994                             ((open_file->pfile->f_flags & O_RDWR) ||
995                             (open_file->pfile->f_flags & O_WRONLY))) {
996                                 if (open_file->invalidHandle == FALSE) {
997                                         /* we found a valid, writeable network
998                                            file handle to use to try to set the
999                                            file size */
1000                                         __u16 nfid = open_file->netfid;
1001                                         __u32 npid = open_file->pid;
1002                                         read_unlock(&GlobalSMBSeslock);
1003                                         found = TRUE;
1004                                         rc = CIFSSMBSetFileSize(xid, pTcon,
1005                                                 attrs->ia_size, nfid, npid,
1006                                                 FALSE);
1007                                         cFYI(1, ("SetFileSize by handle "
1008                                                  "(setattrs) rc = %d", rc));
1009                                         /* Do not need reopen and retry on
1010                                            EAGAIN since we will retry by
1011                                            pathname below */
1012
1013                                         /* now that we found one valid file
1014                                            handle no sense continuing to loop
1015                                            trying others, so break here */
1016                                         break;
1017                                 }
1018                         }
1019                 }
1020                 if (found == FALSE)
1021                         read_unlock(&GlobalSMBSeslock);
1022
1023                 if (rc != 0) {
1024                         /* Set file size by pathname rather than by handle
1025                            either because no valid, writeable file handle for
1026                            it was found or because there was an error setting
1027                            it by handle */
1028                         rc = CIFSSMBSetEOF(xid, pTcon, full_path,
1029                                            attrs->ia_size, FALSE,
1030                                            cifs_sb->local_nls, 
1031                                            cifs_sb->mnt_cifs_flags &
1032                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1033                         cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
1034                 }
1035
1036                 /* Server is ok setting allocation size implicitly - no need
1037                    to call:
1038                 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
1039                          cifs_sb->local_nls);
1040                    */
1041
1042                 if (rc == 0) {
1043                         rc = vmtruncate(direntry->d_inode, attrs->ia_size);
1044                         cifs_truncate_page(direntry->d_inode->i_mapping,
1045                                            direntry->d_inode->i_size);
1046                 }
1047         }
1048         if (attrs->ia_valid & ATTR_UID) {
1049                 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
1050                 uid = attrs->ia_uid;
1051                 /* entry->uid = cpu_to_le16(attr->ia_uid); */
1052         }
1053         if (attrs->ia_valid & ATTR_GID) {
1054                 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
1055                 gid = attrs->ia_gid;
1056                 /* entry->gid = cpu_to_le16(attr->ia_gid); */
1057         }
1058
1059         time_buf.Attributes = 0;
1060         if (attrs->ia_valid & ATTR_MODE) {
1061                 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
1062                 mode = attrs->ia_mode;
1063                 /* entry->mode = cpu_to_le16(attr->ia_mode); */
1064         }
1065
1066         if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
1067             && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1068                 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
1069                                          0 /* dev_t */, cifs_sb->local_nls,
1070                                          cifs_sb->mnt_cifs_flags & 
1071                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1072         else if (attrs->ia_valid & ATTR_MODE) {
1073                 if ((mode & S_IWUGO) == 0) /* not writeable */ {
1074                         if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
1075                                 time_buf.Attributes =
1076                                         cpu_to_le32(cifsInode->cifsAttrs |
1077                                                     ATTR_READONLY);
1078                 } else if ((mode & S_IWUGO) == S_IWUGO) {
1079                         if (cifsInode->cifsAttrs & ATTR_READONLY)
1080                                 time_buf.Attributes =
1081                                         cpu_to_le32(cifsInode->cifsAttrs &
1082                                                     (~ATTR_READONLY));
1083                 }
1084                 /* BB to be implemented -
1085                    via Windows security descriptors or streams */
1086                 /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
1087                                       cifs_sb->local_nls); */
1088         }
1089
1090         if (attrs->ia_valid & ATTR_ATIME) {
1091                 set_time = TRUE;
1092                 time_buf.LastAccessTime =
1093                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1094         } else
1095                 time_buf.LastAccessTime = 0;
1096
1097         if (attrs->ia_valid & ATTR_MTIME) {
1098                 set_time = TRUE;
1099                 time_buf.LastWriteTime =
1100                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1101         } else
1102                 time_buf.LastWriteTime = 0;
1103
1104         if (attrs->ia_valid & ATTR_CTIME) {
1105                 set_time = TRUE;
1106                 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
1107                 time_buf.ChangeTime =
1108                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1109         } else
1110                 time_buf.ChangeTime = 0;
1111
1112         if (set_time || time_buf.Attributes) {
1113                 /* BB what if setting one attribute fails (such as size) but
1114                    time setting works? */
1115                 time_buf.CreationTime = 0;      /* do not change */
1116                 /* In the future we should experiment - try setting timestamps
1117                    via Handle (SetFileInfo) instead of by path */
1118                 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1119                         rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
1120                                              cifs_sb->local_nls,
1121                                              cifs_sb->mnt_cifs_flags &
1122                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1123                 else
1124                         rc = -EOPNOTSUPP;
1125
1126                 if (rc == -EOPNOTSUPP) {
1127                         int oplock = FALSE;
1128                         __u16 netfid;
1129
1130                         cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1131                                  "times not supported by this server"));
1132                         /* BB we could scan to see if we already have it open
1133                            and pass in pid of opener to function */
1134                         rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1135                                          SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1136                                          CREATE_NOT_DIR, &netfid, &oplock,
1137                                          NULL, cifs_sb->local_nls,
1138                                          cifs_sb->mnt_cifs_flags &
1139                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1140                         if (rc==0) {
1141                                 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1142                                                          netfid);
1143                                 CIFSSMBClose(xid, pTcon, netfid);
1144                         } else {
1145                         /* BB For even older servers we could convert time_buf
1146                            into old DOS style which uses two second
1147                            granularity */
1148
1149                         /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1150                                         &time_buf, cifs_sb->local_nls); */
1151                         }
1152                 }
1153         }
1154
1155         /* do not need local check to inode_check_ok since the server does
1156            that */
1157         if (!rc)
1158                 rc = inode_setattr(direntry->d_inode, attrs);
1159         kfree(full_path);
1160         FreeXid(xid);
1161         return rc;
1162 }
1163
1164 void cifs_delete_inode(struct inode *inode)
1165 {
1166         cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
1167         /* may have to add back in if and when safe distributed caching of
1168            directories added e.g. via FindNotify */
1169 }