#include "headers.h" #include void smbsearchfree(SmbSearch **searchp) { SmbSearch *search = *searchp; if (search) { smbdircachefree(&search->dc); free(search->rep); free(search); *searchp = nil; } } void smbsearchclose(SmbSession *s, SmbSearch *search) { if (search) { smblogprintif(smbglobals.log.sids, "smbsearchclose: tid 0x%.4ux sid 0x%.4ux\n", search->t->id, search->id); smbidmapremove(s->sidmap, search); smbsearchfree(&search); } } void smbsearchclosebyid(SmbSession *s, ushort sid) { smbsearchclose(s, smbidmapfind(s->sidmap, sid)); } SmbSearch * smbsearchnew(SmbSession *s, SmbDirCache *dc, Reprog *r, SmbTree *t) { SmbSearch *search; if (s->sidmap == nil) s->sidmap = smbidmapnew(); search = smbemalloc(sizeof(SmbSearch)); smbidmapadd(s->sidmap, search); search->dc = dc; search->rep = r; search->t = t; smblogprintif(smbglobals.log.sids, "smbsearchnew: 0x%.4ux\n", search->id); return search; } static int standardflatten(SmbSession *s, SmbBuffer *b, Dir *d, ulong *nameoffsetp) { ushort mdate, mtime; ushort adate, atime; ushort fnlfixupoffset; smbplan9time2datetime(d->mtime, s->tzoff, &mdate, &mtime); smbplan9time2datetime(d->atime, s->tzoff, &adate, &atime); if (!smbbufferputs(b, mdate) || !smbbufferputs(b, mtime) || !smbbufferputs(b, adate) || !smbbufferputs(b, atime) || !smbbufferputs(b, mdate) || !smbbufferputs(b, mtime) || !smbbufferputl(b, d->length) || !smbbufferputl(b, 512) // ha || !smbbufferputs(b, (d->qid.type & QTDIR) ? 0x10 : 0)) return 0; fnlfixupoffset = smbbufferwriteoffset(b); if (!smbbufferputs(b, 0)) return 0; *nameoffsetp = smbbufferwriteoffset(b); if (!smbbufferputstring(b, &s->peerinfo, 0, d->name)) return 0; return smbbufferfixuprelatives(b, fnlfixupoffset); } static int findbothflatten(SmbBuffer *b, SmbPeerInfo *p, Dir *d, ulong resumekey, ulong *nameoffsetp) { vlong mtime, atime; ulong fixup; fixup = smbbufferwriteoffset(b); mtime = smbplan9time2time(d->mtime); atime = smbplan9time2time(d->atime); poolcheck(mainmem); if (!smbbufferputl(b, 0) || !smbbufferputl(b, resumekey) || !smbbufferputv(b, mtime) || !smbbufferputv(b, atime) || !smbbufferputv(b, mtime) || !smbbufferputv(b, mtime) || !smbbufferputv(b, d->length) || !smbbufferputv(b, smbl2roundupvlong(d->length, smbglobals.l2allocationsize)) // ha || !smbbufferputl(b, (d->qid.type & QTDIR) ? 0x10 : 0x80) || !smbbufferputl(b, smbstringlen(p, d->name)) || !smbbufferputl(b, 0) || !smbbufferputb(b, 0) || !smbbufferputb(b, 0) || !smbbufferfill(b, 0, 24)) return 0; poolcheck(mainmem); *nameoffsetp = smbbufferwriteoffset(b); if (!smbbufferputstring(b, p, 0, d->name) || !smbbufferalignl2(b, 2)) return 0; poolcheck(mainmem); return smbbufferfixuprelativeinclusivel(b, fixup); } static void populate(SmbSession *s, SmbDirCache *dc, Reprog *r, ushort informationlevel, ushort flags, ushort scount, ushort *ep, ulong *nameoffsetp) { ushort e; ulong nameoffset; e = 0; nameoffset = 0; while (dc->i < dc->n && e < scount) { ulong backup; int rv; if (!smbmatch(dc->buf[dc->i].name, r)) { dc->i++; continue; } rv = 0; backup = smbbufferwriteoffset(s->transaction.out.data); switch (informationlevel) { case SMB_INFO_STANDARD: if (flags & SMB_FIND_RETURN_RESUME_KEYS) { if (!smbbufferputl(s->transaction.out.data, dc->i)) { rv = 0; break; } } rv = standardflatten(s, s->transaction.out.data, dc->buf + dc->i, &nameoffset); break; case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: rv = findbothflatten(s->transaction.out.data, &s->peerinfo, dc->buf + dc->i, dc->i, &nameoffset); break; } if (rv == 0) { smbbufferwritebackup(s->transaction.out.data, backup); break; } dc->i++; e++; } *ep = e; *nameoffsetp = nameoffset; } SmbProcessResult smbtrans2findfirst2(SmbSession *s, SmbHeader *h) { SmbBuffer *b; char *pattern = nil; char *dir = nil; char *name = nil; ushort searchattributes, searchcount, flags, informationlevel; ulong searchstoragetype; SmbDirCache *dc = nil; ushort e; ulong nameoffset; ushort eos; SmbSearch *search; SmbProcessResult pr; Reprog *r = nil; SmbTree *t; int debug; debug = smboptable[h->command].debug || smbtrans2optable[SMB_TRANS2_FIND_FIRST2].debug || smbglobals.log.find; poolcheck(mainmem); b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount); if (!smbbuffergets(b, &searchattributes) || !smbbuffergets(b, &searchcount) || !smbbuffergets(b, &flags) || !smbbuffergets(b, &informationlevel) || !smbbuffergetl(b, &searchstoragetype) || !smbbuffergetstring(b, h, SMB_STRING_PATH, &pattern)) { pr = SmbProcessResultFormat; goto done; } smbloglock(); smblogprintif(debug, "searchattributes: 0x%.4ux\n", searchattributes); smblogprintif(debug, "searchcount: 0x%.4ux\n", searchcount); smblogprintif(debug, "flags: 0x%.4ux\n", flags); smblogprintif(debug, "informationlevel: 0x%.4ux\n", informationlevel); smblogprintif(debug, "searchstoragetype: 0x%.8lux\n", searchstoragetype); smblogprintif(debug, "pattern: %s\n", pattern); smblogunlock(); smbpathsplit(pattern, &dir, &name); if (informationlevel != SMB_INFO_STANDARD && informationlevel != SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { smblogprint(-1, "smbtrans2findfirst2: infolevel 0x%.4ux not implemented\n", informationlevel); smbseterror(s, ERRDOS, ERRunknownlevel); pr = SmbProcessResultError; goto done; } t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); pr = SmbProcessResultError; goto done; } dc = smbmkdircache(t, dir); if (dc == nil) { smbseterror(s, ERRDOS, ERRnoaccess); pr = SmbProcessResultError; goto done; } poolcheck(mainmem); r = smbmkrep(name); populate(s, dc, r, informationlevel, flags, searchcount, &e, &nameoffset); poolcheck(mainmem); eos = dc->i >= dc->n; if ((flags & SMB_FIND_CLOSE) != 0 || ((flags & SMB_FIND_CLOSE_EOS) != 0 && eos)) smbdircachefree(&dc); poolcheck(mainmem); if (dc) { /* create a search handle */ search = smbsearchnew(s, dc, r, t); r = nil; dc = nil; } else search = nil; smbbufferputs(s->transaction.out.parameters, search ? search->id : 0); smbbufferputs(s->transaction.out.parameters, e); smbbufferputs(s->transaction.out.parameters, eos); smbbufferputs(s->transaction.out.parameters, 0); smbbufferputs(s->transaction.out.parameters, nameoffset); pr = SmbProcessResultReply; done: smbbufferfree(&b); free(pattern); free(dir); free(name); smbdircachefree(&dc); free(r); return pr; } SmbProcessResult smbtrans2findnext2(SmbSession *s, SmbHeader *h) { SmbBuffer *b; int debug; ushort sid, scount, infolevel; ulong resumekey; ushort flags; char *filename = nil; SmbProcessResult pr; ushort e; ulong nameoffset; ushort eos; SmbTree *t; SmbSearch *search; debug = smboptable[h->command].debug || smbtrans2optable[SMB_TRANS2_FIND_NEXT2].debug || smbglobals.log.find; b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount); if (!smbbuffergets(b, &sid) || !smbbuffergets(b, &scount) || !smbbuffergets(b, &infolevel) || !smbbuffergetl(b, &resumekey) || !smbbuffergets(b, &flags) || !smbbuffergetstring(b, h, 0, &filename)) { pr = SmbProcessResultFormat; goto done; } smblogprintif(debug, "smbtrans2findnext2: sid %d scount %d infolevel 0x%.4ux resumekey %lud flags 0x%.4ux filename %s\n", sid, scount, infolevel, resumekey, flags, filename); if (infolevel != SMB_INFO_STANDARD && infolevel != SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { smblogprint(-1, "smbtrans2findnext2: infolevel 0x%.4ux not implemented\n", infolevel); smbseterror(s, ERRDOS, ERRunknownlevel); pr = SmbProcessResultError; goto done; } t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); pr = SmbProcessResultError; goto done; } search = smbidmapfind(s->sidmap, sid); if (search == nil) { smbseterror(s, ERRDOS, ERRnofiles); pr = SmbProcessResultError; goto done; } if (search->t != t) { smbseterror(s, ERRSRV, ERRinvtid); pr = SmbProcessResultError; goto done; } if ((flags & (1 << 3)) == 0) { long i; if (filename == nil) { smbseterror(s, ERRDOS, ERRnofiles); pr = SmbProcessResultError; goto done; } for (i = 0; i < search->dc->n; i++) if (strcmp(search->dc->buf[i].name, filename) == 0) { search->dc->i = i + 1; break; } } populate(s, search->dc, search->rep, infolevel, flags, scount, &e, &nameoffset); eos = search->dc->i >= search->dc->n; if ((flags & SMB_FIND_CLOSE) != 0 || ((flags & SMB_FIND_CLOSE_EOS) != 0 && eos)) smbsearchclose(s, search); smbbufferputs(s->transaction.out.parameters, e); smbbufferputs(s->transaction.out.parameters, eos); smbbufferputs(s->transaction.out.parameters, 0); smbbufferputs(s->transaction.out.parameters, nameoffset); pr = SmbProcessResultReply; done: smbbufferfree(&b); free(filename); return pr; }