блокировка файла без его открытия
От: TheRoSS  
Дата: 06.04.09 16:13
Оценка:
Добрый день, уважаемые гуру
Подскажите пожалуйста, как реализовать следующее:

У меня есть файлы, с которыми я работаю без открытия: переименовываю, копирую, удаляю и т.д.
У меня может быть несколько процессов, которые захотят проделать одни и те же операции над теми же самыми файлами.

Вопрос в том, как
1) Не дать другим процессам трогать файлы до тех пор, пока текущий процесс не закончит с ними работу. Другими словами, заблокировать их.
2) Заблокировав эти файлы, самому иметь возможность их удалять, копировать и т.д. То есть выполнять операции, которые делаются без открытия. Ведь, насколько я понимаю, открытие и последующая блокировка типа LockFile не даст мне самому использовать функции DeleteFile, MoveFile и тому подобные.


Вообще задача в следующем (может какое более интересное решение есть):
— Есть система клиент/сервер, которая поддерживает самообновление клиента (в виде подгружаемой из сети динамически линкуемой dll).
— Клиент встраивается в другую программу, которую при наличии обновления тормозить нельзя, как это делается в большинстве программ.
— Поэтому закаченное обновление кладётся рядом с работающим dll с добавлением .tmp (никто, кроме меня туда класть ничего не может, поэтому конфликта имён не боюсь)
— При старте программы она проверяет, есть ли файл file.dll.tmp, проверяет его версию и валидность, после чего файл file.dll удаляется, а файл file.dll.tmp переименовывается в file.dll. Всё бы хорошо, если бы не возможность запускать сразу несколько экземпляров программы (это нужно), в результате чего один процесс может вклиниться в обновление другого процесса и получить х.з. что. Как защитить весь процесс обновления от начала проверки file.dll.tmp до его переименования в file.dll? Может меня спасут какие-то другие локи помимо файловых? Как вообще лучше всего организовать такое обновление?
Re: блокировка файла без его открытия
От: dcb-BanDos Россия  
Дата: 06.04.09 20:22
Оценка:
Здравствуйте, TheRoSS, Вы писали:

TRS>Добрый день, уважаемые гуру

TRS>Подскажите пожалуйста, как реализовать следующее:

TRS>У меня есть файлы, с которыми я работаю без открытия: переименовываю, копирую, удаляю и т.д.

TRS>У меня может быть несколько процессов, которые захотят проделать одни и те же операции над теми же самыми файлами.

TRS>Вопрос в том, как

TRS>1) Не дать другим процессам трогать файлы до тех пор, пока текущий процесс не закончит с ними работу. Другими словами, заблокировать их.
TRS>2) Заблокировав эти файлы, самому иметь возможность их удалять, копировать и т.д. То есть выполнять операции, которые делаются без открытия. Ведь, насколько я понимаю, открытие и последующая блокировка типа LockFile не даст мне самому использовать функции DeleteFile, MoveFile и тому подобные.

я что-то не понимаю, зачем гадать, если в мсдн все написано:

If the call to LockFile completes synchronously, a completion entry may not be queued when a completion port is associated with the file handle.

The UnlockFile function unlocks a file region locked by LockFile.

Locking a region of a file gives the threads of the locking process exclusive access to the specified region using this file handle. If the file handle is inherited by a process created by the locking process, the child process is not granted access to the locked region. If the locking process opens the file a second time, it cannot access the specified region through this second handle until it unlocks the region.

Locking a region of a file does not prevent reading from a mapped file view.

You can lock bytes that are beyond the end of the current file. This is useful to coordinate adding records to the end of a file.

Locks may not overlap an existing locked region of the file.

If LockFile cannot lock a region of a file, it returns zero immediately. It does not block. To issue a file lock request that will block until the lock is acquired, use LockFileEx without LOCKFILE_FAIL_IMMEDIATELY.

If a process terminates with a portion of a file locked or closes a file that has outstanding locks, the locks are unlocked by the operating system. However, the time it takes for the operating system to unlock these locks depends upon available system resources. Therefore, it is recommended that your process explicitly unlock all files it has locked when it terminates. If this is not done, access to these files may be denied if the operating system has not yet unlocked them.

Ничто не ограничивает полет мысли программиста так, как компилятор.
Re[2]: блокировка файла без его открытия
От: Аноним  
Дата: 07.04.09 08:11
Оценка:
DB>я что-то не понимаю, зачем гадать, если в мсдн все написано:

DB>

DB>If the call to LockFile completes synchronously, a completion entry may not be queued when a completion port is associated with the file handle.

DB>The UnlockFile function unlocks a file region locked by LockFile.

DB>Locking a region of a file gives the threads of the locking process exclusive access to the specified region using this file handle. If the file handle is inherited by a process created by the locking process, the child process is not granted access to the locked region. If the locking process opens the file a second time, it cannot access the specified region through this second handle until it unlocks the region.

DB>Locking a region of a file does not prevent reading from a mapped file view.

