-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathjournalcmd.py
117 lines (102 loc) · 4.09 KB
/
journalcmd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import struct
import win32file
import winioctlcon
import win32api
import winerror
import pywintypes
USN_BUFFER_SIZE = 4096
JOURNAL_MAX_SIZE = 16*1048576
JOURNAL_ALLOCATION_DELTA = 65536
def open_volume(drive):
volh = win32file.CreateFile('\\\\.\\' + drive, win32file.GENERIC_READ,
win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, None,
win32file.OPEN_EXISTING, win32file.FILE_ATTRIBUTE_NORMAL, None)
return volh
def close_volume(volh):
win32file.CloseHandle(volh)
def create_journal(volh):
inp = struct.pack('QQ', JOURNAL_MAX_SIZE, JOURNAL_ALLOCATION_DELTA)
win32file.DeviceIoControl(volh, winioctlcon.FSCTL_CREATE_USN_JOURNAL, inp, None)
def query_journal(volh):
fmt = 'QQQQQQQ'
len = struct.calcsize(fmt)
buf = win32file.DeviceIoControl(volh, winioctlcon.FSCTL_QUERY_USN_JOURNAL, None, len)
tup = struct.unpack(fmt, buf)
return tup
def get_ntfs_volume_data(volh):
fmt = 'qqqqqLLLLqqqqq'
len = struct.calcsize(fmt)
buf = win32file.DeviceIoControl(volh, winioctlcon.FSCTL_GET_NTFS_VOLUME_DATA, None, len)
tup = struct.unpack(fmt, buf)
return tup
def get_volume_info(drive):
return win32api.GetVolumeInformation('\\\\.\\' + drive + '\\')
def decode_usn_record(buf):
outfmt = 'LHHQQQQLLLLHH'
outlen = struct.calcsize(outfmt)
tup = struct.unpack(outfmt, buf[:outlen])
recordlen = tup[0]
filenamelen = tup[11]
filenameoffset = tup[12]
name1 = buf[filenameoffset:filenameoffset+filenamelen]
name = name1.decode('UTF-16', 'replace')
return recordlen, tup, name
def decode_usn_data(buf):
headfmt = 'Q'
headlen = struct.calcsize(headfmt)
head_usn = struct.unpack(headfmt, buf[:headlen])[0]
buf = buf[headlen:]
tups = []
while len(buf) > 0:
recordlen, tup, name = decode_usn_record(buf)
tups.append((tup, name))
buf = buf[recordlen:]
return head_usn, tups
ALL_INTERESTING_CHANGES = (winioctlcon.USN_REASON_BASIC_INFO_CHANGE | winioctlcon.USN_REASON_CLOSE
| winioctlcon.USN_REASON_DATA_EXTEND | winioctlcon.USN_REASON_DATA_OVERWRITE | winioctlcon.USN_REASON_DATA_TRUNCATION
| winioctlcon.USN_REASON_FILE_CREATE | winioctlcon.USN_REASON_FILE_DELETE
| winioctlcon.USN_REASON_RENAME_NEW_NAME | winioctlcon.USN_REASON_RENAME_OLD_NAME)
def read_journal(volh, journal_id, first_usn):
reason_mask = ALL_INTERESTING_CHANGES
inp = struct.pack('QLLQQQ', first_usn, reason_mask, 0, 0, 0, journal_id)
buf = win32file.DeviceIoControl(volh, winioctlcon.FSCTL_READ_USN_JOURNAL, inp, USN_BUFFER_SIZE)
return decode_usn_data(buf)
def enum_usn_data(volh, first_frn, low_usn, high_usn):
inp = struct.pack('QQQ', first_frn, low_usn, high_usn)
try:
buf = win32file.DeviceIoControl(volh, winioctlcon.FSCTL_ENUM_USN_DATA, inp, USN_BUFFER_SIZE)
except pywintypes.error, ex:
if ex.args[0] == winerror.ERROR_HANDLE_EOF:
return None, []
raise
head_usn = struct.unpack('Q', buf[:8])[0]
return decode_usn_data(buf)
def generate_journal(volh, journal_id, first_usn):
while True:
try:
first_usn, tups = read_journal(volh, journal_id, first_usn)
except pywintypes.error, ex:
if ex.winerror == 1181: # ERROR_JOURNAL_ENTRY_DELETED
break
raise
if len(tups) == 0:
break
for t,n in tups:
yield t,n
def generate_usns(volh, low_usn, high_usn):
frn_pos = 0
while True:
next_frn, tups = enum_usn_data(volh, frn_pos, low_usn, high_usn)
if len(tups) == 0:
break
for t,n in tups:
yield frn_pos,t,n
frn_pos = next_frn
def read_file_usn(path):
fileh = win32file.CreateFile(path, win32file.GENERIC_READ,
win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, None,
win32file.OPEN_EXISTING, win32file.FILE_ATTRIBUTE_NORMAL, None)
buf = win32file.DeviceIoControl(fileh, winioctlcon.FSCTL_READ_FILE_USN_DATA, None, USN_BUFFER_SIZE)
win32file.CloseHandle(fileh)
recordlen, tups, name = decode_usn_record(buf)
return tups, name