Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.04.05;
Скачать: CL | DM;

Вниз

Узнать хендлы открытых процессом файлов   Найти похожие ветки 

 
Виталий   (2008-04-10 14:57) [0]

Уважаемые мастера, подскажите пожалуйста как по номеру процесса получить хендлы и пути файлов, которые он открыл?
Если можно скажите какая последовательность вызовов функций  должна быть и какие точно функции для этого нужны

Заранее спасибо.


 
Виталий   (2008-04-10 14:57) [1]

О еще, может процессы где то в себе держат этот список, как его получить?


 
Сергей М. ©   (2008-04-10 15:12) [2]

И что ты с ними намерен делать ?

Ты их потерял что ли ?)


 
Виталий   (2008-04-10 15:43) [3]

Я хочу программно получить путь к файлу который открыт в Ворде.
Я запускаю свою программу нахожу процесс WinWord и хочу увидеть какой файл(ы) он открыл


 
Виталий   (2008-04-10 15:43) [4]

Это для сбора информации кто какой пользователь с чем работает


 
Сергей М. ©   (2008-04-10 16:14) [5]

Ты в курсе, что WinWord являет собой полноценный сервер OLE-автоматизации, (который способен сам сообщить о файлах, с которыми он работает, если его об этом спросят на его языке) ?

Или ты про такую слыхом не слыхивал ?


 
Виталий   (2008-04-10 16:36) [6]

В курсе, только мне не только ВинОфис нужно отлавливать а любую программу, окно которой активно в данный момент. Ворд это я к примеру.
Ладно Ворд не нравится, возьмем Сполайт. Он то не сообщит о себе.

Ты лучше скажи знаеш как это делать или как всегда в гугль идти?


 
Сергей М. ©   (2008-04-10 16:40) [7]

Ну раз ты на ходу меняешь формулировку задачи, то как всегда)


 
Riply ©   (2008-04-10 17:21) [8]

> [0] Виталий   (10.04.08 14:57)
> подскажите пожалуйста как по номеру процесса получить хендлы и пути файлов, которые он открыл?

Попробуй с помощью следующих функций:

NtQuerySystemInformation(..,SystemHandleInformation,..)
DuplicateHandle
NtQueryObject

P.S.
Возможно, вместо NtQuerySystemInformation, можно использовать NtQueryInformationProcess для конкретного процесса.
Не знаю, надо смотреть.


 
Riply ©   (2008-04-10 17:22) [9]

>  [8] Riply ©   (10.04.08 17:21)

P.P.S.
Будь осторожен с Pipe -ми :)


 
slow!alfamoon!com   (2008-04-10 18:14) [10]

Riply: вроде проблема с пайпами в сп2 решилась, или я неправильно помню?
Автор: http://slow.alfamoon.com/?module=filesdb&id=1&fid=12&get=1 только тут про сокеты, это тоже файлы, и для всех процессов, так что добавишь фильтрацию по PID нужного процесса


 
Riply ©   (2008-04-10 22:04) [11]

> [10] slow!alfamoon!com   (10.04.08 18:14)
> Riply: вроде проблема с пайпами в сп2 решилась, или я неправильно помню?

Давно это было, но до сих пор пайповая проблемма сидит у меня в голове с меткой "не решенная" :)
Напомни, пожалуйста, на основании чего ты считаешь, что она решилась ?


 
Виталий   (2008-04-11 12:47) [12]

Riply, slow!alfamoon!com - Спасибо за примеры. хоть кто-то не издевается, оказывается есть еще тут нормальные люди.

Собсно почитал МС-Рема и Багеля, и решил проблему. Кстати Пайпы меня не интересуют, только физические файлы.


 
Rouse_ ©   (2008-04-11 15:50) [13]

С пайпами проблема не решилась :) Как висели так и висят :) Надо просто уметь их идентифицировать :)


 
slow!alfamoon!com   (2008-04-11 15:57) [14]


> Напомни, пожалуйста, на основании чего ты считаешь, что
> она решилась ?
>

в каком-то обсуждении на wasm.ru вроде пробегало, надо посмотреть будет.


 
Riply ©   (2008-04-11 16:34) [15]

