]> err.no Git - linux-2.6/blob - fs/cifs/inode.c
[CIFS] New CIFS POSIX mkdir performance improvement
[linux-2.6] / fs / cifs / inode.c
1 /*
2  *   fs/cifs/inode.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2007
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 static void posix_fill_in_inode(struct inode *tmp_inode,
738         FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
739 {
740         loff_t local_size;
741         struct timespec local_mtime;
742
743         struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
744         struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
745
746         __u32 type = le32_to_cpu(pData->Type);
747         __u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
748         __u64 end_of_file = le64_to_cpu(pData->EndOfFile);
749         cifsInfo->time = jiffies;
750         atomic_inc(&cifsInfo->inUse);
751
752         /* save mtime and size */
753         local_mtime = tmp_inode->i_mtime;
754         local_size  = tmp_inode->i_size;
755
756         tmp_inode->i_atime =
757             cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
758         tmp_inode->i_mtime =
759             cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
760         tmp_inode->i_ctime =
761             cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));
762
763         tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
764         /* since we set the inode type below we need to mask off type
765            to avoid strange results if bits above were corrupt */
766         tmp_inode->i_mode &= ~S_IFMT;
767         if (type == UNIX_FILE) {
768                 *pobject_type = DT_REG;
769                 tmp_inode->i_mode |= S_IFREG;
770         } else if (type == UNIX_SYMLINK) {
771                 *pobject_type = DT_LNK;
772                 tmp_inode->i_mode |= S_IFLNK;
773         } else if (type == UNIX_DIR) {
774                 *pobject_type = DT_DIR;
775                 tmp_inode->i_mode |= S_IFDIR;
776         } else if (type == UNIX_CHARDEV) {
777                 *pobject_type = DT_CHR;
778                 tmp_inode->i_mode |= S_IFCHR;
779                 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
780                                 le64_to_cpu(pData->DevMinor) & MINORMASK);
781         } else if (type == UNIX_BLOCKDEV) {
782                 *pobject_type = DT_BLK;
783                 tmp_inode->i_mode |= S_IFBLK;
784                 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
785                                 le64_to_cpu(pData->DevMinor) & MINORMASK);
786         } else if (type == UNIX_FIFO) {
787                 *pobject_type = DT_FIFO;
788                 tmp_inode->i_mode |= S_IFIFO;
789         } else if (type == UNIX_SOCKET) {
790                 *pobject_type = DT_SOCK;
791                 tmp_inode->i_mode |= S_IFSOCK;
792         } else {
793                 /* safest to just call it a file */
794                 *pobject_type = DT_REG;
795                 tmp_inode->i_mode |= S_IFREG;
796                 cFYI(1,("unknown inode type %d",type)); 
797         }
798
799         tmp_inode->i_uid = le64_to_cpu(pData->Uid);
800         tmp_inode->i_gid = le64_to_cpu(pData->Gid);
801         tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);
802
803         spin_lock(&tmp_inode->i_lock);
804         if (is_size_safe_to_change(cifsInfo, end_of_file)) {
805                 /* can not safely change the file size here if the 
806                 client is writing to it due to potential races */
807                 i_size_write(tmp_inode, end_of_file);
808
809         /* 512 bytes (2**9) is the fake blocksize that must be used */
810         /* for this calculation, not the real blocksize */
811                 tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
812         }
813         spin_unlock(&tmp_inode->i_lock);
814
815         if (S_ISREG(tmp_inode->i_mode)) {
816                 cFYI(1, ("File inode"));
817                 tmp_inode->i_op = &cifs_file_inode_ops;
818
819                 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
820                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
821                                 tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
822                         else
823                                 tmp_inode->i_fop = &cifs_file_direct_ops;
824                 
825                 } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
826                         tmp_inode->i_fop = &cifs_file_nobrl_ops;
827                 else
828                         tmp_inode->i_fop = &cifs_file_ops;
829
830                 if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
831                    (cifs_sb->tcon->ses->server->maxBuf < 
832                         PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
833                         tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
834                 else
835                         tmp_inode->i_data.a_ops = &cifs_addr_ops;
836
837                 if(isNewInode)
838                         return; /* No sense invalidating pages for new inode since we
839                                            have not started caching readahead file data yet */
840
841                 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
842                         (local_size == tmp_inode->i_size)) {
843                         cFYI(1, ("inode exists but unchanged"));
844                 } else {
845                         /* file may have changed on server */
846                         cFYI(1, ("invalidate inode, readdir detected change"));
847                         invalidate_remote_inode(tmp_inode);
848                 }
849         } else if (S_ISDIR(tmp_inode->i_mode)) {
850                 cFYI(1, ("Directory inode"));
851                 tmp_inode->i_op = &cifs_dir_inode_ops;
852                 tmp_inode->i_fop = &cifs_dir_ops;
853         } else if (S_ISLNK(tmp_inode->i_mode)) {
854                 cFYI(1, ("Symbolic Link inode"));
855                 tmp_inode->i_op = &cifs_symlink_inode_ops;
856 /* tmp_inode->i_fop = *//* do not need to set to anything */
857         } else {
858                 cFYI(1, ("Special inode")); 
859                 init_special_inode(tmp_inode, tmp_inode->i_mode,
860                                    tmp_inode->i_rdev);
861         }       
862 }
863
864 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
865 {
866         int rc = 0;
867         int xid;
868         struct cifs_sb_info *cifs_sb;
869         struct cifsTconInfo *pTcon;
870         char *full_path = NULL;
871         struct inode *newinode = NULL;
872
873         cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
874
875         xid = GetXid();
876
877         cifs_sb = CIFS_SB(inode->i_sb);
878         pTcon = cifs_sb->tcon;
879
880         full_path = build_path_from_dentry(direntry);
881         if (full_path == NULL) {
882                 FreeXid(xid);
883                 return -ENOMEM;
884         }
885         
886         if((pTcon->ses->capabilities & CAP_UNIX) && 
887                 (CIFS_UNIX_POSIX_PATH_OPS_CAP & 
888                         le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
889                 u32 oplock = 0;
890                 FILE_UNIX_BASIC_INFO * pInfo = 
891                         kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
892                 if(pInfo == NULL) {
893                         rc = -ENOMEM;
894                         goto mkdir_out;
895                 }
896                         
897                 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
898                                 mode, NULL /* netfid */, pInfo, &oplock,
899                                 full_path, cifs_sb->local_nls, 
900                                 cifs_sb->mnt_cifs_flags & 
901                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
902                 if (rc) {
903                         cFYI(1, ("posix mkdir returned 0x%x", rc));
904                         d_drop(direntry);
905                 } else {
906                         if (pInfo->Type == -1) /* no return info - go query */
907                                 goto mkdir_get_info; 
908 /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
909                         inc_nlink(inode);
910                         if (pTcon->nocase)
911                                 direntry->d_op = &cifs_ci_dentry_ops;
912                         else
913                                 direntry->d_op = &cifs_dentry_ops;
914                         d_instantiate(direntry, newinode);
915                         if (direntry->d_inode) {
916                                 int obj_type;
917                                 direntry->d_inode->i_nlink = 2;
918                                 /* already checked in POSIXCreate whether
919                                 frame was long enough */
920                                 posix_fill_in_inode(direntry->d_inode,
921                                         pInfo, &obj_type, 1 /* NewInode */);
922                                 /* could double check that we actually
923                                  * created what we thought we did ie
924                                  * a directory
925                                  */     
926                         }
927                 }
928                 kfree(pInfo);
929                 goto mkdir_out;
930         }       
931         
932         /* BB add setting the equivalent of mode via CreateX w/ACLs */
933         rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
934                           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
935         if (rc) {
936                 cFYI(1, ("cifs_mkdir returned 0x%x", rc));
937                 d_drop(direntry);
938         } else {
939 mkdir_get_info:         
940                 inc_nlink(inode);
941                 if (pTcon->ses->capabilities & CAP_UNIX)
942                         rc = cifs_get_inode_info_unix(&newinode, full_path,
943                                                       inode->i_sb,xid);
944                 else
945                         rc = cifs_get_inode_info(&newinode, full_path, NULL,
946                                                  inode->i_sb,xid);
947
948                 if (pTcon->nocase)
949                         direntry->d_op = &cifs_ci_dentry_ops;
950                 else
951                         direntry->d_op = &cifs_dentry_ops;
952                 d_instantiate(direntry, newinode);
953                  /* setting nlink not necessary except in cases where we
954                   * failed to get it from the server or was set bogus */ 
955                 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
956                                 direntry->d_inode->i_nlink = 2; 
957                 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
958                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
959                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
960                                                     mode,
961                                                     (__u64)current->fsuid,
962                                                     (__u64)current->fsgid,
963                                                     0 /* dev_t */,
964                                                     cifs_sb->local_nls,
965                                                     cifs_sb->mnt_cifs_flags &
966                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
967                         } else {
968                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
969                                                     mode, (__u64)-1,
970                                                     (__u64)-1, 0 /* dev_t */,
971                                                     cifs_sb->local_nls,
972                                                     cifs_sb->mnt_cifs_flags & 
973                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
974                         }
975                 else {
976                         /* BB to be implemented via Windows secrty descriptors
977                            eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
978                                                  -1, -1, local_nls); */
979                         if(direntry->d_inode) {
980                                 direntry->d_inode->i_mode = mode;
981                                 direntry->d_inode->i_mode |= S_IFDIR;
982                                 if(cifs_sb->mnt_cifs_flags & 
983                                      CIFS_MOUNT_SET_UID) {
984                                         direntry->d_inode->i_uid = 
985                                                 current->fsuid;
986                                         direntry->d_inode->i_gid = 
987                                                 current->fsgid;
988                                 }
989                         }
990                 }
991         }
992 mkdir_out:      
993         kfree(full_path);
994         FreeXid(xid);
995         return rc;
996 }
997
998 int cifs_rmdir(struct inode *inode, struct dentry *direntry)
999 {
1000         int rc = 0;
1001         int xid;
1002         struct cifs_sb_info *cifs_sb;
1003         struct cifsTconInfo *pTcon;
1004         char *full_path = NULL;
1005         struct cifsInodeInfo *cifsInode;
1006
1007         cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
1008
1009         xid = GetXid();
1010
1011         cifs_sb = CIFS_SB(inode->i_sb);
1012         pTcon = cifs_sb->tcon;
1013
1014         full_path = build_path_from_dentry(direntry);
1015         if (full_path == NULL) {
1016                 FreeXid(xid);
1017                 return -ENOMEM;
1018         }
1019
1020         rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1021                           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1022
1023         if (!rc) {
1024                 drop_nlink(inode);
1025                 spin_lock(&direntry->d_inode->i_lock);
1026                 i_size_write(direntry->d_inode,0);
1027                 clear_nlink(direntry->d_inode);
1028                 spin_unlock(&direntry->d_inode->i_lock);
1029         }
1030
1031         cifsInode = CIFS_I(direntry->d_inode);
1032         cifsInode->time = 0;    /* force revalidate to go get info when
1033                                    needed */
1034         direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1035                 current_fs_time(inode->i_sb);
1036
1037         kfree(full_path);
1038         FreeXid(xid);
1039         return rc;
1040 }
1041
1042 int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
1043         struct inode *target_inode, struct dentry *target_direntry)
1044 {
1045         char *fromName;
1046         char *toName;
1047         struct cifs_sb_info *cifs_sb_source;
1048         struct cifs_sb_info *cifs_sb_target;
1049         struct cifsTconInfo *pTcon;
1050         int xid;
1051         int rc = 0;
1052
1053         xid = GetXid();
1054
1055         cifs_sb_target = CIFS_SB(target_inode->i_sb);
1056         cifs_sb_source = CIFS_SB(source_inode->i_sb);
1057         pTcon = cifs_sb_source->tcon;
1058
1059         if (pTcon != cifs_sb_target->tcon) {
1060                 FreeXid(xid);
1061                 return -EXDEV;  /* BB actually could be allowed if same server,
1062                                    but different share.
1063                                    Might eventually add support for this */
1064         }
1065
1066         /* we already  have the rename sem so we do not need to grab it again
1067            here to protect the path integrity */
1068         fromName = build_path_from_dentry(source_direntry);
1069         toName = build_path_from_dentry(target_direntry);
1070         if ((fromName == NULL) || (toName == NULL)) {
1071                 rc = -ENOMEM;
1072                 goto cifs_rename_exit;
1073         }
1074
1075         rc = CIFSSMBRename(xid, pTcon, fromName, toName,
1076                            cifs_sb_source->local_nls,
1077                            cifs_sb_source->mnt_cifs_flags &
1078                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1079         if (rc == -EEXIST) {
1080                 /* check if they are the same file because rename of hardlinked
1081                    files is a noop */
1082                 FILE_UNIX_BASIC_INFO *info_buf_source;
1083                 FILE_UNIX_BASIC_INFO *info_buf_target;
1084
1085                 info_buf_source =
1086                         kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
1087                 if (info_buf_source != NULL) {
1088                         info_buf_target = info_buf_source + 1;
1089                         if (pTcon->ses->capabilities & CAP_UNIX)
1090                                 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
1091                                         info_buf_source, 
1092                                         cifs_sb_source->local_nls,
1093                                         cifs_sb_source->mnt_cifs_flags &
1094                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1095                         /* else rc is still EEXIST so will fall through to
1096                            unlink the target and retry rename */
1097                         if (rc == 0) {
1098                                 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
1099                                                 info_buf_target,
1100                                                 cifs_sb_target->local_nls,
1101                                                 /* remap based on source sb */
1102                                                 cifs_sb_source->mnt_cifs_flags &
1103                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
1104                         }
1105                         if ((rc == 0) &&
1106                             (info_buf_source->UniqueId ==
1107                              info_buf_target->UniqueId)) {
1108                         /* do not rename since the files are hardlinked which
1109                            is a noop */
1110                         } else {
1111                         /* we either can not tell the files are hardlinked
1112                            (as with Windows servers) or files are not
1113                            hardlinked so delete the target manually before
1114                            renaming to follow POSIX rather than Windows
1115                            semantics */
1116                                 cifs_unlink(target_inode, target_direntry);
1117                                 rc = CIFSSMBRename(xid, pTcon, fromName,
1118                                                    toName,
1119                                                    cifs_sb_source->local_nls,
1120                                                    cifs_sb_source->mnt_cifs_flags
1121                                                    & CIFS_MOUNT_MAP_SPECIAL_CHR);
1122                         }
1123                         kfree(info_buf_source);
1124                 } /* if we can not get memory just leave rc as EEXIST */
1125         }
1126
1127         if (rc) {
1128                 cFYI(1, ("rename rc %d", rc));
1129         }
1130
1131         if ((rc == -EIO) || (rc == -EEXIST)) {
1132                 int oplock = FALSE;
1133                 __u16 netfid;
1134
1135                 /* BB FIXME Is Generic Read correct for rename? */
1136                 /* if renaming directory - we should not say CREATE_NOT_DIR,
1137                    need to test renaming open directory, also GENERIC_READ
1138                    might not right be right access to request */
1139                 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
1140                                  CREATE_NOT_DIR, &netfid, &oplock, NULL,
1141                                  cifs_sb_source->local_nls, 
1142                                  cifs_sb_source->mnt_cifs_flags & 
1143                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
1144                 if (rc==0) {
1145                         rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
1146                                               cifs_sb_source->local_nls, 
1147                                               cifs_sb_source->mnt_cifs_flags &
1148                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1149                         CIFSSMBClose(xid, pTcon, netfid);
1150                 }
1151         }
1152
1153 cifs_rename_exit:
1154         kfree(fromName);
1155         kfree(toName);
1156         FreeXid(xid);
1157         return rc;
1158 }
1159
1160 int cifs_revalidate(struct dentry *direntry)
1161 {
1162         int xid;
1163         int rc = 0;
1164         char *full_path;
1165         struct cifs_sb_info *cifs_sb;
1166         struct cifsInodeInfo *cifsInode;
1167         loff_t local_size;
1168         struct timespec local_mtime;
1169         int invalidate_inode = FALSE;
1170
1171         if (direntry->d_inode == NULL)
1172                 return -ENOENT;
1173
1174         cifsInode = CIFS_I(direntry->d_inode);
1175
1176         if (cifsInode == NULL)
1177                 return -ENOENT;
1178
1179         /* no sense revalidating inode info on file that no one can write */
1180         if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
1181                 return rc;
1182
1183         xid = GetXid();
1184
1185         cifs_sb = CIFS_SB(direntry->d_sb);
1186
1187         /* can not safely grab the rename sem here if rename calls revalidate
1188            since that would deadlock */
1189         full_path = build_path_from_dentry(direntry);
1190         if (full_path == NULL) {
1191                 FreeXid(xid);
1192                 return -ENOMEM;
1193         }
1194         cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
1195                  "jiffies %ld", full_path, direntry->d_inode,
1196                  direntry->d_inode->i_count.counter, direntry,
1197                  direntry->d_time, jiffies));
1198
1199         if (cifsInode->time == 0) {
1200                 /* was set to zero previously to force revalidate */
1201         } else if (time_before(jiffies, cifsInode->time + HZ) &&
1202                    lookupCacheEnabled) {
1203                 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
1204                     (direntry->d_inode->i_nlink == 1)) {
1205                         kfree(full_path);
1206                         FreeXid(xid);
1207                         return rc;
1208                 } else {
1209                         cFYI(1, ("Have to revalidate file due to hardlinks"));
1210                 }
1211         }
1212
1213         /* save mtime and size */
1214         local_mtime = direntry->d_inode->i_mtime;
1215         local_size = direntry->d_inode->i_size;
1216
1217         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
1218                 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
1219                                               direntry->d_sb,xid);
1220                 if (rc) {
1221                         cFYI(1, ("error on getting revalidate info %d", rc));
1222 /*                      if (rc != -ENOENT)
1223                                 rc = 0; */      /* BB should we cache info on
1224                                                    certain errors? */
1225                 }
1226         } else {
1227                 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
1228                                          direntry->d_sb,xid);
1229                 if (rc) {
1230                         cFYI(1, ("error on getting revalidate info %d", rc));
1231 /*                      if (rc != -ENOENT)
1232                                 rc = 0; */      /* BB should we cache info on
1233                                                    certain errors? */
1234                 }
1235         }
1236         /* should we remap certain errors, access denied?, to zero */
1237
1238         /* if not oplocked, we invalidate inode pages if mtime or file size
1239            had changed on server */
1240
1241         if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
1242             (local_size == direntry->d_inode->i_size)) {
1243                 cFYI(1, ("cifs_revalidate - inode unchanged"));
1244         } else {
1245                 /* file may have changed on server */
1246                 if (cifsInode->clientCanCacheRead) {
1247                         /* no need to invalidate inode pages since we were the
1248                            only ones who could have modified the file and the
1249                            server copy is staler than ours */
1250                 } else {
1251                         invalidate_inode = TRUE;
1252                 }
1253         }
1254
1255         /* can not grab this sem since kernel filesys locking documentation
1256            indicates i_mutex may be taken by the kernel on lookup and rename
1257            which could deadlock if we grab the i_mutex here as well */
1258 /*      mutex_lock(&direntry->d_inode->i_mutex);*/
1259         /* need to write out dirty pages here  */
1260         if (direntry->d_inode->i_mapping) {
1261                 /* do we need to lock inode until after invalidate completes
1262                    below? */
1263                 filemap_fdatawrite(direntry->d_inode->i_mapping);
1264         }
1265         if (invalidate_inode) {
1266         /* shrink_dcache not necessary now that cifs dentry ops
1267         are exported for negative dentries */
1268 /*              if(S_ISDIR(direntry->d_inode->i_mode)) 
1269                         shrink_dcache_parent(direntry); */
1270                 if (S_ISREG(direntry->d_inode->i_mode)) {
1271                         if (direntry->d_inode->i_mapping)
1272                                 filemap_fdatawait(direntry->d_inode->i_mapping);
1273                         /* may eventually have to do this for open files too */
1274                         if (list_empty(&(cifsInode->openFileList))) {
1275                                 /* changed on server - flush read ahead pages */
1276                                 cFYI(1, ("Invalidating read ahead data on "
1277                                          "closed file"));
1278                                 invalidate_remote_inode(direntry->d_inode);
1279                         }
1280                 }
1281         }
1282 /*      mutex_unlock(&direntry->d_inode->i_mutex); */
1283         
1284         kfree(full_path);
1285         FreeXid(xid);
1286         return rc;
1287 }
1288
1289 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1290         struct kstat *stat)
1291 {
1292         int err = cifs_revalidate(dentry);
1293         if (!err) {
1294                 generic_fillattr(dentry->d_inode, stat);
1295                 stat->blksize = CIFS_MAX_MSGSIZE;
1296         }
1297         return err;
1298 }
1299
1300 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1301 {
1302         pgoff_t index = from >> PAGE_CACHE_SHIFT;
1303         unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1304         struct page *page;
1305         char *kaddr;
1306         int rc = 0;
1307
1308         page = grab_cache_page(mapping, index);
1309         if (!page)
1310                 return -ENOMEM;
1311
1312         kaddr = kmap_atomic(page, KM_USER0);
1313         memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
1314         flush_dcache_page(page);
1315         kunmap_atomic(kaddr, KM_USER0);
1316         unlock_page(page);
1317         page_cache_release(page);
1318         return rc;
1319 }
1320
1321 static int cifs_vmtruncate(struct inode * inode, loff_t offset)
1322 {
1323         struct address_space *mapping = inode->i_mapping;
1324         unsigned long limit;
1325
1326         spin_lock(&inode->i_lock);
1327         if (inode->i_size < offset)
1328                 goto do_expand;
1329         /*
1330          * truncation of in-use swapfiles is disallowed - it would cause
1331          * subsequent swapout to scribble on the now-freed blocks.
1332          */
1333         if (IS_SWAPFILE(inode)) {
1334                 spin_unlock(&inode->i_lock);
1335                 goto out_busy;
1336         }
1337         i_size_write(inode, offset);
1338         spin_unlock(&inode->i_lock);
1339         unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
1340         truncate_inode_pages(mapping, offset);
1341         goto out_truncate;
1342
1343 do_expand:
1344         limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
1345         if (limit != RLIM_INFINITY && offset > limit) {
1346                 spin_unlock(&inode->i_lock);
1347                 goto out_sig;
1348         }
1349         if (offset > inode->i_sb->s_maxbytes) {
1350                 spin_unlock(&inode->i_lock);
1351                 goto out_big;
1352         }
1353         i_size_write(inode, offset);
1354         spin_unlock(&inode->i_lock);
1355 out_truncate:
1356         if (inode->i_op && inode->i_op->truncate)
1357                 inode->i_op->truncate(inode);
1358         return 0;
1359 out_sig:
1360         send_sig(SIGXFSZ, current, 0);
1361 out_big:
1362         return -EFBIG;
1363 out_busy:
1364         return -ETXTBSY;
1365 }
1366
1367 int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1368 {
1369         int xid;
1370         struct cifs_sb_info *cifs_sb;
1371         struct cifsTconInfo *pTcon;
1372         char *full_path = NULL;
1373         int rc = -EACCES;
1374         struct cifsFileInfo *open_file = NULL;
1375         FILE_BASIC_INFO time_buf;
1376         int set_time = FALSE;
1377         int set_dosattr = FALSE;
1378         __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
1379         __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
1380         __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
1381         struct cifsInodeInfo *cifsInode;
1382
1383         xid = GetXid();
1384
1385         cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
1386                  direntry->d_name.name, attrs->ia_valid));
1387
1388         cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
1389         pTcon = cifs_sb->tcon;
1390
1391         if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
1392                 /* check if we have permission to change attrs */
1393                 rc = inode_change_ok(direntry->d_inode, attrs);
1394                 if(rc < 0) {
1395                         FreeXid(xid);
1396                         return rc;
1397                 } else
1398                         rc = 0;
1399         }
1400                 
1401         full_path = build_path_from_dentry(direntry);
1402         if (full_path == NULL) {
1403                 FreeXid(xid);
1404                 return -ENOMEM;
1405         }
1406         cifsInode = CIFS_I(direntry->d_inode);
1407
1408         /* BB check if we need to refresh inode from server now ? BB */
1409
1410         /* need to flush data before changing file size on server */
1411         filemap_write_and_wait(direntry->d_inode->i_mapping);
1412
1413         if (attrs->ia_valid & ATTR_SIZE) {
1414                 /* To avoid spurious oplock breaks from server, in the case of
1415                    inodes that we already have open, avoid doing path based
1416                    setting of file size if we can do it by handle.
1417                    This keeps our caching token (oplock) and avoids timeouts
1418                    when the local oplock break takes longer to flush
1419                    writebehind data than the SMB timeout for the SetPathInfo
1420                    request would allow */
1421
1422                 open_file = find_writable_file(cifsInode);
1423                 if (open_file) {
1424                         __u16 nfid = open_file->netfid;
1425                         __u32 npid = open_file->pid;
1426                         rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
1427                                                 nfid, npid, FALSE);
1428                         atomic_dec(&open_file->wrtPending);
1429                         cFYI(1,("SetFSize for attrs rc = %d", rc));
1430                         if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1431                                 int bytes_written;
1432                                 rc = CIFSSMBWrite(xid, pTcon,
1433                                                   nfid, 0, attrs->ia_size,
1434                                                   &bytes_written, NULL, NULL,
1435                                                   1 /* 45 seconds */);
1436                                 cFYI(1,("Wrt seteof rc %d", rc));
1437                         }
1438                 } else 
1439                         rc = -EINVAL;
1440
1441                 if (rc != 0) {
1442                         /* Set file size by pathname rather than by handle
1443                            either because no valid, writeable file handle for
1444                            it was found or because there was an error setting
1445                            it by handle */
1446                         rc = CIFSSMBSetEOF(xid, pTcon, full_path,
1447                                            attrs->ia_size, FALSE,
1448                                            cifs_sb->local_nls, 
1449                                            cifs_sb->mnt_cifs_flags &
1450                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1451                         cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
1452                         if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1453                                 __u16 netfid;
1454                                 int oplock = FALSE;
1455
1456                                 rc = SMBLegacyOpen(xid, pTcon, full_path,
1457                                         FILE_OPEN,
1458                                         SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1459                                         CREATE_NOT_DIR, &netfid, &oplock,
1460                                         NULL, cifs_sb->local_nls,
1461                                         cifs_sb->mnt_cifs_flags &
1462                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1463                                 if (rc==0) {
1464                                         int bytes_written;
1465                                         rc = CIFSSMBWrite(xid, pTcon,
1466                                                         netfid, 0,
1467                                                         attrs->ia_size,
1468                                                         &bytes_written, NULL,
1469                                                         NULL, 1 /* 45 sec */);
1470                                         cFYI(1,("wrt seteof rc %d",rc));
1471                                         CIFSSMBClose(xid, pTcon, netfid);
1472                                 }
1473
1474                         }
1475                 }
1476
1477                 /* Server is ok setting allocation size implicitly - no need
1478                    to call:
1479                 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
1480                          cifs_sb->local_nls);
1481                    */
1482
1483                 if (rc == 0) {
1484                         rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size);
1485                         cifs_truncate_page(direntry->d_inode->i_mapping,
1486                                            direntry->d_inode->i_size);
1487                 } else 
1488                         goto cifs_setattr_exit;
1489         }
1490         if (attrs->ia_valid & ATTR_UID) {
1491                 cFYI(1, ("UID changed to %d", attrs->ia_uid));
1492                 uid = attrs->ia_uid;
1493         }
1494         if (attrs->ia_valid & ATTR_GID) {
1495                 cFYI(1, ("GID changed to %d", attrs->ia_gid));
1496                 gid = attrs->ia_gid;
1497         }
1498
1499         time_buf.Attributes = 0;
1500         if (attrs->ia_valid & ATTR_MODE) {
1501                 cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
1502                 mode = attrs->ia_mode;
1503         }
1504
1505         if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
1506             && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1507                 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
1508                                          0 /* dev_t */, cifs_sb->local_nls,
1509                                          cifs_sb->mnt_cifs_flags & 
1510                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1511         else if (attrs->ia_valid & ATTR_MODE) {
1512                 rc = 0;
1513                 if ((mode & S_IWUGO) == 0) /* not writeable */ {
1514                         if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
1515                                 set_dosattr = TRUE;
1516                                 time_buf.Attributes =
1517                                         cpu_to_le32(cifsInode->cifsAttrs |
1518                                                     ATTR_READONLY);
1519                         }
1520                 } else if (cifsInode->cifsAttrs & ATTR_READONLY) {
1521                         /* If file is readonly on server, we would
1522                         not be able to write to it - so if any write
1523                         bit is enabled for user or group or other we
1524                         need to at least try to remove r/o dos attr */
1525                         set_dosattr = TRUE;
1526                         time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
1527                                             (~ATTR_READONLY));
1528                         /* Windows ignores set to zero */
1529                         if(time_buf.Attributes == 0)
1530                                 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
1531                 }
1532                 /* BB to be implemented -
1533                    via Windows security descriptors or streams */
1534                 /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
1535                                       cifs_sb->local_nls); */
1536         }
1537
1538         if (attrs->ia_valid & ATTR_ATIME) {
1539                 set_time = TRUE;
1540                 time_buf.LastAccessTime =
1541                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1542         } else
1543                 time_buf.LastAccessTime = 0;
1544
1545         if (attrs->ia_valid & ATTR_MTIME) {
1546                 set_time = TRUE;
1547                 time_buf.LastWriteTime =
1548                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1549         } else
1550                 time_buf.LastWriteTime = 0;
1551         /* Do not set ctime explicitly unless other time
1552            stamps are changed explicitly (i.e. by utime()
1553            since we would then have a mix of client and
1554            server times */
1555            
1556         if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
1557                 set_time = TRUE;
1558                 /* Although Samba throws this field away
1559                 it may be useful to Windows - but we do
1560                 not want to set ctime unless some other
1561                 timestamp is changing */
1562                 cFYI(1, ("CIFS - CTIME changed"));
1563                 time_buf.ChangeTime =
1564                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1565         } else
1566                 time_buf.ChangeTime = 0;
1567
1568         if (set_time || set_dosattr) {
1569                 time_buf.CreationTime = 0;      /* do not change */
1570                 /* In the future we should experiment - try setting timestamps
1571                    via Handle (SetFileInfo) instead of by path */
1572                 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1573                         rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
1574                                              cifs_sb->local_nls,
1575                                              cifs_sb->mnt_cifs_flags &
1576                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1577                 else
1578                         rc = -EOPNOTSUPP;
1579
1580                 if (rc == -EOPNOTSUPP) {
1581                         int oplock = FALSE;
1582                         __u16 netfid;
1583
1584                         cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1585                                  "times not supported by this server"));
1586                         /* BB we could scan to see if we already have it open
1587                            and pass in pid of opener to function */
1588                         rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1589                                          SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1590                                          CREATE_NOT_DIR, &netfid, &oplock,
1591                                          NULL, cifs_sb->local_nls,
1592                                          cifs_sb->mnt_cifs_flags &
1593                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1594                         if (rc==0) {
1595                                 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1596                                                          netfid);
1597                                 CIFSSMBClose(xid, pTcon, netfid);
1598                         } else {
1599                         /* BB For even older servers we could convert time_buf
1600                            into old DOS style which uses two second
1601                            granularity */
1602
1603                         /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1604                                         &time_buf, cifs_sb->local_nls); */
1605                         }
1606                 }
1607                 /* Even if error on time set, no sense failing the call if
1608                 the server would set the time to a reasonable value anyway,
1609                 and this check ensures that we are not being called from
1610                 sys_utimes in which case we ought to fail the call back to
1611                 the user when the server rejects the call */
1612                 if((rc) && (attrs->ia_valid &
1613                          (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
1614                         rc = 0;
1615         }
1616
1617         /* do not need local check to inode_check_ok since the server does
1618            that */
1619         if (!rc)
1620                 rc = inode_setattr(direntry->d_inode, attrs);
1621 cifs_setattr_exit:
1622         kfree(full_path);
1623         FreeXid(xid);
1624         return rc;
1625 }
1626
1627 #if 0
1628 void cifs_delete_inode(struct inode *inode)
1629 {
1630         cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
1631         /* may have to add back in if and when safe distributed caching of
1632            directories added e.g. via FindNotify */
1633 }
1634 #endif