示例#1
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
示例#2
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'))