1139776Simp/*-
2206361Sjoel * Copyright (c) 2000-2001 Boris Popov
375374Sbp * All rights reserved.
475374Sbp *
575374Sbp * Redistribution and use in source and binary forms, with or without
675374Sbp * modification, are permitted provided that the following conditions
775374Sbp * are met:
875374Sbp * 1. Redistributions of source code must retain the above copyright
975374Sbp *    notice, this list of conditions and the following disclaimer.
1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright
1175374Sbp *    notice, this list of conditions and the following disclaimer in the
1275374Sbp *    documentation and/or other materials provided with the distribution.
1375374Sbp *
1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1775374Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2475374Sbp * SUCH DAMAGE.
2575374Sbp *
2675374Sbp * $FreeBSD$
2775374Sbp */
2875374Sbp#include <sys/param.h>
2975374Sbp#include <sys/systm.h>
3075374Sbp#include <sys/kernel.h>
31163652Sphk#include <sys/clock.h>
3275374Sbp#include <sys/malloc.h>
3375374Sbp#include <sys/time.h>
3475374Sbp#include <sys/vnode.h>
3575374Sbp#include <sys/sysctl.h>
3675374Sbp#include <sys/iconv.h>
3775374Sbp
3875374Sbp#include <netsmb/smb.h>
3975374Sbp#include <netsmb/smb_conn.h>
4075374Sbp#include <netsmb/smb_subr.h>
4175374Sbp#include <netsmb/smb_rq.h>
4275374Sbp#include <netsmb/smb_dev.h>
4375374Sbp
4475374Sbp#include <fs/smbfs/smbfs.h>
4575374Sbp#include <fs/smbfs/smbfs_node.h>
4675374Sbp#include <fs/smbfs/smbfs_subr.h>
4775374Sbp
48151897SrwatsonMALLOC_DEFINE(M_SMBFSDATA, "smbfs_data", "SMBFS private data");
4975374Sbp
5075374Sbpvoid
5175374Sbpsmb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds)
5275374Sbp{
53110299Sphk	*seconds = tsp->tv_sec - tzoff * 60 /*- tz_minuteswest * 60 -
5475374Sbp	    (wall_cmos_clock ? adjkerntz : 0)*/;
5575374Sbp}
5675374Sbp
5775374Sbpvoid
5875374Sbpsmb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp)
5975374Sbp{
6075374Sbp	tsp->tv_sec = seconds + tzoff * 60;
61110299Sphk	    /*+ tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0)*/;
6275374Sbp}
6375374Sbp
6475374Sbp/*
6575374Sbp * Number of seconds between 1970 and 1601 year
6675374Sbp */
67145974Sanholtstatic int64_t DIFF1970TO1601 = 11644473600ULL;
6875374Sbp
6975374Sbp/*
7075374Sbp * Time from server comes as UTC, so no need to use tz
7175374Sbp */
7275374Sbpvoid
7375374Sbpsmb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp)
7475374Sbp{
7575374Sbp	smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp);
7675374Sbp}
7775374Sbp
7875374Sbpvoid
7975374Sbpsmb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec)
8075374Sbp{
8175374Sbp	u_long seconds;
8275374Sbp
8375374Sbp	smb_time_local2server(tsp, 0, &seconds);
8475374Sbp	*nsec = (((int64_t)(seconds) & ~1) + DIFF1970TO1601) * (int64_t)10000000;
8575374Sbp}
8675374Sbp
8775374Sbpvoid
8875374Sbpsmb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
8975374Sbp	u_int16_t *dtp,	u_int8_t *dhp)
9075374Sbp{
91163652Sphk	struct timespec tt;
92163652Sphk	u_long t;
9375374Sbp
94163652Sphk	tt = *tsp;
9575374Sbp	smb_time_local2server(tsp, tzoff, &t);
96163652Sphk	tt.tv_sec = t;
97163652Sphk	timespec2fattime(&tt, 1, ddp, dtp, dhp);
9875374Sbp}
9975374Sbp
10075374Sbpvoid
10175374Sbpsmb_dos2unixtime(u_int dd, u_int dt, u_int dh, int tzoff,
10275374Sbp	struct timespec *tsp)
10375374Sbp{
10475374Sbp
105163652Sphk	fattime2timespec(dd, dt, dh, 1, tsp);
106163652Sphk	smb_time_server2local(tsp->tv_sec, tzoff, tsp);
10775374Sbp}
10875374Sbp
10975374Sbpstatic int
11075374Sbpsmb_fphelp(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *np,
11175374Sbp	int caseopt)
11275374Sbp{
11375374Sbp	struct smbmount *smp= np->n_mount;
11475374Sbp	struct smbnode **npp = smp->sm_npstack;
11575374Sbp	int i, error = 0;
11675374Sbp
11775374Sbp/*	simple_lock(&smp->sm_npslock);*/
11875374Sbp	i = 0;
11975374Sbp	while (np->n_parent) {
12075374Sbp		if (i++ == SMBFS_MAXPATHCOMP) {
12175374Sbp/*			simple_unlock(&smp->sm_npslock);*/
12275374Sbp			return ENAMETOOLONG;
12375374Sbp		}
12475374Sbp		*npp++ = np;
125116338Stjr		if ((np->n_flag & NREFPARENT) == 0)
126116338Stjr			break;
127107821Stjr		np = VTOSMB(np->n_parent);
12875374Sbp	}
12975374Sbp/*	if (i == 0)
13075374Sbp		return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/
13175374Sbp	while (i--) {
13275374Sbp		np = *--npp;
133230196Skevlo		if (SMB_UNICODE_STRINGS(vcp))
134230196Skevlo			error = mb_put_uint16le(mbp, '\\');
135230196Skevlo		else
136230196Skevlo			error = mb_put_uint8(mbp, '\\');
13775374Sbp		if (error)
13875374Sbp			break;
13975374Sbp		error = smb_put_dmem(mbp, vcp, np->n_name, np->n_nmlen, caseopt);
14075374Sbp		if (error)
14175374Sbp			break;
14275374Sbp	}
14375374Sbp/*	simple_unlock(&smp->sm_npslock);*/
14475374Sbp	return error;
14575374Sbp}
14675374Sbp
14775374Sbpint
14875374Sbpsmbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
14975374Sbp	const char *name, int nmlen)
15075374Sbp{
15175374Sbp	int caseopt = SMB_CS_NONE;
15275374Sbp	int error;
15375374Sbp
154230196Skevlo	if (SMB_UNICODE_STRINGS(vcp)) {
155230196Skevlo		error = mb_put_padbyte(mbp);
156230196Skevlo		if (error)
157230196Skevlo			return error;
158230196Skevlo	}
15975374Sbp	if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
16075374Sbp		caseopt |= SMB_CS_UPPER;
16175374Sbp	if (dnp != NULL) {
16275374Sbp		error = smb_fphelp(mbp, vcp, dnp, caseopt);
16375374Sbp		if (error)
16475374Sbp			return error;
16575374Sbp	}
16675374Sbp	if (name) {
167230196Skevlo		if (SMB_UNICODE_STRINGS(vcp))
168230196Skevlo			error = mb_put_uint16le(mbp, '\\');
169230196Skevlo		else
170230196Skevlo			error = mb_put_uint8(mbp, '\\');
17175374Sbp		if (error)
17275374Sbp			return error;
17375374Sbp		error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt);
17475374Sbp		if (error)
17575374Sbp			return error;
17675374Sbp	}
17775374Sbp	error = mb_put_uint8(mbp, 0);
178230196Skevlo	if (SMB_UNICODE_STRINGS(vcp) && error == 0)
179230196Skevlo		error = mb_put_uint8(mbp, 0);
18075374Sbp	return error;
18175374Sbp}
18275374Sbp
18375374Sbpint
184145872Stakawatasmbfs_fname_tolocal(struct smb_vc *vcp, char *name, int *nmlen, int caseopt)
18575374Sbp{
186145872Stakawata	int copt = (caseopt == SMB_CS_LOWER ? KICONV_FROM_LOWER :
187145872Stakawata		    (caseopt == SMB_CS_UPPER ? KICONV_FROM_UPPER : 0));
188145872Stakawata	int error = 0;
189145900Stakawata	size_t ilen = *nmlen;
190145900Stakawata	size_t olen;
191145872Stakawata	char *ibuf = name;
192145872Stakawata	char outbuf[SMB_MAXFNAMELEN];
193145872Stakawata	char *obuf = outbuf;
194145872Stakawata
195145872Stakawata	if (vcp->vc_tolocal) {
196145872Stakawata		olen = sizeof(outbuf);
197145872Stakawata		bzero(outbuf, sizeof(outbuf));
198145872Stakawata
199145872Stakawata		/*
200145872Stakawata		error = iconv_conv_case
201145872Stakawata			(vcp->vc_tolocal, NULL, NULL, &obuf, &olen, copt);
202145872Stakawata		if (error) return error;
203145872Stakawata		*/
204145872Stakawata
205145872Stakawata		error = iconv_conv_case
206145872Stakawata			(vcp->vc_tolocal, (const char **)&ibuf, &ilen, &obuf, &olen, copt);
207230196Skevlo		if (error && SMB_UNICODE_STRINGS(vcp)) {
208230196Skevlo			/*
209230196Skevlo			 * If using unicode, leaving a file name as it was when
210230196Skevlo			 * convert fails will cause a problem because the file name
211230196Skevlo			 * will contain NULL.
212230196Skevlo			 * Here, put '?' and give converted file name.
213230196Skevlo			 */
214230196Skevlo			*obuf = '?';
215230196Skevlo			olen--;
216230196Skevlo			error = 0;
217230196Skevlo		}
218145872Stakawata		if (!error) {
219145872Stakawata			*nmlen = sizeof(outbuf) - olen;
220145872Stakawata			memcpy(name, outbuf, *nmlen);
221145872Stakawata		}
222145872Stakawata	}
223145872Stakawata	return error;
22475374Sbp}
225