Esempio n. 1
0
        def run(self):
            dir_handle = winutil.create_file(
                self.path_to_watch,
                winutil.FILE_LIST_DIRECTORY,
                winutil.FILE_SHARE_READ,
                winutil.OPEN_EXISTING,
                winutil.FILE_FLAG_BACKUP_SEMANTICS,
            )

            try:
                buffer = b'0' * 8192
                while True:
                    try:
                        results = winutil.read_directory_changes(
                            dir_handle,
                            buffer,
                            True,  # Watch sub-directories as well
                            winutil.FILE_NOTIFY_CHANGE_FILE_NAME
                            | winutil.FILE_NOTIFY_CHANGE_DIR_NAME
                            | winutil.FILE_NOTIFY_CHANGE_ATTRIBUTES
                            | winutil.FILE_NOTIFY_CHANGE_SIZE
                            | winutil.FILE_NOTIFY_CHANGE_LAST_WRITE
                            | winutil.FILE_NOTIFY_CHANGE_SECURITY,
                        )
                        for action, filename in results:
                            if self.file_is_watched(filename):
                                self.modified_queue.put(
                                    os.path.join(self.path_to_watch, filename))
                    except OverflowError:
                        pass  # the buffer overflowed, there are unknown changes
            except Exception:
                import traceback
                traceback.print_exc()
Esempio n. 2
0
    def __init__(self, path):
        from collections import defaultdict
        from calibre_extensions import winutil
        self.handle_map = {}

        if isbytestring(path):
            path = path.decode(filesystem_encoding)

        if not os.path.exists(path):
            return

        names = os.listdir(path)
        name_to_fileid = {x:windows_get_fileid(os.path.join(path, x)) for x in names}
        fileid_to_names = defaultdict(set)
        for name, fileid in iteritems(name_to_fileid):
            fileid_to_names[fileid].add(name)

        for x in names:
            f = os.path.normcase(os.path.abspath(os.path.join(path, x)))
            if not os.path.isfile(f):
                continue
            with suppress(OSError):
                # Ensure the file is not read-only
                winutil.set_file_attributes(f, winutil.FILE_ATTRIBUTE_NORMAL)

            try:
                h = winutil.create_file(f, winutil.GENERIC_READ,
                        winutil.FILE_SHARE_DELETE,
                        winutil.OPEN_EXISTING, winutil.FILE_FLAG_SEQUENTIAL_SCAN)
            except OSError as e:
                if e.winerror == winutil.ERROR_SHARING_VIOLATION:
                    # The file could be a hardlink to an already opened file,
                    # in which case we use the same handle for both files
                    fileid = name_to_fileid[x]
                    found = False
                    if fileid is not None:
                        for other in fileid_to_names[fileid]:
                            other = os.path.normcase(os.path.abspath(os.path.join(path, other)))
                            if other in self.handle_map:
                                self.handle_map[f] = self.handle_map[other]
                                found = True
                                break
                    if found:
                        continue

                self.close_handles()
                if e.winerror == winutil.ERROR_SHARING_VIOLATION:
                    err = IOError(errno.EACCES,
                            _('File is open in another process'))
                    err.filename = f
                    raise err
                prints('CreateFile failed for: %r' % f)
                raise
            except:
                self.close_handles()
                prints('CreateFile failed for: %r' % f)
                raise
            self.handle_map[f] = h
Esempio n. 3
0
def windows_get_size(path):
    ''' On windows file sizes are only accurately stored in the actual file,
    not in the directory entry (which could be out of date). So we open the
    file, and get the actual size. '''
    from calibre_extensions import winutil
    if isbytestring(path):
        path = path.decode(filesystem_encoding)
    with closing(
            winutil.create_file(
                path, 0, winutil.FILE_SHARE_READ | winutil.FILE_SHARE_WRITE
                | winutil.FILE_SHARE_DELETE, winutil.OPEN_EXISTING, 0)) as h:
        return winutil.get_file_size(h)
Esempio n. 4
0
def windows_open(path):
    if isinstance(path, bytes):
        path = os.fsdecode(path)
    h = winutil.create_file(
        path,
        winutil.GENERIC_READ
        | winutil.GENERIC_WRITE,  # Open for reading and writing
        0,  # Open exclusive
        winutil.OPEN_ALWAYS,  # If file does not exist, create it
        winutil.FILE_ATTRIBUTE_NORMAL,  # Normal attributes
    )
    fd = msvcrt.open_osfhandle(int(h), 0)
    ans = os.fdopen(fd, 'r+b')
    h.detach()
    return ans
