📄 disk.c
字号:
{ perror("stat"); out_uint8(out, 0); return STATUS_ACCESS_DENIED; } /* Set file attributes */ file_attributes = 0; if (S_ISDIR(filestat.st_mode)) file_attributes |= FILE_ATTRIBUTE_DIRECTORY; filename = 1 + strrchr(path, '/'); if (filename && filename[0] == '.') file_attributes |= FILE_ATTRIBUTE_HIDDEN; if (!file_attributes) file_attributes |= FILE_ATTRIBUTE_NORMAL; if (!(filestat.st_mode & S_IWUSR)) file_attributes |= FILE_ATTRIBUTE_READONLY; /* Return requested data */ switch (info_class) { case FileBasicInformation: seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low); out_uint32_le(out, ft_low); /* create_access_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_access_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_write_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_change_time */ out_uint32_le(out, ft_high); out_uint32_le(out, file_attributes); break; case FileStandardInformation: out_uint32_le(out, filestat.st_size); /* Allocation size */ out_uint32_le(out, 0); out_uint32_le(out, filestat.st_size); /* End of file */ out_uint32_le(out, 0); out_uint32_le(out, filestat.st_nlink); /* Number of links */ out_uint8(out, 0); /* Delete pending */ out_uint8(out, S_ISDIR(filestat.st_mode) ? 1 : 0); /* Directory */ break; case FileObjectIdInformation: out_uint32_le(out, file_attributes); /* File Attributes */ out_uint32_le(out, 0); /* Reparse Tag */ break; default: unimpl("IRP Query (File) Information class: 0x%x\n", info_class); return STATUS_INVALID_PARAMETER; } return STATUS_SUCCESS;}NTSTATUSdisk_set_information(NTHANDLE handle, uint32 info_class, STREAM in, STREAM out){ uint32 length, file_attributes, ft_high, ft_low, delete_on_close; char newname[PATH_MAX], fullpath[PATH_MAX]; struct fileinfo *pfinfo; int mode; struct stat filestat; time_t write_time, change_time, access_time, mod_time; struct utimbuf tvs; struct STATFS_T stat_fs; pfinfo = &(g_fileinfo[handle]); g_notify_stamp = True; switch (info_class) { case FileBasicInformation: write_time = change_time = access_time = 0; in_uint8s(in, 4); /* Handle of root dir? */ in_uint8s(in, 24); /* unknown */ /* CreationTime */ in_uint32_le(in, ft_low); in_uint32_le(in, ft_high); /* AccessTime */ in_uint32_le(in, ft_low); in_uint32_le(in, ft_high); if (ft_low || ft_high) access_time = convert_1970_to_filetime(ft_high, ft_low); /* WriteTime */ in_uint32_le(in, ft_low); in_uint32_le(in, ft_high); if (ft_low || ft_high) write_time = convert_1970_to_filetime(ft_high, ft_low); /* ChangeTime */ in_uint32_le(in, ft_low); in_uint32_le(in, ft_high); if (ft_low || ft_high) change_time = convert_1970_to_filetime(ft_high, ft_low); in_uint32_le(in, file_attributes); if (fstat(handle, &filestat)) return STATUS_ACCESS_DENIED; tvs.modtime = filestat.st_mtime; tvs.actime = filestat.st_atime; if (access_time) tvs.actime = access_time; if (write_time || change_time) mod_time = MIN(write_time, change_time); else mod_time = write_time ? write_time : change_time; if (mod_time) tvs.modtime = mod_time; if (access_time || write_time || change_time) {#if WITH_DEBUG_RDP5 printf("FileBasicInformation access time %s", ctime(&tvs.actime)); printf("FileBasicInformation modification time %s", ctime(&tvs.modtime));#endif if (utime(pfinfo->path, &tvs) && errno != EPERM) return STATUS_ACCESS_DENIED; } if (!file_attributes) break; /* not valid */ mode = filestat.st_mode; if (file_attributes & FILE_ATTRIBUTE_READONLY) mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); else mode |= S_IWUSR; mode &= 0777;#if WITH_DEBUG_RDP5 printf("FileBasicInformation set access mode 0%o", mode);#endif if (fchmod(handle, mode)) return STATUS_ACCESS_DENIED; break; case FileRenameInformation: in_uint8s(in, 4); /* Handle of root dir? */ in_uint8s(in, 0x1a); /* unknown */ in_uint32_le(in, length); if (length && (length / 2) < 256) { rdp_in_unistr(in, newname, length); convert_to_unix_filename(newname); } else { return STATUS_INVALID_PARAMETER; } sprintf(fullpath, "%s%s", g_rdpdr_device[pfinfo->device_id].local_path, newname); if (rename(pfinfo->path, fullpath) != 0) { perror("rename"); return STATUS_ACCESS_DENIED; } break; case FileDispositionInformation: /* As far as I understand it, the correct thing to do here is to *schedule* a delete, so it will be deleted when the file is closed. Subsequent FileDispositionInformation requests with DeleteFile set to FALSE should unschedule the delete. See http://www.osronline.com/article.cfm?article=245. */ in_uint32_le(in, delete_on_close); if (delete_on_close || (pfinfo-> accessmask & (FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED))) { pfinfo->delete_on_close = True; } break; case FileAllocationInformation: /* Fall through to FileEndOfFileInformation, which uses ftrunc. This is like Samba with "strict allocation = false", and means that we won't detect out-of-quota errors, for example. */ case FileEndOfFileInformation: in_uint8s(in, 28); /* unknown */ in_uint32_le(in, length); /* file size */ /* prevents start of writing if not enough space left on device */ if (STATFS_FN(g_rdpdr_device[pfinfo->device_id].local_path, &stat_fs) == 0) if (stat_fs.f_bfree * stat_fs.f_bsize < length) return STATUS_DISK_FULL; if (ftruncate_growable(handle, length) != 0) { return STATUS_DISK_FULL; } break; default: unimpl("IRP Set File Information class: 0x%x\n", info_class); return STATUS_INVALID_PARAMETER; } return STATUS_SUCCESS;}NTSTATUSdisk_check_notify(NTHANDLE handle){ struct fileinfo *pfinfo; NTSTATUS status = STATUS_PENDING; NOTIFY notify; pfinfo = &(g_fileinfo[handle]); if (!pfinfo->pdir) return STATUS_INVALID_DEVICE_REQUEST; status = NotifyInfo(handle, pfinfo->info_class, ¬ify); if (status != STATUS_PENDING) return status; if (memcmp(&pfinfo->notify, ¬ify, sizeof(NOTIFY))) { /*printf("disk_check_notify found changed event\n"); */ memcpy(&pfinfo->notify, ¬ify, sizeof(NOTIFY)); status = STATUS_NOTIFY_ENUM_DIR; } return status;}NTSTATUSdisk_create_notify(NTHANDLE handle, uint32 info_class){ struct fileinfo *pfinfo; NTSTATUS ret = STATUS_PENDING; /* printf("start disk_create_notify info_class %X\n", info_class); */ pfinfo = &(g_fileinfo[handle]); pfinfo->info_class = info_class; ret = NotifyInfo(handle, info_class, &pfinfo->notify); if (info_class & 0x1000) { /* ???? */ if (ret == STATUS_PENDING) return STATUS_SUCCESS; } /* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */ return ret;}static NTSTATUSNotifyInfo(NTHANDLE handle, uint32 info_class, NOTIFY * p){ struct fileinfo *pfinfo; struct stat buf; struct dirent *dp; char *fullname; DIR *dpr; pfinfo = &(g_fileinfo[handle]); if (fstat(handle, &buf) < 0) { perror("NotifyInfo"); return STATUS_ACCESS_DENIED; } p->modify_time = buf.st_mtime; p->status_time = buf.st_ctime; p->num_entries = 0; p->total_time = 0; dpr = opendir(pfinfo->path); if (!dpr) { perror("NotifyInfo"); return STATUS_ACCESS_DENIED; } while ((dp = readdir(dpr))) { if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; p->num_entries++; fullname = (char *) xmalloc(strlen(pfinfo->path) + strlen(dp->d_name) + 2); sprintf(fullname, "%s/%s", pfinfo->path, dp->d_name); if (!stat(fullname, &buf)) { p->total_time += (buf.st_mtime + buf.st_ctime); } xfree(fullname); } closedir(dpr); return STATUS_PENDING;}static FsInfoType *FsVolumeInfo(char *fpath){ static FsInfoType info;#ifdef USE_SETMNTENT FILE *fdfs; struct mntent *e;#endif /* initialize */ memset(&info, 0, sizeof(info)); strcpy(info.label, "RDESKTOP"); strcpy(info.type, "RDPFS");#ifdef USE_SETMNTENT fdfs = setmntent(MNTENT_PATH, "r"); if (!fdfs) return &info; while ((e = getmntent(fdfs))) { if (str_startswith(e->mnt_dir, fpath)) { strcpy(info.type, e->mnt_type); strcpy(info.name, e->mnt_fsname); if (strstr(e->mnt_opts, "vfat") || strstr(e->mnt_opts, "iso9660")) { int fd = open(e->mnt_fsname, O_RDONLY); if (fd >= 0) { unsigned char buf[512]; memset(buf, 0, sizeof(buf)); if (strstr(e->mnt_opts, "vfat")) /*FAT*/ { strcpy(info.type, "vfat"); read(fd, buf, sizeof(buf)); info.serial = (buf[42] << 24) + (buf[41] << 16) + (buf[40] << 8) + buf[39]; strncpy(info.label, (char *) buf + 43, 10); info.label[10] = '\0'; } else if (lseek(fd, 32767, SEEK_SET) >= 0) /* ISO9660 */ { read(fd, buf, sizeof(buf)); strncpy(info.label, (char *) buf + 41, 32); info.label[32] = '\0'; /* info.Serial = (buf[128]<<24)+(buf[127]<<16)+(buf[126]<<8)+buf[125]; */ } close(fd); } } } } endmntent(fdfs);#else /* initialize */ memset(&info, 0, sizeof(info)); strcpy(info.label, "RDESKTOP"); strcpy(info.type, "RDPFS");#endif return &info;}NTSTATUSdisk_query_volume_information(NTHANDLE handle, uint32 info_class, STREAM out){ struct STATFS_T stat_fs; struct fileinfo *pfinfo; FsInfoType *fsinfo; pfinfo = &(g_fileinfo[handle]); if (STATFS_FN(pfinfo->path, &stat_fs) != 0) { perror("statfs"); return STATUS_ACCESS_DENIED; } fsinfo = FsVolumeInfo(pfinfo->path); switch (info_class) { case FileFsVolumeInformation: out_uint32_le(out, 0); /* volume creation time low */ out_uint32_le(out, 0); /* volume creation time high */ out_uint32_le(out, fsinfo->serial); /* serial */ out_uint32_le(out, 2 * strlen(fsinfo->label)); /* length of string */ out_uint8(out, 0); /* support objects? */ rdp_out_unistr(out, fsinfo->label, 2 * strlen(fsinfo->label) - 2); break; case FileFsSizeInformation: out_uint32_le(out, stat_fs.f_blocks); /* Total allocation units low */ out_uint32_le(out, 0); /* Total allocation high units */ out_uint32_le(out, stat_fs.f_bfree); /* Available allocation units */ out_uint32_le(out, 0); /* Available allowcation units */ out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */ out_uint32_le(out, 0x200); /* Bytes per sector */ break; case FileFsAttributeInformation: out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */ out_uint32_le(out, F_NAMELEN(stat_fs)); /* max length of filename */ out_uint32_le(out, 2 * strlen(fsinfo->type)); /* length of fs_type */ rdp_out_unistr(out, fsinfo->type, 2 * strlen(fsinfo->type) - 2); break; case FileFsLabelInformation: case FileFsDeviceInformation: case FileFsControlInformation: case FileFsFullSizeInformation: case FileFsObjectIdInformation: case FileFsMaximumInformation: default: unimpl("IRP Query Volume Information class: 0x%x\n", info_class); return STATUS_INVALID_PARAMETER; } return STATUS_SUCCESS;}NTSTATUSdisk_query_directory(NTHANDLE handle, uint32 info_class, char *pattern, STREAM out){ uint32 file_attributes, ft_low, ft_high; char *dirname, fullpath[PATH_MAX]; DIR *pdir; struct dirent *pdirent; struct stat fstat; struct fileinfo *pfinfo; pfinfo = &(g_fileinfo[handle]); pdir = pfinfo->pdir; dirname = pfinfo->path; file_attributes = 0; switch (info_class) { case FileBothDirectoryInformation: /* If a search pattern is received, remember this pattern, and restart search */ if (pattern[0] != 0) { strncpy(pfinfo->pattern, 1 + strrchr(pattern, '/'), PATH_MAX - 1); rewinddir(pdir); } /* find next dirent matching pattern */ pdirent = readdir(pdir); while (pdirent && fnmatch(pfinfo->pattern, pdirent->d_name, 0) != 0) pdirent = readdir(pdir); if (pdirent == NULL) return STATUS_NO_MORE_FILES; /* Get information for directory entry */ sprintf(fullpath, "%s/%s", dirname, pdirent->d_name); if (stat(fullpath, &fstat)) { switch (errno) { case ENOENT: case ELOOP: case EACCES: /* These are non-fatal errors. */ memset(&fstat, 0, sizeof(fstat)); break; default: /* Fatal error. By returning STATUS_NO_SUCH_FILE, the directory list operation will be aborted */ perror(fullpath); out_uint8(out, 0); return STATUS_NO_SUCH_FILE; } } if (S_ISDIR(fstat.st_mode)) file_attributes |= FILE_ATTRIBUTE_DIRECTORY; if (pdirent->d_name[0] == '.') file_attributes |= FILE_ATTRIBUTE_HIDDEN; if (!file_attributes) file_attributes |= FILE_ATTRIBUTE_NORMAL; if (!(fstat.st_mode & S_IWUSR)) file_attributes |= FILE_ATTRIBUTE_READONLY; /* Return requested information */ out_uint8s(out, 8); /* unknown zero */ seconds_since_1970_to_filetime(get_create_time(&fstat), &ft_high, &ft_low); out_uint32_le(out, ft_low); /* create time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(fstat.st_atime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_access_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(fstat.st_mtime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_write_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(fstat.st_ctime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* change_write_time */ out_uint32_le(out, ft_high); out_uint32_le(out, fstat.st_size); /* filesize low */ out_uint32_le(out, 0); /* filesize high */ out_uint32_le(out, fstat.st_size); /* filesize low */ out_uint32_le(out, 0); /* filesize high */ out_uint32_le(out, file_attributes); out_uint8(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ out_uint8s(out, 7); /* pad? */ out_uint8(out, 0); /* 8.3 file length */ out_uint8s(out, 2 * 12); /* 8.3 unicode length */ rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); break; default: /* FIXME: Support FileDirectoryInformation, FileFullDirectoryInformation, and FileNamesInformation */ unimpl("IRP Query Directory sub: 0x%x\n", info_class); return STATUS_INVALID_PARAMETER; } return STATUS_SUCCESS;}static NTSTATUSdisk_device_control(NTHANDLE handle, uint32 request, STREAM in, STREAM out){ if (((request >> 16) != 20) || ((request >> 16) != 9)) return STATUS_INVALID_PARAMETER; /* extract operation */ request >>= 2; request &= 0xfff; printf("DISK IOCTL %d\n", request); switch (request) { case 25: /* ? */ case 42: /* ? */ default: unimpl("DISK IOCTL %d\n", request); return STATUS_INVALID_PARAMETER; } return STATUS_SUCCESS;}DEVICE_FNS disk_fns = { disk_create, disk_close, disk_read, disk_write, disk_device_control /* device_control */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -