// // Gets the headers and optionally other meta data out of a cached entry // // Whenever an empty line found in the buffer, the resulting array of // collections will grow in size // private static unsafe Status GetEntryHeaders(Entry entry, EntryBuffer *bufferPtr, byte[] buffer) { entry.Error = Status.Success; entry.MetaInfo = null; // if (bufferPtr->_OffsetHeaderInfo == IntPtr.Zero || bufferPtr->HeaderInfoChars == 0 || (bufferPtr->EntryType & EntryType.UrlHistory) != 0) { return(Status.Success); } int bufferCharLength = bufferPtr->HeaderInfoChars + ((int)(bufferPtr->_OffsetHeaderInfo)) / c_CharSz; if (bufferCharLength * c_CharSz > entry.MaxBufferBytes) { // WinInet bufferCharLength = entry.MaxBufferBytes / c_CharSz; } //WinInet may put terminating nulls at the end of the buffer, remove them. while (((char *)bufferPtr)[bufferCharLength - 1] == 0) { --bufferCharLength; } entry.MetaInfo = Encoding.Unicode.GetString(buffer, (int)bufferPtr->_OffsetHeaderInfo, (bufferCharLength - (int)bufferPtr->_OffsetHeaderInfo / 2) * 2); return(entry.Error); }
// // Gets the headers and optionally other meta data out of a cached entry // // Whenever an empty line found in the buffer, the resulting array of // collections will grow in size // private static unsafe Status GetEntryHeaders(Entry entry, EntryBuffer *bufferPtr, byte[] buffer) { entry.Error = Status.Success; entry.MetaInfo = null; // if (bufferPtr->_OffsetHeaderInfo == IntPtr.Zero || bufferPtr->HeaderInfoChars == 0 || (bufferPtr->EntryType & EntryType.UrlHistory) != 0) { return(Status.Success); } int bufferCharLength = bufferPtr->HeaderInfoChars + ((int)(bufferPtr->_OffsetHeaderInfo)) / c_CharSz; if (bufferCharLength * c_CharSz > entry.MaxBufferBytes) { // WinInet bug? They may report offset+HeaderInfoChars as a greater value than MaxBufferBytes as total buffer size. // Actually, the last one seems to be accurate based on the data we have provided for Commit. bufferCharLength = entry.MaxBufferBytes / c_CharSz; } //WinInet may put terminating nulls at the end of the buffer, remove them. while (((char *)bufferPtr)[bufferCharLength - 1] == 0) { --bufferCharLength; } entry.MetaInfo = Encoding.Unicode.GetString(buffer, (int)bufferPtr->_OffsetHeaderInfo, (bufferCharLength - (int)bufferPtr->_OffsetHeaderInfo / 2) * 2); return(entry.Error); }
private static unsafe Status EntryFixup(Entry entry, EntryBuffer *bufferPtr, byte[] buffer) { bufferPtr._OffsetExtension = (bufferPtr._OffsetExtension == IntPtr.Zero) ? IntPtr.Zero : ((IntPtr)((long)((((void *)bufferPtr._OffsetExtension) - bufferPtr) / 1))); bufferPtr._OffsetFileName = (bufferPtr._OffsetFileName == IntPtr.Zero) ? IntPtr.Zero : ((IntPtr)((long)((((void *)bufferPtr._OffsetFileName) - bufferPtr) / 1))); bufferPtr._OffsetHeaderInfo = (bufferPtr._OffsetHeaderInfo == IntPtr.Zero) ? IntPtr.Zero : ((IntPtr)((long)((((void *)bufferPtr._OffsetHeaderInfo) - bufferPtr) / 1))); bufferPtr._OffsetSourceUrlName = (bufferPtr._OffsetSourceUrlName == IntPtr.Zero) ? IntPtr.Zero : ((IntPtr)((long)((((void *)bufferPtr._OffsetSourceUrlName) - bufferPtr) / 1))); entry.Info = bufferPtr[0]; entry.OriginalUrl = GetEntryBufferString((void *)bufferPtr, (int)bufferPtr._OffsetSourceUrlName); entry.Filename = GetEntryBufferString((void *)bufferPtr, (int)bufferPtr._OffsetFileName); entry.FileExt = GetEntryBufferString((void *)bufferPtr, (int)bufferPtr._OffsetExtension); return(GetEntryHeaders(entry, bufferPtr, buffer)); }
// // Does the fixup of the returned buffer by converting internal pointer to offsets // it also does copying of non-string values from unmanaged buffer to Entry.Buffer members // unsafe private static Status EntryFixup(Entry entry, EntryBuffer *bufferPtr, byte[] buffer) { unchecked { bufferPtr->_OffsetExtension = bufferPtr->_OffsetExtension == IntPtr.Zero? IntPtr.Zero: (IntPtr)((byte *)bufferPtr->_OffsetExtension - (byte *)bufferPtr); bufferPtr->_OffsetFileName = bufferPtr->_OffsetFileName == IntPtr.Zero? IntPtr.Zero: (IntPtr)((byte *)bufferPtr->_OffsetFileName - (byte *)bufferPtr); bufferPtr->_OffsetHeaderInfo = bufferPtr->_OffsetHeaderInfo == IntPtr.Zero? IntPtr.Zero: (IntPtr)((byte *)bufferPtr->_OffsetHeaderInfo - (byte *)bufferPtr); bufferPtr->_OffsetSourceUrlName = bufferPtr->_OffsetSourceUrlName == IntPtr.Zero? IntPtr.Zero: (IntPtr)((byte *)bufferPtr->_OffsetSourceUrlName - (byte *)bufferPtr); // Get a managed EntryBuffer copy out of byte[] entry.Info = *bufferPtr; entry.OriginalUrl = GetEntryBufferString(bufferPtr, (int)(bufferPtr->_OffsetSourceUrlName)); entry.Filename = GetEntryBufferString(bufferPtr, (int)(bufferPtr->_OffsetFileName)); entry.FileExt = GetEntryBufferString(bufferPtr, (int)(bufferPtr->_OffsetExtension)); } return(GetEntryHeaders(entry, bufferPtr, buffer)); }
private static unsafe Status GetEntryHeaders(Entry entry, EntryBuffer *bufferPtr, byte[] buffer) { entry.Error = Status.Success; entry.MetaInfo = null; if (((bufferPtr._OffsetHeaderInfo == IntPtr.Zero) || (bufferPtr.HeaderInfoChars == 0)) || ((bufferPtr.EntryType & EntryType.UrlHistory) != 0)) { return(Status.Success); } int num = bufferPtr.HeaderInfoChars + (((int)bufferPtr._OffsetHeaderInfo) / 2); if ((num * 2) > entry.MaxBufferBytes) { num = entry.MaxBufferBytes / 2; } while (*(((ushort *)(bufferPtr + ((num - 1) * 2)))) == 0) { num--; } entry.MetaInfo = Encoding.Unicode.GetString(buffer, (int)bufferPtr._OffsetHeaderInfo, (num - (((int)bufferPtr._OffsetHeaderInfo) / 2)) * 2); return(entry.Error); }
// // Updates a Cached Entry metadata according to attibutes flags. // internal static Status Update(Entry newEntry, Entry_FC attributes) { // Currently WinInet does not support headers update, // hence don't need space for them although we'll need recreate a cache entry // if headers update is requested byte[] buffer = new byte[EntryBuffer.MarshalSize]; newEntry.Error = Status.Success; unsafe { fixed(byte *bytePtr = buffer) { EntryBuffer *ePtr = (EntryBuffer *)bytePtr; *ePtr = newEntry.Info; //set the version just in case ePtr->StructSize = EntryBuffer.MarshalSize; if ((attributes & Entry_FC.Headerinfo) == 0) { if (!UnsafeNclNativeMethods.UnsafeWinInetCache.SetUrlCacheEntryInfoW(newEntry.Key, bytePtr, attributes)) { newEntry.Error = (Status)Marshal.GetLastWin32Error(); } } else { // simulating headers update using Edited cache entry feature of WinInet Entry oldEntry = new Entry(newEntry.Key, newEntry.MaxBufferBytes); SafeUnlockUrlCacheEntryFile handle = null; bool wasEdited = false; try { // lock the entry and get the filename out. handle = LookupFile(oldEntry); if (handle == null) { //The same error would happen on update attributes, return it. newEntry.Error = oldEntry.Error; return(newEntry.Error); } //Copy strings from old entry that are not present in the method parameters newEntry.Filename = oldEntry.Filename; newEntry.OriginalUrl = oldEntry.OriginalUrl; newEntry.FileExt = oldEntry.FileExt; // We don't need to update this and some other attributes since will replace entire entry attributes &= ~Entry_FC.Headerinfo; //Copy attributes from an old entry that are not present in the method parameters if ((attributes & Entry_FC.Exptime) == 0) { newEntry.Info.ExpireTime = oldEntry.Info.ExpireTime; } if ((attributes & Entry_FC.Modtime) == 0) { newEntry.Info.LastModifiedTime = oldEntry.Info.LastModifiedTime; } if ((attributes & Entry_FC.Attribute) == 0) { newEntry.Info.EntryType = oldEntry.Info.EntryType; newEntry.Info.U.ExemptDelta = oldEntry.Info.U.ExemptDelta; if ((oldEntry.Info.EntryType & EntryType.StickyEntry) == EntryType.StickyEntry) { attributes |= (Entry_FC.Attribute | Entry_FC.ExemptDelta); } } // Those attributes will be taken care of by Commit() attributes &= ~(Entry_FC.Exptime | Entry_FC.Modtime); wasEdited = (oldEntry.Info.EntryType & EntryType.Edited) != 0; if (!wasEdited) { // Prevent the file from being deleted on entry Remove (kinda hack) oldEntry.Info.EntryType |= EntryType.Edited; // Recursion! if (Update(oldEntry, Entry_FC.Attribute) != Status.Success) { newEntry.Error = oldEntry.Error; return(newEntry.Error); } } } finally { if (handle != null) { handle.Close(); } } // At this point we try to delete the exisintg item and create a new one with the same // filename and the new headers. //We wish to ignore any errors from Remove since are going to replace the entry. Remove(oldEntry); if (Commit(newEntry) != Status.Success) { if (!wasEdited) { //revert back the original entry type oldEntry.Info.EntryType &= ~EntryType.Edited; Update(oldEntry, Entry_FC.Attribute); // Being already in error mode, cannot do much if Update fails. } return(newEntry.Error); } // Now see what's left in attributes change request. if (attributes != Entry_FC.None) { Update(newEntry, attributes); } //At this point newEntry.Error should contain the resulting status //and we replaced the entry in the cache with the same body //but different headers. Some more attributes may have changed as well. } } } return(newEntry.Error); }
internal static unsafe Status Update(Entry newEntry, Entry_FC attributes) { byte[] buffer = new byte[EntryBuffer.MarshalSize]; newEntry.Error = Status.Success; fixed(byte *numRef = buffer) { EntryBuffer *bufferPtr = (EntryBuffer *)numRef; bufferPtr[0] = newEntry.Info; bufferPtr->StructSize = EntryBuffer.MarshalSize; if ((attributes & Entry_FC.Headerinfo) == Entry_FC.None) { if (!UnsafeNclNativeMethods.UnsafeWinInetCache.SetUrlCacheEntryInfoW(newEntry.Key, numRef, attributes)) { newEntry.Error = (Status)Marshal.GetLastWin32Error(); } } else { Entry entry = new Entry(newEntry.Key, newEntry.MaxBufferBytes); SafeUnlockUrlCacheEntryFile file = null; bool flag = false; try { file = LookupFile(entry); if (file == null) { newEntry.Error = entry.Error; return(newEntry.Error); } newEntry.Filename = entry.Filename; newEntry.OriginalUrl = entry.OriginalUrl; newEntry.FileExt = entry.FileExt; attributes &= ~Entry_FC.Headerinfo; if ((attributes & Entry_FC.Exptime) == Entry_FC.None) { newEntry.Info.ExpireTime = entry.Info.ExpireTime; } if ((attributes & Entry_FC.Modtime) == Entry_FC.None) { newEntry.Info.LastModifiedTime = entry.Info.LastModifiedTime; } if ((attributes & Entry_FC.Attribute) == Entry_FC.None) { newEntry.Info.EntryType = entry.Info.EntryType; newEntry.Info.U.ExemptDelta = entry.Info.U.ExemptDelta; if ((entry.Info.EntryType & EntryType.StickyEntry) == EntryType.StickyEntry) { attributes |= Entry_FC.ExemptDelta | Entry_FC.Attribute; } } attributes &= ~(Entry_FC.Exptime | Entry_FC.Modtime); flag = (entry.Info.EntryType & EntryType.Edited) != 0; if (!flag) { entry.Info.EntryType |= EntryType.Edited; if (Update(entry, Entry_FC.Attribute) != Status.Success) { newEntry.Error = entry.Error; return(newEntry.Error); } } } finally { if (file != null) { file.Close(); } } Remove(entry); if (Commit(newEntry) != Status.Success) { if (!flag) { entry.Info.EntryType &= ~EntryType.Edited; Update(entry, Entry_FC.Attribute); } return(newEntry.Error); } if (attributes != Entry_FC.None) { Update(newEntry, attributes); } } } return(newEntry.Error); }