| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
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: src/sys/fs/smbfs/smbfs_smb.c,v 1.1.2.2 2003/01/17 08:20:26 tjr Exp $ | |
| 978400d3 | 33 | * $DragonFly: src/sys/vfs/smbfs/smbfs_smb.c,v 1.11 2008/01/06 16:55:53 swildner Exp $ |
| 984263bc MD |
34 | */ |
| 35 | #include <sys/param.h> | |
| 36 | #include <sys/systm.h> | |
| 37 | #include <sys/kernel.h> | |
| 38 | #include <sys/malloc.h> | |
| 39 | #include <sys/proc.h> | |
| 40 | #include <sys/lock.h> | |
| 41 | #include <sys/vnode.h> | |
| 42 | #include <sys/mbuf.h> | |
| 43 | #include <sys/mount.h> | |
| 44 | ||
| 45 | #ifdef USE_MD5_HASH | |
| 46 | #include <sys/md5.h> | |
| 47 | #endif | |
| 48 | ||
| d2438d69 MD |
49 | #include <netproto/smb/smb.h> |
| 50 | #include <netproto/smb/smb_subr.h> | |
| 51 | #include <netproto/smb/smb_rq.h> | |
| 52 | #include <netproto/smb/smb_conn.h> | |
| 984263bc | 53 | |
| 1f2de5d4 MD |
54 | #include "smbfs.h" |
| 55 | #include "smbfs_node.h" | |
| 56 | #include "smbfs_subr.h" | |
| 984263bc MD |
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 | |
| 973c11b9 MD |
140 | return smbfs_smb_lockandx(np, op, (u_int32_t)(uintptr_t)id, |
| 141 | start, end, scred); | |
| 984263bc MD |
142 | } |
| 143 | ||
| 144 | int | |
| 145 | smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp, | |
| 146 | struct smb_cred *scred) | |
| 147 | { | |
| 148 | struct smb_t2rq *t2p; | |
| 149 | struct mbchain *mbp; | |
| 150 | struct mdchain *mdp; | |
| 151 | u_int16_t bsize; | |
| 152 | u_int32_t units, bpu, funits; | |
| 153 | int error; | |
| 154 | ||
| 155 | error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, | |
| 156 | scred, &t2p); | |
| 157 | if (error) | |
| 158 | return error; | |
| 159 | mbp = &t2p->t2_tparam; | |
| 160 | mb_init(mbp); | |
| 161 | mb_put_uint16le(mbp, SMB_INFO_ALLOCATION); | |
| 162 | t2p->t2_maxpcount = 4; | |
| 163 | t2p->t2_maxdcount = 4 * 4 + 2; | |
| 164 | error = smb_t2_request(t2p); | |
| 165 | if (error) { | |
| 166 | smb_t2_done(t2p); | |
| 167 | return error; | |
| 168 | } | |
| 169 | mdp = &t2p->t2_rdata; | |
| 170 | md_get_uint32(mdp, NULL); /* fs id */ | |
| 171 | md_get_uint32le(mdp, &bpu); | |
| 172 | md_get_uint32le(mdp, &units); | |
| 173 | md_get_uint32le(mdp, &funits); | |
| 174 | md_get_uint16le(mdp, &bsize); | |
| 175 | sbp->f_bsize = bpu * bsize; /* fundamental file system block size */ | |
| 176 | sbp->f_blocks= units; /* total data blocks in file system */ | |
| 177 | sbp->f_bfree = funits; /* free blocks in fs */ | |
| 178 | sbp->f_bavail= funits; /* free blocks avail to non-superuser */ | |
| 179 | sbp->f_files = 0xffff; /* total file nodes in file system */ | |
| 180 | sbp->f_ffree = 0xffff; /* free file nodes in fs */ | |
| 181 | smb_t2_done(t2p); | |
| 182 | return 0; | |
| 183 | } | |
| 184 | ||
| 185 | int | |
| 186 | smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, | |
| 187 | struct smb_cred *scred) | |
| 188 | { | |
| 189 | struct smb_rq rq, *rqp = &rq; | |
| 190 | struct mdchain *mdp; | |
| 191 | u_int16_t units, bpu, bsize, funits; | |
| 192 | int error; | |
| 193 | ||
| 194 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred); | |
| 195 | if (error) | |
| 196 | return error; | |
| 197 | smb_rq_wstart(rqp); | |
| 198 | smb_rq_wend(rqp); | |
| 199 | smb_rq_bstart(rqp); | |
| 200 | smb_rq_bend(rqp); | |
| 201 | error = smb_rq_simple(rqp); | |
| 202 | if (error) { | |
| 203 | smb_rq_done(rqp); | |
| 204 | return error; | |
| 205 | } | |
| 206 | smb_rq_getreply(rqp, &mdp); | |
| 207 | md_get_uint16le(mdp, &units); | |
| 208 | md_get_uint16le(mdp, &bpu); | |
| 209 | md_get_uint16le(mdp, &bsize); | |
| 210 | md_get_uint16le(mdp, &funits); | |
| 211 | sbp->f_bsize = bpu * bsize; /* fundamental file system block size */ | |
| 212 | sbp->f_blocks= units; /* total data blocks in file system */ | |
| 213 | sbp->f_bfree = funits; /* free blocks in fs */ | |
| 214 | sbp->f_bavail= funits; /* free blocks avail to non-superuser */ | |
| 215 | sbp->f_files = 0xffff; /* total file nodes in file system */ | |
| 216 | sbp->f_ffree = 0xffff; /* free file nodes in fs */ | |
| 217 | smb_rq_done(rqp); | |
| 218 | return 0; | |
| 219 | } | |
| 220 | ||
| 221 | int | |
| 222 | smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) | |
| 223 | { | |
| 224 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 225 | struct smb_rq rq, *rqp = &rq; | |
| 226 | struct mbchain *mbp; | |
| 227 | int error; | |
| 228 | ||
| 229 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); | |
| 230 | if (error) | |
| 231 | return error; | |
| 232 | smb_rq_getrequest(rqp, &mbp); | |
| 233 | smb_rq_wstart(rqp); | |
| 234 | mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); | |
| 235 | mb_put_uint16le(mbp, 0); | |
| 236 | mb_put_uint32le(mbp, newsize); | |
| 237 | mb_put_uint16le(mbp, 0); | |
| 238 | smb_rq_wend(rqp); | |
| 239 | smb_rq_bstart(rqp); | |
| 240 | mb_put_uint8(mbp, SMB_DT_DATA); | |
| 241 | mb_put_uint16le(mbp, 0); | |
| 242 | smb_rq_bend(rqp); | |
| 243 | error = smb_rq_simple(rqp); | |
| 244 | smb_rq_done(rqp); | |
| 245 | return error; | |
| 246 | } | |
| 247 | ||
| 248 | ||
| 249 | /* | |
| 250 | * Set DOS file attributes. mtime should be NULL for dialects above lm10 | |
| 251 | */ | |
| 252 | int | |
| 253 | smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, | |
| 254 | struct smb_cred *scred) | |
| 255 | { | |
| 256 | struct smb_rq rq, *rqp = &rq; | |
| 257 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 258 | struct mbchain *mbp; | |
| 259 | u_long time; | |
| 260 | int error, svtz; | |
| 261 | ||
| 262 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred); | |
| 263 | if (error) | |
| 264 | return error; | |
| 265 | svtz = SSTOVC(ssp)->vc_sopt.sv_tz; | |
| 266 | smb_rq_getrequest(rqp, &mbp); | |
| 267 | smb_rq_wstart(rqp); | |
| 268 | mb_put_uint16le(mbp, attr); | |
| 269 | if (mtime) { | |
| 270 | smb_time_local2server(mtime, svtz, &time); | |
| 271 | } else | |
| 272 | time = 0; | |
| 273 | mb_put_uint32le(mbp, time); /* mtime */ | |
| 274 | mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); | |
| 275 | smb_rq_wend(rqp); | |
| 276 | smb_rq_bstart(rqp); | |
| 277 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 278 | do { | |
| 279 | error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); | |
| 280 | if (error) | |
| 281 | break; | |
| 282 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 283 | mb_put_uint8(mbp, 0); | |
| 284 | smb_rq_bend(rqp); | |
| 285 | error = smb_rq_simple(rqp); | |
| 286 | SMBERROR("%d\n", error); | |
| 287 | if (error) | |
| 288 | break; | |
| 289 | } while(0); | |
| 290 | smb_rq_done(rqp); | |
| 291 | return error; | |
| 292 | } | |
| 293 | ||
| 294 | /* | |
| 295 | * Note, win95 doesn't support this call. | |
| 296 | */ | |
| 297 | int | |
| 298 | smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, | |
| 299 | struct timespec *atime, int attr, struct smb_cred *scred) | |
| 300 | { | |
| 301 | struct smb_t2rq *t2p; | |
| 302 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 303 | struct smb_vc *vcp = SSTOVC(ssp); | |
| 304 | struct mbchain *mbp; | |
| 305 | u_int16_t date, time; | |
| 306 | int error, tzoff; | |
| 307 | ||
| 308 | error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, | |
| 309 | scred, &t2p); | |
| 310 | if (error) | |
| 311 | return error; | |
| 312 | mbp = &t2p->t2_tparam; | |
| 313 | mb_init(mbp); | |
| 314 | mb_put_uint16le(mbp, SMB_INFO_STANDARD); | |
| 315 | mb_put_uint32le(mbp, 0); /* MBZ */ | |
| 316 | error = smbfs_fullpath(mbp, vcp, np, NULL, 0); | |
| 317 | if (error) { | |
| 318 | smb_t2_done(t2p); | |
| 319 | return error; | |
| 320 | } | |
| 321 | tzoff = vcp->vc_sopt.sv_tz; | |
| 322 | mbp = &t2p->t2_tdata; | |
| 323 | mb_init(mbp); | |
| 324 | mb_put_uint32le(mbp, 0); /* creation time */ | |
| 325 | if (atime) | |
| 326 | smb_time_unix2dos(atime, tzoff, &date, &time, NULL); | |
| 327 | else | |
| 328 | time = date = 0; | |
| 329 | mb_put_uint16le(mbp, date); | |
| 330 | mb_put_uint16le(mbp, time); | |
| 331 | if (mtime) | |
| 332 | smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); | |
| 333 | else | |
| 334 | time = date = 0; | |
| 335 | mb_put_uint16le(mbp, date); | |
| 336 | mb_put_uint16le(mbp, time); | |
| 337 | mb_put_uint32le(mbp, 0); /* file size */ | |
| 338 | mb_put_uint32le(mbp, 0); /* allocation unit size */ | |
| 339 | mb_put_uint16le(mbp, attr); /* DOS attr */ | |
| 340 | mb_put_uint32le(mbp, 0); /* EA size */ | |
| 341 | t2p->t2_maxpcount = 5 * 2; | |
| 342 | t2p->t2_maxdcount = vcp->vc_txmax; | |
| 343 | error = smb_t2_request(t2p); | |
| 344 | smb_t2_done(t2p); | |
| 345 | return error; | |
| 346 | } | |
| 347 | ||
| 348 | /* | |
| 349 | * NT level. Specially for win9x | |
| 350 | */ | |
| 351 | int | |
| 352 | smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, | |
| 353 | struct timespec *atime, struct smb_cred *scred) | |
| 354 | { | |
| 355 | struct smb_t2rq *t2p; | |
| 356 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 357 | struct smb_vc *vcp = SSTOVC(ssp); | |
| 358 | struct mbchain *mbp; | |
| 359 | int64_t tm; | |
| 360 | int error, tzoff; | |
| 361 | ||
| 362 | error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, | |
| 363 | scred, &t2p); | |
| 364 | if (error) | |
| 365 | return error; | |
| 366 | mbp = &t2p->t2_tparam; | |
| 367 | mb_init(mbp); | |
| 368 | mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); | |
| 369 | mb_put_uint32le(mbp, 0); /* MBZ */ | |
| 370 | error = smbfs_fullpath(mbp, vcp, np, NULL, 0); | |
| 371 | if (error) { | |
| 372 | smb_t2_done(t2p); | |
| 373 | return error; | |
| 374 | } | |
| 375 | tzoff = vcp->vc_sopt.sv_tz; | |
| 376 | mbp = &t2p->t2_tdata; | |
| 377 | mb_init(mbp); | |
| 378 | mb_put_int64le(mbp, 0); /* creation time */ | |
| 379 | if (atime) { | |
| 380 | smb_time_local2NT(atime, tzoff, &tm); | |
| 381 | } else | |
| 382 | tm = 0; | |
| 383 | mb_put_int64le(mbp, tm); | |
| 384 | if (mtime) { | |
| 385 | smb_time_local2NT(mtime, tzoff, &tm); | |
| 386 | } else | |
| 387 | tm = 0; | |
| 388 | mb_put_int64le(mbp, tm); | |
| 389 | mb_put_int64le(mbp, tm); /* change time */ | |
| 390 | mb_put_uint32le(mbp, attr); /* attr */ | |
| 391 | t2p->t2_maxpcount = 24; | |
| 392 | t2p->t2_maxdcount = 56; | |
| 393 | error = smb_t2_request(t2p); | |
| 394 | smb_t2_done(t2p); | |
| 395 | return error; | |
| 396 | } | |
| 397 | ||
| 398 | /* | |
| 399 | * Set file atime and mtime. Doesn't supported by core dialect. | |
| 400 | */ | |
| 401 | int | |
| 402 | smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, | |
| 403 | struct timespec *atime, struct smb_cred *scred) | |
| 404 | { | |
| 405 | struct smb_rq rq, *rqp = &rq; | |
| 406 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 407 | struct mbchain *mbp; | |
| 408 | u_int16_t date, time; | |
| 409 | int error, tzoff; | |
| 410 | ||
| 411 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred); | |
| 412 | if (error) | |
| 413 | return error; | |
| 414 | tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; | |
| 415 | smb_rq_getrequest(rqp, &mbp); | |
| 416 | smb_rq_wstart(rqp); | |
| 417 | mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); | |
| 418 | mb_put_uint32le(mbp, 0); /* creation time */ | |
| 419 | ||
| 420 | if (atime) | |
| 421 | smb_time_unix2dos(atime, tzoff, &date, &time, NULL); | |
| 422 | else | |
| 423 | time = date = 0; | |
| 424 | mb_put_uint16le(mbp, date); | |
| 425 | mb_put_uint16le(mbp, time); | |
| 426 | if (mtime) | |
| 427 | smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); | |
| 428 | else | |
| 429 | time = date = 0; | |
| 430 | mb_put_uint16le(mbp, date); | |
| 431 | mb_put_uint16le(mbp, time); | |
| 432 | smb_rq_wend(rqp); | |
| 433 | smb_rq_bstart(rqp); | |
| 434 | smb_rq_bend(rqp); | |
| 435 | error = smb_rq_simple(rqp); | |
| 436 | SMBSDEBUG("%d\n", error); | |
| 437 | smb_rq_done(rqp); | |
| 438 | return error; | |
| 439 | } | |
| 440 | ||
| 441 | /* | |
| 442 | * Set DOS file attributes. | |
| 443 | * Looks like this call can be used only if CAP_NT_SMBS bit is on. | |
| 444 | */ | |
| 445 | int | |
| 446 | smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, | |
| 447 | struct timespec *atime, struct smb_cred *scred) | |
| 448 | { | |
| 449 | struct smb_t2rq *t2p; | |
| 450 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 451 | struct mbchain *mbp; | |
| 452 | int64_t tm; | |
| 453 | int error, svtz; | |
| 454 | ||
| 455 | error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, | |
| 456 | scred, &t2p); | |
| 457 | if (error) | |
| 458 | return error; | |
| 459 | svtz = SSTOVC(ssp)->vc_sopt.sv_tz; | |
| 460 | mbp = &t2p->t2_tparam; | |
| 461 | mb_init(mbp); | |
| 462 | mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); | |
| 463 | mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); | |
| 464 | mb_put_uint32le(mbp, 0); | |
| 465 | mbp = &t2p->t2_tdata; | |
| 466 | mb_init(mbp); | |
| 467 | mb_put_int64le(mbp, 0); /* creation time */ | |
| 468 | if (atime) { | |
| 469 | smb_time_local2NT(atime, svtz, &tm); | |
| 470 | } else | |
| 471 | tm = 0; | |
| 472 | mb_put_int64le(mbp, tm); | |
| 473 | if (mtime) { | |
| 474 | smb_time_local2NT(mtime, svtz, &tm); | |
| 475 | } else | |
| 476 | tm = 0; | |
| 477 | mb_put_int64le(mbp, tm); | |
| 478 | mb_put_int64le(mbp, tm); /* change time */ | |
| 479 | mb_put_uint16le(mbp, attr); | |
| 480 | mb_put_uint32le(mbp, 0); /* padding */ | |
| 481 | mb_put_uint16le(mbp, 0); | |
| 482 | t2p->t2_maxpcount = 2; | |
| 483 | t2p->t2_maxdcount = 0; | |
| 484 | error = smb_t2_request(t2p); | |
| 485 | smb_t2_done(t2p); | |
| 486 | return error; | |
| 487 | } | |
| 488 | ||
| 489 | ||
| 490 | int | |
| 491 | smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) | |
| 492 | { | |
| 493 | struct smb_rq rq, *rqp = &rq; | |
| 494 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 495 | struct mbchain *mbp; | |
| 496 | struct mdchain *mdp; | |
| 497 | u_int8_t wc; | |
| 498 | u_int16_t fid, wattr, grantedmode; | |
| 499 | int error; | |
| 500 | ||
| 501 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred); | |
| 502 | if (error) | |
| 503 | return error; | |
| 504 | smb_rq_getrequest(rqp, &mbp); | |
| 505 | smb_rq_wstart(rqp); | |
| 506 | mb_put_uint16le(mbp, accmode); | |
| 507 | mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); | |
| 508 | smb_rq_wend(rqp); | |
| 509 | smb_rq_bstart(rqp); | |
| 510 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 511 | do { | |
| 512 | error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); | |
| 513 | if (error) | |
| 514 | break; | |
| 515 | smb_rq_bend(rqp); | |
| 516 | error = smb_rq_simple(rqp); | |
| 517 | if (error) | |
| 518 | break; | |
| 519 | smb_rq_getreply(rqp, &mdp); | |
| 520 | if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { | |
| 521 | error = EBADRPC; | |
| 522 | break; | |
| 523 | } | |
| 524 | md_get_uint16(mdp, &fid); | |
| 525 | md_get_uint16le(mdp, &wattr); | |
| 526 | md_get_uint32(mdp, NULL); /* mtime */ | |
| 527 | md_get_uint32(mdp, NULL); /* fsize */ | |
| 528 | md_get_uint16le(mdp, &grantedmode); | |
| 529 | /* | |
| 530 | * TODO: refresh attributes from this reply | |
| 531 | */ | |
| 532 | } while(0); | |
| 533 | smb_rq_done(rqp); | |
| 534 | if (error) | |
| 535 | return error; | |
| 536 | np->n_fid = fid; | |
| 537 | np->n_rwstate = grantedmode; | |
| 538 | return 0; | |
| 539 | } | |
| 540 | ||
| 541 | ||
| 542 | int | |
| 543 | smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, | |
| 544 | struct smb_cred *scred) | |
| 545 | { | |
| 546 | struct smb_rq rq, *rqp = &rq; | |
| 547 | struct mbchain *mbp; | |
| 548 | u_long time; | |
| 549 | int error; | |
| 550 | ||
| 551 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred); | |
| 552 | if (error) | |
| 553 | return error; | |
| 554 | smb_rq_getrequest(rqp, &mbp); | |
| 555 | smb_rq_wstart(rqp); | |
| 556 | mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); | |
| 557 | if (mtime) { | |
| 558 | smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); | |
| 559 | } else | |
| 560 | time = 0; | |
| 561 | mb_put_uint32le(mbp, time); | |
| 562 | smb_rq_wend(rqp); | |
| 563 | smb_rq_bstart(rqp); | |
| 564 | smb_rq_bend(rqp); | |
| 565 | error = smb_rq_simple(rqp); | |
| 566 | smb_rq_done(rqp); | |
| 567 | return error; | |
| 568 | } | |
| 569 | ||
| 570 | int | |
| 571 | smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, | |
| 572 | struct smb_cred *scred) | |
| 573 | { | |
| 574 | struct smb_rq rq, *rqp = &rq; | |
| 575 | struct smb_share *ssp = dnp->n_mount->sm_share; | |
| 576 | struct mbchain *mbp; | |
| 577 | struct mdchain *mdp; | |
| 578 | struct timespec ctime; | |
| 579 | u_int8_t wc; | |
| 580 | u_int16_t fid; | |
| 581 | u_long tm; | |
| 582 | int error; | |
| 583 | ||
| 584 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred); | |
| 585 | if (error) | |
| 586 | return error; | |
| 587 | smb_rq_getrequest(rqp, &mbp); | |
| 588 | smb_rq_wstart(rqp); | |
| 589 | mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ | |
| 590 | nanotime(&ctime); | |
| 591 | smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); | |
| 592 | mb_put_uint32le(mbp, tm); | |
| 593 | smb_rq_wend(rqp); | |
| 594 | smb_rq_bstart(rqp); | |
| 595 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 596 | error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); | |
| 597 | if (!error) { | |
| 598 | smb_rq_bend(rqp); | |
| 599 | error = smb_rq_simple(rqp); | |
| 600 | if (!error) { | |
| 601 | smb_rq_getreply(rqp, &mdp); | |
| 602 | md_get_uint8(mdp, &wc); | |
| 603 | if (wc == 1) | |
| 604 | md_get_uint16(mdp, &fid); | |
| 605 | else | |
| 606 | error = EBADRPC; | |
| 607 | } | |
| 608 | } | |
| 609 | smb_rq_done(rqp); | |
| 610 | if (error) | |
| 611 | return error; | |
| 612 | smbfs_smb_close(ssp, fid, &ctime, scred); | |
| 613 | return error; | |
| 614 | } | |
| 615 | ||
| 616 | int | |
| 617 | smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) | |
| 618 | { | |
| 619 | struct smb_rq rq, *rqp = &rq; | |
| 620 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 621 | struct mbchain *mbp; | |
| 622 | int error; | |
| 623 | ||
| 624 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred); | |
| 625 | if (error) | |
| 626 | return error; | |
| 627 | smb_rq_getrequest(rqp, &mbp); | |
| 628 | smb_rq_wstart(rqp); | |
| 629 | mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); | |
| 630 | smb_rq_wend(rqp); | |
| 631 | smb_rq_bstart(rqp); | |
| 632 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 633 | error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); | |
| 634 | if (!error) { | |
| 635 | smb_rq_bend(rqp); | |
| 636 | error = smb_rq_simple(rqp); | |
| 637 | } | |
| 638 | smb_rq_done(rqp); | |
| 639 | return error; | |
| 640 | } | |
| 641 | ||
| 642 | int | |
| 643 | smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, | |
| 644 | const char *tname, int tnmlen, struct smb_cred *scred) | |
| 645 | { | |
| 646 | struct smb_rq rq, *rqp = &rq; | |
| 647 | struct smb_share *ssp = src->n_mount->sm_share; | |
| 648 | struct mbchain *mbp; | |
| 649 | int error; | |
| 650 | ||
| 651 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred); | |
| 652 | if (error) | |
| 653 | return error; | |
| 654 | smb_rq_getrequest(rqp, &mbp); | |
| 655 | smb_rq_wstart(rqp); | |
| 656 | mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); | |
| 657 | smb_rq_wend(rqp); | |
| 658 | smb_rq_bstart(rqp); | |
| 659 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 660 | do { | |
| 661 | error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); | |
| 662 | if (error) | |
| 663 | break; | |
| 664 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 665 | error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); | |
| 666 | if (error) | |
| 667 | break; | |
| 668 | smb_rq_bend(rqp); | |
| 669 | error = smb_rq_simple(rqp); | |
| 670 | } while(0); | |
| 671 | smb_rq_done(rqp); | |
| 672 | return error; | |
| 673 | } | |
| 674 | ||
| 675 | int | |
| 676 | smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, | |
| 677 | const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) | |
| 678 | { | |
| 679 | struct smb_rq rq, *rqp = &rq; | |
| 680 | struct smb_share *ssp = src->n_mount->sm_share; | |
| 681 | struct mbchain *mbp; | |
| 682 | int error; | |
| 683 | ||
| 684 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred); | |
| 685 | if (error) | |
| 686 | return error; | |
| 687 | smb_rq_getrequest(rqp, &mbp); | |
| 688 | smb_rq_wstart(rqp); | |
| 689 | mb_put_uint16le(mbp, SMB_TID_UNKNOWN); | |
| 690 | mb_put_uint16le(mbp, 0x20); /* delete target file */ | |
| 691 | mb_put_uint16le(mbp, flags); | |
| 692 | smb_rq_wend(rqp); | |
| 693 | smb_rq_bstart(rqp); | |
| 694 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 695 | do { | |
| 696 | error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); | |
| 697 | if (error) | |
| 698 | break; | |
| 699 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 700 | error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); | |
| 701 | if (error) | |
| 702 | break; | |
| 703 | smb_rq_bend(rqp); | |
| 704 | error = smb_rq_simple(rqp); | |
| 705 | } while(0); | |
| 706 | smb_rq_done(rqp); | |
| 707 | return error; | |
| 708 | } | |
| 709 | ||
| 710 | int | |
| 711 | smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, | |
| 712 | struct smb_cred *scred) | |
| 713 | { | |
| 714 | struct smb_rq rq, *rqp = &rq; | |
| 715 | struct smb_share *ssp = dnp->n_mount->sm_share; | |
| 716 | struct mbchain *mbp; | |
| 717 | int error; | |
| 718 | ||
| 719 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred); | |
| 720 | if (error) | |
| 721 | return error; | |
| 722 | smb_rq_getrequest(rqp, &mbp); | |
| 723 | smb_rq_wstart(rqp); | |
| 724 | smb_rq_wend(rqp); | |
| 725 | smb_rq_bstart(rqp); | |
| 726 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 727 | error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); | |
| 728 | if (!error) { | |
| 729 | smb_rq_bend(rqp); | |
| 730 | error = smb_rq_simple(rqp); | |
| 731 | } | |
| 732 | smb_rq_done(rqp); | |
| 733 | return error; | |
| 734 | } | |
| 735 | ||
| 736 | int | |
| 737 | smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) | |
| 738 | { | |
| 739 | struct smb_rq rq, *rqp = &rq; | |
| 740 | struct smb_share *ssp = np->n_mount->sm_share; | |
| 741 | struct mbchain *mbp; | |
| 742 | int error; | |
| 743 | ||
| 744 | error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred); | |
| 745 | if (error) | |
| 746 | return error; | |
| 747 | smb_rq_getrequest(rqp, &mbp); | |
| 748 | smb_rq_wstart(rqp); | |
| 749 | smb_rq_wend(rqp); | |
| 750 | smb_rq_bstart(rqp); | |
| 751 | mb_put_uint8(mbp, SMB_DT_ASCII); | |
| 752 | error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); | |
| 753 | if (!error) { | |
| 754 | smb_rq_bend(rqp); | |
| 755 | error = smb_rq_simple(rqp); | |
| 756 | } | |
| 757 | smb_rq_done(rqp); | |
| 758 | return error; | |
| 759 | } | |
| 760 | ||
| 761 | static int | |
| 762 | smbfs_smb_search(struct smbfs_fctx *ctx) | |
| 763 | { | |
| 764 | struct smb_vc *vcp = SSTOVC(ctx->f_ssp); | |
| 765 | struct smb_rq *rqp; | |
| 766 | struct mbchain *mbp; | |
| 767 | struct mdchain *mdp; | |
| 768 | u_int8_t wc, bt; | |
| 769 | u_int16_t ec, dlen, bc; | |
| 770 | int maxent, error, iseof = 0; | |
| 771 | ||
| 772 | maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); | |
| 773 | if (ctx->f_rq) { | |
| 774 | smb_rq_done(ctx->f_rq); | |
| 775 | ctx->f_rq = NULL; | |
| 776 | } | |
| 777 | error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); | |
| 778 | if (error) | |
| 779 | return error; | |
| 780 | ctx->f_rq = rqp; | |
| 781 | smb_rq_getrequest(rqp, &mbp); | |
| 782 | smb_rq_wstart(rqp); | |
| 783 | mb_put_uint16le(mbp, maxent); /* max entries to return */ | |
| 784 | mb_put_uint16le(mbp, ctx->f_attrmask); | |
| 785 | smb_rq_wend(rqp); | |
| 786 | smb_rq_bstart(rqp); | |
| 787 | mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ | |
| 788 | if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { | |
| 789 | error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); | |
| 790 | if (error) | |
| 791 | return error; | |
| 792 | mb_put_uint8(mbp, SMB_DT_VARIABLE); | |
| 793 | mb_put_uint16le(mbp, 0); /* context length */ | |
| 794 | ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; | |
| 795 | } else { | |
| 796 | mb_put_uint8(mbp, 0); /* file name length */ | |
| 797 | mb_put_uint8(mbp, SMB_DT_VARIABLE); | |
| 798 | mb_put_uint16le(mbp, SMB_SKEYLEN); | |
| 799 | mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); | |
| 800 | } | |
| 801 | smb_rq_bend(rqp); | |
| 802 | error = smb_rq_simple(rqp); | |
| 803 | if (error) { | |
| 804 | if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { | |
| 805 | error = 0; | |
| 806 | iseof = 1; | |
| 807 | ctx->f_flags |= SMBFS_RDD_EOF; | |
| 808 | } else | |
| 809 | return error; | |
| 810 | } | |
| 811 | smb_rq_getreply(rqp, &mdp); | |
| 812 | md_get_uint8(mdp, &wc); | |
| 813 | if (wc != 1) | |
| 814 | return iseof ? ENOENT : EBADRPC; | |
| 815 | md_get_uint16le(mdp, &ec); | |
| 816 | if (ec == 0) | |
| 817 | return ENOENT; | |
| 818 | ctx->f_ecnt = ec; | |
| 819 | md_get_uint16le(mdp, &bc); | |
| 820 | if (bc < 3) | |
| 821 | return EBADRPC; | |
| 822 | bc -= 3; | |
| 823 | md_get_uint8(mdp, &bt); | |
| 824 | if (bt != SMB_DT_VARIABLE) | |
| 825 | return EBADRPC; | |
| 826 | md_get_uint16le(mdp, &dlen); | |
| 827 | if (dlen != bc || dlen % SMB_DENTRYLEN != 0) | |
| 828 | return EBADRPC; | |
| 829 | return 0; | |
| 830 | } | |
| 831 | ||
| 832 | static int | |
| 833 | smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, | |
| 834 | const char *wildcard, int wclen, int attr, struct smb_cred *scred) | |
| 835 | { | |
| 836 | ctx->f_attrmask = attr; | |
| 837 | if (wildcard) { | |
| 838 | if (wclen == 1 && wildcard[0] == '*') { | |
| 839 | ctx->f_wildcard = "*.*"; | |
| 840 | ctx->f_wclen = 3; | |
| 841 | } else { | |
| 842 | ctx->f_wildcard = wildcard; | |
| 843 | ctx->f_wclen = wclen; | |
| 844 | } | |
| 845 | } else { | |
| 846 | ctx->f_wildcard = NULL; | |
| 847 | ctx->f_wclen = 0; | |
| 848 | } | |
| 849 | ctx->f_name = ctx->f_fname; | |
| 850 | return 0; | |
| 851 | } | |
| 852 | ||
| 853 | static int | |
| 854 | smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) | |
| 855 | { | |
| 856 | struct mdchain *mbp; | |
| 857 | struct smb_rq *rqp; | |
| 858 | char *cp; | |
| 859 | u_int8_t battr; | |
| 860 | u_int16_t date, time; | |
| 861 | u_int32_t size; | |
| 862 | int error; | |
| 863 | ||
| 864 | if (ctx->f_ecnt == 0) { | |
| 865 | if (ctx->f_flags & SMBFS_RDD_EOF) | |
| 866 | return ENOENT; | |
| 867 | ctx->f_left = ctx->f_limit = limit; | |
| 868 | error = smbfs_smb_search(ctx); | |
| 869 | if (error) | |
| 870 | return error; | |
| 871 | } | |
| 872 | rqp = ctx->f_rq; | |
| 873 | smb_rq_getreply(rqp, &mbp); | |
| 874 | md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); | |
| 875 | md_get_uint8(mbp, &battr); | |
| 876 | md_get_uint16le(mbp, &time); | |
| 877 | md_get_uint16le(mbp, &date); | |
| 878 | md_get_uint32le(mbp, &size); | |
| 879 | cp = ctx->f_name; | |
| 880 | md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); | |
| 881 | cp[sizeof(ctx->f_fname) - 1] = 0; | |
| 882 | cp += strlen(cp) - 1; | |
| 883 | while (*cp == ' ' && cp >= ctx->f_name) | |
| 884 | *cp-- = 0; | |
| 885 | ctx->f_attr.fa_attr = battr; | |
| 886 | smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, | |
| 887 | &ctx->f_attr.fa_mtime); | |
| 888 | ctx->f_attr.fa_size = size; | |
| 889 | ctx->f_nmlen = strlen(ctx->f_name); | |
| 890 | ctx->f_ecnt--; | |
| 891 | ctx->f_left--; | |
| 892 | return 0; | |
| 893 | } | |
| 894 | ||
| 895 | static int | |
| 896 | smbfs_findcloseLM1(struct smbfs_fctx *ctx) | |
| 897 | { | |
| 898 | if (ctx->f_rq) | |
| 899 | smb_rq_done(ctx->f_rq); | |
| 900 | return 0; | |
| 901 | } | |
| 902 | ||
| 903 | /* | |
| 904 | * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect | |
| 905 | */ | |
| 906 | static int | |
| 907 | smbfs_smb_trans2find2(struct smbfs_fctx *ctx) | |
| 908 | { | |
| 909 | struct smb_t2rq *t2p; | |
| 910 | struct smb_vc *vcp = SSTOVC(ctx->f_ssp); | |
| 911 | struct mbchain *mbp; | |
| 912 | struct mdchain *mdp; | |
| 913 | u_int16_t tw, flags; | |
| 914 | int error; | |
| 915 | ||
| 916 | if (ctx->f_t2) { | |
| 917 | smb_t2_done(ctx->f_t2); | |
| 918 | ctx->f_t2 = NULL; | |
| 919 | } | |
| 920 | ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; | |
| 921 | flags = 8 | 2; /* <resume> | <close if EOS> */ | |
| 922 | if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { | |
| 923 | flags |= 1; /* close search after this request */ | |
| 924 | ctx->f_flags |= SMBFS_RDD_NOCLOSE; | |
| 925 | } | |
| 926 | if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { | |
| 927 | error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, | |
| 928 | ctx->f_scred, &t2p); | |
| 929 | if (error) | |
| 930 | return error; | |
| 931 | ctx->f_t2 = t2p; | |
| 932 | mbp = &t2p->t2_tparam; | |
| 933 | mb_init(mbp); | |
| 934 | mb_put_uint16le(mbp, ctx->f_attrmask); | |
| 935 | mb_put_uint16le(mbp, ctx->f_limit); | |
| 936 | mb_put_uint16le(mbp, flags); | |
| 937 | mb_put_uint16le(mbp, ctx->f_infolevel); | |
| 938 | mb_put_uint32le(mbp, 0); | |
| 939 | error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); | |
| 940 | if (error) | |
| 941 | return error; | |
| 942 | } else { | |
| 943 | error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, | |
| 944 | ctx->f_scred, &t2p); | |
| 945 | if (error) | |
| 946 | return error; | |
| 947 | ctx->f_t2 = t2p; | |
| 948 | mbp = &t2p->t2_tparam; | |
| 949 | mb_init(mbp); | |
| 950 | mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); | |
| 951 | mb_put_uint16le(mbp, ctx->f_limit); | |
| 952 | mb_put_uint16le(mbp, ctx->f_infolevel); | |
| 953 | mb_put_uint32le(mbp, 0); /* resume key */ | |
| 954 | mb_put_uint16le(mbp, flags); | |
| 955 | if (ctx->f_rname) | |
| 956 | mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM); | |
| 957 | else | |
| 958 | mb_put_uint8(mbp, 0); /* resume file name */ | |
| 959 | #if 0 | |
| 960 | struct timeval tv; | |
| 961 | tv.tv_sec = 0; | |
| 962 | tv.tv_usec = 200 * 1000; /* 200ms */ | |
| 963 | if (vcp->vc_flags & SMBC_WIN95) { | |
| 964 | /* | |
| 965 | * some implementations suggests to sleep here | |
| 966 | * for 200ms, due to the bug in the Win95. | |
| 967 | * I've didn't notice any problem, but put code | |
| 968 | * for it. | |
| 969 | */ | |
| a94976ad | 970 | tsleep(&flags, 0, "fix95", tvtohz_high(&tv)); |
| 984263bc MD |
971 | } |
| 972 | #endif | |
| 973 | } | |
| 974 | t2p->t2_maxpcount = 5 * 2; | |
| 975 | t2p->t2_maxdcount = vcp->vc_txmax; | |
| 976 | error = smb_t2_request(t2p); | |
| 977 | if (error) | |
| 978 | return error; | |
| 979 | mdp = &t2p->t2_rparam; | |
| 980 | if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { | |
| 981 | if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) | |
| 982 | return error; | |
| 983 | ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; | |
| 984 | } | |
| 985 | if ((error = md_get_uint16le(mdp, &tw)) != 0) | |
| 986 | return error; | |
| 987 | ctx->f_ecnt = tw; | |
| 988 | if ((error = md_get_uint16le(mdp, &tw)) != 0) | |
| 989 | return error; | |
| 990 | if (tw) | |
| 991 | ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; | |
| 992 | if ((error = md_get_uint16le(mdp, &tw)) != 0) | |
| 993 | return error; | |
| 994 | if ((error = md_get_uint16le(mdp, &tw)) != 0) | |
| 995 | return error; | |
| 996 | if (ctx->f_ecnt == 0) | |
| 997 | return ENOENT; | |
| 998 | ctx->f_rnameofs = tw; | |
| 999 | mdp = &t2p->t2_rdata; | |
| 1000 | if (mdp->md_top == NULL) { | |
| 086c1d7e | 1001 | kprintf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt); |
| 984263bc MD |
1002 | return ENOENT; |
| 1003 | } | |
| 1004 | if (mdp->md_top->m_len == 0) { | |
| 086c1d7e | 1005 | kprintf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next); |
| 984263bc MD |
1006 | return ENOENT; |
| 1007 | } | |
| 1008 | ctx->f_eofs = 0; | |
| 1009 | return 0; | |
| 1010 | } | |
| 1011 | ||
| 1012 | static int | |
| 1013 | smbfs_smb_findclose2(struct smbfs_fctx *ctx) | |
| 1014 | { | |
| 1015 | struct smb_rq rq, *rqp = &rq; | |
| 1016 | struct mbchain *mbp; | |
| 1017 | int error; | |
| 1018 | ||
| 1019 | error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred); | |
| 1020 | if (error) | |
| 1021 | return error; | |
| 1022 | smb_rq_getrequest(rqp, &mbp); | |
| 1023 | smb_rq_wstart(rqp); | |
| 1024 | mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); | |
| 1025 | smb_rq_wend(rqp); | |
| 1026 | smb_rq_bstart(rqp); | |
| 1027 | smb_rq_bend(rqp); | |
| 1028 | error = smb_rq_simple(rqp); | |
| 1029 | smb_rq_done(rqp); | |
| 1030 | return error; | |
| 1031 | } | |
| 1032 | ||
| 1033 | static int | |
| 1034 | smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, | |
| 1035 | const char *wildcard, int wclen, int attr, struct smb_cred *scred) | |
| 1036 | { | |
| efda3bd0 | 1037 | ctx->f_name = kmalloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); |
| 984263bc MD |
1038 | ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? |
| 1039 | SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; | |
| 1040 | ctx->f_attrmask = attr; | |
| 1041 | ctx->f_wildcard = wildcard; | |
| 1042 | ctx->f_wclen = wclen; | |
| 1043 | return 0; | |
| 1044 | } | |
| 1045 | ||
| 1046 | static int | |
| 1047 | smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) | |
| 1048 | { | |
| 1049 | struct mdchain *mbp; | |
| 1050 | struct smb_t2rq *t2p; | |
| 1051 | char *cp; | |
| 1052 | u_int8_t tb; | |
| 1053 | u_int16_t date, time, wattr; | |
| 1054 | u_int32_t size, next, dattr; | |
| 1055 | int64_t lint; | |
| 1056 | int error, svtz, cnt, fxsz, nmlen, recsz; | |
| 1057 | ||
| 1058 | if (ctx->f_ecnt == 0) { | |
| 1059 | if (ctx->f_flags & SMBFS_RDD_EOF) | |
| 1060 | return ENOENT; | |
| 1061 | ctx->f_left = ctx->f_limit = limit; | |
| 1062 | error = smbfs_smb_trans2find2(ctx); | |
| 1063 | if (error) | |
| 1064 | return error; | |
| 1065 | } | |
| 1066 | t2p = ctx->f_t2; | |
| 1067 | mbp = &t2p->t2_rdata; | |
| 1068 | svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; | |
| 1069 | switch (ctx->f_infolevel) { | |
| 1070 | case SMB_INFO_STANDARD: | |
| 1071 | next = 0; | |
| 1072 | fxsz = 0; | |
| 1073 | md_get_uint16le(mbp, &date); | |
| 1074 | md_get_uint16le(mbp, &time); /* creation time */ | |
| 1075 | md_get_uint16le(mbp, &date); | |
| 1076 | md_get_uint16le(mbp, &time); /* access time */ | |
| 1077 | smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); | |
| 1078 | md_get_uint16le(mbp, &date); | |
| 1079 | md_get_uint16le(mbp, &time); /* access time */ | |
| 1080 | smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); | |
| 1081 | md_get_uint32le(mbp, &size); | |
| 1082 | ctx->f_attr.fa_size = size; | |
| 1083 | md_get_uint32(mbp, NULL); /* allocation size */ | |
| 1084 | md_get_uint16le(mbp, &wattr); | |
| 1085 | ctx->f_attr.fa_attr = wattr; | |
| 1086 | md_get_uint8(mbp, &tb); | |
| 1087 | size = nmlen = tb; | |
| 1088 | fxsz = 23; | |
| 1089 | recsz = next = 24 + nmlen; /* docs misses zero byte at end */ | |
| 1090 | break; | |
| 1091 | case SMB_FIND_FILE_DIRECTORY_INFO: | |
| 1092 | md_get_uint32le(mbp, &next); | |
| 1093 | md_get_uint32(mbp, NULL); /* file index */ | |
| 1094 | md_get_int64(mbp, NULL); /* creation time */ | |
| 1095 | md_get_int64le(mbp, &lint); | |
| 1096 | smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); | |
| 1097 | md_get_int64le(mbp, &lint); | |
| 1098 | smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); | |
| 1099 | md_get_int64le(mbp, &lint); | |
| 1100 | smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); | |
| 1101 | md_get_int64le(mbp, &lint); /* file size */ | |
| 1102 | ctx->f_attr.fa_size = lint; | |
| 1103 | md_get_int64(mbp, NULL); /* real size (should use) */ | |
| 1104 | md_get_uint32(mbp, &dattr); /* EA */ | |
| 1105 | ctx->f_attr.fa_attr = dattr; | |
| 1106 | md_get_uint32le(mbp, &size); /* name len */ | |
| 1107 | fxsz = 64; | |
| 1108 | recsz = next ? next : fxsz + size; | |
| 1109 | break; | |
| 1110 | default: | |
| 1111 | SMBERROR("unexpected info level %d\n", ctx->f_infolevel); | |
| 1112 | return EINVAL; | |
| 1113 | } | |
| 1114 | nmlen = min(size, SMB_MAXFNAMELEN); | |
| 1115 | cp = ctx->f_name; | |
| 1116 | error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); | |
| 1117 | if (error) | |
| 1118 | return error; | |
| 1119 | if (next) { | |
| 1120 | cnt = next - nmlen - fxsz; | |
| 1121 | if (cnt > 0) | |
| 1122 | md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); | |
| 1123 | else if (cnt < 0) { | |
| 1124 | SMBERROR("out of sync\n"); | |
| 1125 | return EBADRPC; | |
| 1126 | } | |
| 1127 | } | |
| 1128 | if (nmlen && cp[nmlen - 1] == 0) | |
| 1129 | nmlen--; | |
| 1130 | if (nmlen == 0) | |
| 1131 | return EBADRPC; | |
| 1132 | ||
| 1133 | next = ctx->f_eofs + recsz; | |
| 1134 | if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && | |
| 1135 | (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { | |
| 1136 | /* | |
| 1137 | * Server needs a resume filename. | |
| 1138 | */ | |
| 1139 | if (ctx->f_rnamelen <= nmlen) { | |
| 1140 | if (ctx->f_rname) | |
| efda3bd0 MD |
1141 | kfree(ctx->f_rname, M_SMBFSDATA); |
| 1142 | ctx->f_rname = kmalloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); | |
| 984263bc MD |
1143 | ctx->f_rnamelen = nmlen; |
| 1144 | } | |
| 1145 | bcopy(ctx->f_name, ctx->f_rname, nmlen); | |
| 1146 | ctx->f_rname[nmlen] = 0; | |
| 1147 | ctx->f_flags |= SMBFS_RDD_GOTRNAME; | |
| 1148 | } | |
| 1149 | ctx->f_nmlen = nmlen; | |
| 1150 | ctx->f_eofs = next; | |
| 1151 | ctx->f_ecnt--; | |
| 1152 | ctx->f_left--; | |
| 1153 | return 0; | |
| 1154 | } | |
| 1155 | ||
| 1156 | static int | |
| 1157 | smbfs_findcloseLM2(struct smbfs_fctx *ctx) | |
| 1158 | { | |
| 1159 | if (ctx->f_name) | |
| efda3bd0 | 1160 | kfree(ctx->f_name, M_SMBFSDATA); |
| 984263bc MD |
1161 | if (ctx->f_t2) |
| 1162 | smb_t2_done(ctx->f_t2); | |
| 1163 | if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) | |
| 1164 | smbfs_smb_findclose2(ctx); | |
| 1165 | return 0; | |
| 1166 | } | |
| 1167 | ||
| 1168 | int | |
| 1169 | smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, | |
| 1170 | struct smb_cred *scred, struct smbfs_fctx **ctxpp) | |
| 1171 | { | |
| 1172 | struct smbfs_fctx *ctx; | |
| 1173 | int error; | |
| 1174 | ||
| e7b4468c | 1175 | ctx = kmalloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK | M_ZERO); |
| 984263bc MD |
1176 | ctx->f_ssp = dnp->n_mount->sm_share; |
| 1177 | ctx->f_dnp = dnp; | |
| 1178 | ctx->f_flags = SMBFS_RDD_FINDFIRST; | |
| 1179 | ctx->f_scred = scred; | |
| 1180 | if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || | |
| 1181 | (dnp->n_mount->sm_args.flags & SMBFS_MOUNT_NO_LONG)) { | |
| 1182 | ctx->f_flags |= SMBFS_RDD_USESEARCH; | |
| 1183 | error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); | |
| 1184 | } else | |
| 1185 | error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); | |
| 1186 | if (error) | |
| 1187 | smbfs_findclose(ctx, scred); | |
| 1188 | else | |
| 1189 | *ctxpp = ctx; | |
| 1190 | return error; | |
| 1191 | } | |
| 1192 | ||
| 1193 | int | |
| 1194 | smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) | |
| 1195 | { | |
| 1196 | int error; | |
| 1197 | ||
| 1198 | if (limit == 0) | |
| 1199 | limit = 1000000; | |
| 1200 | else if (limit > 1) | |
| 1201 | limit *= 4; /* imperical */ | |
| 1202 | ctx->f_scred = scred; | |
| 1203 | for (;;) { | |
| 1204 | if (ctx->f_flags & SMBFS_RDD_USESEARCH) { | |
| 1205 | error = smbfs_findnextLM1(ctx, limit); | |
| 1206 | } else | |
| 1207 | error = smbfs_findnextLM2(ctx, limit); | |
| 1208 | if (error) | |
| 1209 | return error; | |
| 1210 | if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || | |
| 1211 | (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && | |
| 1212 | ctx->f_name[1] == '.')) | |
| 1213 | continue; | |
| 1214 | break; | |
| 1215 | } | |
| 1216 | smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen, | |
| 1217 | ctx->f_dnp->n_mount->sm_caseopt); | |
| 1218 | ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); | |
| 1219 | return 0; | |
| 1220 | } | |
| 1221 | ||
| 1222 | int | |
| 1223 | smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) | |
| 1224 | { | |
| 1225 | ctx->f_scred = scred; | |
| 1226 | if (ctx->f_flags & SMBFS_RDD_USESEARCH) { | |
| 1227 | smbfs_findcloseLM1(ctx); | |
| 1228 | } else | |
| 1229 | smbfs_findcloseLM2(ctx); | |
| 1230 | if (ctx->f_rname) | |
| efda3bd0 MD |
1231 | kfree(ctx->f_rname, M_SMBFSDATA); |
| 1232 | kfree(ctx, M_SMBFSDATA); | |
| 984263bc MD |
1233 | return 0; |
| 1234 | } | |
| 1235 | ||
| 1236 | int | |
| 1237 | smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, | |
| 1238 | struct smbfattr *fap, struct smb_cred *scred) | |
| 1239 | { | |
| 1240 | struct smbfs_fctx *ctx; | |
| 1241 | int error; | |
| 1242 | ||
| 1243 | if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { | |
| 1244 | bzero(fap, sizeof(*fap)); | |
| 1245 | fap->fa_attr = SMB_FA_DIR; | |
| 1246 | fap->fa_ino = 2; | |
| 1247 | return 0; | |
| 1248 | } | |
| 1249 | if (nmlen == 1 && name[0] == '.') { | |
| 1250 | error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); | |
| 1251 | return error; | |
| 1252 | } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { | |
| 1253 | error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, | |
| 1254 | scred); | |
| 086c1d7e | 1255 | kprintf("%s: knows NOTHING about '..'\n", __func__); |
| 984263bc MD |
1256 | return error; |
| 1257 | } | |
| 1258 | error = smbfs_findopen(dnp, name, nmlen, | |
| 1259 | SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); | |
| 1260 | if (error) | |
| 1261 | return error; | |
| 1262 | ctx->f_flags |= SMBFS_RDD_FINDSINGLE; | |
| 1263 | error = smbfs_findnext(ctx, 1, scred); | |
| 1264 | if (error == 0) { | |
| 1265 | *fap = ctx->f_attr; | |
| 1266 | if (name == NULL) | |
| 1267 | fap->fa_ino = dnp->n_ino; | |
| 1268 | } | |
| 1269 | smbfs_findclose(ctx, scred); | |
| 1270 | return error; | |
| 1271 | } |