793 lines
19 KiB
C
793 lines
19 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
srvtrans.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Implements transaction smb packets
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Ahmed Mohamed (ahmedm) 1-Feb-2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "srv.h"
|
||
|
|
||
|
typedef struct {
|
||
|
HANDLE handle;
|
||
|
WIN32_FIND_DATA *last;
|
||
|
ULONG cookie;
|
||
|
USHORT Sid;
|
||
|
USHORT info_level;
|
||
|
USHORT base_size;
|
||
|
USHORT add_res_key;
|
||
|
}dm_t;
|
||
|
|
||
|
static CRITICAL_SECTION dLock;
|
||
|
#define DirTableSz 1024
|
||
|
static dm_t *DirTable[DirTableSz];
|
||
|
|
||
|
#define SET_REQ(x, type, p) { \
|
||
|
x = (type) (p)->in.pParameters; \
|
||
|
(p)->in.pParameters += sizeof(*x); \
|
||
|
}
|
||
|
|
||
|
|
||
|
// XXX: need to handle padding
|
||
|
|
||
|
void*
|
||
|
ADD_RESP_PARAMS(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2,
|
||
|
PVOID resp,
|
||
|
USHORT size
|
||
|
)
|
||
|
{
|
||
|
PUCHAR p;
|
||
|
|
||
|
if (trans2->out.ParameterBytesLeft < size) return 0;
|
||
|
if (trans2->out.pResp->DataCount) {
|
||
|
PUCHAR d = (PUCHAR)msg->out.smb;
|
||
|
d += trans2->out.pResp->DataOffset;
|
||
|
// need to use MoveMemory due to possible overlap
|
||
|
RtlMoveMemory((PVOID)(d + size),
|
||
|
(PVOID)d, trans2->out.pResp->DataCount);
|
||
|
// we up the data offset below
|
||
|
}
|
||
|
p = (PUCHAR)msg->out.smb;
|
||
|
p += trans2->out.pResp->ParameterOffset +
|
||
|
trans2->out.pResp->ParameterCount;
|
||
|
if (resp) RtlCopyMemory((PVOID)p, (PVOID)resp, (ULONG)size);
|
||
|
trans2->out.pResp->ParameterCount += size;
|
||
|
trans2->out.pResp->TotalParameterCount += size;
|
||
|
*(trans2->out.pByteCount) += size;
|
||
|
trans2->out.pResp->DataOffset += size;
|
||
|
msg->out.valid += size;
|
||
|
trans2->out.ParameterBytesLeft -= size;
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void*
|
||
|
ADD_RESP_DATA(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2,
|
||
|
PVOID resp,
|
||
|
USHORT size
|
||
|
)
|
||
|
{
|
||
|
PUCHAR d;
|
||
|
|
||
|
if (trans2->out.DataBytesLeft < size) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
d = (PUCHAR)msg->out.smb;
|
||
|
d += (trans2->out.pResp->DataOffset +
|
||
|
trans2->out.pResp->DataCount);
|
||
|
|
||
|
if (resp != NULL) {
|
||
|
RtlCopyMemory((PVOID)d, (PVOID)resp, (ULONG)size);
|
||
|
}
|
||
|
|
||
|
trans2->out.pResp->DataCount += size;
|
||
|
trans2->out.pResp->TotalDataCount += size;
|
||
|
*(trans2->out.pByteCount) += size;
|
||
|
|
||
|
msg->out.valid += size;
|
||
|
trans2->out.DataBytesLeft -= size;
|
||
|
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
////
|
||
|
|
||
|
BOOL
|
||
|
Trans2Unknown(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
SrvLogError(("DOSERROR: (------ CANNOT HANDLE THIS TRANS2 FUNCTION ------)\n"));
|
||
|
SET_DOSERROR(msg, SERVER, NO_SUPPORT);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Trans2QueryFsInfo(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
PVOID fshdl;
|
||
|
USHORT tid = msg->in.smb->Tid;
|
||
|
USHORT uid = msg->in.smb->Uid;
|
||
|
PVOID fsctx = SRV_GET_FS_HANDLE(msg);
|
||
|
FsDispatchTable* pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
|
||
|
fs_attr_t fsattr;
|
||
|
DWORD error;
|
||
|
|
||
|
PREQ_QUERY_FS_INFORMATION pReq;
|
||
|
SET_REQ(pReq, PREQ_QUERY_FS_INFORMATION, trans2);
|
||
|
|
||
|
if (!pDisp) {
|
||
|
SrvLogError(("DOSERROR: no such uid\n"));
|
||
|
SET_DOSERROR(msg, SERVER, BAD_UID);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
error = pDisp->FsStatfs(fshdl, &fsattr);
|
||
|
if (error) {
|
||
|
SrvLogError(("WIN32ERROR: statfs error 0x%08X\n", error));
|
||
|
SET_WIN32ERROR(msg, error);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
SrvLog(("statfs %s level %d %d\n",
|
||
|
fsattr.fs_name,
|
||
|
pReq->InformationLevel,
|
||
|
trans2->out.pResp->WordCount));
|
||
|
trans2->out.pResp->WordCount--;
|
||
|
switch (pReq->InformationLevel) {
|
||
|
case SMB_INFO_ALLOCATION: {
|
||
|
FSALLOCATE Resp;
|
||
|
Resp.idFileSystem = 0;
|
||
|
Resp.cSectorUnit = fsattr.sectors_per_unit;
|
||
|
Resp.cbSector = (USHORT)fsattr.bytes_per_sector;
|
||
|
Resp.cUnit = (ULONG)fsattr.total_units;
|
||
|
Resp.cUnitAvail = (ULONG)fsattr.free_units;
|
||
|
SrvLog(("statfs %u %u\n", Resp.cUnit, Resp.cUnitAvail));
|
||
|
ADD_RESP_DATA(msg, trans2, &Resp, sizeof(FSALLOCATE));
|
||
|
return TRUE;
|
||
|
}
|
||
|
case SMB_INFO_VOLUME: {
|
||
|
FSINFO Resp;
|
||
|
const int maxlen = sizeof(Resp.vol.szVolLabel);
|
||
|
Resp.ulVsn = 0xFADB;
|
||
|
Resp.vol.cch = min(lstrlen(fsattr.fs_name), maxlen);
|
||
|
lstrcpyn(Resp.vol.szVolLabel, fsattr.fs_name, maxlen);
|
||
|
SrvLog(("statfs name %s %d %d, %d\n",
|
||
|
fsattr.fs_name, Resp.vol.cch,
|
||
|
sizeof(FSINFO), sizeof(*msg->out.smb)));
|
||
|
ADD_RESP_DATA(msg, trans2, &Resp, sizeof(FSINFO));
|
||
|
return TRUE;
|
||
|
}
|
||
|
case SMB_QUERY_FS_VOLUME_INFO: {
|
||
|
const int name_len = lstrlen(fsattr.fs_name);
|
||
|
const USHORT size = sizeof(FILE_FS_VOLUME_INFORMATION) + name_len + 2;
|
||
|
PFILE_FS_VOLUME_INFORMATION pResp =
|
||
|
(PFILE_FS_VOLUME_INFORMATION)xmalloc(size);
|
||
|
pResp->VolumeCreationTime.QuadPart = 0;
|
||
|
pResp->VolumeSerialNumber = 0xFEED;
|
||
|
pResp->VolumeLabelLength = name_len * sizeof(WCHAR);
|
||
|
// sprintf((char*)pResp->VolumeLabel, "%S", fsattr.fs_name);
|
||
|
strcpy((char *)pResp->VolumeLabel, fsattr.fs_name);
|
||
|
ADD_RESP_DATA(msg, trans2, pResp, size);
|
||
|
xfree(pResp);
|
||
|
return TRUE;
|
||
|
}
|
||
|
default:
|
||
|
SrvLogError(("DOSERROR: <COULD NOT UNDERSTAND INFO LEVEL>\n"));
|
||
|
SET_DOSERROR(msg, SERVER, NO_SUPPORT);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
Trans2Init()
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
InitializeCriticalSection(&dLock);
|
||
|
memset(DirTable, 0, sizeof(DirTable));
|
||
|
}
|
||
|
|
||
|
dm_t *
|
||
|
dm_alloc()
|
||
|
{
|
||
|
int i;
|
||
|
dm_t *dm;
|
||
|
|
||
|
dm = (dm_t *) malloc(sizeof(*dm));
|
||
|
if (dm == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
dm->handle = INVALID_HANDLE_VALUE;
|
||
|
dm->last = NULL;
|
||
|
|
||
|
EnterCriticalSection(&dLock);
|
||
|
for (i = 0; i < DirTableSz; i++) {
|
||
|
if (DirTable[i] == NULL) {
|
||
|
dm->Sid = (USHORT) i;
|
||
|
DirTable[i] = dm;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
LeaveCriticalSection(&dLock);
|
||
|
|
||
|
if (i == DirTableSz) {
|
||
|
free((char *) dm);
|
||
|
dm = NULL;
|
||
|
}
|
||
|
return dm;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
dm_init(dm_t *p, USHORT _info_level, USHORT _add_res_key)
|
||
|
{
|
||
|
|
||
|
p->info_level = _info_level;
|
||
|
p->add_res_key = _add_res_key;
|
||
|
p->base_size = p->add_res_key ? sizeof(ULONG):0;
|
||
|
|
||
|
switch (p->info_level) {
|
||
|
case SMB_INFO_STANDARD:
|
||
|
p->base_size += sizeof(SMB_FIND_BUFFER);
|
||
|
break;
|
||
|
case SMB_INFO_QUERY_EA_SIZE:
|
||
|
p->base_size += sizeof(SMB_FIND_BUFFER2);
|
||
|
break;
|
||
|
case SMB_INFO_QUERY_EAS_FROM_LIST:
|
||
|
case SMB_FIND_FILE_DIRECTORY_INFO:
|
||
|
case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
|
||
|
case SMB_FIND_FILE_NAMES_INFO:
|
||
|
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
|
||
|
default:
|
||
|
p->base_size = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
dm_free(dm_t *dm)
|
||
|
{
|
||
|
|
||
|
EnterCriticalSection(&dLock);
|
||
|
|
||
|
ASSERT(DirTable[dm->Sid] == dm);
|
||
|
|
||
|
DirTable[dm->Sid] = NULL;
|
||
|
LeaveCriticalSection(&dLock);
|
||
|
|
||
|
if (dm->last) {
|
||
|
free((char *) dm->last);
|
||
|
}
|
||
|
if (dm->handle != INVALID_HANDLE_VALUE) {
|
||
|
// printf("Closing srch hdl %x\n", dm->handle);
|
||
|
FindClose(dm->handle);
|
||
|
}
|
||
|
|
||
|
free((char *)dm);
|
||
|
}
|
||
|
|
||
|
dm_t *
|
||
|
dm_find(USHORT Sid)
|
||
|
{
|
||
|
dm_t *dm;
|
||
|
|
||
|
if (Sid >= DirTableSz) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// no need to get lock
|
||
|
dm = DirTable[Sid];
|
||
|
|
||
|
ASSERT(dm != NULL);
|
||
|
ASSERT(dm->Sid == Sid);
|
||
|
|
||
|
return dm;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
dm_close(USHORT Sid)
|
||
|
{
|
||
|
dm_t *dm;
|
||
|
|
||
|
dm = dm_find(Sid);
|
||
|
if (dm == NULL) {
|
||
|
return ERROR_INVALID_HANDLE;
|
||
|
}
|
||
|
dm_free(dm);
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
dm_addentry(dm_t *dm, void* p, WIN32_FIND_DATA *entry, USHORT name_len)
|
||
|
{
|
||
|
if (dm->add_res_key) {
|
||
|
PULONG pl = (PULONG)p;
|
||
|
*pl = dm->cookie;
|
||
|
pl++;
|
||
|
p = pl;
|
||
|
}
|
||
|
|
||
|
switch (dm->info_level) {
|
||
|
case SMB_INFO_STANDARD: {
|
||
|
PSMB_FIND_BUFFER pResp = (PSMB_FIND_BUFFER) p;
|
||
|
|
||
|
time64_to_smb_datetime((TIME64 *)&entry->ftCreationTime,
|
||
|
&pResp->CreationDate.Ushort,
|
||
|
&pResp->CreationTime.Ushort);
|
||
|
|
||
|
time64_to_smb_datetime((TIME64 *)&entry->ftLastAccessTime,
|
||
|
&pResp->LastAccessDate.Ushort,
|
||
|
&pResp->LastAccessTime.Ushort);
|
||
|
|
||
|
time64_to_smb_datetime((TIME64 *)&entry->ftLastWriteTime,
|
||
|
&pResp->LastWriteDate.Ushort,
|
||
|
&pResp->LastWriteTime.Ushort);
|
||
|
|
||
|
pResp->DataSize = entry->nFileSizeLow;
|
||
|
pResp->AllocationSize = pResp->DataSize;
|
||
|
pResp->Attributes = attribs_to_smb_attribs(entry->dwFileAttributes);
|
||
|
pResp->FileNameLength = (UCHAR) name_len;
|
||
|
RtlCopyMemory(pResp->FileName, entry->cFileName, name_len + 1);
|
||
|
return;
|
||
|
}
|
||
|
case SMB_INFO_QUERY_EA_SIZE: {
|
||
|
PSMB_FIND_BUFFER2 pResp = (PSMB_FIND_BUFFER2) p;
|
||
|
time64_to_smb_datetime((TIME64 *)&entry->ftCreationTime,
|
||
|
&pResp->CreationDate.Ushort,
|
||
|
&pResp->CreationTime.Ushort);
|
||
|
|
||
|
time64_to_smb_datetime((TIME64 *)&entry->ftLastAccessTime,
|
||
|
&pResp->LastAccessDate.Ushort,
|
||
|
&pResp->LastAccessTime.Ushort);
|
||
|
|
||
|
time64_to_smb_datetime((TIME64 *)&entry->ftLastWriteTime,
|
||
|
&pResp->LastWriteDate.Ushort,
|
||
|
&pResp->LastWriteTime.Ushort);
|
||
|
|
||
|
pResp->DataSize = entry->nFileSizeLow;
|
||
|
pResp->AllocationSize = pResp->DataSize;
|
||
|
pResp->Attributes = attribs_to_smb_attribs(entry->dwFileAttributes);
|
||
|
pResp->EaSize = 0;
|
||
|
pResp->FileNameLength = (UCHAR)name_len;
|
||
|
RtlCopyMemory(pResp->FileName, entry->cFileName, name_len + 1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
case SMB_INFO_QUERY_EAS_FROM_LIST:
|
||
|
case SMB_FIND_FILE_DIRECTORY_INFO:
|
||
|
case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
|
||
|
case SMB_FIND_FILE_NAMES_INFO:
|
||
|
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
|
||
|
default:
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
bad_info_level(
|
||
|
Packet_t * msg
|
||
|
)
|
||
|
{
|
||
|
SrvLogError(("DOSERROR: <COULD NOT UNDERSTAND INFO LEVEL>\n"));
|
||
|
return ERROR_INVALID_FUNCTION;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Trans2FindFirst2(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
PVOID fshdl;
|
||
|
USHORT tid;
|
||
|
USHORT uid;
|
||
|
PVOID fsctx;
|
||
|
FsDispatchTable* pDisp;
|
||
|
dm_t *dm;
|
||
|
WCHAR wfull_path[MAXPATH];
|
||
|
char *path, full_path[MAXPATH];
|
||
|
DWORD error;
|
||
|
WIN32_FIND_DATA entry;
|
||
|
PVOID d = 0;
|
||
|
|
||
|
PRESP_FIND_FIRST2 pResp;
|
||
|
PREQ_FIND_FIRST2 pReq;
|
||
|
|
||
|
if (msg == NULL || trans2 == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
tid = msg->in.smb->Tid;
|
||
|
uid = msg->in.smb->Uid;
|
||
|
fsctx = SRV_GET_FS_HANDLE(msg);
|
||
|
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
|
||
|
|
||
|
|
||
|
SET_REQ(pReq, PREQ_FIND_FIRST2, trans2);
|
||
|
|
||
|
if (!pDisp) {
|
||
|
SrvLogError(("DOSERROR: bad uid %d\n", uid));
|
||
|
SET_DOSERROR(msg, SERVER, BAD_UID);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dm = dm_alloc();
|
||
|
if (!dm) {
|
||
|
SrvLogError(("DOSERROR:dm_alloc failed\n"));
|
||
|
SET_WIN32ERROR(msg, ERROR_TOO_MANY_OPEN_FILES);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dm_init(dm, pReq->InformationLevel,
|
||
|
pReq->Flags & SMB_FIND_RETURN_RESUME_KEYS);
|
||
|
|
||
|
if (!dm->base_size) {
|
||
|
dm_free(dm);
|
||
|
SET_WIN32ERROR(msg, bad_info_level(msg));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
path = (char*)pReq->Buffer;
|
||
|
|
||
|
// todo: Instead of using findfirst(), read whole directory and
|
||
|
// store it locally in a temperary buffer. That way I don't have
|
||
|
// to deal with a handle failing in the middle. Or, ensure that all
|
||
|
// reads happen on a consistent local replica.
|
||
|
|
||
|
// build our path
|
||
|
pDisp->FsGetRoot(fshdl, wfull_path);
|
||
|
|
||
|
// convert to ascii
|
||
|
full_path[0] = '\0';
|
||
|
error = wcstombs(full_path, wfull_path, wcslen(wfull_path));
|
||
|
full_path[error] = '\0';
|
||
|
|
||
|
strcat(full_path, path);
|
||
|
|
||
|
pResp = (PRESP_FIND_FIRST2)
|
||
|
ADD_RESP_PARAMS(msg, trans2, 0, sizeof(RESP_FIND_FIRST2));
|
||
|
if (!pResp) {
|
||
|
SrvLogError(("DOSERROR: not enough buffer space...\n"));
|
||
|
SET_DOSERROR(msg, SERVER, ERROR);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dm->handle = FindFirstFile(full_path, &entry);
|
||
|
|
||
|
if (dm->handle == INVALID_HANDLE_VALUE) {
|
||
|
error = GetLastError();
|
||
|
SrvLogError(("DOSERROR: could not find filter in '%s' %d\n",full_path, error));
|
||
|
SET_DOSERROR(msg, SERVER, FILE_SPECS);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// entry number 0
|
||
|
dm->cookie = 0;
|
||
|
pResp->SearchCount = 0;
|
||
|
dm->last = &entry;
|
||
|
|
||
|
while (msg->out.size > msg->out.valid) {
|
||
|
DWORD name_len;
|
||
|
USHORT len;
|
||
|
|
||
|
len = dm->base_size + lstrlen(entry.cFileName);
|
||
|
if (len <= (msg->out.size - msg->out.valid)) {
|
||
|
d = ADD_RESP_DATA(msg, trans2, 0, len);
|
||
|
dm_addentry(dm, d, &entry, len - dm->base_size);
|
||
|
dm->cookie++;
|
||
|
pResp->SearchCount++;
|
||
|
if (FindNextFile(dm->handle, &entry) == 0) {
|
||
|
error = GetLastError();
|
||
|
dm->last = NULL;
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
// we are out of space
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dm->last != NULL) {
|
||
|
WIN32_FIND_DATA *p;
|
||
|
|
||
|
// we ran out of buffer space, we need to safe this entry in our dm
|
||
|
dm->last = NULL;
|
||
|
p = (WIN32_FIND_DATA *) malloc(sizeof(*p));
|
||
|
if (p != NULL) {
|
||
|
memcpy(p, &entry, sizeof(entry));
|
||
|
dm->last = p;
|
||
|
} else {
|
||
|
// todo: should return failure here
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// -- common --
|
||
|
pResp->EndOfSearch = (error == 18)?1:0;
|
||
|
pResp->LastNameOffset = (pResp->EndOfSearch)?(((USHORT)((char*)d -
|
||
|
(char*)msg->out.smb)) -
|
||
|
trans2->out.pResp->DataOffset):0;
|
||
|
pResp->EaErrorOffset = 0;
|
||
|
|
||
|
if ((pReq->Flags & SMB_FIND_CLOSE_AFTER_REQUEST) ||
|
||
|
((pReq->Flags & SMB_FIND_CLOSE_AT_EOS) && pResp->EndOfSearch)) {
|
||
|
pResp->Sid = 0xFFFF;
|
||
|
dm_free(dm);
|
||
|
} else {
|
||
|
pResp->Sid = dm->Sid;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Trans2FindNext2(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
PVOID fshdl;
|
||
|
USHORT tid;
|
||
|
USHORT uid;
|
||
|
PVOID fsctx;
|
||
|
FsDispatchTable* pDisp;
|
||
|
DWORD error;
|
||
|
dm_t *dm;
|
||
|
PVOID d;
|
||
|
|
||
|
PRESP_FIND_NEXT2 pResp;
|
||
|
PREQ_FIND_NEXT2 pReq;
|
||
|
|
||
|
if (msg == NULL || trans2 == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
tid = msg->in.smb->Tid;
|
||
|
uid = msg->in.smb->Uid;
|
||
|
fsctx = SRV_GET_FS_HANDLE(msg);
|
||
|
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
|
||
|
|
||
|
SET_REQ(pReq, PREQ_FIND_NEXT2, trans2);
|
||
|
|
||
|
if (!pDisp) {
|
||
|
SrvLogError(("DOSERROR: bad uid %d\n", uid));
|
||
|
SET_DOSERROR(msg, SERVER, BAD_UID);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dm = dm_find(pReq->Sid);
|
||
|
if (dm == NULL) {
|
||
|
SrvLogError(("DOSERROR: could not find sid\n"));
|
||
|
SET_DOSERROR(msg, DOS, BAD_FID);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dm_init(dm, pReq->InformationLevel,
|
||
|
pReq->Flags & SMB_FIND_RETURN_RESUME_KEYS);
|
||
|
|
||
|
if (!dm->base_size) {
|
||
|
SET_WIN32ERROR(msg, bad_info_level(msg));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pResp = (PRESP_FIND_NEXT2)
|
||
|
ADD_RESP_PARAMS(msg, trans2, 0, sizeof(RESP_FIND_NEXT2));
|
||
|
if (!pResp) {
|
||
|
SrvLogError(("DOSERROR: not enough buffer space...\n"));
|
||
|
SET_DOSERROR(msg, SERVER, ERROR);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (!(pReq->Flags & SMB_FIND_CONTINUE_FROM_LAST))
|
||
|
dm->cookie = pReq->ResumeKey;
|
||
|
|
||
|
pResp->SearchCount = 0;
|
||
|
while (msg->out.size > msg->out.valid) {
|
||
|
if (dm->last) {
|
||
|
USHORT len;
|
||
|
|
||
|
len = lstrlen(dm->last->cFileName) + dm->base_size;
|
||
|
if (len <= (msg->out.size - msg->out.valid)) {
|
||
|
d = ADD_RESP_DATA(msg, trans2, 0, len);
|
||
|
dm_addentry(dm, d, dm->last, len - dm->base_size);
|
||
|
dm->cookie++;
|
||
|
pResp->SearchCount++;
|
||
|
} else {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FindNextFile(dm->handle, dm->last) == 0) {
|
||
|
error = GetLastError();
|
||
|
free((char *)dm->last);
|
||
|
dm->last = NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// -- common --
|
||
|
pResp->EndOfSearch = (error == 18)?1:0;
|
||
|
pResp->LastNameOffset = (pResp->EndOfSearch)?(((USHORT)((char*)d -
|
||
|
(char*)msg->out.smb)) -
|
||
|
trans2->out.pResp->DataOffset):0;
|
||
|
pResp->EaErrorOffset = 0;
|
||
|
|
||
|
if (pResp->EndOfSearch) {
|
||
|
dm_free(dm);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Trans2QueryPathInfo(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
PVOID fshdl;
|
||
|
USHORT tid;
|
||
|
USHORT uid;
|
||
|
PVOID fsctx;
|
||
|
FsDispatchTable* pDisp;
|
||
|
PREQ_QUERY_PATH_INFORMATION pReq;
|
||
|
PCHAR file_name;
|
||
|
LPWSTR name;
|
||
|
int name_len;
|
||
|
DWORD error;
|
||
|
fattr_t attribs;
|
||
|
|
||
|
if (msg == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
tid = msg->in.smb->Tid;
|
||
|
uid = msg->in.smb->Uid;
|
||
|
fsctx = SRV_GET_FS_HANDLE(msg);
|
||
|
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
|
||
|
|
||
|
SET_REQ(pReq, PREQ_QUERY_PATH_INFORMATION, trans2);
|
||
|
|
||
|
if (!pDisp) {
|
||
|
SrvLogError(("Srv: no such uid\n"));
|
||
|
SET_DOSERROR(msg, SERVER, BAD_UID);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
file_name = (PCHAR)pReq->Buffer;
|
||
|
|
||
|
// convert to unicode
|
||
|
SRV_ASCII_TO_WCHAR(name, name_len, file_name, lstrlen(file_name));
|
||
|
if (name != NULL)
|
||
|
error = pDisp->FsLookup(fshdl, name, (USHORT) name_len, &attribs);
|
||
|
else
|
||
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
SRV_ASCII_FREE(name);
|
||
|
if (error) {
|
||
|
SrvLogError(("Srv: lookup error 0x%08X\n", error));
|
||
|
SET_WIN32ERROR(msg, error);
|
||
|
ADD_RESP_DATA(msg, trans2, NULL, 0);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
switch(pReq->InformationLevel) {
|
||
|
case SMB_INFO_STANDARD: {
|
||
|
USHORT len = sizeof(SMB_FIND_BUFFER) - sizeof(UCHAR) - sizeof(CHAR);
|
||
|
PSMB_FIND_BUFFER pResp = (PSMB_FIND_BUFFER) xmalloc(len);
|
||
|
if (pResp == NULL) {
|
||
|
SET_WIN32ERROR(msg, ERROR_NOT_ENOUGH_MEMORY);
|
||
|
ADD_RESP_DATA(msg, trans2, NULL, 0);
|
||
|
return FALSE;
|
||
|
}
|
||
|
time64_to_smb_datetime(&attribs.create_time,
|
||
|
&pResp->CreationDate.Ushort,
|
||
|
&pResp->CreationTime.Ushort);
|
||
|
time64_to_smb_datetime(&attribs.access_time,
|
||
|
&pResp->LastAccessDate.Ushort,
|
||
|
&pResp->LastAccessTime.Ushort);
|
||
|
time64_to_smb_datetime(&attribs.mod_time,
|
||
|
&pResp->LastWriteDate.Ushort,
|
||
|
&pResp->LastWriteTime.Ushort);
|
||
|
pResp->DataSize = (ULONG)attribs.file_size;
|
||
|
pResp->AllocationSize = (ULONG)attribs.alloc_size;
|
||
|
pResp->Attributes = attribs_to_smb_attribs(attribs.attributes);
|
||
|
ADD_RESP_DATA(msg, trans2, pResp, len);
|
||
|
xfree(pResp);
|
||
|
return TRUE;
|
||
|
}
|
||
|
case SMB_INFO_QUERY_EA_SIZE: {
|
||
|
USHORT len = sizeof(SMB_FIND_BUFFER2) - sizeof(UCHAR) - sizeof(CHAR);
|
||
|
PSMB_FIND_BUFFER2 pResp = (PSMB_FIND_BUFFER2) xmalloc(len);
|
||
|
if (pResp == NULL) {
|
||
|
SET_WIN32ERROR(msg, ERROR_NOT_ENOUGH_MEMORY);
|
||
|
ADD_RESP_DATA(msg, trans2, NULL, 0);
|
||
|
return FALSE;
|
||
|
}
|
||
|
time64_to_smb_datetime(&attribs.create_time,
|
||
|
&pResp->CreationDate.Ushort,
|
||
|
&pResp->CreationTime.Ushort);
|
||
|
time64_to_smb_datetime(&attribs.access_time,
|
||
|
&pResp->LastAccessDate.Ushort,
|
||
|
&pResp->LastAccessTime.Ushort);
|
||
|
time64_to_smb_datetime(&attribs.mod_time,
|
||
|
&pResp->LastWriteDate.Ushort,
|
||
|
&pResp->LastWriteTime.Ushort);
|
||
|
pResp->DataSize = (ULONG)attribs.file_size;
|
||
|
pResp->AllocationSize = (ULONG)attribs.alloc_size;
|
||
|
pResp->Attributes = attribs_to_smb_attribs(attribs.attributes);
|
||
|
pResp->EaSize = 0;
|
||
|
ADD_RESP_DATA(msg, trans2, pResp, len);
|
||
|
xfree(pResp);
|
||
|
return TRUE;
|
||
|
}
|
||
|
case SMB_INFO_QUERY_EAS_FROM_LIST:
|
||
|
case SMB_FIND_FILE_DIRECTORY_INFO:
|
||
|
case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
|
||
|
case SMB_FIND_FILE_NAMES_INFO:
|
||
|
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
|
||
|
default: {
|
||
|
SrvLogError(("Srv: unsupported info level %d>\n"
|
||
|
,pReq->InformationLevel));
|
||
|
SET_DOSERROR(msg, SERVER, NO_SUPPORT);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Trans2SetPathInfo(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
return Trans2Unknown(msg, trans2);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Trans2QueryFileInfo(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
return Trans2Unknown(msg, trans2);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Trans2SetFileInfo(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
return Trans2Unknown(msg, trans2);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Trans2GetDfsReferral(
|
||
|
Packet_t * msg,
|
||
|
Trans2_t * trans2
|
||
|
)
|
||
|
{
|
||
|
return Trans2Unknown(msg, trans2);
|
||
|
}
|
||
|
|
||
|
|