char *MidiDriver_CAMD::getDevice() { char *retname = NULL; APTR key; if (key = _ICamd->LockCAMD(CD_Linkages)) { struct MidiCluster *cluster = _ICamd->NextCluster(NULL); while (cluster && !retname) { // Get the current cluster name char *dev = cluster->mcl_Node.ln_Name; if (strstr(dev, "out") != NULL) { // This is an output device, return this retname = dev; } else { // Search the next one cluster = _ICamd->NextCluster(cluster); } } _ICamd->UnlockCAMD(key); } return retname; }
// File is bigger than a single cluster // Load first 3 extents // Bad news: Opening a very large file takes a long time // Good news: unless file is badly fragmented, subsequent acceses will be much faster void LoadExtents(Extent* extents, int maxExtents) { u8 i = 0; u32 state = 0; u32 current = extents[0].start; for (;;) { u32 next = NextCluster(&state,current); if (next != current + 1) { if (i == maxExtents-1) break; if (next == (_fat.rootCluster ? 0x0FFFFFFF : 0xFFFF)) break; extents[++i].start = next; extents[i].count = 0; } extents[i].count++; current = next; } while (i < maxExtents-1) extents[++i].start = 0; }
static NTSTATUS VfatWriteFileData( PVFAT_IRP_CONTEXT IrpContext, ULONG Length, LARGE_INTEGER WriteOffset) { PDEVICE_EXTENSION DeviceExt; PVFATFCB Fcb; ULONG Count; ULONG FirstCluster; ULONG CurrentCluster; ULONG BytesDone; ULONG StartCluster; ULONG ClusterCount; NTSTATUS Status = STATUS_SUCCESS; BOOLEAN First = TRUE; ULONG BytesPerSector; ULONG BytesPerCluster; LARGE_INTEGER StartOffset; ULONG BufferOffset; ULONG LastCluster; ULONG LastOffset; /* PRECONDITION */ ASSERT(IrpContext); DeviceExt = IrpContext->DeviceExt; ASSERT(DeviceExt); ASSERT(DeviceExt->FatInfo.BytesPerCluster); ASSERT(IrpContext->FileObject); ASSERT(IrpContext->FileObject->FsContext2 != NULL); Fcb = IrpContext->FileObject->FsContext; BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster; BytesPerSector = DeviceExt->FatInfo.BytesPerSector; DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, " "Length %u, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt, IrpContext->FileObject, Length, WriteOffset.QuadPart, &Fcb->PathNameU); ASSERT(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart); ASSERT(WriteOffset.u.LowPart % BytesPerSector == 0); ASSERT(Length % BytesPerSector == 0); /* Is this a write of the volume? */ if (Fcb->Flags & FCB_IS_VOLUME) { Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("Volume writing failed, Status %x\n", Status); } return Status; } /* Is this a write to the FAT? */ if (Fcb->Flags & FCB_IS_FAT) { WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector; IrpContext->RefCount = 1; for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++) { Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, FALSE); if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) { DPRINT1("FAT writing failed, Status %x\n", Status); break; } WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart; } if (InterlockedDecrement((PLONG)&IrpContext->RefCount) != 0) { KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); } if (NT_SUCCESS(Status) || Status == STATUS_PENDING) { Status = IrpContext->Irp->IoStatus.Status; } return Status; } /* * Find the first cluster */ FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry); if (FirstCluster == 1) { ASSERT(WriteOffset.u.LowPart + Length <= DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector); // Directory of FAT12/16 needs a special handling WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector; // Fire up the write command Status = VfatWriteDiskPartial (IrpContext, &WriteOffset, Length, 0, TRUE); return Status; } ExAcquireFastMutex(&Fcb->LastMutex); LastCluster = Fcb->LastCluster; LastOffset = Fcb->LastOffset; ExReleaseFastMutex(&Fcb->LastMutex); /* * Find the cluster to start the write from */ if (LastCluster > 0 && WriteOffset.u.LowPart >= LastOffset) { Status = OffsetToCluster(DeviceExt, LastCluster, ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) - LastOffset, &CurrentCluster, FALSE); #ifdef DEBUG_VERIFY_OFFSET_CACHING /* DEBUG VERIFICATION */ { ULONG CorrectCluster; OffsetToCluster(DeviceExt, FirstCluster, ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster), &CorrectCluster, FALSE); if (CorrectCluster != CurrentCluster) KeBugCheck(FAT_FILE_SYSTEM); } #endif } else { Status = OffsetToCluster(DeviceExt, FirstCluster, ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster), &CurrentCluster, FALSE); } if (!NT_SUCCESS(Status)) { return Status; } ExAcquireFastMutex(&Fcb->LastMutex); Fcb->LastCluster = CurrentCluster; Fcb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster); ExReleaseFastMutex(&Fcb->LastMutex); IrpContext->RefCount = 1; BufferOffset = 0; while (Length > 0 && CurrentCluster != 0xffffffff) { StartCluster = CurrentCluster; StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector; BytesDone = 0; ClusterCount = 0; do { ClusterCount++; if (First) { BytesDone = min (Length, BytesPerCluster - (WriteOffset.u.LowPart % BytesPerCluster)); StartOffset.QuadPart += WriteOffset.u.LowPart % BytesPerCluster; First = FALSE; } else { if (Length - BytesDone > BytesPerCluster) { BytesDone += BytesPerCluster; } else { BytesDone = Length; } } Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE); } while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone); DPRINT("start %08x, next %08x, count %u\n", StartCluster, CurrentCluster, ClusterCount); ExAcquireFastMutex(&Fcb->LastMutex); Fcb->LastCluster = StartCluster + (ClusterCount - 1); Fcb->LastOffset = ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster; ExReleaseFastMutex(&Fcb->LastMutex); // Fire up the write command Status = VfatWriteDiskPartial (IrpContext, &StartOffset, BytesDone, BufferOffset, FALSE); if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) { break; } BufferOffset += BytesDone; Length -= BytesDone; WriteOffset.u.LowPart += BytesDone; } if (InterlockedDecrement((PLONG)&IrpContext->RefCount) != 0) { KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); } if (NT_SUCCESS(Status) || Status == STATUS_PENDING) { if (Length > 0) { Status = STATUS_UNSUCCESSFUL; } else { Status = IrpContext->Irp->IoStatus.Status; } } return Status; }
static NTSTATUS VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext) { PIO_STACK_LOCATION Stack; LARGE_INTEGER Vcn; PRETRIEVAL_POINTERS_BUFFER RetrievalPointers; PFILE_OBJECT FileObject; ULONG MaxExtentCount; PVFATFCB Fcb; PDEVICE_EXTENSION DeviceExt; ULONG FirstCluster; ULONG CurrentCluster; ULONG LastCluster; NTSTATUS Status; DPRINT("VfatGetRetrievalPointers(IrpContext %p)\n", IrpContext); DeviceExt = IrpContext->DeviceExt; FileObject = IrpContext->FileObject; Stack = IrpContext->Stack; if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER) || Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL) { return STATUS_INVALID_PARAMETER; } if (IrpContext->Irp->UserBuffer == NULL || Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER)) { return STATUS_BUFFER_TOO_SMALL; } Fcb = FileObject->FsContext; ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE); Vcn = ((PSTARTING_VCN_INPUT_BUFFER)Stack->Parameters.DeviceIoControl.Type3InputBuffer)->StartingVcn; RetrievalPointers = IrpContext->Irp->UserBuffer; MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(RetrievalPointers->ExtentCount) - sizeof(RetrievalPointers->StartingVcn)) / sizeof(RetrievalPointers->Extents[0])); if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry); Status = OffsetToCluster(DeviceExt, FirstCluster, Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster, &CurrentCluster, FALSE); if (!NT_SUCCESS(Status)) { goto ByeBye; } RetrievalPointers->StartingVcn = Vcn; RetrievalPointers->ExtentCount = 0; RetrievalPointers->Extents[0].Lcn.u.HighPart = 0; RetrievalPointers->Extents[0].Lcn.u.LowPart = CurrentCluster - 2; LastCluster = 0; while (CurrentCluster != 0xffffffff && RetrievalPointers->ExtentCount < MaxExtentCount) { LastCluster = CurrentCluster; Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE); Vcn.QuadPart++; if (!NT_SUCCESS(Status)) { goto ByeBye; } if (LastCluster + 1 != CurrentCluster) { RetrievalPointers->Extents[RetrievalPointers->ExtentCount].NextVcn = Vcn; RetrievalPointers->ExtentCount++; if (RetrievalPointers->ExtentCount < MaxExtentCount) { RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.HighPart = 0; RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.LowPart = CurrentCluster - 2; } } } IrpContext->Irp->IoStatus.Information = sizeof(RETRIEVAL_POINTERS_BUFFER) + (sizeof(RetrievalPointers->Extents[0]) * (RetrievalPointers->ExtentCount - 1)); Status = STATUS_SUCCESS; ByeBye: ExReleaseResourceLite(&Fcb->MainResource); return Status; }