Esempio n. 5
0
    def os_open(path,
                flags,
                mode=0o777,
                share_flags=winutil.FILE_SHARE_VALID_FLAGS):
        '''
        Replacement for os.open() allowing moving or unlinking before closing
        '''
        if not isinstance(flags, Integral):
            raise TypeError('flags must be an integer')
        if not isinstance(mode, Integral):
            raise TypeError('mode must be an integer')

        if share_flags & ~winutil.FILE_SHARE_VALID_FLAGS:
            raise ValueError('bad share_flags: %r' % share_flags)

        access_flags = _ACCESS_MAP[flags & _ACCESS_MASK]
        create_flags = _CREATE_MAP[flags & _CREATE_MASK]
        attrib_flags = winutil.FILE_ATTRIBUTE_NORMAL

        if flags & os.O_CREAT and mode & ~0o444 == 0:
            attrib_flags = winutil.FILE_ATTRIBUTE_READONLY

        if flags & os.O_TEMPORARY:
            share_flags |= winutil.FILE_SHARE_DELETE
            attrib_flags |= winutil.FILE_FLAG_DELETE_ON_CLOSE
            access_flags |= winutil.DELETE

        if flags & os.O_SHORT_LIVED:
            attrib_flags |= winutil.FILE_ATTRIBUTE_TEMPORARY

        if flags & os.O_SEQUENTIAL:
            attrib_flags |= winutil.FILE_FLAG_SEQUENTIAL_SCAN

        if flags & os.O_RANDOM:
            attrib_flags |= winutil.FILE_FLAG_RANDOM_ACCESS

        h = winutil.create_file(path, access_flags, share_flags, create_flags,
                                attrib_flags)
        ans = msvcrt.open_osfhandle(int(h), flags | os.O_NOINHERIT)
        h.detach()
        return ans
