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

Cache object: f7444f4b7fec52f50e438a73d5e297bb


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