Простой сценарий Perl для очистки кэша

Современные программы и операционные системы обеспечивают быстрый доступ к недавно использовавшимся данным и документам с помощью кэшируемых Web-страниц, списков ранее набранных фраз и списков часто используемых элементов (MRU). Все эти функции полезны, но иногда они занимают огромное количество дискового пространства и могут доставлять немало хлопот администратору, который вынужден защищать конфиденциальность пользовательских данных. Если подобные проблемы возникают, можно использовать сценарий на языке Perl CleanCache.p», приведенный в Листинге 8, для удаления большинства часто используемых кэшированных файлов в системе Windows и списков MRU. Я полагаю, что читатели имеют некоторое представление о языке Perl, а дополнительно c этим языком можно ознакомиться на сайте http://www.roth.net/perl.

Кэш Internet Explorer

Когда вы используете Microsoft Internet Explorer (IE) для навигации по Web-ресурсам, он сохраняет Web-страницы, графику, cookies-файлы, сценарии Java и другую загружаемую информацию на жесткий диск в область, обозначенную как кэш IE. Последующие обращения к объектам, сохраненным подобным образом, не требуют повторного соединения с Web-сервером. Это позволяет экономить время, которое затрачивается на установку соединения и загрузку, особенно при работе с объемными файлами. Однако правом использования кэша владеет не только IE. Точнее, данная область принадлежит библиотеке WinInet.dll. Эта библиотека предоставляет доступ по протоколам Web и FTP, а также функции кэширования. IE и другие приложения, такие как Microsoft Outlook Express и Windows Media Player (WMP), используют кэш библиотеки WinInet, поэтому кэш может содержать файлы с полезной информацией. Для просмотра списка содержимого кэша откройте приложение Internet Options в Control Panel, перейдите на вкладку General и нажмите кнопку Settings (под надписью «Temporary Internet files»). Далее нажмите кнопку View Files в окне диалогового окна Settings.

Кэш библиотеки WinInet состоит из двух компонентов: базы данных и контейнера. Контейнер – это каталог или набор каталогов, в которых размещаются кэшированные файлы. База данных содержит записи, которые отображают каждый из URL-адресов местоположения кэшированных элементов на диске. Когда вы загружаете файл с Web-ресурса, IE сохраняет файл в контейнере и добавляет запись-указатель в базу данных. Обычно контейнер кэша находится по адресу %systemroot%documents and settingsusernamelocal settings emporary internet files, где «username» - имя пользователя.

Очистить кэш достаточно легко – нужно лишь удалить кэшированные файлы из контейнера на жестком диске (обычно папка Temporary Internet Files) и удалить записи из базы данных. Однако записи базы данных кэша могут указывать не только на контейнер, но и на любой файл, в любом каталоге, на любом диске локальной системы или даже на удаленной системе. Поэтому если просто удалить все файлы из папки Temporary Internet Files, можно пропустить некоторые кэшированные файлы.

Кроме того, кэш библиотеки WinInet может хранить файлы, как по отдельности, так и группами. Следовательно, любой сценарий, чистящий кэш, должен запрашивать из базы данных кэша как отдельные файлы, так и группы файлов. Например, WMP может кэшировать потоковые данные с потокового сервера или постепенно загружать данные с Web-сервера. WMP хранит эти файлы группой в кэше библиотеки WinInet. Следовательно, если сценарий ищет и удаляет только файлы, он может пропустить группу кэшированных файлов WMP. Аналогично, чтобы удалить только те файлы, которые принадлежат WMP, необходим сценарий, который будет распознавать группу кэшированных файлов.

Более того, удаление кэшированных файлов не приводит к очистке базы данных кэша, для которой приложение (например, IE) или сценарий могут продолжать создание запросов. Для полной очистки кэша необходимо перебрать все записи в базе данных, после чего удалить каждый кэшированный файл и связанную с ним запись из базы данных. Библиотека WinInet предлагает функцию для перебора всех записей кэша и функцию DeleteUrlCacheEntry(), которая удаляет и сам кэшированный файл, и запись в базе данных кэша. Та же процедура требуется для удаления кэшированных данных cookies-файлов и информации по использованию браузера. Так как множество процессов могут использовать кэш библиотеки WinInet одновременно, файлы базы данных обычно находятся в открытом состоянии. Поэтому сценарий не может удалить текущие файлы базы данных. Вместо этого сценарий должен просто удалить информацию из файлов базы данных.

Временные файлы

Приложения генерируют все виды временных файлов. Хотя некоторые приложения при завершении работы автоматически удаляют свои временные файлы, многие программы оставляют их. Пакет Microsoft Word печально известен тем, что создает временные файлы и никогда их не удаляет.

Со временем накопленные временные файлы начинают занимать значительный объем дискового пространства, от нескольких килобайт до сотен мегабайт. Еще хуже то, что большинство этих файлов имеют маленький размер, и их хранение может привести к фрагментации более крупных файлов. Сильная фрагментация файла может снизить общую производительность системы (особенно если фрагментируется файл подкачки Windows) и послужить причиной чрезмерной загрузки жесткого диска. Поэтому периодическая очистка каталогов временных файлов очень желательна.

Временные файлы хранятся в двух местах: в каталоге Temporary Internet и в каталоге Temp. Как я пояснил выше, библиотека WinInet использует каталог Temporary Internet Files для хранения кэшированных файлов из Internet. В каталоге Temp хранятся временные файлы, создаваемые приложениями и операционной системой. Переменная окружения temp описывает точное местоположение папки Temp. Вы можете просмотреть эту переменную, выполнив команду Set в командной строке. В языке Perl можно использовать список %ENV с ключом TEMP - ENV{'TEMP'} – для получения пути к папке Temp. Для просмотра списка переменных окружения следует щелкнуть правой кнопкой мыши на ярлыке My Computer и выбрать пункт Properties. Затем перейдите на вкладку Advanced и нажмите кнопку Environment Variables. Удаление временных файлов сводится к удалению всех файлов из каталога Temp; удаление файлов из папки Temporary Internet Files, как я объяснил выше, является чуть более сложной задачей.

Другие данные

Несколько других типов данных могут создавать хаотичность в дисковом пространстве. Сценарий CleanCache.pl можно использовать для удаления следующих данных (часто путем простого удаления значений определенных подключей реестра):

Данные форм IE. IE может запоминать данные, которые пользователь вводит в Web-формы. Эта способность облегчает процесс заполнения форм. Запоминаемая информация располагается в подразделе реестра HKEY_CURRENT_USERSoftwareMicrosoftInternet ExplorerIntelliFormsSPW.

Список введенных адресов URL. Когда вы вводите адрес URL в строку адреса, IE сохраняет этот адрес в списке введенных адресов, из которого в дальнейшем можно выбирать ранее введенные адреса. Список введенных адресов располагается в разделе реестра HKEY_CURRENT_USERSoftwareMicrosoftInternet ExplorerTypedURLs.

Список MRU. Выбор в меню Start пункта Run открывает текстовое поле, в которое можно ввести команду или путь для запуска приложения. Это текстовое поле имеет ниспадающий список путей, введенных ранее. Данный список известен как список MRU. Список MRU удобен, так как не требуется целиком запоминать команду или путь, использованный ранее для запуска приложения. Однако любой, кто получит доступ к вашей учетной записи или разделу реестра, в котором содержатся настройки списка MRU, также сможет получить эту информацию. Список MRU располагается в подразделе реестра HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionExplorerRunMRU.

Список Recent File. Система Windows содержит список Recent File (также известный как список My Documents), который содержит все недавно загруженные файлы, аналогично тому, как список MRU отображает список недавно запущенных приложений. «Троянский конь» или вирус могут обратиться к списку Recent File для получения данных о рабочих привычках пользователя. На самом деле список представляет собой папку на жестком диске. Обычно это папка %systemdrive%documents and settingsuser- name ecent. Каталог содержит ярлыки (файлы .lnk), которые указывают на реальные файлы. Папка может содержать сотни записей, но система Windows отображает только короткий список файлов, доступ к которым осуществлялся недавно.

Корзины. Когда вы используете службу Windows Explorer для удаления файлов, система Windows сохраняет файлы в Корзине, чтобы при необходимости можно было восстановить их. Обычно своя корзина существует на каждом диске, а общая корзина располагается на рабочем столе. Корзины со временем начинают занимать довольно много места, и их следует периодически очищать.

Сценарий

Сценарий CleanCache.pl удаляет различные типы кэшируемых данных. Он полезен для очистки учетной записи на системе, чтобы другие пользователи не смогли узнать, к каким данным обращался тот или иной пользователь. Сценарий, на первый взгляд, может показаться сложным, но на самом деле он достаточно прост. Давайте рассмотрим наиболее важные части сценария.

Код, приведенный в Листинге 1, отображает работу с настройками. В этом разделе сценарий присваивает значения различным переменным. Я обнаружил большинство этих значений в документации Microsoft Developer Network (MSDN); остальные были получены методом проб и ошибок. Эта часть сценария находится в блоке "без ограничений", в котором отключено ограничение языка Perl, так что большинство определенных переменных, лексически не выделенных словом «my», не вызовут появления предупреждений при работе сценария.

Код, приведенный в Листинге 2, отображает загрузку различных библиотек для получения доступа к необходимым функциям. Данный сценарий будет использовать модуль Win32::API::Prototype для вызова этих функций, чтобы выполнить определенные задачи, такие как очистка Корзины (функция SHQueryRecycleBin()) и удаление записи из кэша (функция DeleteUrlCacheEntry()). Код, приведенный в Листинге 3, отображает вызов различных процедур для удаления файлов, значений подключей реестра и вызова функций операционной системы.

Процедура DeleteUrlCacheGroups перебирает группы кэша, которые находятся в базе данных кэша библиотеки WinInet. Далее сценарий получает информацию (например, используемый под группу объем дискового пространства) по каждой группе в кэше, как показано в коде Листинга 4. Имейте в виду, что в коде блока A в Листинге 4 для присвоения значений списку используется небольшая хитрость. Этот прием работает, так как порядок массива значений хорошо известен. Однако данный блок может вызвать ошибки, если не отменено применение ограничения для данного блока. Код в Листинге 5 отображает удаление файлов и очистку кэша (как я объяснил выше, предполагается, что сценарий создается именно для этого).

Процедура DeleteUrlCacheFiles делает практически то же самое, что и процедура DeleteUrlCacheGroups, но вместо групп из кэша удаляет отдельные записи и является более сложной, чем процедура DeleteUrlCacheGroups. Каждая запись в кэше содержит информацию и атрибуты, такие как дата и время кэширования файла, адрес URL и время истечения срока хранения файла. Каждая запись имеет свой размер, поэтому сценарий сначала адресует буфер размером 1Кбайт с помощью переменной $pCacheInfo. Код в Листинге 6 отображает начало процесса перебора, но при этом должен определять, достаточно ли выделенного буфера для хранения данных из записей. Если объем буфера недостаточен, сценарий производит повторное размещение буфера в памяти. Сценарий использует эту стратегию каждый раз при обращении к записи из кэша. Код в Листинге 7 демонстрирует использование технологии из Листинга 4 для распаковки данных из записи в список %Cache. После извлечения данных кэша сценарий определяет тип записи (то есть данные cookie-файлов, данные по использованным URL-адресам или кэшированный файл).

Процедура CleanDirectory осуществляет вызов системной функции SHGetFolderpath(). Используя значение идентификатора класса (CLSID), функция возвращает полный путь к специализированному каталогу (например, к папкам My Documents, Recent File или Temporary Internet Files). Дополнительную информацию о том, как сценарий получает пути, можно найти во врезке «Определение путей». Функция возвращает строку в кодировке Unicode, и код удаляет все символы NULL в строке. Выполнение этой операции может оказаться затруднительным для путей, в которых на самом деле используются символы Unicode. Далее процедура вызывает функцию CleanDirectoryAndFiles() для удаления файлов из данного каталога. Если удаление файлов выполнить невозможно, сценарий пытается переименовать файл, так, чтобы его было легко обнаружить при следующей очистке.

Процедура ClearRegistryKey() удаляет все значения из определенного подраздела реестра. Сценарий вызывает эту процедуру несколько раз для очистки списка MRU, данных форм IE и списка введенных адресов IE.

Процедура EmptyRecycleBin запрашивает статистику по Корзине на данной системе (например, какое количество файлов хранится в корзине) и очищает Корзины. Когда сценарий вызывает системную функцию SHEmptyRecycleBin() для очистки корзин, функция выставляет несколько флагов, чтобы предотвратить появление диалогового окна подтверждения. Флаги также подавляют любое звуковое оповещение об очистке корзины и появление диалогового окна, отображающего степень очистки корзины.

Работа со сценарием

Сценарий использует модуль Win32::API::Prototype, который можно установить, используя службу Perl Package Manager (PPM). Для этого в командную строку нужно ввести:

ppm install http://www.roth.net/perl/ 
packages/win32-api-prototype.ppd

