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