Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/Paket.Core/Common/Utils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Paket.Utils

open System
open System.IO
open System.IO.Compression
open System.Xml
open System.Text
open Paket
Expand Down Expand Up @@ -674,6 +675,59 @@ let getSha512File (filePath:string) =
use stream = File.OpenRead(filePath)
getSha512Stream stream

let fixDatesInArchive fileName =
try
use zipToOpen = new FileStream(fileName, FileMode.Open)
use archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update)
let maxTime = DateTimeOffset.Now

for e in archive.Entries do
try
let d = min maxTime e.LastWriteTime
e.LastWriteTime <- d
with
| _ -> e.LastWriteTime <- maxTime
with
| exn -> traceWarnfn "Could not fix timestamps in %s. Error: %s" fileName exn.Message

let fixArchive fileName =
if isMonoRuntime then
fixDatesInArchive fileName

let extractZipToDirectory (zipFileName:string) (directoryName:string) =
Directory.CreateDirectory directoryName |> ignore
try
fixArchive zipFileName
ZipFile.ExtractToDirectory(zipFileName, directoryName)
with
| exn ->
let targetPath = FileInfo(directoryName).FullName |> normalizePath
traceWarnfn "Package %s couldn't be extracted to \"%s\". %s: %s. Trying to extract files individually." zipFileName directoryName (exn.GetType().FullName) exn.Message
use archive = ZipFile.OpenRead zipFileName
for entry in archive.Entries do
let destinationPath = Path.GetFullPath(Path.Combine(targetPath, entry.FullName.Trim([| '/'; '\\'|])))

let fi = FileInfo(destinationPath)
let folder = fi.Directory.FullName |> normalizePath
let isSubFolder =
let comparer =
if isLinux then
System.StringComparison.Ordinal
else
System.StringComparison.OrdinalIgnoreCase

folder.StartsWith(targetPath,comparer)

if not isSubFolder then
raise (Exception(sprintf "Error during extraction of %s.%sPackage is corrupted or possible zip leak attack in entry \"%s\"." zipFileName Environment.NewLine entry.FullName))

if not fi.Directory.Exists then
fi.Directory.Create()
if fi.Exists then
try fi.Delete() with | _ -> ()

entry.ExtractToFile(destinationPath)

// adapted from MiniRx
// http://minirx.codeplex.com/
[<AutoOpen>]
Expand Down
88 changes: 22 additions & 66 deletions src/Paket.Core/Dependencies/NuGetCache.fs
Original file line number Diff line number Diff line change
Expand Up @@ -167,25 +167,6 @@ let getCacheFiles force cacheVersion nugetURL (packageName:PackageName) (version
| ex -> traceErrorfn "Cannot cleanup '%s': %O" (sprintf "%s*.json" prefix) ex
FileInfo(newFile)

let fixDatesInArchive fileName =
try
use zipToOpen = new FileStream(fileName, FileMode.Open)
use archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update)
let maxTime = DateTimeOffset.Now

for e in archive.Entries do
try
let d = min maxTime e.LastWriteTime
e.LastWriteTime <- d
with
| _ -> e.LastWriteTime <- maxTime
with
| exn -> traceWarnfn "Could not fix timestamps in %s. Error: %s" fileName exn.Message

let fixArchive fileName =
if isMonoRuntime then
fixDatesInArchive fileName

let GetLicenseFileName (packageName:PackageName) (version:SemVerInfo) = packageName.CompareString + "." + version.Normalize() + ".license.html"
let GetPackageFileName (packageName:PackageName) (version:SemVerInfo) = packageName.CompareString + "." + version.Normalize() + ".nupkg"

Expand Down Expand Up @@ -485,14 +466,12 @@ let rec ExtractPackageToUserFolder(fileName:string, packageName:PackageName, ver
let targetFolder = DirectoryInfo(dir)

use _ = Profile.startCategory Profile.Category.FileIO
if isExtracted targetFolder packageName version |> not then
Directory.CreateDirectory(targetFolder.FullName) |> ignore
let fi = FileInfo fileName
let targetPackageFileName = Path.Combine(targetFolder.FullName,fi.Name)
if normalizePath fileName <> normalizePath targetPackageFileName then
File.Copy(fileName,targetPackageFileName,true)

ZipFile.ExtractToDirectory(fileName, targetFolder.FullName)
if isExtracted targetFolder packageName version then
if verbose then
verbosefn "%O %O already extracted" packageName version
else
extractZipToDirectory fileName targetFolder.FullName

// lowercase the .nuspec file to mimic NuGet behavior
let nuspecFileName = sprintf "%s.nuspec" (packageName.ToString())
let nuspecLowerFileName = sprintf "%s.nuspec" (packageName.CompareString)
Expand All @@ -507,13 +486,22 @@ let rec ExtractPackageToUserFolder(fileName:string, packageName:PackageName, ver
// in the filesystem, because otherwise it is noop (at least in explorer)
File.Move(filePath, tempFilePath)
File.Move(tempFilePath, lowerFilePath)

let fi = FileInfo fileName
let targetPackageFileName = Path.Combine(targetFolder.FullName,fi.Name)
if normalizePath fileName <> normalizePath targetPackageFileName then
File.Copy(fileName,targetPackageFileName,true)

let cachedHashFile = Path.Combine(Constants.NuGetCacheFolder,fi.Name + ".sha512")
if not (File.Exists cachedHashFile) then
let packageHash = getSha512File fileName
File.WriteAllText(cachedHashFile,packageHash)

File.Copy(cachedHashFile,targetPackageFileName + ".sha512")

cleanup targetFolder
if verbose then
verbosefn "%O %O unzipped to %s" packageName version targetFolder.FullName

return targetFolder.FullName
}

Expand All @@ -523,48 +511,16 @@ let ExtractPackage(fileName:string, targetFolder, packageName:PackageName, versi
use _ = Profile.startCategory Profile.Category.FileIO
let directory = DirectoryInfo(targetFolder)
if isExtracted directory packageName version then
if verbose then
verbosefn "%O %O already extracted" packageName version
if verbose then
verbosefn "%O %O already extracted" packageName version
else
Directory.CreateDirectory targetFolder |> ignore

try
fixArchive fileName
ZipFile.ExtractToDirectory(fileName, targetFolder)
extractZipToDirectory fileName targetFolder
with
| exn ->
try
let target = FileInfo(targetFolder).FullName |> normalizePath
traceWarnfn "Package couldn't be extracted to %s. Message: %s. Trying to extract files individually." targetFolder exn.Message
use archive = ZipFile.OpenRead fileName
for entry in archive.Entries do
let destinationPath = Path.GetFullPath(Path.Combine(targetFolder, entry.FullName.Trim([| '/'; '\\'|])))

let fi = FileInfo(destinationPath)
let folder = fi.Directory.FullName |> normalizePath
let isSubFolder =
let comparer =
if isLinux then
System.StringComparison.Ordinal
else
System.StringComparison.OrdinalIgnoreCase

folder.StartsWith(target,comparer)

if not isSubFolder then
raise (Exception(sprintf "Error during extraction of %s.%sPackage is corrupted or possible zip leak attac in entry \"%s\"." fileName Environment.NewLine entry.FullName))

if not fi.Directory.Exists then
fi.Directory.Create()
if fi.Exists then
try fi.Delete() with | _ -> ()

entry.ExtractToFile(destinationPath)
with
| exn ->
let text = if detailed then sprintf "%s In rare cases a firewall might have blocked the download. Please look into the file and see if it contains text with further information." Environment.NewLine else ""
let path = try Path.GetFullPath fileName with :? PathTooLongException -> sprintf "%s (!too long!)" fileName
raise (Exception(sprintf "Error during extraction of %s.%s%s" path Environment.NewLine text, exn))
let text = if detailed then sprintf "%s In rare cases a firewall might have blocked the download. Please look into the file and see if it contains text with further information." Environment.NewLine else ""
let path = try Path.GetFullPath fileName with :? PathTooLongException -> sprintf "%s (!too long!)" fileName
raise (Exception(sprintf "Error during extraction of %s.%s%s" path Environment.NewLine text, exn))

cleanup directory
if verbose then
Expand Down
4 changes: 2 additions & 2 deletions src/Paket.Core/Dependencies/RemoteDownload.fs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ let downloadRemoteFiles(remoteFile:ResolvedSourceFile,destination) = async {
let authentication = auth remoteFile.AuthKey
CleanDir projectPath
do! downloadFromUrl(authentication, downloadUrl) zipFile
ZipFile.ExtractToDirectory(zipFile,projectPath)
Utils.extractZipToDirectory zipFile projectPath

let source = Path.Combine(projectPath, sprintf "%s-%s" remoteFile.Project remoteFile.Commit)
DirectoryCopy(source,projectPath,true)
Expand All @@ -280,7 +280,7 @@ let downloadRemoteFiles(remoteFile:ResolvedSourceFile,destination) = async {
match Path.GetExtension(destination).ToLowerInvariant() with
| ".zip" ->
do! downloadFromUrlWithTimeout(authentication, url) timeout destination
ZipFile.ExtractToDirectory(destination, targetFolder.FullName)
Utils.extractZipToDirectory destination targetFolder.FullName
| _ ->
do! downloadFromUrlWithTimeout(authentication, url) timeout destination
}
Expand Down
2 changes: 1 addition & 1 deletion src/Paket.Core/Packaging/PackageProcess.fs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ let Pack(workingDir: string, dependenciesFile : DependenciesFile, packageOutputP
| CompleteTemplate(core, optional) ->
tracefn "Packaging: %s" templateFile.FileName
let outputPath = NupkgWriter.Write core optional (Path.GetDirectoryName templateFile.FileName) packageOutputPath
NuGetCache.fixDatesInArchive outputPath
Utils.fixDatesInArchive outputPath
tracefn "Wrote: %s" outputPath
| IncompleteTemplate ->
failwithf "There was an attempt to pack the incomplete template file %s." templateFile.FileName
Expand Down