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