[PATCH] cifs: character mapping of special characters (part 3 of 3)
[sfrench/cifs-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);
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                 direntry->d_inode->i_nlink--;
426         } else if (rc == -ENOENT) {
427                 d_drop(direntry);
428         } else if (rc == -ETXTBSY) {
429                 int oplock = FALSE;
430                 __u16 netfid;
431
432                 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
433                                  CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
434                                  &netfid, &oplock, NULL, cifs_sb->local_nls,
435                                  cifs_sb->mnt_cifs_flags & 
436                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
437                 if (rc==0) {
438                         CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
439                                               cifs_sb->local_nls, 
440                                               cifs_sb->mnt_cifs_flags & 
441                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
442                         CIFSSMBClose(xid, pTcon, netfid);
443                         direntry->d_inode->i_nlink--;
444                 }
445         } else if (rc == -EACCES) {
446                 /* try only if r/o attribute set in local lookup data? */
447                 pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
448                 if (pinfo_buf) {
449                         memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
450                         /* ATTRS set to normal clears r/o bit */
451                         pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
452                         if (!(pTcon->ses->flags & CIFS_SES_NT4))
453                                 rc = CIFSSMBSetTimes(xid, pTcon, full_path,
454                                                      pinfo_buf,
455                                                      cifs_sb->local_nls,
456                                                      cifs_sb->mnt_cifs_flags & 
457                                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
458                         else
459                                 rc = -EOPNOTSUPP;
460
461                         if (rc == -EOPNOTSUPP) {
462                                 int oplock = FALSE;
463                                 __u16 netfid;
464                         /*      rc = CIFSSMBSetAttrLegacy(xid, pTcon,
465                                                           full_path,
466                                                           (__u16)ATTR_NORMAL,
467                                                           cifs_sb->local_nls); 
468                            For some strange reason it seems that NT4 eats the
469                            old setattr call without actually setting the
470                            attributes so on to the third attempted workaround
471                            */
472
473                         /* BB could scan to see if we already have it open
474                            and pass in pid of opener to function */
475                                 rc = CIFSSMBOpen(xid, pTcon, full_path,
476                                                  FILE_OPEN, SYNCHRONIZE |
477                                                  FILE_WRITE_ATTRIBUTES, 0,
478                                                  &netfid, &oplock, NULL,
479                                                  cifs_sb->local_nls,
480                                                  cifs_sb->mnt_cifs_flags & 
481                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
482                                 if (rc==0) {
483                                         rc = CIFSSMBSetFileTimes(xid, pTcon,
484                                                                  pinfo_buf,
485                                                                  netfid);
486                                         CIFSSMBClose(xid, pTcon, netfid);
487                                 }
488                         }
489                         kfree(pinfo_buf);
490                 }
491                 if (rc==0) {
492                         rc = CIFSSMBDelFile(xid, pTcon, full_path, 
493                                             cifs_sb->local_nls, 
494                                             cifs_sb->mnt_cifs_flags & 
495                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
496                         if (!rc) {
497                                 direntry->d_inode->i_nlink--;
498                         } else if (rc == -ETXTBSY) {
499                                 int oplock = FALSE;
500                                 __u16 netfid;
501
502                                 rc = CIFSSMBOpen(xid, pTcon, full_path,
503                                                  FILE_OPEN, DELETE,
504                                                  CREATE_NOT_DIR |
505                                                  CREATE_DELETE_ON_CLOSE,
506                                                  &netfid, &oplock, NULL,
507                                                  cifs_sb->local_nls, 
508                                                  cifs_sb->mnt_cifs_flags & 
509                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
510                                 if (rc==0) {
511                                         CIFSSMBRenameOpenFile(xid, pTcon,
512                                                 netfid, NULL,
513                                                 cifs_sb->local_nls,
514                                                 cifs_sb->mnt_cifs_flags &
515                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
516                                         CIFSSMBClose(xid, pTcon, netfid);
517                                         direntry->d_inode->i_nlink--;
518                                 }
519                         /* BB if rc = -ETXTBUSY goto the rename logic BB */
520                         }
521                 }
522         }
523         cifsInode = CIFS_I(direntry->d_inode);
524         cifsInode->time = 0;    /* will force revalidate to get info when
525                                    needed */
526         direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
527                 current_fs_time(inode->i_sb);
528         cifsInode = CIFS_I(inode);
529         cifsInode->time = 0;    /* force revalidate of dir as well */
530
531         kfree(full_path);
532         FreeXid(xid);
533         return rc;
534 }
535
536 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
537 {
538         int rc = 0;
539         int xid;
540         struct cifs_sb_info *cifs_sb;
541         struct cifsTconInfo *pTcon;
542         char *full_path = NULL;
543         struct inode *newinode = NULL;
544
545         cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
546
547         xid = GetXid();
548
549         cifs_sb = CIFS_SB(inode->i_sb);
550         pTcon = cifs_sb->tcon;
551
552         down(&inode->i_sb->s_vfs_rename_sem);
553         full_path = build_path_from_dentry(direntry);
554         up(&inode->i_sb->s_vfs_rename_sem);
555         if (full_path == NULL) {
556                 FreeXid(xid);
557                 return -ENOMEM;
558         }
559         /* BB add setting the equivalent of mode via CreateX w/ACLs */
560         rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
561                           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
562         if (rc) {
563                 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
564                 d_drop(direntry);
565         } else {
566                 inode->i_nlink++;
567                 if (pTcon->ses->capabilities & CAP_UNIX)
568                         rc = cifs_get_inode_info_unix(&newinode, full_path,
569                                                       inode->i_sb,xid);
570                 else
571                         rc = cifs_get_inode_info(&newinode, full_path, NULL,
572                                                  inode->i_sb,xid);
573
574                 direntry->d_op = &cifs_dentry_ops;
575                 d_instantiate(direntry, newinode);
576                 if (direntry->d_inode)
577                         direntry->d_inode->i_nlink = 2;
578                 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
579                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
580                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
581                                                     mode,
582                                                     (__u64)current->euid,
583                                                     (__u64)current->egid,
584                                                     0 /* dev_t */,
585                                                     cifs_sb->local_nls,
586                                                     cifs_sb->mnt_cifs_flags &
587                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
588                         } else {
589                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
590                                                     mode, (__u64)-1,
591                                                     (__u64)-1, 0 /* dev_t */,
592                                                     cifs_sb->local_nls,
593                                                     cifs_sb->mnt_cifs_flags & 
594                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
595                         }
596                 else {
597                         /* BB to be implemented via Windows secrty descriptors
598                            eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
599                                                  -1, -1, local_nls); */
600                 }
601         }
602         kfree(full_path);
603         FreeXid(xid);
604         return rc;
605 }
606
607 int cifs_rmdir(struct inode *inode, struct dentry *direntry)
608 {
609         int rc = 0;
610         int xid;
611         struct cifs_sb_info *cifs_sb;
612         struct cifsTconInfo *pTcon;
613         char *full_path = NULL;
614         struct cifsInodeInfo *cifsInode;
615
616         cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
617
618         xid = GetXid();
619
620         cifs_sb = CIFS_SB(inode->i_sb);
621         pTcon = cifs_sb->tcon;
622
623         down(&inode->i_sb->s_vfs_rename_sem);
624         full_path = build_path_from_dentry(direntry);
625         up(&inode->i_sb->s_vfs_rename_sem);
626         if (full_path == NULL) {
627                 FreeXid(xid);
628                 return -ENOMEM;
629         }
630
631         rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
632                           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
633
634         if (!rc) {
635                 inode->i_nlink--;
636                 i_size_write(direntry->d_inode,0);
637                 direntry->d_inode->i_nlink = 0;
638         }
639
640         cifsInode = CIFS_I(direntry->d_inode);
641         cifsInode->time = 0;    /* force revalidate to go get info when
642                                    needed */
643         direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
644                 current_fs_time(inode->i_sb);
645
646         kfree(full_path);
647         FreeXid(xid);
648         return rc;
649 }
650
651 int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
652         struct inode *target_inode, struct dentry *target_direntry)
653 {
654         char *fromName;
655         char *toName;
656         struct cifs_sb_info *cifs_sb_source;
657         struct cifs_sb_info *cifs_sb_target;
658         struct cifsTconInfo *pTcon;
659         int xid;
660         int rc = 0;
661
662         xid = GetXid();
663
664         cifs_sb_target = CIFS_SB(target_inode->i_sb);
665         cifs_sb_source = CIFS_SB(source_inode->i_sb);
666         pTcon = cifs_sb_source->tcon;
667
668         if (pTcon != cifs_sb_target->tcon) {
669                 FreeXid(xid);
670                 return -EXDEV;  /* BB actually could be allowed if same server,
671                                    but different share.
672                                    Might eventually add support for this */
673         }
674
675         /* we already  have the rename sem so we do not need to grab it again
676            here to protect the path integrity */
677         fromName = build_path_from_dentry(source_direntry);
678         toName = build_path_from_dentry(target_direntry);
679         if ((fromName == NULL) || (toName == NULL)) {
680                 rc = -ENOMEM;
681                 goto cifs_rename_exit;
682         }
683
684         rc = CIFSSMBRename(xid, pTcon, fromName, toName,
685                            cifs_sb_source->local_nls,
686                            cifs_sb_source->mnt_cifs_flags &
687                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
688         if (rc == -EEXIST) {
689                 /* check if they are the same file because rename of hardlinked
690                    files is a noop */
691                 FILE_UNIX_BASIC_INFO *info_buf_source;
692                 FILE_UNIX_BASIC_INFO *info_buf_target;
693
694                 info_buf_source =
695                         kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
696                 if (info_buf_source != NULL) {
697                         info_buf_target = info_buf_source + 1;
698                         rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
699                                 info_buf_source, cifs_sb_source->local_nls, 
700                                 cifs_sb_source->mnt_cifs_flags &
701                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
702                         if (rc == 0) {
703                                 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
704                                                 info_buf_target,
705                                                 cifs_sb_target->local_nls,
706                                                 /* remap based on source sb */
707                                                 cifs_sb_source->mnt_cifs_flags &
708                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
709                         }
710                         if ((rc == 0) &&
711                             (info_buf_source->UniqueId ==
712                              info_buf_target->UniqueId)) {
713                         /* do not rename since the files are hardlinked which
714                            is a noop */
715                         } else {
716                         /* we either can not tell the files are hardlinked
717                            (as with Windows servers) or files are not
718                            hardlinked so delete the target manually before
719                            renaming to follow POSIX rather than Windows
720                            semantics */
721                                 cifs_unlink(target_inode, target_direntry);
722                                 rc = CIFSSMBRename(xid, pTcon, fromName,
723                                                    toName,
724                                                    cifs_sb_source->local_nls,
725                                                    cifs_sb_source->mnt_cifs_flags
726                                                    & CIFS_MOUNT_MAP_SPECIAL_CHR);
727                         }
728                         kfree(info_buf_source);
729                 } /* if we can not get memory just leave rc as EEXIST */
730         }
731
732         if (rc) {
733                 cFYI(1, ("rename rc %d", rc));
734         }
735
736         if ((rc == -EIO) || (rc == -EEXIST)) {
737                 int oplock = FALSE;
738                 __u16 netfid;
739
740                 /* BB FIXME Is Generic Read correct for rename? */
741                 /* if renaming directory - we should not say CREATE_NOT_DIR,
742                    need to test renaming open directory, also GENERIC_READ
743                    might not right be right access to request */
744                 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
745                                  CREATE_NOT_DIR, &netfid, &oplock, NULL,
746                                  cifs_sb_source->local_nls, 
747                                  cifs_sb_source->mnt_cifs_flags & 
748                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
749                 if (rc==0) {
750                         CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
751                                               cifs_sb_source->local_nls, 
752                                               cifs_sb_source->mnt_cifs_flags &
753                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
754                         CIFSSMBClose(xid, pTcon, netfid);
755                 }
756         }
757
758 cifs_rename_exit:
759         kfree(fromName);
760         kfree(toName);
761         FreeXid(xid);
762         return rc;
763 }
764
765 int cifs_revalidate(struct dentry *direntry)
766 {
767         int xid;
768         int rc = 0;
769         char *full_path;
770         struct cifs_sb_info *cifs_sb;
771         struct cifsInodeInfo *cifsInode;
772         loff_t local_size;
773         struct timespec local_mtime;
774         int invalidate_inode = FALSE;
775
776         if (direntry->d_inode == NULL)
777                 return -ENOENT;
778
779         cifsInode = CIFS_I(direntry->d_inode);
780
781         if (cifsInode == NULL)
782                 return -ENOENT;
783
784         /* no sense revalidating inode info on file that no one can write */
785         if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
786                 return rc;
787
788         xid = GetXid();
789
790         cifs_sb = CIFS_SB(direntry->d_sb);
791
792         /* can not safely grab the rename sem here if rename calls revalidate
793            since that would deadlock */
794         full_path = build_path_from_dentry(direntry);
795         if (full_path == NULL) {
796                 FreeXid(xid);
797                 return -ENOMEM;
798         }
799         cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
800                  "jiffies %ld", full_path, direntry->d_inode,
801                  direntry->d_inode->i_count.counter, direntry,
802                  direntry->d_time, jiffies));
803
804         if (cifsInode->time == 0) {
805                 /* was set to zero previously to force revalidate */
806         } else if (time_before(jiffies, cifsInode->time + HZ) &&
807                    lookupCacheEnabled) {
808                 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
809                     (direntry->d_inode->i_nlink == 1)) {
810                         kfree(full_path);
811                         FreeXid(xid);
812                         return rc;
813                 } else {
814                         cFYI(1, ("Have to revalidate file due to hardlinks"));
815                 }
816         }
817
818         /* save mtime and size */
819         local_mtime = direntry->d_inode->i_mtime;
820         local_size = direntry->d_inode->i_size;
821
822         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
823                 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
824                                               direntry->d_sb,xid);
825                 if (rc) {
826                         cFYI(1, ("error on getting revalidate info %d", rc));
827 /*                      if (rc != -ENOENT)
828                                 rc = 0; */      /* BB should we cache info on
829                                                    certain errors? */
830                 }
831         } else {
832                 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
833                                          direntry->d_sb,xid);
834                 if (rc) {
835                         cFYI(1, ("error on getting revalidate info %d", rc));
836 /*                      if (rc != -ENOENT)
837                                 rc = 0; */      /* BB should we cache info on
838                                                    certain errors? */
839                 }
840         }
841         /* should we remap certain errors, access denied?, to zero */
842
843         /* if not oplocked, we invalidate inode pages if mtime or file size
844            had changed on server */
845
846         if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
847             (local_size == direntry->d_inode->i_size)) {
848                 cFYI(1, ("cifs_revalidate - inode unchanged"));
849         } else {
850                 /* file may have changed on server */
851                 if (cifsInode->clientCanCacheRead) {
852                         /* no need to invalidate inode pages since we were the
853                            only ones who could have modified the file and the
854                            server copy is staler than ours */
855                 } else {
856                         invalidate_inode = TRUE;
857                 }
858         }
859
860         /* can not grab this sem since kernel filesys locking documentation
861            indicates i_sem may be taken by the kernel on lookup and rename
862            which could deadlock if we grab the i_sem here as well */
863 /*      down(&direntry->d_inode->i_sem);*/
864         /* need to write out dirty pages here  */
865         if (direntry->d_inode->i_mapping) {
866                 /* do we need to lock inode until after invalidate completes
867                    below? */
868                 filemap_fdatawrite(direntry->d_inode->i_mapping);
869         }
870         if (invalidate_inode) {
871                 if (direntry->d_inode->i_mapping)
872                         filemap_fdatawait(direntry->d_inode->i_mapping);
873                 /* may eventually have to do this for open files too */
874                 if (list_empty(&(cifsInode->openFileList))) {
875                         /* Has changed on server - flush read ahead pages */
876                         cFYI(1, ("Invalidating read ahead data on "
877                                  "closed file"));
878                         invalidate_remote_inode(direntry->d_inode);
879                 }
880         }
881 /*      up(&direntry->d_inode->i_sem); */
882         
883         kfree(full_path);
884         FreeXid(xid);
885         return rc;
886 }
887
888 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
889         struct kstat *stat)
890 {
891         int err = cifs_revalidate(dentry);
892         if (!err)
893                 generic_fillattr(dentry->d_inode, stat);
894         return err;
895 }
896
897 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
898 {
899         pgoff_t index = from >> PAGE_CACHE_SHIFT;
900         unsigned offset = from & (PAGE_CACHE_SIZE - 1);
901         struct page *page;
902         char *kaddr;
903         int rc = 0;
904
905         page = grab_cache_page(mapping, index);
906         if (!page)
907                 return -ENOMEM;
908
909         kaddr = kmap_atomic(page, KM_USER0);
910         memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
911         flush_dcache_page(page);
912         kunmap_atomic(kaddr, KM_USER0);
913         unlock_page(page);
914         page_cache_release(page);
915         return rc;
916 }
917
918 int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
919 {
920         int xid;
921         struct cifs_sb_info *cifs_sb;
922         struct cifsTconInfo *pTcon;
923         char *full_path = NULL;
924         int rc = -EACCES;
925         int found = FALSE;
926         struct cifsFileInfo *open_file = NULL;
927         FILE_BASIC_INFO time_buf;
928         int set_time = FALSE;
929         __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
930         __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
931         __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
932         struct cifsInodeInfo *cifsInode;
933         struct list_head *tmp;
934
935         xid = GetXid();
936
937         cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
938                  direntry->d_name.name, attrs->ia_valid));
939         cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
940         pTcon = cifs_sb->tcon;
941
942         down(&direntry->d_sb->s_vfs_rename_sem);
943         full_path = build_path_from_dentry(direntry);
944         up(&direntry->d_sb->s_vfs_rename_sem);
945         if (full_path == NULL) {
946                 FreeXid(xid);
947                 return -ENOMEM;
948         }
949         cifsInode = CIFS_I(direntry->d_inode);
950
951         /* BB check if we need to refresh inode from server now ? BB */
952
953         /* need to flush data before changing file size on server */
954         filemap_fdatawrite(direntry->d_inode->i_mapping);
955         filemap_fdatawait(direntry->d_inode->i_mapping);
956
957         if (attrs->ia_valid & ATTR_SIZE) {
958                 read_lock(&GlobalSMBSeslock);
959                 /* To avoid spurious oplock breaks from server, in the case of
960                    inodes that we already have open, avoid doing path based
961                    setting of file size if we can do it by handle.
962                    This keeps our caching token (oplock) and avoids timeouts
963                    when the local oplock break takes longer to flush
964                    writebehind data than the SMB timeout for the SetPathInfo
965                    request would allow */
966                 list_for_each(tmp, &cifsInode->openFileList) {
967                         open_file = list_entry(tmp, struct cifsFileInfo,
968                                                flist);
969                         /* We check if file is open for writing first */
970                         if ((open_file->pfile) &&
971                             ((open_file->pfile->f_flags & O_RDWR) ||
972                             (open_file->pfile->f_flags & O_WRONLY))) {
973                                 if (open_file->invalidHandle == FALSE) {
974                                         /* we found a valid, writeable network
975                                            file handle to use to try to set the
976                                            file size */
977                                         __u16 nfid = open_file->netfid;
978                                         __u32 npid = open_file->pid;
979                                         read_unlock(&GlobalSMBSeslock);
980                                         found = TRUE;
981                                         rc = CIFSSMBSetFileSize(xid, pTcon,
982                                                 attrs->ia_size, nfid, npid,
983                                                 FALSE);
984                                         cFYI(1, ("SetFileSize by handle "
985                                                  "(setattrs) rc = %d", rc));
986                                         /* Do not need reopen and retry on
987                                            EAGAIN since we will retry by
988                                            pathname below */
989
990                                         /* now that we found one valid file
991                                            handle no sense continuing to loop
992                                            trying others, so break here */
993                                         break;
994                                 }
995                         }
996                 }
997                 if (found == FALSE)
998                         read_unlock(&GlobalSMBSeslock);
999
1000                 if (rc != 0) {
1001                         /* Set file size by pathname rather than by handle
1002                            either because no valid, writeable file handle for
1003                            it was found or because there was an error setting
1004                            it by handle */
1005                         rc = CIFSSMBSetEOF(xid, pTcon, full_path,
1006                                            attrs->ia_size, FALSE,
1007                                            cifs_sb->local_nls, 
1008                                            cifs_sb->mnt_cifs_flags &
1009                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1010                         cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
1011                 }
1012
1013                 /* Server is ok setting allocation size implicitly - no need
1014                    to call:
1015                 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
1016                          cifs_sb->local_nls);
1017                    */
1018
1019                 if (rc == 0) {
1020                         rc = vmtruncate(direntry->d_inode, attrs->ia_size);
1021                         cifs_truncate_page(direntry->d_inode->i_mapping,
1022                                            direntry->d_inode->i_size);
1023                 }
1024         }
1025         if (attrs->ia_valid & ATTR_UID) {
1026                 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
1027                 uid = attrs->ia_uid;
1028                 /* entry->uid = cpu_to_le16(attr->ia_uid); */
1029         }
1030         if (attrs->ia_valid & ATTR_GID) {
1031                 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
1032                 gid = attrs->ia_gid;
1033                 /* entry->gid = cpu_to_le16(attr->ia_gid); */
1034         }
1035
1036         time_buf.Attributes = 0;
1037         if (attrs->ia_valid & ATTR_MODE) {
1038                 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
1039                 mode = attrs->ia_mode;
1040                 /* entry->mode = cpu_to_le16(attr->ia_mode); */
1041         }
1042
1043         if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
1044             && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1045                 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
1046                                          0 /* dev_t */, cifs_sb->local_nls,
1047                                          cifs_sb->mnt_cifs_flags & 
1048                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1049         else if (attrs->ia_valid & ATTR_MODE) {
1050                 if ((mode & S_IWUGO) == 0) /* not writeable */ {
1051                         if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
1052                                 time_buf.Attributes =
1053                                         cpu_to_le32(cifsInode->cifsAttrs |
1054                                                     ATTR_READONLY);
1055                 } else if ((mode & S_IWUGO) == S_IWUGO) {
1056                         if (cifsInode->cifsAttrs & ATTR_READONLY)
1057                                 time_buf.Attributes =
1058                                         cpu_to_le32(cifsInode->cifsAttrs &
1059                                                     (~ATTR_READONLY));
1060                 }
1061                 /* BB to be implemented -
1062                    via Windows security descriptors or streams */
1063                 /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
1064                                       cifs_sb->local_nls); */
1065         }
1066
1067         if (attrs->ia_valid & ATTR_ATIME) {
1068                 set_time = TRUE;
1069                 time_buf.LastAccessTime =
1070                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1071         } else
1072                 time_buf.LastAccessTime = 0;
1073
1074         if (attrs->ia_valid & ATTR_MTIME) {
1075                 set_time = TRUE;
1076                 time_buf.LastWriteTime =
1077                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1078         } else
1079                 time_buf.LastWriteTime = 0;
1080
1081         if (attrs->ia_valid & ATTR_CTIME) {
1082                 set_time = TRUE;
1083                 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
1084                 time_buf.ChangeTime =
1085                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1086         } else
1087                 time_buf.ChangeTime = 0;
1088
1089         if (set_time || time_buf.Attributes) {
1090                 /* BB what if setting one attribute fails (such as size) but
1091                    time setting works? */
1092                 time_buf.CreationTime = 0;      /* do not change */
1093                 /* In the future we should experiment - try setting timestamps
1094                    via Handle (SetFileInfo) instead of by path */
1095                 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1096                         rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
1097                                              cifs_sb->local_nls,
1098                                              cifs_sb->mnt_cifs_flags &
1099                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1100                 else
1101                         rc = -EOPNOTSUPP;
1102
1103                 if (rc == -EOPNOTSUPP) {
1104                         int oplock = FALSE;
1105                         __u16 netfid;
1106
1107                         cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1108                                  "times not supported by this server"));
1109                         /* BB we could scan to see if we already have it open
1110                            and pass in pid of opener to function */
1111                         rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1112                                          SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1113                                          CREATE_NOT_DIR, &netfid, &oplock,
1114                                          NULL, cifs_sb->local_nls,
1115                                          cifs_sb->mnt_cifs_flags &
1116                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1117                         if (rc==0) {
1118                                 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1119                                                          netfid);
1120                                 CIFSSMBClose(xid, pTcon, netfid);
1121                         } else {
1122                         /* BB For even older servers we could convert time_buf
1123                            into old DOS style which uses two second
1124                            granularity */
1125
1126                         /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1127                                         &time_buf, cifs_sb->local_nls); */
1128                         }
1129                 }
1130         }
1131
1132         /* do not need local check to inode_check_ok since the server does
1133            that */
1134         if (!rc)
1135                 rc = inode_setattr(direntry->d_inode, attrs);
1136         kfree(full_path);
1137         FreeXid(xid);
1138         return rc;
1139 }
1140
1141 void cifs_delete_inode(struct inode *inode)
1142 {
1143         cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
1144         /* may have to add back in if and when safe distributed caching of
1145            directories added e.g. via FindNotify */
1146 }