1/* 2 * Copyright (c) 2000-2001, Boris Popov 3 * All rights reserved. 4 * 5 * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/vnode.h> 38#include <sys/kernel.h> 39#include <sys/proc.h> 40#include <sys/fcntl.h> 41#include <sys/mount.h> 42#include <sys/namei.h> 43#include <sys/dirent.h> 44#include <sys/sysctl.h> 45#include <sys/kauth.h> 46 47#include <sys/smb_apple.h> 48#include <netsmb/smb.h> 49#include <netsmb/smb_2.h> 50#include <netsmb/smb_rq.h> 51#include <netsmb/smb_rq_2.h> 52#include <netsmb/smb_conn.h> 53#include <netsmb/smb_conn_2.h> 54#include <netsmb/smb_subr.h> 55 56#include <smbfs/smbfs.h> 57#include <smbfs/smbfs_node.h> 58#include <smbfs/smbfs_subr.h> 59#include <smbfs/smbfs_subr_2.h> 60#include <netsmb/smb_converter.h> 61 62static int smbfs_fastlookup = 1; 63 64SYSCTL_DECL(_net_smb_fs); 65SYSCTL_INT(_net_smb_fs, OID_AUTO, fastlookup, CTLFLAG_RW, &smbfs_fastlookup, 0, ""); 66 67/* 68 * In the future I would like to move all the read directory code into 69 * its own file, but for now lets leave it here. 70 */ 71#define SMB_DIRENTRY_LEN(namlen) \ 72 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 7) & ~7) 73#define SMB_DIRENT_LEN(namlen) \ 74 ((sizeof(struct dirent) - (NAME_MAX+1)) + (((namlen) + 1 + 3) &~ 3)) 75 76/* 77 * This routine will fill in the correct values for the correct structure. The 78 * de value points t0 either a direntry or dirent structure. 79 */ 80static uint32_t 81smbfs_fill_direntry(void *de, const char *name, size_t nmlen, uint8_t dtype, 82 uint64_t ino, int flags) 83{ 84 uint32_t delen = 0; 85 86 if (flags & VNODE_READDIR_EXTENDED) { 87 struct direntry *de64 = (struct direntry *)de; 88 89 /* Never truncate the name, if it won't fit just drop it */ 90 if (nmlen >= sizeof(de64->d_name)) 91 return 0; 92 bzero(de64, sizeof(*de64)); 93 de64->d_fileno = ino; 94 de64->d_type = dtype; 95 de64->d_namlen = nmlen; 96 bcopy(name, de64->d_name, de64->d_namlen); 97 delen = de64->d_reclen = SMB_DIRENTRY_LEN(de64->d_namlen); 98 SMBVDEBUG("de64.d_name = %s de64.d_namlen = %d\n", de64->d_name, de64->d_namlen); 99 } else { 100 struct dirent *de32 = (struct dirent *)de; 101 102 /* Never truncate the name, if it won't fit just drop it */ 103 if (nmlen >= sizeof(de32->d_name)) 104 return 0; 105 bzero(de32, sizeof(*de32)); 106 de32->d_fileno = (ino_t)ino; 107 de32->d_type = dtype; 108 /* Should never happen, but just in case never overwrite the buffer */ 109 de32->d_namlen = nmlen; 110 bcopy(name, de32->d_name, de32->d_namlen); 111 delen = de32->d_reclen = SMB_DIRENT_LEN(de32->d_namlen); 112 SMBVDEBUG("de32.d_name = %s de32.d_namlen = %d\n", de32->d_name, de32->d_namlen); 113 } 114 return delen; 115} 116 117/* We have an entry left over from before we need to put it into the users 118 * buffer before doing any more searches. At this point we always expect 119 * them to have enough room for one entry. If not enough room then uiomove 120 * will return an error. We need to check and make sure they are using the 121 * same size structure as the last lookup. If not reset the entry before 122 * doing the uiomove. 123 */ 124static int 125smb_add_next_entry(struct smbnode *np, uio_t uio, int flags, int32_t *numdirent) 126{ 127 union { 128 struct dirent de32; 129 struct direntry de64; 130 }hold_de; 131 void *de = &hold_de; 132 uint32_t delen; 133 int error = 0; 134 135 if (np->d_nextEntryFlags != (flags & VNODE_READDIR_EXTENDED)) { 136 SMBVDEBUG("Next Entry flags don't match was 0x%x now 0x%x\n", 137 np->d_nextEntryFlags, (flags & VNODE_READDIR_EXTENDED)); 138 if (np->d_nextEntryFlags & VNODE_READDIR_EXTENDED) { 139 /* Have a direntry need a dirent */ 140 struct direntry *de64p = np->d_nextEntry; 141 delen = smbfs_fill_direntry(de, de64p->d_name, de64p->d_namlen, 142 de64p->d_type, de64p->d_fileno, flags); 143 } else { 144 /* Have a dirent need a direntry */ 145 struct dirent *de32p = np->d_nextEntry; 146 delen = smbfs_fill_direntry(de, de32p->d_name, de32p->d_namlen, 147 de32p->d_type, de32p->d_fileno, flags); 148 } 149 } else { 150 de = np->d_nextEntry; 151 delen = np->d_nextEntryLen; 152 } 153 /* Name wouldn't fit in the directory entry just drop it nothing else we can do */ 154 if (delen == 0) 155 goto done; 156 error = uiomove(de, delen, uio); 157 if (error) 158 goto done; 159 (*numdirent)++; 160 np->d_offset++; 161 162done: 163 SMB_FREE(np->d_nextEntry, M_TEMP); 164 np->d_nextEntry = NULL; 165 np->d_nextEntryLen = 0; 166 return error; 167} 168 169int 170smbfs_readvdir(vnode_t dvp, uio_t uio, vfs_context_t context, int flags, 171 int32_t *numdirent) 172{ 173 struct smbnode *dnp = VTOSMB(dvp); 174 union { 175 struct dirent de32; 176 struct direntry de64; 177 }de; 178 struct smbfs_fctx *ctx; 179 off_t offset; 180 uint8_t dtype; 181 uint32_t delen; 182 int error = 0; 183 struct smb_share * share = NULL; 184 uint64_t node_ino; 185 186 /* Do we need to start or restarting the directory listing */ 187 offset = uio_offset(uio); 188 189 share = smb_get_share_with_reference(VTOSMBFS(dvp)); 190 if (!dnp->d_fctx || (dnp->d_fctx->f_share != share) || (offset == 0) || 191 (offset != dnp->d_offset)) { 192 193 smbfs_closedirlookup(dnp, context); 194 error = smbfs_smb_findopen(share, dnp, "*", 1, &dnp->d_fctx, TRUE, 195 context); 196 } 197 /* 198 * The directory fctx keeps a reference on the share so we can release our 199 * reference on the share now. 200 */ 201 smb_share_rele(share, context); 202 203 if (error) { 204 goto done; 205 } 206 ctx = dnp->d_fctx; 207 208 /* 209 * SMB servers will return the dot and dotdot in most cases. If the share is a 210 * FAT Filesystem then the information return could be bogus, also if its a 211 * FAT drive then they won't even return the dot or the dotdot. Since we already 212 * know everything about dot and dotdot just fill them in here and then skip 213 * them during the lookup. 214 */ 215 if (offset == 0) { 216 int ii; 217 218 for (ii = 0; ii < 2; ii++) { 219 if (ii == 0) { 220 node_ino = dnp->n_ino; 221 } else { 222 lck_rw_lock_shared(&dnp->n_parent_rwlock); 223 node_ino = (dnp->n_parent) ? dnp->n_parent->n_ino : SMBFS_ROOT_INO; 224 lck_rw_unlock_shared(&dnp->n_parent_rwlock); 225 } 226 227 delen = smbfs_fill_direntry(&de, "..", ii + 1, DT_DIR, node_ino, flags); 228 /* 229 * At this point we always expect them to have enough room for dot 230 * and dotdot. If not enough room then uiomove will return an error. 231 */ 232 error = uiomove((void *)&de, delen, uio); 233 if (error) 234 goto done; 235 (*numdirent)++; 236 dnp->d_offset++; 237 offset++; 238 } 239 } 240 241 /* 242 * They are continuing from some point ahead of us in the buffer. Skip all 243 * entries until we reach their point in the buffer. 244 */ 245 while (dnp->d_offset < offset) { 246 error = smbfs_findnext(ctx, context); 247 if (error) { 248 smbfs_closedirlookup(dnp, context); 249 goto done; 250 } 251 dnp->d_offset++; 252 } 253 /* We have an entry left over from before we need to put it into the users 254 * buffer before doing any more searches. 255 */ 256 if (dnp->d_nextEntry) { 257 error = smb_add_next_entry(dnp, uio, flags, numdirent); 258 if (error) 259 goto done; 260 } 261 262 /* Loop until we end the search or we don't have enough room for the max element */ 263 while (uio_resid(uio)) { 264 error = smbfs_findnext(ctx, context); 265 if (error) { 266 break; 267 } 268 269 /* 270 * <14430881> If file IDs are supported by this server, skip any 271 * child that has the same id as the current parent that we are 272 * enumerating. Seems like snapshot dirs have the same id as the parent 273 * and that will cause us to deadlock when we find the vnode with same 274 * id and then try to lock it again (deadlock on parent id). 275 */ 276 if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) { 277 if (ctx->f_attr.fa_ino == dnp->n_ino) { 278 SMBDEBUG("Skipping <%s> as it has same ID as parent\n", 279 ctx->f_LocalName); 280 continue; 281 } 282 } 283 284 dtype = (ctx->f_attr.fa_attr & SMB_EFA_DIRECTORY) ? DT_DIR : DT_REG; 285 delen = smbfs_fill_direntry(&de, ctx->f_LocalName, ctx->f_LocalNameLen, 286 dtype, ctx->f_attr.fa_ino, flags); 287 if (smbfs_fastlookup) { 288 vnode_t vp = NULL; 289 290 error = smbfs_nget(ctx->f_share, vnode_mount(dvp), 291 dvp, ctx->f_LocalName, ctx->f_LocalNameLen, 292 &ctx->f_attr, &vp, 293 MAKEENTRY, SMBFS_NGET_CREATE_VNODE, 294 context); 295 if (error == 0) { 296 struct smbnode *np = VTOSMB(vp); 297 298 /* 299 * Some applications use the inode as a marker and expect it to 300 * be persistent. If file IDs are not supported by the server, 301 * then our inode numbers are created by hashing the name and 302 * adding the parent inode number. Once a node is created we 303 * should try to keep the same inode number through out its 304 * life. The smbfs_nget will either create the node or 305 * return one found in the hash table. The one that gets created 306 * will use ctx->f_attr.fa_ino, but if its in our hash table it 307 * will have its original number. So in either case set the file 308 * number to the inode number that was used when the node was 309 * created. 310 */ 311 if (flags & VNODE_READDIR_EXTENDED) 312 de.de64.d_fileno = np->n_ino; 313 else 314 de.de32.d_fileno = (ino_t)np->n_ino; 315 316 /* 317 * Enumerates alway return the correct case of the name. 318 * Update the name and parent if needed. 319 */ 320 smbfs_update_name_par(ctx->f_share, dvp, vp, 321 &ctx->f_attr.fa_reqtime, 322 ctx->f_LocalName, ctx->f_LocalNameLen); 323 324 smbnode_unlock(np); /* Release the smbnode lock */ 325 vnode_put(vp); 326 } else { 327 /* ignore errors from smbfs_nget, shouldn't stop the directory listing */ 328 error = 0; 329 } 330 } 331 /* Name wouldn't fit in the directory entry just drop it nothing else we can do */ 332 if (delen == 0) 333 continue; 334 if (uio_resid(uio) >= delen) { 335 error = uiomove((void *)&de, delen, uio); 336 if (error) 337 break; 338 (*numdirent)++; 339 dnp->d_offset++; 340 } else { 341 SMB_MALLOC(dnp->d_nextEntry, void *, delen, M_TEMP, M_WAITOK); 342 if (dnp->d_nextEntry) { 343 bcopy(&de, dnp->d_nextEntry, delen); 344 dnp->d_nextEntryLen = delen; 345 dnp->d_nextEntryFlags = (flags & VNODE_READDIR_EXTENDED); 346 } 347 break; 348 } 349 } 350done: 351 /* 352 * We use the uio offset to store the last directory index count. Since 353 * the uio offset is really never used, we can set it without causing any 354 * issues. Got this idea from the NFS code and it makes things a 355 * lot simplier. 356 */ 357 uio_setoffset(uio, dnp->d_offset); 358 359 return error; 360} 361 362/* 363 * This routine will zero fill the data between from and to. We may want to allocate 364 * smbzeroes in the future. 365 * 366 * The calling routine must hold a reference on the share 367 */ 368static char smbzeroes[4096] = { 0 }; 369 370static int 371smbfs_zero_fill(struct smb_share *share, SMBFID fid, u_quad_t from, 372 u_quad_t to, int ioflag, vfs_context_t context) 373{ 374 user_size_t len; 375 int error = 0; 376 uio_t uio; 377 378 /* 379 * Coherence callers must prevent VM from seeing the file size 380 * grow until this loop is complete. 381 */ 382 uio = uio_create(1, from, UIO_SYSSPACE, UIO_WRITE); 383 while (from < to) { 384 len = MIN((to - from), sizeof(smbzeroes)); 385 uio_reset(uio, from, UIO_SYSSPACE, UIO_WRITE ); 386 uio_addiov(uio, CAST_USER_ADDR_T(&smbzeroes[0]), len); 387 error = smb_smb_write(share, fid, uio, ioflag, context); 388 if (error) 389 break; 390 /* nothing written */ 391 if (uio_resid(uio) == (user_ssize_t)len) { 392 SMBDEBUG(" short from=%llu to=%llu\n", from, to); 393 break; 394 } 395 from += len - uio_resid(uio); 396 } 397 398 uio_free(uio); 399 return (error); 400} 401 402/* 403 * One of two things has happen. The file is growing or the file has holes in it. 404 * Either case we would like to make sure the data return is zero filled. For 405 * UNIX servers we get this for free. So if the server is UNIX just return and 406 * let the server handle this issue. 407 * 408 * The calling routine must hold a reference on the share 409 * 410 */ 411int 412smbfs_0extend(struct smb_share *share, SMBFID fid, u_quad_t from, 413 u_quad_t to, int ioflag, vfs_context_t context) 414{ 415 int error; 416 417 /* 418 * Make an exception here for UNIX servers. Since UNIX servers always zero 419 * fill there is no reason to make this call in their case. So if this is a 420 * UNIX server just return no error. 421 */ 422 if (UNIX_SERVER(SSTOVC(share))) 423 return(0); 424 /* 425 * We always zero fill the whole amount if the share is FAT based. We always 426 * zero fill NT4 servers and Windows 2000 servers. For all others just write 427 * one byte of zero data at the eof of file. This will cause the NTFS windows 428 * servers to zero fill. 429 */ 430 if ((share->ss_fstype == SMB_FS_FAT) || 431 ((SSTOVC(share)->vc_flags & SMBV_NT4)) || 432 ((SSTOVC(share)->vc_flags & SMBV_WIN2K_XP))) { 433 error = smbfs_zero_fill(share, fid, from, to, ioflag, context); 434 } else { 435 char onezero = 0; 436 int len = 1; 437 uio_t uio; 438 439 /* Writing one byte of zero before the eof will force NTFS to zero fill. */ 440 uio = uio_create(1, (to - 1) , UIO_SYSSPACE, UIO_WRITE); 441 uio_addiov(uio, CAST_USER_ADDR_T(&onezero), len); 442 error = smb_smb_write(share, fid, uio, ioflag, context); 443 uio_free(uio); 444 } 445 return(error); 446} 447 448/* 449 * The calling routine must hold a reference on the share 450 */ 451int 452smbfs_doread(struct smb_share *share, off_t endOfFile, uio_t uiop, 453 SMBFID fid, vfs_context_t context) 454{ 455 int error; 456 user_ssize_t requestsize; 457 user_ssize_t remainder; 458 459 /* if offset is beyond EOF, read nothing */ 460 if (uio_offset(uiop) >= endOfFile) { 461 error = 0; 462 goto exit; 463 } 464 465 /* pin requestsize to EOF */ 466 requestsize = MIN(uio_resid(uiop), endOfFile - uio_offset(uiop)); 467 468 /* subtract requestSize from uio_resid and save remainder */ 469 remainder = uio_resid(uiop) - requestsize; 470 471 /* adjust size of read */ 472 uio_setresid(uiop, requestsize); 473 474 error = smb_smb_read(share, fid, uiop, context); 475 476 /* set remaining uio_resid */ 477 uio_setresid(uiop, (uio_resid(uiop) + remainder)); 478 479exit: 480 481 return error; 482} 483 484/* 485 * %%% Radar 4573627 We should resend the write if we failed because of a 486 * reconnect. We need to dup the uio before the write and if it fails reset 487 * it back to the dup verison. 488 * 489 * The calling routine must hold a reference on the share 490 * 491 */ 492int 493smbfs_dowrite(struct smb_share *share, off_t endOfFile, uio_t uiop, 494 SMBFID fid, int ioflag, vfs_context_t context) 495{ 496 int error = 0; 497 498 SMBVDEBUG("ofs=%lld,resid=%lld\n",uio_offset(uiop), uio_resid(uiop)); 499 500 if (uio_resid(uiop) == 0) 501 return (0); 502 503 /* 504 * When the pageout and strategy routines call this function n_size should 505 * always be bigger than the offset. We count on this so if we every change 506 * that behavior this code will need to be changed. 507 * We have a hole in the file make sure it gets zero filled 508 */ 509 if (uio_offset(uiop) > endOfFile) { 510 error = smbfs_0extend(share, fid, endOfFile, uio_offset(uiop), ioflag, context); 511 } 512 513 if (!error) { 514 error = smb_smb_write(share, fid, uiop, ioflag, context); 515 } 516 517 return error; 518} 519