> [13] Rouse_ ©   (11.04.08 15:50)
> С пайпами проблема не решилась :) Как висели так и висят :) Надо просто уметь их идентифицировать :)

Сколько не билась над их идентификацией (имея на руках только информацию от NtQuerySystemInformation), ничего у меня не вышло :(.
На самом незначительном запросе - висла.
Саш, подскажи как надо делать.


 
slow!alfamoon!com   (2008-04-11 16:36) [16]

2 Riply собственно вариант решения это запрос в отдельном потоке, был предложен еще давно и ничего нового не придумано


 
Riply ©   (2008-04-11 16:42) [17]

> [16] slow!alfamoon!com   (11.04.08 16:36)
> 2 Riply собственно вариант решения это запрос в отдельном потоке,
> был предложен еще давно и ничего нового не придумано

Терминирование нити ?
Я не считаю это за "вариант решения". IMHO, так некузяво, что дальше некуда :)
Кто-то из форумчан хорошо по этому поводу сказал: "Ведь по живому режешь".
Я с ним согласна :)


 
Rouse_ ©   (2008-04-11 16:46) [18]


> Riply ©   (11.04.08 16:34) [15]

Т.к. нужно искать только файловые хэндлы, то перед вызовом NtQueryObject нужно сказать NtQueryInformationFile и проверить результат, если STATUS_SUCCESS, то повиснуть не должны ;)
Т.е. что-то вроде этого:

 function GetFileNameThread(lpParameters: Pointer): DWORD; stdcall;
 var
   FileNameInfo: FILE_NAME_INFORMATION;
   ObjectNameInfo: TOBJECT_NAME_INFORMATION;
   IoStatusBlock: IO_STATUS_BLOCK;
   pThreadParam: TGetFileNameThreadParam;
   dwReturn: DWORD;
 begin
   ZeroMemory(@FileNameInfo, SizeOf(FILE_NAME_INFORMATION));
   pThreadParam := PGetFileNameThreadParam(lpParameters)^;
   Result := NtQueryInformationFile(pThreadParam.hFile, @IoStatusBlock,
     @FileNameInfo, MAX_PATH * 2, FileNameInformation);
   if Result = STATUS_SUCCESS then
   begin
     Result := NtQueryObject(pThreadParam.hFile, ObjectNameInformation,
       @ObjectNameInfo, MAX_PATH * 2, @dwReturn);
     if Result = STATUS_SUCCESS then
     begin
       pThreadParam.Status := Result;
       WideCharToMultiByte(CP_ACP, 0,
         @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength -
         ObjectNameInfo.Name.Length],
         ObjectNameInfo.Name.Length, @pThreadParam.Data[0],
         MAX_PATH, nil, nil);
     end
     else
     begin
       pThreadParam.Status := STATUS_SUCCESS;
       Result := STATUS_SUCCESS;
       WideCharToMultiByte(CP_ACP, 0,
         @FileNameInfo.FileName[0], IoStatusBlock.Information,
         @pThreadParam.Data[0],
         MAX_PATH, nil, nil);
     end;
   end;
   PGetFileNameThreadParam(lpParameters)^ := pThreadParam;
   ExitThread(Result);
 end;

 function GetFileNameFromHandle(hFile: THandle): String;
 var
   lpExitCode: DWORD;
   pThreadParam: TGetFileNameThreadParam;
   hThread: THandle;
 begin
   Result := "";
   ZeroMemory(@pThreadParam, SizeOf(TGetFileNameThreadParam));
   pThreadParam.hFile := hFile;
   hThread := CreateThread(nil, 0, @GetFileNameThread, @pThreadParam, 0, PDWORD(nil)^);
   if hThread <> 0 then
   try
     case WaitForSingleObject(hThread, 100) of
       WAIT_OBJECT_0:
       begin
         GetExitCodeThread(hThread, lpExitCode);
         if lpExitCode = STATUS_SUCCESS then
           Result := pThreadParam.Data;
       end;
       WAIT_TIMEOUT:
         TerminateThread(hThread, 0);
     end;
   finally
     CloseHandle(hThread);
   end;
 end;


Я ж тебе помоемому давал уже этот код...


 
slow!alfamoon!com   (2008-04-11 17:02) [19]

2 Rouse_
NtQueryObject тоже виснет. На wasm.ru обсуждали

