static Expression <Func <TEntity, bool> > BuildPredicate <TEntity>(object key) { /* * key: * 如果实体是单一主键,则传入的 key 与主键属性类型相同的值 * 如果实体是多主键,则传入的 key 须是包含了与实体主键类型相同的属性的对象,如:new { Key1 = "1", Key2 = "2" } */ Utils.CheckNull(key); Type entityType = typeof(TEntity); TypeDescriptor typeDescriptor = EntityTypeContainer.GetDescriptor(entityType); EnsureEntityHasPrimaryKey(typeDescriptor); KeyValuePairList <MemberInfo, object> keyValueMap = new KeyValuePairList <MemberInfo, object>(); if (typeDescriptor.PrimaryKeys.Count == 1) { keyValueMap.Add(typeDescriptor.PrimaryKeys[0].Property, key); } else { /* * key: new { Key1 = "1", Key2 = "2" } */ object multipleKeyObject = key; Type multipleKeyObjectType = multipleKeyObject.GetType(); for (int i = 0; i < typeDescriptor.PrimaryKeys.Count; i++) { var keyMemberDescriptor = typeDescriptor.PrimaryKeys[i]; MemberInfo keyMember = multipleKeyObjectType.GetProperty(keyMemberDescriptor.Property.Name); if (keyMember == null) { throw new ArgumentException(string.Format("The input object does not define property for key '{0}'.", keyMemberDescriptor.Property.Name)); } object value = keyMember.GetMemberValue(multipleKeyObject); if (value == null) { throw new ArgumentException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.Property.Name)); } keyValueMap.Add(keyMemberDescriptor.Property, value); } } ParameterExpression parameter = Expression.Parameter(entityType, "a"); Expression lambdaBody = null; foreach (var keyValue in keyValueMap) { Expression propOrField = Expression.PropertyOrField(parameter, keyValue.Key.Name); Expression wrappedValue = Chloe.Extensions.ExpressionExtension.MakeWrapperAccess(keyValue.Value, keyValue.Key.GetMemberType()); Expression e = Expression.Equal(propOrField, wrappedValue); lambdaBody = lambdaBody == null ? e : Expression.AndAlso(lambdaBody, e); } Expression <Func <TEntity, bool> > predicate = Expression.Lambda <Func <TEntity, bool> >(lambdaBody, parameter); return(predicate); }
static KeyValuePairList <JoinType, Expression> ResolveJoinInfo(LambdaExpression joinInfoExp) { /* * Usage: * var view = context.JoinQuery<User, City, Province, User, City>((user, city, province, user1, city1) => new object[] * { * JoinType.LeftJoin, user.CityId == city.Id, * JoinType.RightJoin, city.ProvinceId == province.Id, * JoinType.InnerJoin,user.Id==user1.Id, * JoinType.FullJoin,city.Id==city1.Id * }).Select((user, city, province, user1, city1) => new { User = user, City = city, Province = province, User1 = user1, City1 = city1 }); * * To resolve join infomation: * JoinType.LeftJoin, user.CityId == city.Id index of joinType is 0 * JoinType.RightJoin, city.ProvinceId == province.Id index of joinType is 2 * JoinType.InnerJoin,user.Id==user1.Id index of joinType is 4 * JoinType.FullJoin,city.Id==city1.Id index of joinType is 6 */ NewArrayExpression body = joinInfoExp.Body as NewArrayExpression; if (body == null) { throw new ArgumentException(string.Format("Invalid join infomation '{0}'. The correct usage is like: {1}", joinInfoExp, "context.JoinQuery<User, City>((user, city) => new object[] { JoinType.LeftJoin, user.CityId == city.Id })")); } KeyValuePairList <JoinType, Expression> ret = new KeyValuePairList <JoinType, Expression>(); if ((joinInfoExp.Parameters.Count - 1) * 2 != body.Expressions.Count) { throw new ArgumentException(string.Format("Invalid join infomation '{0}'.", joinInfoExp)); } for (int i = 0; i < joinInfoExp.Parameters.Count - 1; i++) { /* * 0 0 * 1 2 * 2 4 * 3 6 * ... */ int indexOfJoinType = i * 2; Expression joinTypeExpression = body.Expressions[indexOfJoinType]; object inputJoinType = ExpressionEvaluator.Evaluate(joinTypeExpression); if (inputJoinType == null || inputJoinType.GetType() != typeof(JoinType)) { throw new ArgumentException(string.Format("Not support '{0}', please pass correct type of 'Chloe.JoinType'.", joinTypeExpression)); } /* * The next expression of join type must be join condition. */ Expression joinCondition = body.Expressions[indexOfJoinType + 1].StripConvert(); if (joinCondition.Type != UtilConstants.TypeOfBoolean) { throw new ArgumentException(string.Format("Not support '{0}', please pass correct join condition.", joinCondition)); } ParameterExpression[] parameters = joinInfoExp.Parameters.Take(i + 2).ToArray(); List <Type> typeArguments = parameters.Select(a => a.Type).ToList(); typeArguments.Add(UtilConstants.TypeOfBoolean); Type delegateType = Utils.GetFuncDelegateType(typeArguments.ToArray()); LambdaExpression lambdaOfJoinCondition = Expression.Lambda(delegateType, joinCondition, parameters); ret.Add((JoinType)inputJoinType, lambdaOfJoinCondition); } return(ret); }
/// <param name="endOfTransferRecorded">True if one or more pages has been filled and the next transfer will be seen as a separate IO transfer</param> private void FlushRecords(List <LfsRecord> records, out bool endOfTransferRecorded) { KeyValuePairList <ulong, LfsRecordPage> pagesToWrite = new KeyValuePairList <ulong, LfsRecordPage>(); int bytesAvailableInPage = (int)m_restartPage.LogPageSize - (int)m_restartPage.RestartArea.LogPageDataOffset; LfsRecordPage currentPage = null; bool overwriteTailPage = false; for (int recordIndex = 0; recordIndex < records.Count; recordIndex++) { LfsRecord record = records[recordIndex]; ulong pageOffsetInFile = LsnToPageOffsetInFile(record.ThisLsn); int recordOffsetInPage = LsnToRecordOffsetInPage(record.ThisLsn); bool initializeNewPage = (recordOffsetInPage == m_restartPage.RestartArea.LogPageDataOffset); if (initializeNewPage) // We write the record at the beginning of a new page, we must initialize the page { currentPage = new LfsRecordPage((int)m_restartPage.LogPageSize, m_restartPage.RestartArea.LogPageDataOffset); currentPage.LastLsnOrFileOffset = 0; currentPage.LastEndLsn = 0; currentPage.NextRecordOffset = m_restartPage.RestartArea.LogPageDataOffset; currentPage.UpdateSequenceNumber = m_nextUpdateSequenceNumber; // There is no rule governing the value of the USN m_nextUpdateSequenceNumber++; pagesToWrite.Add(pageOffsetInFile, currentPage); } else { if (recordIndex == 0) // currentPage == null { if (m_tailPage == null) { m_tailPage = ReadPage(pageOffsetInFile);; m_tailPageOffsetInFile = pageOffsetInFile; } else if (m_tailPageOffsetInFile != pageOffsetInFile) { throw new InvalidOperationException("LFS log records must be written sequentially"); } currentPage = m_tailPage; overwriteTailPage = true; pagesToWrite.Add(pageOffsetInFile, currentPage); } // currentPage cannot be null when !initializeNewPage && recordIndex > 0 System.Diagnostics.Debug.Assert(currentPage != null); } int bytesAvailableInFirstPage = (int)m_restartPage.LogPageSize - recordOffsetInPage; int bytesToWrite = Math.Min(record.Length, bytesAvailableInFirstPage); int bytesRemaining = record.Length - bytesToWrite; record.IsMultiPageRecord = (bytesRemaining > 0); byte[] recordBytes = record.GetBytes(); currentPage.WriteBytes(recordOffsetInPage, recordBytes, bytesToWrite); currentPage.LastLsnOrFileOffset = record.ThisLsn; if (!record.IsMultiPageRecord) { currentPage.NextRecordOffset = (ushort)(recordOffsetInPage + bytesToWrite); currentPage.LastEndLsn = record.ThisLsn; currentPage.HasRecordEnd = true; } bool reusePage = !record.IsMultiPageRecord && (bytesAvailableInFirstPage >= m_restartPage.RestartArea.RecordHeaderLength); if (!reusePage) { currentPage = null; } while (bytesRemaining > 0) { pageOffsetInFile += m_restartPage.LogPageSize; if (pageOffsetInFile == m_restartPage.RestartArea.FileSize) { pageOffsetInFile = m_restartPage.SystemPageSize * 2 + m_restartPage.LogPageSize * 2; } bytesToWrite = Math.Min(bytesRemaining, bytesAvailableInPage); LfsRecordPage nextPage = new LfsRecordPage((int)m_restartPage.LogPageSize, m_restartPage.RestartArea.LogPageDataOffset); Array.Copy(recordBytes, recordBytes.Length - bytesRemaining, nextPage.Data, 0, bytesToWrite); bytesRemaining -= bytesToWrite; nextPage.LastLsnOrFileOffset = record.ThisLsn; if (bytesRemaining == 0) { nextPage.LastEndLsn = record.ThisLsn; nextPage.NextRecordOffset = (ushort)(m_restartPage.RestartArea.LogPageDataOffset + bytesToWrite); nextPage.Flags |= LfsRecordPageFlags.RecordEnd; int bytesAvailableInLastPage = (int)m_restartPage.LogPageSize - ((int)m_restartPage.RestartArea.LogPageDataOffset + bytesToWrite); bool reuseLastPage = (bytesAvailableInLastPage >= m_restartPage.RestartArea.RecordHeaderLength); if (reuseLastPage) { currentPage = nextPage; } } nextPage.UpdateSequenceNumber = m_nextUpdateSequenceNumber; // There is no rule governing the value of the USN m_nextUpdateSequenceNumber++; pagesToWrite.Add(pageOffsetInFile, nextPage); } } // The tail copy is used to avoid losing both the records from the previous IO transfer and the current one if the page becomes corrupted due to a power failue. endOfTransferRecorded = (pagesToWrite.Count > 1 || currentPage == null); if (!endOfTransferRecorded) { ulong pageOffsetInFile = pagesToWrite[0].Key; if (m_isTailCopyDirty || !overwriteTailPage) { WritePage(pageOffsetInFile, currentPage); m_isTailCopyDirty = false; } else { WriteTailCopy(pageOffsetInFile, currentPage);; m_isTailCopyDirty = true; } } else { for (int pageIndex = 0; pageIndex < pagesToWrite.Count; pageIndex++) { ulong pageOffsetInFile = pagesToWrite[pageIndex].Key; LfsRecordPage page = pagesToWrite[pageIndex].Value; page.PagePosition = (ushort)(pageIndex + 1); page.PageCount = (ushort)pagesToWrite.Count; if (pageIndex == 0 && !m_isTailCopyDirty && overwriteTailPage) { // We are about to overwrite a page from an older transfer that does not have a tail copy, create a tail copy WriteTailCopy(pageOffsetInFile, page); } WritePage(pageOffsetInFile, page); } } if (currentPage == null) { m_tailPage = null; m_isTailCopyDirty = false; } else { m_tailPage = currentPage; m_tailPageOffsetInFile = pagesToWrite[pagesToWrite.Count - 1].Key; } }
public void InnerList_JustCreated_NoItemsAdded() { var list = new KeyValuePairList <string, string>(); Assert.AreEqual(0, list.InnerList.Count); }
public static void UpdateOperationalParameters(KeyValuePairList <string, string> loginParameters, SessionParameters sessionParameters, ConnectionParameters connectionParameters) { sessionParameters.InitialR2T = ISCSIServer.OfferedInitialR2T; sessionParameters.ImmediateData = ISCSIServer.OfferedImmediateData; sessionParameters.MaxBurstLength = ISCSIServer.OfferedMaxBurstLength; sessionParameters.FirstBurstLength = ISCSIServer.OfferedFirstBurstLength; sessionParameters.MaxConnections = ISCSIServer.OfferedMaxConnections; sessionParameters.DataPDUInOrder = ISCSIServer.OfferedDataPDUInOrder; sessionParameters.DataSequenceInOrder = ISCSIServer.OfferedDataSequenceInOrder; sessionParameters.DefaultTime2Wait = ISCSIServer.OfferedDefaultTime2Wait; sessionParameters.DefaultTime2Retain = ISCSIServer.OfferedDefaultTime2Retain; sessionParameters.MaxOutstandingR2T = ISCSIServer.OfferedMaxOutstandingR2T; string value = loginParameters.ValueOf("MaxRecvDataSegmentLength"); if (value != null) { connectionParameters.InitiatorMaxRecvDataSegmentLength = Convert.ToInt32(value); } value = loginParameters.ValueOf("InitialR2T"); if (value != null) { sessionParameters.InitialR2T = (value == "Yes") || ISCSIServer.OfferedInitialR2T; } value = loginParameters.ValueOf("ImmediateData"); if (value != null) { sessionParameters.ImmediateData = (value == "Yes") && ISCSIServer.OfferedImmediateData; } value = loginParameters.ValueOf("MaxBurstLength"); if (value != null) { sessionParameters.MaxBurstLength = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedMaxBurstLength); } value = loginParameters.ValueOf("FirstBurstLength"); if (value != null) { sessionParameters.FirstBurstLength = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedFirstBurstLength); } value = loginParameters.ValueOf("MaxConnections"); if (value != null) { sessionParameters.MaxConnections = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedMaxConnections); } value = loginParameters.ValueOf("DataPDUInOrder"); if (value != null) { sessionParameters.DataPDUInOrder = (value == "Yes") || ISCSIServer.OfferedDataPDUInOrder; } value = loginParameters.ValueOf("DataSequenceInOrder"); if (value != null) { sessionParameters.DataSequenceInOrder = (value == "Yes") || ISCSIServer.OfferedDataSequenceInOrder; } value = loginParameters.ValueOf("DefaultTime2Wait"); if (value != null) { sessionParameters.DefaultTime2Wait = Math.Max(Convert.ToInt32(value), ISCSIServer.OfferedDefaultTime2Wait); } value = loginParameters.ValueOf("DefaultTime2Retain"); if (value != null) { sessionParameters.DefaultTime2Retain = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedDefaultTime2Retain); } value = loginParameters.ValueOf("MaxOutstandingR2T"); if (value != null) { sessionParameters.MaxOutstandingR2T = Math.Min(Convert.ToInt32(value), ISCSIServer.OfferedMaxOutstandingR2T); } }
public void RemoveEntry(byte[] key) { if (!m_rootRecord.IsParentNode) { int index = CollationHelper.FindIndexInLeafNode(m_rootRecord.IndexEntries, key, m_rootRecord.CollationRule); if (index >= 0) { m_rootRecord.IndexEntries.RemoveAt(index); } m_volume.UpdateFileRecord(m_fileRecord); } else { int indexOfEntryToRemove; KeyValuePairList <int, IndexRecord> path = FindRemovalPath(key, out indexOfEntryToRemove); if (path == null) { return; } if ((path.Count > 0 && path[path.Count - 1].Value.IsParentNode) || path.Count == 0) { // We find the rightmost leaf entry in the left branch and put it instead. // Note: Excluding the root of the branch, the rightmost leaf entry in the branch collates last. KeyValuePairList <int, IndexRecord> pathToLeaf = FindPathToRightmostLeaf(path, indexOfEntryToRemove); IndexRecord leaf = pathToLeaf[pathToLeaf.Count - 1].Value; IndexEntry entryToRemoveFromLeaf = leaf.IndexEntries[leaf.IndexEntries.Count - 1]; leaf.IndexEntries.RemoveAt(leaf.IndexEntries.Count - 1); long leafRecordIndex = ConvertToRecordIndex(leaf.RecordVBN); // Note: CHKDSK does not accept an empty IndexRecord, however, we must not call RemovePointer just yet because it might affect the parent as well. WriteIndexRecord(leafRecordIndex, leaf); if (path.Count == 0) { m_rootRecord.IndexEntries[indexOfEntryToRemove].FileReference = entryToRemoveFromLeaf.FileReference; m_rootRecord.IndexEntries[indexOfEntryToRemove].Key = entryToRemoveFromLeaf.Key; m_volume.UpdateFileRecord(m_fileRecord); } else { path[path.Count - 1].Value.IndexEntries[indexOfEntryToRemove].FileReference = entryToRemoveFromLeaf.FileReference; path[path.Count - 1].Value.IndexEntries[indexOfEntryToRemove].Key = entryToRemoveFromLeaf.Key; long recordIndex = ConvertToRecordIndex(path[path.Count - 1].Value.RecordVBN); WriteIndexRecord(recordIndex, path[path.Count - 1].Value); } if (leaf.IndexEntries.Count == 0) { int indexOfLeafPointer = pathToLeaf[pathToLeaf.Count - 1].Key; RemovePointer(pathToLeaf.GetRange(0, pathToLeaf.Count - 1), indexOfLeafPointer); DeallocateIndexRecord(leafRecordIndex); } } else { int indexInParentRecord = path[path.Count - 1].Key; IndexRecord leaf = path[path.Count - 1].Value; leaf.IndexEntries.RemoveAt(indexOfEntryToRemove); long recordIndex = ConvertToRecordIndex(leaf.RecordVBN); if (leaf.IndexEntries.Count > 0) { WriteIndexRecord(recordIndex, leaf); } else { path.RemoveAt(path.Count - 1); RemovePointer(path, indexInParentRecord); DeallocateIndexRecord(recordIndex); } } } }
/// <param name="path">Key is index in parent node</param> private void SplitIndexRecord(KeyValuePairList <int, IndexRecord> path) { int indexInParentRecord = path[path.Count - 1].Key; // We will treat the record we want to split as the right node, and create a left node IndexRecord rightNode = path[path.Count - 1].Value; long rightNodeVBN = rightNode.RecordVBN; long rightNodeIndex = ConvertToRecordIndex(rightNodeVBN); List <IndexEntry> rightNodeEntries = rightNode.IndexEntries; int splitIndex = rightNodeEntries.Count / 2; IndexEntry middleEntry = rightNodeEntries[splitIndex]; IndexRecord leftNode = new IndexRecord(); leftNode.IsParentNode = rightNode.IsParentNode; leftNode.IndexEntries = rightNodeEntries.GetRange(0, splitIndex); rightNodeEntries.RemoveRange(0, splitIndex + 1); if (rightNode.IsParentNode) { // A parent node has n keys and points to (n + 1) subnodes, // When splitting it to two nodes we will take the pointer from the entry we wish to push to the parent node, // and use it as the last pointer in the left node. IndexEntry leftNodeLastEntry = new IndexEntry(); leftNodeLastEntry.ParentNodeForm = true; leftNodeLastEntry.IsLastEntry = true; leftNodeLastEntry.SubnodeVBN = middleEntry.SubnodeVBN; leftNode.IndexEntries.Add(leftNodeLastEntry); } long leftNodeIndex = AllocateIndexRecord(); leftNode.RecordVBN = ConvertToVirtualBlockNumber(leftNodeIndex); IndexEntry newParentEntry = new IndexEntry(middleEntry.FileReference, middleEntry.Key); newParentEntry.ParentNodeForm = true; newParentEntry.SubnodeVBN = leftNode.RecordVBN; WriteIndexRecord(rightNodeIndex, rightNode); WriteIndexRecord(leftNodeIndex, leftNode); if (path.Count > 1) { IndexRecord parentRecord = path[path.Count - 2].Value; long parentRecordIndex = ConvertToRecordIndex(parentRecord.RecordVBN); List <IndexEntry> parentEntries = parentRecord.IndexEntries; parentEntries.Insert(indexInParentRecord, newParentEntry); if (parentRecord.DoesFit((int)m_rootRecord.BytesPerIndexRecord)) { WriteIndexRecord(parentRecordIndex, parentRecord); } else { // Split parent index record path.RemoveAt(path.Count - 1); SplitIndexRecord(path); } } else { m_rootRecord.IndexEntries.Insert(indexInParentRecord, newParentEntry); if (m_rootRecord.RecordLength >= m_volume.AttributeRecordLengthToMakeNonResident) { SplitRootIndexRecord(); } else { m_volume.UpdateFileRecord(m_fileRecord); } } }
public static void SetCommand(string[] args) { if (args.Length == 2) { KeyValuePairList <string, string> parameters = ParseParameters(args, 1); if (!VerifyParameters(parameters, "debug", "commandqueue", "MaxRecvDataSegmentLength".ToLower(), "MaxBurstLength".ToLower(), "FirstBurstLength".ToLower())) { Console.WriteLine("Invalid parameter."); return; } if (parameters.ContainsKey("debug")) { m_debug = true; } if (parameters.ContainsKey("CommandQueue".ToLower())) { int requestedCommandQueueSize = Conversion.ToInt32(parameters.ValueOf("commandqueue"), 0); if (requestedCommandQueueSize < 0) { Console.WriteLine("Invalid queue size (must be non-negative)."); return; } SessionParameters.DefaultCommandQueueSize = (uint)requestedCommandQueueSize; } if (parameters.ContainsKey("MaxRecvDataSegmentLength".ToLower())) { int requestedMaxRecvDataSegmentLength = Conversion.ToInt32(parameters.ValueOf("MaxRecvDataSegmentLength".ToLower()), 0); if (requestedMaxRecvDataSegmentLength <= 0) { Console.WriteLine("Invalid length (must be positive)."); return; } ConnectionParameters.DeclaredMaxRecvDataSegmentLength = requestedMaxRecvDataSegmentLength; Console.WriteLine("MaxRecvDataSegmentLength has been set to " + ISCSIServer.OfferedMaxBurstLength); } if (parameters.ContainsKey("MaxBurstLength".ToLower())) { int requestedMaxBurstLength = Conversion.ToInt32(parameters.ValueOf("MaxBurstLength".ToLower()), 0); if (requestedMaxBurstLength <= 0) { Console.WriteLine("Invalid length (must be positive)."); return; } ISCSIServer.OfferedMaxBurstLength = requestedMaxBurstLength; Console.WriteLine("Offered MaxBurstLength has been set to " + ISCSIServer.OfferedMaxBurstLength); if (ISCSIServer.OfferedMaxBurstLength < ISCSIServer.OfferedFirstBurstLength) { // FirstBurstLength MUST NOT exceed MaxBurstLength ISCSIServer.OfferedFirstBurstLength = ISCSIServer.OfferedMaxBurstLength; Console.WriteLine("Offered FirstBurstLength has been set to " + ISCSIServer.OfferedFirstBurstLength); } } if (parameters.ContainsKey("FirstBurstLength".ToLower())) { int requestedFirstBurstLength = Conversion.ToInt32(parameters.ValueOf("FirstBurstLength".ToLower()), 0); if (requestedFirstBurstLength <= 0) { Console.WriteLine("Invalid length (must be positive)."); return; } ISCSIServer.OfferedFirstBurstLength = requestedFirstBurstLength; Console.WriteLine("Offered FirstBurstLength has been set to " + ISCSIServer.OfferedFirstBurstLength); if (ISCSIServer.OfferedMaxBurstLength < ISCSIServer.OfferedFirstBurstLength) { // FirstBurstLength MUST NOT exceed MaxBurstLength ISCSIServer.OfferedMaxBurstLength = ISCSIServer.OfferedFirstBurstLength; Console.WriteLine("Offered MaxBurstLength has been set to " + ISCSIServer.OfferedMaxBurstLength); } } } else if (args.Length > 2) { Console.WriteLine("Too many arguments."); HelpSet(); } else { HelpSet(); } }
private static KeyValuePair <MftSegmentReference, FileNameRecord>?FindFileNameRecord(KeyValuePairList <MftSegmentReference, FileNameRecord> records, string name) { foreach (KeyValuePair <MftSegmentReference, FileNameRecord> record in records) { if (String.Equals(record.Value.FileName, name, StringComparison.InvariantCultureIgnoreCase)) { return(record); } } return(null); }
public static void AttachCommand(string[] args) { if (m_server != null) { Console.WriteLine("Server is already running"); return; } if (args.Length >= 2) { KeyValuePairList <string, string> parameters = ParseParameters(args, 2); if (!VerifyParameters(parameters, "vdisk", "disk", "volume", "readonly", "target")) { Console.WriteLine(); Console.WriteLine("Invalid parameter"); HelpAttach(); return; } switch (args[1].ToLower()) { case "vdisk": { if (m_selectedDisk == null) { Console.WriteLine("No disk has been selected"); break; } if (!(m_selectedDisk is DiskImage)) { Console.WriteLine("Selected disk is not a disk image"); break; } DiskImage disk = (DiskImage)m_selectedDisk; string defaultStorageTargetName = Path.GetFileNameWithoutExtension(disk.Path); string defaultTargetName = DefaultTargetIQN + ":" + defaultStorageTargetName.Replace(" ", ""); // spaces are not allowed AttachISCSIDisk(disk, defaultTargetName, parameters); break; } case "disk": { if (m_selectedDisk == null) { Console.WriteLine("Error: No disk has been selected."); break; } if (!(m_selectedDisk is PhysicalDisk)) { Console.WriteLine("Error: The selected disk is not a physical disk."); break; } bool isAttachmentReadOnly = parameters.ContainsKey("readonly"); PhysicalDisk disk = (PhysicalDisk)m_selectedDisk; if (!isAttachmentReadOnly) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) //if (Environment.OSVersion.Version.Major >= 6) { bool isDiskReadOnly; bool isOnline = disk.GetOnlineStatus(out isDiskReadOnly); if (isOnline) { Console.WriteLine(); Console.WriteLine("Error: The selected disk must be taken offline."); break; } if (!isAttachmentReadOnly && isDiskReadOnly) { Console.WriteLine(); Console.WriteLine("Error: The selected disk is set to readonly!"); break; } } else { Console.WriteLine(); // Locking mechanism is not implemented Console.Write("Warning: if a volume on this disk is mounted locally, data corruption may occur!"); } } string defaultStorageTargetName = string.Format("disk{0}", disk.PhysicalDiskIndex); string defaultTargetName = DefaultTargetIQN + ":" + defaultStorageTargetName; AttachISCSIDisk(disk, defaultTargetName, parameters); break; } case "volume": { if (m_selectedVolume == null) { Console.WriteLine("No volume has been selected."); break; } VolumeDisk virtualDisk = new VolumeDisk(m_selectedVolume); string defaultTargetName = DefaultTargetIQN + ":Volume"; bool isAttachmentReadOnly = parameters.ContainsKey("readonly"); if (!isAttachmentReadOnly) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) //if (Environment.OSVersion.Version.Major >= 6) { if (m_selectedVolume is DynamicVolume) { foreach (DiskExtent extent in ((DynamicVolume)m_selectedVolume).Extents) { if (extent.Disk is PhysicalDisk) { bool isDiskReadOnly; bool isOnline = ((PhysicalDisk)extent.Disk).GetOnlineStatus(out isDiskReadOnly); if (isOnline) { Console.WriteLine("Error: All disks containing the volume must be taken offline."); return; } if (isDiskReadOnly) { Console.WriteLine("Error: A disk containing the volume is set to readonly."); return; } } } } else if (m_selectedVolume is Partition) { Disk disk = ((Partition)m_selectedVolume).Disk; if (disk is PhysicalDisk) { bool isDiskReadOnly; bool isOnline = ((PhysicalDisk)disk).GetOnlineStatus(out isDiskReadOnly); if (isOnline) { Console.WriteLine("Error: The disk containing the volume must be taken offline."); return; } if (isDiskReadOnly) { Console.WriteLine("Error: The disk containing the volume is set to readonly."); return; } } } } else { Console.WriteLine(); // Locking mechanism is not implemented Console.WriteLine("Warning: if this volume is mounted locally, data corruption may occur!"); } } AttachISCSIDisk(virtualDisk, defaultTargetName, parameters); break; } default: { Console.WriteLine(); Console.WriteLine("Invalid argument."); HelpAttach(); break; } } } else { HelpAttach(); } }