mscorlib(4.0.0.0) API with additions
_WinInetCache.cs
2 using System.Text;
3 using System.Threading;
4 
5 namespace System.Net.Cache
6 {
7  internal static class _WinInetCache
8  {
9  [Flags]
10  internal enum EntryType
11  {
12  NormalEntry = 0x41,
13  StickyEntry = 0x44,
14  Edited = 0x8,
15  TrackOffline = 0x10,
16  TrackOnline = 0x20,
17  Sparse = 0x10000,
18  Cookie = 0x100000,
19  UrlHistory = 0x200000
20  }
21 
22  [Flags]
23  internal enum Entry_FC
24  {
25  None = 0x0,
26  Attribute = 0x4,
27  Hitrate = 0x10,
28  Modtime = 0x40,
29  Exptime = 0x80,
30  Acctime = 0x100,
31  Synctime = 0x200,
32  Headerinfo = 0x400,
33  ExemptDelta = 0x800
34  }
35 
36  internal enum Status
37  {
38  Success = 0,
39  InsufficientBuffer = 122,
40  FileNotFound = 2,
41  NoMoreItems = 259,
42  NotEnoughStorage = 8,
43  SharingViolation = 0x20,
44  InvalidParameter = 87,
45  Warnings = 0x1000000,
46  FatalErrors = 16781312,
47  CorruptedHeaders = 16781313,
48  InternalError = 16781314
49  }
50 
51  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
52  internal struct FILETIME
53  {
54  public uint Low;
55 
56  public uint High;
57 
58  public static readonly FILETIME Zero = new FILETIME(0L);
59 
60  public bool IsNull
61  {
62  get
63  {
64  if (Low == 0)
65  {
66  return High == 0;
67  }
68  return false;
69  }
70  }
71 
72  public FILETIME(long time)
73  {
74  Low = (uint)time;
75  High = (uint)(time >> 32);
76  }
77 
78  public long ToLong()
79  {
80  return (long)(((ulong)High << 32) | Low);
81  }
82  }
83 
84  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
85  internal struct EntryBuffer
86  {
87  [StructLayout(LayoutKind.Explicit)]
88  public struct Rsv
89  {
90  [FieldOffset(0)]
91  public int ExemptDelta;
92 
93  [FieldOffset(0)]
94  public int Reserved;
95  }
96 
97  public static int MarshalSize = Marshal.SizeOf(typeof(EntryBuffer));
98 
99  public int StructSize;
100 
101  public IntPtr _OffsetSourceUrlName;
102 
103  public IntPtr _OffsetFileName;
104 
105  public EntryType EntryType;
106 
107  public int UseCount;
108 
109  public int HitRate;
110 
111  public int SizeLow;
112 
113  public int SizeHigh;
114 
115  public FILETIME LastModifiedTime;
116 
117  public FILETIME ExpireTime;
118 
119  public FILETIME LastAccessTime;
120 
121  public FILETIME LastSyncTime;
122 
123  public IntPtr _OffsetHeaderInfo;
124 
125  public int HeaderInfoChars;
126 
127  public IntPtr _OffsetExtension;
128 
129  public Rsv U;
130  }
131 
132  internal class Entry
133  {
134  public const int DefaultBufferSize = 2048;
135 
136  public Status Error;
137 
138  public string Key;
139 
140  public string Filename;
141 
142  public string FileExt;
143 
144  public int OptionalLength;
145 
146  public string OriginalUrl;
147 
148  public string MetaInfo;
149 
150  public int MaxBufferBytes;
151 
152  public EntryBuffer Info;
153 
154  public Entry(string key, int maxHeadersSize)
155  {
156  Key = key;
157  MaxBufferBytes = maxHeadersSize;
158  if (maxHeadersSize != int.MaxValue && int.MaxValue - (key.Length + EntryBuffer.MarshalSize + 1024) * 2 > maxHeadersSize)
159  {
160  MaxBufferBytes += (key.Length + EntryBuffer.MarshalSize + 1024) * 2;
161  }
162  Info.EntryType = EntryType.NormalEntry;
163  }
164  }
165 
166  private const int c_CharSz = 2;
167 
168  internal unsafe static Status LookupInfo(Entry entry)
169  {
170  byte[] array = new byte[2048];
171  int bufferSz = array.Length;
172  byte[] array2 = array;
173  for (int i = 0; i < 64; i++)
174  {
175  try
176  {
177  byte[] array3 = array2;
178  fixed (byte* ptr = array3)
179  {
180  if (UnsafeNclNativeMethods.UnsafeWinInetCache.GetUrlCacheEntryInfoW(entry.Key, ptr, ref bufferSz))
181  {
182  array = array2;
183  entry.MaxBufferBytes = bufferSz;
184  EntryFixup(entry, (EntryBuffer*)ptr, array2);
185  entry.Error = Status.Success;
186  return entry.Error;
187  }
188  entry.Error = (Status)Marshal.GetLastWin32Error();
189  if (entry.Error == Status.InsufficientBuffer && array2 == array && bufferSz <= entry.MaxBufferBytes)
190  {
191  array2 = new byte[bufferSz];
192  continue;
193  }
194  }
195  }
196  finally
197  {
198  }
199  break;
200  }
201  return entry.Error;
202  }
203 
204  internal unsafe static SafeUnlockUrlCacheEntryFile LookupFile(Entry entry)
205  {
206  byte[] array = new byte[2048];
207  int entryBufSize = array.Length;
208  SafeUnlockUrlCacheEntryFile handle = null;
209  try
210  {
211  while (true)
212  {
213  try
214  {
215  byte[] array2 = array;
216  fixed (byte* ptr = array2)
217  {
218  entry.Error = SafeUnlockUrlCacheEntryFile.GetAndLockFile(entry.Key, ptr, ref entryBufSize, out handle);
219  if (entry.Error == Status.Success)
220  {
221  entry.MaxBufferBytes = entryBufSize;
222  EntryFixup(entry, (EntryBuffer*)ptr, array);
223  return handle;
224  }
225  if (entry.Error == Status.InsufficientBuffer && entryBufSize <= entry.MaxBufferBytes)
226  {
227  array = new byte[entryBufSize];
228  continue;
229  }
230  }
231  }
232  finally
233  {
234  }
235  break;
236  }
237  }
238  catch (Exception ex)
239  {
240  handle?.Close();
242  {
243  throw;
244  }
245  if (entry.Error == Status.Success)
246  {
247  entry.Error = Status.InternalError;
248  }
249  }
250  return null;
251  }
252 
253  private unsafe static Status EntryFixup(Entry entry, EntryBuffer* bufferPtr, byte[] buffer)
254  {
255  bufferPtr->_OffsetExtension = ((bufferPtr->_OffsetExtension == IntPtr.Zero) ? IntPtr.Zero : ((IntPtr)((byte*)(void*)bufferPtr->_OffsetExtension - (byte*)bufferPtr)));
256  bufferPtr->_OffsetFileName = ((bufferPtr->_OffsetFileName == IntPtr.Zero) ? IntPtr.Zero : ((IntPtr)((byte*)(void*)bufferPtr->_OffsetFileName - (byte*)bufferPtr)));
257  bufferPtr->_OffsetHeaderInfo = ((bufferPtr->_OffsetHeaderInfo == IntPtr.Zero) ? IntPtr.Zero : ((IntPtr)((byte*)(void*)bufferPtr->_OffsetHeaderInfo - (byte*)bufferPtr)));
258  bufferPtr->_OffsetSourceUrlName = ((bufferPtr->_OffsetSourceUrlName == IntPtr.Zero) ? IntPtr.Zero : ((IntPtr)((byte*)(void*)bufferPtr->_OffsetSourceUrlName - (byte*)bufferPtr)));
259  entry.Info = *bufferPtr;
260  entry.OriginalUrl = GetEntryBufferString(bufferPtr, (int)bufferPtr->_OffsetSourceUrlName);
261  entry.Filename = GetEntryBufferString(bufferPtr, (int)bufferPtr->_OffsetFileName);
262  entry.FileExt = GetEntryBufferString(bufferPtr, (int)bufferPtr->_OffsetExtension);
263  return GetEntryHeaders(entry, bufferPtr, buffer);
264  }
265 
266  internal static Status CreateFileName(Entry entry)
267  {
268  entry.Error = Status.Success;
269  StringBuilder stringBuilder = new StringBuilder(260);
270  if (UnsafeNclNativeMethods.UnsafeWinInetCache.CreateUrlCacheEntryW(entry.Key, entry.OptionalLength, entry.FileExt, stringBuilder, 0))
271  {
272  entry.Filename = stringBuilder.ToString();
273  return Status.Success;
274  }
275  entry.Error = (Status)Marshal.GetLastWin32Error();
276  return entry.Error;
277  }
278 
279  internal unsafe static Status Commit(Entry entry)
280  {
281  string text = entry.MetaInfo;
282  if (text == null)
283  {
284  text = string.Empty;
285  }
286  if (text.Length + entry.Key.Length + entry.Filename.Length + ((entry.OriginalUrl != null) ? entry.OriginalUrl.Length : 0) > entry.MaxBufferBytes / 2)
287  {
288  entry.Error = Status.InsufficientBuffer;
289  return entry.Error;
290  }
291  entry.Error = Status.Success;
292  fixed (char* ptr = text)
293  {
294  byte* headerInfo = (byte*)(long)((text.Length == 0) ? ((IntPtr)(void*)null) : ((IntPtr)ptr));
295  if (!UnsafeNclNativeMethods.UnsafeWinInetCache.CommitUrlCacheEntryW(entry.Key, entry.Filename, entry.Info.ExpireTime, entry.Info.LastModifiedTime, entry.Info.EntryType, headerInfo, text.Length, null, entry.OriginalUrl))
296  {
297  entry.Error = (Status)Marshal.GetLastWin32Error();
298  }
299  }
300  return entry.Error;
301  }
302 
303  internal unsafe static Status Update(Entry newEntry, Entry_FC attributes)
304  {
305  byte[] array = new byte[EntryBuffer.MarshalSize];
306  newEntry.Error = Status.Success;
307  byte[] array2 = array;
308  fixed (byte* ptr = array2)
309  {
310  EntryBuffer* ptr2 = (EntryBuffer*)ptr;
311  *ptr2 = newEntry.Info;
312  ptr2->StructSize = EntryBuffer.MarshalSize;
313  if ((attributes & Entry_FC.Headerinfo) == Entry_FC.None)
314  {
315  if (!UnsafeNclNativeMethods.UnsafeWinInetCache.SetUrlCacheEntryInfoW(newEntry.Key, ptr, attributes))
316  {
317  newEntry.Error = (Status)Marshal.GetLastWin32Error();
318  }
319  }
320  else
321  {
322  Entry entry = new Entry(newEntry.Key, newEntry.MaxBufferBytes);
323  SafeUnlockUrlCacheEntryFile safeUnlockUrlCacheEntryFile = null;
324  bool flag = false;
325  try
326  {
327  safeUnlockUrlCacheEntryFile = LookupFile(entry);
328  if (safeUnlockUrlCacheEntryFile == null)
329  {
330  newEntry.Error = entry.Error;
331  return newEntry.Error;
332  }
333  newEntry.Filename = entry.Filename;
334  newEntry.OriginalUrl = entry.OriginalUrl;
335  newEntry.FileExt = entry.FileExt;
336  attributes &= ~Entry_FC.Headerinfo;
337  if ((attributes & Entry_FC.Exptime) == Entry_FC.None)
338  {
339  newEntry.Info.ExpireTime = entry.Info.ExpireTime;
340  }
341  if ((attributes & Entry_FC.Modtime) == Entry_FC.None)
342  {
343  newEntry.Info.LastModifiedTime = entry.Info.LastModifiedTime;
344  }
345  if ((attributes & Entry_FC.Attribute) == Entry_FC.None)
346  {
347  newEntry.Info.EntryType = entry.Info.EntryType;
348  newEntry.Info.U.ExemptDelta = entry.Info.U.ExemptDelta;
349  if ((entry.Info.EntryType & EntryType.StickyEntry) == EntryType.StickyEntry)
350  {
351  attributes |= (Entry_FC.Attribute | Entry_FC.ExemptDelta);
352  }
353  }
354  attributes &= ~(Entry_FC.Modtime | Entry_FC.Exptime);
355  flag = ((entry.Info.EntryType & EntryType.Edited) != (EntryType)0);
356  if (!flag)
357  {
358  entry.Info.EntryType |= EntryType.Edited;
359  if (Update(entry, Entry_FC.Attribute) != 0)
360  {
361  newEntry.Error = entry.Error;
362  return newEntry.Error;
363  }
364  }
365  }
366  finally
367  {
368  safeUnlockUrlCacheEntryFile?.Close();
369  }
370  Remove(entry);
371  if (Commit(newEntry) != 0)
372  {
373  if (!flag)
374  {
375  entry.Info.EntryType &= ~EntryType.Edited;
376  Update(entry, Entry_FC.Attribute);
377  }
378  return newEntry.Error;
379  }
380  if (attributes != 0)
381  {
382  Update(newEntry, attributes);
383  }
384  }
385  }
386  return newEntry.Error;
387  }
388 
389  internal static Status Remove(Entry entry)
390  {
391  entry.Error = Status.Success;
392  if (!UnsafeNclNativeMethods.UnsafeWinInetCache.DeleteUrlCacheEntryW(entry.Key))
393  {
394  entry.Error = (Status)Marshal.GetLastWin32Error();
395  }
396  return entry.Error;
397  }
398 
399  private unsafe static string GetEntryBufferString(void* bufferPtr, int offset)
400  {
401  if (offset == 0)
402  {
403  return null;
404  }
405  IntPtr ptr = new IntPtr((byte*)bufferPtr + offset);
406  return Marshal.PtrToStringUni(ptr);
407  }
408 
409  private unsafe static Status GetEntryHeaders(Entry entry, EntryBuffer* bufferPtr, byte[] buffer)
410  {
411  entry.Error = Status.Success;
412  entry.MetaInfo = null;
413  if (bufferPtr->_OffsetHeaderInfo == IntPtr.Zero || bufferPtr->HeaderInfoChars == 0 || (bufferPtr->EntryType & EntryType.UrlHistory) != 0)
414  {
415  return Status.Success;
416  }
417  int num = bufferPtr->HeaderInfoChars + (int)bufferPtr->_OffsetHeaderInfo / 2;
418  if (num * 2 > entry.MaxBufferBytes)
419  {
420  num = entry.MaxBufferBytes / 2;
421  }
422  while (*(ushort*)((byte*)bufferPtr + (long)(num - 1) * 2L) == 0)
423  {
424  num--;
425  }
426  entry.MetaInfo = Encoding.Unicode.GetString(buffer, (int)bufferPtr->_OffsetHeaderInfo, (num - (int)bufferPtr->_OffsetHeaderInfo / 2) * 2);
427  return entry.Error;
428  }
429  }
430 }
Represents a character encoding.To browse the .NET Framework source code for this type,...
Definition: Encoding.cs:15
unsafe string GetString(byte *bytes, int byteCount)
When overridden in a derived class, decodes a specified number of bytes starting at a specified addre...
Definition: Encoding.cs:1918
unsafe override string ToString()
Converts the value of this instance to a T:System.String.
The exception that is thrown when the execution stack overflows because it contains too many nested m...
static Encoding Unicode
Gets an encoding for the UTF-16 format using the little endian byte order.
Definition: Encoding.cs:975
Represents the base class for custom attributes.
Definition: Attribute.cs:15
LayoutKind
Controls the layout of an object when exported to unmanaged code.
Definition: LayoutKind.cs:7
Definition: __Canon.cs:3
static int SizeOf(object structure)
Returns the unmanaged size of an object in bytes.
Definition: Marshal.cs:159
For internal use only. The Framework will throw an T:System.ArgumentException if you try to use this ...
A platform-specific type that is used to represent a pointer or a handle.
Definition: IntPtr.cs:14
The exception that is thrown when there is not enough memory to continue the execution of a program.
Provides a collection of methods for allocating unmanaged memory, copying unmanaged memory blocks,...
Definition: Marshal.cs:15
CharSet
Dictates which character set marshaled strings should use.
Definition: CharSet.cs:7
Represents a mutable string of characters. This class cannot be inherited.To browse the ....
static unsafe string PtrToStringUni(IntPtr ptr, int len)
Allocates a managed T:System.String and copies a specified number of characters from an unmanaged Uni...
Definition: Marshal.cs:103
Represents errors that occur during application execution.To browse the .NET Framework source code fo...
Definition: Exception.cs:22
static readonly IntPtr Zero
A read-only field that represents a pointer or handle that has been initialized to zero.
Definition: IntPtr.cs:20
static int GetLastWin32Error()
Returns the error code returned by the last unmanaged function that was called using platform invoke ...
The exception that is thrown when a call is made to the M:System.Threading.Thread....
Use T:System.Runtime.InteropServices.ComTypes.FILETIME instead.
Definition: FILETIME.cs:5