http://www.wasm.ru/forum/viewtopic.php?id=7728


 
Rouse_ ©   (2008-04-11 17:04) [20]

Ну не знаю... У меня этот код отрабатывает четко, ни одного срыва потока нет, хоть код и оставлен на всякий случай... Если без NtQueryInformationFile тогда виснет...


 
Rouse_ ©   (2008-04-11 17:07) [21]

А, ну понятно, там запрашивается FileModeInformation, а я прошу FileNameInformation :)


 
Riply ©   (2008-04-11 17:07) [22]

> [18] Rouse_ ©   (11.04.08 16:46)

> Т.к. нужно искать только файловые хэндлы, то перед вызовом NtQueryObject нужно сказать
> NtQueryInformationFile и проверить результат, если STATUS_SUCCESS, то повиснуть не должны ;)

Саш, насколько я помню, на самом запросе NtQueryInformationFile мы виснем с не меньшим успехом,
просто зависание не такое "глубокое" :)
Но нить терминировать все равно приходиться.
Могу еще раз проверить, если ошибаюсь.

P.S.
Кто-то говорил, что решил данную проблемму "путем анализа таблицы Handle`ов"
или что-то в этом духе. Не помню. Поиск по архивам старых веток ничего не дал.


 
Rouse_ ©   (2008-04-11 17:08) [23]

Проверь...


 
Riply ©   (2008-04-11 17:09) [24]

> [21] Rouse_ ©   (11.04.08 17:07)
> А, ну понятно, там запрашивается FileModeInformation, а я прошу FileNameInformation :)

Так. Бросаю все дела и иду проверять :)


 
Riply ©   (2008-04-11 17:10) [25]

>  [24] Riply ©   (11.04.08 17:09)

P.S.
Надеюсь что много времени это не займет :)


 
Rouse_ ©   (2008-04-11 17:26) [26]

Код у меня на сайте в разделе WinAPI возьми, чтоб самой не собирать...


 
Rouse_ ©   (2008-04-11 17:40) [27]

я сейчас изменил свой код на вот такой:

       WAIT_TIMEOUT:
       begin
         TerminateThread(hThread, 0);
         Result := "Thread terminated";
       end;


сработок не было :)


 
Riply ©   (2008-04-11 17:41) [28]

>  [26] Rouse_ ©   (11.04.08 17:26)
> Код у меня на сайте в разделе WinAPI возьми, чтоб самой не собирать...

Хорошо.

Пока протестила у себя (на своем коде).
Добавила проверку NtQueryInformationFile(FileNameInformation).
Не помогло:
Если пробегаться по всем процессам системы, то терминировать нить приходится 25-26 раз.

Сейчас скачаю оригинальный код и попробую тоже самое с ним.


 
Rouse_ ©   (2008-04-11 17:48) [29]

обманул я тебя :) действительно приходится срывать... оть-же... Не обращал на этот момент внимание... Там у меня логика работы, что ищется процесс и путь к файлу, если не находит - в лог ничего не выводиться... Блин... Лан будем думать...


 
Riply ©   (2008-04-11 18:00) [30]

> [29] Rouse_ ©   (11.04.08 17:48)
> обманул я тебя :)

А я уж было стала готовить отчет: чем твой пример компилировался, да на какой системе тестировался :)

> Лан будем думать...

Повторюсь: к сожалению, не помню кто с нашего форума (из мастеров)
говорил что решил проблемму "путем анализа таблицы Handle`ов". Или что-то в таком духе.


 
Riply ©   (2008-04-12 04:50) [31]

Вот ведь надо же было напоминать об этой проблемме.
Вместо того чтобы делом заниматься, Handl`ы тут перечисляю :)

Если кому интересно вот некоторые результаты:
Как я уже говорила, давным-давно пыталась найти хоть какой-то запрос,
на котором не виснем, и по результату (или по возвращаемой ошибке) которого
можно было бы хотя бы разбить объекты типа файл на две группы:
"Опасную" и "Безопасную".

В этом случае, для "Опасной" группы, если уж так приспичило создаем нить,
а с другой работаем "напрямую".

Меня постигла неудача - самые невинные запросы приводили к зависанию.
Сейчас я подумала, а может попробовать в запросе не напрямую,
а как-то косвенно обратиться к Handl`у ?
И вот что у меня получилось:

