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