You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,168 @@
|
||||
// <copyright file="HostFileChangeMonitor.cs" company="Microsoft">
|
||||
// Copyright (c) 2009 Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
using System;
|
||||
using System.Runtime.Caching.Hosting;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.Caching.Resources;
|
||||
using System.Globalization;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Runtime.Caching {
|
||||
public sealed class HostFileChangeMonitor : FileChangeMonitor {
|
||||
private const int MAX_CHAR_COUNT_OF_LONG_CONVERTED_TO_HEXADECIMAL_STRING = 16;
|
||||
private static IFileChangeNotificationSystem s_fcn;
|
||||
private readonly ReadOnlyCollection<String> _filePaths;
|
||||
private String _uniqueId;
|
||||
private Object _fcnState;
|
||||
private DateTimeOffset _lastModified;
|
||||
|
||||
private HostFileChangeMonitor() { } // hide default .ctor
|
||||
|
||||
private void InitDisposableMembers() {
|
||||
bool dispose = true;
|
||||
try {
|
||||
string uniqueId = null;
|
||||
if (_filePaths.Count == 1) {
|
||||
string path = _filePaths[0];
|
||||
DateTimeOffset lastWrite;
|
||||
long fileSize;
|
||||
s_fcn.StartMonitoring(path, new OnChangedCallback(OnChanged), out _fcnState, out lastWrite, out fileSize);
|
||||
uniqueId = path + lastWrite.UtcDateTime.Ticks.ToString("X", CultureInfo.InvariantCulture) + fileSize.ToString("X", CultureInfo.InvariantCulture);
|
||||
_lastModified = lastWrite;
|
||||
}
|
||||
else {
|
||||
int capacity = 0;
|
||||
foreach (string path in _filePaths) {
|
||||
capacity += path.Length + (2 * MAX_CHAR_COUNT_OF_LONG_CONVERTED_TO_HEXADECIMAL_STRING);
|
||||
}
|
||||
Hashtable fcnState = new Hashtable(_filePaths.Count);
|
||||
_fcnState = fcnState;
|
||||
StringBuilder sb = new StringBuilder(capacity);
|
||||
foreach (string path in _filePaths) {
|
||||
if (fcnState.Contains(path)) {
|
||||
continue;
|
||||
}
|
||||
DateTimeOffset lastWrite;
|
||||
long fileSize;
|
||||
object state;
|
||||
s_fcn.StartMonitoring(path, new OnChangedCallback(OnChanged), out state, out lastWrite, out fileSize);
|
||||
fcnState[path] = state;
|
||||
sb.Append(path);
|
||||
sb.Append(lastWrite.UtcDateTime.Ticks.ToString("X", CultureInfo.InvariantCulture));
|
||||
sb.Append(fileSize.ToString("X", CultureInfo.InvariantCulture));
|
||||
if (lastWrite > _lastModified) {
|
||||
_lastModified = lastWrite;
|
||||
}
|
||||
}
|
||||
uniqueId = sb.ToString();
|
||||
}
|
||||
_uniqueId = uniqueId;
|
||||
dispose = false;
|
||||
}
|
||||
finally {
|
||||
InitializationComplete();
|
||||
if (dispose) {
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
|
||||
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "Grandfathered suppression from original caching code checkin")]
|
||||
private static void InitFCN() {
|
||||
if (s_fcn == null) {
|
||||
IFileChangeNotificationSystem fcn = null;
|
||||
IServiceProvider host = ObjectCache.Host;
|
||||
if (host != null) {
|
||||
fcn = host.GetService(typeof(IFileChangeNotificationSystem)) as IFileChangeNotificationSystem;
|
||||
}
|
||||
if (fcn == null) {
|
||||
fcn = new FileChangeNotificationSystem();
|
||||
}
|
||||
Interlocked.CompareExchange(ref s_fcn, fcn, null);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// protected members
|
||||
//
|
||||
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && s_fcn != null) {
|
||||
if (_filePaths != null && _fcnState != null) {
|
||||
if (_filePaths.Count > 1) {
|
||||
Hashtable fcnState = _fcnState as Hashtable;
|
||||
foreach (string path in _filePaths) {
|
||||
if (path != null) {
|
||||
object state = fcnState[path];
|
||||
if (state != null) {
|
||||
s_fcn.StopMonitoring(path, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
string path = _filePaths[0];
|
||||
if (path != null && _fcnState != null) {
|
||||
s_fcn.StopMonitoring(path, _fcnState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// public and internal members
|
||||
//
|
||||
|
||||
public override ReadOnlyCollection<String> FilePaths { get { return _filePaths; } }
|
||||
public override String UniqueId { get { return _uniqueId; } }
|
||||
public override DateTimeOffset LastModified { get { return _lastModified; } }
|
||||
|
||||
public HostFileChangeMonitor(IList<String> filePaths) {
|
||||
if (filePaths == null) {
|
||||
throw new ArgumentNullException("filePaths");
|
||||
}
|
||||
if (filePaths.Count == 0) {
|
||||
throw new ArgumentException(RH.Format(R.Empty_collection, "filePaths"));
|
||||
}
|
||||
|
||||
// *SECURITY* - filePaths is untrusted and should not be consumed outside of the sanitization method.
|
||||
_filePaths = SanitizeFilePathsList(filePaths);
|
||||
|
||||
InitFCN();
|
||||
InitDisposableMembers();
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
private static ReadOnlyCollection<string> SanitizeFilePathsList(IList<string> filePaths) {
|
||||
List<string> newList = new List<string>(filePaths.Count);
|
||||
|
||||
foreach (string path in filePaths) {
|
||||
if (String.IsNullOrEmpty(path)) {
|
||||
throw new ArgumentException(RH.Format(R.Collection_contains_null_or_empty_string, "filePaths"));
|
||||
}
|
||||
else {
|
||||
// DevDiv #269534: When we use a user-provided string in the constructor to this FileIOPermission and demand the permission,
|
||||
// we need to be certain that we're adding *exactly that string* to the new list we're generating. The original code tried to
|
||||
// optimize by checking all of the permissions upfront then doing a List<T>.AddRange at the end, but this opened the method
|
||||
// to a TOCTOU attack since a malicious user could have modified the original IList<T> between the two calls.
|
||||
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand();
|
||||
newList.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
return newList.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user