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

Cache object: 039ed94912258b8e21724aa1cfeeb0fb


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