static uint32 disk_write(IRP * irp) { FILE_INFO * finfo; ssize_t r; uint32 len; LLOGLN(10, ("disk_write: id=%d len=%d off=%lld", irp->fileID, irp->inputBufferLength, irp->offset)); finfo = disk_get_file_info(irp->dev, irp->fileID); if (finfo == NULL) { LLOGLN(0, ("disk_read: invalid file id")); return RD_STATUS_INVALID_HANDLE; } if (finfo->is_dir) return RD_STATUS_FILE_IS_A_DIRECTORY; if (finfo->file == -1) return RD_STATUS_INVALID_HANDLE; if (lseek(finfo->file, irp->offset, SEEK_SET) == (off_t) - 1) return get_error_status(); len = 0; while (len < irp->inputBufferLength) { r = write(finfo->file, irp->inputBuffer, irp->inputBufferLength); if (r == -1) { return get_error_status(); } len += r; } return RD_STATUS_SUCCESS; }
static uint32 disk_read(IRP * irp) { FILE_INFO * finfo; char * buf; ssize_t r; LLOGLN(10, ("disk_read: id=%d len=%d off=%lld", irp->fileID, irp->length, irp->offset)); finfo = disk_get_file_info(irp->dev, irp->fileID); if (finfo == NULL) { LLOGLN(0, ("disk_read: invalid file id")); return RD_STATUS_INVALID_HANDLE; } if (finfo->is_dir) return RD_STATUS_FILE_IS_A_DIRECTORY; if (finfo->file == -1) return RD_STATUS_INVALID_HANDLE; if (lseek(finfo->file, irp->offset, SEEK_SET) == (off_t) - 1) return get_error_status(); buf = malloc(irp->length); memset(buf, 0, irp->length); r = read(finfo->file, buf, irp->length); if (r == -1) { free(buf); return get_error_status(); } else { irp->outputBuffer = buf; irp->outputBufferLength = r; return RD_STATUS_SUCCESS; } }
static uint32 disk_query_directory(IRP * irp, uint8 initialQuery, const char * path) { DISK_DEVICE_INFO * info; FILE_INFO * finfo; char * p; uint32 status; char * buf; int size; int len; struct dirent * pdirent; struct stat file_stat; uint32 attr; LLOGLN(10, ("disk_query_directory: class=%d id=%d init=%d path=%s", irp->infoClass, irp->fileID, initialQuery, path)); finfo = disk_get_file_info(irp->dev, irp->fileID); if (finfo == NULL || finfo->dir == NULL) { LLOGLN(0, ("disk_query_directory: invalid file id")); return RD_STATUS_INVALID_HANDLE; } info = (DISK_DEVICE_INFO *) irp->dev->info; if (initialQuery) { if (finfo->pattern) free(finfo->pattern); p = strrchr(path, '\\'); p = (p ? p + 1 : (char *)path); finfo->pattern = malloc(strlen(p) + 1); strcpy(finfo->pattern, p); rewinddir(finfo->dir); } status = RD_STATUS_SUCCESS; buf = NULL; size = 0; pdirent = readdir(finfo->dir); while (pdirent && finfo->pattern[0] && fnmatch(finfo->pattern, pdirent->d_name, 0) != 0) pdirent = readdir(finfo->dir); if (pdirent == NULL) { return RD_STATUS_NO_MORE_FILES; } memset(&file_stat, 0, sizeof(struct stat)); p = malloc(strlen(finfo->fullpath) + strlen(pdirent->d_name) + 2); sprintf(p, "%s/%s", finfo->fullpath, pdirent->d_name); if (stat(p, &file_stat) != 0) { LLOGLN(0, ("disk_query_directory: stat %s failed (%i)\n", p, errno)); } free(p); attr = get_file_attribute(pdirent->d_name, &file_stat); switch (irp->infoClass) { case FileBothDirectoryInformation: size = 93 + strlen(pdirent->d_name) * 2; buf = malloc(size); memset(buf, 0, size); SET_UINT32(buf, 0, 0); /* NextEntryOffset */ SET_UINT32(buf, 4, 0); /* FileIndex */ SET_UINT64(buf, 8, get_rdp_filetime(file_stat.st_ctime < file_stat.st_mtime ? file_stat.st_ctime : file_stat.st_mtime)); /* CreationTime */ SET_UINT64(buf, 16, get_rdp_filetime(file_stat.st_atime)); /* LastAccessTime */ SET_UINT64(buf, 24, get_rdp_filetime(file_stat.st_mtime)); /* LastWriteTime */ SET_UINT64(buf, 32, get_rdp_filetime(file_stat.st_ctime)); /* ChangeTime */ SET_UINT64(buf, 40, file_stat.st_size); /* EndOfFile */ SET_UINT64(buf, 48, file_stat.st_size); /* AllocationSize */ SET_UINT32(buf, 56, attr); /* FileAttributes */ SET_UINT32(buf, 64, 0); /* EaSize */ SET_UINT8(buf, 68, 0); /* ShortNameLength */ /* [MS-FSCC] has one byte padding here but RDP does not! */ //SET_UINT8(buf, 69, 0); /* Reserved */ /* ShortName 24 bytes */ len = freerdp_set_wstr(buf + 93, size - 93, pdirent->d_name, strlen(pdirent->d_name)); SET_UINT32(buf, 60, len); /* FileNameLength */ size = 93 + len; break; case FileFullDirectoryInformation: size = 68 + strlen(pdirent->d_name) * 2; buf = malloc(size); memset(buf, 0, size); SET_UINT32(buf, 0, 0); /* NextEntryOffset */ SET_UINT32(buf, 4, 0); /* FileIndex */ SET_UINT64(buf, 8, get_rdp_filetime(file_stat.st_ctime < file_stat.st_mtime ? file_stat.st_ctime : file_stat.st_mtime)); /* CreationTime */ SET_UINT64(buf, 16, get_rdp_filetime(file_stat.st_atime)); /* LastAccessTime */ SET_UINT64(buf, 24, get_rdp_filetime(file_stat.st_mtime)); /* LastWriteTime */ SET_UINT64(buf, 32, get_rdp_filetime(file_stat.st_ctime)); /* ChangeTime */ SET_UINT64(buf, 40, file_stat.st_size); /* EndOfFile */ SET_UINT64(buf, 48, file_stat.st_size); /* AllocationSize */ SET_UINT32(buf, 56, attr); /* FileAttributes */ SET_UINT32(buf, 64, 0); /* EaSize */ len = freerdp_set_wstr(buf + 68, size - 68, pdirent->d_name, strlen(pdirent->d_name)); SET_UINT32(buf, 60, len); /* FileNameLength */ size = 68 + len; break; default: LLOGLN(0, ("disk_query_directory: invalid info class")); status = RD_STATUS_NOT_SUPPORTED; break; } irp->outputBuffer = buf; irp->outputBufferLength = size; return status; }
static uint32 disk_set_info(IRP * irp) { FILE_INFO *finfo; uint32 status; uint64 len; char * buf; int size; char * fullpath; struct stat file_stat; struct utimbuf tvs; int mode; uint32 attr; time_t t; LLOGLN(10, ("disk_set_info: class=%d id=%d", irp->infoClass, irp->fileID)); finfo = disk_get_file_info(irp->dev, irp->fileID); if (finfo == NULL) { LLOGLN(0, ("disk_set_info: invalid file id")); return RD_STATUS_INVALID_HANDLE; } status = RD_STATUS_SUCCESS; switch (irp->infoClass) { case FileBasicInformation: if (stat(finfo->fullpath, &file_stat) != 0) return get_error_status(); /* Change file time */ tvs.actime = file_stat.st_atime; tvs.modtime = file_stat.st_mtime; t = get_system_filetime(GET_UINT64(irp->inputBuffer, 8)); /* LastAccessTime */ if (t > 0) tvs.actime = t; t = get_system_filetime(GET_UINT64(irp->inputBuffer, 16)); /* LastWriteTime */ if (t > 0) tvs.modtime = t; utime(finfo->fullpath, &tvs); /* Change read-only flag */ attr = GET_UINT32(irp->inputBuffer, 32); if (attr == 0) break; mode = file_stat.st_mode; if (attr & FILE_ATTRIBUTE_READONLY) mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); else mode |= S_IWUSR; mode &= 0777; chmod(finfo->fullpath, mode); break; case FileEndOfFileInformation: case FileAllocationInformation: len = GET_UINT64(irp->inputBuffer, 0); set_file_size(finfo->file, len); break; case FileDispositionInformation: /* Delete on close */ finfo->delete_pending = 1; break; case FileRenameInformation: //replaceIfExists = GET_UINT8(irp->inputBuffer, 0); /* ReplaceIfExists */ //rootDirectory = GET_UINT8(irp->inputBuffer, 1); /* RootDirectory */ len = GET_UINT32(irp->inputBuffer, 2); size = len * 2; buf = malloc(size); memset(buf, 0, size); freerdp_get_wstr(buf, size, irp->inputBuffer + 6, len); fullpath = disk_get_fullpath(irp->dev, buf); free(buf); LLOGLN(10, ("disk_set_info: rename %s to %s", finfo->fullpath, fullpath)); if (rename(finfo->fullpath, fullpath) == 0) { free(finfo->fullpath); finfo->fullpath = fullpath; } else { free(fullpath); return get_error_status(); } break; default: LLOGLN(0, ("disk_set_info: invalid info class")); status = RD_STATUS_NOT_SUPPORTED; break; } return status; }
static uint32 disk_query_info(IRP * irp) { FILE_INFO *finfo; uint32 status; int size; char * buf; LLOGLN(10, ("disk_query_info: class=%d id=%d", irp->infoClass, irp->fileID)); finfo = disk_get_file_info(irp->dev, irp->fileID); if (finfo == NULL) { LLOGLN(0, ("disk_query_info: invalid file id")); return RD_STATUS_INVALID_HANDLE; } size = 256; buf = malloc(size); memset(buf, 0, size); status = RD_STATUS_SUCCESS; switch (irp->infoClass) { case FileBasicInformation: SET_UINT64(buf, 0, get_rdp_filetime(finfo->file_stat.st_ctime < finfo->file_stat.st_mtime ? finfo->file_stat.st_ctime : finfo->file_stat.st_mtime)); /* CreationTime */ SET_UINT64(buf, 8, get_rdp_filetime(finfo->file_stat.st_atime)); /* LastAccessTime */ SET_UINT64(buf, 16, get_rdp_filetime(finfo->file_stat.st_mtime)); /* LastWriteTime */ SET_UINT64(buf, 24, get_rdp_filetime(finfo->file_stat.st_ctime)); /* ChangeTime */ SET_UINT32(buf, 32, finfo->file_attr); /* FileAttributes */ size = 36; break; case FileStandardInformation: SET_UINT64(buf, 0, finfo->file_stat.st_size); /* AllocationSize */ SET_UINT64(buf, 8, finfo->file_stat.st_size); /* EndOfFile */ SET_UINT32(buf, 16, finfo->file_stat.st_nlink); /* NumberOfLinks */ SET_UINT8(buf, 20, 0); /* DeletePending */ SET_UINT8(buf, 21, finfo->is_dir); /* Directory */ size = 22; break; case FileObjectIdInformation: SET_UINT32(buf, 0, finfo->file_attr); /* FileAttributes */ SET_UINT32(buf, 4, 0); /* ReparseTag */ size = 8; break; default: LLOGLN(0, ("disk_query_info: invalid info class")); size = 0; status = RD_STATUS_NOT_SUPPORTED; break; } irp->outputBuffer = buf; irp->outputBufferLength = size; return status; }
static uint32 disk_query_volume_info(IRP * irp) { FILE_INFO * finfo; struct STATFS_T stat_fs; uint32 status; int size; char * buf; int len; LLOGLN(10, ("disk_query_volume_info: class=%d id=%d", irp->infoClass, irp->fileID)); finfo = disk_get_file_info(irp->dev, irp->fileID); if (finfo == NULL) { LLOGLN(0, ("disk_query_volume_info: invalid file id")); return RD_STATUS_INVALID_HANDLE; } if (STATFS_FN(finfo->fullpath, &stat_fs) != 0) { LLOGLN(0, ("disk_query_volume_info: statfs failed")); return RD_STATUS_ACCESS_DENIED; } size = 0; buf = NULL; status = RD_STATUS_SUCCESS; switch (irp->infoClass) { case FileFsVolumeInformation: buf = malloc(256); memset(buf, 0, 256); SET_UINT64(buf, 0, 0); /* VolumeCreationTime */ SET_UINT32(buf, 8, 0); /* VolumeSerialNumber */ len = freerdp_set_wstr(buf + 17, size - 17, "FREERDP", strlen("FREERDP") + 1); SET_UINT32(buf, 12, len); /* VolumeLabelLength */ SET_UINT8(buf, 16, 0); /* SupportsObjects */ size = 17 + len; break; case FileFsSizeInformation: size = 24; buf = malloc(size); memset(buf, 0, size); SET_UINT64(buf, 0, stat_fs.f_blocks); /* TotalAllocationUnits */ SET_UINT64(buf, 8, stat_fs.f_bfree); /* AvailableAllocationUnits */ SET_UINT32(buf, 16, stat_fs.f_bsize / 0x200); /* SectorsPerAllocationUnit */ SET_UINT32(buf, 20, 0x200); /* BytesPerSector */ break; case FileFsAttributeInformation: buf = malloc(256); memset(buf, 0, 256); SET_UINT32(buf, 0, FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK); /* FileSystemAttributes */ SET_UINT32(buf, 4, F_NAMELEN(stat_fs)); /* MaximumComponentNameLength */ len = freerdp_set_wstr(buf + 12, 256 - 12, "FREERDP", 8); SET_UINT32(buf, 8, len); /* FileSystemNameLength */ size = 12 + len; break; case FileFsFullSizeInformation: size = 32; buf = malloc(size); memset(buf, 0, size); SET_UINT64(buf, 0, stat_fs.f_blocks); /* TotalAllocationUnits */ SET_UINT64(buf, 8, stat_fs.f_bfree); /* CallerAvailableAllocationUnits */ SET_UINT64(buf, 16, stat_fs.f_bfree); /* ActualAvailableAllocationUnits */ SET_UINT32(buf, 24, stat_fs.f_bsize / 0x200); /* SectorsPerAllocationUnit */ SET_UINT32(buf, 28, 0x200); /* BytesPerSector */ break; case FileFsDeviceInformation: size = 8; buf = malloc(size); memset(buf, 0, size); SET_UINT32(buf, 0, FILE_DEVICE_DISK); /* DeviceType */ SET_UINT32(buf, 4, 0); /* BytesPerSector */ break; default: LLOGLN(0, ("disk_query_volume_info: invalid info class")); status = RD_STATUS_NOT_SUPPORTED; break; } irp->outputBuffer = buf; irp->outputBufferLength = size; return status; }
static int disk_get_fd(IRP * irp) { FILE_INFO * finfo = disk_get_file_info(irp->dev, irp->fileID); return finfo->file; }