Storage_base.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import os
  2. from BitTorrent.platform import get_sparse_files_support
  3. class UnregisteredFileException(Exception):
  4. pass
  5. # Make this a separate function because having this code in Storage.__init__()
  6. # would make python print a SyntaxWarning (uses builtin 'file' before 'global')
  7. def bad_libc_workaround():
  8. global file
  9. def file(name, mode = 'r', buffering = None):
  10. return open(name, mode)
  11. def is_open_for_write(mode):
  12. if 'w' in mode:
  13. return True
  14. if 'r' in mode and '+' in mode:
  15. return True
  16. return False
  17. if os.name == 'nt':
  18. import win32file
  19. FSCTL_SET_SPARSE = 0x900C4
  20. def _sparse_magic(handle, length=0):
  21. win32file.DeviceIoControl(handle, FSCTL_SET_SPARSE, '', 0, None)
  22. win32file.SetFilePointer(handle, length, win32file.FILE_BEGIN)
  23. win32file.SetEndOfFile(handle)
  24. win32file.SetFilePointer(handle, 0, win32file.FILE_BEGIN)
  25. def make_file_sparse(path, f, length=0):
  26. supported = get_sparse_files_support(path)
  27. if not supported:
  28. return
  29. handle = win32file._get_osfhandle(f.fileno())
  30. _sparse_magic(handle, length)
  31. else:
  32. def make_file_sparse(*args, **kwargs):
  33. return
  34. def open_sparse_file(path, mode, length=0, overlapped=False):
  35. supported = get_sparse_files_support(path)
  36. flags = 0
  37. # some day I might support sparse files elsewhere
  38. if not supported and os.name != 'nt':
  39. return file(path, mode, 0)
  40. flags = win32file.FILE_FLAG_RANDOM_ACCESS
  41. if overlapped:
  42. flags |= win32file.FILE_FLAG_OVERLAPPED
  43. # If the hFile handle is opened with the
  44. # FILE_FLAG_NO_BUFFERING flag set, an application can move the
  45. # file pointer only to sector-aligned positions. A
  46. # sector-aligned position is a position that is a whole number
  47. # multiple of the volume sector size. An application can
  48. # obtain a volume sector size by calling the GetDiskFreeSpace
  49. # function.
  50. #flags |= win32file.FILE_FLAG_NO_BUFFERING
  51. access = win32file.GENERIC_READ
  52. # Shared write is necessary because lock is assigned
  53. # per file handle. --Dave
  54. share = win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE
  55. #share = win32file.FILE_SHARE_READ #| win32file.FILE_SHARE_WRITE
  56. if is_open_for_write(mode):
  57. access |= win32file.GENERIC_WRITE
  58. if isinstance(path, unicode):
  59. CreateFile = win32file.CreateFileW
  60. else:
  61. CreateFile = win32file.CreateFile
  62. handle = CreateFile(path, access, share, None,
  63. win32file.OPEN_ALWAYS,
  64. flags, None)
  65. if supported and is_open_for_write(mode):
  66. _sparse_magic(handle, length)
  67. fd = win32file._open_osfhandle(handle, os.O_BINARY)
  68. handle.Detach()
  69. f = os.fdopen(fd, mode)
  70. return f