"""
This demonstrates the creation of miniversions of a file during a transaction.
The FSCTL_TXFS_CREATE_MINIVERSION control code saves any changes to a new
miniversion (effectively a savepoint within a transaction).
"""

import win32file, win32api, win32transaction
import win32con, winioctlcon
import struct
import os
from pywin32_testutil import str2bytes # py3k-friendly helper

"""
Definition of buffer used with FSCTL_TXFS_CREATE_MINIVERSION:
typedef struct _TXFS_CREATE_MINIVERSION_INFO{
	USHORT StructureVersion;  
	USHORT StructureLength;
	ULONG BaseVersion;
	USHORT MiniVersion;}
"""
buf_fmt='HHLH0L'   ## buffer size must include struct padding
buf_size=struct.calcsize(buf_fmt)

tempdir=win32api.GetTempPath()
tempfile=win32api.GetTempFileName(tempdir,'cft')[0]
print "Demonstrating transactions on tempfile", tempfile
f=open(tempfile,'w')
f.write('This is original file.\n')
f.close()

trans=win32transaction.CreateTransaction(Description='Test creating miniversions of a file')
hfile=win32file.CreateFileW(tempfile, win32con.GENERIC_READ|win32con.GENERIC_WRITE,
    win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE,
    None, win32con.OPEN_EXISTING, 0 , None, Transaction=trans)

win32file.WriteFile(hfile, str2bytes('This is first miniversion.\n'))
buf=win32file.DeviceIoControl(hfile, winioctlcon.FSCTL_TXFS_CREATE_MINIVERSION,None,buf_size,None)
struct_ver, struct_len, base_ver, ver_1=struct.unpack(buf_fmt, buf)

win32file.SetFilePointer(hfile, 0, win32con.FILE_BEGIN)
win32file.WriteFile(hfile, str2bytes('This is second miniversion!\n'))
buf=win32file.DeviceIoControl(hfile, winioctlcon.FSCTL_TXFS_CREATE_MINIVERSION,None,buf_size,None)
struct_ver, struct_len, base_ver, ver_2=struct.unpack(buf_fmt, buf)
hfile.Close()

## miniversions can't be opened with write access
hfile_0=win32file.CreateFileW(tempfile, win32con.GENERIC_READ,
    win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE,
    None, win32con.OPEN_EXISTING, 0 , None, Transaction=trans, MiniVersion=base_ver)
print 'version:',base_ver,win32file.ReadFile(hfile_0, 100)
hfile_0.Close()

hfile_1=win32file.CreateFileW(tempfile, win32con.GENERIC_READ,
    win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE,
    None, win32con.OPEN_EXISTING, 0 , None, Transaction=trans, MiniVersion=ver_1)
print 'version:',ver_1,win32file.ReadFile(hfile_1, 100)
hfile_1.Close()

hfile_2=win32file.CreateFileW(tempfile, win32con.GENERIC_READ,
    win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE,
    None, win32con.OPEN_EXISTING, 0 , None, Transaction=trans, MiniVersion=ver_2)
print 'version:',ver_2,win32file.ReadFile(hfile_2, 100)
hfile_2.Close()

## MiniVersions are destroyed when transaction is committed or rolled back
win32transaction.CommitTransaction(trans)

os.unlink(tempfile)
