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