/// <summary> /// Recursively copy from one folder to another by reading the files into memory. /// </summary> /// <param name="fromDir">The folder to copy from.</param> /// <param name="fromImpersonationBehavior">The identity that has rights to read the <paramref name="fromDir"/>.</param> /// <param name="toDir">The folder to write to. Writing is not done in an impersonation block.</param> private static void RecursiveCopyStreams(DirectoryInfo fromDir, ImpersonationBehavior fromImpersonationBehavior, DirectoryInfo toDir) { FileInfo[] files; using (ImpersonateIdentity id = new ImpersonateIdentity(fromImpersonationBehavior)) { files = fromDir.GetFiles(); } foreach (FileInfo file in files) { using(Disposer disposer = new Disposer()) { FileStream fromStream; using (ImpersonateIdentity id = new ImpersonateIdentity(fromImpersonationBehavior)) { fromStream = file.OpenRead(); disposer.Push(fromStream); } string toPath = PackageReader.SafePathCombine(toDir.FullName, file.Name); FileInfo toFileInfo = new FileInfo(toPath); FileStream toStream = toFileInfo.OpenWrite(); disposer.Push(toStream); Utilities.CopyStream(fromStream, fromImpersonationBehavior, toStream, ImpersonationBehavior.UseImpersonatedIdentity); } } foreach (DirectoryInfo sub in fromDir.GetDirectories()) { DirectoryInfo newSub = Directory.CreateDirectory(Path.Combine(toDir.FullName, sub.Name)); RecursiveCopy(sub, newSub); } }
/// <summary> /// Writes the file from a byte array directly to the response. The output stream /// extension must be set prior to calling this method. /// If the response is provided and the path extension is not /// in the list of files to use IIS compatibility mode, this is much faster than /// copying the file contents to the output stream and should be used whenever possible. /// If there is no response object, the method reverts to copying the file between streams. /// </summary> /// <param name="fileBytes">The file to render.</param> internal void WriteFileToResponse(byte[] fileBytes) { using (Disposer disposer = new Disposer()) { // Open a stream on the file. For some odd reason fxcop does not acknowledge the ability of disposer // to actually dispose fileStream, so we give it its own using block. using (Stream fileStream = new MemoryStream(fileBytes)) { // If the response was provided (which it will be, in most non-test cases), then // do the TransmitFile or WriteFile. Otherwise, copy the streams to the response output stream. if (Response != null) { // IisCompatibilityMode is not considered here, because in no case do we have a file // path that can be read by TransmitFile. WriteIisCompatibilityModeToResponse(fileStream); } else { DetachableStream outputDS = new DetachableStream(OutputStream); disposer.Push(outputDS); Utilities.CopyStream(fileStream, ImpersonationBehavior.UseImpersonatedIdentity, outputDS, ImpersonationBehavior.UseImpersonatedIdentity); outputDS.Detach(); } } } }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")] // the writer is disposed for all code paths internal static void CopyStream(Stream fromStream, ImpersonationBehavior readImpersonationBehavior, Stream toStream, ImpersonationBehavior writeImpersonationBehavior) { using (Disposer disposer = new Disposer()) { DetachableStream dsToStream = new DetachableStream(toStream); disposer.Push(dsToStream); BinaryWriter writer = new BinaryWriter(dsToStream); disposer.Push(writer); // An addition revert during write operations is required if the setting for reading and writing // is not the same bool requiresWriteRevert = (readImpersonationBehavior != writeImpersonationBehavior); using (ImpersonateIdentity readId = new ImpersonateIdentity(readImpersonationBehavior)) { byte[] bytesIn = new byte[65536]; int bytesRead; while ((bytesRead = fromStream.Read(bytesIn, 0, bytesIn.Length)) != 0) { // If we have to impersonate to write, then do it. Otherwise skip it. if (requiresWriteRevert) { using (ImpersonateIdentity id = new ImpersonateIdentity(writeImpersonationBehavior)) { writer.Write(bytesIn, 0, bytesRead); } } else { writer.Write(bytesIn, 0, bytesRead); } } } dsToStream.Detach(); } }
/// <summary> /// Writes the file from the package directly to the response and set the appropriate /// content type in the response. If the response is provided and the path extension is not /// in the list of files to use IIS compatibility mode, this is much faster than /// copying the file contents to the output stream and should be used whenever possible. /// If there is no response object, the method reverts to copying the file between streams. /// </summary> /// <param name="relativePath">The package-relative path to the file to render.</param> internal void WriteFileToResponse(string relativePath) { // Set the mime type on the response string pathExtension = Path.GetExtension(relativePath); SetOutputStreamExtension(pathExtension); using(Disposer disposer = new Disposer()) { PackageReader pkgReader = m_session.GetPackageReader(); disposer.Push(pkgReader); // If the response was provided (which it will be, in most non-test cases), then // do the TransmitFile or WriteFile. Otherwise, copy the streams to the response output stream. if (Response != null) { // If we are to use Compatibility mode, then write the file if (UseCompatibilityMode(pathExtension)) { Stream packageFile = pkgReader.GetFileStream(relativePath); WriteIisCompatibilityModeToResponse(packageFile); } else { pkgReader.TransmitFile(relativePath, m_context.Response); } } else { DetachableStream outputDS = new DetachableStream(OutputStream); disposer.Push(outputDS); Stream packageFile = pkgReader.GetFileStream(relativePath); disposer.Push(packageFile); Utilities.CopyStream(packageFile, ImpersonationBehavior.UseImpersonatedIdentity, outputDS, ImpersonationBehavior.UseImpersonatedIdentity); outputDS.Detach(); } } }
/// <summary> /// Get the schema information for this store from the cache or from the database. /// </summary> /// <param name="connectionString">Connection string used to access the store.</param> /// <param name="impersonationBehavior">Identifies which <c>WindowsIdentity</c> is used to /// access the database when impersonation is involved.</param> /// <param name="debugLog">Location to which the debug log should be written, or /// null if there isn't a debug log.</param> /// <returns>The schema information.</returns> private static LearningStoreSchema GetSchemaInformationFromCache(string connectionString, ImpersonationBehavior impersonationBehavior, TextWriter debugLog) { // Try to find the connection in the cache lock (s_allSchemasLock) { LearningStoreSchema schema; if (s_allSchemas.TryGetValue(connectionString, out schema)) { return(schema); } } // Not found in the cache -- so go get it from the database // This try/catch block is here for security reasons. Search MSDN for // "WrapVulnerableFinallyClausesInOuterTry" to see details. try { WindowsImpersonationContext impersonationContext = null; try { // Impersonate if necessary if (impersonationBehavior == ImpersonationBehavior.UseOriginalIdentity) { // Not adding it to the disposer, since that could fail (e.g., OutOfMemoryException), // which could cause a security hole. Instead, we'll clean it up manually later. impersonationContext = WindowsIdentity.Impersonate(IntPtr.Zero); } using (Microsoft.LearningComponents.Disposer disposer = new Microsoft.LearningComponents.Disposer()) { // Create a connection SqlConnection connection = new SqlConnection(connectionString); disposer.Push(connection); connection.Open(); // Create a command to retrieve information from the configuration table LogableSqlCommand command = new LogableSqlCommand(connection, debugLog); disposer.Push(command); // Execute command.Execute( "SELECT EngineVersion,\r\n" + " SchemaDefinition\r\n" + "FROM Configuration\r\n"); // Read return values from the database if (!command.Read()) { throw new LearningComponentsInternalException("LSTR1500"); } if (command.GetFieldCount() != 2) { throw new LearningComponentsInternalException("LSTR1510"); } int engineVersion = command.GetInt32(0); SqlXml schemaXml = command.GetSqlXml(1); XPathDocument schemaDoc; using (XmlReader reader = schemaXml.CreateReader()) { schemaDoc = new XPathDocument(reader); } LearningStoreSchema newSchema = LearningStoreSchema.CreateSchema(schemaDoc); if (command.Read()) { throw new LearningComponentsInternalException("LSTR1520"); } if (command.NextResult()) { throw new LearningComponentsInternalException("LSTR1530"); } // Fail if a different engine created this if (engineVersion != LearningStore.EngineVersion) { throw new InvalidOperationException(LearningStoreStrings.IncompatibleEngineVersion); } // Save it in the cache lock (s_allSchemasLock) { LearningStoreSchema schema; if (s_allSchemas.TryGetValue(connectionString, out schema)) { return(schema); } s_allSchemas.Add(connectionString, newSchema); } return(newSchema); } } finally { if (impersonationContext != null) { impersonationContext.Dispose(); } } } catch { throw; } }