The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nwfs/nwfs_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 04a2df92cd7edfb7a3b94f9c45318e14


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.