瀏覽代碼

Merge pull request #1411 from Anakonda/windows_ads

Windows: alternate data steams
enkore 8 年之前
父節點
當前提交
9eae6b2090
共有 3 個文件被更改,包括 44 次插入1 次删除
  1. 8 0
      src/borg/archiver.py
  2. 1 0
      src/borg/platform/__init__.py
  3. 35 1
      src/borg/platform/windows.pyx

+ 8 - 0
src/borg/archiver.py

@@ -51,6 +51,7 @@ from .upgrader import AtticRepositoryUpgrader, BorgRepositoryUpgrader
 
 if sys.platform == 'win32':
     import posixpath
+    from .platform import get_ads
 
 
 def argument(args, str_or_bool):
@@ -409,6 +410,13 @@ class Archiver:
             else:
                 status = '-'  # dry run, item was not backed up
         self.print_file_status(status, path)
+        if sys.platform == 'win32':
+            if ':' not in os.path.basename(path):
+                for stream in get_ads(path):
+                    if stream != '::$DATA':
+                        self._process(archive, cache, matcher, exclude_caches, exclude_if_present,
+                            keep_tag_files, skip_inodes, path + stream[:-6], restrict_dev,
+                            read_special, dry_run, st)
 
     @with_repository()
     @with_archive

+ 1 - 0
src/borg/platform/__init__.py

@@ -27,3 +27,4 @@ elif sys.platform == 'win32':  # pragma: windows only
     from .windows import API_VERSION
     from .windows import sync_dir
     from .windows import get_owner, set_owner
+    from .windows import get_ads

+ 35 - 1
src/borg/platform/windows.pyx

@@ -3,7 +3,7 @@
 import json
 import os.path
 from libc.stddef cimport wchar_t
-from libc.stdint cimport uint16_t, uint32_t, uint64_t
+from libc.stdint cimport uint16_t, uint32_t, uint64_t, int64_t
 cimport cpython.array
 import array
 
@@ -34,6 +34,7 @@ cdef extern from 'windows.h':
     ctypedef DWORD* LPDWORD
     ctypedef int BOOL
     ctypedef BYTE* PSID
+    ctypedef void* HANDLE
     struct _ACL:
         uint16_t AceCount
         
@@ -49,12 +50,24 @@ cdef extern from 'windows.h':
         SidTypeComputer,
         SidTypeLabel
 
+    cdef enum _STREAM_INFO_LEVELS:
+        FindStreamInfoStandard
+
+    struct _LARGE_INTEGER:
+        int64_t QuadPart
+    struct _WIN32_FIND_STREAM_DATA:
+        _LARGE_INTEGER StreamSize
+        wchar_t[296] cStreamName # MAX_PATH + 36
+
     HLOCAL LocalFree(HLOCAL)
     DWORD GetLastError();
     void SetLastError(DWORD)
 
     DWORD FormatMessageW(DWORD, void*, DWORD, DWORD, wchar_t*, DWORD, void*)
 
+    HANDLE FindFirstStreamW(wchar_t*, _STREAM_INFO_LEVELS, void*, DWORD)
+    BOOL FindNextStreamW(HANDLE, void*)
+    BOOL FindClose(HANDLE)
 
     BOOL InitializeSecurityDescriptor(BYTE*, DWORD)
 
@@ -64,6 +77,7 @@ cdef extern from 'windows.h':
     cdef extern int ERROR_INSUFFICIENT_BUFFER
     cdef extern int ERROR_INVALID_SID
     cdef extern int ERROR_NONE_MAPPED
+    cdef extern int ERROR_HANDLE_EOF
 
     cdef extern int OWNER_SECURITY_INFORMATION
     cdef extern int GROUP_SECURITY_INFORMATION
@@ -84,6 +98,7 @@ cdef extern from 'windows.h':
     cdef extern int FORMAT_MESSAGE_FROM_SYSTEM
     cdef extern int FORMAT_MESSAGE_IGNORE_INSERTS
 
+    cdef extern int INVALID_HANDLE_VALUE
 
 cdef extern from 'accctrl.h':
     ctypedef enum _SE_OBJECT_TYPE:
@@ -345,3 +360,22 @@ def sync_dir(path):
     # TODO
     pass
 
+
+def get_ads(path):
+    ret = []
+    cdef _WIN32_FIND_STREAM_DATA data
+    cdef wchar_t* cstrPath = PyUnicode_AsWideCharString(path, NULL)
+    cdef HANDLE searchHandle = FindFirstStreamW(cstrPath, FindStreamInfoStandard, <void*>&data, 0)
+    if searchHandle == <HANDLE>INVALID_HANDLE_VALUE:
+        PyMem_Free(cstrPath)
+        return []
+    ret.append(PyUnicode_FromWideChar(data.cStreamName, -1))
+    while FindNextStreamW(searchHandle, <void*>&data) != 0:
+        ret.append(PyUnicode_FromWideChar(data.cStreamName, -1))
+    errno = GetLastError()
+    if errno != ERROR_HANDLE_EOF:
+        raise_error('FindNextStreamW', path)
+
+    FindClose(searchHandle)
+    PyMem_Free(cstrPath)
+    return ret