File:  [DragonFly] / src / sys / vfs / nwfs / nwfs_subr.c
Revision 1.5: download - view: text, annotated - select for diffs
Thu Aug 7 21:54:35 2003 UTC (11 years, 2 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
kernel tree reorganization stage 1: Major cvs repository work (not logged as
commits) plus a major reworking of the #include's to accomodate the
relocations.

    * CVS repository files manually moved.  Old directories left intact
      and empty (temporary).

    * Reorganize all filesystems into vfs/, most devices into dev/,
      sub-divide devices by function.

    * Begin to move device-specific architecture files to the device
      subdirs rather then throwing them all into, e.g. i386/include

    * Reorganize files related to system busses, placing the related code
      in a new bus/ directory.  Also move cam to bus/cam though this may
      not have been the best idea in retrospect.

    * Reorganize emulation code and place it in a new emulation/ directory.

    * Remove the -I- compiler option in order to allow #include file
      localization, rename all config generated X.h files to use_X.h to
      clean up the conflicts.

    * Remove /usr/src/include (or /usr/include) dependancies during the
      kernel build, beyond what is normally needed to compile helper
      programs.

    * Make config create 'machine' softlinks for architecture specific
      directories outside of the standard <arch>/include.

    * Bump the config rev.

    WARNING! after this commit /usr/include and /usr/src/sys/compile/*
    should be regenerated from scratch.

    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.5 2003/08/07 21:54:35 dillon 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, struct nw_entry_info *target) {
   57: 	u_char name_len;
   58: 	const int info_struct_size = sizeof(struct nw_entry_info) - 257;
   59: 
   60: 	ncp_rp_mem(rqp,(caddr_t)target,info_struct_size);
   61: 	name_len = ncp_rp_byte(rqp);
   62: 	target->nameLen = name_len;
   63: 	ncp_rp_mem(rqp,(caddr_t)target->entryName, name_len);
   64: 	target->entryName[name_len] = '\0';
   65: 	ncp_path2unix(target->entryName, target->entryName, name_len, &nmp->m.nls);
   66: 	return;
   67: }
   68: 
   69: static void 
   70: ncp_update_file_info(struct nwmount *nmp, struct ncp_rq *rqp, 
   71: 	struct nw_entry_info *target)
   72: {
   73: 	int info_struct_size = sizeof(struct nw_entry_info) - 257;
   74: 
   75: 	ncp_rp_mem(rqp,(caddr_t)target,info_struct_size);
   76: 	return;
   77: }
   78: 
   79: int
   80: ncp_initsearch(struct vnode *dvp,struct thread *td,struct ucred *cred)
   81: {
   82: 	struct nwmount *nmp = VTONWFS(dvp);
   83: 	struct ncp_conn *conn = NWFSTOCONN(nmp);
   84: 	struct nwnode *np = VTONW(dvp);
   85: 	u_int8_t volnum = nmp->n_volume;
   86: 	u_int32_t dirent = np->n_fid.f_id;
   87: 	int error;
   88: 	DECLARE_RQ;
   89: 
   90: 	NCPNDEBUG("vol=%d,dir=%d\n", volnum, dirent);
   91: 	NCP_RQ_HEAD(87,td,cred);
   92: 	ncp_rq_byte(rqp, 2);		/* subfunction */
   93: 	ncp_rq_byte(rqp, nmp->name_space);
   94: 	ncp_rq_byte(rqp, 0);		/* reserved */
   95: 	ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
   96: 	checkbad(ncp_request(conn,rqp));
   97: 	ncp_rp_mem(rqp,(caddr_t)&np->n_seq, sizeof(np->n_seq));
   98: 	NCP_RQ_EXIT;
   99: 	return error;
  100: }
  101: 
  102: int 
  103: ncp_search_for_file_or_subdir(struct nwmount *nmp,
  104: 			      struct nw_search_seq *seq,
  105: 			      struct nw_entry_info *target,
  106: 			      struct thread *td,struct ucred *cred)
  107: {
  108: 	struct ncp_conn *conn = NWFSTOCONN(nmp);
  109: 	int error;
  110: 	DECLARE_RQ;
  111: 
  112: 	NCP_RQ_HEAD(87,td,cred);
  113: 	ncp_rq_byte(rqp, 3);		/* subfunction */
  114: 	ncp_rq_byte(rqp, nmp->name_space);
  115: 	ncp_rq_byte(rqp, 0);		/* data stream */
  116: 	ncp_rq_word_lh(rqp, 0xffff);	/* Search attribs */
  117: 	ncp_rq_dword(rqp, IM_ALL);	/* return info mask */
  118: 	ncp_rq_mem(rqp, (caddr_t)seq, 9);
  119: 	ncp_rq_byte(rqp, 2);		/* 2 byte pattern */
  120: 	ncp_rq_byte(rqp, 0xff);		/* following is a wildcard */
  121: 	ncp_rq_byte(rqp, '*');
  122: 	checkbad(ncp_request(conn,rqp));
  123: 	ncp_rp_mem(rqp,(caddr_t)seq, sizeof(*seq));
  124: 	ncp_rp_byte(rqp);		/* skip */
  125: 	ncp_extract_file_info(nmp, rqp, target);
  126: 	NCP_RQ_EXIT;
  127: 	return error;
  128: }
  129: 
  130: /*
  131:  * Returns information for a (one-component) name relative to the specified
  132:  * directory.
  133:  */
  134: int 
  135: ncp_obtain_info(struct nwmount *nmp,  u_int32_t dirent,
  136: 		int namelen, char *path, struct nw_entry_info *target,
  137: 		struct thread *td,struct ucred *cred)
  138: {
  139: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  140: 	int error;
  141: 	u_char volnum = nmp->n_volume, ns;
  142: 	DECLARE_RQ;
  143: 
  144: 	if (target == NULL) {
  145: 		NCPFATAL("target == NULL\n");
  146: 		return EINVAL;
  147: 	}
  148: 	ns = (path == NULL || path[0] == 0) ? NW_NS_DOS : nmp->name_space;
  149: 	NCP_RQ_HEAD(87, td, cred);
  150: 	ncp_rq_byte(rqp, 6);			/* subfunction */
  151: 	ncp_rq_byte(rqp, ns);
  152: 	ncp_rq_byte(rqp, ns);	/* DestNameSpace */
  153: 	ncp_rq_word(rqp, htons(0xff00));	/* get all */
  154: 	ncp_rq_dword(rqp, IM_ALL);
  155: 	ncp_rq_dbase_path(rqp, volnum, dirent, namelen, path, &nmp->m.nls);
  156: 	checkbad(ncp_request(conn,rqp));
  157: 	if (path)
  158: 		ncp_extract_file_info(nmp, rqp, target);
  159: 	else
  160: 		ncp_update_file_info(nmp, rqp, target);
  161: 	NCP_RQ_EXIT;
  162: 	return error;
  163: }
  164: /* 
  165:  * lookup name pointed by cnp in directory dvp and return file info in np.
  166:  * May be I should create a little cache, but another way is to minimize
  167:  * number of calls, on other hand, in multiprocess environment ...
  168:  */
  169: int
  170: ncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap,
  171: 		struct thread *td,struct ucred *cred)
  172: {
  173: 	struct nwmount *nmp;
  174: 	struct nwnode *dnp = VTONW(dvp);
  175: 	struct ncp_conn *conn;
  176: 	int error;
  177: 
  178: 	if (!dvp || dvp->v_type != VDIR) {
  179: 		nwfs_printf("dvp is NULL or not a directory.\n");
  180: 		return (ENOENT);
  181: 	}
  182: 	nmp = VTONWFS(dvp);
  183: 	conn = NWFSTOCONN(nmp);
  184: 
  185: 	if (len == 1 && name[0] == '.') {
  186: 		if (strcmp(dnp->n_name, NWFS_ROOTVOL) == 0) {
  187: 			error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 0, NULL,
  188: 				fap, td, cred);
  189: 		} else {
  190: 			error = ncp_obtain_info(nmp, dnp->n_fid.f_parent, 
  191: 				dnp->n_nmlen, dnp->n_name, fap, td, cred);
  192: 		}
  193: 		return error;
  194: 	} else if (len == 2 && name[0] == '.' && name[1] == '.') {
  195: 		printf("%s: knows NOTHING about '..'\n", __FUNCTION__);
  196: 		return EIO;
  197: 	} else {
  198: 		error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 
  199: 			len, name, fap, td, cred);
  200: 	}
  201: 	return error;
  202: }
  203: 
  204: static void ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh);
  205: static void 
  206: ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh) {
  207: 	fh->val1 = (fh->val.val32 = sfd);
  208: 	return;
  209: }
  210: 
  211: /*
  212:  * If both dir and name are NULL, then in target there's already a looked-up
  213:  * entry that wants to be opened.
  214:  */
  215: int 
  216: ncp_open_create_file_or_subdir(struct nwmount *nmp,struct vnode *dvp,int namelen,
  217: 	    char *name, int open_create_mode, u_int32_t create_attributes,
  218: 	    int desired_acc_rights, struct ncp_open_info *nop,
  219: 	    struct thread *td,struct ucred *cred)
  220: {
  221: 	
  222: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  223: 	u_int16_t search_attribs = SA_ALL & (~SA_SUBDIR_FILES);
  224: 	u_int8_t volnum;
  225: 	u_int32_t dirent;
  226: 	int error;
  227: 	DECLARE_RQ;
  228: 
  229: 	volnum = nmp->n_volume;
  230: 	dirent = VTONW(dvp)->n_fid.f_id;
  231: 	if ((create_attributes & aDIR) != 0) {
  232: 		search_attribs |= SA_SUBDIR_FILES;
  233: 	}
  234: 	NCP_RQ_HEAD(87,td,cred);
  235: 	ncp_rq_byte(rqp, 1);/* subfunction */
  236: 	ncp_rq_byte(rqp, nmp->name_space);
  237: 	ncp_rq_byte(rqp, open_create_mode);
  238: 	ncp_rq_word(rqp, search_attribs);
  239: 	ncp_rq_dword(rqp, IM_ALL);
  240: 	ncp_rq_dword(rqp, create_attributes);
  241: 	/*
  242: 	 * The desired acc rights seem to be the inherited rights mask for
  243: 	 * directories
  244: 	 */
  245: 	ncp_rq_word(rqp, desired_acc_rights);
  246: 	ncp_rq_dbase_path(rqp, volnum, dirent, namelen, name, &nmp->m.nls);
  247: 	checkbad(ncp_request(conn,rqp));
  248: 
  249: 	nop->origfh = ncp_rp_dword_lh(rqp);
  250: 	nop->action = ncp_rp_byte(rqp);
  251: 	ncp_rp_byte(rqp);	/* skip */
  252: 	ncp_extract_file_info(nmp, rqp, &nop->fattr);
  253: 	ConvertToNWfromDWORD(nop->origfh, &nop->fh);
  254: 	NCP_RQ_EXIT;
  255: 	switch(error) {
  256: 	    case NWE_FILE_NO_CREATE_PRIV:
  257: 		error = EACCES;
  258: 		break;
  259: 	}
  260: 	return error;
  261: }
  262: 
  263: int
  264: ncp_close_file(struct ncp_conn *conn, ncp_fh *fh,struct thread *td,struct ucred *cred) {
  265: 	int error;
  266: 	DECLARE_RQ;
  267: 
  268: 	NCP_RQ_HEAD(66,td,cred);
  269: 	ncp_rq_byte(rqp, 0);
  270: 	ncp_rq_mem(rqp, (caddr_t)fh, 6);
  271: 	error = ncp_request(conn,rqp);
  272: 	NCP_RQ_EXIT_NB;
  273: 	return error;
  274: }
  275: 
  276: int
  277: ncp_DeleteNSEntry(struct nwmount *nmp, u_int32_t dirent,
  278: 			int namelen,char *name,struct thread *td,struct ucred *cred)
  279: {
  280: 	int error;
  281: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  282: 	DECLARE_RQ;
  283: 
  284: 	NCP_RQ_HEAD(87,td,cred);
  285: 	ncp_rq_byte(rqp, 8);		/* subfunction */
  286: 	ncp_rq_byte(rqp, nmp->name_space);
  287: 	ncp_rq_byte(rqp, 0);		/* reserved */
  288: 	ncp_rq_word(rqp, SA_ALL);	/* search attribs: all */
  289: 	ncp_rq_dbase_path(rqp, nmp->n_volume, dirent, namelen, name, &nmp->m.nls);
  290: 	error = ncp_request(conn,rqp);
  291: 	NCP_RQ_EXIT_NB;
  292: 	return error;
  293: }
  294: 
  295: int 
  296: ncp_nsrename(struct ncp_conn *conn, int volume, int ns, int oldtype, 
  297: 	struct ncp_nlstables *nt,
  298: 	nwdirent fdir, char *old_name, int oldlen,
  299: 	nwdirent tdir, char *new_name, int newlen,
  300: 	struct thread *td, struct ucred *cred)
  301: {
  302: 	DECLARE_RQ;
  303: 	int error;
  304: 
  305: 	NCP_RQ_HEAD(87,td,cred);
  306: 	ncp_rq_byte(rqp, 4);
  307: 	ncp_rq_byte(rqp, ns);
  308: 	ncp_rq_byte(rqp, 1);
  309: 	ncp_rq_word(rqp, oldtype);
  310: 	/* source Handle Path */
  311: 	ncp_rq_byte(rqp, volume);
  312: 	ncp_rq_dword(rqp, fdir);
  313: 	ncp_rq_byte(rqp, 1);
  314: 	ncp_rq_byte(rqp, 1);	/* 1 source component */
  315: 	/* dest Handle Path */
  316: 	ncp_rq_byte(rqp, volume);
  317: 	ncp_rq_dword(rqp, tdir);
  318: 	ncp_rq_byte(rqp, 1);
  319: 	ncp_rq_byte(rqp, 1);	/* 1 destination component */
  320: 	ncp_rq_pathstring(rqp, oldlen, old_name, nt);
  321: 	ncp_rq_pathstring(rqp, newlen, new_name, nt);
  322: 	error = ncp_request(conn,rqp);
  323: 	NCP_RQ_EXIT_NB;
  324: 	return error;
  325: }
  326: 
  327: int
  328: ncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp, 
  329: 				u_int32_t info_mask,
  330: 				struct nw_modify_dos_info *info,
  331: 				struct thread *td,struct ucred *cred)
  332: {
  333: 	struct nwnode *np=VTONW(vp);
  334: 	u_int8_t volnum = nmp->n_volume;
  335: 	u_int32_t dirent = np->n_fid.f_id;
  336: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  337: 	int             error;
  338: 	DECLARE_RQ;
  339: 
  340: 	NCP_RQ_HEAD(87,td,cred);
  341: 	ncp_rq_byte(rqp, 7);	/* subfunction */
  342: 	ncp_rq_byte(rqp, nmp->name_space);
  343: 	ncp_rq_byte(rqp, 0);	/* reserved */
  344: 	ncp_rq_word(rqp, htons(0x0680));	/* search attribs: all */
  345: 	ncp_rq_dword(rqp, info_mask);
  346: 	ncp_rq_mem(rqp, (caddr_t)info, sizeof(*info));
  347: 	ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
  348: 	error = ncp_request(conn,rqp);
  349: 	NCP_RQ_EXIT_NB;
  350: 	return error;
  351: }
  352: 
  353: int
  354: ncp_setattr(vp, vap, cred, td)
  355: 	struct vnode *vp;
  356: 	struct vattr *vap;
  357: 	struct ucred *cred;
  358: 	struct thread *td;
  359: {
  360: 	struct nwmount *nmp=VTONWFS(vp);
  361: 	struct nwnode *np=VTONW(vp);
  362: 	struct ncp_open_info nwn;
  363: 	struct ncp_conn *conn=NWFSTOCONN(nmp);
  364: 	struct nw_modify_dos_info info;
  365: 	int error = 0, info_mask;
  366: 	DECLARE_RQ;
  367: 
  368: 	if (vap->va_size != VNOVAL) {
  369: 		error = ncp_open_create_file_or_subdir(
  370: 			    nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
  371: 			    AR_WRITE | AR_READ, &nwn,td,cred);
  372: 		if (error) return error;
  373: 		NCP_RQ_HEAD(73,td,cred);
  374: 		ncp_rq_byte(rqp, 0);
  375: 		ncp_rq_mem(rqp, (caddr_t)&nwn.fh, 6);
  376: 		ncp_rq_dword(rqp, htonl(vap->va_size));
  377: 		ncp_rq_word_hl(rqp, 0);
  378: 		checkbad(ncp_request(conn,rqp));
  379: 		np->n_vattr.va_size = np->n_size = vap->va_size;
  380: 		NCP_RQ_EXIT;
  381: 		ncp_close_file(conn, &nwn.fh, td, cred);
  382: 		if (error) return error;
  383: 	}
  384: 	info_mask = 0;
  385: 	bzero(&info, sizeof(info));
  386: 
  387: 	if (vap->va_mtime.tv_sec != VNOVAL) {
  388: 		info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
  389: 		ncp_unix2dostime(&vap->va_mtime, nmp->m.tz, &info.modifyDate, &info.modifyTime, NULL);
  390: 	}
  391: 	if (vap->va_atime.tv_sec != VNOVAL) {
  392: 		info_mask |= (DM_LAST_ACCESS_DATE);
  393: 		ncp_unix2dostime(&vap->va_atime, nmp->m.tz, &info.lastAccessDate, NULL, NULL);
  394: 	}
  395: 	if (info_mask) {
  396: 		error = ncp_modify_file_or_subdir_dos_info(nmp, vp, info_mask, &info,td,cred);
  397: 	}
  398: 	return (error);
  399: }
  400: 
  401: int
  402: ncp_get_volume_info_with_number(struct ncp_conn *conn, 
  403: 	    int n, struct ncp_volume_info *target,
  404: 	    struct thread *td,struct ucred *cred) {
  405: 	int error,len;
  406: 	DECLARE_RQ;
  407: 
  408: 	NCP_RQ_HEAD_S(22,44,td,cred);
  409: 	ncp_rq_byte(rqp,n);
  410: 	checkbad(ncp_request(conn,rqp));
  411: 	target->total_blocks = ncp_rp_dword_lh(rqp);
  412: 	target->free_blocks = ncp_rp_dword_lh(rqp);
  413: 	target->purgeable_blocks = ncp_rp_dword_lh(rqp);
  414: 	target->not_yet_purgeable_blocks = ncp_rp_dword_lh(rqp);
  415: 	target->total_dir_entries = ncp_rp_dword_lh(rqp);
  416: 	target->available_dir_entries = ncp_rp_dword_lh(rqp);
  417: 	ncp_rp_dword_lh(rqp);
  418: 	target->sectors_per_block = ncp_rp_byte(rqp);
  419: 	bzero(&target->volume_name, sizeof(target->volume_name));
  420: 	len = ncp_rp_byte(rqp);
  421: 	if (len > NCP_VOLNAME_LEN) {
  422: 		error = ENAMETOOLONG;
  423: 	} else {
  424: 		ncp_rp_mem(rqp,(caddr_t)&target->volume_name, len);
  425: 	}
  426: 	NCP_RQ_EXIT;
  427: 	return error;
  428: }
  429: 
  430: int
  431: ncp_get_namespaces(struct ncp_conn *conn, u_int32_t volume, int *nsf,
  432: 	    struct thread *td,struct ucred *cred) {
  433: 	int error;
  434: 	u_int8_t ns;
  435: 	u_int16_t nscnt;
  436: 	DECLARE_RQ;
  437: 
  438: 	NCP_RQ_HEAD(87,td,cred);
  439: 	ncp_rq_byte(rqp, 24);	/* Subfunction: Get Loaded Name Spaces */
  440: 	ncp_rq_word(rqp, 0);
  441: 	ncp_rq_byte(rqp, volume);
  442: 	checkbad(ncp_request(conn,rqp));
  443: 	nscnt = ncp_rp_word_lh(rqp);
  444: 	*nsf = 0;
  445: 	while (nscnt-- > 0) {
  446: 		ns = ncp_rp_byte(rqp);
  447: 		*nsf |= 1 << ns;
  448: 	}
  449: 	NCP_RQ_EXIT;
  450: 	return error;
  451: }
  452: 
  453: int
  454: ncp_lookup_volume(struct ncp_conn *conn, char *volname, 
  455: 		u_char *volNum, u_int32_t *dirEnt,
  456: 		struct thread *td,struct ucred *cred)
  457: {
  458: 	int error;
  459: 	DECLARE_RQ;
  460: 
  461: 	NCPNDEBUG("looking up vol %s\n", volname);
  462: 	NCP_RQ_HEAD(87,td,cred);
  463: 	ncp_rq_byte(rqp, 22);	/* Subfunction: Generate dir handle */
  464: 	ncp_rq_byte(rqp, 0);	/* src name space */
  465: 	ncp_rq_byte(rqp, 0);	/* dst name space, always zero */
  466: 	ncp_rq_word(rqp, 0);	/* dstNSIndicator */
  467: 
  468: 	ncp_rq_byte(rqp, 0);	/* faked volume number */
  469: 	ncp_rq_dword(rqp, 0);	/* faked dir_base */
  470: 	ncp_rq_byte(rqp, 0xff);	/* Don't have a dir_base */
  471: 	ncp_rq_byte(rqp, 1);	/* 1 path component */
  472: 	ncp_rq_pstring(rqp, volname);
  473: 	checkbad(ncp_request(conn,rqp));
  474: 	ncp_rp_dword_lh(rqp); 	/* NSDirectoryBase*/
  475: 	*dirEnt = ncp_rp_dword_lh(rqp);
  476: 	*volNum = ncp_rp_byte(rqp);
  477: 	NCP_RQ_EXIT;
  478: 	return error;
  479: }
  480: 
  481: /* 
  482:  * Time & date conversion routines taken from msdosfs. Although leap
  483:  * year calculation is bogus, it's sufficient before 2100 :)
  484:  */
  485: /*
  486:  * This is the format of the contents of the deTime field in the direntry
  487:  * structure.
  488:  * We don't use bitfields because we don't know how compilers for
  489:  * arbitrary machines will lay them out.
  490:  */
  491: #define DT_2SECONDS_MASK	0x1F	/* seconds divided by 2 */
  492: #define DT_2SECONDS_SHIFT	0
  493: #define DT_MINUTES_MASK		0x7E0	/* minutes */
  494: #define DT_MINUTES_SHIFT	5
  495: #define DT_HOURS_MASK		0xF800	/* hours */
  496: #define DT_HOURS_SHIFT		11
  497: 
  498: /*
  499:  * This is the format of the contents of the deDate field in the direntry
  500:  * structure.
  501:  */
  502: #define DD_DAY_MASK		0x1F	/* day of month */
  503: #define DD_DAY_SHIFT		0
  504: #define DD_MONTH_MASK		0x1E0	/* month */
  505: #define DD_MONTH_SHIFT		5
  506: #define DD_YEAR_MASK		0xFE00	/* year - 1980 */
  507: #define DD_YEAR_SHIFT		9
  508: /*
  509:  * Total number of days that have passed for each month in a regular year.
  510:  */
  511: static u_short regyear[] = {
  512: 	31, 59, 90, 120, 151, 181,
  513: 	212, 243, 273, 304, 334, 365
  514: };
  515: 
  516: /*
  517:  * Total number of days that have passed for each month in a leap year.
  518:  */
  519: static u_short leapyear[] = {
  520: 	31, 60, 91, 121, 152, 182,
  521: 	213, 244, 274, 305, 335, 366
  522: };
  523: 
  524: /*
  525:  * Variables used to remember parts of the last time conversion.  Maybe we
  526:  * can avoid a full conversion.
  527:  */
  528: static u_long  lasttime;
  529: static u_long  lastday;
  530: static u_short lastddate;
  531: static u_short lastdtime;
  532: /*
  533:  * Convert the unix version of time to dos's idea of time to be used in
  534:  * file timestamps. The passed in unix time is assumed to be in GMT.
  535:  */
  536: void
  537: ncp_unix2dostime(tsp, tzoff, ddp, dtp, dhp)
  538: 	struct timespec *tsp;
  539: 	int tzoff;
  540: 	u_int16_t *ddp;
  541: 	u_int16_t *dtp;
  542: 	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(dd, dt, dh, tzoff, tsp)
  619: 	u_int dd;
  620: 	u_int dt;
  621: 	u_int dh;
  622: 	int tzoff;
  623: 	struct timespec *tsp;
  624: {
  625: 	u_long seconds;
  626: 	u_long month;
  627: 	u_long year;
  628: 	u_long days;
  629: 	u_short *months;
  630: 
  631: 	if (dd == 0) {
  632: 		/*
  633: 		 * Uninitialized field, return the epoch.
  634: 		 */
  635: 		tsp->tv_sec = 0;
  636: 		tsp->tv_nsec = 0;
  637: 		return;
  638: 	}
  639: 	seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
  640: 	    + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
  641: 	    + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
  642: 	    + dh / 100;
  643: 	/*
  644: 	 * If the year, month, and day from the last conversion are the
  645: 	 * same then use the saved value.
  646: 	 */
  647: 	if (lastdosdate != dd) {
  648: 		lastdosdate = dd;
  649: 		days = 0;
  650: 		year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
  651: 		days = year * 365;
  652: 		days += year / 4 + 1;	/* add in leap days */
  653: 		if ((year & 0x03) == 0)
  654: 			days--;		/* if year is a leap year */
  655: 		months = year & 0x03 ? regyear : leapyear;
  656: 		month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
  657: 		if (month < 1 || month > 12) {
  658: 			month = 1;
  659: 		}
  660: 		if (month > 1)
  661: 			days += months[month - 2];
  662: 		days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
  663: 		lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
  664: 	}
  665: 	tsp->tv_sec = seconds + lastseconds + tz.tz_minuteswest * 60 +
  666: 	    tzoff * 60 + (wall_cmos_clock ? adjkerntz : 0);
  667: 	tsp->tv_nsec = (dh % 100) * 10000000;
  668: }