From f598bca687b54577ddc19cfaf0807b8d18298e5a Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Sun, 7 Aug 2011 19:24:29 +0800 Subject: [PATCH] rdpdr/disk: add query directory irp processing. --- channels/rdpdr/disk/disk_file.c | 134 ++++++++++++++++++++++++++++++-- channels/rdpdr/disk/disk_file.h | 3 +- channels/rdpdr/disk/disk_main.c | 61 +++++++++++++++ 3 files changed, 189 insertions(+), 9 deletions(-) diff --git a/channels/rdpdr/disk/disk_file.c b/channels/rdpdr/disk/disk_file.c index 3fad16acc..32b03d237 100644 --- a/channels/rdpdr/disk/disk_file.c +++ b/channels/rdpdr/disk/disk_file.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -247,7 +246,6 @@ void disk_file_free(DISK_FILE* file) } xfree(file->fullpath); - xfree(file->pattern); xfree(file); } @@ -309,26 +307,26 @@ boolean disk_file_query_information(DISK_FILE* file, uint32 FsInformationClass, { case FileBasicInformation: /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */ - stream_write_uint32(output, 40); /* Length */ - stream_check_size(output, 40); + stream_write_uint32(output, 36); /* Length */ + stream_check_size(output, 36); stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */ stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */ stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */ stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */ stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ - stream_write_uint32(output, 0); /* Reserved */ + /* Reserved(4), MUST NOT be added! */ break; case FileStandardInformation: /* http://msdn.microsoft.com/en-us/library/cc232088.aspx */ - stream_write_uint32(output, 24); /* Length */ - stream_check_size(output, 24); + stream_write_uint32(output, 22); /* Length */ + stream_check_size(output, 22); stream_write_uint64(output, st.st_size); /* AllocationSize */ stream_write_uint64(output, st.st_size); /* EndOfFile */ stream_write_uint32(output, st.st_nlink); /* NumberOfLinks */ stream_write_uint8(output, file->delete_pending ? 1 : 0); /* DeletePending */ stream_write_uint8(output, file->is_dir ? 1 : 0); /* Directory */ - stream_write_uint16(output, 0); /* Reserved */ + /* Reserved(2), MUST NOT be added! */ break; case FileAttributeTagInformation: @@ -346,3 +344,123 @@ boolean disk_file_query_information(DISK_FILE* file, uint32 FsInformationClass, } return True; } + +boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, uint8 InitialQuery, + const char* path, STREAM* output) +{ + struct dirent* ent; + char* ent_path; + struct stat st; + UNICONV* uniconv; + size_t len; + boolean ret; + + DEBUG_SVC("path %s FsInformationClass %d", path, FsInformationClass); + + if (InitialQuery != 0) + { + rewinddir(file->dir); + } + + ent = readdir(file->dir); + if (ent == NULL) + { + stream_write_uint32(output, 0); /* Length */ + stream_write_uint8(output, 0); /* Padding */ + return False; + } + + memset(&st, 0, sizeof(struct stat)); + ent_path = xmalloc(strlen(file->fullpath) + strlen(ent->d_name) + 2); + sprintf(ent_path, "%s/%s", file->fullpath, ent->d_name); + if (stat(ent_path, &st) != 0) + { + DEBUG_WARN("stat %s failed.", ent_path); + } + xfree(ent_path); + + uniconv = freerdp_uniconv_new(); + ent_path = freerdp_uniconv_out(uniconv, ent->d_name, &len); + freerdp_uniconv_free(uniconv); + + ret = True; + switch (FsInformationClass) + { + case FileDirectoryInformation: + /* http://msdn.microsoft.com/en-us/library/cc232097.aspx */ + stream_write_uint32(output, 64 + len); /* Length */ + stream_check_size(output, 64 + len); + stream_write_uint32(output, 0); /* NextEntryOffset */ + stream_write_uint32(output, 0); /* FileIndex */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */ + stream_write_uint64(output, st.st_size); /* EndOfFile */ + stream_write_uint64(output, st.st_size); /* AllocationSize */ + stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ + stream_write_uint32(output, len); /* FileNameLength */ + stream_write(output, ent_path, len); + break; + + case FileFullDirectoryInformation: + /* http://msdn.microsoft.com/en-us/library/cc232068.aspx */ + stream_write_uint32(output, 68 + len); /* Length */ + stream_check_size(output, 68 + len); + stream_write_uint32(output, 0); /* NextEntryOffset */ + stream_write_uint32(output, 0); /* FileIndex */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */ + stream_write_uint64(output, st.st_size); /* EndOfFile */ + stream_write_uint64(output, st.st_size); /* AllocationSize */ + stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ + stream_write_uint32(output, len); /* FileNameLength */ + stream_write_uint32(output, 0); /* EaSize */ + stream_write(output, ent_path, len); + break; + + case FileBothDirectoryInformation: + /* http://msdn.microsoft.com/en-us/library/cc232095.aspx */ + stream_write_uint32(output, 93 + len); /* Length */ + stream_check_size(output, 93 + len); + stream_write_uint32(output, 0); /* NextEntryOffset */ + stream_write_uint32(output, 0); /* FileIndex */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */ + stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */ + stream_write_uint64(output, st.st_size); /* EndOfFile */ + stream_write_uint64(output, st.st_size); /* AllocationSize */ + stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ + stream_write_uint32(output, len); /* FileNameLength */ + stream_write_uint32(output, 0); /* EaSize */ + stream_write_uint8(output, 0); /* ShortNameLength */ + /* Reserved(1), MUST NOT be added! */ + stream_write_zero(output, 24); /* ShortName */ + stream_write(output, ent_path, len); + break; + + case FileNamesInformation: + /* http://msdn.microsoft.com/en-us/library/cc232077.aspx */ + stream_write_uint32(output, 12 + len); /* Length */ + stream_check_size(output, 12 + len); + stream_write_uint32(output, 0); /* NextEntryOffset */ + stream_write_uint32(output, 0); /* FileIndex */ + stream_write_uint32(output, len); /* FileNameLength */ + stream_write(output, ent_path, len); + break; + + default: + stream_write_uint32(output, 0); /* Length */ + stream_write_uint8(output, 0); /* Padding */ + DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass); + ret = False; + break; + } + + xfree(ent_path); + + return ret; +} diff --git a/channels/rdpdr/disk/disk_file.h b/channels/rdpdr/disk/disk_file.h index 8441647e9..1ba1fc1b3 100644 --- a/channels/rdpdr/disk/disk_file.h +++ b/channels/rdpdr/disk/disk_file.h @@ -34,7 +34,6 @@ struct _DISK_FILE DIR* dir; char* fullpath; char* filename; - char* pattern; boolean delete_pending; }; @@ -46,5 +45,7 @@ boolean disk_file_seek(DISK_FILE* file, uint64 Offset); boolean disk_file_read(DISK_FILE* file, uint8* buffer, uint32* Length); boolean disk_file_write(DISK_FILE* file, uint8* buffer, uint32 Length); boolean disk_file_query_information(DISK_FILE* file, uint32 FsInformationClass, STREAM* output); +boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, uint8 InitialQuery, + const char* path, STREAM* output); #endif /* __DISK_FILE_H */ diff --git a/channels/rdpdr/disk/disk_main.c b/channels/rdpdr/disk/disk_main.c index 162a97bef..86dacc713 100644 --- a/channels/rdpdr/disk/disk_main.c +++ b/channels/rdpdr/disk/disk_main.c @@ -352,6 +352,63 @@ static void disk_process_irp_query_volume_information(DISK_DEVICE* disk, IRP* ir irp->Complete(irp); } +static void disk_process_irp_query_directory(DISK_DEVICE* disk, IRP* irp) +{ + DISK_FILE* file; + uint32 FsInformationClass; + uint8 InitialQuery; + uint32 PathLength; + UNICONV* uniconv; + char* path; + + stream_read_uint32(irp->input, FsInformationClass); + stream_read_uint8(irp->input, InitialQuery); + stream_read_uint32(irp->input, PathLength); + stream_seek(irp->input, 23); /* Padding */ + + uniconv = freerdp_uniconv_new(); + path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength); + freerdp_uniconv_free(uniconv); + + file = disk_get_file_by_id(disk, irp->FileId); + + if (file == NULL) + { + irp->IoStatus = STATUS_UNSUCCESSFUL; + stream_write_uint32(irp->output, 0); /* Length */ + DEBUG_WARN("FileId %d not valid.", irp->FileId); + } + else if (!disk_file_query_directory(file, FsInformationClass, InitialQuery, path, irp->output)) + { + irp->IoStatus = STATUS_NO_MORE_FILES; + } + + xfree(path); + + irp->Complete(irp); +} + +static void disk_process_irp_directory_control(DISK_DEVICE* disk, IRP* irp) +{ + switch (irp->MinorFunction) + { + case IRP_MN_QUERY_DIRECTORY: + disk_process_irp_query_directory(disk, irp); + break; + + case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* TODO */ + irp->Discard(irp); + break; + + default: + DEBUG_WARN("MinorFunction 0x%X not supported", irp->MinorFunction); + irp->IoStatus = STATUS_NOT_SUPPORTED; + stream_write_uint32(irp->output, 0); /* Length */ + irp->Complete(irp); + break; + } +} + static void disk_process_irp(DISK_DEVICE* disk, IRP* irp) { switch (irp->MajorFunction) @@ -380,6 +437,10 @@ static void disk_process_irp(DISK_DEVICE* disk, IRP* irp) disk_process_irp_query_volume_information(disk, irp); break; + case IRP_MJ_DIRECTORY_CONTROL: + disk_process_irp_directory_control(disk, irp); + break; + default: DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction); irp->IoStatus = STATUS_NOT_SUPPORTED;