static Bool clipLineInRectangle(int xmin, int ymin, int xmax, int ymax, int *x1, int *y1, int *x2, int *y2) { #define TOP (1<<0) #define BOT (1<<1) #define LEF (1<<2) #define RIG (1<<3) #define CHECK_OUT(X,Y) (((Y) > ymax ? TOP : ((Y) < ymin ? BOT : 0))\ | ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0))) int ocode1, ocode2, ocode; int accept = 0; int x, y; ocode1 = CHECK_OUT(*x1, *y1); ocode2 = CHECK_OUT(*x2, *y2); for (;;) { if (!ocode1 && !ocode2) { /* completely inside */ accept = 1; break; } else if (ocode1 & ocode2) { break; } if (ocode1) ocode = ocode1; else ocode = ocode2; if (ocode & TOP) { x = *x1 + (*x2 - *x1) * (ymax - *y1) / (*y2 - *y1); y = ymax; } else if (ocode & BOT) { x = *x1 + (*x2 - *x1) * (ymin - *y1) / (*y2 - *y1); y = ymin; } else if (ocode & RIG) { y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1); x = xmax; } else { /* //if (ocode & LEF) { */ y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1); x = xmin; } if (ocode == ocode1) { *x1 = x; *y1 = y; ocode1 = CHECK_OUT(x, y); } else { *x2 = x; *y2 = y; ocode2 = CHECK_OUT(x, y); } } return accept; }
// // IOCTL_PREPARE_TO_UNLOAD // NTSTATUS LklPrepareToUnload(PDEVICE_OBJECT device,PIRP irp) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN acq_resource = FALSE; CHECK_OUT(device != lklfsd.device, STATUS_INVALID_DEVICE_REQUEST); ExAcquireResourceExclusiveLite(&lklfsd.global_resource, TRUE); acq_resource = TRUE; CHECK_OUT_MSG(FLAG_ON(lklfsd.flags, VFS_UNLOAD_PENDING), STATUS_ACCESS_DENIED, "Aldready ready to unload"); CHECK_OUT_MSG(!IsListEmpty(&lklfsd.vcb_list), STATUS_ACCESS_DENIED, "Mounted volumes exists"); DbgPrint("Unloading LklVfs"); IoUnregisterFileSystem(lklfsd.device); //unload_linux_kernel(); IoDeleteDevice(lklfsd.device); lklfsd.driver->DriverUnload = DriverUnload; SET_FLAG(lklfsd.flags, VFS_UNLOAD_PENDING); try_exit: if (acq_resource) RELEASE(&lklfsd.global_resource); return status; }
NTSTATUS LklMount(IN PDEVICE_OBJECT dev,IN PVPB vpb) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT volume_device=NULL; PLKLVCB vcb = NULL; LARGE_INTEGER AllocationSize; ULONG ioctlSize; int sectors; PSTR dev_name; STATFS my_stat; ULONG rc; CHECK_OUT(dev == lklfsd.device, STATUS_INVALID_DEVICE_REQUEST); CHECK_OUT(FLAG_ON(lklfsd.flags, VFS_UNLOAD_PENDING),STATUS_UNRECOGNIZED_VOLUME); DbgPrint("Mount volume"); status = IoCreateDevice(lklfsd.driver, sizeof(LKLVCB), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &volume_device); CHECK_OUT(!NT_SUCCESS(status), status); if (dev->AlignmentRequirement > volume_device->AlignmentRequirement) volume_device->AlignmentRequirement = dev->AlignmentRequirement; CLEAR_FLAG(volume_device->Flags, DO_DEVICE_INITIALIZING); volume_device->StackSize = (CCHAR)(dev->StackSize+1); CreateVcb(volume_device,dev,vpb,&AllocationSize); vcb = (PLKLVCB) volume_device->DeviceExtension; if(!FLAG_ON(vcb->flags, VFS_VCB_FLAGS_VCB_INITIALIZED)) TRY_RETURN(STATUS_INSUFFICIENT_RESOURCES); // yup, here we read the disk geometry ioctlSize = sizeof(DISK_GEOMETRY); status = BlockDeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &vcb->disk_geometry, &ioctlSize); CHECK_OUT(!NT_SUCCESS(status), status); ioctlSize = sizeof(PARTITION_INFORMATION); status = BlockDeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &vcb->partition_information, &ioctlSize); CHECK_OUT(!NT_SUCCESS(status), status); int bytes_per_sector = 0; switch (vcb->disk_geometry.BytesPerSector) { case 256: bytes_per_sector = 8; break; case 512: bytes_per_sector = 9; break; case 1024: bytes_per_sector = 10; break; case 2048: bytes_per_sector = 11; break; case 4096: bytes_per_sector = 12; break; case 8192: bytes_per_sector = 13; break; } sectors = vcb->partition_information.PartitionLength.QuadPart >> bytes_per_sector; // try a linux mount if this fails, then we fail to mount // the volume ExAcquireResourceExclusiveLite(&(lklfsd.global_resource), TRUE); lklfsd.no_mounts++; status = sys_mount_wrapper(vcb->target_device, sectors, &vcb->linux_device); DbgPrint("Mounting device '%s' retstatus=%d", dev_name, status); ExFreePool(dev_name); RELEASE(&(lklfsd.global_resource)); CHECK_OUT(!NT_SUCCESS(status), status); //get info about the successfully mounted volume rc = sys_statfs_wrapper(vcb->linux_device.mnt, &my_stat); vpb->DeviceObject = volume_device; // complete vpb fields #define UNKNOWN_LABEL "Local Disk" CharToWchar(vpb->VolumeLabel, UNKNOWN_LABEL , sizeof(UNKNOWN_LABEL)); vpb->VolumeLabel[sizeof(UNKNOWN_LABEL)] = 0; vpb->VolumeLabelLength = sizeof(UNKNOWN_LABEL)*2; vpb->SerialNumber = my_stat.f_type; try_exit: if(!NT_SUCCESS(status)) { ExAcquireResourceExclusiveLite(&(lklfsd.global_resource), TRUE); lklfsd.no_mounts--; RELEASE(&(lklfsd.global_resource)); if(volume_device) { FreeVcb((PLKLVCB) volume_device->DeviceExtension); IoDeleteDevice(volume_device); } } return status; }
// // FSCTL_LOCK_VOLUME // NTSTATUS DDKAPI VfsLockVolume(PIRP irp, PIO_STACK_LOCATION stack_location) { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_OBJECT device = NULL; PLKLVCB vcb; BOOLEAN notified = FALSE; BOOLEAN resource_acquired = FALSE; PFILE_OBJECT file_obj = NULL; // request to fs device not permited device = stack_location->DeviceObject; CHECK_OUT(device == lklfsd.device, STATUS_INVALID_DEVICE_REQUEST); // get vcb vcb = (PLKLVCB)device->DeviceExtension; ASSERT(vcb); // file object - should be the file object for a volume open, // even so we accept it for any open file file_obj = stack_location->FileObject; ASSERT(file_obj); // notify volume locked FsRtlNotifyVolumeEvent(file_obj, FSRTL_VOLUME_LOCK); notified = TRUE; // acquire vcb lock ExAcquireResourceSharedLite(&vcb->vcb_resource, TRUE); resource_acquired = TRUE; // check lock flag if (FLAG_ON(vcb->flags, VFS_VCB_FLAGS_VOLUME_LOCKED)) { VfsReportError("Volume already locked"); TRY_RETURN(STATUS_ACCESS_DENIED); } // abort if open files still exist if (vcb->open_count) { VfsReportError("Open files still exist"); TRY_RETURN(STATUS_ACCESS_DENIED); } // release lock RELEASE(&vcb->vcb_resource); resource_acquired = FALSE; // purge volume VfsPurgeVolume(vcb, TRUE); ExAcquireResourceExclusiveLite(&vcb->vcb_resource, TRUE); resource_acquired = TRUE; // if there are still open referneces we can't lock the volume if (vcb->reference_count > 1) { VfsReportError("Could not purge cached files"); TRY_RETURN(STATUS_ACCESS_DENIED); } // set flag in both vcb and vpb structures SET_FLAG(vcb->flags, VFS_VCB_FLAGS_VOLUME_LOCKED); SetVpbFlag(vcb->vpb, VFS_VCB_FLAGS_VOLUME_LOCKED); DbgPrint("*** Volume LOCKED ***\n"); status = STATUS_SUCCESS; try_exit: if (resource_acquired) RELEASE(&vcb->vcb_resource); if (!NT_SUCCESS(status) && notified) FsRtlNotifyVolumeEvent(file_obj, FSRTL_VOLUME_LOCK_FAILED); return status; }
// // IRP_MJ_DEVICE_CONTROL - is synchronous // NTSTATUS DDKAPI VfsDeviceControl(PDEVICE_OBJECT device, PIRP irp) { NTSTATUS status=STATUS_SUCCESS; BOOLEAN top_level; ULONG ioctl = 0; PIO_STACK_LOCATION stack_location = NULL; PIO_STACK_LOCATION next_stack_location = NULL; BOOLEAN complete_request = FALSE; PLKLVCB vcb = NULL; PLKLFCB fcb = NULL; PFILE_OBJECT file = NULL; PDEVICE_OBJECT targetDevice = NULL; ASSERT(device); ASSERT(irp); top_level = LklIsIrpTopLevel(irp); FsRtlEnterFileSystem(); stack_location = IoGetCurrentIrpStackLocation(irp); ASSERT(stack_location); ioctl = stack_location->Parameters.DeviceIoControl.IoControlCode; if (ioctl == IOCTL_PREPARE_TO_UNLOAD) { complete_request = TRUE; DbgPrint("Prepare to unload"); status = LklPrepareToUnload(device,irp); TRY_RETURN(status); } file = stack_location->FileObject; ASSERT(file); fcb = (PLKLFCB) file->FsContext; CHECK_OUT(fcb == NULL, STATUS_INVALID_PARAMETER); if (fcb->id.type == VCB) { vcb = (PLKLVCB) fcb; } else { vcb = fcb->vcb; } CHECK_OUT(vcb == NULL, STATUS_INVALID_PARAMETER); targetDevice = vcb->target_device; // Pass on the IOCTL to the driver below complete_request = FALSE; next_stack_location = IoGetNextIrpStackLocation(irp); *next_stack_location = *stack_location; IoSetCompletionRoutine(irp, LklIoctlCompletion, NULL, TRUE, TRUE, TRUE); status = IoCallDriver(targetDevice, irp); try_exit: if(complete_request) LklCompleteRequest(irp, status); if (top_level) IoSetTopLevelIrp(NULL); FsRtlExitFileSystem(); return status; }