По аналогии с методикой, используемой в ReopenFile (подсказанной guav - ом),
попробуем запросить атрибуты у файла с пустым именем,
указав в качестве его родителя наш "подопытный" Handle.
Т.е. делаем вид, что он нас вовсе не интересует, а интересует только ребенок :)

var
EmptyName: UNICODE_STRING;
BaseInfo: FILE_BASIC_INFORMATION;
ObjectAttr: OBJECT_ATTRIBUTES;
begin
RtlInitUnicodeString(@EmptyName, nil);
InitializeObjectAttributes(@ObjectAttr, @EmptyName, OBJ_CASE_INSENSITIVE, pThreadParam.hFile, nil);
Result := NtQueryAttributesFile(@ObjectAttr, @BaseInfo);


Если Result = STATUS_SUCCESS, то (в зависимости от типа теста)
обходимся без нити, либо внутри нити не делаем запросы, ведущие к зависанию.

Результаты при пробежке по всем процессам системы:
RequestCount          1248 // Всего запросов для объектов типа FILE
SuccessRequestCount    801 // из них успешных
ErrorRequestCount      447 // и с ошибкой. Здесь, кроме файлов в стандартном понимании, еще куча всего :)

Итого в двух случаях из трех можно обойтись без нити.
И только треть остается под вопросом.
(Выигрыш по времени в разы :)

Тестирование на коде от Rouse дало более интересные результаты:
(У себя я шла по всем объектам без исключений и какой либо фильтрации )

Исходный код без изменений:
---------------------------
NameCount:  433
TickCount:  15015
TerminateCount:  25

Запрос нити для всех объектов, но внутри нити предварительная проверка на NtQueryAttributesFile
---------------------------
NameCount:  429
TickCount:  6000
TerminateCount:  0

Работаем вообще без нитей, основываясь на показаниях NtQueryAttributesFile :)
---------------------------
NameCount:  429
TickCount:  937
TerminateCount:  0

В последнем случае выигыш уже не в разы а на порядки, уж не говоря о "нерезаньи по-живому" :)

Есть маленькая неувязочка.
Мы потеряли четыре файла.
Кто они такие (может нормальные пайпы или еще кто) и почему потерялись,
оставляю изучение этого вопроса заинтересованным лицам. :)
Как подсказку к разбирательствам могу дать следующее:
я отбрасывала запрос на имя не анализируя результат.
Т.е если Result <> STATUS_SUCCESS, то бросала это дело.
На самом деле анализ может что-то подсказать.
Возвращаемые ошибки, которые удалось засечь:
STATUS_UNSUCCESSFUL, STATUS_INVALID_DEVICE_REQUEST, STATUS_INVALID_PARAMETER,
STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_NOT_SUPPORTED

Ну и напоследок приведу основные изменения Сашином коде,
которые надо сделать для тестирования описанного выше безобразия:

function GetFileNameDirect(hFile: THandle; var FileName: string): NTSTATUS; // - integer !!!
var
ObjectNameInfo: TOBJECT_NAME_INFORMATION;
dwReturn: DWORD;
// !!!! Это другое определение UNICODE_STRING, не как у Саши в данном примере
EmptyName: UNICODE_STRING;
BaseInfo: FILE_BASIC_INFORMATION;
ObjectAttr: OBJECT_ATTRIBUTES;
begin
 FileName := "";
 RtlInitUnicodeString(@EmptyName, nil);
 InitializeObjectAttributes(@ObjectAttr, @EmptyName, OBJ_CASE_INSENSITIVE, hFile, nil);
 Result := NtQueryAttributesFile(@ObjectAttr, @BaseInfo);
 if Result = STATUS_SUCCESS then
  begin
   Result := NtQueryObject(hFile, ObjectNameInformation,
                           @ObjectNameInfo, MAX_PATH * 2, @dwReturn);
   if Result = STATUS_SUCCESS then
    begin
     SetLength(FileName, MAX_PATH);
     WideCharToMultiByte(CP_ACP, 0, @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength -
         ObjectNameInfo.Name.Length], ObjectNameInfo.Name.Length, PChar(FileName),
         MAX_PATH, nil, nil);
    end
  end;
end;


Чуть измененная GetFileNameThread:

function GetFileNameThread(lpParameters: Pointer): DWORD; stdcall;
var
FileNameInfo: FILE_NAME_INFORMATION;
ObjectNameInfo: TOBJECT_NAME_INFORMATION;
IoStatusBlock: IO_STATUS_BLOCK;
pThreadParam: TGetFileNameThreadParam;
dwReturn: DWORD;
// !!!! Это другое определение UNICODE_STRING, не как у Саши в данном примере
EmptyName: UNICODE_STRING;
BaseInfo: FILE_BASIC_INFORMATION;
ObjectAttr: OBJECT_ATTRIBUTES;
begin
ZeroMemory(@FileNameInfo, SizeOf(FILE_NAME_INFORMATION));
pThreadParam := PGetFileNameThreadParam(lpParameters)^;

// RtlInitUnicodeString(@EmptyName, nil);
// InitializeObjectAttributes(@ObjectAttr, @EmptyName, OBJ_CASE_INSENSITIVE, pThreadParam.hFile, nil);
// Result := NtQueryAttributesFile(@ObjectAttr, @BaseInfo);
   Result := STATUS_SUCCESS;// Для теста внутри нити закоментировать эту строчку и открыть предыдущие

 if Result = STATUS_SUCCESS then
  begin
   // Не убирайте эту строчку - на ней зависание не такое "глубокое"  :)
   if GetFileType(pThreadParam.hFile) <> FILE_TYPE_PIPE
    then Result := NtQueryInformationFile(pThreadParam.hFile, @IoStatusBlock,
                                    @FileNameInfo, MAX_PATH * 2, FileNameInformation);

   if Result = STATUS_SUCCESS then
    begin
     Result := NtQueryObject(pThreadParam.hFile, ObjectNameInformation,
                             @ObjectNameInfo, MAX_PATH * 2, @dwReturn);
     if Result = STATUS_SUCCESS then
      begin
       pThreadParam.Status := Result;
       WideCharToMultiByte(CP_ACP, 0,
         @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength -
         ObjectNameInfo.Name.Length],
         ObjectNameInfo.Name.Length, @pThreadParam.Data[0],
         MAX_PATH, nil, nil);
      end
     else
      begin
       pThreadParam.Status := STATUS_SUCCESS;
       Result := STATUS_SUCCESS;
       WideCharToMultiByte(CP_ACP, 0,
         @FileNameInfo.FileName[0], IoStatusBlock.Information,
         @pThreadParam.Data[0],
         MAX_PATH, nil, nil);
      end;
    end;
  end;

 PGetFileNameThreadParam(lpParameters)^ := pThreadParam;
 ExitThread(Result);
end;


Изменения в главной процедуре:
if GetFileNameDirect(hFile, FilePath) <> STATUS_SUCCESS
then ;//FilePath := GetFileNameFromHandle(hFile);


Уфф... Вроде все.

В заключении хочу сказать, что то что у меня не нашлось объектов,
на которых NtQueryAttributesFile ведет к зависанию, вовсе не означает,
что их не существует :)


 
Игорь Шевченко ©   (2008-04-12 12:03) [32]

Riply ©   (12.04.08 04:50) [31]

Можно нескромный вопрос - а нафига такие извращения ?
Все равно ты не получишь со 100% гарантией список открытых файлов (хендлов) чужого (да и своего тоже) процесса, к чему мучиться ?

Я просто к чему - сам страдал в свое время ерундой, потом сообразил, что лучше самодвижущееся пресс-папье изобрести.

Кому надо узнать список открытых хендлов, нехай запустит handles.exe или Process Explorer, авторы этих инструментов известны, а главное, применяют в корне другой подход.

И это правильно.


 
Riply ©   (2008-04-12 17:07) [33]

> [32] Игорь Шевченко ©   (12.04.08 12:03)
> Все равно ты не получишь со 100% гарантией список открытых файлов (хендлов) чужого (да и своего тоже) процесса, к чему мучиться ?

Когда FileExists возвращает False это не означает что файл не существует, imho. Зачем она нужна ? :)

> Можно нескромный вопрос - а нафига такие извращения ?

