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