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/fs/smbfs/smbfs_smb.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) 2000-2001 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 <sys/proc.h>
   39 #include <sys/lock.h>
   40 #include <sys/vnode.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/mount.h>
   43 
   44 #ifdef USE_MD5_HASH
   45 #include <sys/md5.h>
   46 #endif
   47 
   48 #include <netsmb/smb.h>
   49 #include <netsmb/smb_subr.h>
   50 #include <netsmb/smb_rq.h>
   51 #include <netsmb/smb_conn.h>
   52 
   53 #include <fs/smbfs/smbfs.h>
   54 #include <fs/smbfs/smbfs_node.h>
   55 #include <fs/smbfs/smbfs_subr.h>
   56 
   57 /*
   58  * Lack of inode numbers leads us to the problem of generating them.
   59  * Partially this problem can be solved by having a dir/file cache
   60  * with inode numbers generated from the incremented by one counter.
   61  * However this way will require too much kernel memory, gives all
   62  * sorts of locking and consistency problems, not to mentinon counter overflows.
   63  * So, I'm decided to use a hash function to generate pseudo random (and unique)
   64  * inode numbers.
   65  */
   66 static long
   67 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
   68 {
   69 #ifdef USE_MD5_HASH
   70         MD5_CTX md5;
   71         u_int32_t state[4];
   72         long ino;
   73         int i;
   74 
   75         MD5Init(&md5);
   76         MD5Update(&md5, name, nmlen);
   77         MD5Final((u_char *)state, &md5);
   78         for (i = 0, ino = 0; i < 4; i++)
   79                 ino += state[i];
   80         return dnp->n_ino + ino;
   81 #endif
   82         u_int32_t ino;
   83 
   84         ino = dnp->n_ino + smbfs_hash(name, nmlen);
   85         if (ino <= 2)
   86                 ino += 3;
   87         return ino;
   88 }
   89 
   90 static int
   91 smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
   92         struct smb_cred *scred)
   93 {
   94         struct smb_share *ssp = np->n_mount->sm_share;
   95         struct smb_rq rq, *rqp = &rq;
   96         struct mbchain *mbp;
   97         u_char ltype = 0;
   98         int error;
   99 
  100         if (op == SMB_LOCK_SHARED)
  101                 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
  102         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred);
  103         if (error)
  104                 return error;
  105         smb_rq_getrequest(rqp, &mbp);
  106         smb_rq_wstart(rqp);
  107         mb_put_uint8(mbp, 0xff);        /* secondary command */
  108         mb_put_uint8(mbp, 0);           /* MBZ */
  109         mb_put_uint16le(mbp, 0);
  110         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  111         mb_put_uint8(mbp, ltype);       /* locktype */
  112         mb_put_uint8(mbp, 0);           /* oplocklevel - 0 seems is NO_OPLOCK */
  113         mb_put_uint32le(mbp, 0);        /* timeout - break immediately */
  114         mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
  115         mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
  116         smb_rq_wend(rqp);
  117         smb_rq_bstart(rqp);
  118         mb_put_uint16le(mbp, pid);
  119         mb_put_uint32le(mbp, start);
  120         mb_put_uint32le(mbp, end - start);
  121         smb_rq_bend(rqp);
  122         error = smb_rq_simple(rqp);
  123         smb_rq_done(rqp);
  124         return error;
  125 }
  126 
  127 int
  128 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
  129         off_t start, off_t end, struct smb_cred *scred)
  130 {
  131         struct smb_share *ssp = np->n_mount->sm_share;
  132 
  133         if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
  134                 /*
  135                  * TODO: use LOCK_BYTE_RANGE here.
  136                  */
  137                 return EINVAL;
  138         else
  139                 return smbfs_smb_lockandx(np, op, (u_int32_t)id, start, end, scred);
  140 }
  141 
  142 static int
  143 smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
  144                     struct smb_cred *scred, short infolevel)
  145 {
  146         struct smb_share *ssp = np->n_mount->sm_share;
  147         struct smb_vc *vcp = SSTOVC(ssp);
  148         struct smb_t2rq *t2p;
  149         int error, svtz, timesok = 1;
  150         struct mbchain *mbp;
  151         struct mdchain *mdp;
  152         u_int16_t date, time, wattr;
  153         int64_t lint;
  154         u_int32_t size, dattr;
  155 
  156         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
  157                              scred, &t2p);
  158         if (error)
  159                 return error;
  160         mbp = &t2p->t2_tparam;
  161         mb_init(mbp);
  162         if (!infolevel) {
  163                 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
  164                         infolevel = SMB_QUERY_FILE_STANDARD;
  165                 else
  166                         infolevel = SMB_QUERY_FILE_BASIC_INFO;
  167         }
  168         mb_put_uint16le(mbp, infolevel);
  169         mb_put_uint32le(mbp, 0);
  170         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
  171         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
  172         if (error) {
  173                 smb_t2_done(t2p);
  174                 return error;
  175         }
  176         t2p->t2_maxpcount = 2;
  177         t2p->t2_maxdcount = vcp->vc_txmax;
  178         error = smb_t2_request(t2p);
  179         if (error) {
  180                 smb_t2_done(t2p);
  181                 if (infolevel == SMB_QUERY_FILE_STANDARD || error != EINVAL)
  182                         return error;
  183                 return smbfs_smb_qpathinfo(np, fap, scred,
  184                                            SMB_QUERY_FILE_STANDARD);
  185         }
  186         mdp = &t2p->t2_rdata;
  187         svtz = vcp->vc_sopt.sv_tz;
  188         switch (infolevel) {
  189             case SMB_QUERY_FILE_STANDARD:
  190                 timesok = 0;
  191                 md_get_uint16le(mdp, NULL);
  192                 md_get_uint16le(mdp, NULL);     /* creation time */
  193                 md_get_uint16le(mdp, &date);
  194                 md_get_uint16le(mdp, &time);    /* access time */
  195                 if (date || time) {
  196                         timesok++;
  197                         smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
  198                 }
  199                 md_get_uint16le(mdp, &date);
  200                 md_get_uint16le(mdp, &time);    /* modify time */
  201                 if (date || time) {
  202                         timesok++;
  203                         smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
  204                 }
  205                 md_get_uint32le(mdp, &size);
  206                 fap->fa_size = size;
  207                 md_get_uint32(mdp, NULL);       /* allocation size */
  208                 md_get_uint16le(mdp, &wattr);
  209                 fap->fa_attr = wattr;
  210                 break;
  211             case SMB_QUERY_FILE_BASIC_INFO:
  212                 timesok = 0;
  213                 md_get_int64(mdp, NULL);        /* creation time */
  214                 md_get_int64le(mdp, &lint);
  215                 if (lint) {
  216                         timesok++;
  217                         smb_time_NT2local(lint, svtz, &fap->fa_atime);
  218                 }
  219                 md_get_int64le(mdp, &lint);
  220                 if (lint) {
  221                         timesok++;
  222                         smb_time_NT2local(lint, svtz, &fap->fa_mtime);
  223                 }
  224                 md_get_int64le(mdp, &lint);
  225                 if (lint) {
  226                         timesok++;
  227                         smb_time_NT2local(lint, svtz, &fap->fa_ctime);
  228                 }
  229                 md_get_uint32le(mdp, &dattr);
  230                 fap->fa_attr = dattr;
  231                 md_get_uint32(mdp, NULL);
  232                 /* XXX could use ALL_INFO to get size */
  233                 break;
  234             default:
  235                 SMBERROR("unexpected info level %d\n", infolevel);
  236                 error = EINVAL;
  237         }
  238         smb_t2_done(t2p);
  239         /*
  240          * if all times are zero (observed with FAT on NT4SP6)
  241          * then fall back to older info level
  242          */
  243         if (!timesok) {
  244                 if (infolevel != SMB_QUERY_FILE_STANDARD)
  245                         return smbfs_smb_qpathinfo(np, fap, scred,
  246                                                    SMB_QUERY_FILE_STANDARD);
  247                 error = EINVAL;
  248         }
  249         return error;
  250 }
  251 
  252 int
  253 smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
  254         struct smb_cred *scred)
  255 {
  256         struct smb_t2rq *t2p;
  257         struct mbchain *mbp;
  258         struct mdchain *mdp;
  259         u_int16_t bsize;
  260         u_int32_t units, bpu, funits;
  261         int error;
  262 
  263         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
  264             scred, &t2p);
  265         if (error)
  266                 return error;
  267         mbp = &t2p->t2_tparam;
  268         mb_init(mbp);
  269         mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
  270         t2p->t2_maxpcount = 4;
  271         t2p->t2_maxdcount = 4 * 4 + 2;
  272         error = smb_t2_request(t2p);
  273         if (error) {
  274                 smb_t2_done(t2p);
  275                 return error;
  276         }
  277         mdp = &t2p->t2_rdata;
  278         md_get_uint32(mdp, NULL);       /* fs id */
  279         md_get_uint32le(mdp, &bpu);
  280         md_get_uint32le(mdp, &units);
  281         md_get_uint32le(mdp, &funits);
  282         md_get_uint16le(mdp, &bsize);
  283         sbp->f_bsize = bpu * bsize;     /* fundamental filesystem block size */
  284         sbp->f_blocks= units;           /* total data blocks in filesystem */
  285         sbp->f_bfree = funits;          /* free blocks in fs */
  286         sbp->f_bavail= funits;          /* free blocks avail to non-superuser */
  287         sbp->f_files = 0xffff;          /* total file nodes in filesystem */
  288         sbp->f_ffree = 0xffff;          /* free file nodes in fs */
  289         smb_t2_done(t2p);
  290         return 0;
  291 }
  292 
  293 int
  294 smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
  295         struct smb_cred *scred)
  296 {
  297         struct smb_rq rq, *rqp = &rq;
  298         struct mdchain *mdp;
  299         u_int16_t units, bpu, bsize, funits;
  300         int error;
  301 
  302         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred);
  303         if (error)
  304                 return error;
  305         smb_rq_wstart(rqp);
  306         smb_rq_wend(rqp);
  307         smb_rq_bstart(rqp);
  308         smb_rq_bend(rqp);
  309         error = smb_rq_simple(rqp);
  310         if (error) {
  311                 smb_rq_done(rqp);
  312                 return error;
  313         }
  314         smb_rq_getreply(rqp, &mdp);
  315         md_get_uint16le(mdp, &units);
  316         md_get_uint16le(mdp, &bpu);
  317         md_get_uint16le(mdp, &bsize);
  318         md_get_uint16le(mdp, &funits);
  319         sbp->f_bsize = bpu * bsize;     /* fundamental filesystem block size */
  320         sbp->f_blocks= units;           /* total data blocks in filesystem */
  321         sbp->f_bfree = funits;          /* free blocks in fs */
  322         sbp->f_bavail= funits;          /* free blocks avail to non-superuser */
  323         sbp->f_files = 0xffff;          /* total file nodes in filesystem */
  324         sbp->f_ffree = 0xffff;          /* free file nodes in fs */
  325         smb_rq_done(rqp);
  326         return 0;
  327 }
  328 
  329 static int
  330 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
  331 {
  332         struct smb_t2rq *t2p;
  333         struct smb_share *ssp = np->n_mount->sm_share;
  334         struct mbchain *mbp;
  335         int error;
  336 
  337         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
  338             scred, &t2p);
  339         if (error)
  340                 return error;
  341         mbp = &t2p->t2_tparam;
  342         mb_init(mbp);
  343         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  344         mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
  345         mb_put_uint32le(mbp, 0);
  346         mbp = &t2p->t2_tdata;
  347         mb_init(mbp);
  348         mb_put_int64le(mbp, newsize);
  349         mb_put_uint32le(mbp, 0);                        /* padding */
  350         mb_put_uint16le(mbp, 0);
  351         t2p->t2_maxpcount = 2;
  352         t2p->t2_maxdcount = 0;
  353         error = smb_t2_request(t2p);
  354         smb_t2_done(t2p);
  355         return error;
  356 }
  357 
  358 static int
  359 smb_smb_flush(struct smbnode *np, struct smb_cred *scred)
  360 {
  361         struct smb_share *ssp = np->n_mount->sm_share;
  362         struct smb_rq rq, *rqp = &rq;
  363         struct mbchain *mbp;
  364         int error;
  365 
  366         if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
  367             SMBTOV(np)->v_type != VREG)
  368                 return 0; /* not a regular open file */
  369         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred);
  370         if (error)
  371                 return (error);
  372         smb_rq_getrequest(rqp, &mbp);
  373         smb_rq_wstart(rqp);
  374         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  375         smb_rq_wend(rqp);
  376         smb_rq_bstart(rqp);
  377         smb_rq_bend(rqp);
  378         error = smb_rq_simple(rqp);
  379         smb_rq_done(rqp);
  380         if (!error)
  381                 np->n_flag &= ~NFLUSHWIRE;
  382         return (error);
  383 }
  384 
  385 int
  386 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
  387 {
  388         if (np->n_flag & NFLUSHWIRE)
  389                 return (smb_smb_flush(np, scred));
  390         return (0);
  391 }
  392 
  393 int
  394 smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
  395 {
  396         struct smb_share *ssp = np->n_mount->sm_share;
  397         struct smb_rq rq, *rqp = &rq;
  398         struct mbchain *mbp;
  399         int error;
  400 
  401         if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
  402                 np->n_flag |= NFLUSHWIRE;
  403                 return (0);
  404         }
  405 
  406         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred);
  407         if (error)
  408                 return error;
  409         smb_rq_getrequest(rqp, &mbp);
  410         smb_rq_wstart(rqp);
  411         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  412         mb_put_uint16le(mbp, 0);
  413         mb_put_uint32le(mbp, newsize);
  414         mb_put_uint16le(mbp, 0);
  415         smb_rq_wend(rqp);
  416         smb_rq_bstart(rqp);
  417         mb_put_uint8(mbp, SMB_DT_DATA);
  418         mb_put_uint16le(mbp, 0);
  419         smb_rq_bend(rqp);
  420         error = smb_rq_simple(rqp);
  421         smb_rq_done(rqp);
  422         return error;
  423 }
  424 
  425 int
  426 smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
  427                      struct smbfattr *fap, struct smb_cred *scred)
  428 {
  429         struct smb_rq rq, *rqp = &rq;
  430         struct smb_share *ssp = np->n_mount->sm_share;
  431         struct mbchain *mbp;
  432         struct mdchain *mdp;
  433         u_int8_t wc;
  434         int error;
  435         u_int16_t wattr;
  436         u_int32_t lint;
  437 
  438         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred);
  439         if (error)
  440                 return error;
  441         smb_rq_getrequest(rqp, &mbp);
  442         smb_rq_wstart(rqp);
  443         smb_rq_wend(rqp);
  444         smb_rq_bstart(rqp);
  445         mb_put_uint8(mbp, SMB_DT_ASCII);
  446         do {
  447                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
  448                 if (error)
  449                         break;
  450                 smb_rq_bend(rqp);
  451                 error = smb_rq_simple(rqp);
  452                 if (error)
  453                         break;
  454                 smb_rq_getreply(rqp, &mdp);
  455                 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
  456                         error = EBADRPC;
  457                         break;
  458                 }
  459                 md_get_uint16le(mdp, &wattr);
  460                 fap->fa_attr = wattr;
  461                 /*
  462                  * Be careful using the time returned here, as
  463                  * with FAT on NT4SP6, at least, the time returned is low
  464                  * 32 bits of 100s of nanoseconds (since 1601) so it rolls
  465                  * over about every seven minutes!
  466                  */
  467                 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
  468                 if (lint)       /* avoid bogus zero returns */
  469                         smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
  470                                               &fap->fa_mtime);
  471                 md_get_uint32le(mdp, &lint);
  472                 fap->fa_size = lint;
  473         } while(0);
  474         smb_rq_done(rqp);
  475         return error;
  476 }
  477 
  478 /*
  479  * Set DOS file attributes. mtime should be NULL for dialects above lm10
  480  */
  481 int
  482 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
  483         struct smb_cred *scred)
  484 {
  485         struct smb_rq rq, *rqp = &rq;
  486         struct smb_share *ssp = np->n_mount->sm_share;
  487         struct mbchain *mbp;
  488         u_long time;
  489         int error, svtz;
  490 
  491         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred);
  492         if (error)
  493                 return error;
  494         svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
  495         smb_rq_getrequest(rqp, &mbp);
  496         smb_rq_wstart(rqp);
  497         mb_put_uint16le(mbp, attr);
  498         if (mtime) {
  499                 smb_time_local2server(mtime, svtz, &time);
  500         } else
  501                 time = 0;
  502         mb_put_uint32le(mbp, time);             /* mtime */
  503         mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
  504         smb_rq_wend(rqp);
  505         smb_rq_bstart(rqp);
  506         mb_put_uint8(mbp, SMB_DT_ASCII);
  507         do {
  508                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  509                 if (error)
  510                         break;
  511                 mb_put_uint8(mbp, SMB_DT_ASCII);
  512                 mb_put_uint8(mbp, 0);
  513                 smb_rq_bend(rqp);
  514                 error = smb_rq_simple(rqp);
  515                 SMBERROR("%d\n", error);
  516                 if (error)
  517                         break;
  518         } while(0);
  519         smb_rq_done(rqp);
  520         return error;
  521 }
  522 
  523 /*
  524  * Note, win95 doesn't support this call.
  525  */
  526 int
  527 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
  528         struct timespec *atime, int attr, struct smb_cred *scred)
  529 {
  530         struct smb_t2rq *t2p;
  531         struct smb_share *ssp = np->n_mount->sm_share;
  532         struct smb_vc *vcp = SSTOVC(ssp);
  533         struct mbchain *mbp;
  534         u_int16_t date, time;
  535         int error, tzoff;
  536 
  537         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
  538             scred, &t2p);
  539         if (error)
  540                 return error;
  541         mbp = &t2p->t2_tparam;
  542         mb_init(mbp);
  543         mb_put_uint16le(mbp, SMB_INFO_STANDARD);
  544         mb_put_uint32le(mbp, 0);                /* MBZ */
  545         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
  546         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
  547         if (error) {
  548                 smb_t2_done(t2p);
  549                 return error;
  550         }
  551         tzoff = vcp->vc_sopt.sv_tz;
  552         mbp = &t2p->t2_tdata;
  553         mb_init(mbp);
  554         mb_put_uint32le(mbp, 0);                /* creation time */
  555         if (atime)
  556                 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
  557         else
  558                 time = date = 0;
  559         mb_put_uint16le(mbp, date);
  560         mb_put_uint16le(mbp, time);
  561         if (mtime)
  562                 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
  563         else
  564                 time = date = 0;
  565         mb_put_uint16le(mbp, date);
  566         mb_put_uint16le(mbp, time);
  567         mb_put_uint32le(mbp, 0);                /* file size */
  568         mb_put_uint32le(mbp, 0);                /* allocation unit size */
  569         mb_put_uint16le(mbp, attr);     /* DOS attr */
  570         mb_put_uint32le(mbp, 0);                /* EA size */
  571         t2p->t2_maxpcount = 5 * 2;
  572         t2p->t2_maxdcount = vcp->vc_txmax;
  573         error = smb_t2_request(t2p);
  574         smb_t2_done(t2p);
  575         return error;
  576 }
  577 
  578 /*
  579  * NT level. Specially for win9x
  580  */
  581 int
  582 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
  583         struct timespec *atime, struct smb_cred *scred)
  584 {
  585         struct smb_t2rq *t2p;
  586         struct smb_share *ssp = np->n_mount->sm_share;
  587         struct smb_vc *vcp = SSTOVC(ssp);
  588         struct mbchain *mbp;
  589         int64_t tm;
  590         int error, tzoff;
  591 
  592         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
  593             scred, &t2p);
  594         if (error)
  595                 return error;
  596         mbp = &t2p->t2_tparam;
  597         mb_init(mbp);
  598         mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
  599         mb_put_uint32le(mbp, 0);                /* MBZ */
  600         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
  601         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
  602         if (error) {
  603                 smb_t2_done(t2p);
  604                 return error;
  605         }
  606         tzoff = vcp->vc_sopt.sv_tz;
  607         mbp = &t2p->t2_tdata;
  608         mb_init(mbp);
  609         mb_put_int64le(mbp, 0);         /* creation time */
  610         if (atime) {
  611                 smb_time_local2NT(atime, tzoff, &tm);
  612         } else
  613                 tm = 0;
  614         mb_put_int64le(mbp, tm);
  615         if (mtime) {
  616                 smb_time_local2NT(mtime, tzoff, &tm);
  617         } else
  618                 tm = 0;
  619         mb_put_int64le(mbp, tm);
  620         mb_put_int64le(mbp, tm);                /* change time */
  621         mb_put_uint32le(mbp, attr);             /* attr */
  622         t2p->t2_maxpcount = 24;
  623         t2p->t2_maxdcount = 56;
  624         error = smb_t2_request(t2p);
  625         smb_t2_done(t2p);
  626         return error;
  627 }
  628 
  629 /*
  630  * Set file atime and mtime. Doesn't supported by core dialect.
  631  */
  632 int
  633 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
  634         struct timespec *atime, struct smb_cred *scred)
  635 {
  636         struct smb_rq rq, *rqp = &rq;
  637         struct smb_share *ssp = np->n_mount->sm_share;
  638         struct mbchain *mbp;
  639         u_int16_t date, time;
  640         int error, tzoff;
  641 
  642         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred);
  643         if (error)
  644                 return error;
  645         tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
  646         smb_rq_getrequest(rqp, &mbp);
  647         smb_rq_wstart(rqp);
  648         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  649         mb_put_uint32le(mbp, 0);                /* creation time */
  650 
  651         if (atime)
  652                 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
  653         else
  654                 time = date = 0;
  655         mb_put_uint16le(mbp, date);
  656         mb_put_uint16le(mbp, time);
  657         if (mtime)
  658                 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
  659         else
  660                 time = date = 0;
  661         mb_put_uint16le(mbp, date);
  662         mb_put_uint16le(mbp, time);
  663         smb_rq_wend(rqp);
  664         smb_rq_bstart(rqp);
  665         smb_rq_bend(rqp);
  666         error = smb_rq_simple(rqp);
  667         SMBSDEBUG("%d\n", error);
  668         smb_rq_done(rqp);
  669         return error;
  670 }
  671 
  672 /*
  673  * Set DOS file attributes.
  674  * Looks like this call can be used only if CAP_NT_SMBS bit is on.
  675  */
  676 int
  677 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
  678         struct timespec *atime, struct smb_cred *scred)
  679 {
  680         struct smb_t2rq *t2p;
  681         struct smb_share *ssp = np->n_mount->sm_share;
  682         struct mbchain *mbp;
  683         int64_t tm;
  684         int error, svtz;
  685 
  686         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
  687             scred, &t2p);
  688         if (error)
  689                 return error;
  690         svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
  691         mbp = &t2p->t2_tparam;
  692         mb_init(mbp);
  693         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  694         mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
  695         mb_put_uint32le(mbp, 0);
  696         mbp = &t2p->t2_tdata;
  697         mb_init(mbp);
  698         mb_put_int64le(mbp, 0);         /* creation time */
  699         if (atime) {
  700                 smb_time_local2NT(atime, svtz, &tm);
  701         } else
  702                 tm = 0;
  703         mb_put_int64le(mbp, tm);
  704         if (mtime) {
  705                 smb_time_local2NT(mtime, svtz, &tm);
  706         } else
  707                 tm = 0;
  708         mb_put_int64le(mbp, tm);
  709         mb_put_int64le(mbp, tm);                /* change time */
  710         mb_put_uint16le(mbp, attr);
  711         mb_put_uint32le(mbp, 0);                        /* padding */
  712         mb_put_uint16le(mbp, 0);
  713         t2p->t2_maxpcount = 2;
  714         t2p->t2_maxdcount = 0;
  715         error = smb_t2_request(t2p);
  716         smb_t2_done(t2p);
  717         return error;
  718 }
  719 
  720 
  721 int
  722 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
  723 {
  724         struct smb_rq rq, *rqp = &rq;
  725         struct smb_share *ssp = np->n_mount->sm_share;
  726         struct mbchain *mbp;
  727         struct mdchain *mdp;
  728         u_int8_t wc;
  729         u_int16_t fid, wattr, grantedmode;
  730         int error;
  731 
  732         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
  733         if (error)
  734                 return error;
  735         smb_rq_getrequest(rqp, &mbp);
  736         smb_rq_wstart(rqp);
  737         mb_put_uint16le(mbp, accmode);
  738         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  739         smb_rq_wend(rqp);
  740         smb_rq_bstart(rqp);
  741         mb_put_uint8(mbp, SMB_DT_ASCII);
  742         do {
  743                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  744                 if (error)
  745                         break;
  746                 smb_rq_bend(rqp);
  747                 error = smb_rq_simple(rqp);
  748                 if (error)
  749                         break;
  750                 smb_rq_getreply(rqp, &mdp);
  751                 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
  752                         error = EBADRPC;
  753                         break;
  754                 }
  755                 md_get_uint16(mdp, &fid);
  756                 md_get_uint16le(mdp, &wattr);
  757                 md_get_uint32(mdp, NULL);       /* mtime */
  758                 md_get_uint32(mdp, NULL);       /* fsize */
  759                 md_get_uint16le(mdp, &grantedmode);
  760                 /*
  761                  * TODO: refresh attributes from this reply
  762                  */
  763         } while(0);
  764         smb_rq_done(rqp);
  765         if (error)
  766                 return error;
  767         np->n_fid = fid;
  768         np->n_rwstate = grantedmode;
  769         return 0;
  770 }
  771 
  772 
  773 int
  774 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
  775         struct smb_cred *scred)
  776 {
  777         struct smb_rq rq, *rqp = &rq;
  778         struct mbchain *mbp;
  779         u_long time;
  780         int error;
  781 
  782         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred);
  783         if (error)
  784                 return error;
  785         smb_rq_getrequest(rqp, &mbp);
  786         smb_rq_wstart(rqp);
  787         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  788         if (mtime) {
  789                 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
  790         } else
  791                 time = 0;
  792         mb_put_uint32le(mbp, time);
  793         smb_rq_wend(rqp);
  794         smb_rq_bstart(rqp);
  795         smb_rq_bend(rqp);
  796         error = smb_rq_simple(rqp);
  797         smb_rq_done(rqp);
  798         return error;
  799 }
  800 
  801 int
  802 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
  803         struct smb_cred *scred)
  804 {
  805         struct smb_rq rq, *rqp = &rq;
  806         struct smb_share *ssp = dnp->n_mount->sm_share;
  807         struct mbchain *mbp;
  808         struct mdchain *mdp;
  809         struct timespec ctime;
  810         u_int8_t wc;
  811         u_int16_t fid;
  812         u_long tm;
  813         int error;
  814 
  815         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred);
  816         if (error)
  817                 return error;
  818         smb_rq_getrequest(rqp, &mbp);
  819         smb_rq_wstart(rqp);
  820         mb_put_uint16le(mbp, SMB_FA_ARCHIVE);           /* attributes  */
  821         nanotime(&ctime);
  822         smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
  823         mb_put_uint32le(mbp, tm);
  824         smb_rq_wend(rqp);
  825         smb_rq_bstart(rqp);
  826         mb_put_uint8(mbp, SMB_DT_ASCII);
  827         error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
  828         if (!error) {
  829                 smb_rq_bend(rqp);
  830                 error = smb_rq_simple(rqp);
  831                 if (!error) {
  832                         smb_rq_getreply(rqp, &mdp);
  833                         md_get_uint8(mdp, &wc);
  834                         if (wc == 1)
  835                                 md_get_uint16(mdp, &fid);
  836                         else
  837                                 error = EBADRPC;
  838                 }
  839         }
  840         smb_rq_done(rqp);
  841         if (error)
  842                 return error;
  843         smbfs_smb_close(ssp, fid, &ctime, scred);
  844         return error;
  845 }
  846 
  847 int
  848 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
  849 {
  850         struct smb_rq rq, *rqp = &rq;
  851         struct smb_share *ssp = np->n_mount->sm_share;
  852         struct mbchain *mbp;
  853         int error;
  854 
  855         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred);
  856         if (error)
  857                 return error;
  858         smb_rq_getrequest(rqp, &mbp);
  859         smb_rq_wstart(rqp);
  860         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  861         smb_rq_wend(rqp);
  862         smb_rq_bstart(rqp);
  863         mb_put_uint8(mbp, SMB_DT_ASCII);
  864         error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  865         if (!error) {
  866                 smb_rq_bend(rqp);
  867                 error = smb_rq_simple(rqp);
  868         }
  869         smb_rq_done(rqp);
  870         return error;
  871 }
  872 
  873 int
  874 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
  875         const char *tname, int tnmlen, struct smb_cred *scred)
  876 {
  877         struct smb_rq rq, *rqp = &rq;
  878         struct smb_share *ssp = src->n_mount->sm_share;
  879         struct mbchain *mbp;
  880         int error;
  881 
  882         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred);
  883         if (error)
  884                 return error;
  885         smb_rq_getrequest(rqp, &mbp);
  886         smb_rq_wstart(rqp);
  887         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  888         smb_rq_wend(rqp);
  889         smb_rq_bstart(rqp);
  890         mb_put_uint8(mbp, SMB_DT_ASCII);
  891         do {
  892                 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
  893                 if (error)
  894                         break;
  895                 mb_put_uint8(mbp, SMB_DT_ASCII);
  896                 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
  897                 if (error)
  898                         break;
  899                 smb_rq_bend(rqp);
  900                 error = smb_rq_simple(rqp);
  901         } while(0);
  902         smb_rq_done(rqp);
  903         return error;
  904 }
  905 
  906 int
  907 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
  908         const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
  909 {
  910         struct smb_rq rq, *rqp = &rq;
  911         struct smb_share *ssp = src->n_mount->sm_share;
  912         struct mbchain *mbp;
  913         int error;
  914 
  915         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred);
  916         if (error)
  917                 return error;
  918         smb_rq_getrequest(rqp, &mbp);
  919         smb_rq_wstart(rqp);
  920         mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
  921         mb_put_uint16le(mbp, 0x20);     /* delete target file */
  922         mb_put_uint16le(mbp, flags);
  923         smb_rq_wend(rqp);
  924         smb_rq_bstart(rqp);
  925         mb_put_uint8(mbp, SMB_DT_ASCII);
  926         do {
  927                 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
  928                 if (error)
  929                         break;
  930                 mb_put_uint8(mbp, SMB_DT_ASCII);
  931                 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
  932                 if (error)
  933                         break;
  934                 smb_rq_bend(rqp);
  935                 error = smb_rq_simple(rqp);
  936         } while(0);
  937         smb_rq_done(rqp);
  938         return error;
  939 }
  940 
  941 int
  942 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
  943         struct smb_cred *scred)
  944 {
  945         struct smb_rq rq, *rqp = &rq;
  946         struct smb_share *ssp = dnp->n_mount->sm_share;
  947         struct mbchain *mbp;
  948         int error;
  949 
  950         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred);
  951         if (error)
  952                 return error;
  953         smb_rq_getrequest(rqp, &mbp);
  954         smb_rq_wstart(rqp);
  955         smb_rq_wend(rqp);
  956         smb_rq_bstart(rqp);
  957         mb_put_uint8(mbp, SMB_DT_ASCII);
  958         error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
  959         if (!error) {
  960                 smb_rq_bend(rqp);
  961                 error = smb_rq_simple(rqp);
  962         }
  963         smb_rq_done(rqp);
  964         return error;
  965 }
  966 
  967 int
  968 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
  969 {
  970         struct smb_rq rq, *rqp = &rq;
  971         struct smb_share *ssp = np->n_mount->sm_share;
  972         struct mbchain *mbp;
  973         int error;
  974 
  975         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred);
  976         if (error)
  977                 return error;
  978         smb_rq_getrequest(rqp, &mbp);
  979         smb_rq_wstart(rqp);
  980         smb_rq_wend(rqp);
  981         smb_rq_bstart(rqp);
  982         mb_put_uint8(mbp, SMB_DT_ASCII);
  983         error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  984         if (!error) {
  985                 smb_rq_bend(rqp);
  986                 error = smb_rq_simple(rqp);
  987         }
  988         smb_rq_done(rqp);
  989         return error;
  990 }
  991 
  992 static int
  993 smbfs_smb_search(struct smbfs_fctx *ctx)
  994 {
  995         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
  996         struct smb_rq *rqp;
  997         struct mbchain *mbp;
  998         struct mdchain *mdp;
  999         u_int8_t wc, bt;
 1000         u_int16_t ec, dlen, bc;
 1001         int maxent, error, iseof = 0;
 1002 
 1003         maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
 1004         if (ctx->f_rq) {
 1005                 smb_rq_done(ctx->f_rq);
 1006                 ctx->f_rq = NULL;
 1007         }
 1008         error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
 1009         if (error)
 1010                 return error;
 1011         ctx->f_rq = rqp;
 1012         smb_rq_getrequest(rqp, &mbp);
 1013         smb_rq_wstart(rqp);
 1014         mb_put_uint16le(mbp, maxent);   /* max entries to return */
 1015         mb_put_uint16le(mbp, ctx->f_attrmask);
 1016         smb_rq_wend(rqp);
 1017         smb_rq_bstart(rqp);
 1018         mb_put_uint8(mbp, SMB_DT_ASCII);        /* buffer format */
 1019         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1020                 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
 1021                 if (error)
 1022                         return error;
 1023                 mb_put_uint8(mbp, SMB_DT_VARIABLE);
 1024                 mb_put_uint16le(mbp, 0);        /* context length */
 1025                 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
 1026         } else {
 1027                 mb_put_uint8(mbp, 0);   /* file name length */
 1028                 mb_put_uint8(mbp, SMB_DT_VARIABLE);
 1029                 mb_put_uint16le(mbp, SMB_SKEYLEN);
 1030                 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
 1031         }
 1032         smb_rq_bend(rqp);
 1033         error = smb_rq_simple(rqp);
 1034         if (error) {
 1035                 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
 1036                         error = 0;
 1037                         iseof = 1;
 1038                         ctx->f_flags |= SMBFS_RDD_EOF;
 1039                 } else
 1040                         return error;
 1041         }
 1042         smb_rq_getreply(rqp, &mdp);
 1043         md_get_uint8(mdp, &wc);
 1044         if (wc != 1) 
 1045                 return iseof ? ENOENT : EBADRPC;
 1046         md_get_uint16le(mdp, &ec);
 1047         if (ec == 0)
 1048                 return ENOENT;
 1049         ctx->f_ecnt = ec;
 1050         md_get_uint16le(mdp, &bc);
 1051         if (bc < 3)
 1052                 return EBADRPC;
 1053         bc -= 3;
 1054         md_get_uint8(mdp, &bt);
 1055         if (bt != SMB_DT_VARIABLE)
 1056                 return EBADRPC;
 1057         md_get_uint16le(mdp, &dlen);
 1058         if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
 1059                 return EBADRPC;
 1060         return 0;
 1061 }
 1062 
 1063 static int
 1064 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
 1065         const char *wildcard, int wclen, int attr, struct smb_cred *scred)
 1066 {
 1067         ctx->f_attrmask = attr;
 1068         if (wildcard) {
 1069                 if (wclen == 1 && wildcard[0] == '*') {
 1070                         ctx->f_wildcard = "*.*";
 1071                         ctx->f_wclen = 3;
 1072                 } else {
 1073                         ctx->f_wildcard = wildcard;
 1074                         ctx->f_wclen = wclen;
 1075                 }
 1076         } else {
 1077                 ctx->f_wildcard = NULL;
 1078                 ctx->f_wclen = 0;
 1079         }
 1080         ctx->f_name = ctx->f_fname;
 1081         return 0;
 1082 }
 1083 
 1084 static int
 1085 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
 1086 {
 1087         struct mdchain *mbp;
 1088         struct smb_rq *rqp;
 1089         char *cp;
 1090         u_int8_t battr;
 1091         u_int16_t date, time;
 1092         u_int32_t size;
 1093         int error;
 1094 
 1095         if (ctx->f_ecnt == 0) {
 1096                 if (ctx->f_flags & SMBFS_RDD_EOF)
 1097                         return ENOENT;
 1098                 ctx->f_left = ctx->f_limit = limit;
 1099                 error = smbfs_smb_search(ctx);
 1100                 if (error)
 1101                         return error;
 1102         }
 1103         rqp = ctx->f_rq;
 1104         smb_rq_getreply(rqp, &mbp);
 1105         md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
 1106         md_get_uint8(mbp, &battr);
 1107         md_get_uint16le(mbp, &time);
 1108         md_get_uint16le(mbp, &date);
 1109         md_get_uint32le(mbp, &size);
 1110         cp = ctx->f_name;
 1111         md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
 1112         cp[sizeof(ctx->f_fname) - 1] = 0;
 1113         cp += strlen(cp) - 1;
 1114         while (*cp == ' ' && cp >= ctx->f_name)
 1115                 *cp-- = 0;
 1116         ctx->f_attr.fa_attr = battr;
 1117         smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
 1118             &ctx->f_attr.fa_mtime);
 1119         ctx->f_attr.fa_size = size;
 1120         ctx->f_nmlen = strlen(ctx->f_name);
 1121         ctx->f_ecnt--;
 1122         ctx->f_left--;
 1123         return 0;
 1124 }
 1125 
 1126 static int
 1127 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
 1128 {
 1129         if (ctx->f_rq)
 1130                 smb_rq_done(ctx->f_rq);
 1131         return 0;
 1132 }
 1133 
 1134 /*
 1135  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
 1136  */
 1137 static int
 1138 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
 1139 {
 1140         struct smb_t2rq *t2p;
 1141         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
 1142         struct mbchain *mbp;
 1143         struct mdchain *mdp;
 1144         u_int16_t tw, flags;
 1145         int error;
 1146 
 1147         if (ctx->f_t2) {
 1148                 smb_t2_done(ctx->f_t2);
 1149                 ctx->f_t2 = NULL;
 1150         }
 1151         ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
 1152         flags = 8 | 2;                  /* <resume> | <close if EOS> */
 1153         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
 1154                 flags |= 1;             /* close search after this request */
 1155                 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
 1156         }
 1157         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1158                 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
 1159                     ctx->f_scred, &t2p);
 1160                 if (error)
 1161                         return error;
 1162                 ctx->f_t2 = t2p;
 1163                 mbp = &t2p->t2_tparam;
 1164                 mb_init(mbp);
 1165                 mb_put_uint16le(mbp, ctx->f_attrmask);
 1166                 mb_put_uint16le(mbp, ctx->f_limit);
 1167                 mb_put_uint16le(mbp, flags);
 1168                 mb_put_uint16le(mbp, ctx->f_infolevel);
 1169                 mb_put_uint32le(mbp, 0);
 1170                 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
 1171                 if (error)
 1172                         return error;
 1173         } else  {
 1174                 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
 1175                     ctx->f_scred, &t2p);
 1176                 if (error)
 1177                         return error;
 1178                 ctx->f_t2 = t2p;
 1179                 mbp = &t2p->t2_tparam;
 1180                 mb_init(mbp);
 1181                 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
 1182                 mb_put_uint16le(mbp, ctx->f_limit);
 1183                 mb_put_uint16le(mbp, ctx->f_infolevel);
 1184                 mb_put_uint32le(mbp, 0);                /* resume key */
 1185                 mb_put_uint16le(mbp, flags);
 1186                 if (ctx->f_rname)
 1187                         mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
 1188                 else
 1189                         mb_put_uint8(mbp, 0);   /* resume file name */
 1190 #if 0
 1191         struct timeval tv;
 1192         tv.tv_sec = 0;
 1193         tv.tv_usec = 200 * 1000;        /* 200ms */
 1194                 if (vcp->vc_flags & SMBC_WIN95) {
 1195                         /*
 1196                          * some implementations suggests to sleep here
 1197                          * for 200ms, due to the bug in the Win95.
 1198                          * I've didn't notice any problem, but put code
 1199                          * for it.
 1200                          */
 1201                          tsleep(&flags, PVFS, "fix95", tvtohz(&tv));
 1202                 }
 1203 #endif
 1204         }
 1205         t2p->t2_maxpcount = 5 * 2;
 1206         t2p->t2_maxdcount = vcp->vc_txmax;
 1207         error = smb_t2_request(t2p);
 1208         if (error)
 1209                 return error;
 1210         mdp = &t2p->t2_rparam;
 1211         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1212                 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
 1213                         return error;
 1214                 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
 1215         }
 1216         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1217                 return error;
 1218         ctx->f_ecnt = tw;
 1219         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1220                 return error;
 1221         if (tw)
 1222                 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
 1223         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1224                 return error;
 1225         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1226                 return error;
 1227         if (ctx->f_ecnt == 0)
 1228                 return ENOENT;
 1229         ctx->f_rnameofs = tw;
 1230         mdp = &t2p->t2_rdata;
 1231         if (mdp->md_top == NULL) {
 1232                 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
 1233                 return ENOENT;
 1234         }
 1235         if (mdp->md_top->m_len == 0) {
 1236                 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
 1237                 return ENOENT;
 1238         }
 1239         ctx->f_eofs = 0;
 1240         return 0;
 1241 }
 1242 
 1243 static int
 1244 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
 1245 {
 1246         struct smb_rq rq, *rqp = &rq;
 1247         struct mbchain *mbp;
 1248         int error;
 1249 
 1250         error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred);
 1251         if (error)
 1252                 return error;
 1253         smb_rq_getrequest(rqp, &mbp);
 1254         smb_rq_wstart(rqp);
 1255         mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
 1256         smb_rq_wend(rqp);
 1257         smb_rq_bstart(rqp);
 1258         smb_rq_bend(rqp);
 1259         error = smb_rq_simple(rqp);
 1260         smb_rq_done(rqp);
 1261         return error;
 1262 }
 1263 
 1264 static int
 1265 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
 1266         const char *wildcard, int wclen, int attr, struct smb_cred *scred)
 1267 {
 1268         ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
 1269         if (ctx->f_name == NULL)
 1270                 return ENOMEM;
 1271         ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
 1272             SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
 1273         ctx->f_attrmask = attr;
 1274         ctx->f_wildcard = wildcard;
 1275         ctx->f_wclen = wclen;
 1276         return 0;
 1277 }
 1278 
 1279 static int
 1280 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
 1281 {
 1282         struct mdchain *mbp;
 1283         struct smb_t2rq *t2p;
 1284         char *cp;
 1285         u_int8_t tb;
 1286         u_int16_t date, time, wattr;
 1287         u_int32_t size, next, dattr;
 1288         int64_t lint;
 1289         int error, svtz, cnt, fxsz, nmlen, recsz;
 1290 
 1291         if (ctx->f_ecnt == 0) {
 1292                 if (ctx->f_flags & SMBFS_RDD_EOF)
 1293                         return ENOENT;
 1294                 ctx->f_left = ctx->f_limit = limit;
 1295                 error = smbfs_smb_trans2find2(ctx);
 1296                 if (error)
 1297                         return error;
 1298         }
 1299         t2p = ctx->f_t2;
 1300         mbp = &t2p->t2_rdata;
 1301         svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
 1302         switch (ctx->f_infolevel) {
 1303             case SMB_INFO_STANDARD:
 1304                 next = 0;
 1305                 fxsz = 0;
 1306                 md_get_uint16le(mbp, &date);
 1307                 md_get_uint16le(mbp, &time);    /* creation time */
 1308                 md_get_uint16le(mbp, &date);
 1309                 md_get_uint16le(mbp, &time);    /* access time */
 1310                 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
 1311                 md_get_uint16le(mbp, &date);
 1312                 md_get_uint16le(mbp, &time);    /* access time */
 1313                 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
 1314                 md_get_uint32le(mbp, &size);
 1315                 ctx->f_attr.fa_size = size;
 1316                 md_get_uint32(mbp, NULL);       /* allocation size */
 1317                 md_get_uint16le(mbp, &wattr);
 1318                 ctx->f_attr.fa_attr = wattr;
 1319                 md_get_uint8(mbp, &tb);
 1320                 size = nmlen = tb;
 1321                 fxsz = 23;
 1322                 recsz = next = 24 + nmlen;      /* docs misses zero byte at end */
 1323                 break;
 1324             case SMB_FIND_FILE_DIRECTORY_INFO:
 1325                 md_get_uint32le(mbp, &next);
 1326                 md_get_uint32(mbp, NULL);       /* file index */
 1327                 md_get_int64(mbp, NULL);        /* creation time */
 1328                 md_get_int64le(mbp, &lint);
 1329                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
 1330                 md_get_int64le(mbp, &lint);
 1331                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
 1332                 md_get_int64le(mbp, &lint);
 1333                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
 1334                 md_get_int64le(mbp, &lint);     /* file size */
 1335                 ctx->f_attr.fa_size = lint;
 1336                 md_get_int64(mbp, NULL);        /* real size (should use) */
 1337                 md_get_uint32le(mbp, &dattr);   /* EA */
 1338                 ctx->f_attr.fa_attr = dattr;
 1339                 md_get_uint32le(mbp, &size);    /* name len */
 1340                 fxsz = 64;
 1341                 recsz = next ? next : fxsz + size;
 1342                 break;
 1343             default:
 1344                 SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
 1345                 return EINVAL;
 1346         }
 1347         nmlen = min(size, SMB_MAXFNAMELEN);
 1348         cp = ctx->f_name;
 1349         error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
 1350         if (error)
 1351                 return error;
 1352         if (next) {
 1353                 cnt = next - nmlen - fxsz;
 1354                 if (cnt > 0)
 1355                         md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
 1356                 else if (cnt < 0) {
 1357                         SMBERROR("out of sync\n");
 1358                         return EBADRPC;
 1359                 }
 1360         }
 1361         if (nmlen && cp[nmlen - 1] == 0)
 1362                 nmlen--;
 1363         if (nmlen == 0)
 1364                 return EBADRPC;
 1365 
 1366         next = ctx->f_eofs + recsz;
 1367         if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
 1368             (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
 1369                 /*
 1370                  * Server needs a resume filename.
 1371                  */
 1372                 if (ctx->f_rnamelen <= nmlen) {
 1373                         if (ctx->f_rname)
 1374                                 free(ctx->f_rname, M_SMBFSDATA);
 1375                         ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
 1376                         ctx->f_rnamelen = nmlen;
 1377                 }
 1378                 bcopy(ctx->f_name, ctx->f_rname, nmlen);
 1379                 ctx->f_rname[nmlen] = 0;
 1380                 ctx->f_flags |= SMBFS_RDD_GOTRNAME;
 1381         }
 1382         ctx->f_nmlen = nmlen;
 1383         ctx->f_eofs = next;
 1384         ctx->f_ecnt--;
 1385         ctx->f_left--;
 1386         return 0;
 1387 }
 1388 
 1389 static int
 1390 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
 1391 {
 1392         if (ctx->f_name)
 1393                 free(ctx->f_name, M_SMBFSDATA);
 1394         if (ctx->f_t2)
 1395                 smb_t2_done(ctx->f_t2);
 1396         if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
 1397                 smbfs_smb_findclose2(ctx);
 1398         return 0;
 1399 }
 1400 
 1401 int
 1402 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
 1403         struct smb_cred *scred, struct smbfs_fctx **ctxpp)
 1404 {
 1405         struct smbfs_fctx *ctx;
 1406         int error;
 1407 
 1408         ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK);
 1409         if (ctx == NULL)
 1410                 return ENOMEM;
 1411         bzero(ctx, sizeof(*ctx));
 1412         ctx->f_ssp = dnp->n_mount->sm_share;
 1413         ctx->f_dnp = dnp;
 1414         ctx->f_flags = SMBFS_RDD_FINDFIRST;
 1415         ctx->f_scred = scred;
 1416         if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
 1417             (dnp->n_mount->sm_args.flags & SMBFS_MOUNT_NO_LONG)) {
 1418                 ctx->f_flags |= SMBFS_RDD_USESEARCH;
 1419                 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
 1420         } else
 1421                 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
 1422         if (error)
 1423                 smbfs_findclose(ctx, scred);
 1424         else
 1425                 *ctxpp = ctx;
 1426         return error;
 1427 }
 1428 
 1429 int
 1430 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
 1431 {
 1432         int error;
 1433 
 1434         if (limit == 0)
 1435                 limit = 1000000;
 1436         else if (limit > 1)
 1437                 limit *= 4;     /* imperical */
 1438         ctx->f_scred = scred;
 1439         for (;;) {
 1440                 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
 1441                         error = smbfs_findnextLM1(ctx, limit);
 1442                 } else
 1443                         error = smbfs_findnextLM2(ctx, limit);
 1444                 if (error)
 1445                         return error;
 1446                 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
 1447                     (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
 1448                      ctx->f_name[1] == '.'))
 1449                         continue;
 1450                 break;
 1451         }
 1452         smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen,
 1453             ctx->f_dnp->n_mount->sm_caseopt);
 1454         ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
 1455         return 0;
 1456 }
 1457 
 1458 int
 1459 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
 1460 {
 1461         ctx->f_scred = scred;
 1462         if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
 1463                 smbfs_findcloseLM1(ctx);
 1464         } else
 1465                 smbfs_findcloseLM2(ctx);
 1466         if (ctx->f_rname)
 1467                 free(ctx->f_rname, M_SMBFSDATA);
 1468         free(ctx, M_SMBFSDATA);
 1469         return 0;
 1470 }
 1471 
 1472 int
 1473 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
 1474         struct smbfattr *fap, struct smb_cred *scred)
 1475 {
 1476         struct smbfs_fctx *ctx;
 1477         int error;
 1478 
 1479         if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
 1480                 bzero(fap, sizeof(*fap));
 1481                 fap->fa_attr = SMB_FA_DIR;
 1482                 fap->fa_ino = 2;
 1483                 return 0;
 1484         }
 1485         if (nmlen == 1 && name[0] == '.') {
 1486                 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
 1487                 return error;
 1488         } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
 1489                 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap,
 1490                     scred);
 1491                 printf("%s: knows NOTHING about '..'\n", __func__);
 1492                 return error;
 1493         }
 1494         error = smbfs_findopen(dnp, name, nmlen,
 1495             SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
 1496         if (error)
 1497                 return error;
 1498         ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
 1499         error = smbfs_findnext(ctx, 1, scred);
 1500         if (error == 0) {
 1501                 *fap = ctx->f_attr;
 1502                 if (name == NULL)
 1503                         fap->fa_ino = dnp->n_ino;
 1504         }
 1505         smbfs_findclose(ctx, scred);
 1506         return error;
 1507 }

Cache object: aa8c3d33f63a6b78b9edcad21bf56b95


[ 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.