Esempio n. 6
0
    def test_winutil(self):
        import tempfile
        from calibre import strftime
        from calibre_extensions import winutil
        self.assertEqual(winutil.special_folder_path(winutil.CSIDL_APPDATA), winutil.known_folder_path(winutil.FOLDERID_RoamingAppData))
        self.assertEqual(winutil.special_folder_path(winutil.CSIDL_LOCAL_APPDATA), winutil.known_folder_path(winutil.FOLDERID_LocalAppData))
        self.assertEqual(winutil.special_folder_path(winutil.CSIDL_FONTS), winutil.known_folder_path(winutil.FOLDERID_Fonts))
        self.assertEqual(winutil.special_folder_path(winutil.CSIDL_PROFILE), winutil.known_folder_path(winutil.FOLDERID_Profile))

        def au(x, name):
            self.assertTrue(
                isinstance(x, unicode_type),
                '%s() did not return a unicode string, instead returning: %r' % (name, x))
        for x in 'username temp_path locale_name'.split():
            au(getattr(winutil, x)(), x)
        d = winutil.localeconv()
        au(d['thousands_sep'], 'localeconv')
        au(d['decimal_point'], 'localeconv')
        for k, v in iteritems(d):
            au(v, k)
        os.environ['XXXTEST'] = 'YYY'
        self.assertEqual(getenv('XXXTEST'), 'YYY')
        del os.environ['XXXTEST']
        self.assertIsNone(getenv('XXXTEST'))
        for k in os.environ:
            v = getenv(k)
            if v is not None:
                au(v, 'getenv-' + k)
        t = time.localtime()
        fmt = '%Y%a%b%e%H%M'
        for fmt in (fmt, fmt.encode('ascii')):
            x = strftime(fmt, t)
            au(x, 'strftime')
        tdir = tempfile.mkdtemp(dir=winutil.temp_path())
        path = os.path.join(tdir, 'test-create-file.txt')
        h = winutil.create_file(
            path, winutil.GENERIC_READ | winutil.GENERIC_WRITE, 0, winutil.OPEN_ALWAYS, winutil.FILE_ATTRIBUTE_NORMAL)
        self.assertRaises(OSError, winutil.delete_file, path)
        del h
        winutil.delete_file(path)
        self.assertRaises(OSError, winutil.delete_file, path)
        self.assertRaises(OSError, winutil.create_file,
            os.path.join(path, 'cannot'), winutil.GENERIC_READ, 0, winutil.OPEN_ALWAYS, winutil.FILE_ATTRIBUTE_NORMAL)
        self.assertTrue(winutil.supports_hardlinks(os.path.abspath(os.getcwd())[0] + ':\\'))
        sz = 23
        data = os.urandom(sz)
        open(path, 'wb').write(data)
        h = winutil.Handle(0, winutil.ModuleHandle, 'moo')
        r = repr(h)
        h2 = winutil.Handle(h.detach(), winutil.ModuleHandle, 'moo')
        self.assertEqual(r, repr(h2))
        h2.close()

        h = winutil.create_file(
            path, winutil.GENERIC_READ | winutil.GENERIC_WRITE, 0, winutil.OPEN_ALWAYS, winutil.FILE_ATTRIBUTE_NORMAL)
        self.assertEqual(winutil.get_file_size(h), sz)
        self.assertRaises(OSError, winutil.set_file_pointer, h, 23, 23)
        self.assertEqual(winutil.read_file(h), data)
        self.assertEqual(winutil.read_file(h), b'')
        winutil.set_file_pointer(h, 3)
        self.assertEqual(winutil.read_file(h), data[3:])
        self.assertEqual(winutil.nlinks(path), 1)
        npath = path + '.2'
        winutil.create_hard_link(npath, path)
        h.close()
        self.assertEqual(open(npath, 'rb').read(), data)
        self.assertEqual(winutil.nlinks(path), 2)
        winutil.delete_file(path)
        self.assertEqual(winutil.nlinks(npath), 1)
        winutil.set_file_attributes(npath, winutil.FILE_ATTRIBUTE_READONLY)
        self.assertRaises(OSError, winutil.delete_file, npath)
        winutil.set_file_attributes(npath, winutil.FILE_ATTRIBUTE_NORMAL)
        winutil.delete_file(npath)
        self.assertGreater(min(winutil.get_disk_free_space(None)), 0)
        open(path, 'wb').close()
        open(npath, 'wb').close()
        winutil.move_file(path, npath, winutil.MOVEFILE_WRITE_THROUGH | winutil.MOVEFILE_REPLACE_EXISTING)
        self.assertFalse(os.path.exists(path))
        os.remove(npath)
        dpath = tempfile.mkdtemp(dir=os.path.dirname(path))
        dh = winutil.create_file(
            dpath, winutil.FILE_LIST_DIRECTORY, winutil.FILE_SHARE_READ, winutil.OPEN_EXISTING, winutil.FILE_FLAG_BACKUP_SEMANTICS,
        )
        from threading import Thread, Event
        started = Event()
        events = []

        def read_changes():
            buffer = b'0' * 8192
            started.set()
            events.extend(winutil.read_directory_changes(
                dh, buffer, True,
                winutil.FILE_NOTIFY_CHANGE_FILE_NAME |
                winutil.FILE_NOTIFY_CHANGE_DIR_NAME |
                winutil.FILE_NOTIFY_CHANGE_ATTRIBUTES |
                winutil.FILE_NOTIFY_CHANGE_SIZE |
                winutil.FILE_NOTIFY_CHANGE_LAST_WRITE |
                winutil.FILE_NOTIFY_CHANGE_SECURITY
            ))
        t = Thread(target=read_changes, daemon=True)
        t.start()
        started.wait(1)
        t.join(0.1)
        testp = os.path.join(dpath, 'test')
        open(testp, 'w').close()
        t.join(4)
        self.assertTrue(events)
        for actions, path in events:
            self.assertEqual(os.path.join(dpath, path), testp)
        dh.close()
        os.remove(testp)
        os.rmdir(dpath)
        del h
        shutil.rmtree(tdir)
        m = winutil.create_mutex("test-mutex", False)
        self.assertRaises(OSError, winutil.create_mutex, 'test-mutex', False)
        m.close()
        self.assertEqual(winutil.parse_cmdline('"c:\\test exe.exe" "some arg" 2'), ('c:\\test exe.exe', 'some arg', '2'))