static int smb_t2_reply(struct smb_t2rq *t2p) { struct mdchain *mdp; struct smb_rq *rqp = t2p->t2_rq; int error, totpgot, totdgot; u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp; u_int16_t tmp, bc, dcount; u_int8_t wc; error = smb_rq_reply(rqp); if (error) return error; if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) { /* * this is an interim response, ignore it. */ SMBRQ_SLOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_SUNLOCK(rqp); return 0; } /* * Now we have to get all subsequent responses. The CIFS specification * says that they can be disordered which is weird. * TODO: timo */ totpgot = totdgot = 0; totpcount = totdcount = 0xffff; mdp = &rqp->sr_rp; for (;;) { m_dumpm(mdp->md_top); if ((error = md_get_uint8(mdp, &wc)) != 0) break; if (wc < 10) { error = ENOENT; break; } if ((error = md_get_uint16le(mdp, &tmp)) != 0) break; if (totpcount > tmp) totpcount = tmp; md_get_uint16le(mdp, &tmp); if (totdcount > tmp) totdcount = tmp; if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */ (error = md_get_uint16le(mdp, &pcount)) != 0 || (error = md_get_uint16le(mdp, &poff)) != 0 || (error = md_get_uint16le(mdp, &pdisp)) != 0) break; if (pcount != 0 && pdisp != totpgot) { SMBERROR("Can't handle disordered parameters %d:%d\n", pdisp, totpgot); error = EINVAL; break; } if ((error = md_get_uint16le(mdp, &dcount)) != 0 || (error = md_get_uint16le(mdp, &doff)) != 0 || (error = md_get_uint16le(mdp, &ddisp)) != 0) break; if (dcount != 0 && ddisp != totdgot) { SMBERROR("Can't handle disordered data\n"); error = EINVAL; break; } md_get_uint8(mdp, &wc); md_get_uint8(mdp, NULL); tmp = wc; while (tmp--) md_get_uint16(mdp, NULL); if ((error = md_get_uint16le(mdp, &bc)) != 0) break; /* tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/ if (dcount) { error = smb_t2_placedata(mdp->md_top, doff, dcount, &t2p->t2_rdata); if (error) break; } if (pcount) { error = smb_t2_placedata(mdp->md_top, poff, pcount, &t2p->t2_rparam); if (error) break; } totpgot += pcount; totdgot += dcount; if (totpgot >= totpcount && totdgot >= totdcount) { error = 0; t2p->t2_flags |= SMBT2_ALLRECV; break; } /* * We're done with this reply, look for the next one. */ SMBRQ_SLOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_SUNLOCK(rqp); error = smb_rq_reply(rqp); if (error) break; } return error; }
int smbfs_smb_nt_dirnotify_fetch(struct smb_rq *rqp, int *hint) { int error; struct mdchain *mdp; u_int8_t sc; u_int32_t nextentry; error = smb_rq_reply(rqp); if (error) { /* * If we get EMSGSIZE, there is already too many notifications * available for the directory, and the internal buffer * overflew. Just flag any possible relevant change. */ if (error == EMSGSIZE) { *hint = NOTE_ATTRIB | NOTE_WRITE; error = 0; } goto bad; } smb_rq_getreply(rqp, &mdp); /* Parse reply */ error = md_get_mem(mdp, NULL, 4 + (8*4), MB_MZERO); /* skip */ if (error) goto bad; md_get_uint8(mdp, &sc); /* SetupCount */ if (sc > 0) md_get_mem(mdp, NULL, sc * sizeof(u_int16_t), MB_MZERO); md_get_uint16(mdp, NULL); /* ByteCount */ md_get_mem(mdp, NULL, 1 + (sc % 2) * 2, MB_MZERO); /* Pad */ /* * The notify data are blocks of * ULONG nextentry - offset of next entry from start of this one * ULONG action - type of notification * ULONG filenamelen - length of filename in bytes * WCHAR filename[filenamelen/2] - Unicode filename * nexentry == 0 means last notification, filename is in 16bit LE * unicode */ *hint = 0; do { u_int32_t action; #if 0 u_int32_t fnlen; u_int16_t fnc; #endif md_get_uint32le(mdp, &nextentry); md_get_uint32le(mdp, &action); if (nextentry) md_get_mem(mdp, NULL, nextentry - 2 * 4, MB_MZERO); #if 0 md_get_uint32le(mdp, &fnlen); printf("notify: next %u act %u fnlen %u fname '", nextentry, action, fnlen); for(; fnlen > 0; fnlen -= 2) { md_get_uint16le(mdp, &fnc); printf("%c", fnc&0xff); } printf("'\n"); #endif switch(action) { case FILE_ACTION_ADDED: case FILE_ACTION_REMOVED: case FILE_ACTION_RENAMED_OLD_NAME: case FILE_ACTION_RENAMED_NEW_NAME: *hint |= NOTE_ATTRIB | NOTE_WRITE; break; case FILE_ACTION_MODIFIED: *hint |= NOTE_ATTRIB; break; } } while(nextentry > 0); bad: smb_rq_done(rqp); return error; }