Принудительное закрытие открытых по сети файлов (на удалённой Windows-машине)

14 Сен
2011

Если вы счастливый обладатель сетевого файлового хранилища, которое приходится время от времени обновлять, то наверняка сталкивались с ситуацией, когда файл кем-то открыт и не поддаётся на призывы к уничтожению. Задача легко решается через консоль управлению (System Tools\Shared folders\Open files, можно и с удалённой машины), но если менять приходится часто, а отключать не все файлы, то это может быть утомительно.
Хочу вынести на суд почтеннейшей публики скрипт по автоматизации этого безобразия.
Весь дальнейший текст и код — пляски вокруг OpenFiles. Написано на питоне (во-первых, из спортивного интереса, во-вторых, из-за регулярных выражений и прочего сахара).

В силу специфики моей задачи код выбирает файлы, пути к которым удовлетворяют шаблону (заданному регулярным выражением) и группирует их по части этого пути (в коде эта часть условно именуется client). Так же перед закрытием показываются логины пользователей, открывших файлы, и спрашивается подтверждение на закрытие (чтобы можно было устроить адресную рассылку перед расстрелом).
# encoding: utf-8
# Python 3.1
import subprocess, csv, re, collections

# Имя удалённой машины
serverName = 'ServerName'

# Запускаем нужный процесс и читаем результаты в формате csv
# universal_newlines - открыть в text-mode, нужно для cvs
process = subprocess.Popen('OpenFiles.exe /query /S {0} /FO CSV'.format( serverName ),
    stdout = subprocess.PIPE, universal_newlines = True)
reader = csv.reader( process.stdout )

# Шаблон для файлов (локальные пути на удалённой машине)
pattern = re.compile( r'x:\\local\\path\\(\w+)\\\w+\.\w+', re.IGNORECASE )

# Перебираем открытые дескрипторы
clientUsers = collections.defaultdict(list) # client -> user
openedIds = []
for fileId, user, system, path in reader:
    # Проверяем, что это наш клиент (по пути к файлу)
    processPathParts = pattern.match( path )
    if processPathParts is None : continue # не попали в нужный процесс
    # Группируем по типу открытого ресурса
    client = processPathParts.group( 1 ).lower()
    clientUsers[client].append(user) # выписываем пользователей для всех клиентов
    openedIds.append( fileId )

# Перечисляем все открытые файлы и пользователей на них
for client in clientUsers:
    print( '{0}: {1}'.format( client, ','.join( set( clientUsers[client] ) ) ) )
print( 'Всего открыто файлов: {0}'.format( len( openedIds ) ) )

# Спросим разрешения на отключение
answer = input('Отключить их (y/yes/n/no)?: ')
if answer.lower() not in ('y', 'yes') :
    print( 'Отмена' )
    exit(0)

print( 'Отключаем...' )
for fileId in openedIds:
    process = subprocess.Popen( 'OpenFiles.exe /disconnect /S {0} /ID {1}'.format( serverName, fileId ),
        stdout = subprocess.PIPE, stderr = subprocess.STDOUT, universal_newlines = True )
    text, error = process.communicate()
    if process.wait() != 0:
        print( 'Ошибка при закрытии файла {0}'.format( fileId ) )
        print( text )
print( 'Готово' )

Disclaimer: я знаю, что так грубо обрубать доступ к файлам не есть хорошо, но иногда этого достаточно (файлы открыты только на чтение, закрытие не приведёт к потере сделанной работы).
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх