BackupSeek_streamheaders.py 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. ## demonstrates using BackupSeek to enumerate data streams for a file
  2. import win32file, win32api, win32con
  3. from win32com import storagecon
  4. import pythoncom, pywintypes
  5. import struct, traceback
  6. stream_types={
  7. win32con.BACKUP_DATA:"Standard data",
  8. win32con.BACKUP_EA_DATA:"Extended attribute data",
  9. win32con.BACKUP_SECURITY_DATA:"Security descriptor data",
  10. win32con.BACKUP_ALTERNATE_DATA:"Alternative data streams",
  11. win32con.BACKUP_LINK:"Hard link information",
  12. win32con.BACKUP_PROPERTY_DATA:"Property data",
  13. win32con.BACKUP_OBJECT_ID:"Objects identifiers",
  14. win32con.BACKUP_REPARSE_DATA:"Reparse points",
  15. win32con.BACKUP_SPARSE_BLOCK:"Sparse file"
  16. }
  17. tempdir=win32api.GetTempPath()
  18. tempfile=win32api.GetTempFileName(tempdir,'bkr')[0]
  19. print('Filename:',tempfile)
  20. f=open(tempfile,'w')
  21. f.write('some random junk'+'x'*100)
  22. f.close()
  23. f=open(tempfile+':streamdata','w')
  24. f.write('data written to alternate stream'+'y'*100)
  25. f.close()
  26. f=open(tempfile+':anotherstream','w')
  27. f.write('z'*200)
  28. f.close()
  29. ## add Summary Information, which is stored as a separate stream
  30. m=storagecon.STGM_READWRITE | storagecon.STGM_SHARE_EXCLUSIVE |storagecon.STGM_DIRECT
  31. pss=pythoncom.StgOpenStorageEx(tempfile, m, storagecon.STGFMT_FILE, 0 , pythoncom.IID_IPropertySetStorage,None)
  32. ps=pss.Create(pythoncom.FMTID_SummaryInformation,pythoncom.IID_IPropertyStorage,0,storagecon.STGM_READWRITE|storagecon.STGM_SHARE_EXCLUSIVE)
  33. ps.WriteMultiple((storagecon.PIDSI_KEYWORDS,storagecon.PIDSI_COMMENTS),('keywords','comments'))
  34. ps=None
  35. pss=None
  36. sa=pywintypes.SECURITY_ATTRIBUTES()
  37. sa.bInheritHandle=False
  38. h=win32file.CreateFile(tempfile, win32con.GENERIC_ALL ,win32con.FILE_SHARE_READ,
  39. sa, win32con.OPEN_EXISTING, win32file.FILE_FLAG_BACKUP_SEMANTICS , None)
  40. """ stream header:
  41. typedef struct _WIN32_STREAM_ID {
  42. DWORD dwStreamId; DWORD dwStreamAttributes; LARGE_INTEGER Size;
  43. DWORD dwStreamNameSize; WCHAR cStreamName[ANYSIZE_ARRAY];
  44. }
  45. """
  46. win32_stream_id_format="LLQL"
  47. win32_stream_id_size=struct.calcsize(win32_stream_id_format)
  48. def parse_stream_header(h,ctxt,data):
  49. stream_type, stream_attributes, stream_size, stream_name_size=struct.unpack(win32_stream_id_format,data)
  50. print('\nType:',stream_type,stream_types[stream_type], 'Attributes:', stream_attributes, 'Size:', stream_size, 'Name len:',stream_name_size)
  51. if stream_name_size>0:
  52. ## ??? sdk says this size is in characters, but it appears to be number of bytes ???
  53. bytes_read, stream_name_buf, ctxt=win32file.BackupRead(h, stream_name_size, None, False, True, ctxt)
  54. stream_name=pywintypes.UnicodeFromRaw(stream_name_buf[:])
  55. else:
  56. stream_name='Unnamed'
  57. print('Name:'+stream_name)
  58. return ctxt, stream_type, stream_attributes, stream_size, stream_name_size, stream_name
  59. ctxt=0
  60. win32_stream_id_buf=None ## gets rebound to a writable buffer on first call and reused
  61. while 1:
  62. bytes_read, win32_stream_id_buf, ctxt=win32file.BackupRead(h, win32_stream_id_size, win32_stream_id_buf, False, True, ctxt)
  63. if bytes_read==0:
  64. break
  65. ctxt, stream_type, stream_attributes, stream_size, stream_name_size, stream_name=\
  66. parse_stream_header(h, ctxt, win32_stream_id_buf[:])
  67. if stream_size>0:
  68. bytes_moved=win32file.BackupSeek(h, stream_size, ctxt)
  69. print('Moved: ',bytes_moved)
  70. win32file.BackupRead(h, win32_stream_id_size, win32_stream_id_buf, True, True, ctxt)
  71. win32file.CloseHandle(h)