Этот модуль использует расширение Win32-API, которое входит в стандартный набор пакета Perl от компании ActiveState. Вы также можете получить расширение по адресу http://dada.perl.it/#api и задействовать службу PPM для его установки с помощью команды:

ppm install win32-api

Когда мы запускаем сценарий без указания параметров, он собирает информацию об объеме дискового пространства, используемого кэшем, количестве кэшированных файлов, количестве элементов в списке MRU и так далее. В результате сценарий отобразит итоговые значения, но не удалит ни одного элемента и не очистит кэш. Если вы запускаете сценарий с параметром /v, результаты будут отображены подробно. Если вы запускаете сценарий с параметром /s, сценарий будет работать в скрытом режиме, не выдавая никакой информации. Данный параметр перекрывает параметр /v. Если вы запускаете сценарий с параметром /d, он удалит кэшированные файлы, очистит базу данных кэша и удалит другие названные выше типы данных.

Успех использования сценария зависит от количества приложений, имеющих доступ к базе данных кэша. Если другой процесс использует библиотеку WinInet, база данных кэша может быть очищена не полностью. Поэтому необходимо закрыть все сопроцессы IE, включая процессы, внедренные в другие приложения, такие как WMP Media Guide, перед запуском сценария. Кроме того, некоторые некорректно написанные приложения используют библиотеку WinInet и должны быть остановлены перед запуском сценария.

Также следует иметь в виду, что даже после запуска сценария с параметром /d список MRUWindows Explorer может казаться не очищенным. Windows Explorer загружает список MRU в память и не обязательно производит повторную загрузку с диска. Чтобы отобразить очищенный список MRU, нужно остановить и перезапустить Windows Explorer, завершив сеанс и заново зарегистрировавшись в системе.


Определение путей

Каждый пользователь имеет выделенный каталог со своим профилем. Этот профиль содержит индивидуальную информацию об учетной записи (например, Internet-закладки, раздел реестра, список Recent File, список My Documents, настройки программ). Обычно каталог с профилем является подкаталогом папки C:documents and settings и идентифицируется по имени пользователя. Например, пользователь с именем Ralph будет иметь профиль в папке C:documents and settings alph. Однако предположение, что недавно загруженные пользователем документы будут храниться в папке C:documents and settings alph ecent, может быть и неверным. Например, если пользователь имеет перемещаемый профиль, каталог с профилем может иметь адрес profile_serverusers alph.

В системе Windows есть специальная функция, SHGetFolderPath(), служащая для определения пути к папкам, таким как Temporary Internet Files и Recent File List. Когда вы вызываете эту функцию, необходимо указать значение папки, называемое идентификатором класса (CLSID), которое идентифицирует нужный каталог. Дополнительную информацию о значениях CLSID можно найти по адресу http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp.


ЛИСТИНГ 1. Присвоение значений переменным
$CACHEGROUP_SEARCH_ALL = 0x00000000;
$CACHEGROUP_FLAG_FLUSHURL_ONDELETE = 0x00000002;
$CACHEGROUP_ATTRIBUTE_GET_ALL = 0xffffffff;
$ERROR_NO_MORE_FILES = 18;
$ERROR_NO_MORE_ITEMS = 259;
$ERROR_INSUFFICIENT_BUFFER = 122;
$GROUPNAME_MAX_LENGTH = 120;
$GROUP_OWNER_STORAGE_SIZE = 4;
$CACHE_GROUP_STRUCT = "L5L$GROUP_OWNER_STORAGE_SIZE" . 
"A$GROUPNAME_MAX_LENGTH";
$KILOBYTE = 1024;
$MEGABYTE = 1024 * $KILOBYTE;
$GIGABYTE = 1024 * $MEGABYTE;
$TERABYTE = 1024 * $GIGABYTE;
$SHERB_NOCONFIRMATION = 0x00000001;
$SHERB_NOPROGRESSUI = 0x00000002;
$SHERB_NOSOUND= 0x00000004;
$QUERY_RECYCLE_BIN_STRUCT = "LL2L2";
$SHGFP_TYPE_CURRENT = 0;
$CSIDL_RECENT= 0x0008;
$CSIDL_INTERNET_CACHE = 0x0020;
$CSIDL_HISTORY= 0x0022;
$DELETED_FILE_RENAME_SUFFIX = ".OLD.DELETE.ME";
$SHERB_NOCONFIRMATION = 0x00000001;
$SHERB_NOPROGRESSUI = 0x00000002;
$SHERB_NOSOUND= 0x00000004;
$QUERY_RECYCLE_BIN_STRUCT = "LL2L2";
 
