1139776Simp/*-
274062Sbp * Copyright (c) 1999, 2001 Boris Popov
351852Sbp * All rights reserved.
451852Sbp *
551852Sbp * Redistribution and use in source and binary forms, with or without
651852Sbp * modification, are permitted provided that the following conditions
751852Sbp * are met:
851852Sbp * 1. Redistributions of source code must retain the above copyright
951852Sbp *    notice, this list of conditions and the following disclaimer.
1051852Sbp * 2. Redistributions in binary form must reproduce the above copyright
1151852Sbp *    notice, this list of conditions and the following disclaimer in the
1251852Sbp *    documentation and/or other materials provided with the distribution.
1351852Sbp *
1451852Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1551852Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1651852Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1751852Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1851852Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1951852Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2051852Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2151852Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2251852Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2351852Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2451852Sbp * SUCH DAMAGE.
2551852Sbp *
2651852Sbp * $FreeBSD$
2751852Sbp */
2851852Sbp#include <sys/param.h>
2951852Sbp#include <sys/systm.h>
3051852Sbp#include <sys/kernel.h>
31176708Sattilio#include <sys/lock.h>
32102821Siedowse#include <sys/lockmgr.h>
3351852Sbp#include <sys/malloc.h>
34162970Sphk#include <sys/clock.h>
3551852Sbp#include <sys/time.h>
3651852Sbp
3751852Sbp#include <netncp/ncp.h>
3851852Sbp#include <netncp/ncp_conn.h>
3951852Sbp#include <netncp/ncp_ncp.h>
4051852Sbp#include <netncp/ncp_subr.h>
4151852Sbp#include <netncp/ncp_rq.h>
4251852Sbp#include <netncp/nwerror.h>
4351852Sbp
4477223Sru#include <fs/nwfs/nwfs.h>
4577223Sru#include <fs/nwfs/nwfs_node.h>
4677223Sru#include <fs/nwfs/nwfs_subr.h>
4751852Sbp
4874062Sbp#define NCP_INFOSZ	(sizeof(struct nw_entry_info) - 257)
4974062Sbp
50151897SrwatsonMALLOC_DEFINE(M_NWFSDATA, "nwfs_data", "NWFS private data");
5151852Sbp
5274062Sbpstatic int
5374062Sbpncp_extract_file_info(struct nwmount *nmp, struct ncp_rq *rqp,
5474062Sbp	struct nw_entry_info *target, int withname)
5574062Sbp{
5674062Sbp	u_int8_t name_len;
5751852Sbp
5874062Sbp	md_get_mem(&rqp->rp, (caddr_t)target, NCP_INFOSZ, MB_MSYSTEM);
5974062Sbp	if (!withname)
6074062Sbp		return 0;
6174062Sbp	md_get_uint8(&rqp->rp, &name_len);
6251852Sbp	target->nameLen = name_len;
6374062Sbp	md_get_mem(&rqp->rp, (caddr_t)target->entryName, name_len, MB_MSYSTEM);
6451852Sbp	target->entryName[name_len] = '\0';
6551852Sbp	ncp_path2unix(target->entryName, target->entryName, name_len, &nmp->m.nls);
6674062Sbp	return 0;
6751852Sbp}
6851852Sbp
6951852Sbpint
7083366Sjulianncp_initsearch(struct vnode *dvp, struct thread *td, struct ucred *cred)
7151852Sbp{
7251852Sbp	struct nwmount *nmp = VTONWFS(dvp);
7351852Sbp	struct ncp_conn *conn = NWFSTOCONN(nmp);
7451852Sbp	struct nwnode *np = VTONW(dvp);
7574062Sbp	struct ncp_rq *rqp;
7651852Sbp	u_int8_t volnum = nmp->n_volume;
7751852Sbp	u_int32_t dirent = np->n_fid.f_id;
7851852Sbp	int error;
7951852Sbp
8051852Sbp	NCPNDEBUG("vol=%d,dir=%d\n", volnum, dirent);
8183366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
8274062Sbp	if (error)
8374062Sbp		return error;
8474062Sbp	mb_put_uint8(&rqp->rq, 2);		/* subfunction */
8574062Sbp	mb_put_uint8(&rqp->rq, nmp->name_space);
8674062Sbp	mb_put_uint8(&rqp->rq, 0);		/* reserved */
8751852Sbp	ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
8874062Sbp	rqp->nr_minrplen = sizeof(np->n_seq);
8974062Sbp	error = ncp_request(rqp);
9074062Sbp	if (error)
9174062Sbp		return error;
9274062Sbp	md_get_mem(&rqp->rp, (caddr_t)&np->n_seq, sizeof(np->n_seq), MB_MSYSTEM);
9374062Sbp	ncp_rq_done(rqp);
9474062Sbp	return 0;
9551852Sbp}
9651852Sbp
9751852Sbpint
9851852Sbpncp_search_for_file_or_subdir(struct nwmount *nmp,
9951852Sbp			      struct nw_search_seq *seq,
10051852Sbp			      struct nw_entry_info *target,
10183366Sjulian			      struct thread *td,struct ucred *cred)
10251852Sbp{
10351852Sbp	struct ncp_conn *conn = NWFSTOCONN(nmp);
10474062Sbp	struct ncp_rq *rqp;
10551852Sbp	int error;
10651852Sbp
10783366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
10874062Sbp	if (error)
10974062Sbp		return error;
11074062Sbp	mb_put_uint8(&rqp->rq, 3);		/* subfunction */
11174062Sbp	mb_put_uint8(&rqp->rq, nmp->name_space);
11274062Sbp	mb_put_uint8(&rqp->rq, 0);		/* data stream */
11374062Sbp	mb_put_uint16le(&rqp->rq, 0xffff);	/* Search attribs */
11474062Sbp	mb_put_uint32le(&rqp->rq, IM_ALL);	/* return info mask */
11574062Sbp	mb_put_mem(&rqp->rq, (caddr_t)seq, 9, MB_MSYSTEM);
11674062Sbp	mb_put_uint8(&rqp->rq, 2);		/* 2 byte pattern */
11774062Sbp	mb_put_uint8(&rqp->rq, 0xff);		/* following is a wildcard */
11874062Sbp	mb_put_uint8(&rqp->rq, '*');
11974062Sbp	rqp->nr_minrplen = sizeof(*seq) +  1 + NCP_INFOSZ + 1;
12074062Sbp	error = ncp_request(rqp);
12174062Sbp	if (error)
12274062Sbp		return error;
12374062Sbp	md_get_mem(&rqp->rp, (caddr_t)seq, sizeof(*seq), MB_MSYSTEM);
12474062Sbp	md_get_uint8(&rqp->rp, NULL);		/* skip */
12574062Sbp	error = ncp_extract_file_info(nmp, rqp, target, 1);
12674062Sbp	ncp_rq_done(rqp);
12751852Sbp	return error;
12851852Sbp}
12951852Sbp
13051852Sbp/*
13151852Sbp * Returns information for a (one-component) name relative to the specified
13251852Sbp * directory.
13351852Sbp */
13451852Sbpint
13551852Sbpncp_obtain_info(struct nwmount *nmp,  u_int32_t dirent,
13651852Sbp		int namelen, char *path, struct nw_entry_info *target,
13783366Sjulian		struct thread *td,struct ucred *cred)
13851852Sbp{
13951852Sbp	struct ncp_conn *conn=NWFSTOCONN(nmp);
14074062Sbp	struct ncp_rq *rqp;
14151852Sbp	int error;
14251852Sbp	u_char volnum = nmp->n_volume, ns;
14351852Sbp
14451852Sbp	if (target == NULL) {
14551852Sbp		NCPFATAL("target == NULL\n");
14651852Sbp		return EINVAL;
14751852Sbp	}
14851852Sbp	ns = (path == NULL || path[0] == 0) ? NW_NS_DOS : nmp->name_space;
14983366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
15074062Sbp	if (error)
15174062Sbp		return error;
15274062Sbp	mb_put_uint8(&rqp->rq, 6);	/* subfunction */
15374062Sbp	mb_put_uint8(&rqp->rq, ns);
15474062Sbp	mb_put_uint8(&rqp->rq, ns);	/* DestNameSpace */
15574062Sbp	mb_put_uint16le(&rqp->rq, 0xff);	/* get all */
15674062Sbp	mb_put_uint32le(&rqp->rq, IM_ALL);
15751852Sbp	ncp_rq_dbase_path(rqp, volnum, dirent, namelen, path, &nmp->m.nls);
15874062Sbp	error = ncp_request(rqp);
15974062Sbp	if (error)
16074062Sbp		return error;
16174062Sbp	error = ncp_extract_file_info(nmp, rqp, target, path != NULL);
16274062Sbp	ncp_rq_done(rqp);
16351852Sbp	return error;
16451852Sbp}
16551852Sbp/*
16651852Sbp * lookup name pointed by cnp in directory dvp and return file info in np.
16751852Sbp * May be I should create a little cache, but another way is to minimize
16851852Sbp * number of calls, on other hand, in multiprocess environment ...
16951852Sbp */
17051852Sbpint
17151852Sbpncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap,
17283366Sjulian		struct thread *td,struct ucred *cred)
17351852Sbp{
17451852Sbp	struct nwmount *nmp;
175146115Skan	struct nwnode *dnp;
17651852Sbp	int error;
17751852Sbp
17851852Sbp	if (!dvp || dvp->v_type != VDIR) {
17951852Sbp		nwfs_printf("dvp is NULL or not a directory.\n");
18051852Sbp		return (ENOENT);
18151852Sbp	}
182146115Skan	dnp = VTONW(dvp);
18351852Sbp	nmp = VTONWFS(dvp);
18451852Sbp
18551852Sbp	if (len == 1 && name[0] == '.') {
18674064Sbp		if (dnp->n_flag & NVOLUME) {
18751852Sbp			error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 0, NULL,
18883366Sjulian				fap, td, cred);
18951852Sbp		} else {
19051852Sbp			error = ncp_obtain_info(nmp, dnp->n_fid.f_parent,
19183366Sjulian				dnp->n_nmlen, dnp->n_name, fap, td, cred);
19251852Sbp		}
19351852Sbp		return error;
19451852Sbp	} else if (len == 2 && name[0] == '.' && name[1] == '.') {
19587599Sobrien		printf("%s: knows NOTHING about '..'\n", __func__);
19651852Sbp		return EIO;
19751852Sbp	} else {
19851852Sbp		error = ncp_obtain_info(nmp, dnp->n_fid.f_id,
19983366Sjulian			len, name, fap, td, cred);
20051852Sbp	}
20151852Sbp	return error;
20251852Sbp}
20351852Sbp
20451852Sbpstatic void ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh);
20551852Sbpstatic void
20651852SbpConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh) {
20751852Sbp	fh->val1 = (fh->val.val32 = sfd);
20851852Sbp	return;
20951852Sbp}
21051852Sbp
21151852Sbp/*
21251852Sbp * If both dir and name are NULL, then in target there's already a looked-up
21351852Sbp * entry that wants to be opened.
21451852Sbp */
21551852Sbpint
21651852Sbpncp_open_create_file_or_subdir(struct nwmount *nmp,struct vnode *dvp,int namelen,
21751852Sbp	    char *name, int open_create_mode, u_int32_t create_attributes,
21851852Sbp	    int desired_acc_rights, struct ncp_open_info *nop,
21983366Sjulian	    struct thread *td,struct ucred *cred)
22051852Sbp{
22151852Sbp
22251852Sbp	struct ncp_conn *conn=NWFSTOCONN(nmp);
22374062Sbp	struct ncp_rq *rqp;
22451852Sbp	u_int16_t search_attribs = SA_ALL & (~SA_SUBDIR_FILES);
22551852Sbp	u_int8_t volnum;
22651852Sbp	u_int32_t dirent;
22751852Sbp	int error;
22851852Sbp
22983366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
23074062Sbp	if (error)
23174062Sbp		return error;
23251852Sbp	volnum = nmp->n_volume;
23351852Sbp	dirent = VTONW(dvp)->n_fid.f_id;
23451852Sbp	if ((create_attributes & aDIR) != 0) {
23551852Sbp		search_attribs |= SA_SUBDIR_FILES;
23651852Sbp	}
23774062Sbp	mb_put_uint8(&rqp->rq, 1);/* subfunction */
23874062Sbp	mb_put_uint8(&rqp->rq, nmp->name_space);
23974062Sbp	mb_put_uint8(&rqp->rq, open_create_mode);
24074062Sbp	mb_put_uint16le(&rqp->rq, search_attribs);
24174062Sbp	mb_put_uint32le(&rqp->rq, IM_ALL);
24274062Sbp	mb_put_uint32le(&rqp->rq, create_attributes);
24351852Sbp	/*
24451852Sbp	 * The desired acc rights seem to be the inherited rights mask for
24551852Sbp	 * directories
24651852Sbp	 */
24774062Sbp	mb_put_uint16le(&rqp->rq, desired_acc_rights);
24851852Sbp	ncp_rq_dbase_path(rqp, volnum, dirent, namelen, name, &nmp->m.nls);
24974062Sbp	error = ncp_request(rqp);
25074062Sbp	if (error) {
25174062Sbp		if (error == NWE_FILE_NO_CREATE_PRIV)
25274062Sbp			error = EACCES;
25374062Sbp		return error;
25474062Sbp	}
25574062Sbp	md_get_uint32le(&rqp->rp, &nop->origfh);
25674062Sbp	md_get_uint8(&rqp->rp, &nop->action);
25774062Sbp	md_get_uint8(&rqp->rp, NULL);	/* skip */
25874062Sbp	error = ncp_extract_file_info(nmp, rqp, &nop->fattr, 1);
25974062Sbp	ncp_rq_done(rqp);
26051852Sbp	ConvertToNWfromDWORD(nop->origfh, &nop->fh);
26151852Sbp	return error;
26251852Sbp}
26351852Sbp
26451852Sbpint
26583366Sjulianncp_close_file(struct ncp_conn *conn, ncp_fh *fh,struct thread *td,struct ucred *cred)
26674062Sbp{
26774062Sbp	struct ncp_rq *rqp;
26851852Sbp	int error;
26951852Sbp
27083366Sjulian	error = ncp_rq_alloc(66, conn, td, cred, &rqp);
27174062Sbp	if (error)
27274062Sbp		return error;
27374062Sbp	mb_put_uint8(&rqp->rq, 0);
27474062Sbp	mb_put_mem(&rqp->rq, (caddr_t)fh, 6, MB_MSYSTEM);
27574062Sbp	error = ncp_request(rqp);
27674062Sbp	if (error)
27774062Sbp		return error;
27874062Sbp	ncp_rq_done(rqp);
27951852Sbp	return error;
28051852Sbp}
28151852Sbp
28251852Sbpint
28351852Sbpncp_DeleteNSEntry(struct nwmount *nmp, u_int32_t dirent,
28483366Sjulian	int namelen,char *name,struct thread *td,struct ucred *cred)
28551852Sbp{
28674062Sbp	struct ncp_rq *rqp;
28751852Sbp	int error;
28851852Sbp	struct ncp_conn *conn=NWFSTOCONN(nmp);
28951852Sbp
29083366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
29174062Sbp	if (error)
29274062Sbp		return error;
29374062Sbp	mb_put_uint8(&rqp->rq, 8);		/* subfunction */
29474062Sbp	mb_put_uint8(&rqp->rq, nmp->name_space);
29574062Sbp	mb_put_uint8(&rqp->rq, 0);		/* reserved */
29674062Sbp	mb_put_uint16le(&rqp->rq, SA_ALL);	/* search attribs: all */
29751852Sbp	ncp_rq_dbase_path(rqp, nmp->n_volume, dirent, namelen, name, &nmp->m.nls);
29874062Sbp	error = ncp_request(rqp);
29974062Sbp	if (!error)
30074062Sbp		ncp_rq_done(rqp);
30151852Sbp	return error;
30251852Sbp}
30351852Sbp
30451852Sbpint
30551852Sbpncp_nsrename(struct ncp_conn *conn, int volume, int ns, int oldtype,
30651852Sbp	struct ncp_nlstables *nt,
30751852Sbp	nwdirent fdir, char *old_name, int oldlen,
30851852Sbp	nwdirent tdir, char *new_name, int newlen,
30983366Sjulian	struct thread *td, struct ucred *cred)
31051852Sbp{
31174062Sbp	struct ncp_rq *rqp;
31251852Sbp	int error;
31351852Sbp
31483366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
31574062Sbp	if (error)
31674062Sbp		return error;
31774062Sbp	mb_put_uint8(&rqp->rq, 4);
31874062Sbp	mb_put_uint8(&rqp->rq, ns);
31974062Sbp	mb_put_uint8(&rqp->rq, 1);	/* RRenameToMySelf */
32074062Sbp	mb_put_uint16le(&rqp->rq, oldtype);
32151852Sbp	/* source Handle Path */
32274062Sbp	mb_put_uint8(&rqp->rq, volume);
32374062Sbp	mb_put_mem(&rqp->rq, (c_caddr_t)&fdir, sizeof(fdir), MB_MSYSTEM);
32474062Sbp	mb_put_uint8(&rqp->rq, 1);
32574062Sbp	mb_put_uint8(&rqp->rq, 1);	/* 1 source component */
32651852Sbp	/* dest Handle Path */
32774062Sbp	mb_put_uint8(&rqp->rq, volume);
32874062Sbp	mb_put_mem(&rqp->rq, (c_caddr_t)&tdir, sizeof(tdir), MB_MSYSTEM);
32974062Sbp	mb_put_uint8(&rqp->rq, 1);
33074062Sbp	mb_put_uint8(&rqp->rq, 1);	/* 1 destination component */
33151852Sbp	ncp_rq_pathstring(rqp, oldlen, old_name, nt);
33251852Sbp	ncp_rq_pathstring(rqp, newlen, new_name, nt);
33374062Sbp	error = ncp_request(rqp);
33474062Sbp	if (!error)
33574062Sbp		ncp_rq_done(rqp);
33651852Sbp	return error;
33751852Sbp}
33851852Sbp
33951852Sbpint
34051852Sbpncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp,
34151852Sbp				u_int32_t info_mask,
34251852Sbp				struct nw_modify_dos_info *info,
34383366Sjulian				struct thread *td,struct ucred *cred)
34451852Sbp{
34551852Sbp	struct nwnode *np=VTONW(vp);
34674062Sbp	struct ncp_rq *rqp;
34751852Sbp	u_int8_t volnum = nmp->n_volume;
34851852Sbp	u_int32_t dirent = np->n_fid.f_id;
34951852Sbp	struct ncp_conn *conn=NWFSTOCONN(nmp);
35051852Sbp	int             error;
35151852Sbp
35283366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
35374062Sbp	if (error)
35474062Sbp		return error;
35574062Sbp	mb_put_uint8(&rqp->rq, 7);	/* subfunction */
35674062Sbp	mb_put_uint8(&rqp->rq, nmp->name_space);
35774062Sbp	mb_put_uint8(&rqp->rq, 0);	/* reserved */
35874062Sbp	mb_put_uint16le(&rqp->rq, SA_ALL);	/* search attribs: all */
35974062Sbp	mb_put_uint32le(&rqp->rq, info_mask);
36074062Sbp	mb_put_mem(&rqp->rq, (caddr_t)info, sizeof(*info), MB_MSYSTEM);
36151852Sbp	ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
36274062Sbp	error = ncp_request(rqp);
36374062Sbp	if (!error)
36474062Sbp		ncp_rq_done(rqp);
36551852Sbp	return error;
36651852Sbp}
36751852Sbp
36851852Sbpint
36983366Sjulianncp_setattr(vp, vap, cred, td)
37066539Sbp	struct vnode *vp;
37166539Sbp	struct vattr *vap;
37251852Sbp	struct ucred *cred;
37383366Sjulian	struct thread *td;
37451852Sbp{
37551852Sbp	struct nwmount *nmp=VTONWFS(vp);
37651852Sbp	struct nwnode *np=VTONW(vp);
37751852Sbp	struct ncp_open_info nwn;
37851852Sbp	struct ncp_conn *conn=NWFSTOCONN(nmp);
37951852Sbp	struct nw_modify_dos_info info;
38074062Sbp	struct ncp_rq *rqp;
38151852Sbp	int error = 0, info_mask;
38251852Sbp
38351852Sbp	if (vap->va_size != VNOVAL) {
38451852Sbp		error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
38583366Sjulian						   AR_WRITE | AR_READ, &nwn,td,cred);
38674062Sbp		if (error)
38774062Sbp			return error;
38883366Sjulian		error = ncp_rq_alloc(73, conn, td, cred, &rqp);
38974062Sbp		if (error) {
39083366Sjulian			ncp_close_file(conn, &nwn.fh, td, cred);
39174062Sbp			return error;
39274062Sbp		}
39374062Sbp		mb_put_uint8(&rqp->rq, 0);
39474062Sbp		mb_put_mem(&rqp->rq, (caddr_t)&nwn.fh, 6, MB_MSYSTEM);
39574062Sbp		mb_put_uint32be(&rqp->rq, vap->va_size);
39674062Sbp		mb_put_uint16be(&rqp->rq, 0);
39774062Sbp		error = ncp_request(rqp);
39851852Sbp		np->n_vattr.va_size = np->n_size = vap->va_size;
39974062Sbp		if (!error)
40074062Sbp			ncp_rq_done(rqp);
40183366Sjulian		ncp_close_file(conn, &nwn.fh, td, cred);
40274062Sbp		if (error)
40374062Sbp			return error;
40451852Sbp	}
40551852Sbp	info_mask = 0;
40651852Sbp	bzero(&info, sizeof(info));
40751852Sbp
40851852Sbp	if (vap->va_mtime.tv_sec != VNOVAL) {
40951852Sbp		info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
41059034Sbp		ncp_unix2dostime(&vap->va_mtime, nmp->m.tz, &info.modifyDate, &info.modifyTime, NULL);
41151852Sbp	}
41251852Sbp	if (vap->va_atime.tv_sec != VNOVAL) {
41351852Sbp		info_mask |= (DM_LAST_ACCESS_DATE);
41459034Sbp		ncp_unix2dostime(&vap->va_atime, nmp->m.tz, &info.lastAccessDate, NULL, NULL);
41551852Sbp	}
41651852Sbp	if (info_mask) {
41783366Sjulian		error = ncp_modify_file_or_subdir_dos_info(nmp, vp, info_mask, &info,td,cred);
41851852Sbp	}
41951852Sbp	return (error);
42051852Sbp}
42151852Sbp
42251852Sbpint
42351852Sbpncp_get_volume_info_with_number(struct ncp_conn *conn,
42474062Sbp	int n, struct ncp_volume_info *target,
42583366Sjulian	struct thread *td,struct ucred *cred)
42674062Sbp{
42774062Sbp	struct ncp_rq *rqp;
42874062Sbp	u_int32_t tmp32;
42974062Sbp	u_int8_t len;
43074062Sbp	int error;
43151852Sbp
43283366Sjulian	error = ncp_rq_alloc_subfn(22, 44, conn, td, cred, &rqp);
43374062Sbp	if (error)
43474062Sbp		return error;
43574062Sbp	mb_put_uint8(&rqp->rq,n);
43674062Sbp	error = ncp_request(rqp);
43774062Sbp	if (error)
43874062Sbp		return error;
43974062Sbp	md_get_uint32le(&rqp->rp, &target->total_blocks);
44074062Sbp	md_get_uint32le(&rqp->rp, &target->free_blocks);
44174062Sbp	md_get_uint32le(&rqp->rp, &target->purgeable_blocks);
44274062Sbp	md_get_uint32le(&rqp->rp, &target->not_yet_purgeable_blocks);
44374062Sbp	md_get_uint32le(&rqp->rp, &target->total_dir_entries);
44474062Sbp	md_get_uint32le(&rqp->rp, &target->available_dir_entries);
44574062Sbp	md_get_uint32le(&rqp->rp, &tmp32);
44674062Sbp	md_get_uint8(&rqp->rp, &target->sectors_per_block);
44751852Sbp	bzero(&target->volume_name, sizeof(target->volume_name));
44874062Sbp	md_get_uint8(&rqp->rp, &len);
44951852Sbp	if (len > NCP_VOLNAME_LEN) {
45051852Sbp		error = ENAMETOOLONG;
45151852Sbp	} else {
45274062Sbp		md_get_mem(&rqp->rp, (caddr_t)&target->volume_name, len, MB_MSYSTEM);
45351852Sbp	}
45474062Sbp	ncp_rq_done(rqp);
45551852Sbp	return error;
45651852Sbp}
45751852Sbp
45851852Sbpint
45951852Sbpncp_get_namespaces(struct ncp_conn *conn, u_int32_t volume, int *nsf,
46083366Sjulian	struct thread *td,struct ucred *cred)
46174062Sbp{
46274062Sbp	struct ncp_rq *rqp;
46351852Sbp	int error;
46451852Sbp	u_int8_t ns;
46551852Sbp	u_int16_t nscnt;
46651852Sbp
46783366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
46874062Sbp	if (error)
46974062Sbp		return error;
47074062Sbp	mb_put_uint8(&rqp->rq, 24);	/* Subfunction: Get Loaded Name Spaces */
47174062Sbp	mb_put_uint16le(&rqp->rq, 0);	/* reserved */
47274062Sbp	mb_put_uint8(&rqp->rq, volume);
47374062Sbp	error = ncp_request(rqp);
47474062Sbp	if (error)
47574062Sbp		return error;
47674062Sbp	md_get_uint16le(&rqp->rp, &nscnt);
47751852Sbp	*nsf = 0;
47851852Sbp	while (nscnt-- > 0) {
47974062Sbp		md_get_uint8(&rqp->rp, &ns);
48051852Sbp		*nsf |= 1 << ns;
48151852Sbp	}
48274062Sbp	ncp_rq_done(rqp);
48351852Sbp	return error;
48451852Sbp}
48551852Sbp
48651852Sbpint
48751852Sbpncp_lookup_volume(struct ncp_conn *conn, char *volname,
48851852Sbp		u_char *volNum, u_int32_t *dirEnt,
48983366Sjulian		struct thread *td,struct ucred *cred)
49051852Sbp{
49174062Sbp	struct ncp_rq *rqp;
49274062Sbp	u_int32_t tmp32;
49351852Sbp	int error;
49451852Sbp
49551852Sbp	NCPNDEBUG("looking up vol %s\n", volname);
49683366Sjulian	error = ncp_rq_alloc(87, conn, td, cred, &rqp);
49774062Sbp	if (error)
49874062Sbp		return error;
49974062Sbp	mb_put_uint8(&rqp->rq, 22);	/* Subfunction: Generate dir handle */
50074062Sbp	mb_put_uint8(&rqp->rq, 0);	/* src name space */
50174062Sbp	mb_put_uint8(&rqp->rq, 0);	/* dst name space, always zero */
50274062Sbp	mb_put_uint16le(&rqp->rq, 0);	/* dstNSIndicator (Jn) */
50351852Sbp
50474062Sbp	mb_put_uint8(&rqp->rq, 0);	/* faked volume number */
50574062Sbp	mb_put_uint32be(&rqp->rq, 0);	/* faked dir_base */
50674062Sbp	mb_put_uint8(&rqp->rq, 0xff);	/* Don't have a dir_base */
50774062Sbp	mb_put_uint8(&rqp->rq, 1);	/* 1 path component */
50851852Sbp	ncp_rq_pstring(rqp, volname);
50974062Sbp	error = ncp_request(rqp);
51074062Sbp	if (error)
51174062Sbp		return error;
51274062Sbp	md_get_uint32le(&rqp->rp, &tmp32);
51374062Sbp	md_get_uint32le(&rqp->rp, dirEnt);
51474062Sbp	md_get_uint8(&rqp->rp, volNum);
51574062Sbp	ncp_rq_done(rqp);
51651852Sbp	return error;
51751852Sbp}
51851852Sbp
51951852Sbp/*
520163651Sphk * XXX: I think the timezone in struct nwfs_args is truly bogus, especially
521163651Sphk * XXX: considering that nwfs_mount(8) picks this up from the kernel in
522163651Sphk * XXX: the first place.  Since I can't test this, I won't attempt to fix it.
523163651Sphk * XXX: /phk
52451852Sbp */
52551852Sbp
52651852Sbpvoid
52759034Sbpncp_unix2dostime(tsp, tzoff, ddp, dtp, dhp)
52851852Sbp	struct timespec *tsp;
52959034Sbp	int tzoff;
53051852Sbp	u_int16_t *ddp;
53151852Sbp	u_int16_t *dtp;
53251852Sbp	u_int8_t *dhp;
53351852Sbp{
534163651Sphk	struct timespec t;
53551852Sbp
536163651Sphk	t = *tsp;
537163651Sphk
538163651Sphk	t.tv_sec = - tzoff * 60 - utc_offset();
539163651Sphk	timespec2fattime(&t, 1, ddp, dtp, dhp);
54051852Sbp}
54151852Sbp
54251852Sbpvoid
54359034Sbpncp_dos2unixtime(dd, dt, dh, tzoff, tsp)
54451852Sbp	u_int dd;
54551852Sbp	u_int dt;
54651852Sbp	u_int dh;
54759034Sbp	int tzoff;
54851852Sbp	struct timespec *tsp;
54951852Sbp{
55051852Sbp
551163651Sphk	fattime2timespec(dd, dt, dh, 1, tsp);
552163651Sphk	tsp->tv_sec += tzoff * 60 + utc_offset();
55351852Sbp}
554