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