%REGISTRY_KEY = (
 'typed_url_list' => "SoftwareMicrosoftInternet
 ExplorerTypedURLs",
 'intelliforms_data' => "SoftwareMicrosoftInternet Explorer
IntelliFormsSPW",
 'explorer_run_mru' => "SoftwareMicrosoftWindowsCurrentVersion
ExplorerRunMRU",
);
 
%CACHE_ENTRY = (
 COOKIE => 0x00100000,
 NORMAL => 0x00000001,
 STICKY => 0x00000004,
 TRACK_OFFLINE => 0x00000010,
 TRACK_ONLINE => 0x00000020,
 URLHISTORY => 0x00200000,
 SPARSE => 0x00010000
);
 
%Time = ();
##########################################################################
#
# Set up the %Config global hash with default values and
# configure the %Config hash with user settings passed in.
#
%Config = (
 filter => $CACHE_ENTRY{COOKIE}
| $CACHE_ENTRY{STICKY}
| $CACHE_ENTRY{URLHISTORY}
| $CACHE_ENTRY{NORMAL},
);
 
Листинг 2. Загрузка библиотек
ApiLink( "wininet", "HANDLE FindFirstUrlCacheEntry(
 LPCTSTR lpszUrlSearchPattern,
 PVOID lpFirstCacheEntryInfo,
 LPDWORD lpdwFirstCacheEntryInfoBufferSize )" ) || die;
ApiLink( "wininet", "BOOL FindNextUrlCacheEntry(
 HANDLE hEnumHandle,
 PVOID lpNextCacheEntryInfo,
 LPWORD lpdwNextCacheEntryInfoBufferSize )" ) || die;
ApiLink( "wininet", "HANDLE FindFirstUrlCacheGroup(
 DWORD dwFlags,
 DWORD dwFilter,
 LPVOID lpSearchCondition,
 DWORD dwSearchCondition,
 LPVOID lpGroupId,
 LPVOID lpReserved )" ) || die;
ApiLink( "wininet", "BOOL FindNextUrlCacheGroup(
 HANDLE hFind,
 PVOID lpGroupId,
 LPVOID lpReserved )" ) || die;
ApiLink( "wininet", "BOOL DeleteUrlCacheGroup(
 DWORD GroupIdLo,
 DWORD GroupIdHi,
 DWORD dwFlags,
 LPVOID lpReserved )" ) || die;
ApiLink( "wininet", "BOOL GetUrlCacheGroupAttribute( 
 DWORD GroupIdLo,
 DWORD GroupIdHi,
 DWORD dwFlags,
 DWORD dwAttributes,
 PVOID lpGroupInfo,
 LPDWORD lpdwGroupInfo,
 LPVOID lpReserved )" ) || die;
ApiLink( "shell32", "HRESULT SHGetFolderPath(
 HWND hwndOwner,
 int nFolder,
 HANDLE hToken,
 DWORD dwFlags,
 LPTSTR pszPath )" ) || die;
ApiLink( "wininet", "BOOL FindCloseUrlCache( HANDLE hEnumHandle )" )
 || die;
ApiLink( "wininet", "BOOL DeleteUrlCacheEntry(LPCTSTR lpszUrlName)" )
 || die;
ApiLink( "shell32.dll", "HRESULT SHEmptyRecycleBin(
HWND hwnd,
LPSTR pszRootPath,
DWORD dwFlags
)" ) || die;
ApiLink( "shell32.dll", "HRESULT SHQueryRecycleBin(
 LPSTR pszRootPath,
 PVOID pSHQueryRBInfo
 )" ) || die;
 
Листинг 3. Вызов процедур для очистки данных
print "
Deleting cache groups.
" if( ! $Config{silent}
 && ( $Config{delete} 
|| $Config{verbose} ) );
DeleteUrlCacheGroups();
 
print "
Deleting cache files.
" if( ! $Config{silent}
  && ( $Config{delete} 
|| $Config{verbose} ) );
DeleteUrlCacheFiles();
 
print "
Deleting history files.
" if( ! $Config{silent}
 && ( $Config{delete} 
|| $Config{verbose} ) );
DeleteUrlHistory();
 
