Blame view
fs/cifs/inode.c
59.4 KB
1da177e4c
|
1 2 3 |
/* * fs/cifs/inode.c * |
f19159dc5
|
4 |
* Copyright (C) International Business Machines Corp., 2002,2010 |
1da177e4c
|
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
* Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/fs.h> |
1da177e4c
|
22 |
#include <linux/stat.h> |
5a0e3ad6a
|
23 |
#include <linux/slab.h> |
1da177e4c
|
24 25 26 27 28 29 30 31 |
#include <linux/pagemap.h> #include <asm/div64.h> #include "cifsfs.h" #include "cifspdu.h" #include "cifsglob.h" #include "cifsproto.h" #include "cifs_debug.h" #include "cifs_fs_sb.h" |
9451a9a52
|
32 |
#include "fscache.h" |
1da177e4c
|
33 |
|
70eff55d2
|
34 |
|
01c64feac
|
35 |
static void cifs_set_ops(struct inode *inode) |
70eff55d2
|
36 37 38 39 40 41 42 43 44 45 46 |
{ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); switch (inode->i_mode & S_IFMT) { case S_IFREG: inode->i_op = &cifs_file_inode_ops; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) inode->i_fop = &cifs_file_direct_nobrl_ops; else inode->i_fop = &cifs_file_direct_ops; |
8be7e6ba1
|
47 48 49 50 51 |
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) inode->i_fop = &cifs_file_strict_nobrl_ops; else inode->i_fop = &cifs_file_strict_ops; |
70eff55d2
|
52 53 54 55 56 |
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) inode->i_fop = &cifs_file_nobrl_ops; else { /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; } |
70eff55d2
|
57 |
/* check if server can support readpages */ |
0d424ad0a
|
58 |
if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf < |
70eff55d2
|
59 60 61 62 63 64 |
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops = &cifs_addr_ops_smallbuf; else inode->i_data.a_ops = &cifs_addr_ops; break; case S_IFDIR: |
bc5b6e24a
|
65 |
#ifdef CONFIG_CIFS_DFS_UPCALL |
01c64feac
|
66 |
if (IS_AUTOMOUNT(inode)) { |
7962670e6
|
67 68 |
inode->i_op = &cifs_dfs_referral_inode_operations; } else { |
bc5b6e24a
|
69 70 71 |
#else /* NO DFS support, treat as a directory */ { #endif |
7962670e6
|
72 73 74 |
inode->i_op = &cifs_dir_inode_ops; inode->i_fop = &cifs_dir_ops; } |
70eff55d2
|
75 76 77 78 79 80 81 82 83 |
break; case S_IFLNK: inode->i_op = &cifs_symlink_inode_ops; break; default: init_special_inode(inode, inode->i_mode, inode->i_rdev); break; } } |
df2cf170c
|
84 85 86 87 88 89 90 |
/* check inode attributes against fattr. If they don't match, tag the * inode for cache invalidation */ static void cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) { struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
f19159dc5
|
91 |
cFYI(1, "%s: revalidating inode %llu", __func__, cifs_i->uniqueid); |
df2cf170c
|
92 93 |
if (inode->i_state & I_NEW) { |
f19159dc5
|
94 |
cFYI(1, "%s: inode %llu is new", __func__, cifs_i->uniqueid); |
df2cf170c
|
95 96 97 98 99 |
return; } /* don't bother with revalidation if we have an oplock */ if (cifs_i->clientCanCacheRead) { |
f19159dc5
|
100 101 |
cFYI(1, "%s: inode %llu is oplocked", __func__, cifs_i->uniqueid); |
df2cf170c
|
102 103 104 105 106 107 |
return; } /* revalidate if mtime or size have changed */ if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) && cifs_i->server_eof == fattr->cf_eof) { |
f19159dc5
|
108 109 |
cFYI(1, "%s: inode %llu is unchanged", __func__, cifs_i->uniqueid); |
df2cf170c
|
110 111 |
return; } |
f19159dc5
|
112 113 |
cFYI(1, "%s: invalidating inode %llu mapping", __func__, cifs_i->uniqueid); |
df2cf170c
|
114 115 |
cifs_i->invalid_mapping = true; } |
cc0bad755
|
116 117 118 |
/* populate an inode with info from a cifs_fattr struct */ void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) |
75f12983d
|
119 |
{ |
cc0bad755
|
120 |
struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
0b8f18e35
|
121 122 |
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); unsigned long oldtime = cifs_i->time; |
cc0bad755
|
123 |
|
df2cf170c
|
124 |
cifs_revalidate_cache(inode, fattr); |
cc0bad755
|
125 126 127 |
inode->i_atime = fattr->cf_atime; inode->i_mtime = fattr->cf_mtime; inode->i_ctime = fattr->cf_ctime; |
cc0bad755
|
128 |
inode->i_rdev = fattr->cf_rdev; |
bfe868486
|
129 |
set_nlink(inode, fattr->cf_nlink); |
cc0bad755
|
130 131 |
inode->i_uid = fattr->cf_uid; inode->i_gid = fattr->cf_gid; |
0b8f18e35
|
132 133 134 135 |
/* if dynperm is set, don't clobber existing mode */ if (inode->i_state & I_NEW || !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) inode->i_mode = fattr->cf_mode; |
cc0bad755
|
136 |
cifs_i->cifsAttrs = fattr->cf_cifsattrs; |
75f12983d
|
137 |
|
0b8f18e35
|
138 139 140 141 |
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) cifs_i->time = 0; else cifs_i->time = jiffies; |
b6b38f704
|
142 143 |
cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode, oldtime, cifs_i->time); |
0b8f18e35
|
144 145 |
cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; |
cc0bad755
|
146 |
|
835a36ca4
|
147 |
cifs_i->server_eof = fattr->cf_eof; |
cc0bad755
|
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
/* * Can't safely change the file size here if the client is writing to * it due to potential races. */ spin_lock(&inode->i_lock); if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) { i_size_write(inode, fattr->cf_eof); /* * i_blocks is not related to (i_size / i_blksize), * but instead 512 byte (2**9) size is required for * calculating num blocks. */ inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9; } spin_unlock(&inode->i_lock); |
01c64feac
|
164 165 166 |
if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL) inode->i_flags |= S_AUTOMOUNT; cifs_set_ops(inode); |
cc0bad755
|
167 |
} |
4065c802d
|
168 169 170 171 172 173 174 175 176 177 |
void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr) { struct cifs_sb_info *cifs_sb = CIFS_SB(sb); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) return; fattr->cf_uniqueid = iunique(sb, ROOT_I); } |
cc0bad755
|
178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */ void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, struct cifs_sb_info *cifs_sb) { memset(fattr, 0, sizeof(*fattr)); fattr->cf_uniqueid = le64_to_cpu(info->UniqueId); fattr->cf_bytes = le64_to_cpu(info->NumOfBytes); fattr->cf_eof = le64_to_cpu(info->EndOfFile); fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); fattr->cf_mode = le64_to_cpu(info->Permissions); |
75f12983d
|
192 193 194 195 196 |
/* * Since we set the inode type below we need to mask off * to avoid strange results if bits set above. */ |
cc0bad755
|
197 |
fattr->cf_mode &= ~S_IFMT; |
75f12983d
|
198 199 |
switch (le32_to_cpu(info->Type)) { case UNIX_FILE: |
cc0bad755
|
200 201 |
fattr->cf_mode |= S_IFREG; fattr->cf_dtype = DT_REG; |
75f12983d
|
202 203 |
break; case UNIX_SYMLINK: |
cc0bad755
|
204 205 |
fattr->cf_mode |= S_IFLNK; fattr->cf_dtype = DT_LNK; |
75f12983d
|
206 207 |
break; case UNIX_DIR: |
cc0bad755
|
208 209 |
fattr->cf_mode |= S_IFDIR; fattr->cf_dtype = DT_DIR; |
75f12983d
|
210 211 |
break; case UNIX_CHARDEV: |
cc0bad755
|
212 213 214 215 |
fattr->cf_mode |= S_IFCHR; fattr->cf_dtype = DT_CHR; fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), le64_to_cpu(info->DevMinor) & MINORMASK); |
75f12983d
|
216 217 |
break; case UNIX_BLOCKDEV: |
cc0bad755
|
218 219 220 221 |
fattr->cf_mode |= S_IFBLK; fattr->cf_dtype = DT_BLK; fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), le64_to_cpu(info->DevMinor) & MINORMASK); |
75f12983d
|
222 223 |
break; case UNIX_FIFO: |
cc0bad755
|
224 225 |
fattr->cf_mode |= S_IFIFO; fattr->cf_dtype = DT_FIFO; |
75f12983d
|
226 227 |
break; case UNIX_SOCKET: |
cc0bad755
|
228 229 |
fattr->cf_mode |= S_IFSOCK; fattr->cf_dtype = DT_SOCK; |
75f12983d
|
230 231 232 |
break; default: /* safest to call it a file if we do not know */ |
cc0bad755
|
233 234 |
fattr->cf_mode |= S_IFREG; fattr->cf_dtype = DT_REG; |
b6b38f704
|
235 |
cFYI(1, "unknown type %d", le32_to_cpu(info->Type)); |
75f12983d
|
236 237 |
break; } |
cc0bad755
|
238 239 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) fattr->cf_uid = cifs_sb->mnt_uid; |
75f12983d
|
240 |
else |
cc0bad755
|
241 |
fattr->cf_uid = le64_to_cpu(info->Uid); |
75f12983d
|
242 |
|
cc0bad755
|
243 244 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) fattr->cf_gid = cifs_sb->mnt_gid; |
75f12983d
|
245 |
else |
cc0bad755
|
246 |
fattr->cf_gid = le64_to_cpu(info->Gid); |
75f12983d
|
247 |
|
cc0bad755
|
248 |
fattr->cf_nlink = le64_to_cpu(info->Nlinks); |
75f12983d
|
249 |
} |
b9a3260f2
|
250 |
/* |
cc0bad755
|
251 252 253 254 255 |
* Fill a cifs_fattr struct with fake inode info. * * Needed to setup cifs_fattr data for the directory which is the * junction to the new submount (ie to setup the fake directory * which represents a DFS referral). |
b9a3260f2
|
256 |
*/ |
f1230c979
|
257 |
static void |
cc0bad755
|
258 |
cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) |
0e4bbde94
|
259 |
{ |
cc0bad755
|
260 |
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
0e4bbde94
|
261 |
|
b6b38f704
|
262 |
cFYI(1, "creating fake fattr for DFS referral"); |
cc0bad755
|
263 264 265 266 267 268 269 270 271 272 |
memset(fattr, 0, sizeof(*fattr)); fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; fattr->cf_uid = cifs_sb->mnt_uid; fattr->cf_gid = cifs_sb->mnt_gid; fattr->cf_atime = CURRENT_TIME; fattr->cf_ctime = CURRENT_TIME; fattr->cf_mtime = CURRENT_TIME; fattr->cf_nlink = 2; fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; |
0e4bbde94
|
273 |
} |
abab095d1
|
274 275 276 277 278 279 280 281 |
int cifs_get_file_info_unix(struct file *filp) { int rc; int xid; FILE_UNIX_BASIC_INFO find_data; struct cifs_fattr fattr; struct inode *inode = filp->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
c21dfb699
|
282 |
struct cifsFileInfo *cfile = filp->private_data; |
96daf2b09
|
283 |
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
abab095d1
|
284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
xid = GetXid(); rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); if (!rc) { cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); } else if (rc == -EREMOTE) { cifs_create_dfs_fattr(&fattr, inode->i_sb); rc = 0; } cifs_fattr_to_inode(inode, &fattr); FreeXid(xid); return rc; } |
1da177e4c
|
298 |
int cifs_get_inode_info_unix(struct inode **pinode, |
cc0bad755
|
299 300 |
const unsigned char *full_path, struct super_block *sb, int xid) |
1da177e4c
|
301 |
{ |
cc0bad755
|
302 |
int rc; |
0e4bbde94
|
303 |
FILE_UNIX_BASIC_INFO find_data; |
cc0bad755
|
304 |
struct cifs_fattr fattr; |
96daf2b09
|
305 |
struct cifs_tcon *tcon; |
7ffec3724
|
306 |
struct tcon_link *tlink; |
1da177e4c
|
307 |
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
1da177e4c
|
308 |
|
b6b38f704
|
309 |
cFYI(1, "Getting info on %s", full_path); |
7962670e6
|
310 |
|
7ffec3724
|
311 312 313 314 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); |
1da177e4c
|
315 |
/* could have done a find first instead but this returns more info */ |
cc0bad755
|
316 |
rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, |
737b758c9
|
317 318 |
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
7ffec3724
|
319 |
cifs_put_tlink(tlink); |
e911d0cc8
|
320 |
|
cc0bad755
|
321 322 323 324 325 326 327 328 |
if (!rc) { cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); } else if (rc == -EREMOTE) { cifs_create_dfs_fattr(&fattr, sb); rc = 0; } else { return rc; } |
1da177e4c
|
329 |
|
1b12b9c15
|
330 331 332 333 334 335 |
/* check for Minshall+French symlinks */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); if (tmprc) cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); } |
0e4bbde94
|
336 |
if (*pinode == NULL) { |
cc0bad755
|
337 |
/* get new inode */ |
4065c802d
|
338 |
cifs_fill_uniqueid(sb, &fattr); |
cc0bad755
|
339 340 |
*pinode = cifs_iget(sb, &fattr); if (!*pinode) |
0e4bbde94
|
341 |
rc = -ENOMEM; |
cc0bad755
|
342 343 344 |
} else { /* we already have inode, update it */ cifs_fattr_to_inode(*pinode, &fattr); |
0e4bbde94
|
345 |
} |
1da177e4c
|
346 |
|
1da177e4c
|
347 348 |
return rc; } |
0b8f18e35
|
349 350 351 |
static int cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, struct cifs_sb_info *cifs_sb, int xid) |
d6e2f2a4c
|
352 353 |
{ int rc; |
4b18f2a9c
|
354 |
int oplock = 0; |
d6e2f2a4c
|
355 |
__u16 netfid; |
7ffec3724
|
356 |
struct tcon_link *tlink; |
96daf2b09
|
357 |
struct cifs_tcon *tcon; |
d4ffff1fa
|
358 |
struct cifs_io_parms io_parms; |
86c96b4bb
|
359 |
char buf[24]; |
d6e2f2a4c
|
360 |
unsigned int bytes_read; |
fb8c4b14d
|
361 |
char *pbuf; |
d6e2f2a4c
|
362 363 |
pbuf = buf; |
0b8f18e35
|
364 365 366 367 368 |
fattr->cf_mode &= ~S_IFMT; if (fattr->cf_eof == 0) { fattr->cf_mode |= S_IFIFO; fattr->cf_dtype = DT_FIFO; |
d6e2f2a4c
|
369 |
return 0; |
0b8f18e35
|
370 371 372 |
} else if (fattr->cf_eof < 8) { fattr->cf_mode |= S_IFREG; fattr->cf_dtype = DT_REG; |
d6e2f2a4c
|
373 374 |
return -EINVAL; /* EOPNOTSUPP? */ } |
50c2f7538
|
375 |
|
7ffec3724
|
376 377 378 379 380 381 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ, |
d6e2f2a4c
|
382 383 384 385 |
CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
fb8c4b14d
|
386 |
if (rc == 0) { |
ec637e3ff
|
387 |
int buf_type = CIFS_NO_BUFFER; |
d6e2f2a4c
|
388 |
/* Read header */ |
d4ffff1fa
|
389 390 391 392 393 394 395 |
io_parms.netfid = netfid; io_parms.pid = current->tgid; io_parms.tcon = tcon; io_parms.offset = 0; io_parms.length = 24; rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); |
4523cc304
|
396 397 |
if ((rc == 0) && (bytes_read >= 8)) { if (memcmp("IntxBLK", pbuf, 8) == 0) { |
b6b38f704
|
398 |
cFYI(1, "Block device"); |
0b8f18e35
|
399 400 |
fattr->cf_mode |= S_IFBLK; fattr->cf_dtype = DT_BLK; |
4523cc304
|
401 |
if (bytes_read == 24) { |
86c96b4bb
|
402 403 404 405 406 |
/* we have enough to decode dev num */ __u64 mjr; /* major */ __u64 mnr; /* minor */ mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); |
0b8f18e35
|
407 |
fattr->cf_rdev = MKDEV(mjr, mnr); |
86c96b4bb
|
408 |
} |
4523cc304
|
409 |
} else if (memcmp("IntxCHR", pbuf, 8) == 0) { |
b6b38f704
|
410 |
cFYI(1, "Char device"); |
0b8f18e35
|
411 412 |
fattr->cf_mode |= S_IFCHR; fattr->cf_dtype = DT_CHR; |
4523cc304
|
413 |
if (bytes_read == 24) { |
86c96b4bb
|
414 415 416 417 418 |
/* we have enough to decode dev num */ __u64 mjr; /* major */ __u64 mnr; /* minor */ mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); |
0b8f18e35
|
419 |
fattr->cf_rdev = MKDEV(mjr, mnr); |
fb8c4b14d
|
420 |
} |
4523cc304
|
421 |
} else if (memcmp("IntxLNK", pbuf, 7) == 0) { |
b6b38f704
|
422 |
cFYI(1, "Symlink"); |
0b8f18e35
|
423 424 |
fattr->cf_mode |= S_IFLNK; fattr->cf_dtype = DT_LNK; |
86c96b4bb
|
425 |
} else { |
0b8f18e35
|
426 427 |
fattr->cf_mode |= S_IFREG; /* file? */ fattr->cf_dtype = DT_REG; |
fb8c4b14d
|
428 |
rc = -EOPNOTSUPP; |
86c96b4bb
|
429 |
} |
3020a1f58
|
430 |
} else { |
0b8f18e35
|
431 432 |
fattr->cf_mode |= S_IFREG; /* then it is a file */ fattr->cf_dtype = DT_REG; |
fb8c4b14d
|
433 434 |
rc = -EOPNOTSUPP; /* or some unknown SFU type */ } |
7ffec3724
|
435 |
CIFSSMBClose(xid, tcon, netfid); |
d6e2f2a4c
|
436 |
} |
7ffec3724
|
437 |
cifs_put_tlink(tlink); |
d6e2f2a4c
|
438 |
return rc; |
d6e2f2a4c
|
439 |
} |
9e294f1c4
|
440 |
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ |
0b8f18e35
|
441 442 443 444 445 446 447 |
/* * Fetch mode bits as provided by SFU. * * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ? */ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, struct cifs_sb_info *cifs_sb, int xid) |
9e294f1c4
|
448 |
{ |
3020a1f58
|
449 |
#ifdef CONFIG_CIFS_XATTR |
9e294f1c4
|
450 451 452 |
ssize_t rc; char ea_value[4]; __u32 mode; |
7ffec3724
|
453 |
struct tcon_link *tlink; |
96daf2b09
|
454 |
struct cifs_tcon *tcon; |
7ffec3724
|
455 456 457 458 459 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); |
9e294f1c4
|
460 |
|
7ffec3724
|
461 |
rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS", |
0b8f18e35
|
462 463 464 |
ea_value, 4 /* size of buf */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
7ffec3724
|
465 |
cifs_put_tlink(tlink); |
4523cc304
|
466 |
if (rc < 0) |
9e294f1c4
|
467 468 469 |
return (int)rc; else if (rc > 3) { mode = le32_to_cpu(*((__le32 *)ea_value)); |
0b8f18e35
|
470 |
fattr->cf_mode &= ~SFBITS_MASK; |
b6b38f704
|
471 472 |
cFYI(1, "special bits 0%o org mode 0%o", mode, fattr->cf_mode); |
0b8f18e35
|
473 |
fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode; |
b6b38f704
|
474 |
cFYI(1, "special mode bits 0%o", mode); |
9e294f1c4
|
475 |
} |
0b8f18e35
|
476 477 |
return 0; |
3020a1f58
|
478 479 480 |
#else return -EOPNOTSUPP; #endif |
9e294f1c4
|
481 |
} |
0b8f18e35
|
482 |
/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
f1230c979
|
483 |
static void |
0b8f18e35
|
484 485 |
cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, struct cifs_sb_info *cifs_sb, bool adjust_tz) |
b9a3260f2
|
486 |
{ |
96daf2b09
|
487 |
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
0d424ad0a
|
488 |
|
0b8f18e35
|
489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
memset(fattr, 0, sizeof(*fattr)); fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); if (info->DeletePending) fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING; if (info->LastAccessTime) fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); else fattr->cf_atime = CURRENT_TIME; fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); if (adjust_tz) { |
0d424ad0a
|
503 504 |
fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; |
0b8f18e35
|
505 506 507 508 |
} fattr->cf_eof = le64_to_cpu(info->EndOfFile); fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
20054bd65
|
509 |
fattr->cf_createtime = le64_to_cpu(info->CreationTime); |
0b8f18e35
|
510 511 512 513 514 515 516 |
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; fattr->cf_dtype = DT_DIR; } else { fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_REG; |
0b8f18e35
|
517 |
|
d0c280d26
|
518 519 520 521 |
/* clear write bits if ATTR_READONLY is set */ if (fattr->cf_cifsattrs & ATTR_READONLY) fattr->cf_mode &= ~(S_IWUGO); } |
0b8f18e35
|
522 523 524 525 526 |
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); fattr->cf_uid = cifs_sb->mnt_uid; fattr->cf_gid = cifs_sb->mnt_gid; |
b9a3260f2
|
527 |
} |
abab095d1
|
528 529 530 531 532 533 534 535 |
int cifs_get_file_info(struct file *filp) { int rc; int xid; FILE_ALL_INFO find_data; struct cifs_fattr fattr; struct inode *inode = filp->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
c21dfb699
|
536 |
struct cifsFileInfo *cfile = filp->private_data; |
96daf2b09
|
537 |
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
abab095d1
|
538 539 540 |
xid = GetXid(); rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); |
42274bb22
|
541 542 543 544 545 546 547 548 549 550 |
switch (rc) { case 0: cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false); break; case -EREMOTE: cifs_create_dfs_fattr(&fattr, inode->i_sb); rc = 0; break; case -EOPNOTSUPP: case -EINVAL: |
abab095d1
|
551 552 |
/* * FIXME: legacy server -- fall back to path-based call? |
ff215713e
|
553 554 555 |
* for now, just skip revalidating and mark inode for * immediate reval. */ |
abab095d1
|
556 557 |
rc = 0; CIFS_I(inode)->time = 0; |
42274bb22
|
558 |
default: |
abab095d1
|
559 |
goto cgfi_exit; |
42274bb22
|
560 |
} |
abab095d1
|
561 562 563 564 565 |
/* * don't bother with SFU junk here -- just mark inode as needing * revalidation. */ |
abab095d1
|
566 567 568 569 570 571 572 |
fattr.cf_uniqueid = CIFS_I(inode)->uniqueid; fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; cifs_fattr_to_inode(inode, &fattr); cgfi_exit: FreeXid(xid); return rc; } |
1da177e4c
|
573 |
int cifs_get_inode_info(struct inode **pinode, |
646dd5398
|
574 |
const unsigned char *full_path, FILE_ALL_INFO *pfindData, |
8b1327f6e
|
575 |
struct super_block *sb, int xid, const __u16 *pfid) |
1da177e4c
|
576 |
{ |
0b8f18e35
|
577 |
int rc = 0, tmprc; |
96daf2b09
|
578 |
struct cifs_tcon *pTcon; |
7ffec3724
|
579 |
struct tcon_link *tlink; |
1da177e4c
|
580 |
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
1da177e4c
|
581 |
char *buf = NULL; |
5ade9deaa
|
582 |
bool adjustTZ = false; |
0b8f18e35
|
583 |
struct cifs_fattr fattr; |
1da177e4c
|
584 |
|
7ffec3724
|
585 586 587 588 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); |
b6b38f704
|
589 |
cFYI(1, "Getting info on %s", full_path); |
1da177e4c
|
590 |
|
d0d2f2df6
|
591 592 |
if ((pfindData == NULL) && (*pinode != NULL)) { if (CIFS_I(*pinode)->clientCanCacheRead) { |
b6b38f704
|
593 |
cFYI(1, "No need to revalidate cached inode sizes"); |
7ffec3724
|
594 |
goto cgii_exit; |
1da177e4c
|
595 596 597 598 |
} } /* if file info not passed in then get it from server */ |
d0d2f2df6
|
599 |
if (pfindData == NULL) { |
1da177e4c
|
600 |
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
7ffec3724
|
601 602 603 604 |
if (buf == NULL) { rc = -ENOMEM; goto cgii_exit; } |
1da177e4c
|
605 |
pfindData = (FILE_ALL_INFO *)buf; |
7962670e6
|
606 |
|
1da177e4c
|
607 |
/* could do find first instead but this returns more info */ |
7962670e6
|
608 |
rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, |
acf1a1b10
|
609 |
0 /* not legacy */, |
6b8edfe0f
|
610 |
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
737b758c9
|
611 |
CIFS_MOUNT_MAP_SPECIAL_CHR); |
6b8edfe0f
|
612 613 614 |
/* BB optimize code so we do not make the above call when server claims no NT SMB support and the above call failed at least once - set flag in tcon or mount */ |
4523cc304
|
615 |
if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { |
7962670e6
|
616 |
rc = SMBQueryInformation(xid, pTcon, full_path, |
fb8c4b14d
|
617 |
pfindData, cifs_sb->local_nls, |
6b8edfe0f
|
618 619 |
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
4b18f2a9c
|
620 |
adjustTZ = true; |
6b8edfe0f
|
621 |
} |
1da177e4c
|
622 |
} |
0b8f18e35
|
623 624 625 626 627 628 |
if (!rc) { cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData, cifs_sb, adjustTZ); } else if (rc == -EREMOTE) { cifs_create_dfs_fattr(&fattr, sb); |
b9a3260f2
|
629 |
rc = 0; |
0b8f18e35
|
630 |
} else { |
7962670e6
|
631 |
goto cgii_exit; |
0b8f18e35
|
632 |
} |
1da177e4c
|
633 |
|
0b8f18e35
|
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
/* * If an inode wasn't passed in, then get the inode number * * Is an i_ino of zero legal? Can we use that to check if the server * supports returning inode numbers? Are there other sanity checks we * can use to ensure that the server is really filling in that field? * * We can not use the IndexNumber field by default from Windows or * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA * CIFS spec claims that this value is unique within the scope of a * share, and the windows docs hint that it's actually unique * per-machine. * * There may be higher info levels that work but are there Windows * server or network appliances for which IndexNumber field is not * guaranteed unique? */ |
b9a3260f2
|
651 |
if (*pinode == NULL) { |
b9a3260f2
|
652 653 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { int rc1 = 0; |
b9a3260f2
|
654 655 |
rc1 = CIFSGetSrvInodeNumber(xid, pTcon, |
0b8f18e35
|
656 |
full_path, &fattr.cf_uniqueid, |
737b758c9
|
657 658 659 |
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
ec06aedd4
|
660 |
if (rc1 || !fattr.cf_uniqueid) { |
b6b38f704
|
661 |
cFYI(1, "GetSrvInodeNum rc %d", rc1); |
0b8f18e35
|
662 |
fattr.cf_uniqueid = iunique(sb, ROOT_I); |
ec06aedd4
|
663 |
cifs_autodisable_serverino(cifs_sb); |
132ac7b77
|
664 |
} |
132ac7b77
|
665 |
} else { |
0b8f18e35
|
666 |
fattr.cf_uniqueid = iunique(sb, ROOT_I); |
132ac7b77
|
667 |
} |
b9a3260f2
|
668 |
} else { |
0b8f18e35
|
669 |
fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid; |
b9a3260f2
|
670 |
} |
0b8f18e35
|
671 672 673 674 675 |
/* query for SFU type info if supported and needed */ if (fattr.cf_cifsattrs & ATTR_SYSTEM && cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid); if (tmprc) |
b6b38f704
|
676 |
cFYI(1, "cifs_sfu_type failed: %d", tmprc); |
b9a3260f2
|
677 |
} |
1da177e4c
|
678 |
|
79df1baee
|
679 |
#ifdef CONFIG_CIFS_ACL |
b9a3260f2
|
680 681 |
/* fill in 0777 bits from ACL */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
78415d2d3
|
682 683 684 685 686 687 688 |
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid); if (rc) { cFYI(1, "%s: Getting ACL failed with error: %d", __func__, rc); goto cgii_exit; } |
b9a3260f2
|
689 |
} |
79df1baee
|
690 |
#endif /* CONFIG_CIFS_ACL */ |
b9a3260f2
|
691 |
|
0b8f18e35
|
692 693 694 |
/* fill in remaining high mode bits e.g. SUID, VTX */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); |
b9a3260f2
|
695 |
|
1b12b9c15
|
696 697 698 699 700 701 |
/* check for Minshall+French symlinks */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); if (tmprc) cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); } |
0b8f18e35
|
702 703 704 705 706 707 708 |
if (!*pinode) { *pinode = cifs_iget(sb, &fattr); if (!*pinode) rc = -ENOMEM; } else { cifs_fattr_to_inode(*pinode, &fattr); } |
b9a3260f2
|
709 |
|
7962670e6
|
710 |
cgii_exit: |
1da177e4c
|
711 |
kfree(buf); |
7ffec3724
|
712 |
cifs_put_tlink(tlink); |
1da177e4c
|
713 714 |
return rc; } |
7f8ed420f
|
715 716 717 |
static const struct inode_operations cifs_ipc_inode_ops = { .lookup = cifs_lookup, }; |
f87d39d95
|
718 |
char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, |
96daf2b09
|
719 |
struct cifs_tcon *tcon) |
8be0ed44c
|
720 |
{ |
f87d39d95
|
721 |
int pplen = vol->prepath ? strlen(vol->prepath) : 0; |
8be0ed44c
|
722 723 724 725 726 727 728 729 730 731 |
int dfsplen; char *full_path = NULL; /* if no prefix path, simply set path to the root of share to "" */ if (pplen == 0) { full_path = kmalloc(1, GFP_KERNEL); if (full_path) full_path[0] = 0; return full_path; } |
0d424ad0a
|
732 733 |
if (tcon->Flags & SMB_SHARE_IS_IN_DFS) dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); |
8be0ed44c
|
734 735 736 737 738 739 |
else dfsplen = 0; full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL); if (full_path == NULL) return full_path; |
f9e8c4500
|
740 |
if (dfsplen) |
0d424ad0a
|
741 |
strncpy(full_path, tcon->treeName, dfsplen); |
f87d39d95
|
742 |
strncpy(full_path + dfsplen, vol->prepath, pplen); |
f9e8c4500
|
743 |
convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); |
8be0ed44c
|
744 745 746 |
full_path[dfsplen + pplen] = 0; /* add trailing null */ return full_path; } |
cc0bad755
|
747 748 749 750 |
static int cifs_find_inode(struct inode *inode, void *opaque) { struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; |
f30b9c118
|
751 |
/* don't match inode with different uniqueid */ |
cc0bad755
|
752 753 |
if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) return 0; |
20054bd65
|
754 755 756 |
/* use createtime like an i_generation field */ if (CIFS_I(inode)->createtime != fattr->cf_createtime) return 0; |
f30b9c118
|
757 758 759 |
/* don't match inode of different type */ if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) return 0; |
5acfec250
|
760 761 |
/* if it's not a directory or has no dentries, then flag it */ if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) |
3d6943803
|
762 |
fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; |
3d6943803
|
763 |
|
cc0bad755
|
764 765 766 767 768 769 770 771 772 |
return 1; } static int cifs_init_inode(struct inode *inode, void *opaque) { struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; |
20054bd65
|
773 |
CIFS_I(inode)->createtime = fattr->cf_createtime; |
cc0bad755
|
774 775 |
return 0; } |
5acfec250
|
776 777 778 779 780 781 782 783 784 |
/* * walk dentry list for an inode and report whether it has aliases that * are hashed. We use this to determine if a directory inode can actually * be used. */ static bool inode_has_hashed_dentries(struct inode *inode) { struct dentry *dentry; |
873feea09
|
785 |
spin_lock(&inode->i_lock); |
5acfec250
|
786 787 |
list_for_each_entry(dentry, &inode->i_dentry, d_alias) { if (!d_unhashed(dentry) || IS_ROOT(dentry)) { |
873feea09
|
788 |
spin_unlock(&inode->i_lock); |
5acfec250
|
789 790 791 |
return true; } } |
873feea09
|
792 |
spin_unlock(&inode->i_lock); |
5acfec250
|
793 794 |
return false; } |
cc0bad755
|
795 796 797 798 799 800 |
/* Given fattrs, get a corresponding inode */ struct inode * cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) { unsigned long hash; struct inode *inode; |
3d6943803
|
801 |
retry_iget5_locked: |
b6b38f704
|
802 |
cFYI(1, "looking for uniqueid=%llu", fattr->cf_uniqueid); |
cc0bad755
|
803 804 805 806 807 |
/* hash down to 32-bits on 32-bit arch */ hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); |
cc0bad755
|
808 |
if (inode) { |
5acfec250
|
809 |
/* was there a potentially problematic inode collision? */ |
3d6943803
|
810 |
if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { |
3d6943803
|
811 |
fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; |
5acfec250
|
812 813 814 815 816 817 818 |
if (inode_has_hashed_dentries(inode)) { cifs_autodisable_serverino(CIFS_SB(sb)); iput(inode); fattr->cf_uniqueid = iunique(sb, ROOT_I); goto retry_iget5_locked; } |
3d6943803
|
819 |
} |
cc0bad755
|
820 821 822 823 824 |
cifs_fattr_to_inode(inode, fattr); if (sb->s_flags & MS_NOATIME) inode->i_flags |= S_NOATIME | S_NOCMTIME; if (inode->i_state & I_NEW) { inode->i_ino = hash; |
522440ed5
|
825 826 |
if (S_ISREG(inode->i_mode)) inode->i_data.backing_dev_info = sb->s_bdi; |
0ccd48025
|
827 |
#ifdef CONFIG_CIFS_FSCACHE |
9451a9a52
|
828 829 |
/* initialize per-inode cache cookie pointer */ CIFS_I(inode)->fscache = NULL; |
0ccd48025
|
830 |
#endif |
cc0bad755
|
831 832 833 834 835 836 |
unlock_new_inode(inode); } } return inode; } |
1da177e4c
|
837 |
/* gets root inode */ |
9b6763e0a
|
838 |
struct inode *cifs_root_iget(struct super_block *sb) |
1da177e4c
|
839 |
{ |
ce634ab28
|
840 |
int xid; |
0d424ad0a
|
841 |
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
cc0bad755
|
842 |
struct inode *inode = NULL; |
ce634ab28
|
843 |
long rc; |
96daf2b09
|
844 |
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
ce634ab28
|
845 |
|
8be0ed44c
|
846 |
xid = GetXid(); |
0d424ad0a
|
847 |
if (tcon->unix_ext) |
f87d39d95
|
848 |
rc = cifs_get_inode_info_unix(&inode, "", sb, xid); |
0b8f18e35
|
849 |
else |
f87d39d95
|
850 |
rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL); |
0b8f18e35
|
851 |
|
a7851ce73
|
852 853 854 855 |
if (!inode) { inode = ERR_PTR(rc); goto out; } |
cc0bad755
|
856 |
|
0ccd48025
|
857 |
#ifdef CONFIG_CIFS_FSCACHE |
d03382ce9
|
858 |
/* populate tcon->resource_id */ |
0d424ad0a
|
859 |
tcon->resource_id = CIFS_I(inode)->uniqueid; |
0ccd48025
|
860 |
#endif |
d03382ce9
|
861 |
|
0d424ad0a
|
862 |
if (rc && tcon->ipc) { |
b6b38f704
|
863 |
cFYI(1, "ipc connection - fake read inode"); |
7f8ed420f
|
864 |
inode->i_mode |= S_IFDIR; |
bfe868486
|
865 |
set_nlink(inode, 2); |
7f8ed420f
|
866 867 868 869 |
inode->i_op = &cifs_ipc_inode_ops; inode->i_fop = &simple_dir_operations; inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; |
ad661334b
|
870 |
} else if (rc) { |
ce634ab28
|
871 |
iget_failed(inode); |
a7851ce73
|
872 |
inode = ERR_PTR(rc); |
7f8ed420f
|
873 |
} |
a7851ce73
|
874 |
out: |
ce634ab28
|
875 876 877 |
/* can not call macro FreeXid here since in a void func * TODO: This is no longer true */ |
1da177e4c
|
878 |
_FreeXid(xid); |
ce634ab28
|
879 |
return inode; |
1da177e4c
|
880 |
} |
388e57b27
|
881 882 883 884 885 886 887 888 889 890 891 892 |
static int cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, char *full_path, __u32 dosattr) { int rc; int oplock = 0; __u16 netfid; __u32 netpid; bool set_time = false; struct cifsFileInfo *open_file; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
7ffec3724
|
893 |
struct tcon_link *tlink = NULL; |
96daf2b09
|
894 |
struct cifs_tcon *pTcon; |
388e57b27
|
895 |
FILE_BASIC_INFO info_buf; |
1adcb7109
|
896 897 |
if (attrs == NULL) return -EINVAL; |
388e57b27
|
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
if (attrs->ia_valid & ATTR_ATIME) { set_time = true; info_buf.LastAccessTime = cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); } else info_buf.LastAccessTime = 0; if (attrs->ia_valid & ATTR_MTIME) { set_time = true; info_buf.LastWriteTime = cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); } else info_buf.LastWriteTime = 0; /* * Samba throws this field away, but windows may actually use it. * Do not set ctime unless other time stamps are changed explicitly * (i.e. by utimes()) since we would then have a mix of client and * server times. */ if (set_time && (attrs->ia_valid & ATTR_CTIME)) { |
b6b38f704
|
919 |
cFYI(1, "CIFS - CTIME changed"); |
388e57b27
|
920 921 922 923 924 925 926 927 928 929 930 |
info_buf.ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); } else info_buf.ChangeTime = 0; info_buf.CreationTime = 0; /* don't change */ info_buf.Attributes = cpu_to_le32(dosattr); /* * If the file is already open for write, just use that fileid */ |
6508d904e
|
931 |
open_file = find_writable_file(cifsInode, true); |
388e57b27
|
932 933 934 |
if (open_file) { netfid = open_file->netfid; netpid = open_file->pid; |
13cfb7334
|
935 |
pTcon = tlink_tcon(open_file->tlink); |
388e57b27
|
936 937 |
goto set_via_filehandle; } |
7ffec3724
|
938 939 940 941 942 943 944 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); tlink = NULL; goto out; } pTcon = tlink_tcon(tlink); |
ba00ba64c
|
945 |
|
388e57b27
|
946 947 948 949 950 951 952 953 954 |
/* * NT4 apparently returns success on this call, but it doesn't * really work. */ if (!(pTcon->ses->flags & CIFS_SES_NT4)) { rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, &info_buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
6b37faa17
|
955 956 957 958 |
if (rc == 0) { cifsInode->cifsAttrs = dosattr; goto out; } else if (rc != -EOPNOTSUPP && rc != -EINVAL) |
388e57b27
|
959 960 |
goto out; } |
b6b38f704
|
961 962 |
cFYI(1, "calling SetFileInfo since SetPathInfo for " "times not supported by this server"); |
388e57b27
|
963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 |
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc != 0) { if (rc == -EIO) rc = -EINVAL; goto out; } netpid = current->tgid; set_via_filehandle: rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid); |
d388908ec
|
980 981 |
if (!rc) cifsInode->cifsAttrs = dosattr; |
388e57b27
|
982 983 984 |
if (open_file == NULL) CIFSSMBClose(xid, pTcon, netfid); else |
6ab409b53
|
985 |
cifsFileInfo_put(open_file); |
388e57b27
|
986 |
out: |
7ffec3724
|
987 988 |
if (tlink != NULL) cifs_put_tlink(tlink); |
388e57b27
|
989 990 |
return rc; } |
a12a1ac7a
|
991 992 993 994 995 996 |
/* * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit * and rename it to a random name that hopefully won't conflict with * anything else. */ static int |
3270958b7
|
997 |
cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid) |
a12a1ac7a
|
998 999 1000 1001 |
{ int oplock = 0; int rc; __u16 netfid; |
3270958b7
|
1002 |
struct inode *inode = dentry->d_inode; |
a12a1ac7a
|
1003 1004 |
struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
7ffec3724
|
1005 |
struct tcon_link *tlink; |
96daf2b09
|
1006 |
struct cifs_tcon *tcon; |
3270958b7
|
1007 1008 |
__u32 dosattr, origattr; FILE_BASIC_INFO *info_buf = NULL; |
a12a1ac7a
|
1009 |
|
7ffec3724
|
1010 1011 1012 1013 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); |
a12a1ac7a
|
1014 |
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, |
dd1db2ded
|
1015 |
DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, |
a12a1ac7a
|
1016 1017 1018 1019 |
&netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc != 0) goto out; |
3270958b7
|
1020 1021 1022 1023 1024 |
origattr = cifsInode->cifsAttrs; if (origattr == 0) origattr |= ATTR_NORMAL; dosattr = origattr & ~ATTR_READONLY; |
a12a1ac7a
|
1025 1026 1027 |
if (dosattr == 0) dosattr |= ATTR_NORMAL; dosattr |= ATTR_HIDDEN; |
3270958b7
|
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 |
/* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */ if (dosattr != origattr) { info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL); if (info_buf == NULL) { rc = -ENOMEM; goto out_close; } info_buf->Attributes = cpu_to_le32(dosattr); rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid); /* although we would like to mark the file hidden if that fails we will still try to rename it */ |
413460980
|
1040 |
if (rc != 0) |
3270958b7
|
1041 1042 1043 |
cifsInode->cifsAttrs = dosattr; else dosattr = origattr; /* since not able to change them */ |
a12a1ac7a
|
1044 |
} |
a12a1ac7a
|
1045 |
|
dd1db2ded
|
1046 1047 |
/* rename the file */ rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls, |
a12a1ac7a
|
1048 1049 |
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
3270958b7
|
1050 1051 1052 1053 |
if (rc != 0) { rc = -ETXTBSY; goto undo_setattr; } |
6d22f0989
|
1054 |
|
3270958b7
|
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 |
/* try to set DELETE_ON_CLOSE */ if (!cifsInode->delete_pending) { rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid); /* * some samba versions return -ENOENT when we try to set the * file disposition here. Likely a samba bug, but work around * it for now. This means that some cifsXXX files may hang * around after they shouldn't. * * BB: remove this hack after more servers have the fix */ if (rc == -ENOENT) rc = 0; else if (rc != 0) { rc = -ETXTBSY; goto undo_rename; } cifsInode->delete_pending = true; } |
7ce86d5a9
|
1075 |
|
a12a1ac7a
|
1076 1077 1078 |
out_close: CIFSSMBClose(xid, tcon, netfid); out: |
3270958b7
|
1079 |
kfree(info_buf); |
7ffec3724
|
1080 |
cifs_put_tlink(tlink); |
a12a1ac7a
|
1081 |
return rc; |
3270958b7
|
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 |
/* * reset everything back to the original state. Don't bother * dealing with errors here since we can't do anything about * them anyway. */ undo_rename: CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); undo_setattr: if (dosattr != origattr) { info_buf->Attributes = cpu_to_le32(origattr); if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid)) cifsInode->cifsAttrs = origattr; } goto out_close; |
a12a1ac7a
|
1101 |
} |
ff6945279
|
1102 1103 1104 1105 |
/* * If dentry->d_inode is null (usually meaning the cached dentry * is a negative dentry) then we would attempt a standard SMB delete, but |
af901ca18
|
1106 1107 |
* if that fails we can not attempt the fall back mechanisms on EACCESS * but will return the EACCESS to the caller. Note that the VFS does not call |
ff6945279
|
1108 1109 |
* unlink on negative dentries currently. */ |
5f0319a79
|
1110 |
int cifs_unlink(struct inode *dir, struct dentry *dentry) |
1da177e4c
|
1111 1112 1113 |
{ int rc = 0; int xid; |
1da177e4c
|
1114 |
char *full_path = NULL; |
5f0319a79
|
1115 |
struct inode *inode = dentry->d_inode; |
ff6945279
|
1116 |
struct cifsInodeInfo *cifs_inode; |
5f0319a79
|
1117 1118 |
struct super_block *sb = dir->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
7ffec3724
|
1119 |
struct tcon_link *tlink; |
96daf2b09
|
1120 |
struct cifs_tcon *tcon; |
6050247d8
|
1121 1122 |
struct iattr *attrs = NULL; __u32 dosattr = 0, origattr = 0; |
1da177e4c
|
1123 |
|
b6b38f704
|
1124 |
cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry); |
1da177e4c
|
1125 |
|
7ffec3724
|
1126 1127 1128 1129 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); |
1da177e4c
|
1130 |
xid = GetXid(); |
5f0319a79
|
1131 1132 1133 |
/* Unlink can be called from rename so we can not take the * sb->s_vfs_rename_mutex here */ full_path = build_path_from_dentry(dentry); |
1da177e4c
|
1134 |
if (full_path == NULL) { |
0f3bc09ee
|
1135 |
rc = -ENOMEM; |
7ffec3724
|
1136 |
goto unlink_out; |
1da177e4c
|
1137 |
} |
2d785a50a
|
1138 |
|
5f0319a79
|
1139 |
if ((tcon->ses->capabilities & CAP_UNIX) && |
2d785a50a
|
1140 |
(CIFS_UNIX_POSIX_PATH_OPS_CAP & |
5f0319a79
|
1141 1142 |
le64_to_cpu(tcon->fsUnixInfo.Capability))) { rc = CIFSPOSIXDelFile(xid, tcon, full_path, |
2d785a50a
|
1143 |
SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, |
737b758c9
|
1144 |
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
b6b38f704
|
1145 |
cFYI(1, "posix del rc %d", rc); |
2d785a50a
|
1146 1147 1148 |
if ((rc == 0) || (rc == -ENOENT)) goto psx_del_no_retry; } |
1da177e4c
|
1149 |
|
6050247d8
|
1150 |
retry_std_delete: |
5f0319a79
|
1151 |
rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls, |
2d785a50a
|
1152 |
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
6050247d8
|
1153 |
|
2d785a50a
|
1154 |
psx_del_no_retry: |
1da177e4c
|
1155 |
if (!rc) { |
5f0319a79
|
1156 1157 |
if (inode) drop_nlink(inode); |
1da177e4c
|
1158 |
} else if (rc == -ENOENT) { |
5f0319a79
|
1159 |
d_drop(dentry); |
1da177e4c
|
1160 |
} else if (rc == -ETXTBSY) { |
3270958b7
|
1161 |
rc = cifs_rename_pending_delete(full_path, dentry, xid); |
a12a1ac7a
|
1162 1163 |
if (rc == 0) drop_nlink(inode); |
ff6945279
|
1164 |
} else if ((rc == -EACCES) && (dosattr == 0) && inode) { |
388e57b27
|
1165 1166 1167 1168 |
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); if (attrs == NULL) { rc = -ENOMEM; goto out_reval; |
1da177e4c
|
1169 |
} |
388e57b27
|
1170 1171 |
/* try to reset dos attributes */ |
ff6945279
|
1172 1173 |
cifs_inode = CIFS_I(inode); origattr = cifs_inode->cifsAttrs; |
6050247d8
|
1174 1175 1176 |
if (origattr == 0) origattr |= ATTR_NORMAL; dosattr = origattr & ~ATTR_READONLY; |
388e57b27
|
1177 1178 1179 1180 1181 |
if (dosattr == 0) dosattr |= ATTR_NORMAL; dosattr |= ATTR_HIDDEN; rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); |
388e57b27
|
1182 1183 |
if (rc != 0) goto out_reval; |
6050247d8
|
1184 1185 |
goto retry_std_delete; |
1da177e4c
|
1186 |
} |
6050247d8
|
1187 1188 1189 1190 |
/* undo the setattr if we errored out and it's needed */ if (rc != 0 && dosattr != 0) cifs_set_file_info(inode, attrs, xid, full_path, origattr); |
388e57b27
|
1191 |
out_reval: |
4523cc304
|
1192 |
if (inode) { |
ff6945279
|
1193 1194 |
cifs_inode = CIFS_I(inode); cifs_inode->time = 0; /* will force revalidate to get info |
5f0319a79
|
1195 1196 |
when needed */ inode->i_ctime = current_fs_time(sb); |
06bcfedd0
|
1197 |
} |
5f0319a79
|
1198 |
dir->i_ctime = dir->i_mtime = current_fs_time(sb); |
ff6945279
|
1199 |
cifs_inode = CIFS_I(dir); |
6050247d8
|
1200 |
CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ |
7ffec3724
|
1201 |
unlink_out: |
1da177e4c
|
1202 |
kfree(full_path); |
6050247d8
|
1203 |
kfree(attrs); |
1da177e4c
|
1204 |
FreeXid(xid); |
7ffec3724
|
1205 |
cifs_put_tlink(tlink); |
1da177e4c
|
1206 1207 1208 1209 1210 |
return rc; } int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) { |
6b37faa17
|
1211 |
int rc = 0, tmprc; |
1da177e4c
|
1212 1213 |
int xid; struct cifs_sb_info *cifs_sb; |
7ffec3724
|
1214 |
struct tcon_link *tlink; |
96daf2b09
|
1215 |
struct cifs_tcon *pTcon; |
1da177e4c
|
1216 1217 |
char *full_path = NULL; struct inode *newinode = NULL; |
cc0bad755
|
1218 |
struct cifs_fattr fattr; |
1da177e4c
|
1219 |
|
b6b38f704
|
1220 |
cFYI(1, "In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode); |
1da177e4c
|
1221 |
|
1da177e4c
|
1222 |
cifs_sb = CIFS_SB(inode->i_sb); |
7ffec3724
|
1223 1224 1225 1226 1227 1228 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); xid = GetXid(); |
1da177e4c
|
1229 |
|
7f57356b7
|
1230 |
full_path = build_path_from_dentry(direntry); |
1da177e4c
|
1231 |
if (full_path == NULL) { |
0f3bc09ee
|
1232 |
rc = -ENOMEM; |
7ffec3724
|
1233 |
goto mkdir_out; |
1da177e4c
|
1234 |
} |
50c2f7538
|
1235 |
|
fb8c4b14d
|
1236 1237 |
if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
2dd29d313
|
1238 1239 |
le64_to_cpu(pTcon->fsUnixInfo.Capability))) { u32 oplock = 0; |
f6d099821
|
1240 |
FILE_UNIX_BASIC_INFO *pInfo = |
2dd29d313
|
1241 |
kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); |
fb8c4b14d
|
1242 |
if (pInfo == NULL) { |
2dd29d313
|
1243 1244 1245 |
rc = -ENOMEM; goto mkdir_out; } |
50c2f7538
|
1246 |
|
ce3b0f8d5
|
1247 |
mode &= ~current_umask(); |
2dd29d313
|
1248 1249 |
rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, NULL /* netfid */, pInfo, &oplock, |
fb8c4b14d
|
1250 1251 |
full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
2dd29d313
|
1252 |
CIFS_MOUNT_MAP_SPECIAL_CHR); |
c45d707f6
|
1253 1254 1255 1256 |
if (rc == -EOPNOTSUPP) { kfree(pInfo); goto mkdir_retry_old; } else if (rc) { |
b6b38f704
|
1257 |
cFYI(1, "posix mkdir returned 0x%x", rc); |
2dd29d313
|
1258 1259 |
d_drop(direntry); } else { |
8f2376adf
|
1260 1261 |
if (pInfo->Type == cpu_to_le32(-1)) { /* no return info, go query for it */ |
5a07cdf86
|
1262 |
kfree(pInfo); |
fb8c4b14d
|
1263 |
goto mkdir_get_info; |
5a07cdf86
|
1264 |
} |
fb8c4b14d
|
1265 1266 |
/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ |
2dd29d313
|
1267 |
inc_nlink(inode); |
cbac3cba6
|
1268 |
|
cc0bad755
|
1269 |
cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); |
4065c802d
|
1270 |
cifs_fill_uniqueid(inode->i_sb, &fattr); |
cc0bad755
|
1271 1272 |
newinode = cifs_iget(inode->i_sb, &fattr); if (!newinode) { |
5a07cdf86
|
1273 |
kfree(pInfo); |
cbac3cba6
|
1274 |
goto mkdir_get_info; |
5a07cdf86
|
1275 |
} |
6b37faa17
|
1276 |
|
2dd29d313
|
1277 |
d_instantiate(direntry, newinode); |
cbac3cba6
|
1278 |
|
cbac3cba6
|
1279 |
#ifdef CONFIG_CIFS_DEBUG2 |
b6b38f704
|
1280 1281 |
cFYI(1, "instantiated dentry %p %s to inode %p", direntry, direntry->d_name.name, newinode); |
cbac3cba6
|
1282 |
|
fb8c4b14d
|
1283 |
if (newinode->i_nlink != 2) |
b6b38f704
|
1284 1285 |
cFYI(1, "unexpected number of links %d", newinode->i_nlink); |
cbac3cba6
|
1286 |
#endif |
2dd29d313
|
1287 1288 1289 |
} kfree(pInfo); goto mkdir_out; |
fb8c4b14d
|
1290 |
} |
c45d707f6
|
1291 |
mkdir_retry_old: |
1da177e4c
|
1292 |
/* BB add setting the equivalent of mode via CreateX w/ACLs */ |
737b758c9
|
1293 1294 |
rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
1da177e4c
|
1295 |
if (rc) { |
b6b38f704
|
1296 |
cFYI(1, "cifs_mkdir returned 0x%x", rc); |
1da177e4c
|
1297 1298 |
d_drop(direntry); } else { |
fb8c4b14d
|
1299 |
mkdir_get_info: |
d8c76e6f4
|
1300 |
inc_nlink(inode); |
c18c842b1
|
1301 |
if (pTcon->unix_ext) |
1da177e4c
|
1302 |
rc = cifs_get_inode_info_unix(&newinode, full_path, |
fb8c4b14d
|
1303 |
inode->i_sb, xid); |
1da177e4c
|
1304 1305 |
else rc = cifs_get_inode_info(&newinode, full_path, NULL, |
8b1327f6e
|
1306 |
inode->i_sb, xid, NULL); |
1da177e4c
|
1307 |
|
1da177e4c
|
1308 |
d_instantiate(direntry, newinode); |
2dd29d313
|
1309 |
/* setting nlink not necessary except in cases where we |
fb8c4b14d
|
1310 |
* failed to get it from the server or was set bogus */ |
2dd29d313
|
1311 |
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) |
bfe868486
|
1312 |
set_nlink(direntry->d_inode, 2); |
950899109
|
1313 |
|
ce3b0f8d5
|
1314 |
mode &= ~current_umask(); |
950899109
|
1315 1316 1317 |
/* must turn on setgid bit if parent dir has it */ if (inode->i_mode & S_ISGID) mode |= S_ISGID; |
c18c842b1
|
1318 |
if (pTcon->unix_ext) { |
4e1e7fb9e
|
1319 1320 1321 1322 1323 1324 1325 |
struct cifs_unix_set_info_args args = { .mode = mode, .ctime = NO_CHANGE_64, .atime = NO_CHANGE_64, .mtime = NO_CHANGE_64, .device = 0, }; |
d0d2f2df6
|
1326 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
a001e5b55
|
1327 |
args.uid = (__u64)current_fsuid(); |
950899109
|
1328 1329 1330 |
if (inode->i_mode & S_ISGID) args.gid = (__u64)inode->i_gid; else |
a001e5b55
|
1331 |
args.gid = (__u64)current_fsgid(); |
1da177e4c
|
1332 |
} else { |
4e1e7fb9e
|
1333 1334 |
args.uid = NO_CHANGE_64; args.gid = NO_CHANGE_64; |
1da177e4c
|
1335 |
} |
01ea95e3b
|
1336 1337 1338 1339 |
CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
3ce53fc4c
|
1340 |
} else { |
67750fb9e
|
1341 1342 1343 |
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && (mode & S_IWUGO) == 0) { FILE_BASIC_INFO pInfo; |
6b37faa17
|
1344 1345 |
struct cifsInodeInfo *cifsInode; u32 dosattrs; |
67750fb9e
|
1346 |
memset(&pInfo, 0, sizeof(pInfo)); |
6b37faa17
|
1347 1348 1349 1350 1351 1352 |
cifsInode = CIFS_I(newinode); dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; pInfo.Attributes = cpu_to_le32(dosattrs); tmprc = CIFSSMBSetPathInfo(xid, pTcon, full_path, &pInfo, cifs_sb->local_nls, |
67750fb9e
|
1353 1354 |
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
6b37faa17
|
1355 1356 |
if (tmprc == 0) cifsInode->cifsAttrs = dosattrs; |
67750fb9e
|
1357 |
} |
fb8c4b14d
|
1358 |
if (direntry->d_inode) { |
b0fd30d3e
|
1359 1360 1361 1362 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) direntry->d_inode->i_mode = (mode | S_IFDIR); |
4e94a105e
|
1363 |
|
fb8c4b14d
|
1364 |
if (cifs_sb->mnt_cifs_flags & |
6473a559c
|
1365 |
CIFS_MOUNT_SET_UID) { |
fb8c4b14d
|
1366 |
direntry->d_inode->i_uid = |
a001e5b55
|
1367 |
current_fsuid(); |
950899109
|
1368 1369 1370 1371 1372 |
if (inode->i_mode & S_ISGID) direntry->d_inode->i_gid = inode->i_gid; else direntry->d_inode->i_gid = |
a001e5b55
|
1373 |
current_fsgid(); |
6473a559c
|
1374 1375 |
} } |
2a138ebb0
|
1376 |
} |
1da177e4c
|
1377 |
} |
fb8c4b14d
|
1378 |
mkdir_out: |
1da177e4c
|
1379 1380 |
kfree(full_path); FreeXid(xid); |
7ffec3724
|
1381 |
cifs_put_tlink(tlink); |
1da177e4c
|
1382 1383 1384 1385 1386 1387 1388 1389 |
return rc; } int cifs_rmdir(struct inode *inode, struct dentry *direntry) { int rc = 0; int xid; struct cifs_sb_info *cifs_sb; |
7ffec3724
|
1390 |
struct tcon_link *tlink; |
96daf2b09
|
1391 |
struct cifs_tcon *pTcon; |
1da177e4c
|
1392 1393 |
char *full_path = NULL; struct cifsInodeInfo *cifsInode; |
b6b38f704
|
1394 |
cFYI(1, "cifs_rmdir, inode = 0x%p", inode); |
1da177e4c
|
1395 1396 |
xid = GetXid(); |
7f57356b7
|
1397 |
full_path = build_path_from_dentry(direntry); |
1da177e4c
|
1398 |
if (full_path == NULL) { |
0f3bc09ee
|
1399 |
rc = -ENOMEM; |
7ffec3724
|
1400 |
goto rmdir_exit; |
1da177e4c
|
1401 |
} |
7ffec3724
|
1402 1403 1404 1405 1406 1407 1408 |
cifs_sb = CIFS_SB(inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); goto rmdir_exit; } pTcon = tlink_tcon(tlink); |
737b758c9
|
1409 1410 |
rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
7ffec3724
|
1411 |
cifs_put_tlink(tlink); |
1da177e4c
|
1412 1413 |
if (!rc) { |
9a53c3a78
|
1414 |
drop_nlink(inode); |
3677db10a
|
1415 |
spin_lock(&direntry->d_inode->i_lock); |
fb8c4b14d
|
1416 |
i_size_write(direntry->d_inode, 0); |
ce71ec368
|
1417 |
clear_nlink(direntry->d_inode); |
3677db10a
|
1418 |
spin_unlock(&direntry->d_inode->i_lock); |
1da177e4c
|
1419 1420 1421 1422 1423 |
} cifsInode = CIFS_I(direntry->d_inode); cifsInode->time = 0; /* force revalidate to go get info when needed */ |
42c245447
|
1424 1425 1426 1427 |
cifsInode = CIFS_I(inode); cifsInode->time = 0; /* force revalidate to get parent dir info since cached search results now invalid */ |
1da177e4c
|
1428 1429 |
direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); |
7ffec3724
|
1430 |
rmdir_exit: |
1da177e4c
|
1431 1432 1433 1434 |
kfree(full_path); FreeXid(xid); return rc; } |
ee2fd967f
|
1435 1436 1437 1438 1439 |
static int cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, struct dentry *to_dentry, const char *toPath) { struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); |
7ffec3724
|
1440 |
struct tcon_link *tlink; |
96daf2b09
|
1441 |
struct cifs_tcon *pTcon; |
ee2fd967f
|
1442 1443 |
__u16 srcfid; int oplock, rc; |
7ffec3724
|
1444 1445 1446 1447 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); |
ee2fd967f
|
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 |
/* try path-based rename first */ rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); /* * don't bother with rename by filehandle unless file is busy and * source Note that cross directory moves do not work with * rename by filehandle to various Windows servers. */ if (rc == 0 || rc != -ETXTBSY) |
7ffec3724
|
1459 |
goto do_rename_exit; |
ee2fd967f
|
1460 |
|
ed0e3ace5
|
1461 1462 |
/* open-file renames don't work across directories */ if (to_dentry->d_parent != from_dentry->d_parent) |
7ffec3724
|
1463 |
goto do_rename_exit; |
ed0e3ace5
|
1464 |
|
ee2fd967f
|
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 |
/* open the file to be renamed -- we need DELETE perms */ rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, CREATE_NOT_DIR, &srcfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == 0) { rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid, (const char *) to_dentry->d_name.name, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, srcfid); } |
7ffec3724
|
1479 1480 |
do_rename_exit: cifs_put_tlink(tlink); |
ee2fd967f
|
1481 1482 |
return rc; } |
14121bdcc
|
1483 1484 |
int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, struct inode *target_dir, struct dentry *target_dentry) |
1da177e4c
|
1485 |
{ |
ee2fd967f
|
1486 1487 |
char *fromName = NULL; char *toName = NULL; |
639e7a913
|
1488 |
struct cifs_sb_info *cifs_sb; |
7ffec3724
|
1489 |
struct tcon_link *tlink; |
96daf2b09
|
1490 |
struct cifs_tcon *tcon; |
ee2fd967f
|
1491 1492 |
FILE_UNIX_BASIC_INFO *info_buf_source = NULL; FILE_UNIX_BASIC_INFO *info_buf_target; |
8d281efb6
|
1493 |
int xid, rc, tmprc; |
1da177e4c
|
1494 |
|
639e7a913
|
1495 |
cifs_sb = CIFS_SB(source_dir->i_sb); |
7ffec3724
|
1496 1497 1498 1499 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); |
1da177e4c
|
1500 |
|
ee2fd967f
|
1501 1502 1503 |
xid = GetXid(); /* |
ee2fd967f
|
1504 1505 1506 |
* we already have the rename sem so we do not need to * grab it again here to protect the path integrity */ |
14121bdcc
|
1507 |
fromName = build_path_from_dentry(source_dentry); |
ee2fd967f
|
1508 1509 1510 1511 |
if (fromName == NULL) { rc = -ENOMEM; goto cifs_rename_exit; } |
14121bdcc
|
1512 |
toName = build_path_from_dentry(target_dentry); |
ee2fd967f
|
1513 |
if (toName == NULL) { |
1da177e4c
|
1514 1515 1516 |
rc = -ENOMEM; goto cifs_rename_exit; } |
14121bdcc
|
1517 1518 |
rc = cifs_do_rename(xid, source_dentry, fromName, target_dentry, toName); |
ee2fd967f
|
1519 |
|
14121bdcc
|
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 |
if (rc == -EEXIST && tcon->unix_ext) { /* * Are src and dst hardlinks of same inode? We can * only tell with unix extensions enabled */ info_buf_source = kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); if (info_buf_source == NULL) { rc = -ENOMEM; goto cifs_rename_exit; } info_buf_target = info_buf_source + 1; |
8d281efb6
|
1534 |
tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, |
14121bdcc
|
1535 |
info_buf_source, |
639e7a913
|
1536 1537 |
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
14121bdcc
|
1538 |
CIFS_MOUNT_MAP_SPECIAL_CHR); |
8d281efb6
|
1539 |
if (tmprc != 0) |
14121bdcc
|
1540 |
goto unlink_target; |
ee2fd967f
|
1541 |
|
639e7a913
|
1542 1543 1544 1545 |
tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName, info_buf_target, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
14121bdcc
|
1546 |
CIFS_MOUNT_MAP_SPECIAL_CHR); |
8d281efb6
|
1547 |
if (tmprc == 0 && (info_buf_source->UniqueId == |
ae6884a9d
|
1548 |
info_buf_target->UniqueId)) { |
14121bdcc
|
1549 |
/* same file, POSIX says that this is a noop */ |
ae6884a9d
|
1550 |
rc = 0; |
14121bdcc
|
1551 |
goto cifs_rename_exit; |
ae6884a9d
|
1552 |
} |
14121bdcc
|
1553 |
} /* else ... BB we could add the same check for Windows by |
ee2fd967f
|
1554 |
checking the UniqueId via FILE_INTERNAL_INFO */ |
14121bdcc
|
1555 |
|
ee2fd967f
|
1556 |
unlink_target: |
fc6f39433
|
1557 1558 |
/* Try unlinking the target dentry if it's not negative */ if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) { |
8d281efb6
|
1559 |
tmprc = cifs_unlink(target_dir, target_dentry); |
14121bdcc
|
1560 1561 |
if (tmprc) goto cifs_rename_exit; |
14121bdcc
|
1562 1563 |
rc = cifs_do_rename(xid, source_dentry, fromName, target_dentry, toName); |
1da177e4c
|
1564 1565 1566 |
} cifs_rename_exit: |
ee2fd967f
|
1567 |
kfree(info_buf_source); |
1da177e4c
|
1568 1569 1570 |
kfree(fromName); kfree(toName); FreeXid(xid); |
7ffec3724
|
1571 |
cifs_put_tlink(tlink); |
1da177e4c
|
1572 1573 |
return rc; } |
df2cf170c
|
1574 1575 |
static bool cifs_inode_needs_reval(struct inode *inode) |
1da177e4c
|
1576 |
{ |
df2cf170c
|
1577 |
struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
6d20e8406
|
1578 |
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
1da177e4c
|
1579 |
|
df2cf170c
|
1580 1581 |
if (cifs_i->clientCanCacheRead) return false; |
1da177e4c
|
1582 |
|
df2cf170c
|
1583 1584 |
if (!lookupCacheEnabled) return true; |
1da177e4c
|
1585 |
|
df2cf170c
|
1586 1587 |
if (cifs_i->time == 0) return true; |
1da177e4c
|
1588 |
|
6d20e8406
|
1589 1590 |
if (!time_in_range(jiffies, cifs_i->time, cifs_i->time + cifs_sb->actimeo)) |
df2cf170c
|
1591 |
return true; |
db19272ed
|
1592 |
/* hardlinked files w/ noserverino get "special" treatment */ |
6d20e8406
|
1593 |
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && |
db19272ed
|
1594 1595 |
S_ISREG(inode->i_mode) && inode->i_nlink != 1) return true; |
df2cf170c
|
1596 1597 |
return false; } |
523fb8c86
|
1598 1599 1600 |
/* * Zap the cache. Called when invalid_mapping flag is set. */ |
6feb9891d
|
1601 |
int |
df2cf170c
|
1602 1603 |
cifs_invalidate_mapping(struct inode *inode) { |
6feb9891d
|
1604 |
int rc = 0; |
df2cf170c
|
1605 1606 1607 |
struct cifsInodeInfo *cifs_i = CIFS_I(inode); cifs_i->invalid_mapping = false; |
df2cf170c
|
1608 |
if (inode->i_mapping && inode->i_mapping->nrpages != 0) { |
257fb1f15
|
1609 1610 1611 1612 1613 1614 |
rc = invalidate_inode_pages2(inode->i_mapping); if (rc) { cERROR(1, "%s: could not invalidate inode %p", __func__, inode); cifs_i->invalid_mapping = true; } |
df2cf170c
|
1615 |
} |
257fb1f15
|
1616 |
|
9451a9a52
|
1617 |
cifs_fscache_reset_inode_cookie(inode); |
6feb9891d
|
1618 |
return rc; |
df2cf170c
|
1619 |
} |
6feb9891d
|
1620 |
int cifs_revalidate_file_attr(struct file *filp) |
abab095d1
|
1621 1622 1623 |
{ int rc = 0; struct inode *inode = filp->f_path.dentry->d_inode; |
ba00ba64c
|
1624 |
struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; |
abab095d1
|
1625 1626 |
if (!cifs_inode_needs_reval(inode)) |
6feb9891d
|
1627 |
return rc; |
abab095d1
|
1628 |
|
13cfb7334
|
1629 |
if (tlink_tcon(cfile->tlink)->unix_ext) |
abab095d1
|
1630 1631 1632 |
rc = cifs_get_file_info_unix(filp); else rc = cifs_get_file_info(filp); |
abab095d1
|
1633 1634 |
return rc; } |
6feb9891d
|
1635 |
int cifs_revalidate_dentry_attr(struct dentry *dentry) |
df2cf170c
|
1636 1637 1638 |
{ int xid; int rc = 0; |
df2cf170c
|
1639 1640 |
struct inode *inode = dentry->d_inode; struct super_block *sb = dentry->d_sb; |
6feb9891d
|
1641 |
char *full_path = NULL; |
df2cf170c
|
1642 1643 1644 |
if (inode == NULL) return -ENOENT; |
1da177e4c
|
1645 |
|
df2cf170c
|
1646 |
if (!cifs_inode_needs_reval(inode)) |
6feb9891d
|
1647 1648 1649 |
return rc; xid = GetXid(); |
1da177e4c
|
1650 1651 1652 |
/* can not safely grab the rename sem here if rename calls revalidate since that would deadlock */ |
df2cf170c
|
1653 |
full_path = build_path_from_dentry(dentry); |
1da177e4c
|
1654 |
if (full_path == NULL) { |
0f3bc09ee
|
1655 |
rc = -ENOMEM; |
6feb9891d
|
1656 |
goto out; |
1da177e4c
|
1657 |
} |
6feb9891d
|
1658 1659 |
cFYI(1, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time " "%ld jiffies %ld", full_path, inode, inode->i_count.counter, |
f19159dc5
|
1660 |
dentry, dentry->d_time, jiffies); |
1da177e4c
|
1661 |
|
0d424ad0a
|
1662 |
if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) |
df2cf170c
|
1663 1664 1665 1666 |
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, NULL); |
1da177e4c
|
1667 |
|
6feb9891d
|
1668 |
out: |
1da177e4c
|
1669 1670 1671 1672 |
kfree(full_path); FreeXid(xid); return rc; } |
6feb9891d
|
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 |
int cifs_revalidate_file(struct file *filp) { int rc; struct inode *inode = filp->f_path.dentry->d_inode; rc = cifs_revalidate_file_attr(filp); if (rc) return rc; if (CIFS_I(inode)->invalid_mapping) rc = cifs_invalidate_mapping(inode); return rc; } /* revalidate a dentry's inode attributes */ int cifs_revalidate_dentry(struct dentry *dentry) { int rc; struct inode *inode = dentry->d_inode; rc = cifs_revalidate_dentry_attr(dentry); if (rc) return rc; if (CIFS_I(inode)->invalid_mapping) rc = cifs_invalidate_mapping(inode); return rc; } |
1da177e4c
|
1701 |
int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, |
1c456013e
|
1702 |
struct kstat *stat) |
1da177e4c
|
1703 |
{ |
3aa1c8c29
|
1704 |
struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); |
96daf2b09
|
1705 |
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
6feb9891d
|
1706 1707 |
struct inode *inode = dentry->d_inode; int rc; |
3aa1c8c29
|
1708 |
|
6feb9891d
|
1709 1710 1711 1712 1713 1714 1715 |
/* * We need to be sure that all dirty pages are written and the server * has actual ctime, mtime and file length. */ if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_fdatawait(inode->i_mapping); |
156ecb2d8
|
1716 1717 1718 1719 |
if (rc) { mapping_set_error(inode->i_mapping, rc); return rc; } |
6feb9891d
|
1720 |
} |
1c456013e
|
1721 |
|
6feb9891d
|
1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 |
rc = cifs_revalidate_dentry_attr(dentry); if (rc) return rc; generic_fillattr(inode, stat); stat->blksize = CIFS_MAX_MSGSIZE; stat->ino = CIFS_I(inode)->uniqueid; /* * If on a multiuser mount without unix extensions, and the admin hasn't * overridden them, set the ownership to the fsuid/fsgid of the current * process. */ if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && !tcon->unix_ext) { if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) stat->uid = current_fsuid(); if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) stat->gid = current_fsgid(); |
5fe14c851
|
1741 |
} |
6feb9891d
|
1742 |
return rc; |
1da177e4c
|
1743 1744 1745 1746 1747 1748 1749 |
} static int cifs_truncate_page(struct address_space *mapping, loff_t from) { pgoff_t index = from >> PAGE_CACHE_SHIFT; unsigned offset = from & (PAGE_CACHE_SIZE - 1); struct page *page; |
1da177e4c
|
1750 1751 1752 1753 1754 |
int rc = 0; page = grab_cache_page(mapping, index); if (!page) return -ENOMEM; |
eebd2aa35
|
1755 |
zero_user_segment(page, offset, PAGE_CACHE_SIZE); |
1da177e4c
|
1756 1757 1758 1759 |
unlock_page(page); page_cache_release(page); return rc; } |
1b9474635
|
1760 |
static void cifs_setsize(struct inode *inode, loff_t offset) |
3677db10a
|
1761 |
{ |
c08d3b0e3
|
1762 |
loff_t oldsize; |
3677db10a
|
1763 |
|
ba6a46a03
|
1764 |
spin_lock(&inode->i_lock); |
c08d3b0e3
|
1765 |
oldsize = inode->i_size; |
3677db10a
|
1766 |
i_size_write(inode, offset); |
ba6a46a03
|
1767 |
spin_unlock(&inode->i_lock); |
1b9474635
|
1768 |
|
c08d3b0e3
|
1769 |
truncate_pagecache(inode, oldsize, offset); |
3677db10a
|
1770 |
} |
8efdbde64
|
1771 1772 1773 1774 1775 1776 1777 1778 |
static int cifs_set_file_size(struct inode *inode, struct iattr *attrs, int xid, char *full_path) { int rc; struct cifsFileInfo *open_file; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
7ffec3724
|
1779 |
struct tcon_link *tlink = NULL; |
96daf2b09
|
1780 |
struct cifs_tcon *pTcon = NULL; |
fa2989f44
|
1781 |
struct cifs_io_parms io_parms; |
8efdbde64
|
1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 |
/* * To avoid spurious oplock breaks from server, in the case of * inodes that we already have open, avoid doing path based * setting of file size if we can do it by handle. * This keeps our caching token (oplock) and avoids timeouts * when the local oplock break takes longer to flush * writebehind data than the SMB timeout for the SetPathInfo * request would allow */ |
6508d904e
|
1792 |
open_file = find_writable_file(cifsInode, true); |
8efdbde64
|
1793 1794 1795 |
if (open_file) { __u16 nfid = open_file->netfid; __u32 npid = open_file->pid; |
13cfb7334
|
1796 |
pTcon = tlink_tcon(open_file->tlink); |
8efdbde64
|
1797 1798 |
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, npid, false); |
6ab409b53
|
1799 |
cifsFileInfo_put(open_file); |
b6b38f704
|
1800 |
cFYI(1, "SetFSize for attrs rc = %d", rc); |
8efdbde64
|
1801 1802 |
if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { unsigned int bytes_written; |
fa2989f44
|
1803 1804 1805 1806 1807 1808 1809 1810 |
io_parms.netfid = nfid; io_parms.pid = npid; io_parms.tcon = pTcon; io_parms.offset = 0; io_parms.length = attrs->ia_size; rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL, NULL, 1); |
b6b38f704
|
1811 |
cFYI(1, "Wrt seteof rc %d", rc); |
8efdbde64
|
1812 1813 1814 1815 1816 |
} } else rc = -EINVAL; if (rc != 0) { |
7ffec3724
|
1817 1818 1819 1820 1821 1822 |
if (pTcon == NULL) { tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); } |
ba00ba64c
|
1823 |
|
8efdbde64
|
1824 1825 1826 1827 1828 1829 1830 1831 |
/* Set file size by pathname rather than by handle either because no valid, writeable file handle for it was found or because there was an error setting it by handle */ rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, false, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
b6b38f704
|
1832 |
cFYI(1, "SetEOF by path (setattrs) rc = %d", rc); |
8efdbde64
|
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 |
if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { __u16 netfid; int oplock = 0; rc = SMBLegacyOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_WRITE, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == 0) { unsigned int bytes_written; |
fa2989f44
|
1845 1846 1847 1848 1849 1850 1851 1852 1853 |
io_parms.netfid = netfid; io_parms.pid = current->tgid; io_parms.tcon = pTcon; io_parms.offset = 0; io_parms.length = attrs->ia_size; rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL, NULL, 1); |
b6b38f704
|
1854 |
cFYI(1, "wrt seteof rc %d", rc); |
8efdbde64
|
1855 1856 1857 |
CIFSSMBClose(xid, pTcon, netfid); } } |
7ffec3724
|
1858 1859 |
if (tlink) cifs_put_tlink(tlink); |
8efdbde64
|
1860 1861 1862 |
} if (rc == 0) { |
fbec9ab95
|
1863 |
cifsInode->server_eof = attrs->ia_size; |
1b9474635
|
1864 |
cifs_setsize(inode, attrs->ia_size); |
8efdbde64
|
1865 1866 1867 1868 1869 |
cifs_truncate_page(inode->i_mapping, inode->i_size); } return rc; } |
3fe5c1dd0
|
1870 1871 1872 1873 1874 1875 1876 1877 1878 |
static int cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) { int rc; int xid; char *full_path = NULL; struct inode *inode = direntry->d_inode; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
7ffec3724
|
1879 |
struct tcon_link *tlink; |
96daf2b09
|
1880 |
struct cifs_tcon *pTcon; |
3fe5c1dd0
|
1881 |
struct cifs_unix_set_info_args *args = NULL; |
3bbeeb3c9
|
1882 |
struct cifsFileInfo *open_file; |
3fe5c1dd0
|
1883 |
|
b6b38f704
|
1884 1885 |
cFYI(1, "setattr_unix on file %s attrs->ia_valid=0x%x", direntry->d_name.name, attrs->ia_valid); |
3fe5c1dd0
|
1886 1887 |
xid = GetXid(); |
db78b877f
|
1888 1889 1890 1891 1892 1893 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) attrs->ia_valid |= ATTR_FORCE; rc = inode_change_ok(inode, attrs); if (rc < 0) goto out; |
3fe5c1dd0
|
1894 1895 1896 1897 1898 1899 |
full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto out; } |
0f4d634c5
|
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 |
/* * Attempt to flush data before changing attributes. We need to do * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the * ownership or mode then we may also need to do this. Here, we take * the safe way out and just do the flush on all setattr requests. If * the flush returns error, store it to report later and continue. * * BB: This should be smarter. Why bother flushing pages that * will be truncated anyway? Also, should we error out here if * the flush returns error? */ rc = filemap_write_and_wait(inode->i_mapping); |
eb4b756b1
|
1912 1913 |
mapping_set_error(inode->i_mapping, rc); rc = 0; |
3fe5c1dd0
|
1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 |
if (attrs->ia_valid & ATTR_SIZE) { rc = cifs_set_file_size(inode, attrs, xid, full_path); if (rc != 0) goto out; } /* skip mode change if it's just for clearing setuid/setgid */ if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) attrs->ia_valid &= ~ATTR_MODE; args = kmalloc(sizeof(*args), GFP_KERNEL); if (args == NULL) { rc = -ENOMEM; goto out; } /* set up the struct */ if (attrs->ia_valid & ATTR_MODE) args->mode = attrs->ia_mode; else args->mode = NO_CHANGE_64; if (attrs->ia_valid & ATTR_UID) args->uid = attrs->ia_uid; else args->uid = NO_CHANGE_64; if (attrs->ia_valid & ATTR_GID) args->gid = attrs->ia_gid; else args->gid = NO_CHANGE_64; if (attrs->ia_valid & ATTR_ATIME) args->atime = cifs_UnixTimeToNT(attrs->ia_atime); else args->atime = NO_CHANGE_64; if (attrs->ia_valid & ATTR_MTIME) args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime); else args->mtime = NO_CHANGE_64; if (attrs->ia_valid & ATTR_CTIME) args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime); else args->ctime = NO_CHANGE_64; args->device = 0; |
6508d904e
|
1963 |
open_file = find_writable_file(cifsInode, true); |
3bbeeb3c9
|
1964 1965 1966 |
if (open_file) { u16 nfid = open_file->netfid; u32 npid = open_file->pid; |
13cfb7334
|
1967 |
pTcon = tlink_tcon(open_file->tlink); |
3bbeeb3c9
|
1968 |
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); |
6ab409b53
|
1969 |
cifsFileInfo_put(open_file); |
3bbeeb3c9
|
1970 |
} else { |
7ffec3724
|
1971 1972 1973 1974 1975 1976 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); goto out; } pTcon = tlink_tcon(tlink); |
3bbeeb3c9
|
1977 |
rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, |
01ea95e3b
|
1978 1979 1980 |
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
7ffec3724
|
1981 |
cifs_put_tlink(tlink); |
3bbeeb3c9
|
1982 |
} |
3fe5c1dd0
|
1983 |
|
1025774ce
|
1984 1985 |
if (rc) goto out; |
ccd4bb1be
|
1986 |
|
1025774ce
|
1987 |
if ((attrs->ia_valid & ATTR_SIZE) && |
1b9474635
|
1988 1989 |
attrs->ia_size != i_size_read(inode)) truncate_setsize(inode, attrs->ia_size); |
1025774ce
|
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 |
setattr_copy(inode, attrs); mark_inode_dirty(inode); /* force revalidate when any of these times are set since some of the fs types (eg ext3, fat) do not have fine enough time granularity to match protocol, and we do not have a a way (yet) to query the server fs's time granularity (and whether it rounds times down). */ if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) cifsInode->time = 0; |
3fe5c1dd0
|
2002 2003 2004 2005 2006 2007 |
out: kfree(args); kfree(full_path); FreeXid(xid); return rc; } |
0510eeb73
|
2008 2009 |
static int cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) |
1da177e4c
|
2010 2011 |
{ int xid; |
a5ff37696
|
2012 2013 |
uid_t uid = NO_CHANGE_32; gid_t gid = NO_CHANGE_32; |
3fe5c1dd0
|
2014 2015 |
struct inode *inode = direntry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
3fe5c1dd0
|
2016 |
struct cifsInodeInfo *cifsInode = CIFS_I(inode); |
1da177e4c
|
2017 2018 |
char *full_path = NULL; int rc = -EACCES; |
feb3e20ce
|
2019 |
__u32 dosattr = 0; |
4e1e7fb9e
|
2020 |
__u64 mode = NO_CHANGE_64; |
3fe5c1dd0
|
2021 |
|
1da177e4c
|
2022 |
xid = GetXid(); |
b6b38f704
|
2023 2024 |
cFYI(1, "setattr on file %s attrs->iavalid 0x%x", direntry->d_name.name, attrs->ia_valid); |
6473a559c
|
2025 |
|
db78b877f
|
2026 2027 2028 2029 2030 2031 2032 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) attrs->ia_valid |= ATTR_FORCE; rc = inode_change_ok(inode, attrs); if (rc < 0) { FreeXid(xid); return rc; |
6473a559c
|
2033 |
} |
50c2f7538
|
2034 |
|
7f57356b7
|
2035 |
full_path = build_path_from_dentry(direntry); |
1da177e4c
|
2036 |
if (full_path == NULL) { |
0f3bc09ee
|
2037 |
rc = -ENOMEM; |
1da177e4c
|
2038 |
FreeXid(xid); |
0f3bc09ee
|
2039 |
return rc; |
1da177e4c
|
2040 |
} |
1da177e4c
|
2041 |
|
0f4d634c5
|
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 |
/* * Attempt to flush data before changing attributes. We need to do * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the * ownership or mode then we may also need to do this. Here, we take * the safe way out and just do the flush on all setattr requests. If * the flush returns error, store it to report later and continue. * * BB: This should be smarter. Why bother flushing pages that * will be truncated anyway? Also, should we error out here if * the flush returns error? */ rc = filemap_write_and_wait(inode->i_mapping); |
eb4b756b1
|
2054 2055 |
mapping_set_error(inode->i_mapping, rc); rc = 0; |
cea218054
|
2056 |
|
50531444f
|
2057 |
if (attrs->ia_valid & ATTR_SIZE) { |
8efdbde64
|
2058 2059 |
rc = cifs_set_file_size(inode, attrs, xid, full_path); if (rc != 0) |
e30dcf3a1
|
2060 |
goto cifs_setattr_exit; |
1da177e4c
|
2061 |
} |
4ca691a89
|
2062 |
|
a5ff37696
|
2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 |
if (attrs->ia_valid & ATTR_UID) uid = attrs->ia_uid; if (attrs->ia_valid & ATTR_GID) gid = attrs->ia_gid; #ifdef CONFIG_CIFS_ACL if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { if (uid != NO_CHANGE_32 || gid != NO_CHANGE_32) { rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64, uid, gid); if (rc) { cFYI(1, "%s: Setting id failed with error: %d", __func__, rc); goto cifs_setattr_exit; } } } else #endif /* CONFIG_CIFS_ACL */ |
3fe5c1dd0
|
2082 |
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) |
4ca691a89
|
2083 |
attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); |
1da177e4c
|
2084 |
|
d32c4f262
|
2085 2086 2087 |
/* skip mode change if it's just for clearing setuid/setgid */ if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) attrs->ia_valid &= ~ATTR_MODE; |
1da177e4c
|
2088 |
if (attrs->ia_valid & ATTR_MODE) { |
1da177e4c
|
2089 |
mode = attrs->ia_mode; |
cdbce9c87
|
2090 |
rc = 0; |
79df1baee
|
2091 |
#ifdef CONFIG_CIFS_ACL |
78415d2d3
|
2092 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
a5ff37696
|
2093 2094 |
rc = id_mode_to_cifs_acl(inode, full_path, mode, NO_CHANGE_32, NO_CHANGE_32); |
78415d2d3
|
2095 2096 2097 2098 2099 2100 |
if (rc) { cFYI(1, "%s: Setting ACL failed with error: %d", __func__, rc); goto cifs_setattr_exit; } } else |
79df1baee
|
2101 |
#endif /* CONFIG_CIFS_ACL */ |
5132861a7
|
2102 2103 |
if (((mode & S_IWUGO) == 0) && (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { |
feb3e20ce
|
2104 2105 |
dosattr = cifsInode->cifsAttrs | ATTR_READONLY; |
5132861a7
|
2106 2107 2108 2109 2110 |
/* fix up mode if we're not using dynperm */ if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) attrs->ia_mode = inode->i_mode & ~S_IWUGO; } else if ((mode & S_IWUGO) && (cifsInode->cifsAttrs & ATTR_READONLY)) { |
feb3e20ce
|
2111 2112 2113 2114 2115 |
dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; /* Attributes of 0 are ignored */ if (dosattr == 0) dosattr |= ATTR_NORMAL; |
5132861a7
|
2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 |
/* reset local inode permissions to normal */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { attrs->ia_mode &= ~(S_IALLUGO); if (S_ISDIR(inode->i_mode)) attrs->ia_mode |= cifs_sb->mnt_dir_mode; else attrs->ia_mode |= cifs_sb->mnt_file_mode; } } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { /* ignore mode change - ATTR_READONLY hasn't changed */ attrs->ia_valid &= ~ATTR_MODE; |
1da177e4c
|
2130 |
} |
1da177e4c
|
2131 |
} |
feb3e20ce
|
2132 2133 2134 2135 |
if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) || ((attrs->ia_valid & ATTR_MODE) && dosattr)) { rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */ |
1da177e4c
|
2136 |
|
e30dcf3a1
|
2137 2138 2139 2140 2141 |
/* Even if error on time set, no sense failing the call if the server would set the time to a reasonable value anyway, and this check ensures that we are not being called from sys_utimes in which case we ought to fail the call back to the user when the server rejects the call */ |
fb8c4b14d
|
2142 |
if ((rc) && (attrs->ia_valid & |
feb3e20ce
|
2143 |
(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) |
e30dcf3a1
|
2144 |
rc = 0; |
1da177e4c
|
2145 2146 2147 2148 |
} /* do not need local check to inode_check_ok since the server does that */ |
1025774ce
|
2149 2150 2151 2152 |
if (rc) goto cifs_setattr_exit; if ((attrs->ia_valid & ATTR_SIZE) && |
1b9474635
|
2153 2154 |
attrs->ia_size != i_size_read(inode)) truncate_setsize(inode, attrs->ia_size); |
1025774ce
|
2155 2156 2157 |
setattr_copy(inode, attrs); mark_inode_dirty(inode); |
1025774ce
|
2158 |
|
e30dcf3a1
|
2159 |
cifs_setattr_exit: |
1da177e4c
|
2160 2161 2162 2163 |
kfree(full_path); FreeXid(xid); return rc; } |
0510eeb73
|
2164 2165 2166 2167 2168 |
int cifs_setattr(struct dentry *direntry, struct iattr *attrs) { struct inode *inode = direntry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
96daf2b09
|
2169 |
struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb); |
0510eeb73
|
2170 2171 2172 2173 2174 2175 2176 2177 |
if (pTcon->unix_ext) return cifs_setattr_unix(direntry, attrs); return cifs_setattr_nounix(direntry, attrs); /* BB: add cifs_setattr_legacy for really old servers */ } |
99ee4dbd7
|
2178 |
#if 0 |
1da177e4c
|
2179 2180 |
void cifs_delete_inode(struct inode *inode) { |
b6b38f704
|
2181 |
cFYI(1, "In cifs_delete_inode, inode = 0x%p", inode); |
1da177e4c
|
2182 2183 2184 |
/* may have to add back in if and when safe distributed caching of directories added e.g. via FindNotify */ } |
99ee4dbd7
|
2185 |
#endif |