Вопрос скромный :)
Начнем с того, что свой блок для работы с Handl`ми (не обязательно "файловыми") я написала только для
себя и не собираюсь его предлагать другим.
Не потому что жадная, а потому что нехай запустит "handles.exe или Process Explorer". :)
Мой блок работает так как надо мне и умеет то, что нужно мне.
А чтобы что-то работало так как надо ее величеству Riply, может написать только Riply :)
И он мне в работе неоднократно помогал в работе.  
Это раз.

Второе:
мне очень не нравиться, когда у меня за спиной висят нерешенные задачи.
А я люблю себя чуствовать комфортно. :)

Третье:
этот вопрос интересует многих и мне будет приятно, если мое решение окажется правильным и принесет кому-то пользу :)

Четвертое:
Во время "страдания ерундой" я лучше начинаю понимать (чуствовать) как работает система
и получаю новые знания.


Есть еще пятое, шестое и т.д. Если будет интересно, продолжу перечисление :)

Вот так и получается, Игорь, что все это я делала для себя любимой :)


 
Riply ©   (2008-04-12 17:10) [34]

> [33] Riply ©   (12.04.08 17:07)

Нулевой пункт забыла:

Мне интересно !  :)


 
Игорь Шевченко ©   (2008-04-12 23:52) [35]

Riply ©   (12.04.08 17:07) [33]

Я к чему - и Process Explorer и handles.exe используют для получения информации ядерный драйвер.

Как ты понимаешь, и Руссиновичу и брату его во Христе Когсуэллу тоже интересно "как это там система работает", весьма вероятно, что было интересно даже больше, чем тебе. Следовательно, они пришли к выводу, что попытки получить такую информацию из пользовательского режима рано или поздно закончатся неудачей. Вот и Шрайбер тоже рекомендует для получения информации пользоваться драйвером - у него, у драйвера, возможностей больше - можно читать напрямую те же таблицы, из которых получается информация, возвращаемая NtQueryxxxxx, и главное, что в это время тебе никто не мешает. А от вызова NtQueryxxxx до вызова NtQueryzzzz в системе может произойти масса событий, в результате чего информация собранная обоими вызовами будет настолько не соответствовать действительности, что потеряет всякий смысл.


 
Riply ©   (2008-04-13 00:54) [36]

> [35] Игорь Шевченко ©   (12.04.08 23:52)

Вынуждена полностью согласиться со всеми утверждениями.
К сожалению, до написания драйвера я еще не доросла. Уровень не тот :(
Правда, "еще не вечер" :)

А пока идет обучение, вынуждена довольствоваться тем,
что удается получить в пользовательском режиме :)


 
Игорь Шевченко ©   (2008-04-13 00:59) [37]


> К сожалению, до написания драйвера я еще не доросла. Уровень
> не тот :(


Да это несложно. Покупается/ищется книга Свена Шрайбера "Недокументированные возможности Windows 2000" - там как раз таких драйверов, которые читают ядерные таблицы, штук несколько, и по шагам расписано их написание. Я серьезно.


 
Riply ©   (2008-04-13 01:22) [38]

> [37] Игорь Шевченко ©   (13.04.08 00:59)
> Да это несложно. Покупается/ищется книга Свена Шрайбера "Недокументированные возможности Windows 2000" -
> там как раз таких драйверов, которые читают ядерные таблицы, штук несколько, и по шагам расписано их написание.
> Я серьезно.

Ой, Игорь, я ведь могу последовать совету и сунуться в эту область :)
И дорги назад уже не будет. Уж я то себя знаю. Так и завязну там :)



Страницы: 1 вся ветка

Текущий архив: 2009.04.05;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.015 c
2-1234415459
SyS
2009-02-12 08:10
2009.04.05
Сворачивание вторичных форм приложения в трей


15-1233847881
Илья_
2009-02-05 18:31
2009.04.05
Красивые рисунки с эффектом стеклянной поверхности


15-1233422138
blackman
2009-01-31 20:15
2009.04.05
Отстал от жизни.


15-1233843683
Городской Шаман
2009-02-05 17:21
2009.04.05
Дал бы я всем этим "экологам" по 15 суток на шахте Засядько.


11-1199012224
=BuckLr=
2007-12-30 13:57
2009.04.05
С новым годом!