print "
Deleting recent files list.
" if( ! $Config{silent}
 && ( $Config{delete} 
|| $Config{verbose} ) );
DeleteRecentFileList();
 
print "
Deleting temporary files.
" if( ! $Config{silent}
 && ( $Config{delete} 
|| $Config{verbose} ) );
DeleteTempFiles();
 
print "
Deleting temporary Internet files.
" if(
 ! $Config{silent}
 && ( $Config{delete}
 || $Config{verbose} ) );
DeleteTempInternetFiles();
 
print "
Emptying recycle bins.
" if( ! $Config{silent}
 && ( $Config{delete} 
|| $Config{verbose} ) );
EmptyRecycleBin();
 
print "
Clearing IE forms data.
" if( ! $Config{silent}
 && ( $Config{delete} 
|| $Config{verbose} ) );
ClearFormData();
 
print "
Clearing IE typed URL list.
" if( ! $Config{silent}
 && ( $Config{delete} 
|| $Config{verbose} ) );
ClearTypedURLList();
 
print "
Clearing Explorer Run Most Recent Used (MRU) list.
"
 if( ! $Config{silent} 
&& ( $Config{delete} || $Config{verbose} ) );
ClearRunMRU();
 
Листинг 4. Получение информации о группах в кэше
 if( 0 != GetUrlCacheGroupAttribute( $GroupHi, $GroupLo, 0, 
$CACHEGROUP_ATTRIBUTE_GET_ALL,
 $pGroupInfo,
 $pdwGroupInfoSize,
 undef ) )
 {
 # Следующее значение присваивается для снятия ограничения
 и предотвращения появления предупреждений
 {
 no strict;
 @Group{
StructSize, Flags, Type,
DiskUsageKB, DiskQuotaKB, Temp} = unpack( "L5a*", $pGroupInfo );
}
 @{$Group{OwnerStorage}} = unpack( "L$GROUP_OWNER_STORAGE_SIZE", 
$Group{Temp} );
 ($Group{Name} ) = unpack( "@" x ( 4 * $GROUP_OWNER_STORAGE_SIZE )
 . "x16A*", 
$Group{Temp} );
 # Не обновляйте данные Total,если имя группы - "", и она занимает
 # 0 Кб на диске. Это может быть ошибкой в библиотеке WinInet.
 if( ! ( "" eq $Group{Name} && 0 == $Group{DiskUsageKB} ) )
 {
 print " Group Name: $Group{Name} (" . FormatNumberPretty(
 $Group{DiskUsageKB} * 
1024 ) . " bytes)
" if( $Config{verbose} );
 }
 }
Листинг 5. Очистка кэша
 if( $Config{delete} )
 {
 if( 0 != DeleteUrlCacheGroup( $GroupHi, $GroupLo, 
$CACHEGROUP_FLAG_FLUSHURL_ONDELETE, undef ) )
 {
 # Не обновляйте данные Total,если имя группы - "", и она занимает
 # 0 Кб на диске. Это может быть ошибкой в библиотеке WinInet
if( ! ( "" eq $Group{Name} && 0 == $Group{DiskUsageKB} ) )
 {
$Total{'Internet Cache Group'}->{_size} += $Group{DiskUsageKB} * 1024;
$Total{'Internet Cache Group'}->{_count}++;
 }
 }
 }
Листинг 6. Начало перебора записей
 my $hCache = FindFirstUrlCacheEntry( undef, $pCacheInfo, $pdwSize );
 if( 0 == $hCache && $ERROR_INSUFFICIENT_BUFFER == Win32::GetLastError() )
 {
 my $NewBufferSize = unpack( "L", $pdwSize );
 $pCacheInfo = pack( "C$NewBufferSize", 0 );
 $hCache = FindFirstUrlCacheEntry( undef, $pCacheInfo, $pdwSize );
 }
