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