DB>You can lock bytes that are beyond the end of the current file. This is useful to coordinate adding records to the end of a file.

DB>Locks may not overlap an existing locked region of the file.

DB>If LockFile cannot lock a region of a file, it returns zero immediately. It does not block. To issue a file lock request that will block until the lock is acquired, use LockFileEx without LOCKFILE_FAIL_IMMEDIATELY.

DB>If a process terminates with a portion of a file locked or closes a file that has outstanding locks, the locks are unlocked by the operating system. However, the time it takes for the operating system to unlock these locks depends upon available system resources. Therefore, it is recommended that your process explicitly unlock all files it has locked when it terminates. If this is not done, access to these files may be denied if the operating system has not yet unlocked them.


Проверил. Не катит.

Происходит следующее...
У меня есть два файла: file.dll и file.dll.tmp
При проверке этих файлов я их открываю и на каждый вешаю лок (хотя без лока происходит всё то же самое).
Если версия file.dll.tmp выше версии file.dll, я должен заменить file.dll на file.dll.tmp.
Функция MoveFileEx( file.dll.tmp, file.dll, MOVEFILE_REPLACE_EXISTING ) вылетает с ошибкой "Ошибка доступа"
Функция DeleteFile( file.dll ) файл не удаляет, а лишь помечает к удалению _ПОСЛЕ_ закрытия, и следовательно MoveFile опять выдаёт "Ошибку доступа".
Если перед удалением файл закрывать, упадёт блокировка.

То есть происходит именно то, о чём я писал в своём первом посте.
Re: блокировка файла без его открытия
От: mike_rs Россия  
Дата: 07.04.09 08:27
Оценка:
Здравствуйте, TheRoSS, Вы писали:

TRS>- При старте программы она проверяет, есть ли файл file.dll.tmp, проверяет его версию и валидность, после чего файл file.dll удаляется, а файл file.dll.tmp переименовывается в file.dll. Всё бы хорошо, если бы не возможность запускать сразу несколько экземпляров программы (это нужно), в результате чего один процесс может вклиниться в обновление другого процесса и получить х.з. что. Как защитить весь процесс обновления от начала проверки file.dll.tmp до его переименования в file.dll? Может меня спасут какие-то другие локи помимо файловых? Как вообще лучше всего организовать такое обновление?


перед началом переименования файлов создай глобальный мьютекс и залочь его. Если он уже создан, то просто залочь. Второй _твой_ процесс будет висеть на локе мьютекса пока первый (который смог залочить мьютекс) выполнить все файловые операции.
Re[2]: блокировка файла без его открытия
От: TheRoSS  
Дата: 07.04.09 08:36
Оценка:
Здравствуйте, mike_rs, Вы писали:

_>перед началом переименования файлов создай глобальный мьютекс и залочь его. Если он уже создан, то просто залочь. Второй _твой_ процесс будет висеть на локе мьютекса пока первый (который смог залочить мьютекс) выполнить все файловые операции.


Ага, спасибо, наверное так и сделаю
Re[3]: блокировка файла без его открытия
От: dcb-BanDos Россия  
Дата: 07.04.09 09:02
Оценка:
Здравствуйте, Аноним, Вы писали:

На сколько я понял, тебе нужна глобальная блокировка из нескольких процессов в момент апдейта, так воспользуйся именованным мьютексом и во всех процессах жди какое-то время
Ничто не ограничивает полет мысли программиста так, как компилятор.
Re: блокировка файла без его открытия
От: Аноним  
Дата: 07.04.09 09:29
Оценка:
CreateFile с эксклюзивным доступом
Вместо DeleteFile/MoveFile юзайте ZwSetInformationFile(..FileDispositionInformation/FileRenameInformation..)
Re[4]: блокировка файла без его открытия
От: TheRoSS  
Дата: 07.04.09 09:29
Оценка:
Здравствуйте, dcb-BanDos, Вы писали:

DB>Здравствуйте, Аноним, Вы писали:


DB>На сколько я понял, тебе нужна глобальная блокировка из нескольких процессов в момент апдейта, так воспользуйся именованным мьютексом и во всех процессах жди какое-то время


Угу, спасибо
Re[3]: блокировка файла без его открытия
От: Аноним  
Дата: 07.04.09 12:03
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Проверил. Не катит.


А>Происходит следующее...

А>У меня есть два файла: file.dll и file.dll.tmp
А>При проверке этих файлов я их открываю и на каждый вешаю лок (хотя без лока происходит всё то же самое).
А>Если версия file.dll.tmp выше версии file.dll, я должен заменить file.dll на file.dll.tmp.
А>Функция MoveFileEx( file.dll.tmp, file.dll, MOVEFILE_REPLACE_EXISTING ) вылетает с ошибкой "Ошибка доступа"

Потому что она пробует открыть файл повторно (а повторные открытия будут обламываться, о чём нам и говорит MSDN). Но если у нас есть HANDLE открытого с нужными правами файла — никто не мешает удалить/переместить его без повторных переоткрытий (см. native api, Nt(Zw)SetFileInformation).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.