File:  [DragonFly] / src / sys / vfs / nwfs / nwfs_subr.c
Revision 1.6: download - view: text, annotated - select for diffs
Thu Apr 22 17:56:44 2004 UTC (9 years, 11 months ago) by cpressey
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Style(9) cleanup to src/sys/vfs, stage 13/21: nwfs.

- Convert K&R-style function definitions to ANSI style.

Submitted-by: Andre Nathan <andre@digirati.com.br>
Additional-reformatting-by: cpressey

    1: /*
    2:  * Copyright (c) 1999, Boris Popov
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. All advertising materials mentioning features or use of this software
   14:  *    must display the following acknowledgement:
   15:  *    This product includes software developed by Boris Popov.
   16:  * 4. Neither the name of the author nor the names of any co-contributors
   17:  *    may be used to endorse or promote products derived from this software
   18:  *    without specific prior written permission.
   19:  *
   20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30:  * SUCH DAMAGE.
   31:  *
   32:  * $FreeBSD: src/sys/nwfs/nwfs_subr.c,v 1.2.2.2 2000/10/25 02:11:10 bp Exp $
   33:  * $DragonFly: src/sys/vfs/nwfs/nwfs_subr.c,v 1.6 2004/04/22 17:56:44 cpressey Exp $
   34:  */
   35: #include <sys/param.h>
   36: #include <sys/systm.h>
   37: #include <sys/kernel.h>
   38: #include <sys/malloc.h>
   39: #include <machine/clock.h>
   40: #include <sys/time.h>
   41: 
   42: #include <netproto/ncp/ncp.h>
   43: #include <netproto/ncp/ncp_conn.h>
   44: #include <netproto/ncp/ncp_ncp.h>
   45: #include <netproto/ncp/ncp_subr.h>
   46: #include <netproto/ncp/ncp_rq.h>
   47: #include <netproto/ncp/nwerror.h>
   48: 
   49: #include "nwfs.h"
   50: #include "nwfs_node.h"
   51: #include "nwfs_subr.h"
   52: 
   53: MALLOC_DEFINE(M_NWFSDATA, "NWFS data", "NWFS private data");
   54: 
   55: static void 
   56: ncp_extract_file_info(struct nwmount *nmp, struct ncp_rq *rqp,
   57: 		      struct nw_entry_info *target)
   58: {
   59: 	u_char name_len;
   60: 	const int info_struct_size = sizeof(struct nw_entry_info) - 257;
   61: 
   62: 	ncp_rp_mem(rqp,(caddr_t)target,info_struct_size);
   63: 	name_len = ncp_rp_byte(rqp);
   64: 	target->nameLen = name_len;
   65: 	ncp_rp_mem(rqp,(caddr_t)target->entryName, name_len);
   66: 	target->entryName[name_len] = '\0';
   67: 	ncp_path2unix(target->entryName, target->entryName, name_len, &nmp->m.nls);
   68: 	return;
   69: }
   70: 
   71: static void 
   72: ncp_update_file_info(struct nwmount *nmp, struct ncp_rq *rqp, 
   73: 		     struct nw_entry_info *target)
   74: {
   75: 	int info_struct_size = sizeof(struct nw_entry_info) - 257;
   76: 
   77: 	ncp_rp_mem(rqp,(caddr_t)target,info_struct_size);
   78: 	return;
   79: }
   80: 
   81: int
   82: ncp_initsearch(struct vnode *dvp, struct thread *td, struct ucred *cred)
   83: {
   84: 	struct nwmount *nmp = VTONWFS(dvp);
   85: 	struct ncp_conn *conn = NWFSTOCONN(nmp);
   86: 	struct nwnode *np = VTONW(dvp);
   87: 	u_int8_t volnum = nmp->n_volume;
   88: 	u_int32_t dirent = np->n_fid.f_id;
   89: 	int error;
   90: 	DECLARE_RQ;
   91: 
   92: 	NCPNDEBUG("vol=%d,dir=%d\n", volnum, dirent);
   93: 	NCP_RQ_HEAD(87,td,cred);
   94: 	ncp_rq_byte(rqp, 2);		/* subfunction */
   95: 	ncp_rq_byte(rqp, nmp->name_space);
   96: 	ncp_rq_byte(rqp, 0);		/* reserved */
   97: 	ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
   98: 	checkbad(ncp_request(conn,rqp));
   99: 	ncp_rp_mem(rqp,(caddr_t)&np->n_seq, sizeof(np->n_seq));
  100: 	NCP_RQ_EXIT;
  101: 	return error;
  102: }
  103: 
  104: int 
  105: ncp_search_for_file_or_subdir(struct nwmount *nmp,
  106: 			      struct nw_search_seq *seq,
  107: 			      struct nw_entry_info *target,
  108: 			      struct thread *td, struct ucred *cred)
  109: {
  110: 	struct ncp_conn *conn = NWFSTOCONN(nmp);
  111: 	int error;
  112: 	DECLARE_RQ;
  113: 
  114: 	NCP_RQ_HEAD(87,td,cred);
  115: 	ncp_rq_byte(rqp, 3);		/* subfunction */
  116: 	ncp_rq_byte(rqp, nmp->name_space);
  117: 	ncp_rq_byte(rqp, 0);		/* data stream */
  118: 	ncp_rq_word_lh(rqp, 0xffff);	/* Search attribs */
  119: 	ncp_rq_dword(rqp, IM_ALL);	/* return info mask */
  120: 	ncp_rq_mem(rqp, (caddr_t)seq, 9);
  121: 	ncp_rq_byte(rqp, 2);		/* 2 byte pattern */
  122: 	ncp_rq_byte(rqp, 0xff);		/* following is a wildcard */
  123: 	ncp_rq_byte(rqp, '*');
  124: 	checkbad(ncp_request(conn,rqp));
  125: 	ncp_rp_mem(rqp,(caddr_t)seq, sizeof(*seq));
  126: 	ncp_rp_byte(rqp);		/* skip */
  127: 	ncp_extract_file_info(nmp, rqp, target);
  128: 	NCP_RQ_EXIT;
  129: 	return error;
  130: }
  131: 
  132: /*
  133:  * Returns information for a (one-component) name relative to the specified
  134:  * directory.
  135:  */
  136: int 
  137: ncp_obtain_info(struct nwmount *nmp, u_int32_t dirent,
  138: 		int namelen, char *path, struct nw_entry_info *target,
  139: 		struct thread *td, struct ucred *cred)
  140: {
  141: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  142: 	int error;
  143: 	u_char volnum = nmp->n_volume, ns;
  144: 	DECLARE_RQ;
  145: 
  146: 	if (target == NULL) {
  147: 		NCPFATAL("target == NULL\n");
  148: 		return EINVAL;
  149: 	}
  150: 	ns = (path == NULL || path[0] == 0) ? NW_NS_DOS : nmp->name_space;
  151: 	NCP_RQ_HEAD(87, td, cred);
  152: 	ncp_rq_byte(rqp, 6);			/* subfunction */
  153: 	ncp_rq_byte(rqp, ns);
  154: 	ncp_rq_byte(rqp, ns);	/* DestNameSpace */
  155: 	ncp_rq_word(rqp, htons(0xff00));	/* get all */
  156: 	ncp_rq_dword(rqp, IM_ALL);
  157: 	ncp_rq_dbase_path(rqp, volnum, dirent, namelen, path, &nmp->m.nls);
  158: 	checkbad(ncp_request(conn,rqp));
  159: 	if (path)
  160: 		ncp_extract_file_info(nmp, rqp, target);
  161: 	else
  162: 		ncp_update_file_info(nmp, rqp, target);
  163: 	NCP_RQ_EXIT;
  164: 	return error;
  165: }
  166: /* 
  167:  * lookup name pointed by cnp in directory dvp and return file info in np.
  168:  * May be I should create a little cache, but another way is to minimize
  169:  * number of calls, on other hand, in multiprocess environment ...
  170:  */
  171: int
  172: ncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap,
  173: 	   struct thread *td, struct ucred *cred)
  174: {
  175: 	struct nwmount *nmp;
  176: 	struct nwnode *dnp = VTONW(dvp);
  177: 	struct ncp_conn *conn;
  178: 	int error;
  179: 
  180: 	if (!dvp || dvp->v_type != VDIR) {
  181: 		nwfs_printf("dvp is NULL or not a directory.\n");
  182: 		return (ENOENT);
  183: 	}
  184: 	nmp = VTONWFS(dvp);
  185: 	conn = NWFSTOCONN(nmp);
  186: 
  187: 	if (len == 1 && name[0] == '.') {
  188: 		if (strcmp(dnp->n_name, NWFS_ROOTVOL) == 0) {
  189: 			error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 0, NULL,
  190: 				fap, td, cred);
  191: 		} else {
  192: 			error = ncp_obtain_info(nmp, dnp->n_fid.f_parent, 
  193: 				dnp->n_nmlen, dnp->n_name, fap, td, cred);
  194: 		}
  195: 		return error;
  196: 	} else if (len == 2 && name[0] == '.' && name[1] == '.') {
  197: 		printf("%s: knows NOTHING about '..'\n", __FUNCTION__);
  198: 		return EIO;
  199: 	} else {
  200: 		error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 
  201: 			len, name, fap, td, cred);
  202: 	}
  203: 	return error;
  204: }
  205: 
  206: static void ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh);
  207: static void 
  208: ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh) {
  209: 	fh->val1 = (fh->val.val32 = sfd);
  210: 	return;
  211: }
  212: 
  213: /*
  214:  * If both dir and name are NULL, then in target there's already a looked-up
  215:  * entry that wants to be opened.
  216:  */
  217: int 
  218: ncp_open_create_file_or_subdir(struct nwmount *nmp, struct vnode *dvp,
  219: 			       int namelen, char *name, int open_create_mode,
  220: 			       u_int32_t create_attributes,
  221: 			       int desired_acc_rights,
  222: 			       struct ncp_open_info *nop,
  223: 			       struct thread *td, struct ucred *cred)
  224: {
  225: 	
  226: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  227: 	u_int16_t search_attribs = SA_ALL & (~SA_SUBDIR_FILES);
  228: 	u_int8_t volnum;
  229: 	u_int32_t dirent;
  230: 	int error;
  231: 	DECLARE_RQ;
  232: 
  233: 	volnum = nmp->n_volume;
  234: 	dirent = VTONW(dvp)->n_fid.f_id;
  235: 	if ((create_attributes & aDIR) != 0) {
  236: 		search_attribs |= SA_SUBDIR_FILES;
  237: 	}
  238: 	NCP_RQ_HEAD(87,td,cred);
  239: 	ncp_rq_byte(rqp, 1);/* subfunction */
  240: 	ncp_rq_byte(rqp, nmp->name_space);
  241: 	ncp_rq_byte(rqp, open_create_mode);
  242: 	ncp_rq_word(rqp, search_attribs);
  243: 	ncp_rq_dword(rqp, IM_ALL);
  244: 	ncp_rq_dword(rqp, create_attributes);
  245: 	/*
  246: 	 * The desired acc rights seem to be the inherited rights mask for
  247: 	 * directories
  248: 	 */
  249: 	ncp_rq_word(rqp, desired_acc_rights);
  250: 	ncp_rq_dbase_path(rqp, volnum, dirent, namelen, name, &nmp->m.nls);
  251: 	checkbad(ncp_request(conn,rqp));
  252: 
  253: 	nop->origfh = ncp_rp_dword_lh(rqp);
  254: 	nop->action = ncp_rp_byte(rqp);
  255: 	ncp_rp_byte(rqp);	/* skip */
  256: 	ncp_extract_file_info(nmp, rqp, &nop->fattr);
  257: 	ConvertToNWfromDWORD(nop->origfh, &nop->fh);
  258: 	NCP_RQ_EXIT;
  259: 	switch(error) {
  260: 	    case NWE_FILE_NO_CREATE_PRIV:
  261: 		error = EACCES;
  262: 		break;
  263: 	}
  264: 	return error;
  265: }
  266: 
  267: int
  268: ncp_close_file(struct ncp_conn *conn, ncp_fh *fh, struct thread *td,
  269: 	       struct ucred *cred)
  270: {
  271: 	int error;
  272: 	DECLARE_RQ;
  273: 
  274: 	NCP_RQ_HEAD(66,td,cred);
  275: 	ncp_rq_byte(rqp, 0);
  276: 	ncp_rq_mem(rqp, (caddr_t)fh, 6);
  277: 	error = ncp_request(conn,rqp);
  278: 	NCP_RQ_EXIT_NB;
  279: 	return error;
  280: }
  281: 
  282: int
  283: ncp_DeleteNSEntry(struct nwmount *nmp, u_int32_t dirent, int namelen,
  284: 		  char *name, struct thread *td, struct ucred *cred)
  285: {
  286: 	int error;
  287: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  288: 	DECLARE_RQ;
  289: 
  290: 	NCP_RQ_HEAD(87,td,cred);
  291: 	ncp_rq_byte(rqp, 8);		/* subfunction */
  292: 	ncp_rq_byte(rqp, nmp->name_space);
  293: 	ncp_rq_byte(rqp, 0);		/* reserved */
  294: 	ncp_rq_word(rqp, SA_ALL);	/* search attribs: all */
  295: 	ncp_rq_dbase_path(rqp, nmp->n_volume, dirent, namelen, name, &nmp->m.nls);
  296: 	error = ncp_request(conn,rqp);
  297: 	NCP_RQ_EXIT_NB;
  298: 	return error;
  299: }
  300: 
  301: int 
  302: ncp_nsrename(struct ncp_conn *conn, int volume, int ns, int oldtype, 
  303: 	     struct ncp_nlstables *nt, nwdirent fdir, char *old_name,
  304: 	     int oldlen, nwdirent tdir, char *new_name, int newlen,
  305: 	     struct thread *td, struct ucred *cred)
  306: {
  307: 	DECLARE_RQ;
  308: 	int error;
  309: 
  310: 	NCP_RQ_HEAD(87,td,cred);
  311: 	ncp_rq_byte(rqp, 4);
  312: 	ncp_rq_byte(rqp, ns);
  313: 	ncp_rq_byte(rqp, 1);
  314: 	ncp_rq_word(rqp, oldtype);
  315: 	/* source Handle Path */
  316: 	ncp_rq_byte(rqp, volume);
  317: 	ncp_rq_dword(rqp, fdir);
  318: 	ncp_rq_byte(rqp, 1);
  319: 	ncp_rq_byte(rqp, 1);	/* 1 source component */
  320: 	/* dest Handle Path */
  321: 	ncp_rq_byte(rqp, volume);
  322: 	ncp_rq_dword(rqp, tdir);
  323: 	ncp_rq_byte(rqp, 1);
  324: 	ncp_rq_byte(rqp, 1);	/* 1 destination component */
  325: 	ncp_rq_pathstring(rqp, oldlen, old_name, nt);
  326: 	ncp_rq_pathstring(rqp, newlen, new_name, nt);
  327: 	error = ncp_request(conn,rqp);
  328: 	NCP_RQ_EXIT_NB;
  329: 	return error;
  330: }
  331: 
  332: int
  333: ncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp, 
  334: 				   u_int32_t info_mask,
  335: 				   struct nw_modify_dos_info *info,
  336: 				   struct thread *td, struct ucred *cred)
  337: {
  338: 	struct nwnode *np=VTONW(vp);
  339: 	u_int8_t volnum = nmp->n_volume;
  340: 	u_int32_t dirent = np->n_fid.f_id;
  341: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  342: 	int             error;
  343: 	DECLARE_RQ;
  344: 
  345: 	NCP_RQ_HEAD(87,td,cred);
  346: 	ncp_rq_byte(rqp, 7);	/* subfunction */
  347: 	ncp_rq_byte(rqp, nmp->name_space);
  348: 	ncp_rq_byte(rqp, 0);	/* reserved */
  349: 	ncp_rq_word(rqp, htons(0x0680));	/* search attribs: all */
  350: 	ncp_rq_dword(rqp, info_mask);
  351: 	ncp_rq_mem(rqp, (caddr_t)info, sizeof(*info));
  352: 	ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
  353: 	error = ncp_request(conn,rqp);
  354: 	NCP_RQ_EXIT_NB;
  355: 	return error;
  356: }
  357: 
  358: int
  359: ncp_setattr(struct vnode *vp, struct vattr *vap, struct ucred *cred,
  360: 	    struct thread *td)
  361: {
  362: 	struct nwmount *nmp=VTONWFS(vp);
  363: 	struct nwnode *np=VTONW(vp);
  364: 	struct ncp_open_info nwn;
  365: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  366: 	struct nw_modify_dos_info info;
  367: 	int error = 0, info_mask;
  368: 	DECLARE_RQ;
  369: 
  370: 	if (vap->va_size != VNOVAL) {
  371: 		error = ncp_open_create_file_or_subdir(
  372: 			    nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
  373: 			    AR_WRITE | AR_READ, &nwn,td,cred);
  374: 		if (error) return error;
  375: 		NCP_RQ_HEAD(73,td,cred);
  376: 		ncp_rq_byte(rqp, 0);
  377: 		ncp_rq_mem(rqp, (caddr_t)&nwn.fh, 6);
  378: 		ncp_rq_dword(rqp, htonl(vap->va_size));
  379: 		ncp_rq_word_hl(rqp, 0);
  380: 		checkbad(ncp_request(conn,rqp));
  381: 		np->n_vattr.va_size = np->n_size = vap->va_size;
  382: 		NCP_RQ_EXIT;
  383: 		ncp_close_file(conn, &nwn.fh, td, cred);
  384: 		if (error) return error;
  385: 	}
  386: 	info_mask = 0;
  387: 	bzero(&info, sizeof(info));
  388: 
  389: 	if (vap->va_mtime.tv_sec != VNOVAL) {
  390: 		info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
  391: 		ncp_unix2dostime(&vap->va_mtime, nmp->m.tz, &info.modifyDate, &info.modifyTime, NULL);
  392: 	}
  393: 	if (vap->va_atime.tv_sec != VNOVAL) {
  394: 		info_mask |= (DM_LAST_ACCESS_DATE);
  395: 		ncp_unix2dostime(&vap->va_atime, nmp->m.tz, &info.lastAccessDate, NULL, NULL);
  396: 	}
  397: 	if (info_mask) {
  398: 		error = ncp_modify_file_or_subdir_dos_info(nmp, vp, info_mask, &info,td,cred);
  399: 	}
  400: 	return (error);
  401: }
  402: 
  403: int
  404: ncp_get_volume_info_with_number(struct ncp_conn *conn, int n,
  405: 			        struct ncp_volume_info *target,
  406: 				struct thread *td, struct ucred *cred)
  407: {
  408: 	int error,len;
  409: 	DECLARE_RQ;
  410: 
  411: 	NCP_RQ_HEAD_S(22,44,td,cred);
  412: 	ncp_rq_byte(rqp,n);
  413: 	checkbad(ncp_request(conn,rqp));
  414: 	target->total_blocks = ncp_rp_dword_lh(rqp);
  415: 	target->free_blocks = ncp_rp_dword_lh(rqp);
  416: 	target->purgeable_blocks = ncp_rp_dword_lh(rqp);
  417: 	target->not_yet_purgeable_blocks = ncp_rp_dword_lh(rqp);
  418: 	target->total_dir_entries = ncp_rp_dword_lh(rqp);
  419: 	target->available_dir_entries = ncp_rp_dword_lh(rqp);
  420: 	ncp_rp_dword_lh(rqp);
  421: 	target->sectors_per_block = ncp_rp_byte(rqp);
  422: 	bzero(&target->volume_name, sizeof(target->volume_name));
  423: 	len = ncp_rp_byte(rqp);
  424: 	if (len > NCP_VOLNAME_LEN) {
  425: 		error = ENAMETOOLONG;
  426: 	} else {
  427: 		ncp_rp_mem(rqp,(caddr_t)&target->volume_name, len);
  428: 	}
  429: 	NCP_RQ_EXIT;
  430: 	return error;
  431: }
  432: 
  433: int
  434: ncp_get_namespaces(struct ncp_conn *conn, u_int32_t volume, int *nsf,
  435: 		   struct thread *td, struct ucred *cred)
  436: {
  437: 	int error;
  438: 	u_int8_t ns;
  439: 	u_int16_t nscnt;
  440: 	DECLARE_RQ;
  441: 
  442: 	NCP_RQ_HEAD(87,td,cred);
  443: 	ncp_rq_byte(rqp, 24);	/* Subfunction: Get Loaded Name Spaces */
  444: 	ncp_rq_word(rqp, 0);
  445: 	ncp_rq_byte(rqp, volume);
  446: 	checkbad(ncp_request(conn,rqp));
  447: 	nscnt = ncp_rp_word_lh(rqp);
  448: 	*nsf = 0;
  449: 	while (nscnt-- > 0) {
  450: 		ns = ncp_rp_byte(rqp);
  451: 		*nsf |= 1 << ns;
  452: 	}
  453: 	NCP_RQ_EXIT;
  454: 	return error;
  455: }
  456: 
  457: int
  458: ncp_lookup_volume(struct ncp_conn *conn, char *volname, 
  459: 		  u_char *volNum, u_int32_t *dirEnt,
  460: 		  struct thread *td, struct ucred *cred)
  461: {
  462: 	int error;
  463: 	DECLARE_RQ;
  464: 
  465: 	NCPNDEBUG("looking up vol %s\n", volname);
  466: 	NCP_RQ_HEAD(87,td,cred);
  467: 	ncp_rq_byte(rqp, 22);	/* Subfunction: Generate dir handle */
  468: 	ncp_rq_byte(rqp, 0);	/* src name space */
  469: 	ncp_rq_byte(rqp, 0);	/* dst name space, always zero */
  470: 	ncp_rq_word(rqp, 0);	/* dstNSIndicator */
  471: 
  472: 	ncp_rq_byte(rqp, 0);	/* faked volume number */
  473: 	ncp_rq_dword(rqp, 0);	/* faked dir_base */
  474: 	ncp_rq_byte(rqp, 0xff);	/* Don't have a dir_base */
  475: 	ncp_rq_byte(rqp, 1);	/* 1 path component */
  476: 	ncp_rq_pstring(rqp, volname);
  477: 	checkbad(ncp_request(conn,rqp));
  478: 	ncp_rp_dword_lh(rqp); 	/* NSDirectoryBase*/
  479: 	*dirEnt = ncp_rp_dword_lh(rqp);
  480: 	*volNum = ncp_rp_byte(rqp);
  481: 	NCP_RQ_EXIT;
  482: 	return error;
  483: }
  484: 
  485: /* 
  486:  * Time & date conversion routines taken from msdosfs. Although leap
  487:  * year calculation is bogus, it's sufficient before 2100 :)
  488:  */
  489: /*
  490:  * This is the format of the contents of the deTime field in the direntry
  491:  * structure.
  492:  * We don't use bitfields because we don't know how compilers for
  493:  * arbitrary machines will lay them out.
  494:  */
  495: #define DT_2SECONDS_MASK	0x1F	/* seconds divided by 2 */
  496: #define DT_2SECONDS_SHIFT	0
  497: #define DT_MINUTES_MASK		0x7E0	/* minutes */
  498: #define DT_MINUTES_SHIFT	5
  499: #define DT_HOURS_MASK		0xF800	/* hours */
  500: #define DT_HOURS_SHIFT		11
  501: 
  502: /*
  503:  * This is the format of the contents of the deDate field in the direntry
  504:  * structure.
  505:  */
  506: #define DD_DAY_MASK		0x1F	/* day of month */
  507: #define DD_DAY_SHIFT		0
  508: #define DD_MONTH_MASK		0x1E0	/* month */
  509: #define DD_MONTH_SHIFT		5
  510: #define DD_YEAR_MASK		0xFE00	/* year - 1980 */
  511: #define DD_YEAR_SHIFT		9
  512: /*
  513:  * Total number of days that have passed for each month in a regular year.
  514:  */
  515: static u_short regyear[] = {
  516: 	31, 59, 90, 120, 151, 181,
  517: 	212, 243, 273, 304, 334, 365
  518: };
  519: 
  520: /*
  521:  * Total number of days that have passed for each month in a leap year.
  522:  */
  523: static u_short leapyear[] = {
  524: 	31, 60, 91, 121, 152, 182,
  525: 	213, 244, 274, 305, 335, 366
  526: };
  527: 
  528: /*
  529:  * Variables used to remember parts of the last time conversion.  Maybe we
  530:  * can avoid a full conversion.
  531:  */
  532: static u_long  lasttime;
  533: static u_long  lastday;
  534: static u_short lastddate;
  535: static u_short lastdtime;
  536: /*
  537:  * Convert the unix version of time to dos's idea of time to be used in
  538:  * file timestamps. The passed in unix time is assumed to be in GMT.
  539:  */
  540: void
  541: ncp_unix2dostime(struct timespec *tsp, int tzoff, u_int16_t *ddp,
  542: 		 u_int16_t *dtp, u_int8_t *dhp)
  543: {
  544: 	u_long t;
  545: 	u_long days;
  546: 	u_long inc;
  547: 	u_long year;
  548: 	u_long month;
  549: 	u_short *months;
  550: 
  551: 	/*
  552: 	 * If the time from the last conversion is the same as now, then
  553: 	 * skip the computations and use the saved result.
  554: 	 */
  555: 	t = tsp->tv_sec - tzoff * 60 - tz.tz_minuteswest * 60 -
  556: 	    (wall_cmos_clock ? adjkerntz : 0);
  557: 	t &= ~1;
  558: 	if (lasttime != t) {
  559: 		lasttime = t;
  560: 		lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
  561: 		    + (((t / 60) % 60) << DT_MINUTES_SHIFT)
  562: 		    + (((t / 3600) % 24) << DT_HOURS_SHIFT);
  563: 
  564: 		/*
  565: 		 * If the number of days since 1970 is the same as the last
  566: 		 * time we did the computation then skip all this leap year
  567: 		 * and month stuff.
  568: 		 */
  569: 		days = t / (24 * 60 * 60);
  570: 		if (days != lastday) {
  571: 			lastday = days;
  572: 			for (year = 1970;; year++) {
  573: 				inc = year & 0x03 ? 365 : 366;
  574: 				if (days < inc)
  575: 					break;
  576: 				days -= inc;
  577: 			}
  578: 			months = year & 0x03 ? regyear : leapyear;
  579: 			for (month = 0; days >= months[month]; month++)
  580: 				;
  581: 			if (month > 0)
  582: 				days -= months[month - 1];
  583: 			lastddate = ((days + 1) << DD_DAY_SHIFT)
  584: 			    + ((month + 1) << DD_MONTH_SHIFT);
  585: 			/*
  586: 			 * Remember dos's idea of time is relative to 1980.
  587: 			 * unix's is relative to 1970.  If somehow we get a
  588: 			 * time before 1980 then don't give totally crazy
  589: 			 * results.
  590: 			 */
  591: 			if (year > 1980)
  592: 				lastddate += (year - 1980) << DD_YEAR_SHIFT;
  593: 		}
  594: 	}
  595: 	if (dtp)
  596: 		*dtp = lastdtime;
  597: 	if (dhp)
  598: 		*dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
  599: 
  600: 	*ddp = lastddate;
  601: }
  602: 
  603: /*
  604:  * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
  605:  * interval there were 8 regular years and 2 leap years.
  606:  */
  607: #define	SECONDSTO1980	(((8 * 365) + (2 * 366)) * (24 * 60 * 60))
  608: 
  609: static u_short lastdosdate;
  610: static u_long  lastseconds;
  611: 
  612: /*
  613:  * Convert from dos' idea of time to unix'. This will probably only be
  614:  * called from the stat(), and fstat() system calls and so probably need
  615:  * not be too efficient.
  616:  */
  617: void
  618: ncp_dos2unixtime(u_int dd, u_int dt, u_int dh, int tzoff, struct timespec *tsp)
  619: {
  620: 	u_long seconds;
  621: 	u_long month;
  622: 	u_long year;
  623: 	u_long days;
  624: 	u_short *months;
  625: 
  626: 	if (dd == 0) {
  627: 		/*
  628: 		 * Uninitialized field, return the epoch.
  629: 		 */
  630: 		tsp->tv_sec = 0;
  631: 		tsp->tv_nsec = 0;
  632: 		return;
  633: 	}
  634: 	seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
  635: 	    + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
  636: 	    + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
  637: 	    + dh / 100;
  638: 	/*
  639: 	 * If the year, month, and day from the last conversion are the
  640: 	 * same then use the saved value.
  641: 	 */
  642: 	if (lastdosdate != dd) {
  643: 		lastdosdate = dd;
  644: 		days = 0;
  645: 		year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
  646: 		days = year * 365;
  647: 		days += year / 4 + 1;	/* add in leap days */
  648: 		if ((year & 0x03) == 0)
  649: 			days--;		/* if year is a leap year */
  650: 		months = year & 0x03 ? regyear : leapyear;
  651: 		month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
  652: 		if (month < 1 || month > 12) {
  653: 			month = 1;
  654: 		}
  655: 		if (month > 1)
  656: 			days += months[month - 2];
  657: 		days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
  658: 		lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
  659: 	}
  660: 	tsp->tv_sec = seconds + lastseconds + tz.tz_minuteswest * 60 +
  661: 	    tzoff * 60 + (wall_cmos_clock ? adjkerntz : 0);
  662: 	tsp->tv_nsec = (dh % 100) * 10000000;
  663: }