Листинг 7. Распаковка данных из записи
 my( $Temp, $dwHeaderSize ) = unpack( "A68L", $pCacheInfo );
 my $Result;
 my %Cache;
 # Следующее значение присваивается для снятия ограничения
 и предотвращения появления предупреждений
 {
 no strict;
 @Cache{
StructSize, SourceUrl, LocalFile,
CacheEntryType, UseCount, HitRate,
SizeLow, SizeHigh, LastModifiedTimeLow,
LastModifiedTimeHigh, ExpireTimeLow,
ExpireTimeHigh, LastAccessTimeLow,
LastAccessTimeHigh, LastSyncTimeLow,
LastSyncTimeHigh, HeaderInfo, HeaderSize,
FileExtension, Reserved, ExemptDelta
} = unpack( "Lp2L5L8P" . $dwHeaderSize . "LpL2", $pCacheInfo );
 }
 my $DeleteUrl = $Cache{SourceUrl};
 my $Type = "Internet Cache";
 if( $CACHE_ENTRY{COOKIE} & $Cache{CacheEntryType} )
 {
 $Type = "Internet Cookie";
 }
 elsif( $CACHE_ENTRY{URLHISTORY} & $Cache{CacheEntryType} )
 {
 $Type = "Internet History";
 }
 
Листинг 8. CleanCache.pl
 
##########################################################################
#
# CleanCache.pl
# -------------
# Этот сценарий удаляет все из кэша Windows Internet, в том числе
# кэшированные группы, кэшированные файлы, данные «cookies»,
 список использованных URL-адресов, временные файлы, 
# временные файлы из Internet, список истории использования
 и список недавно загруженных файлов
#
# Этот сценарий для работы требует наличия расширений Win32::API
 и Win32::API::Prototype,
# которые можно получить по адресам http://dada.perl.it/#api и
# http://www.roth.net/perl/packages, соответственно.
 
use Win32::API::Prototype;
use Win32::Registry;
use Getopt::Long;
use strict;
use vars qw( %Config %Total $VERSION %REGISTRY_KEY %Time %CACHE_ENTRY
$CACHEGROUP_SEARCH_ALL
$CACHEGROUP_FLAG_FLUSHURL_ONDELETE
$CACHEGROUP_ATTRIBUTE_GET_ALL
$ERROR_NO_MORE_FILES
$ERROR_NO_MORE_ITEMS
$ERROR_INSUFFICIENT_BUFFER
$GROUPNAME_MAX_LENGTH
$GROUP_OWNER_STORAGE_SIZE
$CACHE_GROUP_STRUCT
$KILOBYTE
$MEGABYTE
$GIGABYTE
$TERABYTE
$SHERB_NOCONFIRMATION 
$SHERB_NOPROGRESSUI 
$SHERB_NOSOUND 
$QUERY_RECYCLE_BIN_STRUCT
$SHGFP_TYPE_CURRENT
$CSIDL_RECENT
$CSIDL_INTERNET_CACHE 
$CSIDL_HISTORY 
$DELETED_FILE_RENAME_SUFFIX
$SHERB_NOCONFIRMATION 
$SHERB_NOPROGRESSUI 
$SHERB_NOSOUND
$QUERY_RECYCLE_BIN_STRUCT
);
 
##########################################################################
#
# Глобальные переменные, лексически не выделяются
#
$VERSION = 20030806;
 
$CACHEGROUP_SEARCH_ALL = 0x00000000;
$CACHEGROUP_FLAG_FLUSHURL_ONDELETE = 0x00000002;
$CACHEGROUP_ATTRIBUTE_GET_ALL = 0xffffffff;
$ERROR_NO_MORE_FILES = 18;
$ERROR_NO_MORE_ITEMS = 259;
$ERROR_INSUFFICIENT_BUFFER = 122;
$GROUPNAME_MAX_LENGTH = 120;
$GROUP_OWNER_STORAGE_SIZE = 4;
$CACHE_GROUP_STRUCT = "L5L$GROUP_OWNER_STORAGE_SIZE" . 
"A$GROUPNAME_MAX_LENGTH";
$KILOBYTE = 1024;
$MEGABYTE = 1024 * $KILOBYTE;
$GIGABYTE = 1024 * $MEGABYTE;
$TERABYTE = 1024 * $GIGABYTE;
$SHERB_NOCONFIRMATION = 0x00000001;
$SHERB_NOPROGRESSUI = 0x00000002;
$SHERB_NOSOUND= 0x00000004;
$QUERY_RECYCLE_BIN_STRUCT = "LL2L2";
$SHGFP_TYPE_CURRENT = 0;
$CSIDL_RECENT= 0x0008;
$CSIDL_INTERNET_CACHE = 0x0020;
$CSIDL_HISTORY= 0x0022;
$DELETED_FILE_RENAME_SUFFIX = ".OLD.DELETE.ME";
$SHERB_NOCONFIRMATION = 0x00000001;
$SHERB_NOPROGRESSUI = 0x00000002;
$SHERB_NOSOUND= 0x00000004;