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